eclair snapshot
diff --git a/CHANGES.TXT b/CHANGES.TXT
index 8f276d4..a91d6d6 100644
--- a/CHANGES.TXT
+++ b/CHANGES.TXT
@@ -14,7 +14,27 @@
    1.8 => SDK 1.1
    1.9 => SDK 1.5_r1 (and SDK 1.5_r2)
    1.10 => SDK 1.5_r3
-   1.11 => current
+   1.11 => SDK 1.6_r1
+   1.12 => current
+
+==============================================================================
+Changes between 1.12 and 1.11
+
+IMPORTANT BUG FIXES:
+
+- Fixed a nasty race condition in the Linux EsounD audio backend which resulted
+  in rare lockups when stopping the emulator on this platform.
+
+- The key-bindings for the Menu button (F2 and PageUp by default) didn't work
+  due to a typo.
+
+OTHER:
+
+- Sources have been refreshed by a large integration of upstream QEMU
+  sources (version 0.10.50). The integration is based on the following commit,
+  dated 2009-06-19:
+
+         d2e9fd8f703203c2eeeed120b1ef6c3a6574e0ab
 
 ==============================================================================
 Changes between 1.11 and 1.10
diff --git a/COPYING b/COPYING
index e77696a..00ccfbb 100644
--- a/COPYING
+++ b/COPYING
@@ -1,8 +1,8 @@
 		    GNU GENERAL PUBLIC LICENSE
 		       Version 2, June 1991
 
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                          675 Mass Ave, Cambridge, MA 02139, USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -15,7 +15,7 @@
 General Public License applies to most of the Free Software
 Foundation's software and to any other program whose authors commit to
 using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
+the GNU Lesser General Public License instead.)  You can apply it to
 your programs, too.
 
   When we speak of free software, we are referring to freedom, not
@@ -291,7 +291,7 @@
 the "copyright" line and a pointer to where the full notice is found.
 
     <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) 19yy  <name of author>
+    Copyright (C) <year>  <name of author>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -303,16 +303,16 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 Also add information on how to contact you by electronic and paper mail.
 
 If the program is interactive, make it output a short notice like this
 when it starts in an interactive mode:
 
-    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision version 69, Copyright (C) year name of author
     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.
@@ -335,5 +335,5 @@
 This General Public License does not permit incorporating your program into
 proprietary programs.  If your program is a subroutine library, you may
 consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
+library.  If this is what you want to do, use the GNU Lesser General
 Public License instead of this License.
diff --git a/COPYING.LIB b/COPYING.LIB
index 223ede7..48afc2e 100644
--- a/COPYING.LIB
+++ b/COPYING.LIB
@@ -2,7 +2,7 @@
 		       Version 2.1, February 1999
 
  Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+	51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -485,7 +485,7 @@
 
     You should have received a copy of the GNU Lesser General Public
     License along with this library; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 Also add information on how to contact you by electronic and paper mail.
 
diff --git a/Changelog b/Changelog
index 58f3e5e..2a3e37d 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,112 @@
+version 0.10.2:
+
+  - fix savevm/loadvm (Anthony Liguori)
+  - live migration: fix dirty tracking windows (Glauber Costa)
+  - live migration: improve error propogation (Glauber Costa)
+  - qcow2: fix image creation for > ~2TB images (Chris Wright)
+  - hotplug: fix error handling for if= parameter (Eduardo Habkost)
+  - qcow2: fix data corruption (Nolan Leake)
+  - virtio: fix guest oops with 2.6.25 kernels (Rusty Russell)
+  - SH4: add support for -kernel (Takashi Yoshii, Aurelien Jarno)
+  - hotplug: fix closing of char devices (Jan Kiszka)
+  - hotplug: remove incorrect check for device name (Eduardo Habkost)
+  - enable -k on win32 (Herve Poussineau)
+  - configure: use LANG=C for grep (Andreas Faerber)
+  - fix VGA regression (malc)
+	
+version 0.10.1:
+
+  - virtio-net: check right return size on sg list (Alex Williamson)
+  - Make qemu_announce_self handle holes (live migration after hotplug)
+    (Marcelo Tosatti)
+  - Revert r6804-r6808 (qcow2 allocation info).  This series of changes added
+    a high cost to startup for large qcow2 images (Anthony Liguori)
+  - qemu-img: fix help message (Aurelien Jarno)
+  - Fix build for non-default installs of SDL (Anthony Liguori)
+  - Fix race condition in env->interrupt_request.  When using TCG and a dynticks
+    host timer, this condition could cause TCG to get stuck in an infinite
+    loop (Aurelien Jarno)
+  - Fix reading encrypted hard disk passwords during early startup (Jan Kiszka)
+  - Fix encrypted disk reporting in 'info block' (Jan Kiszka)
+  - Fix console size with tiny displays (MusicPal) (Jan Kiszka)
+  - Improve error handling in bdrv_open2 (Jan Kiszka)
+  - Avoid leaking data in mux'ed character devices (Jan Kiszka)
+  - Fix initial character device reset (no banner in monitor) (Jan Kiszka)
+  - Fix cpuid KVM crash on i386 host (Lubomir Rintel)
+  - Fix SLES10sp2 installation by adding ISTAT1 register to LSI SCSI emulation
+    (Ryan Harper)
+
+version 0.10.0:
+
+  - TCG support (No longer requires GCC 3.x)
+  - Kernel Virtual Machine acceleration support
+  - BSD userspace emulation
+  - Bluetooth emulation and host passthrough support
+  - GDB XML register description support
+  - Intel e1000 emulation
+  - HPET emulation
+  - VirtIO paravirtual device support
+  - Marvell 88w8618 / MusicPal emulation
+  - Nokia N-series tablet emulation / OMAP2 processor emulation
+  - PCI hotplug support
+  - Live migration and new save/restore formats
+  - Curses display support
+  - qemu-nbd utility to mount supported block formats
+  - Altivec support in PPC emulation and new firmware (OpenBIOS)
+  - Multiple VNC clients are now supported
+  - TLS encryption is now supported in VNC
+  - MIPS Magnum R4000 machine (Hervé Poussineau)
+  - Braille support (Samuel Thibault)
+  - Freecom MusicPal system emulation (Jan Kiszka)
+  - OMAP242x and Nokia N800, N810 machines (Andrzej Zaborowski)
+  - EsounD audio driver (Frederick Reeve)
+  - Gravis Ultrasound GF1 sound card (Tibor "TS" Schütz)
+  - Many, many, bug fixes and new features
+
+version 0.9.1:
+
+  - TFTP booting from host directory (Anthony Liguori, Erwan Velu)
+  - Tap device emulation for Solaris (Sittichai Palanisong)
+  - Monitor multiplexing to several I/O channels (Jason Wessel)
+  - ds1225y nvram support (Herve Poussineau)
+  - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
+  - Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif)
+  - MIPS 64-bit FPU support (Thiemo Seufer)
+  - Xscale PDA emulation (Andrzej Zaborowski)
+  - ColdFire system emulation (Paul Brook)
+  - Improved SH4 support (Magnus Damm)
+  - MIPS64 support (Aurelien Jarno, Thiemo Seufer)
+  - Preliminary Alpha guest support (J. Mayer)
+  - Read-only support for Parallels disk images (Alex Beregszaszi)
+  - SVM (x86 virtualization) support (Alexander Graf)
+  - CRIS emulation (Edgar E. Iglesias)
+  - SPARC32PLUS execution support (Blue Swirl)
+  - MIPS mipssim pseudo machine (Thiemo Seufer)
+  - Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh)
+  - OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski)
+  - ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery)
+  - Gumstix boards: connex and verdex emulation (Thorsten Zitterell)
+  - Intel mainstone II board emulation (Armin Kuster)
+  - VMware SVGA II graphics card support (Andrzej Zaborowski)
+
+version 0.9.0:
+
+  - Support for relative paths in backing files for disk images
+  - Async file I/O API
+  - New qcow2 disk image format
+  - Support of multiple VM snapshots
+  - Linux: specific host CDROM and floppy support
+  - SMM support
+  - Moved PCI init, MP table init and ACPI table init to Bochs BIOS
+  - Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
+  - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
+  - Darwin userspace emulation (Pierre d'Herbemont)
+  - m68k user support (Paul Brook)
+  - several x86 and x86_64 emulation fixes
+  - Mouse relative offset VNC extension (Anthony Liguori)
+  - PXE boot support (Anthony Liguori)
+  - '-daemonize' option (Anthony Liguori)
+
 version 0.8.2:
 
   - ACPI support
@@ -5,7 +114,7 @@
   - switch to OpenBios for SPARC targets (Blue Swirl)
   - VNC server fixes
   - MIPS FPU support (Marius Groeger)
-  - Solaris/SPARC host support (Ben Taylor)
+  - Solaris/SPARC host support (Juergen Keil)
   - PPC breakpoints and single stepping (Jason Wessel)
   - USB updates (Paul Brook)
   - UDP/TCP/telnet character devices (Jason Wessel)
@@ -24,7 +133,7 @@
   - PC speaker support (Joachim Henke)
   - IDE LBA48 support (Jens Axboe)
   - SSE3 support
-  - Solaris port (Ben Taylor)
+  - Solaris port (Juergen Keil)
   - Preliminary SH4 target (Samuel Tardieu)
   - VNC server (Anthony Liguori)
   - slirp fixes (Ed Swierk et al.)
@@ -54,7 +163,7 @@
     (Johannes Schindelin)
 
 version 0.7.2:
-  
+
   - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
   - merge self modifying code handling in dirty ram page mecanism.
   - MIPS fixes (Ralf Baechle)
@@ -103,7 +212,7 @@
   - Mac OS X port (Pierre d'Herbemont)
   - Virtual console support
   - Better monitor line edition
-  - New block device layer 
+  - New block device layer
   - New 'qcow' growable disk image support with AES encryption and
     transparent decompression
   - VMware 3 and 4 read-only disk image support (untested)
@@ -169,7 +278,7 @@
   - FDC fixes for Win98
 
 version 0.5.4:
-  
+
   - qemu-fast fixes
   - BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
   - keyboard/mouse fix (Mike Nordell)
@@ -196,7 +305,7 @@
   - added accurate CR0.MP/ME/TS emulation
   - fixed DMA memory write access (Win95 boot floppy fix)
   - graphical x86 linux loader
-  - command line monitor 
+  - command line monitor
   - generic removable device support
   - support of CD-ROM change
   - multiple network interface support
@@ -234,7 +343,7 @@
   - eflags optimisation fix for string operations
 
 version 0.5.1:
-  
+
   - float access fixes when using soft mmu
   - PC emulation support on PowerPC
   - A20 support
@@ -249,7 +358,7 @@
   - Major SPARC target fixes (dynamically linked programs begin to work)
 
 version 0.5.0:
-  
+
   - full hardware level VGA emulation
   - graphical display with SDL
   - added PS/2 mouse and keyboard emulation
@@ -287,7 +396,7 @@
  - SMP kernels can at least be booted
 
 version 0.4.1:
-  
+
  - more accurate timer support in vl.
  - more reliable NE2000 probe in vl.
  - added 2.5.66 kernel in vl-test.
@@ -373,7 +482,7 @@
  - added bound, cmpxchg8b, cpuid instructions
  - added 16 bit addressing support/override for string operations
  - poll() fix
- 
+
 version 0.1.2:
 
  - compile fixes
diff --git a/LICENSE b/LICENSE
index bfc9a1f..cbd92c0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,12 +1,18 @@
-The following points clarify the QEMU licenses:
+The following points clarify the QEMU license:
 
-1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC
-   system emulator are released under the GNU Lesser General Public
-   License.
+1) QEMU as a whole is released under the GNU General Public License
 
-2) The Linux user mode QEMU emulator is released under the GNU General
-   Public License.
+2) Parts of QEMU have specific licenses which are compatible with the
+GNU General Public License. Hence each source file contains its own
+licensing information.
 
-3) QEMU is a trademark of Fabrice Bellard.
+In particular, the QEMU virtual CPU core library (libqemu.a) is
+released under the GNU Lesser General Public License. Many hardware
+device emulation sources are released under the BSD license.
 
-Fabrice Bellard.
\ No newline at end of file
+3) The Tiny Code Generator (TCG) is released under the BSD license
+   (see license headers in files).
+
+4) QEMU is a trademark of Fabrice Bellard.
+
+Fabrice Bellard.
diff --git a/Makefile.android b/Makefile.android
index a844a6b..e9a71c3 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -9,10 +9,12 @@
 
 CONFIG_INCLUDES := $(CONFIG_DIRS:%=-I%)
 
-MY_CFLAGS := $(CONFIG_INCLUDES) -O2 -g \
-             -fno-PIC \
-             -falign-functions=0 \
-             -fomit-frame-pointer \
+MY_OPTIM := -O2 -g -fno-PIC -falign-functions=0 -fomit-frame-pointer
+ifeq ($(BUILD_DEBUG_EMULATOR),true)
+    MY_OPTIM := -O0 -g
+endif
+
+MY_CFLAGS := $(CONFIG_INCLUDES) $(MY_OPTIM)
 
 # Overwrite configuration for debug builds.
 #
@@ -121,7 +123,6 @@
 
 LOCAL_SRC_FILES := \
     tcg/tcg.c \
-    tcg/tcg-dyngen.c \
     tcg/tcg-runtime.c \
 
 include $(BUILD_HOST_STATIC_LIBRARY)
@@ -144,6 +145,11 @@
 HW_SOURCES := \
     android_arm.c \
     arm_pic.c \
+    bt.c \
+    bt-hci.c \
+    bt-hid.c \
+    bt-l2cap.c \
+    bt-sdp.c \
     cdrom.c \
     dma.c \
     irq.c \
@@ -160,14 +166,18 @@
     goldfish_timer.c \
     goldfish_trace.c \
     goldfish_tty.c \
+    msmouse.c \
     pci.c \
+    qdev.c \
     scsi-disk.c \
     smc91c111.c \
+    sysbus.c \
     usb-hid.c \
     usb-hub.c \
     usb-msd.c \
     usb-ohci.c \
     usb.c \
+    watchdog.c \
 
 LOCAL_SRC_FILES += $(HW_SOURCES:%=hw/%)
 
@@ -243,6 +253,7 @@
 
 ifeq ($(HOST_OS),darwin)
   CONFIG_COREAUDIO ?= yes
+  AUDIO_CFLAGS += -DHOST_BSD=1
 endif
 
 ifeq ($(HOST_OS),windows)
@@ -344,9 +355,9 @@
 LOCAL_LDLIBS                    := $(MY_LDLIBS)
 
 # don't remove the -fno-strict-aliasing, or you'll break things
-# (e.g. slirp2/network support)
+# (e.g. slirp-android/network support)
 #
-LOCAL_CFLAGS := -fno-PIC -fomit-frame-pointer -Wno-sign-compare \
+LOCAL_CFLAGS := -fno-PIC -Wno-sign-compare \
                 -fno-strict-aliasing -g -W -Wall -Wno-unused-parameter
 
 LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
@@ -370,6 +381,9 @@
                    $(TCG_CFLAGS) \
                    $(HW_CFLAGS) \
 
+# Needed by the upstream code
+LOCAL_CFLAGS += -DNEED_CPU_H
+
 # include telephony stuff
 #
 TELEPHONY_SOURCES := android_modem.c modem_driver.c gsm.c sim_card.c sysdeps_qemu.c sms.c remote_call.c
@@ -392,14 +406,14 @@
 LOCAL_CFLAGS  += $(AUDIO_CFLAGS)
 LOCAL_LDLIBS  += $(AUDIO_LDLIBS)
 
-# include slirp2 code, i.e. the user-level networking stuff
+# include slirp-android code, i.e. the user-level networking stuff
 #
 SLIRP_SOURCES := bootp.c     cksum.c      debug.c  if.c     ip_icmp.c  ip_input.c   ip_output.c  \
                  mbuf.c      misc.c       sbuf.c   slirp.c  socket.c   tcp_input.c  tcp_output.c \
                  tcp_subr.c  tcp_timer.c  tftp.c   udp.c
 
-LOCAL_SRC_FILES += $(SLIRP_SOURCES:%=slirp2/%)
-LOCAL_CFLAGS    += -I$(LOCAL_PATH)/slirp2
+LOCAL_SRC_FILES += $(SLIRP_SOURCES:%=slirp-android/%)
+LOCAL_CFLAGS    += -I$(LOCAL_PATH)/slirp-android
 
 # socket proxy support
 #
@@ -441,16 +455,37 @@
 
 # include other sources
 #
-VL_SOURCES := vl.c osdep.c cutils.c \
+VL_SOURCES := vl-android.c osdep.c cutils.c \
               block.c readline.c monitor.c console.c loader.c sockets.c \
-              block-qcow.c aes.c d3des.c block-cloop.c block-dmg.c block-vvfat.c \
-              block-qcow2.c block-cow.c \
+              aes.c d3des.c \
+              block/qcow.c \
+              block/qcow2.c \
+              block/qcow2-refcount.c \
+              block/qcow2-snapshot.c \
+              block/qcow2-cluster.c \
+              block/cloop.c \
+              block/dmg.c \
+              block/vvfat.c \
+              buffered_file.c \
               cbuffer.c \
-              gdbstub.c usb-linux.c \
-              vnc.c disas.c arm-dis.c \
+              gdbstub.c \
+              vnc-android.c disas.c arm-dis.c \
               shaper.c charpipe.c loadpng.c \
               framebuffer.c \
               tcpdump.c \
+              qemu-char-android.c \
+              qemu-malloc.c \
+              qemu-option.c \
+              savevm.c \
+              net-android.c \
+              acl.c \
+              aio-android.c \
+              dma-helpers.c \
+              qemu-sockets-android.c \
+              keymaps.c \
+              bt-host.c \
+              bt-vhci.c \
+              module.c \
               android/boot-properties.c \
               android/charmap.c \
               android/cmdline-option.c \
@@ -464,6 +499,7 @@
               android/hw-lcd.c \
               android/hw-qemud.c \
               android/hw-sensors.c \
+              android/keycode.c \
               android/main.c \
               android/resource.c \
               android/user-config.c \
@@ -486,13 +522,23 @@
               hw/android_arm.c \
 
 ifeq ($(HOST_OS),windows)
-  VL_SOURCES += block-raw-win32.c
+  VL_SOURCES += block/raw-win32.c \
+                migration-dummy-android.c \
+                iolooper-select.c
 else
-  VL_SOURCES += block-raw-posix.c
+  VL_SOURCES += block/raw-posix.c \
+                migration.c \
+                migration-exec.c \
+                migration-tcp-android.c \
+                iolooper-select.c
 endif
 
 ifeq ($(HOST_OS),linux)
+    VL_SOURCES += usb-linux.c \
+                  qemu-thread.c
     LOCAL_LDLIBS += -lX11
+else
+    VL_SOURCES += usb-dummy-android.c
 endif
 
 ifeq ($(HOST_ARCH),x86)
@@ -506,7 +552,7 @@
 endif
 
 ifeq ($(HOST_OS),windows)
-  #VL_SOURCES   += tap-win32.c
+  VL_SOURCES   += tap-win32.c
   LOCAL_LDLIBS += -mno-cygwin -mwindows -mconsole
 endif
 
@@ -542,6 +588,79 @@
 LOCAL_PREBUILT_OBJ_FILES += images/$(ANDROID_ICON_OBJ)
 endif
 
+# qemu-options.h is generated from qemu-options.hx with the "hxtool" shell script
+#
+intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
+
+QEMU_OPTIONS_H := $(intermediates)/qemu-options.h
+$(QEMU_OPTIONS_H): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_OPTIONS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/hxtool -h < $< > $@
+$(QEMU_OPTIONS_H): $(LOCAL_PATH)/qemu-options.hx $(LOCAL_PATH)/hxtool
+	$(transform-generated-source)
+
+$(intermediates)/vl-android.o: $(QEMU_OPTIONS_H)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_OPTIONS_H)
+
+# qemu-monitor.h is generated from qemu-monitor.hx with the "hxtool" shell script
+#
+intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
+
+QEMU_MONITOR_H := $(intermediates)/qemu-monitor.h
+$(QEMU_MONITOR_H): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_MONITOR_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/hxtool -h < $< > $@
+$(QEMU_MONITOR_H): $(LOCAL_PATH)/qemu-monitor.hx $(LOCAL_PATH)/hxtool
+	$(transform-generated-source)
+
+$(intermediates)/vl-android.o: $(QEMU_MONITOR_H)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_MONITOR_H)
+
+
+# gdbstub-xml.c contains C-compilable arrays corresponding to the content
+# of $(LOCAL_PATH)/gdb-xml/, and is generated with the 'feature_to_c.sh' script.
+#
+ifeq ($(QEMU_TARGET_XML_SOURCES),)
+    QEMU_TARGET_XML_SOURCES := arm-core arm-neon arm-vfp arm-vfp3
+    QEMU_TARGET_XML_SOURCES := $(QEMU_TARGET_XML_SOURCES:%=$(LOCAL_PATH)/gdb-xml/%.xml)
+endif
+
+QEMU_GDBSTUB_XML_C := $(intermediates)/gdbstub-xml.c
+$(QEMU_GDBSTUB_XML_C): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_GDBSTUB_XML_C): PRIVATE_SOURCES := $(TARGET_XML_SOURCES)
+$(QEMU_GDBSTUB_XML_C): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/feature_to_c.sh $@ $(QEMU_TARGET_XML_SOURCES)
+$(QEMU_GDBSTUB_XML_C): $(QEMU_TARGET_XML_SOURCES) $(LOCAL_PATH)/feature_to_c.sh
+	$(hide) rm -f $@
+	$(transform-generated-source)
+
+$(intermediates)/vl-android.o: $(QEMU_GDBSTUB_XML_C)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_GDBSTUB_XML_C)
+
+# hw-config-defs.h is generated from android/avd/hardware-properties.ini
+#
+QEMU_HARDWARE_PROPERTIES_INI := $(LOCAL_PATH)/android/avd/hardware-properties.ini
+QEMU_HW_CONFIG_DEFS_H := $(LOCAL_PATH)/android/avd/hw-config-defs.h
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_SOURCES := $(QEMU_HARDWARE_PROPERTIES_INI)
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/android/tools/gen-hw-config.py $(QEMU_HARDWARE_PROPERTIES_INI) $@
+$(QEMU_HW_CONFIG_DEFS_H): $(QEMU_HARDWARE_PROPERTIES_INI) $(LOCAL_PATH)/android/tools/gen-hw-config.py
+	$(hide) rm -f $@
+	$(transform-generated-source)
+
+$(LOCAL_PATH)/android/avd/hw-config.h: $(QEMU_HW_CONFIG_DEFS_H)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_HW_CONFIG_DEFS_H)
+
+# this is already done by the Android build system, but is done for the
+# benefit of the stand-alone one.
+#
+ifeq ($(BUILD_STANDALONE_EMULATOR),true)
+  LOCAL_CFLAGS += -I$(intermediates)
+endif
+
+
+
 # other flags
 LOCAL_CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
 LOCAL_LDLIBS += -lm -lpthread
diff --git a/a.out.h b/a.out.h
index 2d35ebf..dfc104e 100644
--- a/a.out.h
+++ b/a.out.h
@@ -428,4 +428,3 @@
 #endif
 
 #endif /* _A_OUT_H_ */
-
diff --git a/acl.c b/acl.c
new file mode 100644
index 0000000..f69db25
--- /dev/null
+++ b/acl.c
@@ -0,0 +1,185 @@
+/*
+ * QEMU access control list management
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "acl.h"
+
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
+
+static unsigned int nacls = 0;
+static qemu_acl **acls = NULL;
+
+
+
+qemu_acl *qemu_acl_find(const char *aclname)
+{
+    int i;
+    for (i = 0 ; i < nacls ; i++) {
+        if (strcmp(acls[i]->aclname, aclname) == 0)
+            return acls[i];
+    }
+
+    return NULL;
+}
+
+qemu_acl *qemu_acl_init(const char *aclname)
+{
+    qemu_acl *acl;
+
+    acl = qemu_acl_find(aclname);
+    if (acl)
+        return acl;
+
+    acl = qemu_malloc(sizeof(*acl));
+    acl->aclname = qemu_strdup(aclname);
+    /* Deny by default, so there is no window of "open
+     * access" between QEMU starting, and the user setting
+     * up ACLs in the monitor */
+    acl->defaultDeny = 1;
+
+    acl->nentries = 0;
+    TAILQ_INIT(&acl->entries);
+
+    acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1));
+    acls[nacls] = acl;
+    nacls++;
+
+    return acl;
+}
+
+int qemu_acl_party_is_allowed(qemu_acl *acl,
+                              const char *party)
+{
+    qemu_acl_entry *entry;
+
+    TAILQ_FOREACH(entry, &acl->entries, next) {
+#ifdef HAVE_FNMATCH_H
+        if (fnmatch(entry->match, party, 0) == 0)
+            return entry->deny ? 0 : 1;
+#else
+        /* No fnmatch, so fallback to exact string matching
+         * instead of allowing wildcards */
+        if (strcmp(entry->match, party) == 0)
+            return entry->deny ? 0 : 1;
+#endif
+    }
+
+    return acl->defaultDeny ? 0 : 1;
+}
+
+
+void qemu_acl_reset(qemu_acl *acl)
+{
+    qemu_acl_entry *entry;
+
+    /* Put back to deny by default, so there is no window
+     * of "open access" while the user re-initializes the
+     * access control list */
+    acl->defaultDeny = 1;
+    TAILQ_FOREACH(entry, &acl->entries, next) {
+        TAILQ_REMOVE(&acl->entries, entry, next);
+        free(entry->match);
+        free(entry);
+    }
+    acl->nentries = 0;
+}
+
+
+int qemu_acl_append(qemu_acl *acl,
+                    int deny,
+                    const char *match)
+{
+    qemu_acl_entry *entry;
+
+    entry = qemu_malloc(sizeof(*entry));
+    entry->match = qemu_strdup(match);
+    entry->deny = deny;
+
+    TAILQ_INSERT_TAIL(&acl->entries, entry, next);
+    acl->nentries++;
+
+    return acl->nentries;
+}
+
+
+int qemu_acl_insert(qemu_acl *acl,
+                    int deny,
+                    const char *match,
+                    int index)
+{
+    qemu_acl_entry *entry;
+    qemu_acl_entry *tmp;
+    int i = 0;
+
+    if (index <= 0)
+        return -1;
+    if (index >= acl->nentries)
+        return qemu_acl_append(acl, deny, match);
+
+
+    entry = qemu_malloc(sizeof(*entry));
+    entry->match = qemu_strdup(match);
+    entry->deny = deny;
+
+    TAILQ_FOREACH(tmp, &acl->entries, next) {
+        i++;
+        if (i == index) {
+            TAILQ_INSERT_BEFORE(tmp, entry, next);
+            acl->nentries++;
+            break;
+        }
+    }
+
+    return i;
+}
+
+int qemu_acl_remove(qemu_acl *acl,
+                    const char *match)
+{
+    qemu_acl_entry *entry;
+    int i = 0;
+
+    TAILQ_FOREACH(entry, &acl->entries, next) {
+        i++;
+        if (strcmp(entry->match, match) == 0) {
+            TAILQ_REMOVE(&acl->entries, entry, next);
+            return i;
+        }
+    }
+    return -1;
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ * End:
+ */
diff --git a/acl.h b/acl.h
new file mode 100644
index 0000000..62a5e56
--- /dev/null
+++ b/acl.h
@@ -0,0 +1,74 @@
+/*
+ * QEMU access control list management
+ *
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef __QEMU_ACL_H__
+#define __QEMU_ACL_H__
+
+#include "sys-queue.h"
+
+typedef struct qemu_acl_entry qemu_acl_entry;
+typedef struct qemu_acl qemu_acl;
+
+struct qemu_acl_entry {
+    char *match;
+    int deny;
+
+    TAILQ_ENTRY(qemu_acl_entry) next;
+};
+
+struct qemu_acl {
+    char *aclname;
+    unsigned int nentries;
+    TAILQ_HEAD(,qemu_acl_entry) entries;
+    int defaultDeny;
+};
+
+qemu_acl *qemu_acl_init(const char *aclname);
+
+qemu_acl *qemu_acl_find(const char *aclname);
+
+int qemu_acl_party_is_allowed(qemu_acl *acl,
+			      const char *party);
+
+void qemu_acl_reset(qemu_acl *acl);
+
+int qemu_acl_append(qemu_acl *acl,
+		    int deny,
+		    const char *match);
+int qemu_acl_insert(qemu_acl *acl,
+		    int deny,
+		    const char *match,
+		    int index);
+int qemu_acl_remove(qemu_acl *acl,
+		    const char *match);
+
+#endif /* __QEMU_ACL_H__ */
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ * End:
+ */
diff --git a/aes.c b/aes.c
index 3700894..eb37adb 100644
--- a/aes.c
+++ b/aes.c
@@ -34,16 +34,10 @@
 #define NDEBUG
 #endif
 
-#include <assert.h>
-
 typedef uint32_t u32;
 typedef uint16_t u16;
 typedef uint8_t u8;
 
-#define MAXKC   (256/32)
-#define MAXKB   (256/8)
-#define MAXNR   14
-
 /* This controls loop-unrolling in aes_core.c */
 #undef FULL_UNROLL
 # define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
diff --git a/aio-android.c b/aio-android.c
new file mode 100644
index 0000000..a5be934
--- /dev/null
+++ b/aio-android.c
@@ -0,0 +1,192 @@
+/*
+ * QEMU aio implementation
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "block.h"
+#include "sys-queue.h"
+#include "qemu_socket.h"
+#include "iolooper.h"
+
+typedef struct AioHandler AioHandler;
+
+/* The list of registered AIO handlers */
+static LIST_HEAD(, AioHandler) aio_handlers;
+
+/* This is a simple lock used to protect the aio_handlers list.  Specifically,
+ * it's used to ensure that no callbacks are removed while we're walking and
+ * dispatching callbacks.
+ */
+static int walking_handlers;
+
+struct AioHandler
+{
+    int fd;
+    IOHandler *io_read;
+    IOHandler *io_write;
+    AioFlushHandler *io_flush;
+    int deleted;
+    void *opaque;
+    LIST_ENTRY(AioHandler) node;
+};
+
+static AioHandler *find_aio_handler(int fd)
+{
+    AioHandler *node;
+
+    LIST_FOREACH(node, &aio_handlers, node) {
+        if (node->fd == fd)
+            if (!node->deleted)
+                return node;
+    }
+
+    return NULL;
+}
+
+int qemu_aio_set_fd_handler(int fd,
+                            IOHandler *io_read,
+                            IOHandler *io_write,
+                            AioFlushHandler *io_flush,
+                            void *opaque)
+{
+    AioHandler *node;
+
+    node = find_aio_handler(fd);
+
+    /* Are we deleting the fd handler? */
+    if (!io_read && !io_write) {
+        if (node) {
+            /* If the lock is held, just mark the node as deleted */
+            if (walking_handlers)
+                node->deleted = 1;
+            else {
+                /* Otherwise, delete it for real.  We can't just mark it as
+                 * deleted because deleted nodes are only cleaned up after
+                 * releasing the walking_handlers lock.
+                 */
+                LIST_REMOVE(node, node);
+                qemu_free(node);
+            }
+        }
+    } else {
+        if (node == NULL) {
+            /* Alloc and insert if it's not already there */
+            node = qemu_mallocz(sizeof(AioHandler));
+            node->fd = fd;
+            LIST_INSERT_HEAD(&aio_handlers, node, node);
+        }
+        /* Update handler with latest information */
+        node->io_read = io_read;
+        node->io_write = io_write;
+        node->io_flush = io_flush;
+        node->opaque = opaque;
+    }
+
+    qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
+
+    return 0;
+}
+
+void qemu_aio_flush(void)
+{
+    AioHandler *node;
+    int ret;
+
+    do {
+        ret = 0;
+
+	/*
+	 * If there are pending emulated aio start them now so flush
+	 * will be able to return 1.
+	 */
+        qemu_aio_wait();
+
+        LIST_FOREACH(node, &aio_handlers, node) {
+            ret |= node->io_flush(node->opaque);
+        }
+    } while (ret > 0);
+}
+
+void qemu_aio_wait(void)
+{
+    int ret;
+    IoLooper*  looper;
+
+    if (qemu_bh_poll())
+        return;
+
+    looper = iolooper_new();
+
+    do {
+        AioHandler *node;
+
+        iolooper_reset(looper);
+        walking_handlers = 1;
+
+        /* fill fd sets */
+        LIST_FOREACH(node, &aio_handlers, node) {
+            /* If there aren't pending AIO operations, don't invoke callbacks.
+             * Otherwise, if there are no AIO requests, qemu_aio_wait() would
+             * wait indefinitely.
+             */
+            if (node->io_flush && node->io_flush(node->opaque) == 0)
+                continue;
+
+            if (!node->deleted && node->io_read) {
+                iolooper_add_read(looper, node->fd);
+            }
+            if (!node->deleted && node->io_write) {
+                iolooper_add_write(looper, node->fd);
+            }
+        }
+
+        walking_handlers = 0;
+
+        /* wait until next event */
+        ret = iolooper_wait(looper, -1);
+
+        /* if we have any readable fds, dispatch event */
+        if (ret > 0) {
+            walking_handlers = 1;
+
+            /* we have to walk very carefully in case
+             * qemu_aio_set_fd_handler is called while we're walking */
+            node = LIST_FIRST(&aio_handlers);
+            while (node) {
+                AioHandler *tmp;
+
+                if (!node->deleted &&
+                    iolooper_is_read(looper, node->fd) &&
+                    node->io_read) {
+                    node->io_read(node->opaque);
+                }
+                if (!node->deleted &&
+                    iolooper_is_write(looper, node->fd) &&
+                    node->io_write) {
+                    node->io_write(node->opaque);
+                }
+
+                tmp = node;
+                node = LIST_NEXT(node, node);
+
+                if (tmp->deleted) {
+                    LIST_REMOVE(tmp, node);
+                    qemu_free(tmp);
+                }
+            }
+
+            walking_handlers = 0;
+        }
+    } while (ret == 0);
+
+    iolooper_free(looper);
+}
diff --git a/aio.c b/aio.c
new file mode 100644
index 0000000..dc9b85d
--- /dev/null
+++ b/aio.c
@@ -0,0 +1,198 @@
+/*
+ * QEMU aio implementation
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "block.h"
+#include "sys-queue.h"
+#include "qemu_socket.h"
+
+typedef struct AioHandler AioHandler;
+
+/* The list of registered AIO handlers */
+static LIST_HEAD(, AioHandler) aio_handlers;
+
+/* This is a simple lock used to protect the aio_handlers list.  Specifically,
+ * it's used to ensure that no callbacks are removed while we're walking and
+ * dispatching callbacks.
+ */
+static int walking_handlers;
+
+struct AioHandler
+{
+    int fd;
+    IOHandler *io_read;
+    IOHandler *io_write;
+    AioFlushHandler *io_flush;
+    int deleted;
+    void *opaque;
+    LIST_ENTRY(AioHandler) node;
+};
+
+static AioHandler *find_aio_handler(int fd)
+{
+    AioHandler *node;
+
+    LIST_FOREACH(node, &aio_handlers, node) {
+        if (node->fd == fd)
+            if (!node->deleted)
+                return node;
+    }
+
+    return NULL;
+}
+
+int qemu_aio_set_fd_handler(int fd,
+                            IOHandler *io_read,
+                            IOHandler *io_write,
+                            AioFlushHandler *io_flush,
+                            void *opaque)
+{
+    AioHandler *node;
+
+    node = find_aio_handler(fd);
+
+    /* Are we deleting the fd handler? */
+    if (!io_read && !io_write) {
+        if (node) {
+            /* If the lock is held, just mark the node as deleted */
+            if (walking_handlers)
+                node->deleted = 1;
+            else {
+                /* Otherwise, delete it for real.  We can't just mark it as
+                 * deleted because deleted nodes are only cleaned up after
+                 * releasing the walking_handlers lock.
+                 */
+                LIST_REMOVE(node, node);
+                qemu_free(node);
+            }
+        }
+    } else {
+        if (node == NULL) {
+            /* Alloc and insert if it's not already there */
+            node = qemu_mallocz(sizeof(AioHandler));
+            node->fd = fd;
+            LIST_INSERT_HEAD(&aio_handlers, node, node);
+        }
+        /* Update handler with latest information */
+        node->io_read = io_read;
+        node->io_write = io_write;
+        node->io_flush = io_flush;
+        node->opaque = opaque;
+    }
+
+    qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);
+
+    return 0;
+}
+
+void qemu_aio_flush(void)
+{
+    AioHandler *node;
+    int ret;
+
+    do {
+        ret = 0;
+
+	/*
+	 * If there are pending emulated aio start them now so flush
+	 * will be able to return 1.
+	 */
+        qemu_aio_wait();
+
+        LIST_FOREACH(node, &aio_handlers, node) {
+            ret |= node->io_flush(node->opaque);
+        }
+    } while (ret > 0);
+}
+
+void qemu_aio_wait(void)
+{
+    int ret;
+
+    if (qemu_bh_poll())
+        return;
+
+    do {
+        AioHandler *node;
+        fd_set rdfds, wrfds;
+        int max_fd = -1;
+
+        walking_handlers = 1;
+
+        FD_ZERO(&rdfds);
+        FD_ZERO(&wrfds);
+
+        /* fill fd sets */
+        LIST_FOREACH(node, &aio_handlers, node) {
+            /* If there aren't pending AIO operations, don't invoke callbacks.
+             * Otherwise, if there are no AIO requests, qemu_aio_wait() would
+             * wait indefinitely.
+             */
+            if (node->io_flush && node->io_flush(node->opaque) == 0)
+                continue;
+
+            if (!node->deleted && node->io_read) {
+                FD_SET(node->fd, &rdfds);
+                max_fd = MAX(max_fd, node->fd + 1);
+            }
+            if (!node->deleted && node->io_write) {
+                FD_SET(node->fd, &wrfds);
+                max_fd = MAX(max_fd, node->fd + 1);
+            }
+        }
+
+        walking_handlers = 0;
+
+        /* No AIO operations?  Get us out of here */
+        if (max_fd == -1)
+            break;
+
+        /* wait until next event */
+        ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
+        if (ret == -1 && errno == EINTR)
+            continue;
+
+        /* if we have any readable fds, dispatch event */
+        if (ret > 0) {
+            walking_handlers = 1;
+
+            /* we have to walk very carefully in case
+             * qemu_aio_set_fd_handler is called while we're walking */
+            node = LIST_FIRST(&aio_handlers);
+            while (node) {
+                AioHandler *tmp;
+
+                if (!node->deleted &&
+                    FD_ISSET(node->fd, &rdfds) &&
+                    node->io_read) {
+                    node->io_read(node->opaque);
+                }
+                if (!node->deleted &&
+                    FD_ISSET(node->fd, &wrfds) &&
+                    node->io_write) {
+                    node->io_write(node->opaque);
+                }
+
+                tmp = node;
+                node = LIST_NEXT(node, node);
+
+                if (tmp->deleted) {
+                    LIST_REMOVE(tmp, node);
+                    qemu_free(tmp);
+                }
+            }
+
+            walking_handlers = 0;
+        }
+    } while (ret == 0);
+}
diff --git a/android-configure.sh b/android-configure.sh
index 59ec9b4..84e4535 100755
--- a/android-configure.sh
+++ b/android-configure.sh
@@ -395,7 +395,8 @@
 if [ "$OS" != "windows" ] ; then
     echo "#define CONFIG_NAND_LIMITS  1" >> $config_h
 fi
-echo "#define QEMU_VERSION    \"0.8.2\"" >> $config_h
+echo "#define QEMU_VERSION    \"0.10.50\"" >> $config_h
+echo "#define QEMU_PKGVERSION \"Android\"" >> $config_h
 case "$CPU" in
     x86) CONFIG_CPU=I386
     ;;
@@ -418,12 +419,20 @@
     ;;
     *) CONFIG_OS=$OS
 esac
+
+case $OS in
+    linux-*|darwin-*)
+        echo "#define HAVE_IOVEC 1" >> $config_h
+        ;;
+esac
+
 echo "#define CONFIG_$CONFIG_OS   1" >> $config_h
 if [ $BSD = 1 ] ; then
     echo "#define _BSD             1" >> $config_h
     echo "#define O_LARGEFILE      0" >> $config_h
     echo "#define MAP_ANONYMOUS    MAP_ANON" >> $config_h
 fi
+
 log "Generate   : $config_h"
 
 echo "Ready to go. Type 'make' to build emulator"
diff --git a/android/android.h b/android/android.h
index 6d23e6e..6d092fd 100644
--- a/android/android.h
+++ b/android/android.h
@@ -13,7 +13,7 @@
 #define  _qemu_android_h
 
 #define  ANDROID_VERSION_MAJOR  1
-#define  ANDROID_VERSION_MINOR  11
+#define  ANDROID_VERSION_MINOR  12
 
 #define  CONFIG_SHAPER  1
 
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini
index c655100..615c758 100644
--- a/android/avd/hardware-properties.ini
+++ b/android/avd/hardware-properties.ini
@@ -142,3 +142,11 @@
 default     = 160
 abstract    = Abstracted LCD density
 description = Must be one of 120, 160 or 240. A value used to roughly describe the density of the LCD screen for automatic resource/asset selection.
+
+# Maximum VM heap size
+# Higher values are required for high-dpi devices
+name        = vm.heapSize
+type        = integer
+default     = 16
+abstract    = Max VM application heap size
+description = The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes.
diff --git a/android/avd/hw-config-defs.h b/android/avd/hw-config-defs.h
index 7fcf732..77cb8fe 100644
--- a/android/avd/hw-config-defs.h
+++ b/android/avd/hw-config-defs.h
@@ -143,6 +143,13 @@
   "Abstracted LCD density",
   "Must be one of 120, 160 or 240. A value used to roughly describe the density of the LCD screen for automatic resource/asset selection.")
 
+HWCFG_INT(
+  vm_heapSize,
+  "vm.heapSize",
+  16,
+  "Max VM application heap size",
+  "The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes.")
+
 #undef HWCFG_INT
 #undef HWCFG_BOOL
 #undef HWCFG_DISKSIZE
diff --git a/android/avd/info.c b/android/avd/info.c
index 1bdb59c..10e2005 100644
--- a/android/avd/info.c
+++ b/android/avd/info.c
@@ -1358,6 +1358,21 @@
     return i->imagePath[imageType];
 }
 
+uint64_t
+avdInfo_getImageFileSize( AvdInfo*  i, AvdImageType  imageType )
+{
+    const char* file = avdInfo_getImageFile(i, imageType);
+    uint64_t    size;
+
+    if (file == NULL)
+        return 0ULL;
+
+    if (path_get_size(file, &size) < 0)
+        return 0ULL;
+
+    return size;
+}
+
 int
 avdInfo_isImageReadOnly( AvdInfo*  i, AvdImageType  imageType )
 {
diff --git a/android/avd/info.h b/android/avd/info.h
index 6cd97dc..19df807 100644
--- a/android/avd/info.h
+++ b/android/avd/info.h
@@ -131,6 +131,11 @@
  */
 const char*  avdInfo_getImageFile( AvdInfo*  i, AvdImageType  imageType );
 
+/* Return the size of a given image file. Returns 0 if the file
+ * does not exist or could not be accessed.
+ */
+uint64_t     avdInfo_getImageFileSize( AvdInfo*  i, AvdImageType  imageType );
+
 /* Returns 1 if the corresponding image file is read-only
  */
 int          avdInfo_isImageReadOnly( AvdInfo*  i, AvdImageType  imageType );
diff --git a/android/build/binary.make b/android/build/binary.make
index 1c75d52..5052dc1 100644
--- a/android/build/binary.make
+++ b/android/build/binary.make
@@ -20,8 +20,8 @@
 LOCAL_OBJS_DIR  := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE))
 LOCAL_OBJECTS   :=
 LOCAL_CC        ?= $(CC)
-LOCAL_C_SOURCES := $(filter  %.c,$(LOCAL_SRC_FILES))
-LOCAL_OBJC_SOURCES := $(filter %.m,$(LOCAL_SRC_FILES))
+LOCAL_C_SOURCES := $(filter  %.c,$(LOCAL_SRC_FILES) $(LOCAL_GENERATED_SOURCES))
+LOCAL_OBJC_SOURCES := $(filter %.m,$(LOCAL_SRC_FILES) $(LOCAL_GENERATED_SOURCES))
 
 $(foreach src,$(LOCAL_C_SOURCES), \
     $(eval $(call compile-c-source,$(src))) \
diff --git a/android/build/common.sh b/android/build/common.sh
index b22ef7d..3f2c642 100644
--- a/android/build/common.sh
+++ b/android/build/common.sh
@@ -444,18 +444,6 @@
 {
     # locate prebuilt directory
     ANDROID_PREBUILT_HOST_TAG=$OS
-    case $OS in
-        linux-*)
-            # Linux is a special case because in the old tree layout
-            # we simply used 'Linux' as the prebuilt host tag, but
-            # are now using "linux-x86" in the new layout
-            # check which one should be used
-            #
-            if [ -d $ANDROID_TOP/prebuilt/Linux ] ; then
-                PREBUILT_HOST_TAG=Linux
-            fi
-            ;;
-    esac
     ANDROID_PREBUILT=$ANDROID_TOP/prebuilt/$ANDROID_PREBUILT_HOST_TAG
     if [ ! -d $ANDROID_PREBUILT ] ; then
         # this can happen when building on x86_64
diff --git a/android/build/definitions.make b/android/build/definitions.make
index 4ba0d07..54d1a8a 100644
--- a/android/build/definitions.make
+++ b/android/build/definitions.make
@@ -123,3 +123,9 @@
 	mkdir -p $(1)
 endef
 
+define transform-generated-source
+@echo "Generated: $(PRIVATE_MODULE) <= $<"
+@mkdir -p $(dir $@)
+$(hide) $(PRIVATE_CUSTOM_TOOL)
+endef
+
diff --git a/android/charmap.c b/android/charmap.c
index c8ed2d6..08c0901 100644
--- a/android/charmap.c
+++ b/android/charmap.c
@@ -9,8 +9,126 @@
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 */
+#include "qemu-common.h"
+#include "android/utils/path.h"
+#include "android/utils/misc.h"
+#include "android/utils/debug.h"
 #include "android/charmap.h"
 
+/* Parses .kcm file producing key characters map.
+ * .kcm file parsed by this module is expected to contain 4 types of
+ * lines:
+ * 1. An empty line (containing no characters, or only space or tab
+ *    characters).
+ * 2. A comment line (begins with '#')
+ * 3. A type section line (begins with '[')
+ * 4. Character map line, formatted as such:
+ * Key code value, followed by one or more space or tab characters.
+ * Display value, followed by one or more space or tab characters.
+ * Number value, followed by one or more space or tab characters.
+ * Base value, followed by one or more space or tab characters.
+ * Caps value, followed by one or more space or tab characters.
+ * Fn value, followed by one or more space or tab characters.
+ * Caps_fn value, followed by one or more space or tab characters.
+ * All values, except for the key code value must be either in character
+ * form ('X', where X is the value), or in hexadecimal form (0xXXXX, where
+ * XXXX is hexadecimal representation of the value). Note that if value is
+ * in hexadecimal form, it must not exceed value that can be contained in
+ * variable of 'unsigned short' type.
+ * Bellow are a couple of examples of valid .kcm file lines:
+ * # keycode       display number  base    caps    fn      caps_fn
+ * A               'A'     '2'     'a'     'A'     '#'     0x00
+ * PERIOD          '.'     '.'     '.'     ':'     ':'     0x2026
+ * SPACE           0x20    0x20    0x20    0x20    0xEF01  0xEF01
+*/
+
+/* Maximum length of a line expected in .kcm file. */
+#define KCM_MAX_LINE_LEN    1024
+
+/* Maximum length of a token in a key map line. */
+#define KCM_MAX_TOKEN_LEN   512
+
+/* Maps symbol name from .kcm file to a keycode value. */
+typedef struct AKeycodeMapEntry {
+    /* Symbol name from .kcm file. */
+    const char* key_name;
+
+    /* Key code value for the symbol. */
+    int         key_code;
+} AKeycodeMapEntry;
+
+/* Result of parsing a line in a .kcm file. */
+typedef enum {
+    /* Line format was bad. */
+    BAD_FORMAT,
+
+    /* Line had been skipped (an empty line, or a comment, etc.). */
+    SKIP_LINE,
+
+    /* Line represents an entry in the key map. */
+    KEY_ENTRY,
+} ParseStatus;
+
+static const AKeycodeMapEntry keycode_map[] = {
+    /*  Symbol           Key code */
+
+      { "A",             kKeyCodeA },
+      { "B",             kKeyCodeB },
+      { "C",             kKeyCodeC },
+      { "D",             kKeyCodeD },
+      { "E",             kKeyCodeE },
+      { "F",             kKeyCodeF },
+      { "G",             kKeyCodeG },
+      { "H",             kKeyCodeH },
+      { "I",             kKeyCodeI },
+      { "J",             kKeyCodeJ },
+      { "K",             kKeyCodeK },
+      { "L",             kKeyCodeL },
+      { "M",             kKeyCodeM },
+      { "N",             kKeyCodeN },
+      { "O",             kKeyCodeO },
+      { "P",             kKeyCodeP },
+      { "Q",             kKeyCodeQ },
+      { "R",             kKeyCodeR },
+      { "S",             kKeyCodeS },
+      { "T",             kKeyCodeT },
+      { "U",             kKeyCodeU },
+      { "V",             kKeyCodeV },
+      { "W",             kKeyCodeW },
+      { "X",             kKeyCodeX },
+      { "Y",             kKeyCodeY },
+      { "Z",             kKeyCodeZ },
+      { "0",             kKeyCode0 },
+      { "1",             kKeyCode1 },
+      { "2",             kKeyCode2 },
+      { "3",             kKeyCode3 },
+      { "4",             kKeyCode4 },
+      { "5",             kKeyCode5 },
+      { "6",             kKeyCode6 },
+      { "7",             kKeyCode7 },
+      { "8",             kKeyCode8 },
+      { "9",             kKeyCode9 },
+      { "COMMA",         kKeyCodeComma },
+      { "PERIOD",        kKeyCodePeriod },
+      { "AT",            kKeyCodeAt },
+      { "SLASH",         kKeyCodeSlash },
+      { "SPACE",         kKeyCodeSpace },
+      { "ENTER",         kKeyCodeNewline },
+      { "TAB",           kKeyCodeTab },
+      { "GRAVE",         kKeyCodeGrave },
+      { "MINUS",         kKeyCodeMinus },
+      { "EQUALS",        kKeyCodeEquals },
+      { "LEFT_BRACKET",  kKeyCodeLeftBracket },
+      { "RIGHT_BRACKET", kKeyCodeRightBracket },
+      { "BACKSLASH",     kKeyCodeBackslash },
+      { "SEMICOLON",     kKeyCodeSemicolon },
+      { "APOSTROPHE",    kKeyCodeApostrophe },
+      { "STAR",          kKeyCodeStar },
+      { "POUND",         kKeyCodePound },
+      { "PLUS",          kKeyCodePlus },
+      { "DEL",           kKeyCodeDel },
+};
+
 /* the following is automatically generated by the 'gen-charmap.py' script
  * do not touch. the generation command was:
  *   gen-charmap.py qwerty.kcm qwerty2.kcm
@@ -144,5 +262,474 @@
     "qwerty2"
 };
 
-const AKeyCharmap*  android_charmaps[2] = { &_qwerty_charmap , &_qwerty2_charmap };
-const int           android_charmap_count = 2;
+/* Custom character map created with -charmap option. */
+static AKeyCharmap android_custom_charmap = { 0 };
+
+const AKeyCharmap** android_charmaps = 0;
+int                 android_charmap_count = 0;
+
+/* Checks if a character represents an end of the line.
+ * Returns a non-zero value if ch is an EOL character. Returns
+ * zero value if ch is not an EOL character.
+*/
+static int
+kcm_is_eol(char ch) {
+    // EOLs are 0, \r and \n chars.
+    return ('\0' == ch) || ('\n' == ch) || ('\r' == ch);
+}
+
+/* Checks if a character represents a token separator.
+ * Returns a non-zero value if ch is a token separator.
+ * Returns zero value if ch is not a token separator.
+*/
+static int
+kcm_is_token_separator(char ch) {
+    // Spaces and tabs are the only separators allowed
+    // between tokens in .kcm files.
+    return (' ' == ch) || ('\t' == ch);
+}
+
+/* Checks if a character represents a path separator.
+ * Returns a non-zero value if ch is a path separator.
+ * Returns zero value if ch is not a path separator.
+*/
+static int
+kcm_is_path_separator(char ch) {
+#ifdef _WIN32
+    return '/' == ch || '\\' == ch;
+#else
+    return '/' == ch;
+#endif  // _WIN32
+}
+
+/* Skips space separators in a string.
+ * str - string to advance past space separators.
+ * Returns pointer to the first character in the string, that is
+ * not a space separator. Note that this routine may return
+ * pointer to EOL in case if all characters in the string were
+ * space separators.
+*/
+static const char*
+kcm_skip_spaces(const char* str) {
+    while (!kcm_is_eol(*str) && kcm_is_token_separator(*str)) {
+        str++;
+    }
+    return str;
+}
+
+/* Advances string to the first space separator character.
+ * str - string to advance.
+ * Returns pointer to the first space separator character in the string.
+ * Note that this routine may return pointer to EOL in case if all
+ * characters in the string were not space separators.
+*/
+static const char*
+kcm_skip_non_spaces(const char* str) {
+    while (!kcm_is_eol(*str) && !kcm_is_token_separator(*str)) {
+        str++;
+    }
+    return str;
+}
+
+/* Gets first token from a string.
+ * line - String to get token from. End of the string should be
+ * determined using kcm_is_eol() routine.
+ * token - String where to copy token. Token, copied to this
+ * string will be zero-terminated. Note that buffer for the
+ * token string must be large enough to fit token of any size.
+ * max_token_len - character size of the buffer addressed by
+ * the 'token' parameter.
+ * Returns NULL if there were no tokens found in the string, or
+ * a pointer to the line string, advanced past the found token.
+*/
+static const char*
+kcm_get_token(const char* line, char* token, size_t max_token_len) {
+    // Pass spaces and tabs.
+    const char* token_starts = kcm_skip_spaces(line);
+    // Advance to next space.
+    const char* token_ends = kcm_skip_non_spaces(token_starts);
+    // Calc token length
+    size_t token_len = token_ends - token_starts;
+    if ((0 == token_len) || (token_len >= max_token_len)) {
+      return NULL;
+    }
+    memcpy(token, token_starts, token_len);
+    token[token_len] = '\0';
+    return token_ends;
+}
+
+/* Checks if token represents a comment.
+ * Returns non-zero value if token represents a comment, or zero otherwise.
+*/
+static int
+kcm_is_token_comment(const char* token) {
+    return '#' == *token;
+}
+
+/* Converts a key name to a key code as defined by AndroidKeyCode enum.
+ * key_name - Key name to convert.
+ * key_code - Upon success contains key code value for the key_name.
+ * Returns a zero value on success, or -1 if key code was not found
+ * for the given key_name.
+*/
+static int
+kcm_get_key_code(const char* key_name, unsigned short* key_code) {
+    int n;
+    // Iterate through the key code map, matching key names.
+    for (n = 0; n < sizeof(keycode_map) / sizeof(keycode_map[0]); n++) {
+        if (0 == strcmp(key_name, keycode_map[n].key_name)) {
+            *key_code = keycode_map[n].key_code;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+/* Gets unsigned short hexadecimal value for a token.
+ * token - Token to get hexadecimal value for. Note that this
+ * routine expects a "clean" (i.e. no "0x" prefix) hex number
+ * represented by the token string.
+ * val - Upon success contains hexadecimal value for the token.
+ * Returns a zero value on success, or -1 on error.
+*/
+static int
+kcm_get_ushort_hex_val(const char* token, unsigned short* val) {
+    int hex_val = hex2int(token, strlen(token));
+    // Make sure token format was ok and value doesn't exceed unsigned short.
+    if (-1 == hex_val || 0 != (hex_val & ~0xFFFF)) {
+      return -1;
+    }
+
+    *val = (unsigned short)hex_val;
+
+    return 0;
+}
+
+/* Gets a character or hexadecimal value represented by a token.
+ * token - Token to get value from.
+ * val - Upon success will contain a character or hexadecimal
+ * value represented by a token.
+ * Returns a zero value on success, or -1 on error.
+*/
+static int
+kcm_get_char_or_hex_val(const char* token, unsigned short* val) {
+    // For chars token must begin with ' followed by character followed by '
+    if ('\'' == *token) {
+        if ('\0' == token[1] || '\'' != token[2] || '\0' != token[3]) {
+            return 0;
+        }
+        *val = token[1];
+        return 0;
+    } else {
+        // Make sure that hex token is prefixed with "0x"
+        if (('0' != *token) || ('x' != token[1])) {
+            return -1;
+        }
+        // Past 0x
+        return kcm_get_ushort_hex_val(token + 2, val);
+    }
+}
+
+/* Gets first token for the line and calculates its value.
+ * line - Line to get token's value from.
+ * val - Upon success will contain a character or hexadecimal
+ * value represented by the first token in the line.
+ * returns NULL on error, or a pointer to the line string,
+ * advanced past the found token.
+*/
+static const char*
+kcm_get_char_or_hex_token_value(const char* line, unsigned short* val) {
+    char token[KCM_MAX_TOKEN_LEN];
+    line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
+    if (NULL != line) {
+        // Token must be a char, or a hex number.
+        if (kcm_get_char_or_hex_val(token, val)) {
+            return NULL;
+        }
+    }
+
+    return line;
+}
+
+/* Parses a line in .kcm file extracting key information.
+ * line - Line in .kcm file to parse.
+ * line_index - Index of the parsing line in .kcm file.
+ * key_entry - Upon success contains key information extracted from
+ * the line.
+ * kcm_file_path - Path to the charmap file, where paresed line was taken from.
+ * returns BAD_FORMAT if line format was not recognized, SKIP_LINE if line
+ * format was ok, but it didn't contain key information, or KEY_ENTRY
+ * if key information was successfuly extracted from the line.
+*/
+static ParseStatus
+kcm_parse_line(const char* line,
+               int line_index,
+               AKeyEntry* key_entry,
+               const char* kcm_file_path) {
+      char token[KCM_MAX_TOKEN_LEN];
+      unsigned short disp;
+
+      // Get first token, and see if it's an empty, or a comment line.
+      line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
+      if ((NULL == line) || kcm_is_token_comment(token)) {
+          // Empty line, or a comment.
+          return SKIP_LINE;
+      }
+
+      // Here we expect either [type=XXXX], or a key string.
+      if ('[' == token[0]) {
+          return SKIP_LINE;
+      }
+
+      // It must be a key string.
+      // First token is key code.
+      if (kcm_get_key_code(token, &key_entry->code)) {
+          derror("Invalid format of charmap file %s. Unknown key %s in line %d",
+                 kcm_file_path, token, line_index);
+          return BAD_FORMAT;
+      }
+
+      // 2-nd token is display character, which is ignored.
+      line = kcm_get_char_or_hex_token_value(line, &disp);
+      if (NULL == line) {
+          derror("Invalid format of charmap file %s. Invalid display value in line %d",
+                 kcm_file_path, line_index);
+          return BAD_FORMAT;
+      }
+
+      // 3-rd token is number.
+      line = kcm_get_char_or_hex_token_value(line, &key_entry->number);
+      if (NULL == line) {
+          derror("Invalid format of charmap file %s. Invalid number value in line %d",
+                 kcm_file_path, line_index);
+          return BAD_FORMAT;
+      }
+
+      // 4-th token is base.
+      line = kcm_get_char_or_hex_token_value(line, &key_entry->base);
+      if (NULL == line) {
+          derror("Invalid format of charmap file %s. Invalid base value in line %d",
+                 kcm_file_path, line_index);
+          return BAD_FORMAT;
+      }
+
+      // 5-th token is caps.
+      line = kcm_get_char_or_hex_token_value(line, &key_entry->caps);
+      if (NULL == line) {
+          derror("Invalid format of charmap file %s. Invalid caps value in line %d",
+                 kcm_file_path, line_index);
+          return BAD_FORMAT;
+      }
+
+      // 6-th token is fn.
+      line = kcm_get_char_or_hex_token_value(line, &key_entry->fn);
+      if (NULL == line) {
+          derror("Invalid format of charmap file %s. Invalid fn value in line %d",
+                 kcm_file_path, line_index);
+          return BAD_FORMAT;
+      }
+
+      // 7-th token is caps_fn.
+      line = kcm_get_char_or_hex_token_value(line, &key_entry->caps_fn);
+      if (NULL == line) {
+          derror("Invalid format of charmap file %s. Invalid caps_fn value in line %d",
+                 kcm_file_path, line_index);
+          return BAD_FORMAT;
+      }
+
+      // Make sure that line doesn't contain anything else,
+      // except (may be) a comment token.
+      line = kcm_get_token(line, token, KCM_MAX_TOKEN_LEN);
+      if ((NULL == line) || kcm_is_token_comment(token)) {
+          return KEY_ENTRY;
+      } else {
+          derror("Invalid format of charmap file %s in line %d",
+                 kcm_file_path, line_index);
+          return BAD_FORMAT;
+      }
+}
+
+void
+kcm_extract_charmap_name(const char* kcm_file_path,
+                         char* charmap_name,
+                         int max_len) {
+    const char* ext_separator;
+    size_t to_copy;
+
+    // Initialize charmap name with name of .kcm file.
+    // First, get file name from the full path to .kcm file.
+    const char* file_name = kcm_file_path + strlen(kcm_file_path);
+    while (!kcm_is_path_separator(*file_name) &&
+           (file_name != kcm_file_path)) {
+        file_name--;
+    }
+    if (kcm_is_path_separator(*file_name)) {
+        file_name++;
+    }
+
+    // Cut off file name extension.
+    ext_separator = strrchr(file_name, '.');
+    if (NULL == ext_separator) {
+      // "filename" is legal name.
+      ext_separator = file_name + strlen(file_name);
+    } else if (ext_separator == file_name) {
+      // ".filename" is legal name too. In this case we will use
+      // "filename" as our custom charmap name.
+      file_name++;
+      ext_separator = file_name + strlen(file_name);
+    }
+
+    // Copy file name to charmap name.
+    to_copy = ext_separator - file_name;
+    if (to_copy > (max_len - 1)) {
+        to_copy = max_len - 1;
+    }
+    memcpy(charmap_name, file_name, to_copy);
+    charmap_name[to_copy] = '\0';
+}
+
+/* Extracts charmap name from .kcm file name,
+ * and saves it into char_map as its name.
+*/
+static void
+kcm_get_charmap_name(const char* kcm_file_path, AKeyCharmap* char_map) {
+    kcm_extract_charmap_name(kcm_file_path, char_map->name,
+                             sizeof(char_map->name));
+}
+
+/* Parses .kcm file producing key characters map.
+ * See comments to this module for .kcm file format information.
+ * This routine checks format only for character map lines. It will not check
+ * format for empty lines, comments, and type section lines.
+ * Note that line length in .kcm file should not exceed 1024 characters,
+ * including newline character.
+ *
+ * Parameters:
+ * kcm_file_path - Full path to the .kcm file to parse.
+ * char_map - Upon success will contain initialized characters map.
+ * Returns a zero value on success, or -1 on failure.
+*/
+static int
+parse_kcm_file(const char* kcm_file_path, AKeyCharmap* char_map) {
+    // A line read from .kcm file.
+    char line[KCM_MAX_LINE_LEN];
+    // Return code.
+    int err = 0;
+    // Number of the currently parsed line.
+    int cur_line = 1;
+    // Initial size of the charmap's array of keys.
+    int map_size = 52;
+    FILE* kcm_file;
+
+    char_map->num_entries = 0;
+    char_map->entries = 0;
+
+    kcm_file = fopen(kcm_file_path, "r");
+    if (NULL == kcm_file) {
+        derror("Unable to open charmap file %s : %s",
+               kcm_file_path, strerror(errno));
+        return -1;
+    }
+
+    // Calculate charmap name.
+    kcm_get_charmap_name(kcm_file_path, char_map);
+
+    // Preallocate map.
+    char_map->num_entries = 0;
+    char_map->entries = qemu_malloc(sizeof(AKeyEntry) * map_size);
+
+    // Line by line parse the file.
+    for (; 0 != fgets(line, sizeof(line), kcm_file); cur_line++) {
+        AKeyEntry key_entry;
+        ParseStatus parse_res =
+            kcm_parse_line(line, cur_line, &key_entry, kcm_file_path);
+        if (BAD_FORMAT == parse_res) {
+            err = -1;
+            break;
+        } else if (KEY_ENTRY == parse_res) {
+            AKeyEntry* entries;
+            // Key information has been extracted. Add it to the map.
+            // Lets see if we need to reallocate map.
+            if (map_size == char_map->num_entries) {
+                void* new_map;
+                map_size += 10;
+                new_map = qemu_malloc(sizeof(AKeyEntry) * map_size);
+                memcpy(new_map, char_map->entries,
+                       char_map->num_entries * sizeof(AKeyEntry));
+                qemu_free((void*)char_map->entries);
+                char_map->entries = new_map;
+            }
+            entries = (AKeyEntry*)char_map->entries;
+            entries[char_map->num_entries] = key_entry;
+            char_map->num_entries++;
+        }
+    }
+
+    if (!err) {
+        // Make sure we exited the loop on EOF condition. Any other
+        // condition is an error.
+        if (0 == feof(kcm_file)) {
+            err = -1;
+        }
+        if (err) {
+          derror("Error reading charmap file %s : %s",
+                  kcm_file_path, strerror(errno));
+        }
+    }
+
+    fclose(kcm_file);
+
+    if (err) {
+        // Cleanup on failure.
+        if (0 != char_map->entries) {
+            qemu_free((void*)char_map->entries);
+            char_map->entries = 0;
+        }
+        char_map->num_entries = 0;
+    }
+
+    return err;
+}
+
+int
+android_charmap_setup(const char* kcm_file_path) {
+    if (NULL != kcm_file_path) {
+        if (!parse_kcm_file(kcm_file_path, &android_custom_charmap)) {
+            // Here we have two default charmaps and the custom one.
+            android_charmap_count = 3;
+            android_charmaps = qemu_malloc(sizeof(AKeyCharmap*) *
+                                           android_charmap_count);
+            android_charmaps[0] = &android_custom_charmap;
+            android_charmaps[1] = &_qwerty_charmap;
+            android_charmaps[2] = &_qwerty2_charmap;
+        } else {
+            derror("Unable to parse kcm file.");
+            return -1;
+        }
+    } else {
+        // Here we have only two default charmaps.
+        android_charmap_count = 2;
+        android_charmaps = qemu_malloc(sizeof(AKeyCharmap*) *
+                           android_charmap_count);
+        android_charmaps[0] = &_qwerty_charmap;
+        android_charmaps[1] = &_qwerty2_charmap;
+    }
+
+    return 0;
+}
+
+void
+android_charmap_done(void) {
+  if (NULL != android_charmaps) {
+      int n;
+      for (n = 0; n < android_charmap_count; n++) {
+          // Entries for qwerty and qwerty2 character maps are
+          // static entries defined in charmap.c
+          if ((_qwerty_charmap.entries != android_charmaps[n]->entries) &&
+              (_qwerty2_charmap.entries != android_charmaps[n]->entries)) {
+              qemu_free((void*)android_charmaps[n]->entries);
+          }
+      }
+      qemu_free(android_charmaps);
+  }
+}
diff --git a/android/charmap.h b/android/charmap.h
index 367e730..3d34224 100644
--- a/android/charmap.h
+++ b/android/charmap.h
@@ -12,98 +12,7 @@
 #ifndef _android_charmap_h
 #define _android_charmap_h
 
-#include "linux_keycodes.h"
-
-/* Keep it consistent with linux/input.h */
-typedef enum {
-    kKeyCodeSoftLeft                = KEY_SOFT1,
-    kKeyCodeSoftRight               = KEY_SOFT2,
-    kKeyCodeHome                    = KEY_HOME,
-    kKeyCodeBack                    = KEY_BACK,
-    kKeyCodeCall                    = KEY_SEND,
-    kKeyCodeEndCall                 = KEY_END,
-    kKeyCode0                       = KEY_0,
-    kKeyCode1                       = KEY_1,
-    kKeyCode2                       = KEY_2,
-    kKeyCode3                       = KEY_3,
-    kKeyCode4                       = KEY_4,
-    kKeyCode5                       = KEY_5,
-    kKeyCode6                       = KEY_6,
-    kKeyCode7                       = KEY_7,
-    kKeyCode8                       = KEY_8,
-    kKeyCode9                       = KEY_9,
-    kKeyCodeStar                    = KEY_STAR,
-    kKeyCodePound                   = KEY_SHARP,
-    kKeyCodeDpadUp                  = KEY_UP,
-    kKeyCodeDpadDown                = KEY_DOWN,
-    kKeyCodeDpadLeft                = KEY_LEFT,
-    kKeyCodeDpadRight               = KEY_RIGHT,
-    kKeyCodeDpadCenter              = KEY_CENTER,
-    kKeyCodeVolumeUp                = KEY_VOLUMEUP,
-    kKeyCodeVolumeDown              = KEY_VOLUMEDOWN,
-    kKeyCodePower                   = KEY_POWER,
-    kKeyCodeCamera                  = KEY_CAMERA,
-    kKeyCodeClear                   = KEY_CLEAR,
-    kKeyCodeA                       = KEY_A,
-    kKeyCodeB                       = KEY_B,
-    kKeyCodeC                       = KEY_C,
-    kKeyCodeD                       = KEY_D,
-    kKeyCodeE                       = KEY_E,
-    kKeyCodeF                       = KEY_F,
-    kKeyCodeG                       = KEY_G,
-    kKeyCodeH                       = KEY_H,
-    kKeyCodeI                       = KEY_I,
-    kKeyCodeJ                       = KEY_J,
-    kKeyCodeK                       = KEY_K,
-    kKeyCodeL                       = KEY_L,
-    kKeyCodeM                       = KEY_M,
-    kKeyCodeN                       = KEY_N,
-    kKeyCodeO                       = KEY_O,
-    kKeyCodeP                       = KEY_P,
-    kKeyCodeQ                       = KEY_Q,
-    kKeyCodeR                       = KEY_R,
-    kKeyCodeS                       = KEY_S,
-    kKeyCodeT                       = KEY_T,
-    kKeyCodeU                       = KEY_U,
-    kKeyCodeV                       = KEY_V,
-    kKeyCodeW                       = KEY_W,
-    kKeyCodeX                       = KEY_X,
-    kKeyCodeY                       = KEY_Y,
-    kKeyCodeZ                       = KEY_Z,
-
-    kKeyCodeComma                   = KEY_COMMA,
-    kKeyCodePeriod                  = KEY_DOT,
-    kKeyCodeAltLeft                 = KEY_LEFTALT,
-    kKeyCodeAltRight                = KEY_RIGHTALT,
-    kKeyCodeCapLeft                 = KEY_LEFTSHIFT,
-    kKeyCodeCapRight                = KEY_RIGHTSHIFT,
-    kKeyCodeTab                     = KEY_TAB,
-    kKeyCodeSpace                   = KEY_SPACE,
-    kKeyCodeSym                     = KEY_COMPOSE,
-    kKeyCodeExplorer                = KEY_WWW,
-    kKeyCodeEnvelope                = KEY_MAIL,
-    kKeyCodeNewline                 = KEY_ENTER,
-    kKeyCodeDel                     = KEY_BACKSPACE,
-    kKeyCodeGrave                   = 399,
-    kKeyCodeMinus                   = KEY_MINUS,
-    kKeyCodeEquals                  = KEY_EQUAL,
-    kKeyCodeLeftBracket             = KEY_LEFTBRACE,
-    kKeyCodeRightBracket            = KEY_RIGHTBRACE,
-    kKeyCodeBackslash               = KEY_BACKSLASH,
-    kKeyCodeSemicolon               = KEY_SEMICOLON,
-    kKeyCodeApostrophe              = KEY_APOSTROPHE,
-    kKeyCodeSlash                   = KEY_SLASH,
-    kKeyCodeAt                      = KEY_EMAIL,
-    kKeyCodeNum                     = KEY_NUM,
-    kKeyCodeHeadsetHook             = KEY_HEADSETHOOK,
-    kKeyCodeFocus                   = KEY_FOCUS,
-    kKeyCodePlus                    = KEY_PLUS,
-    kKeyCodeMenu                    = KEY_MENU,
-    kKeyCodeNotification            = KEY_NOTIFICATION,
-    kKeyCodeSearch                  = KEY_SEARCH,
-
-} AndroidKeyCode;
-
+#include "android/keycode.h"
 
 /* this defines a structure used to describe an Android keyboard charmap */
 typedef struct AKeyEntry {
@@ -115,13 +24,52 @@
     unsigned short  number;
 } AKeyEntry;
 
-typedef struct {
+/* Defines size of name buffer in AKeyCharmap entry. */
+#define AKEYCHARMAP_NAME_SIZE   32
+
+typedef struct AKeyCharmap {
     const AKeyEntry*  entries;
     int               num_entries;
-    char              name[ 32 ];
+    char              name[ AKEYCHARMAP_NAME_SIZE ];
 } AKeyCharmap;
 
-extern const int           android_charmap_count;
-extern const AKeyCharmap*  android_charmaps[];
+/* Array of charmaps available in the current emulator session. */
+extern const AKeyCharmap**  android_charmaps;
+
+/* Number of entries in android_charmaps array. */
+extern int                  android_charmap_count;
+
+/* Extracts charmap name from .kcm file name.
+ * Charmap name, extracted by this routine is a name of the kcm file, trimmed
+ * of file name extension, and shrinked (if necessary) to fit into the name
+ * buffer. Here are examples on how this routine extracts charmap name:
+ * /a/path/to/kcmfile.kcm       -> kcmfile
+ * /a/path/to/kcmfile.ext.kcm   -> kcmfile.ext
+ * /a/path/to/kcmfile           -> kcmfile
+ * /a/path/to/.kcmfile          -> kcmfile
+ * /a/path/to/.kcmfile.kcm      -> .kcmfile
+ * kcm_file_path - Path to key charmap file to extract charmap name from.
+ * charmap_name - Buffer, where to save extracted charname.
+ * max_len - charmap_name buffer size.
+*/
+void kcm_extract_charmap_name(const char* kcm_file_path,
+                              char* charmap_name,
+                              int max_len);
+
+/* Initialzes key charmap array.
+ * Key charmap array always contains two maps: one for qwerty, and
+ * another for qwerty2 keyboard layout. However, a custom layout can
+ * be requested with -charmap option. In tha case kcm_file_path
+ * parameter contains path to a .kcm file that defines that custom
+ * layout, and as the result, key charmap array will contain another
+ * entry built from that file. If -charmap option was not specified,
+ * kcm_file_path is NULL and final key charmap array will contain only
+ * two default entries.
+ * Returns a zero value on success, or -1 on failure.
+*/
+int android_charmap_setup(const char* kcm_file_path);
+
+/* Cleanups initialization performed in android_charmap_setup routine. */
+void android_charmap_done(void);
 
 #endif /* _android_charmap_h */
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
index 0689e83..6a4e7ff 100644
--- a/android/cmdline-options.h
+++ b/android/cmdline-options.h
@@ -131,6 +131,8 @@
 
 OPT_PARAM( bootchart, "<timeout>", "enable bootcharting")
 
+OPT_PARAM( charmap, "<file>", "use specific key character map")
+
 OPT_LIST(  prop, "<name>=<value>", "set system property on boot")
 
 #ifdef CONFIG_NAND_LIMITS
diff --git a/android/config/Linux/config-host.h b/android/config/Linux/config-host.h
index 90defbd..cc5e07a 100644
--- a/android/config/Linux/config-host.h
+++ b/android/config/Linux/config-host.h
@@ -6,5 +6,6 @@
 #define CONFIG_GDBSTUB 1
 #define CONFIG_SLIRP 1
 #define QEMU_VERSION "0.8.2"
+#define QEMU_PKGVERSION "Android"
 #define CONFIG_SKINS 1
 #define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/config.h b/android/config/config.h
index be83607..e2191e3 100644
--- a/android/config/config.h
+++ b/android/config/config.h
@@ -3,6 +3,7 @@
 #define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-arm"
 #define TARGET_ARCH "arm"
 #define TARGET_ARM 1
+#define TARGET_PHYS_ADDR_BITS  32
 #define CONFIG_TRACE 1
 #define CONFIG_NAND 1
 #define CONFIG_SHAPER 1
diff --git a/android/config/darwin-x86/config-host.h b/android/config/darwin-x86/config-host.h
index aaf0195..23ccb13 100644
--- a/android/config/darwin-x86/config-host.h
+++ b/android/config/darwin-x86/config-host.h
@@ -5,9 +5,11 @@
 #define CONFIG_DARWIN 1
 #define CONFIG_GDBSTUB 1
 #define CONFIG_SLIRP 1
-#define QEMU_VERSION "0.8.2"
+#define QEMU_VERSION "0.10.50"
+#define QEMU_PKGVERSION "Android"
 #define O_LARGEFILE 0
 #define MAP_ANONYMOUS MAP_ANON
+#define HAVE_IOVEC 1
 #define _BSD 1
 #define CONFIG_SKINS 1
 #define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/linux-x86/config-host.h b/android/config/linux-x86/config-host.h
index 90defbd..7e2ed201 100644
--- a/android/config/linux-x86/config-host.h
+++ b/android/config/linux-x86/config-host.h
@@ -5,6 +5,9 @@
 #define HAVE_BYTESWAP_H 1
 #define CONFIG_GDBSTUB 1
 #define CONFIG_SLIRP 1
-#define QEMU_VERSION "0.8.2"
+#define QEMU_VERSION "0.10.50"
+#define QEMU_PKGVERSION "Android"
 #define CONFIG_SKINS 1
 #define CONFIG_UNAME_RELEASE ""
+#define CONFIG_IOTHREAD 1
+#define HAVE_IOVEC 1
diff --git a/android/config/windows/config-host.h b/android/config/windows/config-host.h
index 8f9e0d9..6e18a02 100644
--- a/android/config/windows/config-host.h
+++ b/android/config/windows/config-host.h
@@ -5,6 +5,7 @@
 #define CONFIG_WIN32 1
 #define CONFIG_GDBSTUB 1
 #define CONFIG_SLIRP 1
-#define QEMU_VERSION "0.8.2"
+#define QEMU_VERSION "0.10.50"
+#define QEMU_PKGVERSION "Android"
 #define CONFIG_SKINS 1
 #define CONFIG_UNAME_RELEASE ""
diff --git a/android/console.c b/android/console.c
index a8560f4..ab32213 100644
--- a/android/console.c
+++ b/android/console.c
@@ -37,6 +37,7 @@
 #include "android/utils/debug.h"
 #include "android/utils/stralloc.h"
 #include "tcpdump.h"
+#include "net.h"
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -72,8 +73,6 @@
 #  define  D(x)   do{}while(0)
 #endif
 
-extern int  slirp_inited;  /* in vl.c */
-
 typedef struct ControlGlobalRec_*  ControlGlobal;
 
 typedef struct ControlClientRec_*  ControlClient;
@@ -892,9 +891,9 @@
     if ( !args )
         goto BadFormat;
 
-    if (!slirp_inited) {
-        slirp_inited = 1;
-        slirp_init();
+    if (!slirp_is_inited()) {
+        control_write( client, "KO: network emulation disabled\r\n");
+        return -1;
     }
 
     len = redir_parse_proto_port( args, &host_port, &host_proto );
diff --git a/android/help.c b/android/help.c
index d01ccc9..50c9d02 100644
--- a/android/help.c
+++ b/android/help.c
@@ -1283,6 +1283,15 @@
 }
 
 static void
+help_charmap(stralloc_t  *out)
+{
+    PRINTF(
+    "  use '-charmap <file>' to use key character map specified in that file.\n"
+    "  <file> must be a full path to a kcm file, containing desired character map.\n\n"
+    );
+}
+
+static void
 help_prop(stralloc_t  *out)
 {
     PRINTF(
diff --git a/android/keycode.c b/android/keycode.c
new file mode 100644
index 0000000..7364427
--- /dev/null
+++ b/android/keycode.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#include "android/keycode.h"
+
+AndroidKeyCode
+android_keycode_rotate( AndroidKeyCode  code, int  rotation )
+{
+    static const AndroidKeyCode  wheel[4] = { kKeyCodeDpadUp,
+                                              kKeyCodeDpadRight,
+                                              kKeyCodeDpadDown,
+                                              kKeyCodeDpadLeft };
+
+    int  index;
+
+    for (index = 0; index < 4; index++) {
+        if (code == wheel[index]) {
+            index = (index + rotation) & 3;
+            code  = wheel[index];
+            break;
+        }
+    }
+    return code;
+}
+
diff --git a/android/keycode.h b/android/keycode.h
new file mode 100644
index 0000000..a32ac0d
--- /dev/null
+++ b/android/keycode.h
@@ -0,0 +1,120 @@
+/* Copyright (C) 2009 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#ifndef ANDROID_KEYCODE_H
+#define ANDROID_KEYCODE_H
+
+#include "linux_keycodes.h"
+
+/* Keep it consistent with linux/input.h */
+typedef enum {
+    kKeyCodeSoftLeft                = KEY_SOFT1,
+    kKeyCodeSoftRight               = KEY_SOFT2,
+    kKeyCodeHome                    = KEY_HOME,
+    kKeyCodeBack                    = KEY_BACK,
+    kKeyCodeCall                    = KEY_SEND,
+    kKeyCodeEndCall                 = KEY_END,
+    kKeyCode0                       = KEY_0,
+    kKeyCode1                       = KEY_1,
+    kKeyCode2                       = KEY_2,
+    kKeyCode3                       = KEY_3,
+    kKeyCode4                       = KEY_4,
+    kKeyCode5                       = KEY_5,
+    kKeyCode6                       = KEY_6,
+    kKeyCode7                       = KEY_7,
+    kKeyCode8                       = KEY_8,
+    kKeyCode9                       = KEY_9,
+    kKeyCodeStar                    = KEY_STAR,
+    kKeyCodePound                   = KEY_SHARP,
+    kKeyCodeDpadUp                  = KEY_UP,
+    kKeyCodeDpadDown                = KEY_DOWN,
+    kKeyCodeDpadLeft                = KEY_LEFT,
+    kKeyCodeDpadRight               = KEY_RIGHT,
+    kKeyCodeDpadCenter              = KEY_CENTER,
+    kKeyCodeVolumeUp                = KEY_VOLUMEUP,
+    kKeyCodeVolumeDown              = KEY_VOLUMEDOWN,
+    kKeyCodePower                   = KEY_POWER,
+    kKeyCodeCamera                  = KEY_CAMERA,
+    kKeyCodeClear                   = KEY_CLEAR,
+    kKeyCodeA                       = KEY_A,
+    kKeyCodeB                       = KEY_B,
+    kKeyCodeC                       = KEY_C,
+    kKeyCodeD                       = KEY_D,
+    kKeyCodeE                       = KEY_E,
+    kKeyCodeF                       = KEY_F,
+    kKeyCodeG                       = KEY_G,
+    kKeyCodeH                       = KEY_H,
+    kKeyCodeI                       = KEY_I,
+    kKeyCodeJ                       = KEY_J,
+    kKeyCodeK                       = KEY_K,
+    kKeyCodeL                       = KEY_L,
+    kKeyCodeM                       = KEY_M,
+    kKeyCodeN                       = KEY_N,
+    kKeyCodeO                       = KEY_O,
+    kKeyCodeP                       = KEY_P,
+    kKeyCodeQ                       = KEY_Q,
+    kKeyCodeR                       = KEY_R,
+    kKeyCodeS                       = KEY_S,
+    kKeyCodeT                       = KEY_T,
+    kKeyCodeU                       = KEY_U,
+    kKeyCodeV                       = KEY_V,
+    kKeyCodeW                       = KEY_W,
+    kKeyCodeX                       = KEY_X,
+    kKeyCodeY                       = KEY_Y,
+    kKeyCodeZ                       = KEY_Z,
+
+    kKeyCodeComma                   = KEY_COMMA,
+    kKeyCodePeriod                  = KEY_DOT,
+    kKeyCodeAltLeft                 = KEY_LEFTALT,
+    kKeyCodeAltRight                = KEY_RIGHTALT,
+    kKeyCodeCapLeft                 = KEY_LEFTSHIFT,
+    kKeyCodeCapRight                = KEY_RIGHTSHIFT,
+    kKeyCodeTab                     = KEY_TAB,
+    kKeyCodeSpace                   = KEY_SPACE,
+    kKeyCodeSym                     = KEY_COMPOSE,
+    kKeyCodeExplorer                = KEY_WWW,
+    kKeyCodeEnvelope                = KEY_MAIL,
+    kKeyCodeNewline                 = KEY_ENTER,
+    kKeyCodeDel                     = KEY_BACKSPACE,
+    kKeyCodeGrave                   = 399,
+    kKeyCodeMinus                   = KEY_MINUS,
+    kKeyCodeEquals                  = KEY_EQUAL,
+    kKeyCodeLeftBracket             = KEY_LEFTBRACE,
+    kKeyCodeRightBracket            = KEY_RIGHTBRACE,
+    kKeyCodeBackslash               = KEY_BACKSLASH,
+    kKeyCodeSemicolon               = KEY_SEMICOLON,
+    kKeyCodeApostrophe              = KEY_APOSTROPHE,
+    kKeyCodeSlash                   = KEY_SLASH,
+    kKeyCodeAt                      = KEY_EMAIL,
+    kKeyCodeNum                     = KEY_NUM,
+    kKeyCodeHeadsetHook             = KEY_HEADSETHOOK,
+    kKeyCodeFocus                   = KEY_FOCUS,
+    kKeyCodePlus                    = KEY_PLUS,
+    kKeyCodeMenu                    = KEY_SOFT1,
+    kKeyCodeNotification            = KEY_NOTIFICATION,
+    kKeyCodeSearch                  = KEY_SEARCH,
+
+} AndroidKeyCode;
+
+/* This function is used to rotate D-Pad keycodes, while leaving other ones
+ * untouched. 'code' is the input keycode, which will be returned as is if
+ * it doesn't correspond to a D-Pad arrow. 'rotation' is the number of
+ * *clockwise* 90 degrees rotations to perform on D-Pad keys.
+ *
+ * Here are examples:
+ *    android_keycode_rotate( kKeyCodeDpadUp, 1 )  => kKeyCodeDpadRight
+ *    android_keycode_rotate( kKeyCodeDpadRight, 2 ) => kKeyCodeDpadLeft
+ *    android_keycode_rotate( kKeyCodeDpadDown, 3 ) => kKeyCodeDpadRight
+ *    android_keycode_rotate( kKeyCodeSpace, n ) => kKeyCodeSpace independent of n
+ */
+extern AndroidKeyCode   android_keycode_rotate( AndroidKeyCode  code, int  rotation );
+
+#endif /* ANDROID_KEYCODE_H */
diff --git a/android/main.c b/android/main.c
index f0b9d16..7b20919 100644
--- a/android/main.c
+++ b/android/main.c
@@ -91,8 +91,6 @@
  */
 #define  DEFAULT_DEVICE_DPI  165
 
-static const AKeyCharmap*  android_charmap;
-
 int    android_base_port;
 
 #if 0
@@ -233,6 +231,48 @@
     }
 }
 
+/* see http://en.wikipedia.org/wiki/List_of_device_bandwidths or a complete list */
+const NetworkSpeed  android_netspeeds[] = {
+    { "gsm", "GSM/CSD", 14400, 14400 },
+    { "hscsd", "HSCSD", 14400, 43200 },
+    { "gprs", "GPRS", 40000, 80000 },
+    { "edge", "EDGE/EGPRS", 118400, 236800 },
+    { "umts", "UMTS/3G", 128000, 1920000 },
+    { "hsdpa", "HSDPA", 348000, 14400000 },
+    { "full", "no limit", 0, 0 },
+    { NULL, NULL, 0, 0 }
+};
+
+const NetworkLatency  android_netdelays[] = {
+    /* FIXME: these numbers are totally imaginary */
+    { "gprs", "GPRS", 150, 550 },
+    { "edge", "EDGE/EGPRS", 80, 400 },
+    { "umts", "UMTS/3G", 35, 200 },
+    { "none", "no latency", 0, 0 },
+    { NULL, NULL, 0, 0 }
+};
+
+
+
+
+#define  ONE_MB  (1024*1024)
+
+unsigned convertBytesToMB( uint64_t  size )
+{
+    if (size == 0)
+        return 0;
+
+    size = (size + ONE_MB-1) >> 20;
+    if (size > UINT_MAX)
+        size = UINT_MAX;
+
+    return (unsigned) size;
+}
+
+uint64_t  convertMBToBytes( unsigned  megaBytes )
+{
+    return ((uint64_t)megaBytes << 20);
+}
 
 /***********************************************************************/
 /***********************************************************************/
@@ -330,7 +370,17 @@
     emulator->aconfig     = aconfig;
     emulator->layout_file = skin_file_create_from_aconfig(aconfig, basepath);
     emulator->layout      = emulator->layout_file->layouts;
-    emulator->keyboard    = skin_keyboard_create_from_aconfig(aconfig, opts->raw_keys);
+    // If we have a custom charmap use it to initialize keyboard.
+    // Otherwise initialize keyboard from configuration settings.
+    // Another way to configure keyboard to use a custom charmap would
+    // be saving a custom charmap name into AConfig's keyboard->charmap
+    // property, and calling single skin_keyboard_create_from_aconfig
+    // routine to initialize keyboard.
+    if (NULL != opts->charmap) {
+        emulator->keyboard = skin_keyboard_create_from_kcm(opts->charmap, opts->raw_keys);
+    } else {
+        emulator->keyboard = skin_keyboard_create_from_aconfig(aconfig, opts->raw_keys);
+    }
     emulator->window      = NULL;
     emulator->win_x       = x;
     emulator->win_y       = y;
@@ -355,40 +405,8 @@
 qemulator_rotate_keycode( QEmulator*      emulator,
                           AndroidKeyCode  sym )
 {
-    switch (skin_layout_get_dpad_rotation(emulator->layout)) {
-        case SKIN_ROTATION_90:
-            switch (sym) {
-                case kKeyCodeDpadLeft:  sym = kKeyCodeDpadDown; break;
-                case kKeyCodeDpadRight: sym = kKeyCodeDpadUp; break;
-                case kKeyCodeDpadUp:    sym = kKeyCodeDpadLeft; break;
-                case kKeyCodeDpadDown:  sym = kKeyCodeDpadRight; break;
-                default: ;
-            }
-            break;
-
-        case SKIN_ROTATION_180:
-            switch (sym) {
-                case kKeyCodeDpadLeft:  sym = kKeyCodeDpadRight; break;
-                case kKeyCodeDpadRight: sym = kKeyCodeDpadLeft; break;
-                case kKeyCodeDpadUp:    sym = kKeyCodeDpadDown; break;
-                case kKeyCodeDpadDown:  sym = kKeyCodeDpadUp; break;
-                default: ;
-            }
-            break;
-
-        case SKIN_ROTATION_270:
-            switch (sym) {
-                case kKeyCodeDpadLeft:  sym = kKeyCodeDpadUp; break;
-                case kKeyCodeDpadRight: sym = kKeyCodeDpadDown; break;
-                case kKeyCodeDpadUp:    sym = kKeyCodeDpadRight; break;
-                case kKeyCodeDpadDown:  sym = kKeyCodeDpadLeft; break;
-                default: ;
-            }
-            break;
-
-        default: ;
-    }
-    return sym;
+    return android_keycode_rotate( sym,
+                                   skin_layout_get_dpad_rotation(emulator->layout) );
 }
 
 static int
@@ -614,13 +632,14 @@
 /* called by the emulated framebuffer device each time the framebuffer
  * is resized or rotated */
 static void
-sdl_resize(DisplayState *ds, int w, int h)
+sdl_resize(DisplayState *ds)
 {
-    fprintf(stderr, "weird, sdl_resize being called with framebuffer interface\n");
-    exit(1);
+    //fprintf(stderr, "weird, sdl_resize being called with framebuffer interface\n");
+    //exit(1);
 }
 
 
+/* called periodically to poll for user input events */
 static void sdl_refresh(DisplayState *ds)
 {
     QEmulator*     emulator = ds->opaque;
@@ -890,21 +909,30 @@
 {
     QEmulator*    emulator = qemulator;
     SkinDisplay*  disp     = skin_layout_get_display(emulator->layout);
-
-//    fprintf(stderr,"*** sdl_display_init ***\n");
-    ds->opaque = emulator;
+    DisplayChangeListener*  dcl;
+    int           width, height;
 
     if (disp->rotation & 1) {
-        ds->width  = disp->rect.size.h;
-        ds->height = disp->rect.size.w;
+        width  = disp->rect.size.h;
+        height = disp->rect.size.w;
     } else {
-        ds->width  = disp->rect.size.w;
-        ds->height = disp->rect.size.h;
+        width  = disp->rect.size.w;
+        height = disp->rect.size.h;
     }
 
-    ds->dpy_update  = sdl_update;
-    ds->dpy_resize  = sdl_resize;
-    ds->dpy_refresh = sdl_refresh;
+    /* Register a display state object for the emulated framebuffer */
+    ds->allocator = &default_allocator;
+    ds->opaque    = emulator;
+    ds->surface   = qemu_create_displaysurface(ds, width, height);
+    register_displaystate(ds);
+
+    /* Register a change listener for it */
+    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl->dpy_update      = sdl_update;
+    dcl->dpy_resize      = sdl_resize;
+    dcl->dpy_refresh     = sdl_refresh;
+    dcl->dpy_text_cursor = NULL;
+    register_displaychangelistener(ds, dcl);
 
     skin_keyboard_enable( emulator->keyboard, 1 );
     skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
@@ -1077,6 +1105,7 @@
         if (userConfig)
             auserConfig_getWindowPos(userConfig, &win_x, &win_y);
     }
+
     if ( qemulator_init( qemulator, root, path, win_x, win_y, opts ) < 0 ) {
         fprintf(stderr, "### Error: could not load emulator skin '%s'\n", name);
         exit(1);
@@ -1721,6 +1750,35 @@
     android_avdParams->forcePaths[imageType] = path;
 }
 
+static uint64_t
+_adjustPartitionSize( const char*  description,
+                      uint64_t     imageBytes,
+                      uint64_t     defaultBytes,
+                      int          inAndroidBuild )
+{
+    char      temp[64];
+    unsigned  imageMB;
+    unsigned  defaultMB;
+
+    if (imageBytes <= defaultBytes)
+        return defaultBytes;
+
+    imageMB   = convertBytesToMB(imageBytes);
+    defaultMB = convertBytesToMB(defaultBytes);
+
+    if (imageMB > defaultMB) {
+        snprintf(temp, sizeof temp, "(%d MB > %d MB)", imageMB, defaultMB);
+    } else {
+        snprintf(temp, sizeof temp, "(%lld bytes > %lld bytes)", imageBytes, defaultBytes);
+    }
+
+    if (inAndroidBuild) {
+        dwarning("%s partition size adjusted to match image file %s\n", description, temp);
+    }
+
+    return convertMBToBytes(imageMB);
+}
+
 #ifdef _WIN32
 #undef main  /* we don't want SDL to define main */
 #endif
@@ -1740,9 +1798,12 @@
     int    shell_serial = 0;
     int    dns_count = 0;
     unsigned  cachePartitionSize = 0;
-    unsigned  defaultPartitionSize = 0x4200000;
+    unsigned  systemPartitionSize = 0;
+    unsigned  dataPartitionSize = 0;
+    unsigned  defaultPartitionSize = convertMBToBytes(66);
 
     AndroidHwConfig*  hw;
+    AvdInfo*          avd;
 
     //const char *appdir = get_app_dir();
     char*       android_build_root = NULL;
@@ -1814,7 +1875,9 @@
             }
     }
 
-    android_charmap = android_charmaps[0];
+    if (android_charmap_setup(opts->charmap)) {
+        exit(1);
+    }
 
     if (opts->version) {
         printf("Android emulator version %s\n"
@@ -2058,9 +2121,11 @@
         }
     }
 
+    avd = android_avdInfo;
+
     /* get the skin from the virtual device configuration */
-    opts->skin    = (char*) avdInfo_getSkinName( android_avdInfo );
-    opts->skindir = (char*) avdInfo_getSkinDir( android_avdInfo );
+    opts->skin    = (char*) avdInfo_getSkinName( avd );
+    opts->skindir = (char*) avdInfo_getSkinDir( avd );
 
     if (opts->skin) {
         D("autoconfig: -skin %s", opts->skin);
@@ -2071,7 +2136,7 @@
 
     /* Read hardware configuration */
     hw = android_hw;
-    if (avdInfo_getHwConfig(android_avdInfo, hw) < 0) {
+    if (avdInfo_getHwConfig(avd, hw) < 0) {
         derror("could not read hardware configuration ?");
         exit(1);
     }
@@ -2203,7 +2268,7 @@
     }
 
     if (opts->trace) {
-        char*   tracePath = avdInfo_getTracePath(android_avdInfo, opts->trace);
+        char*   tracePath = avdInfo_getTracePath(avd, opts->trace);
         int     ret;
 
         if (tracePath == NULL) {
@@ -2264,39 +2329,108 @@
 
     n = 1;
     /* generate arguments for the underlying qemu main() */
-    args[n++] = "-kernel";
-    args[n++] = (char*) avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_KERNEL);
+    {
+        const char*  kernelFile    = avdInfo_getImageFile(avd, AVD_IMAGE_KERNEL);
+        int          kernelFileLen = strlen(kernelFile);
+
+        args[n++] = "-kernel";
+        args[n++] = (char*)kernelFile;
+
+        /* If the kernel image name ends in "-armv7", then change the cpu
+         * type automatically. This is a poor man's approach to configuration
+         * management, but should allow us to get past building ARMv7
+         * system images with dex preopt pass without introducing too many
+         * changes to the emulator sources.
+         *
+         * XXX:
+         * A 'proper' change would require adding some sort of hardware-property
+         * to each AVD config file, then automatically determine its value for
+         * full Android builds (depending on some environment variable), plus
+         * some build system changes. I prefer not to do that for now for reasons
+         * of simplicity.
+         */
+         if (kernelFileLen > 6 && !memcmp(kernelFile + kernelFileLen - 6, "-armv7", 6)) {
+            args[n++] = "-cpu";
+            args[n++] = "cortex-a8";
+         }
+    }
 
     args[n++] = "-initrd";
-    args[n++] = (char*) avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_RAMDISK);
+    args[n++] = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_RAMDISK);
 
     if (opts->partition_size) {
         char*  end;
-        long   size = strtol(opts->partition_size, &end, 0);
-        long   maxSize = LONG_MAX / (1024*1024);
-        long   defaultMB = (defaultPartitionSize + (512*1024)) / (1024*1024);
+        long   sizeMB = strtol(opts->partition_size, &end, 0);
+        long   minSizeMB = 10;
+        long   maxSizeMB = LONG_MAX / ONE_MB;
 
-        if (size < 0 || *end != 0) {
+        if (sizeMB < 0 || *end != 0) {
             derror( "-partition-size must be followed by a positive integer" );
             exit(1);
         }
-        if (size < defaultMB || size > maxSize) {
+        if (sizeMB < minSizeMB || sizeMB > maxSizeMB) {
             derror( "partition-size (%d) must be between %dMB and %dMB",
-                    size, defaultMB, maxSize );
+                    sizeMB, minSizeMB, maxSizeMB );
             exit(1);
         }
-        defaultPartitionSize = size * 1024*1024;
+        defaultPartitionSize = sizeMB * ONE_MB;
+    }
+
+    /* Check the size of the system partition image.
+     * If we have an AVD, it must be smaller than
+     * the disk.systemPartition.size hardware property.
+     *
+     * Otherwise, we need to adjust the systemPartitionSize
+     * automatically, and print a warning.
+     *
+     */
+    {
+        uint64_t   systemBytes  = avdInfo_getImageFileSize(avd, AVD_IMAGE_INITSYSTEM);
+        uint64_t   defaultBytes = defaultPartitionSize;
+
+        if (defaultBytes == 0 || opts->partition_size)
+            defaultBytes = defaultPartitionSize;
+
+        systemPartitionSize = _adjustPartitionSize("system", systemBytes, defaultBytes,
+                                                   android_build_out != NULL);
+    }
+
+    /* Check the size of the /data partition. The only interesting cases here are:
+     * - when the USERDATA image already exists and is larger than the default
+     * - when we're wiping data and the INITDATA is larger than the default.
+     */
+
+    {
+        const char*  dataPath     = avdInfo_getImageFile(avd, AVD_IMAGE_USERDATA);
+        uint64_t     defaultBytes = defaultPartitionSize;
+
+        if (defaultBytes == 0 || opts->partition_size)
+            defaultBytes = defaultPartitionSize;
+
+        if (dataPath == NULL || !path_exists(dataPath) || opts->wipe_data) {
+            dataPath = avdInfo_getImageFile(avd, AVD_IMAGE_INITDATA);
+        }
+        if (dataPath == NULL || !path_exists(dataPath)) {
+            dataPartitionSize = defaultBytes;
+        }
+        else {
+            uint64_t  dataBytes;
+            path_get_size(dataPath, &dataBytes);
+
+            dataPartitionSize = _adjustPartitionSize("data", dataBytes, defaultBytes,
+                                                     android_build_out != NULL);
+        }
     }
 
     {
         const char*  filetype = "file";
 
-        if (avdInfo_isImageReadOnly(android_avdInfo, AVD_IMAGE_INITSYSTEM))
+        if (avdInfo_isImageReadOnly(avd, AVD_IMAGE_INITSYSTEM))
             filetype = "initfile";
 
         bufprint(tmp, tmpend,
-             "system,size=0x%x,%s=%s", defaultPartitionSize, filetype,
-             avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_INITSYSTEM));
+             "system,size=0x%x,%s=%s", systemPartitionSize, filetype,
+             avdInfo_getImageFile(avd, AVD_IMAGE_INITSYSTEM));
 
         args[n++] = "-nand";
         args[n++] = strdup(tmp);
@@ -2304,14 +2438,14 @@
 
     bufprint(tmp, tmpend,
              "userdata,size=0x%x,file=%s",
-             defaultPartitionSize,
-             avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_USERDATA));
+             dataPartitionSize,
+             avdInfo_getImageFile(avd, AVD_IMAGE_USERDATA));
 
     args[n++] = "-nand";
     args[n++] = strdup(tmp);
 
     if (hw->disk_cachePartition) {
-        opts->cache = (char*) avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_CACHE);
+        opts->cache = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_CACHE);
         cachePartitionSize = hw->disk_cachePartition_size;
     }
     else if (opts->cache) {
@@ -2334,7 +2468,7 @@
     }
 
     if (hw->hw_sdCard != 0)
-        opts->sdcard = (char*) avdInfo_getImageFile(android_avdInfo, AVD_IMAGE_SDCARD);
+        opts->sdcard = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_SDCARD);
     else if (opts->sdcard) {
         dwarning( "Emulated hardware doesn't support SD Cards" );
         opts->sdcard = NULL;
@@ -2424,7 +2558,7 @@
         qemud_serial = serial++;
 
         if (opts->radio) {
-            CharDriverState*  cs = qemu_chr_open(opts->radio);
+            CharDriverState*  cs = qemu_chr_open("radio",opts->radio,NULL);
             if (cs == NULL) {
                 derror( "unsupported character device specification: %s\n"
                         "used -help-char-devices for list of available formats\n", opts->radio );
@@ -2440,7 +2574,7 @@
         }
 
         if (opts->gps) {
-            CharDriverState*  cs = qemu_chr_open(opts->gps);
+            CharDriverState*  cs = qemu_chr_open("gps",opts->gps,NULL);
             if (cs == NULL) {
                 derror( "unsupported character device specification: %s\n"
                         "used -help-char-devices for list of available formats\n", opts->gps );
@@ -2501,6 +2635,14 @@
 
     hwLcd_setBootProperty(get_device_dpi(opts));
 
+    /* Set the VM's max heap size, passed as a boot property */
+    if (hw->vm_heapSize > 0) {
+        char  tmp[32], *p=tmp, *end=p + sizeof(tmp);
+        p = bufprint(p, end, "%dm", hw->vm_heapSize);
+
+        boot_property_add("dalvik.vm.heapsize",tmp);
+    }
+
     if (opts->prop != NULL) {
         ParamList*  pl = opts->prop;
         for ( ; pl != NULL; pl = pl->next ) {
@@ -2900,4 +3042,5 @@
 
 void  android_emulation_teardown( void )
 {
+    android_charmap_done();
 }
diff --git a/android/skin/file.c b/android/skin/file.c
index 3d5ea7f..f7f0be9 100644
--- a/android/skin/file.c
+++ b/android/skin/file.c
@@ -424,6 +424,9 @@
 SkinRotation
 skin_layout_get_dpad_rotation( SkinLayout*  layout )
 {
+    if (layout->has_dpad_rotation)
+        return layout->dpad_rotation;
+
     SKIN_LAYOUT_LOOP_LOCS(layout, loc)
         SkinPart*  part = loc->part;
         SKIN_PART_LOOP_BUTTONS(part,button)
@@ -505,6 +508,12 @@
     layout->color = aconfig_unsigned( root, "color", 0x808080 ) | 0xff000000;
     ptail         = &layout->locations;
 
+    node = aconfig_find( root, "dpad-rotation" );
+    if (node != NULL) {
+        layout->dpad_rotation     = aconfig_int( root, "dpad-rotation", 0 );
+        layout->has_dpad_rotation = 1;
+    }
+
     for (node = root->first_child; node; node = node->next)
     {
         if (!memcmp(node->name, "part", 4)) {
diff --git a/android/skin/file.h b/android/skin/file.h
index 8f95368..9f188b9 100644
--- a/android/skin/file.h
+++ b/android/skin/file.h
@@ -75,6 +75,8 @@
     int                 event_type;
     int                 event_code;
     int                 event_value;
+    char                has_dpad_rotation;
+    SkinRotation        dpad_rotation;
     SkinSize            size;
     SkinLocation*       locations;
 } SkinLayout;
diff --git a/android/skin/keyboard.c b/android/skin/keyboard.c
index 0c499df..e3537f1 100644
--- a/android/skin/keyboard.c
+++ b/android/skin/keyboard.c
@@ -578,35 +578,28 @@
     }
 }
 
-
-SkinKeyboard*
-skin_keyboard_create_from_aconfig( AConfig*  aconfig, int  use_raw_keys )
+static SkinKeyboard*
+skin_keyboard_create_from_charmap_name(const char*  charmap_name,
+                                       int  use_raw_keys)
 {
     SkinKeyboard*  kb;
-    const char*    charmap_name = "qwerty";
-    AConfig*       node;
+    int  nn;
 
     ANEW0(kb);
 
-    node = aconfig_find( aconfig, "keyboard" );
-    if (node != NULL)
-        charmap_name = aconfig_str(node, "charmap", charmap_name);
-
-    {
-        int  nn;
-
-        for (nn = 0; nn < android_charmap_count; nn++) {
-            if ( !strcmp(android_charmaps[nn]->name, charmap_name) ) {
-                kb->charmap = android_charmaps[nn];
-                break;
-            }
+    // Find charmap by its name in the array of available charmaps.
+    for (nn = 0; nn < android_charmap_count; nn++) {
+        if (!strcmp(android_charmaps[nn]->name, charmap_name)) {
+            kb->charmap = android_charmaps[nn];
+            break;
         }
+    }
 
-        if (!kb->charmap) {
-            fprintf(stderr, "### warning, skin requires unknown '%s' charmap, reverting to '%s'\n",
-                    charmap_name, android_charmaps[0]->name );
-            kb->charmap = android_charmaps[0];
-        }
+    if (!kb->charmap) {
+        // Charmap name was not found. Default to the first charmap in the array.
+        fprintf(stderr, "### warning, skin requires unknown '%s' charmap, reverting to '%s'\n",
+                charmap_name, android_charmaps[0]->name );
+        kb->charmap = android_charmaps[0];
     }
     kb->raw_keys = use_raw_keys;
     kb->enabled  = 0;
@@ -620,6 +613,26 @@
     return kb;
 }
 
+SkinKeyboard*
+skin_keyboard_create_from_aconfig( AConfig*  aconfig, int  use_raw_keys )
+{
+    const char*    charmap_name = "qwerty";
+    AConfig*       node = aconfig_find( aconfig, "keyboard" );
+    if (node != NULL) {
+        charmap_name = aconfig_str(node, "charmap", charmap_name);
+    }
+    return skin_keyboard_create_from_charmap_name(charmap_name, use_raw_keys);
+}
+
+SkinKeyboard*
+skin_keyboard_create_from_kcm( const char*  kcm_file_path, int  use_raw_keys )
+{
+    char charmap_name[AKEYCHARMAP_NAME_SIZE];
+    kcm_extract_charmap_name(kcm_file_path, charmap_name,
+                             sizeof(charmap_name));
+    return skin_keyboard_create_from_charmap_name(charmap_name, use_raw_keys);
+}
+
 void
 skin_keyboard_free( SkinKeyboard*  keyboard )
 {
diff --git a/android/skin/keyboard.h b/android/skin/keyboard.h
index 45efd18..a86b132 100644
--- a/android/skin/keyboard.h
+++ b/android/skin/keyboard.h
@@ -26,6 +26,8 @@
 
 extern SkinKeyboard*  skin_keyboard_create_from_aconfig( AConfig*  aconfig, int  use_raw_keys );
 
+extern SkinKeyboard*  skin_keyboard_create_from_kcm( const char*  kcm_file_path, int  use_raw_keys );
+
 extern void           skin_keyboard_set_keyset( SkinKeyboard*  keyboard, SkinKeyset*  kset );
 
 extern const char*    skin_keyboard_charmap_name( SkinKeyboard*  keyboard );
@@ -42,6 +44,9 @@
 extern void           skin_keyboard_set_rotation( SkinKeyboard*     keyboard,
                                                   SkinRotation      rotation );
 
+extern AndroidKeyCode skin_keyboard_rotate_keycode( SkinKeyboard*   keyboard,
+                                                    AndroidKeyCode  keycode );
+
 extern void           skin_keyboard_on_key_press( SkinKeyboard*     keyboard,
                                                   SkinKeyEventFunc  press_func,
                                                   void*             press_opaque );
diff --git a/android/skin/window.c b/android/skin/window.c
index 674b594..24baaa6 100644
--- a/android/skin/window.c
+++ b/android/skin/window.c
@@ -14,6 +14,7 @@
 #include "android/skin/scaler.h"
 #include "android/charmap.h"
 #include "android/utils/debug.h"
+#include "android/utils/system.h"
 #include "android/hw-sensors.h"
 #include <SDL_syswm.h>
 #include "qemu-common.h"
@@ -523,7 +524,7 @@
 }
 
 static void
-button_init( Button*  button, SkinButton*  sbutton, SkinLocation*  loc, Background*  back, SkinRect*  frame )
+button_init( Button*  button, SkinButton*  sbutton, SkinLocation*  loc, Background*  back, SkinRect*  frame, SkinLayout*  slayout )
 {
     SkinRect  r;
 
@@ -532,6 +533,14 @@
     button->keycode    = sbutton->keycode;
     button->down       = 0;
 
+    if (slayout->has_dpad_rotation) {
+        /* Dpad keys must be rotated if the skin provides a 'dpad-rotation' field.
+         * this is used as a counter-measure to the fact that the framework always assumes
+         * that the physical D-Pad has been rotated when in landscape mode.
+         */
+        button->keycode = android_keycode_rotate( button->keycode, -slayout->dpad_rotation );
+    }
+
     skin_rect_rotate( &r, &sbutton->rect, loc->rotation );
     r.pos.x += loc->anchor.x;
     r.pos.y += loc->anchor.y;
@@ -759,9 +768,9 @@
     layout->num_displays    = n_displays;
 
     /* now allocate arrays, then populate them */
-    layout->buttons     = qemu_mallocz( sizeof(Button) *     n_buttons );
-    layout->backgrounds = qemu_mallocz( sizeof(Background) * n_backgrounds );
-    layout->displays    = qemu_mallocz( sizeof(ADisplay) *    n_displays );
+    AARRAY_NEW0(layout->buttons,     n_buttons);
+    AARRAY_NEW0(layout->backgrounds, n_backgrounds);
+    AARRAY_NEW0(layout->displays,    n_displays);
 
     if (layout->buttons == NULL && n_buttons > 0) goto Fail;
     if (layout->backgrounds == NULL && n_backgrounds > 0) goto Fail;
@@ -792,7 +801,7 @@
 
         SKIN_PART_LOOP_BUTTONS(part, sbutton)
             Button*  button = layout->buttons + n_buttons;
-            button_init( button, sbutton, loc, back, &layout->rect );
+            button_init( button, sbutton, loc, back, &layout->rect, slayout );
             n_buttons += 1;
         SKIN_PART_LOOP_END
     SKIN_LAYOUT_LOOP_END
@@ -1013,7 +1022,9 @@
 SkinWindow*
 skin_window_create( SkinLayout*  slayout, int  x, int  y, double  scale, int  no_display )
 {
-    SkinWindow*  window = qemu_mallocz(sizeof(*window));
+    SkinWindow*  window;
+
+    ANEW0(window);
 
     window->shrink_scale = scale;
     window->shrink       = (scale != 1.0);
@@ -1165,7 +1176,7 @@
             window_h = (int) ceil(window_h / scale );
 
             window->shrink_surface = surface;
-            window->shrink_pixels  = qemu_mallocz( window_w * window_h * 4 );
+            AARRAY_NEW0(window->shrink_pixels, window_w * window_h * 4);
             if (window->shrink_pixels == NULL) {
                 fprintf(stderr, "### Error: could not allocate memory for rescaling surface\n");
                 exit(1);
diff --git a/android/tools/gen-hw-config.py b/android/tools/gen-hw-config.py
index 928ccc5..3822485 100755
--- a/android/tools/gen-hw-config.py
+++ b/android/tools/gen-hw-config.py
@@ -43,12 +43,17 @@
 targetHeader = """\
 /* this file is automatically generated from 'hardware-properties.ini'
  * DO NOT EDIT IT. To re-generate it, use android/tools/gen-hw-config.py'
- */"""
+ */
+"""
 
 # locate source and target
 programDir = os.path.dirname(sys.argv[0])
-sourceFile = os.path.normpath(os.path.join(programDir,relativeSourcePath))
-targetFile = os.path.normpath(os.path.join(programDir,relativeTargetPath))
+if len(sys.argv) != 3:
+    print "Usage: %s source target\n" % os.path.basename(sys.argv[0])
+    sys.exit(1)
+
+sourceFile = sys.argv[1]
+targetFile = sys.argv[2]
 
 # parse the source file and record items
 # I would love to use Python's ConfigParser, but it doesn't
@@ -94,16 +99,21 @@
 if lastItem:
     items.append(lastItem)
 
+if targetFile == '--':
+    out = sys.stdout
+else:
+    out = open(targetFile,"wb")
 
-print  targetHeader
+out.write(targetHeader)
 
 # write guards to prevent bad compiles
 for m in macroNames:
-    print """\
+    out.write("""\
 #ifndef %(macro)s
 #error  %(macro)s not defined
-#endif""" % { 'macro':m }
-print ""
+#endif
+""" % { 'macro':m })
+out.write("\n")
 
 for item in items:
     if item.type == None:
@@ -131,11 +141,12 @@
         # quote default value for strings
         varDefault = quoteStringForC(varDefault)
 
-    print "%s(\n  %s,\n  %s,\n  %s,\n  %s,\n  %s)\n" % \
-            (varMacro,varName,varNameStr,varDefault,varAbstract,varDesc)
+    out.write("%s(\n  %s,\n  %s,\n  %s,\n  %s,\n  %s)\n\n" % \
+            (varMacro,varName,varNameStr,varDefault,varAbstract,varDesc))
 
 
 for m in macroNames:
-    print "#undef %s" % m
+    out.write("#undef %s\n" % m)
 
-print "/* end of auto-generated file */"
+out.write("/* end of auto-generated file */\n")
+out.close()
diff --git a/arm-dis.c b/arm-dis.c
index ee44292..cc42576 100644
--- a/arm-dis.c
+++ b/arm-dis.c
@@ -1554,32 +1554,6 @@
 int last_mapping_sym = -1;
 bfd_vma last_mapping_addr = 0;
 
-
-/* Functions.  */
-int
-get_arm_regname_num_options (void)
-{
-  return NUM_ARM_REGNAMES;
-}
-
-int
-set_arm_regname_option (int option)
-{
-  int old = regname_selected;
-  regname_selected = option;
-  return old;
-}
-
-int
-get_arm_regnames (int option, const char **setname, const char **setdescription,
-		  const char *const **register_names)
-{
-  *setname = regnames[option].name;
-  *setdescription = regnames[option].description;
-  *register_names = regnames[option].reg_names;
-  return 16;
-}
-
 /* Decode a bitfield of the form matching regexp (N(-N)?,)*N(-N)?.
    Returns pointer to following character of the format string and
    fills in *VALUEP and *WIDTHP with the extracted value and number of
@@ -4144,22 +4118,3 @@
     }
   return size;
 }
-
-void
-print_arm_disassembler_options (FILE *stream)
-{
-  int i;
-
-  fprintf (stream, _("\n\
-The following ARM specific disassembler options are supported for use with\n\
-the -M switch:\n"));
-
-  for (i = NUM_ARM_REGNAMES; i--;)
-    fprintf (stream, "  reg-names-%s %*c%s\n",
-	     regnames[i].name,
-	     (int)(14 - strlen (regnames[i].name)), ' ',
-	     regnames[i].description);
-
-  fprintf (stream, "  force-thumb              Assume all insns are Thumb insns\n");
-  fprintf (stream, "  no-force-thumb           Examine preceeding label to determine an insn's type\n\n");
-}
diff --git a/arm-semi.c b/arm-semi.c
index cd77d1d..a33b8e5 100644
--- a/arm-semi.c
+++ b/arm-semi.c
@@ -16,7 +16,8 @@
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
  */
 
 #include <sys/types.h>
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 1cc4d6e..1ae42b6 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -23,6 +23,7 @@
  * THE SOFTWARE.
  */
 #include <alsa/asoundlib.h>
+#include "qemu-common.h"
 #include "audio.h"
 
 #define AUDIO_CAP "alsa"
@@ -92,10 +93,10 @@
 
 /* these are inlined functions in the original headers */
 #define FF_snd_pcm_hw_params_alloca(ptr) \
-    do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(FF(snd_pcm_hw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_hw_params_sizeof)()); } while (0)
+    do { *ptr = (snd_pcm_hw_params_t *) alloca(FF(snd_pcm_hw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_hw_params_sizeof)()); } while (0)
 
 #define FF_snd_pcm_sw_params_alloca(ptr) \
-    do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(FF(snd_pcm_sw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_sw_params_sizeof)()); } while (0)
+    do { *ptr = (snd_pcm_sw_params_t *) alloca(FF(snd_pcm_sw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_sw_params_sizeof)()); } while (0)
 
 static void*  alsa_lib;
 
@@ -600,7 +601,7 @@
     int rpos, live, decr;
     int samples;
     uint8_t *dst;
-    st_sample_t *src;
+    struct st_sample *src;
     snd_pcm_sframes_t avail;
 
     live = audio_pcm_hw_get_live_out (hw);
@@ -685,13 +686,13 @@
     }
 }
 
-static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
     struct alsa_params_req req;
     struct alsa_params_obt obt;
     snd_pcm_t *handle;
-    audsettings_t obt_as;
+    struct audsettings obt_as;
     int  result = -1;
 
     /* shut alsa debug spew */
@@ -776,13 +777,13 @@
     return -1;
 }
 
-static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
+static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
 {
     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
     struct alsa_params_req req;
     struct alsa_params_obt obt;
     snd_pcm_t *handle;
-    audsettings_t obt_as;
+    struct audsettings obt_as;
     int result = -1;
 
     /* shut alsa debug spew */
@@ -887,7 +888,7 @@
 
     for (i = 0; i < 2; ++i) {
         void *src;
-        st_sample_t *dst;
+        struct st_sample *dst;
         snd_pcm_sframes_t nread;
         snd_pcm_uframes_t len;
 
diff --git a/audio/audio.c b/audio/audio.c
index 5a77dac..fbc8431 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -24,7 +24,7 @@
  */
 #include "hw/hw.h"
 #include "audio.h"
-#include "console.h"
+#include "monitor.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
 
@@ -146,14 +146,14 @@
     int enabled;
     int nb_voices;
     int greedy;
-    audsettings_t settings;
+    struct audsettings settings;
 };
 
 static struct {
     struct fixed_settings fixed_out;
     struct fixed_settings fixed_in;
     union {
-        int hz;
+        int hertz;
         int64_t ticks;
     } period;
     int plive;
@@ -183,14 +183,14 @@
         }
     },
 
-    { 0 },                      /* period */
+    { 250 },                    /* period */
     0,                          /* plive */
     0                           /* log_to_monitor */
 };
 
-AudioState glob_audio_state;
+static AudioState glob_audio_state;
 
-volume_t nominal_volume = {
+struct mixeng_volume nominal_volume = {
     0,
 #ifdef FLOAT_MIXENG
     1.0,
@@ -296,8 +296,8 @@
 static char *audio_alloc_prefix (const char *s)
 {
     const char qemu_prefix[] = "QEMU_";
-    size_t len;
-    char *r;
+    size_t len, i;
+    char *r, *u;
 
     if (!s) {
         return NULL;
@@ -306,17 +306,15 @@
     len = strlen (s);
     r = qemu_malloc (len + sizeof (qemu_prefix));
 
-    if (r) {
-        size_t i;
-        char *u = r + sizeof (qemu_prefix) - 1;
+    u = r + sizeof (qemu_prefix) - 1;
 
-        strcpy (r, qemu_prefix);
-        strcat (r, s);
+    pstrcpy (r, len + sizeof (qemu_prefix), qemu_prefix);
+    pstrcat (r, len + sizeof (qemu_prefix), s);
 
-        for (i = 0; i < len; ++i) {
-            u[i] = toupper (u[i]);
-        }
+    for (i = 0; i < len; ++i) {
+        u[i] = qemu_toupper(u[i]);
     }
+
     return r;
 }
 
@@ -433,10 +431,10 @@
 {
     if (conf.log_to_monitor) {
         if (cap) {
-            term_printf ("%s: ", cap);
+            monitor_printf(cur_mon, "%s: ", cap);
         }
 
-        term_vprintf (fmt, ap);
+        monitor_vprintf(cur_mon, fmt, ap);
     }
     else {
         if (!VERBOSE_CHECK(audio))
@@ -536,7 +534,7 @@
 {
     char *optname;
     const char qemu_prefix[] = "QEMU_";
-    size_t preflen;
+    size_t preflen, optlen;
 
     if (audio_bug (AUDIO_FUNC, !prefix)) {
         dolog ("prefix = NULL\n");
@@ -564,21 +562,17 @@
         /* len of opt->name + len of prefix + size of qemu_prefix
          * (includes trailing zero) + zero + underscore (on behalf of
          * sizeof) */
-        optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1);
-        if (!optname) {
-            dolog ("Could not allocate memory for option name `%s'\n",
-                   opt->name);
-            continue;
-        }
+        optlen = len + preflen + sizeof (qemu_prefix) + 1;
+        optname = qemu_malloc (optlen);
 
-        strcpy (optname, qemu_prefix);
+        pstrcpy (optname, optlen, qemu_prefix);
 
         /* copy while upper-casing, including trailing zero */
         for (i = 0; i <= preflen; ++i) {
-            optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]);
+            optname[i + sizeof (qemu_prefix) - 1] = qemu_toupper(prefix[i]);
         }
-        strcat (optname, "_");
-        strcat (optname, opt->name);
+        pstrcat (optname, optlen, "_");
+        pstrcat (optname, optlen, opt->name);
 
         def = 1;
         switch (opt->tag) {
@@ -618,7 +612,7 @@
     }
 }
 
-static void audio_print_settings (audsettings_t *as)
+static void audio_print_settings (struct audsettings *as)
 {
     dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
 
@@ -635,6 +629,12 @@
     case AUD_FMT_U16:
         AUD_log (NULL, "U16");
         break;
+    case AUD_FMT_S32:
+        AUD_log (NULL, "S32");
+        break;
+    case AUD_FMT_U32:
+        AUD_log (NULL, "U32");
+        break;
     default:
         AUD_log (NULL, "invalid(%d)", as->fmt);
         break;
@@ -655,7 +655,7 @@
     AUD_log (NULL, "\n");
 }
 
-static int audio_validate_settings (audsettings_t *as)
+static int audio_validate_settings (struct audsettings *as)
 {
     int invalid;
 
@@ -679,7 +679,7 @@
     return invalid ? -1 : 0;
 }
 
-static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
+static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
 {
     int bits = 8, sign = 0;
 
@@ -694,6 +694,7 @@
     case AUD_FMT_U16:
         bits = 16;
         break;
+
     case AUD_FMT_S32:
         sign = 1;
     case AUD_FMT_U32:
@@ -707,7 +708,7 @@
         && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
 }
 
-void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
+void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
 {
     int bits = 8, sign = 0, shift = 0;
 
@@ -802,8 +803,8 @@
 /*
  * Capture
  */
-static void noop_conv (st_sample_t *dst, const void *src,
-                       int samples, volume_t *vol)
+static void noop_conv (struct st_sample *dst, const void *src,
+                       int samples, struct mixeng_volume *vol)
 {
     (void) src;
     (void) dst;
@@ -812,11 +813,11 @@
 }
 
 static CaptureVoiceOut *audio_pcm_capture_find_specific (
-    AudioState *s,
-    audsettings_t *as
+    struct audsettings *as
     )
 {
     CaptureVoiceOut *cap;
+    AudioState *s = &glob_audio_state;
 
     for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
         if (audio_pcm_info_eq (&cap->hw.info, as)) {
@@ -891,8 +892,9 @@
     }
 }
 
-static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
+static int audio_attach_capture (HWVoiceOut *hw)
 {
+    AudioState *s = &glob_audio_state;
     CaptureVoiceOut *cap;
 
     audio_detach_capture (hw);
@@ -989,7 +991,7 @@
 {
     HWVoiceIn *hw = sw->hw;
     int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
-    st_sample_t *src, *dst = sw->buf;
+    struct st_sample *src, *dst = sw->buf;
 
     rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
 
@@ -1236,6 +1238,7 @@
 
     hw = sw->hw;
     if (sw->active != on) {
+        AudioState *s = &glob_audio_state;
         SWVoiceOut *temp_sw;
         SWVoiceCap *sc;
 
@@ -1243,9 +1246,11 @@
             hw->pending_disable = 0;
             if (!hw->enabled) {
                 hw->enabled = 1;
+                if (s->vm_running) {
                 BEGIN_NOSIGALRM
                     hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
                 END_NOSIGALRM
+                }
             }
         }
         else {
@@ -1281,14 +1286,17 @@
 
     hw = sw->hw;
     if (sw->active != on) {
+        AudioState *s = &glob_audio_state;
         SWVoiceIn *temp_sw;
 
         if (on) {
             if (!hw->enabled) {
                 hw->enabled = 1;
+                if (s->vm_running) {
                 BEGIN_NOSIGALRM
                     hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
                 END_NOSIGALRM
+                }
             }
             sw->total_hw_samples_acquired = hw->total_samples_captured;
         }
@@ -1404,7 +1412,7 @@
     HWVoiceOut *hw = NULL;
     SWVoiceOut *sw;
 
-    while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
+    while ((hw = audio_pcm_hw_find_any_enabled_out (hw))) {
         int played;
         int live, free, nb_live, cleanup_required, prev_rpos;
 
@@ -1503,7 +1511,7 @@
 #ifdef DEBUG_PLIVE
                     dolog ("Finishing with old voice\n");
 #endif
-                    audio_close_out (s, sw);
+                    audio_close_out (sw);
                 }
                 sw = sw1;
             }
@@ -1515,7 +1523,7 @@
 {
     HWVoiceIn *hw = NULL;
 
-    while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) {
+    while ((hw = audio_pcm_hw_find_any_enabled_in (hw))) {
         SWVoiceIn *sw;
         int captured, min;
 
@@ -1556,7 +1564,7 @@
         while (live) {
             int left = hw->samples - rpos;
             int to_capture = audio_MIN (live, left);
-            st_sample_t *src;
+            struct st_sample *src;
             struct capture_callback *cb;
 
             src = hw->mix_buf + rpos;
@@ -1591,7 +1599,7 @@
 
 static void audio_timer (void *opaque)
 {
-    AudioState* s = opaque;
+    AudioState *s = opaque;
 #if 0
 #define  MAX_DIFFS  1000
     int64_t         now  = qemu_get_clock(vm_clock);
@@ -1662,7 +1670,7 @@
      "Number of voices for ADC", NULL, 0},
 
     /* Misc */
-    {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz,
+    {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hertz,
      "Timer period in HZ (0 - use lowest possible)", NULL, 0},
 
     {"PLIVE", AUD_OPT_BOOL, &conf.plive,
@@ -1698,7 +1706,7 @@
     size_t i;
 
     audio_process_options ("AUDIO", audio_options);
-    for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+    for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
         struct audio_driver *d = drvtab[i];
         if (d->options) {
             audio_process_options (d->name, d->options);
@@ -1711,7 +1719,7 @@
 
     printf ("Available drivers:\n");
 
-    for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+    for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
         struct audio_driver *d = drvtab[i];
 
         printf ("Name: %s\n", d->name);
@@ -1773,8 +1781,8 @@
     END_NOSIGALRM
 
     if (opaque != NULL) {
-        audio_init_nb_voices_out (s, drv);
-        audio_init_nb_voices_in (s, drv);
+        audio_init_nb_voices_out (drv);
+        audio_init_nb_voices_in (drv);
         if (out) {
             s->drv_out         = drv;
             s->drv_out_opaque  = opaque;
@@ -1790,19 +1798,21 @@
     }
 }
 
-static void audio_vm_change_state_handler (void *opaque, int running)
+static void audio_vm_change_state_handler (void *opaque, int running,
+                                           int reason)
 {
     AudioState *s = opaque;
     HWVoiceOut *hwo = NULL;
     HWVoiceIn *hwi = NULL;
     int op = running ? VOICE_ENABLE : VOICE_DISABLE;
 
+    s->vm_running = running;
     BEGIN_NOSIGALRM
-        while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
+        while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
             hwo->pcm_ops->ctl_out (hwo, op);
         }
 
-        while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
+        while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
             hwi->pcm_ops->ctl_in (hwi, op);
         }
     END_NOSIGALRM
@@ -1821,7 +1831,7 @@
     initialized = 0;
 
     BEGIN_NOSIGALRM
-    while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
+    while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
         SWVoiceCap *sc;
 
         hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
@@ -1837,7 +1847,7 @@
         }
     }
 
-    while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
+    while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
         hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
         hwi->pcm_ops->fini_in (hwi);
     }
@@ -1869,21 +1879,6 @@
     return 0;
 }
 
-void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card)
-{
-    card->audio = s;
-    card->name = qemu_strdup (name);
-    memset (&card->entries, 0, sizeof (card->entries));
-    LIST_INSERT_HEAD (&s->card_head, card, entries);
-}
-
-void AUD_remove_card (QEMUSoundCard *card)
-{
-    LIST_REMOVE (card, entries);
-    card->audio = NULL;
-    qemu_free (card->name);
-}
-
 static int
 find_audio_driver( AudioState*  s, int  out )
 {
@@ -1946,10 +1941,14 @@
 }
 
 
-AudioState *AUD_init (void)
+static void audio_init (void)
 {
     AudioState *s = &glob_audio_state;
 
+    if (s->drv_out && s->drv_in) {
+        return;
+    }
+
     LIST_INIT (&s->hw_head_out);
     LIST_INIT (&s->hw_head_in);
     LIST_INIT (&s->cap_head);
@@ -1958,7 +1957,7 @@
     s->ts = qemu_new_timer (vm_clock, audio_timer, s);
     if (!s->ts) {
         dolog ("Could not create audio timer\n");
-        return NULL;
+        return;
     }
 
     audio_process_options ("AUDIO", audio_options);
@@ -1978,32 +1977,29 @@
         s->nb_hw_voices_in = 0;
     }
 
-    if ( find_audio_driver (s, 0) == 0 &&
-         find_audio_driver (s, 1) == 0 )
-    {
-        VMChangeStateEntry *e;
-
-        if (conf.period.hz <= 0) {
-            if (conf.period.hz < 0) {
-                dolog ("warning: Timer period is negative - %d "
-                       "treating as zero\n",
-                       conf.period.hz);
-            }
-            conf.period.ticks = 1;
-        }
-        else {
-            conf.period.ticks = ticks_per_sec / conf.period.hz;
-        }
-
-        e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
-        if (!e) {
-            dolog ("warning: Could not register change state handler\n"
-                   "(Audio can continue looping even after stopping the VM)\n");
-        }
-    }
-    else {
+    if ( find_audio_driver (s, 0) != 0 ||
+         find_audio_driver (s, 1) != 0 ) {
         qemu_del_timer (s->ts);
-        return NULL;
+        return;
+    }
+
+    VMChangeStateEntry *e;
+
+    if (conf.period.hertz <= 0) {
+        if (conf.period.hertz < 0) {
+            dolog ("warning: Timer period is negative - %d "
+                   "treating as zero\n",
+                   conf.period.hertz);
+        }
+        conf.period.ticks = 1;
+    } else {
+        conf.period.ticks = ticks_per_sec / conf.period.hertz;
+    }
+
+    e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
+    if (!e) {
+        dolog ("warning: Could not register change state handler\n"
+               "(Audio can continue looping even after stopping the VM)\n");
     }
 
     initialized = 1;
@@ -2011,7 +2007,20 @@
     LIST_INIT (&s->card_head);
     register_savevm ("audio", 0, 1, audio_save, audio_load, s);
     qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
-    return s;
+}
+
+void AUD_register_card (const char *name, QEMUSoundCard *card)
+{
+    audio_init ();
+    card->name = qemu_strdup (name);
+    memset (&card->entries, 0, sizeof (card->entries));
+    LIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
+}
+
+void AUD_remove_card (QEMUSoundCard *card)
+{
+    LIST_REMOVE (card, entries);
+    qemu_free (card->name);
 }
 
 // this was added to work around a deadlock in SDL when quitting
@@ -2021,20 +2030,15 @@
 }
 
 CaptureVoiceOut *AUD_add_capture (
-    AudioState *s,
-    audsettings_t *as,
+    struct audsettings *as,
     struct audio_capture_ops *ops,
     void *cb_opaque
     )
 {
+    AudioState *s = &glob_audio_state;
     CaptureVoiceOut *cap;
     struct capture_callback *cb;
 
-    if (!s) {
-        /* XXX suppress */
-        s = &glob_audio_state;
-    }
-
     if (audio_validate_settings (as)) {
         dolog ("Invalid settings were passed when trying to add capture\n");
         audio_print_settings (as);
@@ -2050,7 +2054,7 @@
     cb->ops = *ops;
     cb->opaque = cb_opaque;
 
-    cap = audio_pcm_capture_find_specific (s, as);
+    cap = audio_pcm_capture_find_specific (as);
     if (cap) {
         LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
         return cap;
@@ -2073,7 +2077,7 @@
         /* XXX find a more elegant way */
         hw->samples = 4096 * 4;
         hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
-                                    sizeof (st_sample_t));
+                                    sizeof (struct st_sample));
         if (!hw->mix_buf) {
             dolog ("Could not allocate capture mix buffer (%d samples)\n",
                    hw->samples);
@@ -2100,8 +2104,8 @@
         LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
 
         hw = NULL;
-        while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
-            audio_attach_capture (s, hw);
+        while ((hw = audio_pcm_hw_find_any_out (hw))) {
+            audio_attach_capture (hw);
         }
         return cap;
 
diff --git a/audio/audio.h b/audio/audio.h
index 2c347bf..208a811 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -45,12 +45,12 @@
 #define AUDIO_HOST_ENDIANNESS 0
 #endif
 
-typedef struct {
+struct audsettings {
     int freq;
     int nchannels;
     audfmt_e fmt;
     int endianness;
-} audsettings_t;
+};
 
 typedef enum {
     AUD_CNOTIFY_ENABLE,
@@ -79,7 +79,6 @@
 typedef struct SWVoiceIn SWVoiceIn;
 
 typedef struct QEMUSoundCard {
-    AudioState *audio;
     char *name;
     LIST_ENTRY (QEMUSoundCard) entries;
 } QEMUSoundCard;
@@ -95,15 +94,11 @@
 #endif
     ;
 
-extern AudioState glob_audio_state;
-
-AudioState *AUD_init (void);
 void AUD_help (void);
-void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
+void AUD_register_card (const char *name, QEMUSoundCard *card);
 void AUD_remove_card (QEMUSoundCard *card);
 CaptureVoiceOut *AUD_add_capture (
-    AudioState *s,
-    audsettings_t *as,
+    struct audsettings *as,
     struct audio_capture_ops *ops,
     void *opaque
     );
@@ -115,7 +110,7 @@
     const char *name,
     void *callback_opaque,
     audio_callback_fn_t callback_fn,
-    audsettings_t *settings
+    struct audsettings *settings
     );
 
 void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
@@ -136,7 +131,7 @@
     const char *name,
     void *callback_opaque,
     audio_callback_fn_t callback_fn,
-    audsettings_t *settings
+    struct audsettings *settings
     );
 
 void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
@@ -173,6 +168,9 @@
 #define audio_MAX(a, b) ((a)<(b)?(b):(a))
 #endif
 
+int wav_start_capture (CaptureState *s, const char *path, int freq,
+                       int bits, int nchannels);
+
 extern int
 audio_get_backend_count( int  is_input );
 
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 6677ec1..54b0f5a 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -78,7 +78,7 @@
     int rpos;
     uint64_t ts_helper;
 
-    st_sample_t *mix_buf;
+    struct st_sample *mix_buf;
 
     int samples;
     LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
@@ -97,7 +97,7 @@
     int total_samples_captured;
     uint64_t ts_helper;
 
-    st_sample_t *conv_buf;
+    struct st_sample *conv_buf;
 
     int samples;
     LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
@@ -106,32 +106,34 @@
 } HWVoiceIn;
 
 struct SWVoiceOut {
+    QEMUSoundCard *card;
     struct audio_pcm_info info;
     t_sample *conv;
     int64_t ratio;
-    st_sample_t *buf;
+    struct st_sample *buf;
     void *rate;
     int total_hw_samples_mixed;
     int active;
     int empty;
     HWVoiceOut *hw;
     char *name;
-    volume_t vol;
+    struct mixeng_volume vol;
     struct audio_callback callback;
     LIST_ENTRY (SWVoiceOut) entries;
 };
 
 struct SWVoiceIn {
+    QEMUSoundCard *card;
     int active;
     struct audio_pcm_info info;
     int64_t ratio;
     void *rate;
     int total_hw_samples_acquired;
-    st_sample_t *buf;
+    struct st_sample *buf;
     f_sample *clip;
     HWVoiceIn *hw;
     char *name;
-    volume_t vol;
+    struct mixeng_volume vol;
     struct audio_callback callback;
     LIST_ENTRY (SWVoiceIn) entries;
 };
@@ -151,13 +153,13 @@
 };
 
 struct audio_pcm_ops {
-    int  (*init_out)(HWVoiceOut *hw, audsettings_t *as);
+    int  (*init_out)(HWVoiceOut *hw, struct audsettings *as);
     void (*fini_out)(HWVoiceOut *hw);
     int  (*run_out) (HWVoiceOut *hw);
     int  (*write)   (SWVoiceOut *sw, void *buf, int size);
     int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
 
-    int  (*init_in) (HWVoiceIn *hw, audsettings_t *as);
+    int  (*init_in) (HWVoiceIn *hw, struct audsettings *as);
     void (*fini_in) (HWVoiceIn *hw);
     int  (*run_in)  (HWVoiceIn *hw);
     int  (*read)    (SWVoiceIn *sw, void *buf, int size);
@@ -196,6 +198,7 @@
     LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
     int nb_hw_voices_out;
     int nb_hw_voices_in;
+    int vm_running;
 };
 
 extern struct audio_driver no_audio_driver;
@@ -204,14 +207,14 @@
 extern struct audio_driver win_audio_driver;
 extern struct audio_driver wav_audio_driver;
 extern struct audio_driver fmod_audio_driver;
-extern struct audio_driver esd_audio_driver;
 extern struct audio_driver alsa_audio_driver;
 extern struct audio_driver coreaudio_audio_driver;
 extern struct audio_driver dsound_audio_driver;
 extern struct audio_driver esd_audio_driver;
-extern volume_t nominal_volume;
+extern struct audio_driver pa_audio_driver;
+extern struct mixeng_volume nominal_volume;
 
-void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
+void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
 
 int  audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 6f8e166..d6c1037 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -36,11 +36,9 @@
 #define HWBUF hw->conv_buf
 #endif
 
-static void glue (audio_init_nb_voices_, TYPE) (
-    AudioState *s,
-    struct audio_driver *drv
-    )
+static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
 {
+    AudioState *s = &glob_audio_state;
     int max_voices = glue (drv->max_voices_, TYPE);
     int voice_size = glue (drv->voice_size_, TYPE);
 
@@ -82,7 +80,7 @@
 
 static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
 {
-    HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
+    HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample));
     if (!HWBUF) {
         dolog ("Could not allocate " NAME " buffer (%d samples)\n",
                hw->samples);
@@ -116,7 +114,7 @@
     samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
 #endif
 
-    sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t));
+    sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample));
     if (!sw->buf) {
         dolog ("Could not allocate buffer for `%s' (%d samples)\n",
                SW_NAME (sw), samples);
@@ -140,7 +138,7 @@
     SW *sw,
     HW *hw,
     const char *name,
-    audsettings_t *as
+    struct audsettings *as
     )
 {
     int err;
@@ -194,8 +192,9 @@
     LIST_REMOVE (sw, entries);
 }
 
-static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp)
+static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
 {
+    AudioState *s = &glob_audio_state;
     HW *hw = *hwp;
 
     if (!hw->sw_head.lh_first) {
@@ -213,14 +212,15 @@
     }
 }
 
-static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw)
+static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
 {
-    return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first;
+    AudioState *s = &glob_audio_state;
+    return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
 }
 
-static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw)
+static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
 {
-    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
+    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
         if (hw->enabled) {
             return hw;
         }
@@ -229,12 +229,11 @@
 }
 
 static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
-    AudioState *s,
     HW *hw,
-    audsettings_t *as
+    struct audsettings *as
     )
 {
-    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
+    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
         if (audio_pcm_info_eq (&hw->info, as)) {
             return hw;
         }
@@ -242,9 +241,10 @@
     return NULL;
 }
 
-static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
+static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
 {
     HW *hw;
+    AudioState *s = &glob_audio_state;
     struct audio_driver *drv = glue(s->drv_, TYPE);
     int  err;
 
@@ -302,7 +302,7 @@
     LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
     glue (s->nb_hw_voices_, TYPE) -= 1;
 #ifdef DAC
-    audio_attach_capture (s, hw);
+    audio_attach_capture (hw);
 #endif
     return hw;
 
@@ -315,39 +315,38 @@
     return NULL;
 }
 
-static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
+static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
 {
     HW *hw;
 
     if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
-        hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as);
+        hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
         if (hw) {
             return hw;
         }
     }
 
-    hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as);
+    hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as);
     if (hw) {
         return hw;
     }
 
-    hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as);
+    hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
     if (hw) {
         return hw;
     }
 
-    return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL);
+    return glue (audio_pcm_hw_find_any_, TYPE) (NULL);
 }
 
 static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
-    AudioState *s,
     const char *sw_name,
-    audsettings_t *as
+    struct audsettings *as
     )
 {
     SW *sw;
     HW *hw;
-    audsettings_t hw_as;
+    struct audsettings hw_as;
 
     if (glue (conf.fixed_, TYPE).enabled) {
         hw_as = glue (conf.fixed_, TYPE).settings;
@@ -363,7 +362,7 @@
         goto err1;
     }
 
-    hw = glue (audio_pcm_hw_add_, TYPE) (s, &hw_as);
+    hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as);
     if (!hw) {
         goto err2;
     }
@@ -378,31 +377,30 @@
 
 err3:
     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
-    glue (audio_pcm_hw_gc_, TYPE) (s, &hw);
+    glue (audio_pcm_hw_gc_, TYPE) (&hw);
 err2:
     qemu_free (sw);
 err1:
     return NULL;
 }
 
-static void glue (audio_close_, TYPE) (AudioState *s, SW *sw)
+static void glue (audio_close_, TYPE) (SW *sw)
 {
     glue (audio_pcm_sw_fini_, TYPE) (sw);
     glue (audio_pcm_hw_del_sw_, TYPE) (sw);
-    glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw);
+    glue (audio_pcm_hw_gc_, TYPE) (&sw->hw);
     qemu_free (sw);
 }
 
 void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
 {
     if (sw) {
-        if (audio_bug (AUDIO_FUNC, !card || !card->audio)) {
-            dolog ("card=%p card->audio=%p\n",
-                   card, card ? card->audio : NULL);
+        if (audio_bug (AUDIO_FUNC, !card)) {
+            dolog ("card=%p\n", card);
             return;
         }
 
-        glue (audio_close_, TYPE) (card->audio, sw);
+        glue (audio_close_, TYPE) (sw);
     }
 }
 
@@ -412,10 +410,10 @@
     const char *name,
     void *callback_opaque ,
     audio_callback_fn_t callback_fn,
-    audsettings_t *as
+    struct audsettings *as
     )
 {
-    AudioState *s;
+    AudioState *s = &glob_audio_state;
 #ifdef DAC
     int live = 0;
     SW *old_sw = NULL;
@@ -424,15 +422,12 @@
     ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
             name, as->freq, as->nchannels, as->fmt);
 
-    if (audio_bug (AUDIO_FUNC,
-                   !card || !card->audio || !name || !callback_fn || !as)) {
-        dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n",
-               card, card ? card->audio : NULL, name, callback_fn, as);
+    if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
+        dolog ("card=%p name=%p callback_fn=%p as=%p\n",
+               card, name, callback_fn, as);
         goto fail;
     }
 
-    s = card->audio;
-
     if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
         audio_print_settings (as);
         goto fail;
@@ -490,7 +485,7 @@
         }
     }
     else {
-        sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as);
+        sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as);
         if (!sw) {
             dolog ("Failed to create voice `%s'\n", name);
             return NULL;
@@ -498,6 +493,7 @@
     }
 
     if (sw) {
+        sw->card = card;
         sw->vol = nominal_volume;
         sw->callback.fn = callback_fn;
         sw->callback.opaque = callback_opaque;
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index f23ebee..8abe0c4 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -283,7 +283,7 @@
 
 static int
 coreaudio_voice_init (coreaudioVoice*    core,
-                      audsettings_t*     as,
+                      struct audsettings*  as,
                       int                frameSize,
                       AudioDeviceIOProc  ioproc,
                       void*              hw,
@@ -510,7 +510,7 @@
     HWVoiceOut *hw = hwptr;
     coreaudioVoice *core = CORE_OUT(hw);
     int rpos, live;
-    st_sample_t *src;
+    struct st_sample *src;
 #ifndef FLOAT_MIXENG
 #ifdef RECIPROCAL
     const float scale = 1.f / UINT_MAX;
@@ -568,7 +568,7 @@
 }
 
 static int
-coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
+coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     coreaudioVoice*  core = CORE_OUT(hw);
     int              err;
@@ -654,7 +654,7 @@
     HWVoiceIn *hw = hwptr;
     coreaudioVoice *core = CORE_IN(hw);
     int wpos, avail;
-    st_sample_t *dst;
+    struct st_sample *dst;
 #ifndef FLOAT_MIXENG
 #ifdef RECIPROCAL
     const float scale = 1.f / UINT_MAX;
@@ -718,7 +718,7 @@
 }
 
 static int
-coreaudio_init_in (HWVoiceIn *hw, audsettings_t *as)
+coreaudio_init_in (HWVoiceIn *hw, struct audsettings *as)
 {
     coreaudioVoice*  core = CORE_IN(hw);
     int              err;
diff --git a/audio/esdaudio.c b/audio/esdaudio.c
index 2226022..1d72125 100644
--- a/audio/esdaudio.c
+++ b/audio/esdaudio.c
@@ -1,7 +1,7 @@
 /*
  * QEMU ESD audio driver
  *
- * Copyright (c) 2008 The Android Open Source Project
+ * Copyright (c) 2008-2009 The Android Open Source Project
  * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,14 +22,13 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-
 #include <esd.h>
+#include "qemu-common.h"
 #include "audio.h"
 #include <signal.h>
 
 #define AUDIO_CAP "esd"
 #include "audio_int.h"
-#include "audio_pt_int.h"
 #include <dlfcn.h>
 
 #include "qemu_debug.h"
@@ -60,7 +59,6 @@
     int rpos;
     void *pcm_buf;
     int fd;
-    struct audio_pt pt;
 } ESDVoiceOut;
 
 typedef struct {
@@ -71,7 +69,6 @@
     int wpos;
     void *pcm_buf;
     int fd;
-    struct audio_pt pt;
 } ESDVoiceIn;
 
 static struct {
@@ -112,128 +109,50 @@
     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
 }
 
-/* playback */
-static void *qesd_thread_out (void *arg)
-{
-    ESDVoiceOut* esd = arg;
-    HWVoiceOut*  hw  = &esd->hw;
-    int threshold;
-    sigset_t  set;
-
-    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
-
-    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
-        return NULL;
-    }
-
-    /* ignore SIGALRM in this thread */
-    sigemptyset(&set);
-    sigaddset(&set, SIGALRM);
-
-    pthread_sigmask( SIG_BLOCK, &set, NULL);
-
-    O("EsounD output thread starting, threshold is %d samples", threshold);
-    for (;;) {
-        int decr, to_mix, rpos;
-
-        for (;;) {
-            if (esd->done) {
-                goto exit;
-            }
-
-            if (esd->live > threshold) {
-                break;
-            }
-
-            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
-                O("EsounD output thread aborting on wait error");
-                goto exit;
-            }
-        }
-
-        decr = to_mix = esd->live;
-        rpos = hw->rpos;
-
-        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
-            O("EsounD output thread aborting on unlock error");
-            return NULL;
-        }
-
-        while (to_mix) {
-            ssize_t written;
-            int chunk = audio_MIN (to_mix, hw->samples - rpos);
-            st_sample_t *src = hw->mix_buf + rpos;
-
-            hw->clip (esd->pcm_buf, src, chunk);
-
-        again:
-            written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
-            if (written == -1) {
-                if (errno == EINTR || errno == EAGAIN) {
-                    goto again;
-                }
-                qesd_logerr (errno, "write failed\n");
-                O("EsounD output thread aborting on write error: %s", strerror(errno));
-                return NULL;
-            }
-
-            if (written != chunk << hw->info.shift) {
-                int wsamples = written >> hw->info.shift;
-                int wbytes = wsamples << hw->info.shift;
-                if (wbytes != written) {
-                    dolog ("warning: Misaligned write %d (requested %d), "
-                           "alignment %d\n",
-                           wbytes, written, hw->info.align + 1);
-                }
-                to_mix -= wsamples;
-                rpos = (rpos + wsamples) % hw->samples;
-                break;
-            }
-
-            rpos = (rpos + chunk) % hw->samples;
-            to_mix -= chunk;
-        }
-
-        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
-            O("EsounD output thread aborting on lock error\n");
-            return NULL;
-        }
-
-        esd->rpos = rpos;
-        esd->live -= decr;
-        esd->decr += decr;
-    }
-    O("EsounD output thread exiting");
-
- exit:
-    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
-    return NULL;
-}
-
 static int qesd_run_out (HWVoiceOut *hw)
 {
-    int live, decr;
     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+    int  liveSamples, totalSamples;
+    int  rpos, nwrite, writeSamples, writeBytes;
 
-    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
-        O("%s: exiting on lock error", __FUNCTION__);
-        return 0;
-    }
+    liveSamples  = audio_pcm_hw_get_live_out (hw);
+    rpos         = hw->rpos;
+    totalSamples = 0;
 
-    live = audio_pcm_hw_get_live_out (hw);
-    decr = audio_MIN (live, esd->decr);
-    esd->decr -= decr;
-    esd->live = live - decr;
-    hw->rpos = esd->rpos;
-    if (esd->live > 0) {
-        O("%s: signaling %d samples\n", __FUNCTION__, esd->live);
-        audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    while (liveSamples > 0) {
+        int  chunkSamples = audio_MIN (liveSamples, hw->samples - rpos);
+        int  chunkBytes   = chunkSamples << hw->info.shift;
+        struct st_sample *src = hw->mix_buf + rpos;
+
+        hw->clip (esd->pcm_buf, src, chunkSamples);
+
+    AGAIN:
+        nwrite = write (esd->fd, esd->pcm_buf, chunkBytes);
+        if (nwrite == -1) {
+            if (errno == EINTR)
+                goto AGAIN;
+            if (errno == EAGAIN || errno == EWOULDBLOCK)
+                break;
+            qesd_logerr (errno, "write failed: %s\n", strerror(errno));
+            O("EsounD output thread write error: %s", strerror(errno));
+            break;
+        }
+        if (nwrite == 0)
+            break;
+
+        writeSamples = nwrite >> hw->info.shift;
+        writeBytes   = writeSamples << hw->info.shift;
+        if (writeBytes != nwrite) {
+            dolog ("warning: Misaligned write %d (requested %d), "
+                    "alignment %d\n",
+                    nwrite, writeBytes, hw->info.align + 1);
+        }
+        rpos          = (rpos + writeSamples) % hw->samples;
+        totalSamples += writeSamples;
+        liveSamples  -= writeSamples;
     }
-    else {
-        O(".");
-        audio_pt_unlock (&esd->pt, AUDIO_FUNC);
-    }
-    return decr;
+    hw->rpos = rpos;
+    return totalSamples;
 }
 
 static int qesd_write (SWVoiceOut *sw, void *buf, int len)
@@ -241,10 +160,10 @@
     return audio_pcm_sw_write (sw, buf, len);
 }
 
-static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
-    audsettings_t obt_as = *as;
+    struct audsettings obt_as = *as;
     int esdfmt = ESD_STREAM | ESD_PLAY;
     int result = -1;
 
@@ -300,20 +219,15 @@
         }
     }
 
-    if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
-        goto fail3;
+    {
+        int  flags;
+        flags = fcntl(esd->fd, F_GETFL);
+        fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK);
     }
 
     result = 0;  /* success */
     goto exit;
 
- fail3:
-    if (close (esd->fd)) {
-        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
-                     AUDIO_FUNC, esd->fd);
-    }
-    esd->fd = -1;
-
  fail2:
     qemu_free (esd->pcm_buf);
     esd->pcm_buf = NULL;
@@ -327,23 +241,14 @@
 
 static void qesd_fini_out (HWVoiceOut *hw)
 {
-    void *ret;
     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
 
-    audio_pt_lock (&esd->pt, AUDIO_FUNC);
-    esd->done = 1;
-    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
-    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
-
     if (esd->fd >= 0) {
         if (close (esd->fd)) {
             qesd_logerr (errno, "failed to close esd socket\n");
         }
         esd->fd = -1;
     }
-
-    audio_pt_fini (&esd->pt, AUDIO_FUNC);
-
     qemu_free (esd->pcm_buf);
     esd->pcm_buf = NULL;
 }
@@ -356,112 +261,56 @@
 }
 
 /* capture */
-static void *qesd_thread_in (void *arg)
-{
-    ESDVoiceIn *esd = arg;
-    HWVoiceIn *hw = &esd->hw;
-    int threshold;
-
-    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
-
-    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
-        return NULL;
-    }
-
-    for (;;) {
-        int incr, to_grab, wpos;
-
-        for (;;) {
-            if (esd->done) {
-                goto exit;
-            }
-
-            if (esd->dead > threshold) {
-                break;
-            }
-
-            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
-                goto exit;
-            }
-        }
-
-        incr = to_grab = esd->dead;
-        wpos = hw->wpos;
-
-        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
-            return NULL;
-        }
-
-        while (to_grab) {
-            ssize_t nread;
-            int chunk = audio_MIN (to_grab, hw->samples - wpos);
-            void *buf = advance (esd->pcm_buf, wpos);
-
-        again:
-            nread = read (esd->fd, buf, chunk << hw->info.shift);
-            if (nread == -1) {
-                if (errno == EINTR || errno == EAGAIN) {
-                    goto again;
-                }
-                qesd_logerr (errno, "read failed\n");
-                return NULL;
-            }
-
-            if (nread != chunk << hw->info.shift) {
-                int rsamples = nread >> hw->info.shift;
-                int rbytes = rsamples << hw->info.shift;
-                if (rbytes != nread) {
-                    dolog ("warning: Misaligned write %d (requested %d), "
-                           "alignment %d\n",
-                           rbytes, nread, hw->info.align + 1);
-                }
-                to_grab -= rsamples;
-                wpos = (wpos + rsamples) % hw->samples;
-                break;
-            }
-
-            hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
-                      &nominal_volume);
-            wpos = (wpos + chunk) % hw->samples;
-            to_grab -= chunk;
-        }
-
-        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
-            return NULL;
-        }
-
-        esd->wpos = wpos;
-        esd->dead -= incr;
-        esd->incr += incr;
-    }
-
- exit:
-    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
-    return NULL;
-}
-
 static int qesd_run_in (HWVoiceIn *hw)
 {
-    int live, incr, dead;
+    int  wpos, liveSamples, totalSamples;
+    int  grabSamples;
     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
 
-    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
-        return 0;
-    }
+    wpos        = hw->wpos;
+    liveSamples = audio_pcm_hw_get_live_in (hw);
+    grabSamples = hw->samples - liveSamples;
+    totalSamples = 0;
 
-    live = audio_pcm_hw_get_live_in (hw);
-    dead = hw->samples - live;
-    incr = audio_MIN (dead, esd->incr);
-    esd->incr -= incr;
-    esd->dead = dead - incr;
-    hw->wpos = esd->wpos;
-    if (esd->dead > 0) {
-        audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+    while (grabSamples > 0) {
+        ssize_t  nread;
+        int      chunkSamples = audio_MIN (grabSamples, hw->samples - wpos);
+        int      chunkBytes   = chunkSamples << hw->info.shift;
+        int      readSamples, readBytes;
+        void*    buf          = advance (esd->pcm_buf, wpos);
+
+    AGAIN:
+        nread = read (esd->fd, buf, chunkBytes);
+        if (nread == -1) {
+            if (errno == EINTR)
+                goto AGAIN;
+            if (errno == EAGAIN || errno == EWOULDBLOCK)
+                break;
+
+            qesd_logerr (errno, "read failed: %s\n", strerror(errno));
+            break;
+        }
+        if (nread == 0)
+            break;
+
+        readSamples = nread >> hw->info.shift;
+        readBytes   = readSamples << hw->info.shift;
+
+        if (readBytes != nread) {
+            dolog ("warning: Misaligned read %d (requested %d), "
+                    "alignment %d\n",
+                    nread, readBytes, hw->info.align + 1);
+        }
+
+        hw->conv (hw->conv_buf + wpos, buf, readSamples,
+                  &nominal_volume);
+
+        wpos = (wpos + readSamples) % hw->samples;
+        grabSamples  -= readSamples;
+        totalSamples += readSamples;
     }
-    else {
-        audio_pt_unlock (&esd->pt, AUDIO_FUNC);
-    }
-    return incr;
+    hw->wpos = wpos;
+    return totalSamples;
 }
 
 static int qesd_read (SWVoiceIn *sw, void *buf, int len)
@@ -469,10 +318,10 @@
     return audio_pcm_sw_read (sw, buf, len);
 }
 
-static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
+static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
 {
     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
-    audsettings_t obt_as = *as;
+    struct audsettings obt_as = *as;
     int esdfmt = ESD_STREAM | ESD_RECORD;
     int result = -1;
 
@@ -493,6 +342,7 @@
         esdfmt |= ESD_BITS16;
         obt_as.fmt = AUD_FMT_S16;
         break;
+
     case AUD_FMT_S32:
     case AUD_FMT_U32:
         dolog ("Will use 16 instead of 32 bit samples\n");
@@ -523,20 +373,15 @@
         }
     }
 
-    if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
-        goto fail3;
+    {
+        int  flags;
+        flags = fcntl(esd->fd, F_GETFL);
+        fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK);
     }
 
     result = 0;  /* success */
     goto exit;
 
- fail3:
-    if (close (esd->fd)) {
-        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
-                     AUDIO_FUNC, esd->fd);
-    }
-    esd->fd = -1;
-
  fail2:
     qemu_free (esd->pcm_buf);
     esd->pcm_buf = NULL;
@@ -550,23 +395,14 @@
 
 static void qesd_fini_in (HWVoiceIn *hw)
 {
-    void *ret;
     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
 
-    audio_pt_lock (&esd->pt, AUDIO_FUNC);
-    esd->done = 1;
-    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
-    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
-
     if (esd->fd >= 0) {
         if (close (esd->fd)) {
             qesd_logerr (errno, "failed to close esd socket\n");
         }
         esd->fd = -1;
     }
-
-    audio_pt_fini (&esd->pt, AUDIO_FUNC);
-
     qemu_free (esd->pcm_buf);
     esd->pcm_buf = NULL;
 }
@@ -652,7 +488,7 @@
     {NULL, 0, NULL, NULL, NULL, 0}
 };
 
-struct audio_pcm_ops qesd_pcm_ops = {
+static struct audio_pcm_ops qesd_pcm_ops = {
     qesd_init_out,
     qesd_fini_out,
     qesd_run_out,
diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c
index e230e8b..0becd3b 100644
--- a/audio/fmodaudio.c
+++ b/audio/fmodaudio.c
@@ -23,6 +23,7 @@
  */
 #include <fmod.h>
 #include <fmod_errors.h>
+#include "qemu-common.h"
 #include "audio.h"
 
 #define AUDIO_CAP "fmod"
@@ -141,8 +142,8 @@
     int src_len1 = dst_len;
     int src_len2 = 0;
     int pos = hw->rpos + dst_len;
-    st_sample_t *src1 = hw->mix_buf + hw->rpos;
-    st_sample_t *src2 = NULL;
+    struct st_sample *src1 = hw->mix_buf + hw->rpos;
+    struct st_sample *src2 = NULL;
 
     if (pos > hw->samples) {
         src_len1 = hw->samples - hw->rpos;
@@ -354,11 +355,11 @@
     }
 }
 
-static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     int bits16, mode, channel;
     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
-    audsettings_t obt_as = *as;
+    struct audsettings obt_as = *as;
 
     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
     fmd->fmod_sample = FSOUND_Sample_Alloc (
@@ -416,11 +417,11 @@
     return 0;
 }
 
-static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
+static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
 {
     int bits16, mode;
     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
-    audsettings_t obt_as = *as;
+    struct audsettings obt_as = *as;
 
     if (conf.broken_adc) {
         return -1;
@@ -563,7 +564,7 @@
 
     if (drv) {
         int found = 0;
-        for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+        for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
             if (!strcmp (drv, drvtab[i].name)) {
                 output_type = drvtab[i].type;
                 found = 1;
@@ -573,7 +574,7 @@
         if (!found) {
             dolog ("Unknown FMOD driver `%s'\n", drv);
             dolog ("Valid drivers:\n");
-            for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+            for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
                 dolog ("  %s\n", drvtab[i].name);
             }
         }
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 34fc6df..8ce942e 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -22,13 +22,12 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include "qemu-common.h"
 #include "audio.h"
 
 #define AUDIO_CAP "mixeng"
 #include "audio_int.h"
 
-#define NOVOL
-
 /* 8 bit */
 #define ENDIAN_CONVERSION natural
 #define ENDIAN_CONVERT(v) (v)
@@ -291,7 +290,7 @@
     uint64_t opos;
     uint64_t opos_inc;
     uint32_t ipos;              /* position in the input stream (integer) */
-    st_sample_t ilast;          /* last sample in the input stream */
+    struct st_sample ilast;          /* last sample in the input stream */
 };
 
 /*
@@ -330,7 +329,7 @@
     qemu_free (opaque);
 }
 
-void mixeng_clear (st_sample_t *buf, int len)
+void mixeng_clear (struct st_sample *buf, int len)
 {
-    memset (buf, 0, len * sizeof (st_sample_t));
+    memset (buf, 0, len * sizeof (struct st_sample));
 }
diff --git a/audio/mixeng.h b/audio/mixeng.h
index 95b68df..4af1dd9 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -25,27 +25,27 @@
 #define QEMU_MIXENG_H
 
 #ifdef FLOAT_MIXENG
-typedef float real_t;
-typedef struct { int mute; real_t r; real_t l; } volume_t;
-typedef struct { real_t l; real_t r; } st_sample_t;
+typedef float mixeng_real;
+struct mixeng_volume { int mute; mixeng_real r; mixeng_real l; };
+struct st_sample { mixeng_real l; mixeng_real r; };
 #else
-typedef struct { int mute; int64_t r; int64_t l; } volume_t;
-typedef struct { int64_t l; int64_t r; } st_sample_t;
+struct mixeng_volume { int mute; int64_t r; int64_t l; };
+struct st_sample { int64_t l; int64_t r; };
 #endif
 
-typedef void (t_sample) (st_sample_t *dst, const void *src,
-                         int samples, volume_t *vol);
-typedef void (f_sample) (void *dst, const st_sample_t *src, int samples);
+typedef void (t_sample) (struct st_sample *dst, const void *src,
+                         int samples, struct mixeng_volume *vol);
+typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
 
 extern t_sample *mixeng_conv[2][2][2][3];
 extern f_sample *mixeng_clip[2][2][2][3];
 
 void *st_rate_start (int inrate, int outrate);
-void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
+void st_rate_flow (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
                    int *isamp, int *osamp);
-void st_rate_flow_mix (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
+void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
                        int *isamp, int *osamp);
 void st_rate_stop (void *opaque);
-void mixeng_clear (st_sample_t *buf, int len);
+void mixeng_clear (struct st_sample *buf, int len);
 
 #endif  /* mixeng.h */
diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h
index d726441..5617705 100644
--- a/audio/mixeng_template.h
+++ b/audio/mixeng_template.h
@@ -31,39 +31,39 @@
 #define HALF (IN_MAX >> 1)
 #endif
 
-#ifdef NOVOL
-#define VOL(a, b) a
-#else
+#ifdef CONFIG_MIXEMU
 #ifdef FLOAT_MIXENG
 #define VOL(a, b) ((a) * (b))
 #else
 #define VOL(a, b) ((a) * (b)) >> 32
 #endif
+#else
+#define VOL(a, b) a
 #endif
 
 #define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
 
 #ifdef FLOAT_MIXENG
-static real_t inline glue (conv_, ET) (IN_T v)
+static mixeng_real inline glue (conv_, ET) (IN_T v)
 {
     IN_T nv = ENDIAN_CONVERT (v);
 
 #ifdef RECIPROCAL
 #ifdef SIGNED
-    return nv * (1.f / (real_t) (IN_MAX - IN_MIN));
+    return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN));
 #else
-    return (nv - HALF) * (1.f / (real_t) IN_MAX);
+    return (nv - HALF) * (1.f / (mixeng_real) IN_MAX);
 #endif
 #else  /* !RECIPROCAL */
 #ifdef SIGNED
-    return nv / (real_t) (IN_MAX - IN_MIN);
+    return nv / (mixeng_real) (IN_MAX - IN_MIN);
 #else
-    return (nv - HALF) / (real_t) IN_MAX;
+    return (nv - HALF) / (mixeng_real) IN_MAX;
 #endif
 #endif
 }
 
-static IN_T inline glue (clip_, ET) (real_t v)
+static IN_T inline glue (clip_, ET) (mixeng_real v)
 {
     if (v >= 0.5) {
         return IN_MAX;
@@ -109,11 +109,11 @@
 #endif
 
 static void glue (glue (conv_, ET), _to_stereo)
-    (st_sample_t *dst, const void *src, int samples, volume_t *vol)
+    (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
 {
-    st_sample_t *out = dst;
+    struct st_sample *out = dst;
     IN_T *in = (IN_T *) src;
-#ifndef NOVOL
+#ifdef CONFIG_MIXEMU
     if (vol->mute) {
         mixeng_clear (dst, samples);
         return;
@@ -129,11 +129,11 @@
 }
 
 static void glue (glue (conv_, ET), _to_mono)
-    (st_sample_t *dst, const void *src, int samples, volume_t *vol)
+    (struct st_sample *dst, const void *src, int samples, struct mixeng_volume *vol)
 {
-    st_sample_t *out = dst;
+    struct st_sample *out = dst;
     IN_T *in = (IN_T *) src;
-#ifndef NOVOL
+#ifdef CONFIG_MIXEMU
     if (vol->mute) {
         mixeng_clear (dst, samples);
         return;
@@ -150,9 +150,9 @@
 }
 
 static void glue (glue (clip_, ET), _from_stereo)
-    (void *dst, const st_sample_t *src, int samples)
+    (void *dst, const struct st_sample *src, int samples)
 {
-    const st_sample_t *in = src;
+    const struct st_sample *in = src;
     IN_T *out = (IN_T *) dst;
     while (samples--) {
         *out++ = glue (clip_, ET) (in->l);
@@ -162,9 +162,9 @@
 }
 
 static void glue (glue (clip_, ET), _from_mono)
-    (void *dst, const st_sample_t *src, int samples)
+    (void *dst, const struct st_sample *src, int samples)
 {
-    const st_sample_t *in = src;
+    const struct st_sample *in = src;
     IN_T *out = (IN_T *) dst;
     while (samples--) {
         *out++ = glue (clip_, ET) (in->l + in->r);
diff --git a/audio/noaudio.c b/audio/noaudio.c
index 8788a41..7451653 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -21,6 +21,8 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include "qemu-common.h"
+#include "audio.h"
 #include "qemu-timer.h"
 
 #define AUDIO_CAP "noaudio"
@@ -66,7 +68,7 @@
     return audio_pcm_sw_write (sw, buf, len);
 }
 
-static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int no_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     audio_pcm_init_info (&hw->info, as);
     hw->samples = 1024;
@@ -85,7 +87,7 @@
     return 0;
 }
 
-static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
+static int no_init_in (HWVoiceIn *hw, struct audsettings *as)
 {
     audio_pcm_init_info (&hw->info, as);
     hw->samples = 1024;
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 2ccaade..f946f79 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -21,10 +21,17 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#ifdef __OpenBSD__
+#include <soundcard.h>
+#else
 #include <sys/soundcard.h>
+#endif
+#include "qemu-common.h"
+#include "audio.h"
 
 #define AUDIO_CAP "oss"
 #include "audio_int.h"
@@ -143,7 +150,7 @@
 {
     switch (ossfmt) {
     case AFMT_S8:
-        *endianness =0;
+        *endianness = 0;
         *fmt = AUD_FMT_S8;
         break;
 
@@ -248,8 +255,8 @@
     }
 
     if (!abinfo.fragstotal || !abinfo.fragsize) {
-        AUD_log(AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
-                abinfo.fragstotal, abinfo.fragsize, typ);
+        AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
+                 abinfo.fragstotal, abinfo.fragsize, typ);
         goto err;
     }
 
@@ -287,7 +294,7 @@
     int err, rpos, live, decr;
     int samples;
     uint8_t *dst;
-    st_sample_t *src;
+    struct st_sample *src;
     struct audio_buf_info abinfo;
     struct count_info cntinfo;
     int bufsize;
@@ -427,7 +434,7 @@
     }
 }
 
-static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
     struct oss_params req, obt;
@@ -435,7 +442,7 @@
     int err;
     int fd;
     audfmt_e effective_fmt;
-    audsettings_t obt_as;
+    struct audsettings obt_as;
 
     oss->fd = -1;
 
@@ -569,7 +576,7 @@
     return 0;
 }
 
-static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
+static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
 {
     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
     struct oss_params req, obt;
@@ -577,7 +584,7 @@
     int err;
     int fd;
     audfmt_e effective_fmt;
-    audsettings_t obt_as;
+    struct audsettings obt_as;
 
     oss->fd = -1;
 
diff --git a/audio/rate_template.h b/audio/rate_template.h
index 398d305..bd4b1c7 100644
--- a/audio/rate_template.h
+++ b/audio/rate_template.h
@@ -27,15 +27,15 @@
  * Processed signed long samples from ibuf to obuf.
  * Return number of samples processed.
  */
-void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
+void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
            int *isamp, int *osamp)
 {
     struct rate *rate = opaque;
-    st_sample_t *istart, *iend;
-    st_sample_t *ostart, *oend;
-    st_sample_t ilast, icur, out;
+    struct st_sample *istart, *iend;
+    struct st_sample *ostart, *oend;
+    struct st_sample ilast, icur, out;
 #ifdef FLOAT_MIXENG
-    real_t t;
+    mixeng_real t;
 #else
     int64_t t;
 #endif
@@ -84,7 +84,7 @@
 #ifdef RECIPROCAL
         t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX);
 #else
-        t = (rate->opos & UINT_MAX) / (real_t) UINT_MAX;
+        t = (rate->opos & UINT_MAX) / (mixeng_real) UINT_MAX;
 #endif
         out.l = (ilast.l * (1.0 - t)) + icur.l * t;
         out.r = (ilast.r * (1.0 - t)) + icur.r * t;
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index ea5bccd..3e88785 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -23,10 +23,14 @@
  */
 #include <SDL.h>
 #include <SDL_thread.h>
+#include "qemu-common.h"
+#include "audio.h"
 
 #ifndef _WIN32
 #ifdef __sun__
 #define _POSIX_PTHREAD_SEMANTICS 1
+#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+#include <pthread.h>
 #endif
 #include <signal.h>
 #endif
@@ -78,7 +82,7 @@
     int decr;
 } SDLVoiceOut;
 
-struct SDLAudioState {
+static struct SDLAudioState {
     int exit;
     SDL_mutex *mutex;
     SDL_sem *sem;
@@ -337,7 +341,7 @@
         decr = to_mix;
         while (to_mix) {
             int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
-            st_sample_t *src = hw->mix_buf + hw->rpos;
+            struct st_sample *src = hw->mix_buf + hw->rpos;
 
             /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
             hw->clip (buf, src, chunk);
@@ -387,7 +391,7 @@
         int           samples   = bytes >> hw->info.shift;
         int           hwsamples = audio_MIN(hw->samples - hw->rpos, live);
         uint8_t*      dst       = s->data + end;
-        st_sample_t*  src       = hw->mix_buf + hw->rpos;
+        struct st_sample*  src  = hw->mix_buf + hw->rpos;
 
         if (samples == 0)
             break;
@@ -509,7 +513,7 @@
 }
 #endif
 
-static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
 {
     SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
     SDLAudioState *s = &glob_sdl;
@@ -518,7 +522,7 @@
     int endianess;
     int err;
     audfmt_e effective_fmt;
-    audsettings_t obt_as;
+    struct audsettings obt_as;
 
     shift <<= as->nchannels == 2;
 
diff --git a/audio/sys-queue.h b/audio/sys-queue.h
deleted file mode 100644
index 5b6e2a0..0000000
--- a/audio/sys-queue.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (c) 1991, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)queue.h	8.3 (Berkeley) 12/13/93
- */
-
-#ifndef	_SYS_QUEUE_H
-#define	_SYS_QUEUE_H 1
-
-/*
- * This file defines three types of data structures: lists, tail queues,
- * and circular queues.
- *
- * A list is headed by a single forward pointer (or an array of forward
- * pointers for a hash table header). The elements are doubly linked
- * so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list after
- * an existing element or at the head of the list. A list may only be
- * traversed in the forward direction.
- *
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list after
- * an existing element, at the head of the list, or at the end of the
- * list. A tail queue may only be traversed in the forward direction.
- *
- * A circle queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or after
- * an existing element, at the head of the list, or at the end of the list.
- * A circle queue may be traversed in either direction, but has a more
- * complex end of list detection.
- *
- * For details on the use of these macros, see the queue(3) manual page.
- */
-
-/*
- * List definitions.
- */
-#define LIST_HEAD(name, type)						\
-struct name {								\
-	struct type *lh_first;	/* first element */			\
-}
-
-#define LIST_ENTRY(type)						\
-struct {								\
-	struct type *le_next;	/* next element */			\
-	struct type **le_prev;	/* address of previous next element */	\
-}
-
-/*
- * List functions.
- */
-#define	LIST_INIT(head) {						\
-	(head)->lh_first = NULL;					\
-}
-
-#define LIST_INSERT_AFTER(listelm, elm, field) {			\
-	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
-		(listelm)->field.le_next->field.le_prev =		\
-		    &(elm)->field.le_next;				\
-	(listelm)->field.le_next = (elm);				\
-	(elm)->field.le_prev = &(listelm)->field.le_next;		\
-}
-
-#define LIST_INSERT_HEAD(head, elm, field) {				\
-	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
-		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
-	(head)->lh_first = (elm);					\
-	(elm)->field.le_prev = &(head)->lh_first;			\
-}
-
-#define LIST_REMOVE(elm, field) {					\
-	if ((elm)->field.le_next != NULL)				\
-		(elm)->field.le_next->field.le_prev = 			\
-		    (elm)->field.le_prev;				\
-	*(elm)->field.le_prev = (elm)->field.le_next;			\
-}
-
-/*
- * Tail queue definitions.
- */
-#define TAILQ_HEAD(name, type)						\
-struct name {								\
-	struct type *tqh_first;	/* first element */			\
-	struct type **tqh_last;	/* addr of last next element */		\
-}
-
-#define TAILQ_ENTRY(type)						\
-struct {								\
-	struct type *tqe_next;	/* next element */			\
-	struct type **tqe_prev;	/* address of previous next element */	\
-}
-
-/*
- * Tail queue functions.
- */
-#define	TAILQ_INIT(head) {						\
-	(head)->tqh_first = NULL;					\
-	(head)->tqh_last = &(head)->tqh_first;				\
-}
-
-#define TAILQ_INSERT_HEAD(head, elm, field) {				\
-	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
-		(elm)->field.tqe_next->field.tqe_prev =			\
-		    &(elm)->field.tqe_next;				\
-	else								\
-		(head)->tqh_last = &(elm)->field.tqe_next;		\
-	(head)->tqh_first = (elm);					\
-	(elm)->field.tqe_prev = &(head)->tqh_first;			\
-}
-
-#define TAILQ_INSERT_TAIL(head, elm, field) {				\
-	(elm)->field.tqe_next = NULL;					\
-	(elm)->field.tqe_prev = (head)->tqh_last;			\
-	*(head)->tqh_last = (elm);					\
-	(head)->tqh_last = &(elm)->field.tqe_next;			\
-}
-
-#define TAILQ_INSERT_AFTER(head, listelm, elm, field) {			\
-	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
-		(elm)->field.tqe_next->field.tqe_prev = 		\
-		    &(elm)->field.tqe_next;				\
-	else								\
-		(head)->tqh_last = &(elm)->field.tqe_next;		\
-	(listelm)->field.tqe_next = (elm);				\
-	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
-}
-
-#define TAILQ_REMOVE(head, elm, field) {				\
-	if (((elm)->field.tqe_next) != NULL)				\
-		(elm)->field.tqe_next->field.tqe_prev = 		\
-		    (elm)->field.tqe_prev;				\
-	else								\
-		(head)->tqh_last = (elm)->field.tqe_prev;		\
-	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
-}
-
-/*
- * Circular queue definitions.
- */
-#define CIRCLEQ_HEAD(name, type)					\
-struct name {								\
-	struct type *cqh_first;		/* first element */		\
-	struct type *cqh_last;		/* last element */		\
-}
-
-#define CIRCLEQ_ENTRY(type)						\
-struct {								\
-	struct type *cqe_next;		/* next element */		\
-	struct type *cqe_prev;		/* previous element */		\
-}
-
-/*
- * Circular queue functions.
- */
-#define	CIRCLEQ_INIT(head) {						\
-	(head)->cqh_first = (void *)(head);				\
-	(head)->cqh_last = (void *)(head);				\
-}
-
-#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) {		\
-	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
-	(elm)->field.cqe_prev = (listelm);				\
-	if ((listelm)->field.cqe_next == (void *)(head))		\
-		(head)->cqh_last = (elm);				\
-	else								\
-		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
-	(listelm)->field.cqe_next = (elm);				\
-}
-
-#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) {		\
-	(elm)->field.cqe_next = (listelm);				\
-	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
-	if ((listelm)->field.cqe_prev == (void *)(head))		\
-		(head)->cqh_first = (elm);				\
-	else								\
-		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
-	(listelm)->field.cqe_prev = (elm);				\
-}
-
-#define CIRCLEQ_INSERT_HEAD(head, elm, field) {				\
-	(elm)->field.cqe_next = (head)->cqh_first;			\
-	(elm)->field.cqe_prev = (void *)(head);				\
-	if ((head)->cqh_last == (void *)(head))				\
-		(head)->cqh_last = (elm);				\
-	else								\
-		(head)->cqh_first->field.cqe_prev = (elm);		\
-	(head)->cqh_first = (elm);					\
-}
-
-#define CIRCLEQ_INSERT_TAIL(head, elm, field) {				\
-	(elm)->field.cqe_next = (void *)(head);				\
-	(elm)->field.cqe_prev = (head)->cqh_last;			\
-	if ((head)->cqh_first == (void *)(head))			\
-		(head)->cqh_first = (elm);				\
-	else								\
-		(head)->cqh_last->field.cqe_next = (elm);		\
-	(head)->cqh_last = (elm);					\
-}
-
-#define	CIRCLEQ_REMOVE(head, elm, field) {				\
-	if ((elm)->field.cqe_next == (void *)(head))			\
-		(head)->cqh_last = (elm)->field.cqe_prev;		\
-	else								\
-		(elm)->field.cqe_next->field.cqe_prev =			\
-		    (elm)->field.cqe_prev;				\
-	if ((elm)->field.cqe_prev == (void *)(head))			\
-		(head)->cqh_first = (elm)->field.cqe_next;		\
-	else								\
-		(elm)->field.cqe_prev->field.cqe_next =			\
-		    (elm)->field.cqe_next;				\
-}
-#endif	/* sys/queue.h */
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 8a500b9..6f2cc54 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -22,8 +22,11 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#define AUDIO_CAP "wav"
+#include "hw/hw.h"
 #include "qemu-timer.h"
+#include "audio.h"
+
+#define AUDIO_CAP "wav"
 #include "audio_int.h"
 #include "qemu_file.h"
 
@@ -40,7 +43,7 @@
 } WAVVoiceOut;
 
 static struct {
-    audsettings_t settings;
+    struct audsettings settings;
     const char *wav_path;
 } conf_out = {
     {
@@ -57,7 +60,7 @@
     WAVVoiceOut *wav = (WAVVoiceOut *) hw;
     int rpos, live, decr, samples;
     uint8_t *dst;
-    st_sample_t *src;
+    struct st_sample *src;
     int64_t now = qemu_get_clock (vm_clock);
     int64_t ticks = now - wav->old_ticks;
     int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
@@ -112,7 +115,7 @@
     }
 }
 
-static int wav_out_init (HWVoiceOut *hw, audsettings_t *as)
+static int wav_out_init (HWVoiceOut *hw, struct audsettings *as)
 {
     WAVVoiceOut *wav = (WAVVoiceOut *) hw;
     int bits16 = 0, stereo = 0;
@@ -122,7 +125,7 @@
         0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
         0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
     };
-    audsettings_t wav_as = conf_out.settings;
+    struct audsettings wav_as = conf_out.settings;
 
     (void) as;
 
@@ -245,12 +248,12 @@
 }
 
 static int
-wav_in_init (HWVoiceIn *hw, audsettings_t *as)
+wav_in_init (HWVoiceIn *hw, struct audsettings *as)
 {
     WAVVoiceIn*  wav = (WAVVoiceIn *) hw;
     const char*  path = conf_in.wav_path;
     uint8_t      hdr[44];
-    audsettings_t wav_as = *as;
+    struct audsettings wav_as = *as;
     int           nchannels, freq, format, bits;
 
     wav->f = qemu_fopen (path, "rb");
@@ -348,7 +351,7 @@
     WAVVoiceIn*   wav = (WAVVoiceIn *) hw;
     int           wpos, live, decr, samples;
     uint8_t*      src;
-    st_sample_t*  dst;
+    struct st_sample*  dst;
 
     int64_t  now   = qemu_get_clock (vm_clock);
     int64_t  ticks = now - wav->old_ticks;
@@ -417,7 +420,7 @@
     ldebug ("wav_fini");
 }
 
-struct audio_option wav_options[] = {
+static struct audio_option wav_options[] = {
     {"FREQUENCY", AUD_OPT_INT, &conf_out.settings.freq,
      "Frequency", NULL, 0},
 
diff --git a/audio/wavcapture.c b/audio/wavcapture.c
index d6f733e..1f49cd1 100644
--- a/audio/wavcapture.c
+++ b/audio/wavcapture.c
@@ -1,6 +1,6 @@
-#include "audio/audio.h"
-#include "qemu_file.h"
-#include "console.h"
+#include "hw/hw.h"
+#include "monitor.h"
+#include "audio.h"
 
 typedef struct {
     QEMUFile *f;
@@ -36,22 +36,19 @@
     uint32_t datalen = wav->bytes;
     uint32_t rifflen = datalen + 36;
 
-    if (!wav->f) {
-        return;
+    if (wav->f) {
+        le_store (rlen, rifflen, 4);
+        le_store (dlen, datalen, 4);
+
+        qemu_fseek (wav->f, 4, SEEK_SET);
+        qemu_put_buffer (wav->f, rlen, 4);
+
+        qemu_fseek (wav->f, 32, SEEK_CUR);
+        qemu_put_buffer (wav->f, dlen, 4);
+        qemu_fclose (wav->f);
     }
 
-    le_store (rlen, rifflen, 4);
-    le_store (dlen, datalen, 4);
-
-    qemu_fseek (wav->f, 4, SEEK_SET);
-    qemu_put_buffer (wav->f, rlen, 4);
-
-    qemu_fseek (wav->f, 32, SEEK_CUR);
-    qemu_put_buffer (wav->f, dlen, 4);
-    qemu_fclose (wav->f);
-    if (wav->path) {
-        qemu_free (wav->path);
-    }
+    qemu_free (wav->path);
 }
 
 static void wav_capture (void *opaque, void *buf, int size)
@@ -74,9 +71,9 @@
     WAVState *wav = opaque;
     char *path = wav->path;
 
-    term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
-                 wav->freq, wav->bits, wav->nchannels,
-                 path ? path : "<not available>", wav->bytes);
+    monitor_printf(cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n",
+                   wav->freq, wav->bits, wav->nchannels,
+                   path ? path : "<not available>", wav->bytes);
 }
 
 static struct capture_ops wav_capture_ops = {
@@ -87,6 +84,7 @@
 int wav_start_capture (CaptureState *s, const char *path, int freq,
                        int bits, int nchannels)
 {
+    Monitor *mon = cur_mon;
     WAVState *wav;
     uint8_t hdr[] = {
         0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
@@ -94,18 +92,19 @@
         0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
         0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
     };
-    audsettings_t as;
+    struct audsettings as;
     struct audio_capture_ops ops;
     int stereo, bits16, shift;
     CaptureVoiceOut *cap;
 
     if (bits != 8 && bits != 16) {
-        term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
+        monitor_printf(mon, "incorrect bit count %d, must be 8 or 16\n", bits);
         return -1;
     }
 
     if (nchannels != 1 && nchannels != 2) {
-        term_printf ("incorrect channel count %d, must be 1 or 2\n", bits);
+        monitor_printf(mon, "incorrect channel count %d, must be 1 or 2\n",
+                       nchannels);
         return -1;
     }
 
@@ -122,10 +121,6 @@
     ops.destroy = wav_destroy;
 
     wav = qemu_mallocz (sizeof (*wav));
-    if (!wav) {
-        AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav));
-        return -1;
-    }
 
     shift = bits16 + stereo;
     hdr[34] = bits16 ? 0x10 : 0x08;
@@ -137,8 +132,8 @@
 
     wav->f = qemu_fopen (path, "wb");
     if (!wav->f) {
-        term_printf ("Failed to open wave file `%s'\nReason: %s\n",
-                     path, strerror (errno));
+        monitor_printf(mon, "Failed to open wave file `%s'\nReason: %s\n",
+                       path, strerror (errno));
         qemu_free (wav);
         return -1;
     }
@@ -150,9 +145,9 @@
 
     qemu_put_buffer (wav->f, hdr, sizeof (hdr));
 
-    cap = AUD_add_capture (NULL, &as, &ops, wav);
+    cap = AUD_add_capture (&as, &ops, wav);
     if (!cap) {
-        term_printf ("Failed to add audio capture\n");
+        monitor_printf(mon, "Failed to add audio capture\n");
         qemu_free (wav->path);
         qemu_fclose (wav->f);
         qemu_free (wav);
diff --git a/audio/winaudio.c b/audio/winaudio.c
index 6e8daef..ca6c487 100644
--- a/audio/winaudio.c
+++ b/audio/winaudio.c
@@ -156,7 +156,7 @@
 

 

 static int

-winaudio_out_init (HWVoiceOut *hw, audsettings_t *as)

+winaudio_out_init (HWVoiceOut *hw, struct audsettings *as)

 {

     WinAudioOut*   s = (WinAudioOut*) hw;

     MMRESULT       result;

@@ -272,7 +272,7 @@
             int           wav_bytes   = (s->write_size - s->write_pos);

             int           wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);

             int           hw_samples  = audio_MIN(hw->samples - hw->rpos, live);

-            st_sample_t*  src         = hw->mix_buf + hw->rpos;

+            struct st_sample*  src         = hw->mix_buf + hw->rpos;

             uint8_t*      dst         = (uint8_t*)wav_buffer->lpData + s->write_pos;

 

             if (wav_samples > hw_samples) {

@@ -403,7 +403,7 @@
 

 

 static int

-winaudio_in_init (HWVoiceIn *hw, audsettings_t *as)

+winaudio_in_init (HWVoiceIn *hw, struct audsettings *as)

 {

     WinAudioIn*   s = (WinAudioIn*) hw;

     MMRESULT       result;

@@ -532,7 +532,7 @@
             int           wav_bytes   = (s->read_size - s->read_pos);

             int           wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);

             int           hw_samples  = audio_MIN(hw->samples - hw->wpos, live);

-            st_sample_t*  dst         = hw->conv_buf + hw->wpos;

+            struct st_sample*  dst    = hw->conv_buf + hw->wpos;

             uint8_t*      src         = (uint8_t*)wav_buffer->lpData + s->read_pos;

 

             if (wav_samples > hw_samples) {

diff --git a/balloon.h b/balloon.h
new file mode 100644
index 0000000..60b4a5d
--- /dev/null
+++ b/balloon.h
@@ -0,0 +1,27 @@
+/*
+ * Balloon
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_BALLOON_H
+#define _QEMU_BALLOON_H
+
+#include "cpu-defs.h"
+
+typedef ram_addr_t (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
+
+void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
+
+void qemu_balloon(ram_addr_t target);
+
+ram_addr_t qemu_balloon_status(void);
+
+#endif
diff --git a/block-qcow2.c b/block-qcow2.c
deleted file mode 100644
index 5f0fbe8..0000000
--- a/block-qcow2.c
+++ /dev/null
@@ -1,2620 +0,0 @@
-/*
- * Block driver for the QCOW version 2 format
- *
- * Copyright (c) 2004-2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "block_int.h"
-#include <zlib.h>
-#include "aes.h"
-#include <assert.h>
-
-/*
-  Differences with QCOW:
-
-  - Support for multiple incremental snapshots.
-  - Memory management by reference counts.
-  - Clusters which have a reference count of one have the bit
-    QCOW_OFLAG_COPIED to optimize write performance.
-  - Size of compressed clusters is stored in sectors to reduce bit usage
-    in the cluster offsets.
-  - Support for storing additional data (such as the VM state) in the
-    snapshots.
-  - If a backing store is used, the cluster size is not constrained
-    (could be backported to QCOW).
-  - L2 tables have always a size of one cluster.
-*/
-
-//#define DEBUG_ALLOC
-//#define DEBUG_ALLOC2
-
-#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
-#define QCOW_VERSION 2
-
-#define QCOW_CRYPT_NONE 0
-#define QCOW_CRYPT_AES  1
-
-#define QCOW_MAX_CRYPT_CLUSTERS 32
-
-/* indicate that the refcount of the referenced cluster is exactly one. */
-#define QCOW_OFLAG_COPIED     (1LL << 63)
-/* indicate that the cluster is compressed (they never have the copied flag) */
-#define QCOW_OFLAG_COMPRESSED (1LL << 62)
-
-#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
-
-typedef struct QCowHeader {
-    uint32_t magic;
-    uint32_t version;
-    uint64_t backing_file_offset;
-    uint32_t backing_file_size;
-    uint32_t cluster_bits;
-    uint64_t size; /* in bytes */
-    uint32_t crypt_method;
-    uint32_t l1_size; /* XXX: save number of clusters instead ? */
-    uint64_t l1_table_offset;
-    uint64_t refcount_table_offset;
-    uint32_t refcount_table_clusters;
-    uint32_t nb_snapshots;
-    uint64_t snapshots_offset;
-} QCowHeader;
-
-typedef struct __attribute__((packed)) QCowSnapshotHeader {
-    /* header is 8 byte aligned */
-    uint64_t l1_table_offset;
-
-    uint32_t l1_size;
-    uint16_t id_str_size;
-    uint16_t name_size;
-
-    uint32_t date_sec;
-    uint32_t date_nsec;
-
-    uint64_t vm_clock_nsec;
-
-    uint32_t vm_state_size;
-    uint32_t extra_data_size; /* for extension */
-    /* extra data follows */
-    /* id_str follows */
-    /* name follows  */
-} QCowSnapshotHeader;
-
-#define L2_CACHE_SIZE 16
-
-typedef struct QCowSnapshot {
-    uint64_t l1_table_offset;
-    uint32_t l1_size;
-    char *id_str;
-    char *name;
-    uint32_t vm_state_size;
-    uint32_t date_sec;
-    uint32_t date_nsec;
-    uint64_t vm_clock_nsec;
-} QCowSnapshot;
-
-typedef struct BDRVQcowState {
-    BlockDriverState *hd;
-    int cluster_bits;
-    int cluster_size;
-    int cluster_sectors;
-    int l2_bits;
-    int l2_size;
-    int l1_size;
-    int l1_vm_state_index;
-    int csize_shift;
-    int csize_mask;
-    uint64_t cluster_offset_mask;
-    uint64_t l1_table_offset;
-    uint64_t *l1_table;
-    uint64_t *l2_cache;
-    uint64_t l2_cache_offsets[L2_CACHE_SIZE];
-    uint32_t l2_cache_counts[L2_CACHE_SIZE];
-    uint8_t *cluster_cache;
-    uint8_t *cluster_data;
-    uint64_t cluster_cache_offset;
-
-    uint64_t *refcount_table;
-    uint64_t refcount_table_offset;
-    uint32_t refcount_table_size;
-    uint64_t refcount_block_cache_offset;
-    uint16_t *refcount_block_cache;
-    int64_t free_cluster_index;
-    int64_t free_byte_offset;
-
-    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
-    uint32_t crypt_method_header;
-    AES_KEY aes_encrypt_key;
-    AES_KEY aes_decrypt_key;
-    uint64_t snapshots_offset;
-    int snapshots_size;
-    int nb_snapshots;
-    QCowSnapshot *snapshots;
-} BDRVQcowState;
-
-static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
-static int qcow_read(BlockDriverState *bs, int64_t sector_num,
-                     uint8_t *buf, int nb_sectors);
-static int qcow_read_snapshots(BlockDriverState *bs);
-static void qcow_free_snapshots(BlockDriverState *bs);
-static int refcount_init(BlockDriverState *bs);
-static void refcount_close(BlockDriverState *bs);
-static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
-static int update_cluster_refcount(BlockDriverState *bs,
-                                   int64_t cluster_index,
-                                   int addend);
-static void update_refcount(BlockDriverState *bs,
-                            int64_t offset, int64_t length,
-                            int addend);
-static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
-static int64_t alloc_bytes(BlockDriverState *bs, int size);
-static void free_clusters(BlockDriverState *bs,
-                          int64_t offset, int64_t size);
-#ifdef DEBUG_ALLOC
-static void check_refcounts(BlockDriverState *bs);
-#endif
-
-static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
-    const QCowHeader *cow_header = (const void *)buf;
-
-    if (buf_size >= sizeof(QCowHeader) &&
-        be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
-        be32_to_cpu(cow_header->version) == QCOW_VERSION)
-        return 100;
-    else
-        return 0;
-}
-
-static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
-{
-    BDRVQcowState *s = bs->opaque;
-    int len, i, shift, ret;
-    QCowHeader header;
-
-    ret = bdrv_file_open(&s->hd, filename, flags);
-    if (ret < 0)
-        return ret;
-    if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
-        goto fail;
-    be32_to_cpus(&header.magic);
-    be32_to_cpus(&header.version);
-    be64_to_cpus(&header.backing_file_offset);
-    be32_to_cpus(&header.backing_file_size);
-    be64_to_cpus(&header.size);
-    be32_to_cpus(&header.cluster_bits);
-    be32_to_cpus(&header.crypt_method);
-    be64_to_cpus(&header.l1_table_offset);
-    be32_to_cpus(&header.l1_size);
-    be64_to_cpus(&header.refcount_table_offset);
-    be32_to_cpus(&header.refcount_table_clusters);
-    be64_to_cpus(&header.snapshots_offset);
-    be32_to_cpus(&header.nb_snapshots);
-
-    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
-        goto fail;
-    if (header.size <= 1 ||
-        header.cluster_bits < 9 ||
-        header.cluster_bits > 16)
-        goto fail;
-    if (header.crypt_method > QCOW_CRYPT_AES)
-        goto fail;
-    s->crypt_method_header = header.crypt_method;
-    if (s->crypt_method_header)
-        bs->encrypted = 1;
-    s->cluster_bits = header.cluster_bits;
-    s->cluster_size = 1 << s->cluster_bits;
-    s->cluster_sectors = 1 << (s->cluster_bits - 9);
-    s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
-    s->l2_size = 1 << s->l2_bits;
-    bs->total_sectors = header.size / 512;
-    s->csize_shift = (62 - (s->cluster_bits - 8));
-    s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
-    s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
-    s->refcount_table_offset = header.refcount_table_offset;
-    s->refcount_table_size =
-        header.refcount_table_clusters << (s->cluster_bits - 3);
-
-    s->snapshots_offset = header.snapshots_offset;
-    s->nb_snapshots = header.nb_snapshots;
-
-    /* read the level 1 table */
-    s->l1_size = header.l1_size;
-    shift = s->cluster_bits + s->l2_bits;
-    s->l1_vm_state_index = (header.size + (1LL << shift) - 1) >> shift;
-    /* the L1 table must contain at least enough entries to put
-       header.size bytes */
-    if (s->l1_size < s->l1_vm_state_index)
-        goto fail;
-    s->l1_table_offset = header.l1_table_offset;
-    s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
-    if (!s->l1_table)
-        goto fail;
-    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
-        s->l1_size * sizeof(uint64_t))
-        goto fail;
-    for(i = 0;i < s->l1_size; i++) {
-        be64_to_cpus(&s->l1_table[i]);
-    }
-    /* alloc L2 cache */
-    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
-    if (!s->l2_cache)
-        goto fail;
-    s->cluster_cache = qemu_malloc(s->cluster_size);
-    if (!s->cluster_cache)
-        goto fail;
-    /* one more sector for decompressed data alignment */
-    s->cluster_data = qemu_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
-                                  + 512);
-    if (!s->cluster_data)
-        goto fail;
-    s->cluster_cache_offset = -1;
-
-    if (refcount_init(bs) < 0)
-        goto fail;
-
-    /* read the backing file name */
-    if (header.backing_file_offset != 0) {
-        len = header.backing_file_size;
-        if (len > 1023)
-            len = 1023;
-        if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
-            goto fail;
-        bs->backing_file[len] = '\0';
-    }
-    if (qcow_read_snapshots(bs) < 0)
-        goto fail;
-
-#ifdef DEBUG_ALLOC
-    check_refcounts(bs);
-#endif
-    return 0;
-
- fail:
-    qcow_free_snapshots(bs);
-    refcount_close(bs);
-    qemu_free(s->l1_table);
-    qemu_free(s->l2_cache);
-    qemu_free(s->cluster_cache);
-    qemu_free(s->cluster_data);
-    bdrv_delete(s->hd);
-    return -1;
-}
-
-static int qcow_set_key(BlockDriverState *bs, const char *key)
-{
-    BDRVQcowState *s = bs->opaque;
-    uint8_t keybuf[16];
-    int len, i;
-
-    memset(keybuf, 0, 16);
-    len = strlen(key);
-    if (len > 16)
-        len = 16;
-    /* XXX: we could compress the chars to 7 bits to increase
-       entropy */
-    for(i = 0;i < len;i++) {
-        keybuf[i] = key[i];
-    }
-    s->crypt_method = s->crypt_method_header;
-
-    if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
-        return -1;
-    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
-        return -1;
-#if 0
-    /* test */
-    {
-        uint8_t in[16];
-        uint8_t out[16];
-        uint8_t tmp[16];
-        for(i=0;i<16;i++)
-            in[i] = i;
-        AES_encrypt(in, tmp, &s->aes_encrypt_key);
-        AES_decrypt(tmp, out, &s->aes_decrypt_key);
-        for(i = 0; i < 16; i++)
-            printf(" %02x", tmp[i]);
-        printf("\n");
-        for(i = 0; i < 16; i++)
-            printf(" %02x", out[i]);
-        printf("\n");
-    }
-#endif
-    return 0;
-}
-
-/* The crypt function is compatible with the linux cryptoloop
-   algorithm for < 4 GB images. NOTE: out_buf == in_buf is
-   supported */
-static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
-                            uint8_t *out_buf, const uint8_t *in_buf,
-                            int nb_sectors, int enc,
-                            const AES_KEY *key)
-{
-    union {
-        uint64_t ll[2];
-        uint8_t b[16];
-    } ivec;
-    int i;
-
-    for(i = 0; i < nb_sectors; i++) {
-        ivec.ll[0] = cpu_to_le64(sector_num);
-        ivec.ll[1] = 0;
-        AES_cbc_encrypt(in_buf, out_buf, 512, key,
-                        ivec.b, enc);
-        sector_num++;
-        in_buf += 512;
-        out_buf += 512;
-    }
-}
-
-static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
-                        uint64_t cluster_offset, int n_start, int n_end)
-{
-    BDRVQcowState *s = bs->opaque;
-    int n, ret;
-
-    n = n_end - n_start;
-    if (n <= 0)
-        return 0;
-    ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
-    if (ret < 0)
-        return ret;
-    if (s->crypt_method) {
-        encrypt_sectors(s, start_sect + n_start,
-                        s->cluster_data,
-                        s->cluster_data, n, 1,
-                        &s->aes_encrypt_key);
-    }
-    ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start,
-                     s->cluster_data, n);
-    if (ret < 0)
-        return ret;
-    return 0;
-}
-
-static void l2_cache_reset(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-
-    memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
-    memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
-    memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
-}
-
-static inline int l2_cache_new_entry(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    uint32_t min_count;
-    int min_index, i;
-
-    /* find a new entry in the least used one */
-    min_index = 0;
-    min_count = 0xffffffff;
-    for(i = 0; i < L2_CACHE_SIZE; i++) {
-        if (s->l2_cache_counts[i] < min_count) {
-            min_count = s->l2_cache_counts[i];
-            min_index = i;
-        }
-    }
-    return min_index;
-}
-
-static int64_t align_offset(int64_t offset, int n)
-{
-    offset = (offset + n - 1) & ~(n - 1);
-    return offset;
-}
-
-static int grow_l1_table(BlockDriverState *bs, int min_size)
-{
-    BDRVQcowState *s = bs->opaque;
-    int new_l1_size, new_l1_size2, ret, i;
-    uint64_t *new_l1_table;
-    uint64_t new_l1_table_offset;
-    uint64_t data64;
-    uint32_t data32;
-
-    new_l1_size = s->l1_size;
-    if (min_size <= new_l1_size)
-        return 0;
-    while (min_size > new_l1_size) {
-        new_l1_size = (new_l1_size * 3 + 1) / 2;
-    }
-#ifdef DEBUG_ALLOC2
-    printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
-#endif
-
-    new_l1_size2 = sizeof(uint64_t) * new_l1_size;
-    new_l1_table = qemu_mallocz(new_l1_size2);
-    if (!new_l1_table)
-        return -ENOMEM;
-    memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
-
-    /* write new table (align to cluster) */
-    new_l1_table_offset = alloc_clusters(bs, new_l1_size2);
-
-    for(i = 0; i < s->l1_size; i++)
-        new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
-    ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
-    if (ret != new_l1_size2)
-        goto fail;
-    for(i = 0; i < s->l1_size; i++)
-        new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
-
-    /* set new table */
-    data64 = cpu_to_be64(new_l1_table_offset);
-    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_table_offset),
-                    &data64, sizeof(data64)) != sizeof(data64))
-        goto fail;
-    data32 = cpu_to_be32(new_l1_size);
-    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size),
-                    &data32, sizeof(data32)) != sizeof(data32))
-        goto fail;
-    qemu_free(s->l1_table);
-    free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
-    s->l1_table_offset = new_l1_table_offset;
-    s->l1_table = new_l1_table;
-    s->l1_size = new_l1_size;
-    return 0;
- fail:
-    qemu_free(s->l1_table);
-    return -EIO;
-}
-
-/*
- * seek_l2_table
- *
- * seek l2_offset in the l2_cache table
- * if not found, return NULL,
- * if found,
- *   increments the l2 cache hit count of the entry,
- *   if counter overflow, divide by two all counters
- *   return the pointer to the l2 cache entry
- *
- */
-
-static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset)
-{
-    int i, j;
-
-    for(i = 0; i < L2_CACHE_SIZE; i++) {
-        if (l2_offset == s->l2_cache_offsets[i]) {
-            /* increment the hit count */
-            if (++s->l2_cache_counts[i] == 0xffffffff) {
-                for(j = 0; j < L2_CACHE_SIZE; j++) {
-                    s->l2_cache_counts[j] >>= 1;
-                }
-            }
-            return s->l2_cache + (i << s->l2_bits);
-        }
-    }
-    return NULL;
-}
-
-/*
- * l2_load
- *
- * Loads a L2 table into memory. If the table is in the cache, the cache
- * is used; otherwise the L2 table is loaded from the image file.
- *
- * Returns a pointer to the L2 table on success, or NULL if the read from
- * the image file failed.
- */
-
-static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset)
-{
-    BDRVQcowState *s = bs->opaque;
-    int min_index;
-    uint64_t *l2_table;
-
-    /* seek if the table for the given offset is in the cache */
-
-    l2_table = seek_l2_table(s, l2_offset);
-    if (l2_table != NULL)
-        return l2_table;
-
-    /* not found: load a new entry in the least used one */
-
-    min_index = l2_cache_new_entry(bs);
-    l2_table = s->l2_cache + (min_index << s->l2_bits);
-    if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
-        s->l2_size * sizeof(uint64_t))
-        return NULL;
-    s->l2_cache_offsets[min_index] = l2_offset;
-    s->l2_cache_counts[min_index] = 1;
-
-    return l2_table;
-}
-
-/*
- * l2_allocate
- *
- * Allocate a new l2 entry in the file. If l1_index points to an already
- * used entry in the L2 table (i.e. we are doing a copy on write for the L2
- * table) copy the contents of the old L2 table into the newly allocated one.
- * Otherwise the new table is initialized with zeros.
- *
- */
-
-static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
-{
-    BDRVQcowState *s = bs->opaque;
-    int min_index;
-    uint64_t old_l2_offset, tmp;
-    uint64_t *l2_table, l2_offset;
-
-    old_l2_offset = s->l1_table[l1_index];
-
-    /* allocate a new l2 entry */
-
-    l2_offset = alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
-
-    /* update the L1 entry */
-
-    s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
-
-    tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED);
-    if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
-                    &tmp, sizeof(tmp)) != sizeof(tmp))
-        return NULL;
-
-    /* allocate a new entry in the l2 cache */
-
-    min_index = l2_cache_new_entry(bs);
-    l2_table = s->l2_cache + (min_index << s->l2_bits);
-
-    if (old_l2_offset == 0) {
-        /* if there was no old l2 table, clear the new table */
-        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
-    } else {
-        /* if there was an old l2 table, read it from the disk */
-        if (bdrv_pread(s->hd, old_l2_offset,
-                       l2_table, s->l2_size * sizeof(uint64_t)) !=
-            s->l2_size * sizeof(uint64_t))
-            return NULL;
-    }
-    /* write the l2 table to the file */
-    if (bdrv_pwrite(s->hd, l2_offset,
-                    l2_table, s->l2_size * sizeof(uint64_t)) !=
-        s->l2_size * sizeof(uint64_t))
-        return NULL;
-
-    /* update the l2 cache entry */
-
-    s->l2_cache_offsets[min_index] = l2_offset;
-    s->l2_cache_counts[min_index] = 1;
-
-    return l2_table;
-}
-
-/*
- * get_cluster_offset
- *
- * For a given offset of the disk image, return cluster offset in
- * qcow2 file.
- *
- * on entry, *num is the number of contiguous clusters we'd like to
- * access following offset.
- *
- * on exit, *num is the number of contiguous clusters we can read.
- *
- * Return 1, if the offset is found
- * Return 0, otherwise.
- *
- */
-
-static uint64_t get_cluster_offset(BlockDriverState *bs,
-                                   uint64_t offset, int *num)
-{
-    BDRVQcowState *s = bs->opaque;
-    int l1_index, l2_index;
-    uint64_t l2_offset, *l2_table, cluster_offset, next;
-    int l1_bits;
-    int index_in_cluster, nb_available, nb_needed;
-
-    index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
-    nb_needed = *num + index_in_cluster;
-
-    l1_bits = s->l2_bits + s->cluster_bits;
-
-    /* compute how many bytes there are between the offset and
-     * and the end of the l1 entry
-     */
-
-    nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1));
-
-    /* compute the number of available sectors */
-
-    nb_available = (nb_available >> 9) + index_in_cluster;
-
-    cluster_offset = 0;
-
-    /* seek the the l2 offset in the l1 table */
-
-    l1_index = offset >> l1_bits;
-    if (l1_index >= s->l1_size)
-        goto out;
-
-    l2_offset = s->l1_table[l1_index];
-
-    /* seek the l2 table of the given l2 offset */
-
-    if (!l2_offset)
-        goto out;
-
-    /* load the l2 table in memory */
-
-    l2_offset &= ~QCOW_OFLAG_COPIED;
-    l2_table = l2_load(bs, l2_offset);
-    if (l2_table == NULL)
-        return 0;
-
-    /* find the cluster offset for the given disk offset */
-
-    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
-    cluster_offset = be64_to_cpu(l2_table[l2_index]);
-    nb_available = s->cluster_sectors;
-    l2_index++;
-
-    if (!cluster_offset) {
-
-       /* how many empty clusters ? */
-
-       while (nb_available < nb_needed && !l2_table[l2_index]) {
-           l2_index++;
-           nb_available += s->cluster_sectors;
-       }
-    } else {
-
-       /* how many allocated clusters ? */
-
-       cluster_offset &= ~QCOW_OFLAG_COPIED;
-       while (nb_available < nb_needed) {
-           next = be64_to_cpu(l2_table[l2_index]) & ~QCOW_OFLAG_COPIED;
-           if (next != cluster_offset + (nb_available << 9))
-               break;
-           l2_index++;
-           nb_available += s->cluster_sectors;
-       }
-   }
-
-out:
-    if (nb_available > nb_needed)
-        nb_available = nb_needed;
-
-    *num = nb_available - index_in_cluster;
-
-    return cluster_offset;
-}
-
-/*
- * free_any_clusters
- *
- * free clusters according to its type: compressed or not
- *
- */
-
-static void free_any_clusters(BlockDriverState *bs,
-                              uint64_t cluster_offset, int nb_clusters)
-{
-    BDRVQcowState *s = bs->opaque;
-
-    /* free the cluster */
-
-    if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
-        int nb_csectors;
-        nb_csectors = ((cluster_offset >> s->csize_shift) &
-                       s->csize_mask) + 1;
-        free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511,
-                      nb_csectors * 512);
-        return;
-    }
-
-    free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits);
-
-    return;
-}
-
-/*
- * get_cluster_table
- *
- * for a given disk offset, load (and allocate if needed)
- * the l2 table.
- *
- * the l2 table offset in the qcow2 file and the cluster index
- * in the l2 table are given to the caller.
- *
- */
-
-static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
-                             uint64_t **new_l2_table,
-                             uint64_t *new_l2_offset,
-                             int *new_l2_index)
-{
-    BDRVQcowState *s = bs->opaque;
-    int l1_index, l2_index, ret;
-    uint64_t l2_offset, *l2_table;
-
-    /* seek the the l2 offset in the l1 table */
-
-    l1_index = offset >> (s->l2_bits + s->cluster_bits);
-    if (l1_index >= s->l1_size) {
-        ret = grow_l1_table(bs, l1_index + 1);
-        if (ret < 0)
-            return 0;
-    }
-    l2_offset = s->l1_table[l1_index];
-
-    /* seek the l2 table of the given l2 offset */
-
-    if (l2_offset & QCOW_OFLAG_COPIED) {
-        /* load the l2 table in memory */
-        l2_offset &= ~QCOW_OFLAG_COPIED;
-        l2_table = l2_load(bs, l2_offset);
-        if (l2_table == NULL)
-            return 0;
-    } else {
-        if (l2_offset)
-            free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
-        l2_table = l2_allocate(bs, l1_index);
-        if (l2_table == NULL)
-            return 0;
-        l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
-    }
-
-    /* find the cluster offset for the given disk offset */
-
-    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
-
-    *new_l2_table = l2_table;
-    *new_l2_offset = l2_offset;
-    *new_l2_index = l2_index;
-
-    return 1;
-}
-
-/*
- * alloc_compressed_cluster_offset
- *
- * For a given offset of the disk image, return cluster offset in
- * qcow2 file.
- *
- * If the offset is not found, allocate a new compressed cluster.
- *
- * Return the cluster offset if successful,
- * Return 0, otherwise.
- *
- */
-
-static uint64_t alloc_compressed_cluster_offset(BlockDriverState *bs,
-                                                uint64_t offset,
-                                                int compressed_size)
-{
-    BDRVQcowState *s = bs->opaque;
-    int l2_index, ret;
-    uint64_t l2_offset, *l2_table, cluster_offset;
-    int nb_csectors;
-
-    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
-    if (ret == 0)
-        return 0;
-
-    cluster_offset = be64_to_cpu(l2_table[l2_index]);
-    if (cluster_offset & QCOW_OFLAG_COPIED)
-        return cluster_offset & ~QCOW_OFLAG_COPIED;
-
-    if (cluster_offset)
-        free_any_clusters(bs, cluster_offset, 1);
-
-    cluster_offset = alloc_bytes(bs, compressed_size);
-    nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
-                  (cluster_offset >> 9);
-
-    cluster_offset |= QCOW_OFLAG_COMPRESSED |
-                      ((uint64_t)nb_csectors << s->csize_shift);
-
-    /* update L2 table */
-
-    /* compressed clusters never have the copied flag */
-
-    l2_table[l2_index] = cpu_to_be64(cluster_offset);
-    if (bdrv_pwrite(s->hd,
-                    l2_offset + l2_index * sizeof(uint64_t),
-                    l2_table + l2_index,
-                    sizeof(uint64_t)) != sizeof(uint64_t))
-        return 0;
-
-    return cluster_offset;
-}
-
-/*
- * alloc_cluster_offset
- *
- * For a given offset of the disk image, return cluster offset in
- * qcow2 file.
- *
- * If the offset is not found, allocate a new cluster.
- *
- * Return the cluster offset if successful,
- * Return 0, otherwise.
- *
- */
-
-static uint64_t alloc_cluster_offset(BlockDriverState *bs,
-                                     uint64_t offset,
-                                     int n_start, int n_end,
-                                     int *num)
-{
-    BDRVQcowState *s = bs->opaque;
-    int l2_index, ret;
-    uint64_t l2_offset, *l2_table, cluster_offset;
-    int nb_available, nb_clusters, i, j;
-    uint64_t start_sect, current;
-
-    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
-    if (ret == 0)
-        return 0;
-
-    nb_clusters = ((n_end << 9) + s->cluster_size - 1) >>
-                  s->cluster_bits;
-    if (nb_clusters > s->l2_size - l2_index)
-            nb_clusters = s->l2_size - l2_index;
-
-    cluster_offset = be64_to_cpu(l2_table[l2_index]);
-
-    /* We keep all QCOW_OFLAG_COPIED clusters */
-
-    if (cluster_offset & QCOW_OFLAG_COPIED) {
-
-        for (i = 1; i < nb_clusters; i++) {
-            current = be64_to_cpu(l2_table[l2_index + i]);
-            if (cluster_offset + (i << s->cluster_bits) != current)
-                break;
-        }
-        nb_clusters = i;
-
-        nb_available = nb_clusters << (s->cluster_bits - 9);
-        if (nb_available > n_end)
-            nb_available = n_end;
-
-        cluster_offset &= ~QCOW_OFLAG_COPIED;
-
-        goto out;
-    }
-
-    /* for the moment, multiple compressed clusters are not managed */
-
-    if (cluster_offset & QCOW_OFLAG_COMPRESSED)
-        nb_clusters = 1;
-
-    /* how many available clusters ? */
-
-    i = 0;
-    while (i < nb_clusters) {
-
-        i++;
-
-        if (!cluster_offset) {
-
-            /* how many free clusters ? */
-
-            while (i < nb_clusters) {
-                cluster_offset = l2_table[l2_index + i];
-                if (cluster_offset != 0)
-                    break;
-                i++;
-            }
-
-            if ((cluster_offset & QCOW_OFLAG_COPIED) ||
-                (cluster_offset & QCOW_OFLAG_COMPRESSED))
-                break;
-
-        } else {
-
-            /* how many contiguous clusters ? */
-
-            j = 1;
-            current = 0;
-            while (i < nb_clusters) {
-                current = be64_to_cpu(l2_table[l2_index + i]);
-                if (cluster_offset + (j << s->cluster_bits) != current)
-                    break;
-
-                i++;
-                j++;
-            }
-
-            free_any_clusters(bs, cluster_offset, j);
-            if (current)
-                break;
-            cluster_offset = current;
-        }
-    }
-    nb_clusters = i;
-
-    /* allocate a new cluster */
-
-    cluster_offset = alloc_clusters(bs, nb_clusters * s->cluster_size);
-
-    /* we must initialize the cluster content which won't be
-       written */
-
-    nb_available = nb_clusters << (s->cluster_bits - 9);
-    if (nb_available > n_end)
-        nb_available = n_end;
-
-    /* copy content of unmodified sectors */
-
-    start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
-    if (n_start) {
-        ret = copy_sectors(bs, start_sect, cluster_offset, 0, n_start);
-        if (ret < 0)
-            return 0;
-    }
-
-    if (nb_available & (s->cluster_sectors - 1)) {
-        uint64_t end = nb_available & ~(uint64_t)(s->cluster_sectors - 1);
-        ret = copy_sectors(bs, start_sect + end,
-                           cluster_offset + (end << 9),
-                           nb_available - end,
-                           s->cluster_sectors);
-        if (ret < 0)
-            return 0;
-    }
-
-    /* update L2 table */
-
-    for (i = 0; i < nb_clusters; i++)
-        l2_table[l2_index + i] = cpu_to_be64((cluster_offset +
-                                             (i << s->cluster_bits)) |
-                                             QCOW_OFLAG_COPIED);
-
-    if (bdrv_pwrite(s->hd,
-                    l2_offset + l2_index * sizeof(uint64_t),
-                    l2_table + l2_index,
-                    nb_clusters * sizeof(uint64_t)) !=
-                    nb_clusters * sizeof(uint64_t))
-        return 0;
-
-out:
-    *num = nb_available - n_start;
-
-    return cluster_offset;
-}
-
-static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
-                             int nb_sectors, int *pnum)
-{
-    uint64_t cluster_offset;
-
-    *pnum = nb_sectors;
-    cluster_offset = get_cluster_offset(bs, sector_num << 9, pnum);
-
-    return (cluster_offset != 0);
-}
-
-static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
-                             const uint8_t *buf, int buf_size)
-{
-    z_stream strm1, *strm = &strm1;
-    int ret, out_len;
-
-    memset(strm, 0, sizeof(*strm));
-
-    strm->next_in = (uint8_t *)buf;
-    strm->avail_in = buf_size;
-    strm->next_out = out_buf;
-    strm->avail_out = out_buf_size;
-
-    ret = inflateInit2(strm, -12);
-    if (ret != Z_OK)
-        return -1;
-    ret = inflate(strm, Z_FINISH);
-    out_len = strm->next_out - out_buf;
-    if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
-        out_len != out_buf_size) {
-        inflateEnd(strm);
-        return -1;
-    }
-    inflateEnd(strm);
-    return 0;
-}
-
-static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
-{
-    int ret, csize, nb_csectors, sector_offset;
-    uint64_t coffset;
-
-    coffset = cluster_offset & s->cluster_offset_mask;
-    if (s->cluster_cache_offset != coffset) {
-        nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
-        sector_offset = coffset & 511;
-        csize = nb_csectors * 512 - sector_offset;
-        ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors);
-        if (ret < 0) {
-            return -1;
-        }
-        if (decompress_buffer(s->cluster_cache, s->cluster_size,
-                              s->cluster_data + sector_offset, csize) < 0) {
-            return -1;
-        }
-        s->cluster_cache_offset = coffset;
-    }
-    return 0;
-}
-
-/* handle reading after the end of the backing file */
-static int backing_read1(BlockDriverState *bs,
-                         int64_t sector_num, uint8_t *buf, int nb_sectors)
-{
-    int n1;
-    if ((sector_num + nb_sectors) <= bs->total_sectors)
-        return nb_sectors;
-    if (sector_num >= bs->total_sectors)
-        n1 = 0;
-    else
-        n1 = bs->total_sectors - sector_num;
-    memset(buf + n1 * 512, 0, 512 * (nb_sectors - n1));
-    return n1;
-}
-
-static int qcow_read(BlockDriverState *bs, int64_t sector_num,
-                     uint8_t *buf, int nb_sectors)
-{
-    BDRVQcowState *s = bs->opaque;
-    int ret, index_in_cluster, n, n1;
-    uint64_t cluster_offset;
-
-    while (nb_sectors > 0) {
-        n = nb_sectors;
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, &n);
-        index_in_cluster = sector_num & (s->cluster_sectors - 1);
-        if (!cluster_offset) {
-            if (bs->backing_hd) {
-                /* read from the base image */
-                n1 = backing_read1(bs->backing_hd, sector_num, buf, n);
-                if (n1 > 0) {
-                    ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
-                    if (ret < 0)
-                        return -1;
-                }
-            } else {
-                memset(buf, 0, 512 * n);
-            }
-        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
-            if (decompress_cluster(s, cluster_offset) < 0)
-                return -1;
-            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
-        } else {
-            ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
-            if (ret != n * 512)
-                return -1;
-            if (s->crypt_method) {
-                encrypt_sectors(s, sector_num, buf, buf, n, 0,
-                                &s->aes_decrypt_key);
-            }
-        }
-        nb_sectors -= n;
-        sector_num += n;
-        buf += n * 512;
-    }
-    return 0;
-}
-
-static int qcow_write(BlockDriverState *bs, int64_t sector_num,
-                     const uint8_t *buf, int nb_sectors)
-{
-    BDRVQcowState *s = bs->opaque;
-    int ret, index_in_cluster, n;
-    uint64_t cluster_offset;
-    int n_end;
-
-    while (nb_sectors > 0) {
-        index_in_cluster = sector_num & (s->cluster_sectors - 1);
-        n_end = index_in_cluster + nb_sectors;
-        if (s->crypt_method &&
-            n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
-            n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
-        cluster_offset = alloc_cluster_offset(bs, sector_num << 9,
-                                              index_in_cluster,
-                                              n_end, &n);
-        if (!cluster_offset)
-            return -1;
-        if (s->crypt_method) {
-            encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
-                            &s->aes_encrypt_key);
-            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
-                              s->cluster_data, n * 512);
-        } else {
-            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
-        }
-        if (ret != n * 512)
-            return -1;
-        nb_sectors -= n;
-        sector_num += n;
-        buf += n * 512;
-    }
-    s->cluster_cache_offset = -1; /* disable compressed cache */
-    return 0;
-}
-
-typedef struct QCowAIOCB {
-    BlockDriverAIOCB common;
-    int64_t sector_num;
-    uint8_t *buf;
-    int nb_sectors;
-    int n;
-    uint64_t cluster_offset;
-    uint8_t *cluster_data;
-    BlockDriverAIOCB *hd_aiocb;
-} QCowAIOCB;
-
-static void qcow_aio_read_cb(void *opaque, int ret)
-{
-    QCowAIOCB *acb = opaque;
-    BlockDriverState *bs = acb->common.bs;
-    BDRVQcowState *s = bs->opaque;
-    int index_in_cluster, n1;
-
-    acb->hd_aiocb = NULL;
-    if (ret < 0) {
-    fail:
-        acb->common.cb(acb->common.opaque, ret);
-        qemu_aio_release(acb);
-        return;
-    }
-
- redo:
-    /* post process the read buffer */
-    if (!acb->cluster_offset) {
-        /* nothing to do */
-    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
-        /* nothing to do */
-    } else {
-        if (s->crypt_method) {
-            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
-                            acb->n, 0,
-                            &s->aes_decrypt_key);
-        }
-    }
-
-    acb->nb_sectors -= acb->n;
-    acb->sector_num += acb->n;
-    acb->buf += acb->n * 512;
-
-    if (acb->nb_sectors == 0) {
-        /* request completed */
-        acb->common.cb(acb->common.opaque, 0);
-        qemu_aio_release(acb);
-        return;
-    }
-
-    /* prepare next AIO request */
-    acb->n = acb->nb_sectors;
-    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, &acb->n);
-    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
-
-    if (!acb->cluster_offset) {
-        if (bs->backing_hd) {
-            /* read from the base image */
-            n1 = backing_read1(bs->backing_hd, acb->sector_num,
-                               acb->buf, acb->n);
-            if (n1 > 0) {
-                acb->hd_aiocb = bdrv_aio_read(bs->backing_hd, acb->sector_num,
-                                    acb->buf, acb->n, qcow_aio_read_cb, acb);
-                if (acb->hd_aiocb == NULL)
-                    goto fail;
-            } else {
-                goto redo;
-            }
-        } else {
-            /* Note: in this case, no need to wait */
-            memset(acb->buf, 0, 512 * acb->n);
-            goto redo;
-        }
-    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
-        /* add AIO support for compressed blocks ? */
-        if (decompress_cluster(s, acb->cluster_offset) < 0)
-            goto fail;
-        memcpy(acb->buf,
-               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
-        goto redo;
-    } else {
-        if ((acb->cluster_offset & 511) != 0) {
-            ret = -EIO;
-            goto fail;
-        }
-        acb->hd_aiocb = bdrv_aio_read(s->hd,
-                            (acb->cluster_offset >> 9) + index_in_cluster,
-                            acb->buf, acb->n, qcow_aio_read_cb, acb);
-        if (acb->hd_aiocb == NULL)
-            goto fail;
-    }
-}
-
-static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    QCowAIOCB *acb;
-
-    acb = qemu_aio_get(bs, cb, opaque);
-    if (!acb)
-        return NULL;
-    acb->hd_aiocb = NULL;
-    acb->sector_num = sector_num;
-    acb->buf = buf;
-    acb->nb_sectors = nb_sectors;
-    acb->n = 0;
-    acb->cluster_offset = 0;
-    return acb;
-}
-
-static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    QCowAIOCB *acb;
-
-    acb = qcow_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
-    if (!acb)
-        return NULL;
-
-    qcow_aio_read_cb(acb, 0);
-    return &acb->common;
-}
-
-static void qcow_aio_write_cb(void *opaque, int ret)
-{
-    QCowAIOCB *acb = opaque;
-    BlockDriverState *bs = acb->common.bs;
-    BDRVQcowState *s = bs->opaque;
-    int index_in_cluster;
-    uint64_t cluster_offset;
-    const uint8_t *src_buf;
-    int n_end;
-
-    acb->hd_aiocb = NULL;
-
-    if (ret < 0) {
-    fail:
-        acb->common.cb(acb->common.opaque, ret);
-        qemu_aio_release(acb);
-        return;
-    }
-
-    acb->nb_sectors -= acb->n;
-    acb->sector_num += acb->n;
-    acb->buf += acb->n * 512;
-
-    if (acb->nb_sectors == 0) {
-        /* request completed */
-        acb->common.cb(acb->common.opaque, 0);
-        qemu_aio_release(acb);
-        return;
-    }
-
-    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
-    n_end = index_in_cluster + acb->nb_sectors;
-    if (s->crypt_method &&
-        n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
-        n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
-
-    cluster_offset = alloc_cluster_offset(bs, acb->sector_num << 9,
-                                          index_in_cluster,
-                                          n_end, &acb->n);
-    if (!cluster_offset || (cluster_offset & 511) != 0) {
-        ret = -EIO;
-        goto fail;
-    }
-    if (s->crypt_method) {
-        if (!acb->cluster_data) {
-            acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
-                                             s->cluster_size);
-            if (!acb->cluster_data) {
-                ret = -ENOMEM;
-                goto fail;
-            }
-        }
-        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
-                        acb->n, 1, &s->aes_encrypt_key);
-        src_buf = acb->cluster_data;
-    } else {
-        src_buf = acb->buf;
-    }
-    acb->hd_aiocb = bdrv_aio_write(s->hd,
-                                   (cluster_offset >> 9) + index_in_cluster,
-                                   src_buf, acb->n,
-                                   qcow_aio_write_cb, acb);
-    if (acb->hd_aiocb == NULL)
-        goto fail;
-}
-
-static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
-        int64_t sector_num, const uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BDRVQcowState *s = bs->opaque;
-    QCowAIOCB *acb;
-
-    s->cluster_cache_offset = -1; /* disable compressed cache */
-
-    acb = qcow_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
-    if (!acb)
-        return NULL;
-
-    qcow_aio_write_cb(acb, 0);
-    return &acb->common;
-}
-
-static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
-{
-    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
-    if (acb->hd_aiocb)
-        bdrv_aio_cancel(acb->hd_aiocb);
-    qemu_aio_release(acb);
-}
-
-static void qcow_close(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    qemu_free(s->l1_table);
-    qemu_free(s->l2_cache);
-    qemu_free(s->cluster_cache);
-    qemu_free(s->cluster_data);
-    refcount_close(bs);
-    bdrv_delete(s->hd);
-}
-
-/* XXX: use std qcow open function ? */
-typedef struct QCowCreateState {
-    int cluster_size;
-    int cluster_bits;
-    uint16_t *refcount_block;
-    uint64_t *refcount_table;
-    int64_t l1_table_offset;
-    int64_t refcount_table_offset;
-    int64_t refcount_block_offset;
-} QCowCreateState;
-
-static void create_refcount_update(QCowCreateState *s,
-                                   int64_t offset, int64_t size)
-{
-    int refcount;
-    int64_t start, last, cluster_offset;
-    uint16_t *p;
-
-    start = offset & ~(s->cluster_size - 1);
-    last = (offset + size - 1)  & ~(s->cluster_size - 1);
-    for(cluster_offset = start; cluster_offset <= last;
-        cluster_offset += s->cluster_size) {
-        p = &s->refcount_block[cluster_offset >> s->cluster_bits];
-        refcount = be16_to_cpu(*p);
-        refcount++;
-        *p = cpu_to_be16(refcount);
-    }
-}
-
-static int qcow_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
-{
-    int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
-    QCowHeader header;
-    uint64_t tmp, offset;
-    QCowCreateState s1, *s = &s1;
-
-    memset(s, 0, sizeof(*s));
-
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-    if (fd < 0)
-        return -1;
-    memset(&header, 0, sizeof(header));
-    header.magic = cpu_to_be32(QCOW_MAGIC);
-    header.version = cpu_to_be32(QCOW_VERSION);
-    header.size = cpu_to_be64(total_size * 512);
-    header_size = sizeof(header);
-    backing_filename_len = 0;
-    if (backing_file) {
-        header.backing_file_offset = cpu_to_be64(header_size);
-        backing_filename_len = strlen(backing_file);
-        header.backing_file_size = cpu_to_be32(backing_filename_len);
-        header_size += backing_filename_len;
-    }
-    s->cluster_bits = 12;  /* 4 KB clusters */
-    s->cluster_size = 1 << s->cluster_bits;
-    header.cluster_bits = cpu_to_be32(s->cluster_bits);
-    header_size = (header_size + 7) & ~7;
-    if (flags & BLOCK_FLAG_ENCRYPT) {
-        header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
-    } else {
-        header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
-    }
-    l2_bits = s->cluster_bits - 3;
-    shift = s->cluster_bits + l2_bits;
-    l1_size = (((total_size * 512) + (1LL << shift) - 1) >> shift);
-    offset = align_offset(header_size, s->cluster_size);
-    s->l1_table_offset = offset;
-    header.l1_table_offset = cpu_to_be64(s->l1_table_offset);
-    header.l1_size = cpu_to_be32(l1_size);
-    offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
-
-    s->refcount_table = qemu_mallocz(s->cluster_size);
-    if (!s->refcount_table)
-        goto fail;
-    s->refcount_block = qemu_mallocz(s->cluster_size);
-    if (!s->refcount_block)
-        goto fail;
-
-    s->refcount_table_offset = offset;
-    header.refcount_table_offset = cpu_to_be64(offset);
-    header.refcount_table_clusters = cpu_to_be32(1);
-    offset += s->cluster_size;
-
-    s->refcount_table[0] = cpu_to_be64(offset);
-    s->refcount_block_offset = offset;
-    offset += s->cluster_size;
-
-    /* update refcounts */
-    create_refcount_update(s, 0, header_size);
-    create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
-    create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
-    create_refcount_update(s, s->refcount_block_offset, s->cluster_size);
-
-    /* write all the data */
-    write(fd, &header, sizeof(header));
-    if (backing_file) {
-        write(fd, backing_file, backing_filename_len);
-    }
-    lseek(fd, s->l1_table_offset, SEEK_SET);
-    tmp = 0;
-    for(i = 0;i < l1_size; i++) {
-        write(fd, &tmp, sizeof(tmp));
-    }
-    lseek(fd, s->refcount_table_offset, SEEK_SET);
-    write(fd, s->refcount_table, s->cluster_size);
-
-    lseek(fd, s->refcount_block_offset, SEEK_SET);
-    write(fd, s->refcount_block, s->cluster_size);
-
-    qemu_free(s->refcount_table);
-    qemu_free(s->refcount_block);
-    close(fd);
-    return 0;
- fail:
-    qemu_free(s->refcount_table);
-    qemu_free(s->refcount_block);
-    close(fd);
-    return -ENOMEM;
-}
-
-static int qcow_make_empty(BlockDriverState *bs)
-{
-#if 0
-    /* XXX: not correct */
-    BDRVQcowState *s = bs->opaque;
-    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
-    int ret;
-
-    memset(s->l1_table, 0, l1_length);
-    if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
-	return -1;
-    ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
-    if (ret < 0)
-        return ret;
-
-    l2_cache_reset(bs);
-#endif
-    return 0;
-}
-
-/* XXX: put compressed sectors first, then all the cluster aligned
-   tables to avoid losing bytes in alignment */
-static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
-                                 const uint8_t *buf, int nb_sectors)
-{
-    BDRVQcowState *s = bs->opaque;
-    z_stream strm;
-    int ret, out_len;
-    uint8_t *out_buf;
-    uint64_t cluster_offset;
-
-    if (nb_sectors == 0) {
-        /* align end of file to a sector boundary to ease reading with
-           sector based I/Os */
-        cluster_offset = bdrv_getlength(s->hd);
-        cluster_offset = (cluster_offset + 511) & ~511;
-        bdrv_truncate(s->hd, cluster_offset);
-        return 0;
-    }
-
-    if (nb_sectors != s->cluster_sectors)
-        return -EINVAL;
-
-    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
-    if (!out_buf)
-        return -ENOMEM;
-
-    /* best compression, small window, no zlib header */
-    memset(&strm, 0, sizeof(strm));
-    ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
-                       Z_DEFLATED, -12,
-                       9, Z_DEFAULT_STRATEGY);
-    if (ret != 0) {
-        qemu_free(out_buf);
-        return -1;
-    }
-
-    strm.avail_in = s->cluster_size;
-    strm.next_in = (uint8_t *)buf;
-    strm.avail_out = s->cluster_size;
-    strm.next_out = out_buf;
-
-    ret = deflate(&strm, Z_FINISH);
-    if (ret != Z_STREAM_END && ret != Z_OK) {
-        qemu_free(out_buf);
-        deflateEnd(&strm);
-        return -1;
-    }
-    out_len = strm.next_out - out_buf;
-
-    deflateEnd(&strm);
-
-    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
-        /* could not compress: write normal cluster */
-        qcow_write(bs, sector_num, buf, s->cluster_sectors);
-    } else {
-        cluster_offset = alloc_compressed_cluster_offset(bs, sector_num << 9,
-                                              out_len);
-        if (!cluster_offset)
-            return -1;
-        cluster_offset &= s->cluster_offset_mask;
-        if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
-            qemu_free(out_buf);
-            return -1;
-        }
-    }
-
-    qemu_free(out_buf);
-    return 0;
-}
-
-static void qcow_flush(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    bdrv_flush(s->hd);
-}
-
-static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
-{
-    BDRVQcowState *s = bs->opaque;
-    bdi->cluster_size = s->cluster_size;
-    bdi->vm_state_offset = (int64_t)s->l1_vm_state_index <<
-        (s->cluster_bits + s->l2_bits);
-    return 0;
-}
-
-/*********************************************************/
-/* snapshot support */
-
-/* update the refcounts of snapshots and the copied flag */
-static int update_snapshot_refcount(BlockDriverState *bs,
-                                    int64_t l1_table_offset,
-                                    int l1_size,
-                                    int addend)
-{
-    BDRVQcowState *s = bs->opaque;
-    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
-    int64_t old_offset, old_l2_offset;
-    int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
-
-    l2_cache_reset(bs);
-
-    l2_table = NULL;
-    l1_table = NULL;
-    l1_size2 = l1_size * sizeof(uint64_t);
-    l1_allocated = 0;
-    if (l1_table_offset != s->l1_table_offset) {
-        l1_table = qemu_malloc(l1_size2);
-        if (!l1_table)
-            goto fail;
-        l1_allocated = 1;
-        if (bdrv_pread(s->hd, l1_table_offset,
-                       l1_table, l1_size2) != l1_size2)
-            goto fail;
-        for(i = 0;i < l1_size; i++)
-            be64_to_cpus(&l1_table[i]);
-    } else {
-        assert(l1_size == s->l1_size);
-        l1_table = s->l1_table;
-        l1_allocated = 0;
-    }
-
-    l2_size = s->l2_size * sizeof(uint64_t);
-    l2_table = qemu_malloc(l2_size);
-    if (!l2_table)
-        goto fail;
-    l1_modified = 0;
-    for(i = 0; i < l1_size; i++) {
-        l2_offset = l1_table[i];
-        if (l2_offset) {
-            old_l2_offset = l2_offset;
-            l2_offset &= ~QCOW_OFLAG_COPIED;
-            l2_modified = 0;
-            if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
-                goto fail;
-            for(j = 0; j < s->l2_size; j++) {
-                offset = be64_to_cpu(l2_table[j]);
-                if (offset != 0) {
-                    old_offset = offset;
-                    offset &= ~QCOW_OFLAG_COPIED;
-                    if (offset & QCOW_OFLAG_COMPRESSED) {
-                        nb_csectors = ((offset >> s->csize_shift) &
-                                       s->csize_mask) + 1;
-                        if (addend != 0)
-                            update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
-                                            nb_csectors * 512, addend);
-                        /* compressed clusters are never modified */
-                        refcount = 2;
-                    } else {
-                        if (addend != 0) {
-                            refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
-                        } else {
-                            refcount = get_refcount(bs, offset >> s->cluster_bits);
-                        }
-                    }
-
-                    if (refcount == 1) {
-                        offset |= QCOW_OFLAG_COPIED;
-                    }
-                    if (offset != old_offset) {
-                        l2_table[j] = cpu_to_be64(offset);
-                        l2_modified = 1;
-                    }
-                }
-            }
-            if (l2_modified) {
-                if (bdrv_pwrite(s->hd,
-                                l2_offset, l2_table, l2_size) != l2_size)
-                    goto fail;
-            }
-
-            if (addend != 0) {
-                refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);
-            } else {
-                refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
-            }
-            if (refcount == 1) {
-                l2_offset |= QCOW_OFLAG_COPIED;
-            }
-            if (l2_offset != old_l2_offset) {
-                l1_table[i] = l2_offset;
-                l1_modified = 1;
-            }
-        }
-    }
-    if (l1_modified) {
-        for(i = 0; i < l1_size; i++)
-            cpu_to_be64s(&l1_table[i]);
-        if (bdrv_pwrite(s->hd, l1_table_offset, l1_table,
-                        l1_size2) != l1_size2)
-            goto fail;
-        for(i = 0; i < l1_size; i++)
-            be64_to_cpus(&l1_table[i]);
-    }
-    if (l1_allocated)
-        qemu_free(l1_table);
-    qemu_free(l2_table);
-    return 0;
- fail:
-    if (l1_allocated)
-        qemu_free(l1_table);
-    qemu_free(l2_table);
-    return -EIO;
-}
-
-static void qcow_free_snapshots(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    int i;
-
-    for(i = 0; i < s->nb_snapshots; i++) {
-        qemu_free(s->snapshots[i].name);
-        qemu_free(s->snapshots[i].id_str);
-    }
-    qemu_free(s->snapshots);
-    s->snapshots = NULL;
-    s->nb_snapshots = 0;
-}
-
-static int qcow_read_snapshots(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    QCowSnapshotHeader h;
-    QCowSnapshot *sn;
-    int i, id_str_size, name_size;
-    int64_t offset;
-    uint32_t extra_data_size;
-
-    offset = s->snapshots_offset;
-    s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
-    if (!s->snapshots)
-        goto fail;
-    for(i = 0; i < s->nb_snapshots; i++) {
-        offset = align_offset(offset, 8);
-        if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
-            goto fail;
-        offset += sizeof(h);
-        sn = s->snapshots + i;
-        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
-        sn->l1_size = be32_to_cpu(h.l1_size);
-        sn->vm_state_size = be32_to_cpu(h.vm_state_size);
-        sn->date_sec = be32_to_cpu(h.date_sec);
-        sn->date_nsec = be32_to_cpu(h.date_nsec);
-        sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
-        extra_data_size = be32_to_cpu(h.extra_data_size);
-
-        id_str_size = be16_to_cpu(h.id_str_size);
-        name_size = be16_to_cpu(h.name_size);
-
-        offset += extra_data_size;
-
-        sn->id_str = qemu_malloc(id_str_size + 1);
-        if (!sn->id_str)
-            goto fail;
-        if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
-            goto fail;
-        offset += id_str_size;
-        sn->id_str[id_str_size] = '\0';
-
-        sn->name = qemu_malloc(name_size + 1);
-        if (!sn->name)
-            goto fail;
-        if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
-            goto fail;
-        offset += name_size;
-        sn->name[name_size] = '\0';
-    }
-    s->snapshots_size = offset - s->snapshots_offset;
-    return 0;
- fail:
-    qcow_free_snapshots(bs);
-    return -1;
-}
-
-/* add at the end of the file a new list of snapshots */
-static int qcow_write_snapshots(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    QCowSnapshot *sn;
-    QCowSnapshotHeader h;
-    int i, name_size, id_str_size, snapshots_size;
-    uint64_t data64;
-    uint32_t data32;
-    int64_t offset, snapshots_offset;
-
-    /* compute the size of the snapshots */
-    offset = 0;
-    for(i = 0; i < s->nb_snapshots; i++) {
-        sn = s->snapshots + i;
-        offset = align_offset(offset, 8);
-        offset += sizeof(h);
-        offset += strlen(sn->id_str);
-        offset += strlen(sn->name);
-    }
-    snapshots_size = offset;
-
-    snapshots_offset = alloc_clusters(bs, snapshots_size);
-    offset = snapshots_offset;
-
-    for(i = 0; i < s->nb_snapshots; i++) {
-        sn = s->snapshots + i;
-        memset(&h, 0, sizeof(h));
-        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
-        h.l1_size = cpu_to_be32(sn->l1_size);
-        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
-        h.date_sec = cpu_to_be32(sn->date_sec);
-        h.date_nsec = cpu_to_be32(sn->date_nsec);
-        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
-
-        id_str_size = strlen(sn->id_str);
-        name_size = strlen(sn->name);
-        h.id_str_size = cpu_to_be16(id_str_size);
-        h.name_size = cpu_to_be16(name_size);
-        offset = align_offset(offset, 8);
-        if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
-            goto fail;
-        offset += sizeof(h);
-        if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
-            goto fail;
-        offset += id_str_size;
-        if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
-            goto fail;
-        offset += name_size;
-    }
-
-    /* update the various header fields */
-    data64 = cpu_to_be64(snapshots_offset);
-    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
-                    &data64, sizeof(data64)) != sizeof(data64))
-        goto fail;
-    data32 = cpu_to_be32(s->nb_snapshots);
-    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
-                    &data32, sizeof(data32)) != sizeof(data32))
-        goto fail;
-
-    /* free the old snapshot table */
-    free_clusters(bs, s->snapshots_offset, s->snapshots_size);
-    s->snapshots_offset = snapshots_offset;
-    s->snapshots_size = snapshots_size;
-    return 0;
- fail:
-    return -1;
-}
-
-static void find_new_snapshot_id(BlockDriverState *bs,
-                                 char *id_str, int id_str_size)
-{
-    BDRVQcowState *s = bs->opaque;
-    QCowSnapshot *sn;
-    int i, id, id_max = 0;
-
-    for(i = 0; i < s->nb_snapshots; i++) {
-        sn = s->snapshots + i;
-        id = strtoul(sn->id_str, NULL, 10);
-        if (id > id_max)
-            id_max = id;
-    }
-    snprintf(id_str, id_str_size, "%d", id_max + 1);
-}
-
-static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
-{
-    BDRVQcowState *s = bs->opaque;
-    int i;
-
-    for(i = 0; i < s->nb_snapshots; i++) {
-        if (!strcmp(s->snapshots[i].id_str, id_str))
-            return i;
-    }
-    return -1;
-}
-
-static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
-{
-    BDRVQcowState *s = bs->opaque;
-    int i, ret;
-
-    ret = find_snapshot_by_id(bs, name);
-    if (ret >= 0)
-        return ret;
-    for(i = 0; i < s->nb_snapshots; i++) {
-        if (!strcmp(s->snapshots[i].name, name))
-            return i;
-    }
-    return -1;
-}
-
-/* if no id is provided, a new one is constructed */
-static int qcow_snapshot_create(BlockDriverState *bs,
-                                QEMUSnapshotInfo *sn_info)
-{
-    BDRVQcowState *s = bs->opaque;
-    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
-    int i, ret;
-    uint64_t *l1_table = NULL;
-
-    memset(sn, 0, sizeof(*sn));
-
-    if (sn_info->id_str[0] == '\0') {
-        /* compute a new id */
-        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
-    }
-
-    /* check that the ID is unique */
-    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
-        return -ENOENT;
-
-    sn->id_str = qemu_strdup(sn_info->id_str);
-    if (!sn->id_str)
-        goto fail;
-    sn->name = qemu_strdup(sn_info->name);
-    if (!sn->name)
-        goto fail;
-    sn->vm_state_size = sn_info->vm_state_size;
-    sn->date_sec = sn_info->date_sec;
-    sn->date_nsec = sn_info->date_nsec;
-    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
-
-    ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
-    if (ret < 0)
-        goto fail;
-
-    /* create the L1 table of the snapshot */
-    sn->l1_table_offset = alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
-    sn->l1_size = s->l1_size;
-
-    l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
-    if (!l1_table)
-        goto fail;
-    for(i = 0; i < s->l1_size; i++) {
-        l1_table[i] = cpu_to_be64(s->l1_table[i]);
-    }
-    if (bdrv_pwrite(s->hd, sn->l1_table_offset,
-                    l1_table, s->l1_size * sizeof(uint64_t)) !=
-        (s->l1_size * sizeof(uint64_t)))
-        goto fail;
-    qemu_free(l1_table);
-    l1_table = NULL;
-
-    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
-    if (!snapshots1)
-        goto fail;
-    memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
-    s->snapshots = snapshots1;
-    s->snapshots[s->nb_snapshots++] = *sn;
-
-    if (qcow_write_snapshots(bs) < 0)
-        goto fail;
-#ifdef DEBUG_ALLOC
-    check_refcounts(bs);
-#endif
-    return 0;
- fail:
-    qemu_free(sn->name);
-    qemu_free(l1_table);
-    return -1;
-}
-
-/* copy the snapshot 'snapshot_name' into the current disk image */
-static int qcow_snapshot_goto(BlockDriverState *bs,
-                              const char *snapshot_id)
-{
-    BDRVQcowState *s = bs->opaque;
-    QCowSnapshot *sn;
-    int i, snapshot_index, l1_size2;
-
-    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
-    if (snapshot_index < 0)
-        return -ENOENT;
-    sn = &s->snapshots[snapshot_index];
-
-    if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
-        goto fail;
-
-    if (grow_l1_table(bs, sn->l1_size) < 0)
-        goto fail;
-
-    s->l1_size = sn->l1_size;
-    l1_size2 = s->l1_size * sizeof(uint64_t);
-    /* copy the snapshot l1 table to the current l1 table */
-    if (bdrv_pread(s->hd, sn->l1_table_offset,
-                   s->l1_table, l1_size2) != l1_size2)
-        goto fail;
-    if (bdrv_pwrite(s->hd, s->l1_table_offset,
-                    s->l1_table, l1_size2) != l1_size2)
-        goto fail;
-    for(i = 0;i < s->l1_size; i++) {
-        be64_to_cpus(&s->l1_table[i]);
-    }
-
-    if (update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
-        goto fail;
-
-#ifdef DEBUG_ALLOC
-    check_refcounts(bs);
-#endif
-    return 0;
- fail:
-    return -EIO;
-}
-
-static int qcow_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
-{
-    BDRVQcowState *s = bs->opaque;
-    QCowSnapshot *sn;
-    int snapshot_index, ret;
-
-    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
-    if (snapshot_index < 0)
-        return -ENOENT;
-    sn = &s->snapshots[snapshot_index];
-
-    ret = update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
-    if (ret < 0)
-        return ret;
-    /* must update the copied flag on the current cluster offsets */
-    ret = update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
-    if (ret < 0)
-        return ret;
-    free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
-
-    qemu_free(sn->id_str);
-    qemu_free(sn->name);
-    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
-    s->nb_snapshots--;
-    ret = qcow_write_snapshots(bs);
-    if (ret < 0) {
-        /* XXX: restore snapshot if error ? */
-        return ret;
-    }
-#ifdef DEBUG_ALLOC
-    check_refcounts(bs);
-#endif
-    return 0;
-}
-
-static int qcow_snapshot_list(BlockDriverState *bs,
-                              QEMUSnapshotInfo **psn_tab)
-{
-    BDRVQcowState *s = bs->opaque;
-    QEMUSnapshotInfo *sn_tab, *sn_info;
-    QCowSnapshot *sn;
-    int i;
-
-    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
-    if (!sn_tab)
-        goto fail;
-    for(i = 0; i < s->nb_snapshots; i++) {
-        sn_info = sn_tab + i;
-        sn = s->snapshots + i;
-        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
-                sn->id_str);
-        pstrcpy(sn_info->name, sizeof(sn_info->name),
-                sn->name);
-        sn_info->vm_state_size = sn->vm_state_size;
-        sn_info->date_sec = sn->date_sec;
-        sn_info->date_nsec = sn->date_nsec;
-        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
-    }
-    *psn_tab = sn_tab;
-    return s->nb_snapshots;
- fail:
-    qemu_free(sn_tab);
-    *psn_tab = NULL;
-    return -ENOMEM;
-}
-
-/*********************************************************/
-/* refcount handling */
-
-static int refcount_init(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    int ret, refcount_table_size2, i;
-
-    s->refcount_block_cache = qemu_malloc(s->cluster_size);
-    if (!s->refcount_block_cache)
-        goto fail;
-    refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
-    s->refcount_table = qemu_malloc(refcount_table_size2);
-    if (!s->refcount_table)
-        goto fail;
-    if (s->refcount_table_size > 0) {
-        ret = bdrv_pread(s->hd, s->refcount_table_offset,
-                         s->refcount_table, refcount_table_size2);
-        if (ret != refcount_table_size2)
-            goto fail;
-        for(i = 0; i < s->refcount_table_size; i++)
-            be64_to_cpus(&s->refcount_table[i]);
-    }
-    return 0;
- fail:
-    return -ENOMEM;
-}
-
-static void refcount_close(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    qemu_free(s->refcount_block_cache);
-    qemu_free(s->refcount_table);
-}
-
-
-static int load_refcount_block(BlockDriverState *bs,
-                               int64_t refcount_block_offset)
-{
-    BDRVQcowState *s = bs->opaque;
-    int ret;
-    ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache,
-                     s->cluster_size);
-    if (ret != s->cluster_size)
-        return -EIO;
-    s->refcount_block_cache_offset = refcount_block_offset;
-    return 0;
-}
-
-static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
-{
-    BDRVQcowState *s = bs->opaque;
-    int refcount_table_index, block_index;
-    int64_t refcount_block_offset;
-
-    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
-    if (refcount_table_index >= s->refcount_table_size)
-        return 0;
-    refcount_block_offset = s->refcount_table[refcount_table_index];
-    if (!refcount_block_offset)
-        return 0;
-    if (refcount_block_offset != s->refcount_block_cache_offset) {
-        /* better than nothing: return allocated if read error */
-        if (load_refcount_block(bs, refcount_block_offset) < 0)
-            return 1;
-    }
-    block_index = cluster_index &
-        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
-    return be16_to_cpu(s->refcount_block_cache[block_index]);
-}
-
-/* return < 0 if error */
-static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
-{
-    BDRVQcowState *s = bs->opaque;
-    int i, nb_clusters;
-
-    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
-    for(;;) {
-        if (get_refcount(bs, s->free_cluster_index) == 0) {
-            s->free_cluster_index++;
-            for(i = 1; i < nb_clusters; i++) {
-                if (get_refcount(bs, s->free_cluster_index) != 0)
-                    goto not_found;
-                s->free_cluster_index++;
-            }
-#ifdef DEBUG_ALLOC2
-            printf("alloc_clusters: size=%lld -> %lld\n",
-                   size,
-                   (s->free_cluster_index - nb_clusters) << s->cluster_bits);
-#endif
-            return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
-        } else {
-        not_found:
-            s->free_cluster_index++;
-        }
-    }
-}
-
-static int64_t alloc_clusters(BlockDriverState *bs, int64_t size)
-{
-    int64_t offset;
-
-    offset = alloc_clusters_noref(bs, size);
-    update_refcount(bs, offset, size, 1);
-    return offset;
-}
-
-/* only used to allocate compressed sectors. We try to allocate
-   contiguous sectors. size must be <= cluster_size */
-static int64_t alloc_bytes(BlockDriverState *bs, int size)
-{
-    BDRVQcowState *s = bs->opaque;
-    int64_t offset, cluster_offset;
-    int free_in_cluster;
-
-    assert(size > 0 && size <= s->cluster_size);
-    if (s->free_byte_offset == 0) {
-        s->free_byte_offset = alloc_clusters(bs, s->cluster_size);
-    }
- redo:
-    free_in_cluster = s->cluster_size -
-        (s->free_byte_offset & (s->cluster_size - 1));
-    if (size <= free_in_cluster) {
-        /* enough space in current cluster */
-        offset = s->free_byte_offset;
-        s->free_byte_offset += size;
-        free_in_cluster -= size;
-        if (free_in_cluster == 0)
-            s->free_byte_offset = 0;
-        if ((offset & (s->cluster_size - 1)) != 0)
-            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
-    } else {
-        offset = alloc_clusters(bs, s->cluster_size);
-        cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
-        if ((cluster_offset + s->cluster_size) == offset) {
-            /* we are lucky: contiguous data */
-            offset = s->free_byte_offset;
-            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
-            s->free_byte_offset += size;
-        } else {
-            s->free_byte_offset = offset;
-            goto redo;
-        }
-    }
-    return offset;
-}
-
-static void free_clusters(BlockDriverState *bs,
-                          int64_t offset, int64_t size)
-{
-    update_refcount(bs, offset, size, -1);
-}
-
-static int grow_refcount_table(BlockDriverState *bs, int min_size)
-{
-    BDRVQcowState *s = bs->opaque;
-    int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
-    uint64_t *new_table;
-    int64_t table_offset;
-    uint64_t data64;
-    uint32_t data32;
-    int old_table_size;
-    int64_t old_table_offset;
-
-    if (min_size <= s->refcount_table_size)
-        return 0;
-    /* compute new table size */
-    refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
-    for(;;) {
-        if (refcount_table_clusters == 0) {
-            refcount_table_clusters = 1;
-        } else {
-            refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
-        }
-        new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
-        if (min_size <= new_table_size)
-            break;
-    }
-#ifdef DEBUG_ALLOC2
-    printf("grow_refcount_table from %d to %d\n",
-           s->refcount_table_size,
-           new_table_size);
-#endif
-    new_table_size2 = new_table_size * sizeof(uint64_t);
-    new_table = qemu_mallocz(new_table_size2);
-    if (!new_table)
-        return -ENOMEM;
-    memcpy(new_table, s->refcount_table,
-           s->refcount_table_size * sizeof(uint64_t));
-    for(i = 0; i < s->refcount_table_size; i++)
-        cpu_to_be64s(&new_table[i]);
-    /* Note: we cannot update the refcount now to avoid recursion */
-    table_offset = alloc_clusters_noref(bs, new_table_size2);
-    ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
-    if (ret != new_table_size2)
-        goto fail;
-    for(i = 0; i < s->refcount_table_size; i++)
-        be64_to_cpus(&new_table[i]);
-
-    data64 = cpu_to_be64(table_offset);
-    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
-                    &data64, sizeof(data64)) != sizeof(data64))
-        goto fail;
-    data32 = cpu_to_be32(refcount_table_clusters);
-    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_clusters),
-                    &data32, sizeof(data32)) != sizeof(data32))
-        goto fail;
-    qemu_free(s->refcount_table);
-    old_table_offset = s->refcount_table_offset;
-    old_table_size = s->refcount_table_size;
-    s->refcount_table = new_table;
-    s->refcount_table_size = new_table_size;
-    s->refcount_table_offset = table_offset;
-
-    update_refcount(bs, table_offset, new_table_size2, 1);
-    free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
-    return 0;
- fail:
-    free_clusters(bs, table_offset, new_table_size2);
-    qemu_free(new_table);
-    return -EIO;
-}
-
-/* addend must be 1 or -1 */
-/* XXX: cache several refcount block clusters ? */
-static int update_cluster_refcount(BlockDriverState *bs,
-                                   int64_t cluster_index,
-                                   int addend)
-{
-    BDRVQcowState *s = bs->opaque;
-    int64_t offset, refcount_block_offset;
-    int ret, refcount_table_index, block_index, refcount;
-    uint64_t data64;
-
-    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
-    if (refcount_table_index >= s->refcount_table_size) {
-        if (addend < 0)
-            return -EINVAL;
-        ret = grow_refcount_table(bs, refcount_table_index + 1);
-        if (ret < 0)
-            return ret;
-    }
-    refcount_block_offset = s->refcount_table[refcount_table_index];
-    if (!refcount_block_offset) {
-        if (addend < 0)
-            return -EINVAL;
-        /* create a new refcount block */
-        /* Note: we cannot update the refcount now to avoid recursion */
-        offset = alloc_clusters_noref(bs, s->cluster_size);
-        memset(s->refcount_block_cache, 0, s->cluster_size);
-        ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
-        if (ret != s->cluster_size)
-            return -EINVAL;
-        s->refcount_table[refcount_table_index] = offset;
-        data64 = cpu_to_be64(offset);
-        ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
-                          refcount_table_index * sizeof(uint64_t),
-                          &data64, sizeof(data64));
-        if (ret != sizeof(data64))
-            return -EINVAL;
-
-        refcount_block_offset = offset;
-        s->refcount_block_cache_offset = offset;
-        update_refcount(bs, offset, s->cluster_size, 1);
-    } else {
-        if (refcount_block_offset != s->refcount_block_cache_offset) {
-            if (load_refcount_block(bs, refcount_block_offset) < 0)
-                return -EIO;
-        }
-    }
-    /* we can update the count and save it */
-    block_index = cluster_index &
-        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
-    refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
-    refcount += addend;
-    if (refcount < 0 || refcount > 0xffff)
-        return -EINVAL;
-    if (refcount == 0 && cluster_index < s->free_cluster_index) {
-        s->free_cluster_index = cluster_index;
-    }
-    s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
-    if (bdrv_pwrite(s->hd,
-                    refcount_block_offset + (block_index << REFCOUNT_SHIFT),
-                    &s->refcount_block_cache[block_index], 2) != 2)
-        return -EIO;
-    return refcount;
-}
-
-static void update_refcount(BlockDriverState *bs,
-                            int64_t offset, int64_t length,
-                            int addend)
-{
-    BDRVQcowState *s = bs->opaque;
-    int64_t start, last, cluster_offset;
-
-#ifdef DEBUG_ALLOC2
-    printf("update_refcount: offset=%lld size=%lld addend=%d\n",
-           offset, length, addend);
-#endif
-    if (length <= 0)
-        return;
-    start = offset & ~(s->cluster_size - 1);
-    last = (offset + length - 1) & ~(s->cluster_size - 1);
-    for(cluster_offset = start; cluster_offset <= last;
-        cluster_offset += s->cluster_size) {
-        update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
-    }
-}
-
-#ifdef DEBUG_ALLOC
-static void inc_refcounts(BlockDriverState *bs,
-                          uint16_t *refcount_table,
-                          int refcount_table_size,
-                          int64_t offset, int64_t size)
-{
-    BDRVQcowState *s = bs->opaque;
-    int64_t start, last, cluster_offset;
-    int k;
-
-    if (size <= 0)
-        return;
-
-    start = offset & ~(s->cluster_size - 1);
-    last = (offset + size - 1) & ~(s->cluster_size - 1);
-    for(cluster_offset = start; cluster_offset <= last;
-        cluster_offset += s->cluster_size) {
-        k = cluster_offset >> s->cluster_bits;
-        if (k < 0 || k >= refcount_table_size) {
-            printf("ERROR: invalid cluster offset=0x%llx\n", cluster_offset);
-        } else {
-            if (++refcount_table[k] == 0) {
-                printf("ERROR: overflow cluster offset=0x%llx\n", cluster_offset);
-            }
-        }
-    }
-}
-
-static int check_refcounts_l1(BlockDriverState *bs,
-                              uint16_t *refcount_table,
-                              int refcount_table_size,
-                              int64_t l1_table_offset, int l1_size,
-                              int check_copied)
-{
-    BDRVQcowState *s = bs->opaque;
-    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
-    int l2_size, i, j, nb_csectors, refcount;
-
-    l2_table = NULL;
-    l1_size2 = l1_size * sizeof(uint64_t);
-
-    inc_refcounts(bs, refcount_table, refcount_table_size,
-                  l1_table_offset, l1_size2);
-
-    l1_table = qemu_malloc(l1_size2);
-    if (!l1_table)
-        goto fail;
-    if (bdrv_pread(s->hd, l1_table_offset,
-                   l1_table, l1_size2) != l1_size2)
-        goto fail;
-    for(i = 0;i < l1_size; i++)
-        be64_to_cpus(&l1_table[i]);
-
-    l2_size = s->l2_size * sizeof(uint64_t);
-    l2_table = qemu_malloc(l2_size);
-    if (!l2_table)
-        goto fail;
-    for(i = 0; i < l1_size; i++) {
-        l2_offset = l1_table[i];
-        if (l2_offset) {
-            if (check_copied) {
-                refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);
-                if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
-                    printf("ERROR OFLAG_COPIED: l2_offset=%llx refcount=%d\n",
-                           l2_offset, refcount);
-                }
-            }
-            l2_offset &= ~QCOW_OFLAG_COPIED;
-            if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
-                goto fail;
-            for(j = 0; j < s->l2_size; j++) {
-                offset = be64_to_cpu(l2_table[j]);
-                if (offset != 0) {
-                    if (offset & QCOW_OFLAG_COMPRESSED) {
-                        if (offset & QCOW_OFLAG_COPIED) {
-                            printf("ERROR: cluster %lld: copied flag must never be set for compressed clusters\n",
-                                   offset >> s->cluster_bits);
-                            offset &= ~QCOW_OFLAG_COPIED;
-                        }
-                        nb_csectors = ((offset >> s->csize_shift) &
-                                       s->csize_mask) + 1;
-                        offset &= s->cluster_offset_mask;
-                        inc_refcounts(bs, refcount_table,
-                                      refcount_table_size,
-                                      offset & ~511, nb_csectors * 512);
-                    } else {
-                        if (check_copied) {
-                            refcount = get_refcount(bs, (offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);
-                            if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {
-                                printf("ERROR OFLAG_COPIED: offset=%llx refcount=%d\n",
-                                       offset, refcount);
-                            }
-                        }
-                        offset &= ~QCOW_OFLAG_COPIED;
-                        inc_refcounts(bs, refcount_table,
-                                      refcount_table_size,
-                                      offset, s->cluster_size);
-                    }
-                }
-            }
-            inc_refcounts(bs, refcount_table,
-                          refcount_table_size,
-                          l2_offset,
-                          s->cluster_size);
-        }
-    }
-    qemu_free(l1_table);
-    qemu_free(l2_table);
-    return 0;
- fail:
-    printf("ERROR: I/O error in check_refcounts_l1\n");
-    qemu_free(l1_table);
-    qemu_free(l2_table);
-    return -EIO;
-}
-
-static void check_refcounts(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    int64_t size;
-    int nb_clusters, refcount1, refcount2, i;
-    QCowSnapshot *sn;
-    uint16_t *refcount_table;
-
-    size = bdrv_getlength(s->hd);
-    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
-    refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
-
-    /* header */
-    inc_refcounts(bs, refcount_table, nb_clusters,
-                  0, s->cluster_size);
-
-    check_refcounts_l1(bs, refcount_table, nb_clusters,
-                       s->l1_table_offset, s->l1_size, 1);
-
-    /* snapshots */
-    for(i = 0; i < s->nb_snapshots; i++) {
-        sn = s->snapshots + i;
-        check_refcounts_l1(bs, refcount_table, nb_clusters,
-                           sn->l1_table_offset, sn->l1_size, 0);
-    }
-    inc_refcounts(bs, refcount_table, nb_clusters,
-                  s->snapshots_offset, s->snapshots_size);
-
-    /* refcount data */
-    inc_refcounts(bs, refcount_table, nb_clusters,
-                  s->refcount_table_offset,
-                  s->refcount_table_size * sizeof(uint64_t));
-    for(i = 0; i < s->refcount_table_size; i++) {
-        int64_t offset;
-        offset = s->refcount_table[i];
-        if (offset != 0) {
-            inc_refcounts(bs, refcount_table, nb_clusters,
-                          offset, s->cluster_size);
-        }
-    }
-
-    /* compare ref counts */
-    for(i = 0; i < nb_clusters; i++) {
-        refcount1 = get_refcount(bs, i);
-        refcount2 = refcount_table[i];
-        if (refcount1 != refcount2)
-            printf("ERROR cluster %d refcount=%d reference=%d\n",
-                   i, refcount1, refcount2);
-    }
-
-    qemu_free(refcount_table);
-}
-
-#if 0
-static void dump_refcounts(BlockDriverState *bs)
-{
-    BDRVQcowState *s = bs->opaque;
-    int64_t nb_clusters, k, k1, size;
-    int refcount;
-
-    size = bdrv_getlength(s->hd);
-    nb_clusters = (size + s->cluster_size - 1) >> s->cluster_bits;
-    for(k = 0; k < nb_clusters;) {
-        k1 = k;
-        refcount = get_refcount(bs, k);
-        k++;
-        while (k < nb_clusters && get_refcount(bs, k) == refcount)
-            k++;
-        printf("%lld: refcount=%d nb=%lld\n", k, refcount, k - k1);
-    }
-}
-#endif
-#endif
-
-BlockDriver bdrv_qcow2 = {
-    "qcow2",
-    sizeof(BDRVQcowState),
-    qcow_probe,
-    qcow_open,
-    NULL,
-    NULL,
-    qcow_close,
-    qcow_create,
-    qcow_flush,
-    qcow_is_allocated,
-    qcow_set_key,
-    qcow_make_empty,
-
-    .bdrv_aio_read = qcow_aio_read,
-    .bdrv_aio_write = qcow_aio_write,
-    .bdrv_aio_cancel = qcow_aio_cancel,
-    .aiocb_size = sizeof(QCowAIOCB),
-    .bdrv_write_compressed = qcow_write_compressed,
-
-    .bdrv_snapshot_create = qcow_snapshot_create,
-    .bdrv_snapshot_goto = qcow_snapshot_goto,
-    .bdrv_snapshot_delete = qcow_snapshot_delete,
-    .bdrv_snapshot_list = qcow_snapshot_list,
-    .bdrv_get_info = qcow_get_info,
-};
diff --git a/block-raw-posix.c b/block-raw-posix.c
deleted file mode 100644
index 7c42c10..0000000
--- a/block-raw-posix.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-/*
- * Block driver for RAW files (posix)
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "qemu-timer.h"
-#include "qemu-char.h"
-#include "block_int.h"
-#include "compatfd.h"
-#include <assert.h>
-#ifdef CONFIG_AIO
-#include <aio.h>
-#endif
-
-#ifdef CONFIG_COCOA
-#include <paths.h>
-#include <sys/param.h>
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOBSD.h>
-#include <IOKit/storage/IOMediaBSDClient.h>
-#include <IOKit/storage/IOMedia.h>
-#include <IOKit/storage/IOCDMedia.h>
-//#include <IOKit/storage/IOCDTypes.h>
-#include <CoreFoundation/CoreFoundation.h>
-#endif
-
-#ifdef __sun__
-#define _POSIX_PTHREAD_SEMANTICS 1
-#include <signal.h>
-#include <sys/dkio.h>
-#endif
-#ifdef __linux__
-#include <sys/ioctl.h>
-#include <linux/cdrom.h>
-#include <linux/fd.h>
-#endif
-#ifdef __FreeBSD__
-#include <signal.h>
-#include <sys/disk.h>
-#endif
-
-#ifdef __OpenBSD__
-#include <sys/ioctl.h>
-#include <sys/disklabel.h>
-#include <sys/dkio.h>
-#endif
-
-//#define DEBUG_FLOPPY
-
-//#define DEBUG_BLOCK
-#if defined(DEBUG_BLOCK)
-#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0)	\
-    { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
-#else
-#define DEBUG_BLOCK_PRINT(formatCstr, args...)
-#endif
-
-#define FTYPE_FILE   0
-#define FTYPE_CD     1
-#define FTYPE_FD     2
-
-#define ALIGNED_BUFFER_SIZE (32 * 512)
-
-/* if the FD is not accessed during that time (in ms), we try to
-   reopen it to see if the disk has been changed */
-#define FD_OPEN_TIMEOUT 1000
-
-typedef struct BDRVRawState {
-    int fd;
-    int type;
-    unsigned int lseek_err_cnt;
-#if defined(__linux__)
-    /* linux floppy specific */
-    int fd_open_flags;
-    int64_t fd_open_time;
-    int64_t fd_error_time;
-    int fd_got_error;
-    int fd_media_changed;
-#endif
-#if defined(O_DIRECT)
-    uint8_t* aligned_buf;
-#endif
-} BDRVRawState;
-
-static int fd_open(BlockDriverState *bs);
-
-static int raw_open(BlockDriverState *bs, const char *filename, int flags)
-{
-    BDRVRawState *s = bs->opaque;
-    int fd, open_flags, ret;
-
-    s->lseek_err_cnt = 0;
-
-    open_flags = O_BINARY;
-    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
-        open_flags |= O_RDWR;
-    } else {
-        open_flags |= O_RDONLY;
-        bs->read_only = 1;
-    }
-    if (flags & BDRV_O_CREAT)
-        open_flags |= O_CREAT | O_TRUNC;
-#ifdef O_DIRECT
-    if (flags & BDRV_O_DIRECT)
-        open_flags |= O_DIRECT;
-#endif
-
-    s->type = FTYPE_FILE;
-
-    fd = open(filename, open_flags, 0644);
-    if (fd < 0) {
-        ret = -errno;
-        if (ret == -EROFS)
-            ret = -EACCES;
-        return ret;
-    }
-    s->fd = fd;
-#if defined(O_DIRECT)
-    s->aligned_buf = NULL;
-    if (flags & BDRV_O_DIRECT) {
-        s->aligned_buf = qemu_memalign(512, ALIGNED_BUFFER_SIZE);
-        if (s->aligned_buf == NULL) {
-            ret = -errno;
-            close(fd);
-            return ret;
-        }
-    }
-#endif
-    return 0;
-}
-
-/* XXX: use host sector size if necessary with:
-#ifdef DIOCGSECTORSIZE
-        {
-            unsigned int sectorsize = 512;
-            if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
-                sectorsize > bufsize)
-                bufsize = sectorsize;
-        }
-#endif
-#ifdef CONFIG_COCOA
-        u_int32_t   blockSize = 512;
-        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
-            bufsize = blockSize;
-        }
-#endif
-*/
-
-/*
- * offset and count are in bytes, but must be multiples of 512 for files
- * opened with O_DIRECT. buf must be aligned to 512 bytes then.
- *
- * This function may be called without alignment if the caller ensures
- * that O_DIRECT is not in effect.
- */
-static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
-                     uint8_t *buf, int count)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    ret = fd_open(bs);
-    if (ret < 0)
-        return ret;
-
-    if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
-        ++(s->lseek_err_cnt);
-        if(s->lseek_err_cnt <= 10) {
-            DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
-                              "] lseek failed : %d = %s\n",
-                              s->fd, bs->filename, offset, buf, count,
-                              bs->total_sectors, errno, strerror(errno));
-        }
-        return -1;
-    }
-    s->lseek_err_cnt=0;
-
-    ret = read(s->fd, buf, count);
-    if (ret == count)
-        goto label__raw_read__success;
-
-    DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
-                      "] read failed %d : %d = %s\n",
-                      s->fd, bs->filename, offset, buf, count,
-                      bs->total_sectors, ret, errno, strerror(errno));
-
-    /* Try harder for CDrom. */
-    if (bs->type == BDRV_TYPE_CDROM) {
-        lseek(s->fd, offset, SEEK_SET);
-        ret = read(s->fd, buf, count);
-        if (ret == count)
-            goto label__raw_read__success;
-        lseek(s->fd, offset, SEEK_SET);
-        ret = read(s->fd, buf, count);
-        if (ret == count)
-            goto label__raw_read__success;
-
-        DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
-                          "] retry read failed %d : %d = %s\n",
-                          s->fd, bs->filename, offset, buf, count,
-                          bs->total_sectors, ret, errno, strerror(errno));
-    }
-
-label__raw_read__success:
-
-    return ret;
-}
-
-/*
- * offset and count are in bytes, but must be multiples of 512 for files
- * opened with O_DIRECT. buf must be aligned to 512 bytes then.
- *
- * This function may be called without alignment if the caller ensures
- * that O_DIRECT is not in effect.
- */
-static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset,
-                      const uint8_t *buf, int count)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    ret = fd_open(bs);
-    if (ret < 0)
-        return ret;
-
-    if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
-        ++(s->lseek_err_cnt);
-        if(s->lseek_err_cnt) {
-            DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%"
-                              PRId64 "] lseek failed : %d = %s\n",
-                              s->fd, bs->filename, offset, buf, count,
-                              bs->total_sectors, errno, strerror(errno));
-        }
-        return -1;
-    }
-    s->lseek_err_cnt = 0;
-
-    ret = write(s->fd, buf, count);
-    if (ret == count)
-        goto label__raw_write__success;
-
-    DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
-                      "] write failed %d : %d = %s\n",
-                      s->fd, bs->filename, offset, buf, count,
-                      bs->total_sectors, ret, errno, strerror(errno));
-
-label__raw_write__success:
-
-    return ret;
-}
-
-
-#if defined(O_DIRECT)
-/*
- * offset and count are in bytes and possibly not aligned. For files opened
- * with O_DIRECT, necessary alignments are ensured before calling
- * raw_pread_aligned to do the actual read.
- */
-static int raw_pread(BlockDriverState *bs, int64_t offset,
-                     uint8_t *buf, int count)
-{
-    BDRVRawState *s = bs->opaque;
-    int size, ret, shift, sum;
-
-    sum = 0;
-
-    if (s->aligned_buf != NULL)  {
-
-        if (offset & 0x1ff) {
-            /* align offset on a 512 bytes boundary */
-
-            shift = offset & 0x1ff;
-            size = (shift + count + 0x1ff) & ~0x1ff;
-            if (size > ALIGNED_BUFFER_SIZE)
-                size = ALIGNED_BUFFER_SIZE;
-            ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, size);
-            if (ret < 0)
-                return ret;
-
-            size = 512 - shift;
-            if (size > count)
-                size = count;
-            memcpy(buf, s->aligned_buf + shift, size);
-
-            buf += size;
-            offset += size;
-            count -= size;
-            sum += size;
-
-            if (count == 0)
-                return sum;
-        }
-        if (count & 0x1ff || (uintptr_t) buf & 0x1ff) {
-
-            /* read on aligned buffer */
-
-            while (count) {
-
-                size = (count + 0x1ff) & ~0x1ff;
-                if (size > ALIGNED_BUFFER_SIZE)
-                    size = ALIGNED_BUFFER_SIZE;
-
-                ret = raw_pread_aligned(bs, offset, s->aligned_buf, size);
-                if (ret < 0)
-                    return ret;
-
-                size = ret;
-                if (size > count)
-                    size = count;
-
-                memcpy(buf, s->aligned_buf, size);
-
-                buf += size;
-                offset += size;
-                count -= size;
-                sum += size;
-            }
-
-            return sum;
-        }
-    }
-
-    return raw_pread_aligned(bs, offset, buf, count) + sum;
-}
-
-/*
- * offset and count are in bytes and possibly not aligned. For files opened
- * with O_DIRECT, necessary alignments are ensured before calling
- * raw_pwrite_aligned to do the actual write.
- */
-static int raw_pwrite(BlockDriverState *bs, int64_t offset,
-                      const uint8_t *buf, int count)
-{
-    BDRVRawState *s = bs->opaque;
-    int size, ret, shift, sum;
-
-    sum = 0;
-
-    if (s->aligned_buf != NULL) {
-
-        if (offset & 0x1ff) {
-            /* align offset on a 512 bytes boundary */
-            shift = offset & 0x1ff;
-            ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, 512);
-            if (ret < 0)
-                return ret;
-
-            size = 512 - shift;
-            if (size > count)
-                size = count;
-            memcpy(s->aligned_buf + shift, buf, size);
-
-            ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf, 512);
-            if (ret < 0)
-                return ret;
-
-            buf += size;
-            offset += size;
-            count -= size;
-            sum += size;
-
-            if (count == 0)
-                return sum;
-        }
-        if (count & 0x1ff || (uintptr_t) buf & 0x1ff) {
-
-            while ((size = (count & ~0x1ff)) != 0) {
-
-                if (size > ALIGNED_BUFFER_SIZE)
-                    size = ALIGNED_BUFFER_SIZE;
-
-                memcpy(s->aligned_buf, buf, size);
-
-                ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, size);
-                if (ret < 0)
-                    return ret;
-
-                buf += ret;
-                offset += ret;
-                count -= ret;
-                sum += ret;
-            }
-            /* here, count < 512 because (count & ~0x1ff) == 0 */
-            if (count) {
-                ret = raw_pread_aligned(bs, offset, s->aligned_buf, 512);
-                if (ret < 0)
-                    return ret;
-                 memcpy(s->aligned_buf, buf, count);
-
-                 ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, 512);
-                 if (ret < 0)
-                     return ret;
-                 if (count < ret)
-                     ret = count;
-
-                 sum += ret;
-            }
-            return sum;
-        }
-    }
-    return raw_pwrite_aligned(bs, offset, buf, count) + sum;
-}
-
-#else
-#define raw_pread raw_pread_aligned
-#define raw_pwrite raw_pwrite_aligned
-#endif
-
-
-#ifdef CONFIG_AIO
-/***********************************************************/
-/* Unix AIO using POSIX AIO */
-
-typedef struct RawAIOCB {
-    BlockDriverAIOCB common;
-    struct aiocb aiocb;
-    struct RawAIOCB *next;
-    int ret;
-} RawAIOCB;
-
-static int aio_sig_fd = -1;
-static int aio_sig_num = SIGUSR2;
-static RawAIOCB *first_aio; /* AIO issued */
-static int aio_initialized = 0;
-
-static void qemu_aio_poll(void *opaque)
-{
-    RawAIOCB *acb, **pacb;
-    int ret;
-    size_t offset;
-    union {
-        struct qemu_signalfd_siginfo siginfo;
-        char buf[128];
-    } sig;
-
-    /* try to read from signalfd, don't freak out if we can't read anything */
-    offset = 0;
-    while (offset < 128) {
-        ssize_t len;
-
-        len = read(aio_sig_fd, sig.buf + offset, 128 - offset);
-        if (len == -1 && errno == EINTR)
-            continue;
-        if (len == -1 && errno == EAGAIN) {
-            /* there is no natural reason for this to happen,
-             * so we'll spin hard until we get everything just
-             * to be on the safe side. */
-            if (offset > 0)
-                continue;
-        }
-
-        offset += len;
-    }
-
-    for(;;) {
-        pacb = &first_aio;
-        for(;;) {
-            acb = *pacb;
-            if (!acb)
-                goto the_end;
-            ret = aio_error(&acb->aiocb);
-            if (ret == ECANCELED) {
-                /* remove the request */
-                *pacb = acb->next;
-                qemu_aio_release(acb);
-            } else if (ret != EINPROGRESS) {
-                /* end of aio */
-                if (ret == 0) {
-                    ret = aio_return(&acb->aiocb);
-                    if (ret == acb->aiocb.aio_nbytes)
-                        ret = 0;
-                    else
-                        ret = -EINVAL;
-                } else {
-                    ret = -ret;
-                }
-                /* remove the request */
-                *pacb = acb->next;
-                /* call the callback */
-                acb->common.cb(acb->common.opaque, ret);
-                qemu_aio_release(acb);
-                break;
-            } else {
-                pacb = &acb->next;
-            }
-        }
-    }
- the_end: ;
-}
-
-void qemu_aio_init(void)
-{
-    sigset_t mask;
-
-    aio_initialized = 1;
-
-    /* Make sure to block AIO signal */
-    sigemptyset(&mask);
-    sigaddset(&mask, aio_sig_num);
-    sigprocmask(SIG_BLOCK, &mask, NULL);
-    
-    aio_sig_fd = qemu_signalfd(&mask);
-
-    fcntl(aio_sig_fd, F_SETFL, O_NONBLOCK);
-
-    qemu_set_fd_handler2(aio_sig_fd, NULL, qemu_aio_poll, NULL, NULL);
-
-#if defined(__GLIBC__) && defined(__linux__)
-    {
-        /* XXX: aio thread exit seems to hang on RedHat 9 and this init
-           seems to fix the problem. */
-        struct aioinit ai;
-        memset(&ai, 0, sizeof(ai));
-        ai.aio_threads = 1;
-        ai.aio_num = 1;
-        ai.aio_idle_time = 365 * 100000;
-        aio_init(&ai);
-    }
-#endif
-}
-
-/* Wait for all IO requests to complete.  */
-void qemu_aio_flush(void)
-{
-    qemu_aio_poll(NULL);
-    while (first_aio) {
-        qemu_aio_wait();
-    }
-}
-
-void qemu_aio_wait(void)
-{
-    int ret;
-
-    if (qemu_bh_poll())
-        return;
-
-    if (!first_aio)
-        return;
-
-    do {
-        fd_set rdfds;
-
-        FD_ZERO(&rdfds);
-        FD_SET(aio_sig_fd, &rdfds);
-
-        ret = select(aio_sig_fd + 1, &rdfds, NULL, NULL, NULL);
-        if (ret == -1 && errno == EINTR)
-            continue;
-    } while (ret == 0);
-
-    qemu_aio_poll(NULL);
-}
-
-static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BDRVRawState *s = bs->opaque;
-    RawAIOCB *acb;
-
-    if (fd_open(bs) < 0)
-        return NULL;
-
-    acb = qemu_aio_get(bs, cb, opaque);
-    if (!acb)
-        return NULL;
-    acb->aiocb.aio_fildes = s->fd;
-    acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
-    acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
-    acb->aiocb.aio_buf = buf;
-    if (nb_sectors < 0)
-        acb->aiocb.aio_nbytes = -nb_sectors;
-    else
-        acb->aiocb.aio_nbytes = nb_sectors * 512;
-    acb->aiocb.aio_offset = sector_num * 512;
-    acb->next = first_aio;
-    first_aio = acb;
-    return acb;
-}
-
-static void raw_aio_em_cb(void* opaque)
-{
-    RawAIOCB *acb = opaque;
-    acb->common.cb(acb->common.opaque, acb->ret);
-    qemu_aio_release(acb);
-}
-
-static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    RawAIOCB *acb;
-
-    /*
-     * If O_DIRECT is used and the buffer is not aligned fall back
-     * to synchronous IO.
-     */
-#if defined(O_DIRECT)
-    BDRVRawState *s = bs->opaque;
-
-    if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) {
-        QEMUBH *bh;
-        acb = qemu_aio_get(bs, cb, opaque);
-        acb->ret = raw_pread(bs, 512 * sector_num, buf, 512 * nb_sectors);
-        bh = qemu_bh_new(raw_aio_em_cb, acb);
-        qemu_bh_schedule(bh);
-        return &acb->common;
-    }
-#endif
-
-    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
-    if (!acb)
-        return NULL;
-    if (aio_read(&acb->aiocb) < 0) {
-        qemu_aio_release(acb);
-        return NULL;
-    }
-    return &acb->common;
-}
-
-static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
-        int64_t sector_num, const uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    RawAIOCB *acb;
-
-    /*
-     * If O_DIRECT is used and the buffer is not aligned fall back
-     * to synchronous IO.
-     */
-#if defined(O_DIRECT)
-    BDRVRawState *s = bs->opaque;
-
-    if (unlikely(s->aligned_buf != NULL && ((uintptr_t) buf % 512))) {
-        QEMUBH *bh;
-        acb = qemu_aio_get(bs, cb, opaque);
-        acb->ret = raw_pwrite(bs, 512 * sector_num, buf, 512 * nb_sectors);
-        bh = qemu_bh_new(raw_aio_em_cb, acb);
-        qemu_bh_schedule(bh);
-        return &acb->common;
-    }
-#endif
-
-    acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
-    if (!acb)
-        return NULL;
-    if (aio_write(&acb->aiocb) < 0) {
-        qemu_aio_release(acb);
-        return NULL;
-    }
-    return &acb->common;
-}
-
-static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
-{
-    int ret;
-    RawAIOCB *acb = (RawAIOCB *)blockacb;
-    RawAIOCB **pacb;
-
-    ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
-    if (ret == AIO_NOTCANCELED) {
-        /* fail safe: if the aio could not be canceled, we wait for
-           it */
-        while (aio_error(&acb->aiocb) == EINPROGRESS);
-    }
-
-    /* remove the callback from the queue */
-    pacb = &first_aio;
-    for(;;) {
-        if (*pacb == NULL) {
-            break;
-        } else if (*pacb == acb) {
-            *pacb = acb->next;
-            qemu_aio_release(acb);
-            break;
-        }
-        pacb = &acb->next;
-    }
-}
-
-# else /* CONFIG_AIO */
-
-void qemu_aio_init(void)
-{
-}
-
-void qemu_aio_flush(void)
-{
-}
-
-void qemu_aio_wait(void)
-{
-    qemu_bh_poll();
-}
-
-#endif /* CONFIG_AIO */
-
-static void raw_close(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    if (s->fd >= 0) {
-        close(s->fd);
-        s->fd = -1;
-#if defined(O_DIRECT)
-        if (s->aligned_buf != NULL)
-            qemu_free(s->aligned_buf);
-#endif
-    }
-}
-
-static int raw_truncate(BlockDriverState *bs, int64_t offset)
-{
-    BDRVRawState *s = bs->opaque;
-    if (s->type != FTYPE_FILE)
-        return -ENOTSUP;
-    if (ftruncate(s->fd, offset) < 0)
-        return -errno;
-    return 0;
-}
-
-#ifdef __OpenBSD__
-static int64_t raw_getlength(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int fd = s->fd;
-    struct stat st;
-
-    if (fstat(fd, &st))
-        return -1;
-    if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
-        struct disklabel dl;
-
-        if (ioctl(fd, DIOCGDINFO, &dl))
-            return -1;
-        return (uint64_t)dl.d_secsize *
-            dl.d_partitions[DISKPART(st.st_rdev)].p_size;
-    } else
-        return st.st_size;
-}
-#else /* !__OpenBSD__ */
-static int64_t  raw_getlength(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int fd = s->fd;
-    int64_t size;
-#ifdef _BSD
-    struct stat sb;
-#endif
-#ifdef __sun__
-    struct dk_minfo minfo;
-    int rv;
-#endif
-    int ret;
-
-    ret = fd_open(bs);
-    if (ret < 0)
-        return ret;
-
-#ifdef _BSD
-    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
-#ifdef DIOCGMEDIASIZE
-	if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
-#endif
-#ifdef CONFIG_COCOA
-        size = LONG_LONG_MAX;
-#else
-        size = lseek(fd, 0LL, SEEK_END);
-#endif
-    } else
-#endif
-#ifdef __sun__
-    /*
-     * use the DKIOCGMEDIAINFO ioctl to read the size.
-     */
-    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
-    if ( rv != -1 ) {
-        size = minfo.dki_lbsize * minfo.dki_capacity;
-    } else /* there are reports that lseek on some devices
-              fails, but irc discussion said that contingency
-              on contingency was overkill */
-#endif
-    {
-        size = lseek(fd, 0, SEEK_END);
-    }
-    return size;
-}
-#endif
-
-static int raw_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
-{
-    int fd;
-
-    if (flags || backing_file)
-        return -ENOTSUP;
-
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
-              0644);
-    if (fd < 0)
-        return -EIO;
-    ftruncate(fd, total_size * 512);
-    close(fd);
-    return 0;
-}
-
-static void raw_flush(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    fsync(s->fd);
-}
-
-BlockDriver bdrv_raw = {
-    "raw",
-    sizeof(BDRVRawState),
-    NULL, /* no probe for protocols */
-    raw_open,
-    NULL,
-    NULL,
-    raw_close,
-    raw_create,
-    raw_flush,
-
-#ifdef CONFIG_AIO
-    .bdrv_aio_read = raw_aio_read,
-    .bdrv_aio_write = raw_aio_write,
-    .bdrv_aio_cancel = raw_aio_cancel,
-    .aiocb_size = sizeof(RawAIOCB),
-#endif
-    .bdrv_pread = raw_pread,
-    .bdrv_pwrite = raw_pwrite,
-    .bdrv_truncate = raw_truncate,
-    .bdrv_getlength = raw_getlength,
-};
-
-/***********************************************/
-/* host device */
-
-#ifdef CONFIG_COCOA
-static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
-static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
-
-kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
-{
-    kern_return_t       kernResult;
-    mach_port_t     masterPort;
-    CFMutableDictionaryRef  classesToMatch;
-
-    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
-    if ( KERN_SUCCESS != kernResult ) {
-        printf( "IOMasterPort returned %d\n", kernResult );
-    }
-
-    classesToMatch = IOServiceMatching( kIOCDMediaClass );
-    if ( classesToMatch == NULL ) {
-        printf( "IOServiceMatching returned a NULL dictionary.\n" );
-    } else {
-    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
-    }
-    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
-    if ( KERN_SUCCESS != kernResult )
-    {
-        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
-    }
-
-    return kernResult;
-}
-
-kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
-{
-    io_object_t     nextMedia;
-    kern_return_t   kernResult = KERN_FAILURE;
-    *bsdPath = '\0';
-    nextMedia = IOIteratorNext( mediaIterator );
-    if ( nextMedia )
-    {
-        CFTypeRef   bsdPathAsCFString;
-    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
-        if ( bsdPathAsCFString ) {
-            size_t devPathLength;
-            strcpy( bsdPath, _PATH_DEV );
-            strcat( bsdPath, "r" );
-            devPathLength = strlen( bsdPath );
-            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
-                kernResult = KERN_SUCCESS;
-            }
-            CFRelease( bsdPathAsCFString );
-        }
-        IOObjectRelease( nextMedia );
-    }
-
-    return kernResult;
-}
-
-#endif
-
-static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
-{
-    BDRVRawState *s = bs->opaque;
-    int fd, open_flags, ret;
-
-#ifdef CONFIG_COCOA
-    if (strstart(filename, "/dev/cdrom", NULL)) {
-        kern_return_t kernResult;
-        io_iterator_t mediaIterator;
-        char bsdPath[ MAXPATHLEN ];
-        int fd;
-
-        kernResult = FindEjectableCDMedia( &mediaIterator );
-        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
-
-        if ( bsdPath[ 0 ] != '\0' ) {
-            strcat(bsdPath,"s0");
-            /* some CDs don't have a partition 0 */
-            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
-            if (fd < 0) {
-                bsdPath[strlen(bsdPath)-1] = '1';
-            } else {
-                close(fd);
-            }
-            filename = bsdPath;
-        }
-
-        if ( mediaIterator )
-            IOObjectRelease( mediaIterator );
-    }
-#endif
-    open_flags = O_BINARY;
-    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
-        open_flags |= O_RDWR;
-    } else {
-        open_flags |= O_RDONLY;
-        bs->read_only = 1;
-    }
-#ifdef O_DIRECT
-    if (flags & BDRV_O_DIRECT)
-        open_flags |= O_DIRECT;
-#endif
-
-    s->type = FTYPE_FILE;
-#if defined(__linux__)
-    if (strstart(filename, "/dev/cd", NULL)) {
-        /* open will not fail even if no CD is inserted */
-        open_flags |= O_NONBLOCK;
-        s->type = FTYPE_CD;
-    } else if (strstart(filename, "/dev/fd", NULL)) {
-        s->type = FTYPE_FD;
-        s->fd_open_flags = open_flags;
-        /* open will not fail even if no floppy is inserted */
-        open_flags |= O_NONBLOCK;
-    } else if (strstart(filename, "/dev/sg", NULL)) {
-        bs->sg = 1;
-    }
-#endif
-    fd = open(filename, open_flags, 0644);
-    if (fd < 0) {
-        ret = -errno;
-        if (ret == -EROFS)
-            ret = -EACCES;
-        return ret;
-    }
-    s->fd = fd;
-#if defined(__linux__)
-    /* close fd so that we can reopen it as needed */
-    if (s->type == FTYPE_FD) {
-        close(s->fd);
-        s->fd = -1;
-        s->fd_media_changed = 1;
-    }
-#endif
-    return 0;
-}
-
-#if defined(__linux__)
-
-/* Note: we do not have a reliable method to detect if the floppy is
-   present. The current method is to try to open the floppy at every
-   I/O and to keep it opened during a few hundreds of ms. */
-static int fd_open(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int last_media_present;
-
-    if (s->type != FTYPE_FD)
-        return 0;
-    last_media_present = (s->fd >= 0);
-    if (s->fd >= 0 &&
-        (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
-        close(s->fd);
-        s->fd = -1;
-#ifdef DEBUG_FLOPPY
-        printf("Floppy closed\n");
-#endif
-    }
-    if (s->fd < 0) {
-        if (s->fd_got_error &&
-            (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
-#ifdef DEBUG_FLOPPY
-            printf("No floppy (open delayed)\n");
-#endif
-            return -EIO;
-        }
-        s->fd = open(bs->filename, s->fd_open_flags);
-        if (s->fd < 0) {
-            s->fd_error_time = qemu_get_clock(rt_clock);
-            s->fd_got_error = 1;
-            if (last_media_present)
-                s->fd_media_changed = 1;
-#ifdef DEBUG_FLOPPY
-            printf("No floppy\n");
-#endif
-            return -EIO;
-        }
-#ifdef DEBUG_FLOPPY
-        printf("Floppy opened\n");
-#endif
-    }
-    if (!last_media_present)
-        s->fd_media_changed = 1;
-    s->fd_open_time = qemu_get_clock(rt_clock);
-    s->fd_got_error = 0;
-    return 0;
-}
-
-static int raw_is_inserted(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    switch(s->type) {
-    case FTYPE_CD:
-        ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
-        if (ret == CDS_DISC_OK)
-            return 1;
-        else
-            return 0;
-        break;
-    case FTYPE_FD:
-        ret = fd_open(bs);
-        return (ret >= 0);
-    default:
-        return 1;
-    }
-}
-
-/* currently only used by fdc.c, but a CD version would be good too */
-static int raw_media_changed(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-
-    switch(s->type) {
-    case FTYPE_FD:
-        {
-            int ret;
-            /* XXX: we do not have a true media changed indication. It
-               does not work if the floppy is changed without trying
-               to read it */
-            fd_open(bs);
-            ret = s->fd_media_changed;
-            s->fd_media_changed = 0;
-#ifdef DEBUG_FLOPPY
-            printf("Floppy changed=%d\n", ret);
-#endif
-            return ret;
-        }
-    default:
-        return -ENOTSUP;
-    }
-}
-
-static int raw_eject(BlockDriverState *bs, int eject_flag)
-{
-    BDRVRawState *s = bs->opaque;
-
-    switch(s->type) {
-    case FTYPE_CD:
-        if (eject_flag) {
-            if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
-                perror("CDROMEJECT");
-        } else {
-            if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
-                perror("CDROMEJECT");
-        }
-        break;
-    case FTYPE_FD:
-        {
-            int fd;
-            if (s->fd >= 0) {
-                close(s->fd);
-                s->fd = -1;
-            }
-            fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
-            if (fd >= 0) {
-                if (ioctl(fd, FDEJECT, 0) < 0)
-                    perror("FDEJECT");
-                close(fd);
-            }
-        }
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static int raw_set_locked(BlockDriverState *bs, int locked)
-{
-    BDRVRawState *s = bs->opaque;
-
-    switch(s->type) {
-    case FTYPE_CD:
-        if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
-            /* Note: an error can happen if the distribution automatically
-               mounts the CD-ROM */
-            //        perror("CDROM_LOCKDOOR");
-        }
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
-{
-    BDRVRawState *s = bs->opaque;
-
-    return ioctl(s->fd, req, buf);
-}
-#else
-
-static int fd_open(BlockDriverState *bs)
-{
-    return 0;
-}
-
-static int raw_is_inserted(BlockDriverState *bs)
-{
-    return 1;
-}
-
-static int raw_media_changed(BlockDriverState *bs)
-{
-    return -ENOTSUP;
-}
-
-static int raw_eject(BlockDriverState *bs, int eject_flag)
-{
-    return -ENOTSUP;
-}
-
-static int raw_set_locked(BlockDriverState *bs, int locked)
-{
-    return -ENOTSUP;
-}
-
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
-{
-    return -ENOTSUP;
-}
-#endif /* !linux */
-
-BlockDriver bdrv_host_device = {
-    "host_device",
-    sizeof(BDRVRawState),
-    NULL, /* no probe for protocols */
-    hdev_open,
-    NULL,
-    NULL,
-    raw_close,
-    NULL,
-    raw_flush,
-
-#ifdef CONFIG_AIO
-    .bdrv_aio_read = raw_aio_read,
-    .bdrv_aio_write = raw_aio_write,
-    .bdrv_aio_cancel = raw_aio_cancel,
-    .aiocb_size = sizeof(RawAIOCB),
-#endif
-    .bdrv_pread = raw_pread,
-    .bdrv_pwrite = raw_pwrite,
-    .bdrv_getlength = raw_getlength,
-
-    /* removable device support */
-    .bdrv_is_inserted = raw_is_inserted,
-    .bdrv_media_changed = raw_media_changed,
-    .bdrv_eject = raw_eject,
-    .bdrv_set_locked = raw_set_locked,
-    /* generic scsi device */
-    .bdrv_ioctl = raw_ioctl,
-};
diff --git a/block-vpc.c b/block-vpc.c
deleted file mode 100644
index f76c451..0000000
--- a/block-vpc.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Block driver for Conectix/Microsoft Virtual PC images
- *
- * Copyright (c) 2005 Alex Beregszaszi
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "qemu-common.h"
-#include "block_int.h"
-
-/**************************************************************/
-
-#define HEADER_SIZE 512
-
-//#define CACHE
-
-// always big-endian
-struct vpc_subheader {
-    char magic[8]; // "conectix" / "cxsparse"
-    union {
-	struct {
-	    uint32_t unk1[2];
-	    uint32_t unk2; // always zero?
-	    uint32_t subheader_offset;
-	    uint32_t unk3; // some size?
-	    char creator[4]; // "vpc "
-	    uint16_t major;
-	    uint16_t minor;
-	    char guest[4]; // "Wi2k"
-	    uint32_t unk4[7];
-	    uint8_t vnet_id[16]; // virtual network id, purpose unknown
-	    // next 16 longs are used, but dunno the purpose
-	    // next 6 longs unknown, following 7 long maybe a serial
-	    char padding[HEADER_SIZE - 84];
-	} main;
-	struct {
-	    uint32_t unk1[2]; // all bits set
-	    uint32_t unk2; // always zero?
-	    uint32_t pagetable_offset;
-	    uint32_t unk3;
-	    uint32_t pagetable_entries; // 32bit/entry
-	    uint32_t pageentry_size; // 512*8*512
-	    uint32_t nb_sectors;
-	    char padding[HEADER_SIZE - 40];
-	} sparse;
-	char padding[HEADER_SIZE - 8];
-    } type;
-};
-
-typedef struct BDRVVPCState {
-    int fd;
-
-    int pagetable_entries;
-    uint32_t *pagetable;
-
-    uint32_t pageentry_size;
-#ifdef CACHE
-    uint8_t *pageentry_u8;
-    uint32_t *pageentry_u32;
-    uint16_t *pageentry_u16;
-
-    uint64_t last_bitmap;
-#endif
-} BDRVVPCState;
-
-static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
-    if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
-	return 100;
-    return 0;
-}
-
-static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
-{
-    BDRVVPCState *s = bs->opaque;
-    int fd, i;
-    struct vpc_subheader header;
-
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-
-    bs->read_only = 1; // no write support yet
-
-    s->fd = fd;
-
-    if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
-        goto fail;
-
-    if (strncmp(header.magic, "conectix", 8))
-        goto fail;
-    lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
-
-    if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
-        goto fail;
-
-    if (strncmp(header.magic, "cxsparse", 8))
-	goto fail;
-
-    bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
-			be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
-
-    lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
-
-    s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
-    s->pagetable = qemu_malloc(s->pagetable_entries * 4);
-    if (!s->pagetable)
-	goto fail;
-    if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
-	s->pagetable_entries * 4)
-	goto fail;
-    for (i = 0; i < s->pagetable_entries; i++)
-	be32_to_cpus(&s->pagetable[i]);
-
-    s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
-#ifdef CACHE
-    s->pageentry_u8 = qemu_malloc(512);
-    if (!s->pageentry_u8)
-	goto fail;
-    s->pageentry_u32 = s->pageentry_u8;
-    s->pageentry_u16 = s->pageentry_u8;
-    s->last_pagetable = -1;
-#endif
-
-    return 0;
- fail:
-    close(fd);
-    return -1;
-}
-
-static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
-{
-    BDRVVPCState *s = bs->opaque;
-    uint64_t offset = sector_num * 512;
-    uint64_t bitmap_offset, block_offset;
-    uint32_t pagetable_index, pageentry_index;
-
-    pagetable_index = offset / s->pageentry_size;
-    pageentry_index = (offset % s->pageentry_size) / 512;
-
-    if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
-	return -1; // not allocated
-
-    bitmap_offset = 512 * s->pagetable[pagetable_index];
-    block_offset = bitmap_offset + 512 + (512 * pageentry_index);
-
-//    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
-//	sector_num, pagetable_index, pageentry_index,
-//	bitmap_offset, block_offset);
-
-// disabled by reason
-#if 0
-#ifdef CACHE
-    if (bitmap_offset != s->last_bitmap)
-    {
-	lseek(s->fd, bitmap_offset, SEEK_SET);
-
-	s->last_bitmap = bitmap_offset;
-
-	// Scary! Bitmap is stored as big endian 32bit entries,
-	// while we used to look it up byte by byte
-	read(s->fd, s->pageentry_u8, 512);
-	for (i = 0; i < 128; i++)
-	    be32_to_cpus(&s->pageentry_u32[i]);
-    }
-
-    if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
-	return -1;
-#else
-    lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
-
-    read(s->fd, &bitmap_entry, 1);
-
-    if ((bitmap_entry >> (pageentry_index % 8)) & 1)
-	return -1; // not allocated
-#endif
-#endif
-    lseek(s->fd, block_offset, SEEK_SET);
-
-    return 0;
-}
-
-static int vpc_read(BlockDriverState *bs, int64_t sector_num,
-                    uint8_t *buf, int nb_sectors)
-{
-    BDRVVPCState *s = bs->opaque;
-    int ret;
-
-    while (nb_sectors > 0) {
-	if (!seek_to_sector(bs, sector_num))
-	{
-	    ret = read(s->fd, buf, 512);
-	    if (ret != 512)
-		return -1;
-	}
-	else
-            memset(buf, 0, 512);
-        nb_sectors--;
-        sector_num++;
-        buf += 512;
-    }
-    return 0;
-}
-
-static void vpc_close(BlockDriverState *bs)
-{
-    BDRVVPCState *s = bs->opaque;
-    qemu_free(s->pagetable);
-#ifdef CACHE
-    qemu_free(s->pageentry_u8);
-#endif
-    close(s->fd);
-}
-
-BlockDriver bdrv_vpc = {
-    "vpc",
-    sizeof(BDRVVPCState),
-    vpc_probe,
-    vpc_open,
-    vpc_read,
-    NULL,
-    vpc_close,
-};
diff --git a/block.c b/block.c
index 06bea78..844a32b 100644
--- a/block.c
+++ b/block.c
@@ -21,42 +21,49 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "qemu-common.h"
-#include "console.h"
-#include "block_int.h"
+#include "config-host.h"
+#ifdef HOST_BSD
+/* include native header before sys-queue.h */
+#include <sys/queue.h>
+#endif
 
-#ifdef _BSD
+#include "qemu-common.h"
+#include "monitor.h"
+#include "block_int.h"
+#include "module.h"
+
+#ifdef HOST_BSD
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
-#include <sys/queue.h>
+#ifndef __DragonFly__
 #include <sys/disk.h>
 #endif
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
 
 #define SECTOR_BITS 9
 #define SECTOR_SIZE (1 << SECTOR_BITS)
 
-typedef struct BlockDriverAIOCBSync {
-    BlockDriverAIOCB common;
-    QEMUBH *bh;
-    int ret;
-} BlockDriverAIOCBSync;
-
-static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
+static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
-static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
-        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
-static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
 static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
                         uint8_t *buf, int nb_sectors);
 static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
                          const uint8_t *buf, int nb_sectors);
 
+BlockDriverState *bdrv_first;
+
 static BlockDriver *first_drv;
 
-static int path_is_absolute(const char *path)
+int _path_is_absolute(const char *path)
 {
     const char *p;
 #ifdef _WIN32
@@ -88,7 +95,7 @@
 
     if (dest_size <= 0)
         return;
-    if (path_is_absolute(filename)) {
+    if (_path_is_absolute(filename)) {
         pstrcpy(dest, dest_size, filename);
     } else {
         p = strchr(base_path, ':');
@@ -120,16 +127,13 @@
     }
 }
 
-
-static void bdrv_register(BlockDriver *bdrv)
+void bdrv_register(BlockDriver *bdrv)
 {
-    if (!bdrv->bdrv_aio_read) {
+    if (!bdrv->bdrv_aio_readv) {
         /* add AIO emulation layer */
-        bdrv->bdrv_aio_read = bdrv_aio_read_em;
-        bdrv->bdrv_aio_write = bdrv_aio_write_em;
-        bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em;
-        bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);
-    } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) {
+        bdrv->bdrv_aio_readv = bdrv_aio_readv_em;
+        bdrv->bdrv_aio_writev = bdrv_aio_writev_em;
+    } else if (!bdrv->bdrv_read) {
         /* add synchronous IO emulation layer */
         bdrv->bdrv_read = bdrv_read_em;
         bdrv->bdrv_write = bdrv_write_em;
@@ -144,8 +148,6 @@
     BlockDriverState **pbs, *bs;
 
     bs = qemu_mallocz(sizeof(BlockDriverState));
-    if(!bs)
-        return NULL;
     pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
     if (device_name[0] != '\0') {
         /* insert at the end */
@@ -167,13 +169,13 @@
     return NULL;
 }
 
-int bdrv_create(BlockDriver *drv,
-                const char *filename, int64_t size_in_sectors,
-                const char *backing_file, int flags)
+int bdrv_create(BlockDriver *drv, const char* filename,
+    QEMUOptionParameter *options)
 {
     if (!drv->bdrv_create)
         return -ENOTSUP;
-    return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
+
+    return drv->bdrv_create(filename, options);
 }
 
 #ifdef _WIN32
@@ -207,7 +209,7 @@
             filename[1] == ':');
 }
 
-static int is_windows_drive(const char *filename)
+int is_windows_drive(const char *filename)
 {
     if (is_windows_drive_prefix(filename) &&
         filename[2] == '\0')
@@ -229,11 +231,11 @@
 #ifdef _WIN32
     if (is_windows_drive(filename) ||
         is_windows_drive_prefix(filename))
-        return &bdrv_raw;
+        return bdrv_find_format("raw");
 #endif
     p = strchr(filename, ':');
     if (!p)
-        return &bdrv_raw;
+        return bdrv_find_format("raw");
     len = p - filename;
     if (len > sizeof(protocol) - 1)
         len = sizeof(protocol) - 1;
@@ -247,8 +249,28 @@
     return NULL;
 }
 
-/* XXX: force raw format if block or character device ? It would
-   simplify the BSD case */
+/*
+ * Detect host devices. By convention, /dev/cdrom[N] is always
+ * recognized as a host CDROM.
+ */
+static BlockDriver *find_hdev_driver(const char *filename)
+{
+    int score_max = 0, score;
+    BlockDriver *drv = NULL, *d;
+
+    for (d = first_drv; d; d = d->next) {
+        if (d->bdrv_probe_device) {
+            score = d->bdrv_probe_device(filename);
+            if (score > score_max) {
+                score_max = score;
+                drv = d;
+            }
+        }
+    }
+
+    return drv;
+}
+
 static BlockDriver *find_image_format(const char *filename)
 {
     int ret, score, score_max;
@@ -256,26 +278,9 @@
     uint8_t buf[2048];
     BlockDriverState *bs;
 
-    /* detect host devices. By convention, /dev/cdrom[N] is always
-       recognized as a host CDROM */
-    if (strstart(filename, "/dev/cdrom", NULL))
-        return &bdrv_host_device;
-#ifdef _WIN32
-    if (is_windows_drive(filename))
-        return &bdrv_host_device;
-#else
-    {
-        struct stat st;
-        if (stat(filename, &st) >= 0 &&
-            (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
-            return &bdrv_host_device;
-        }
-    }
-#endif
-
     drv = find_protocol(filename);
     /* no need to test disk image formats for vvfat */
-    if (drv == &bdrv_vvfat)
+    if (drv && strcmp(drv->format_name, "vvfat") == 0)
         return drv;
 
     ret = bdrv_file_open(&bs, filename, BDRV_O_RDONLY);
@@ -306,13 +311,12 @@
     int ret;
 
     bs = bdrv_new("");
-    if (!bs)
-        return -ENOMEM;
     ret = bdrv_open2(bs, filename, flags | BDRV_O_FILE, NULL);
     if (ret < 0) {
         bdrv_delete(bs);
         return ret;
     }
+    bs->growable = 1;
     *pbs = bs;
     return 0;
 }
@@ -332,23 +336,26 @@
     bs->read_only = 0;
     bs->is_temporary = 0;
     bs->encrypted = 0;
+    bs->valid_key = 0;
+    /* buffer_alignment defaulted to 512, drivers can change this value */
+    bs->buffer_alignment = 512;
 
     if (flags & BDRV_O_SNAPSHOT) {
         BlockDriverState *bs1;
         int64_t total_size;
         int is_protocol = 0;
+        BlockDriver *bdrv_qcow2;
+        QEMUOptionParameter *options;
 
         /* if snapshot, we create a temporary backing file and open it
            instead of opening 'filename' directly */
 
         /* if there is a backing file, use it */
         bs1 = bdrv_new("");
-        if (!bs1) {
-            return -ENOMEM;
-        }
-        if (bdrv_open(bs1, filename, 0) < 0) {
+        ret = bdrv_open2(bs1, filename, 0, drv);
+        if (ret < 0) {
             bdrv_delete(bs1);
-            return -1;
+            return ret;
         }
         total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
 
@@ -366,45 +373,59 @@
         else
             realpath(filename, backing_filename);
 
-        if (bdrv_create(&bdrv_qcow2, tmp_filename,
-                        total_size, backing_filename, 0) < 0) {
-            return -1;
+        bdrv_qcow2 = bdrv_find_format("qcow2");
+        options = parse_option_parameters("", bdrv_qcow2->create_options, NULL);
+
+        set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size * 512);
+        set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename);
+        if (drv) {
+            set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
+                drv->format_name);
         }
+
+        ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
+        if (ret < 0) {
+            return ret;
+        }
+
         filename = tmp_filename;
+        drv = bdrv_qcow2;
         bs->is_temporary = 1;
     }
 
     pstrcpy(bs->filename, sizeof(bs->filename), filename);
     if (flags & BDRV_O_FILE) {
         drv = find_protocol(filename);
-        if (!drv)
-            return -ENOENT;
-    } else {
+    } else if (!drv) {
+        drv = find_hdev_driver(filename);
         if (!drv) {
             drv = find_image_format(filename);
-            if (!drv)
-                return -1;
         }
     }
+    if (!drv) {
+        ret = -ENOENT;
+        goto unlink_and_fail;
+    }
     bs->drv = drv;
     bs->opaque = qemu_mallocz(drv->instance_size);
-    if (bs->opaque == NULL && drv->instance_size > 0)
-        return -1;
     /* Note: for compatibility, we open disk image files as RDWR, and
        RDONLY as fallback */
     if (!(flags & BDRV_O_FILE))
-        open_flags = BDRV_O_RDWR | (flags & BDRV_O_DIRECT);
+        open_flags = BDRV_O_RDWR | (flags & BDRV_O_CACHE_MASK);
     else
         open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
     ret = drv->bdrv_open(bs, filename, open_flags);
-    if (ret == -EACCES && !(flags & BDRV_O_FILE)) {
-        ret = drv->bdrv_open(bs, filename, BDRV_O_RDONLY);
+    if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) {
+        ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR);
         bs->read_only = 1;
     }
     if (ret < 0) {
         qemu_free(bs->opaque);
         bs->opaque = NULL;
         bs->drv = NULL;
+    unlink_and_fail:
+        if (bs->is_temporary)
+            unlink(filename);
         return ret;
     }
     if (drv->bdrv_getlength) {
@@ -417,23 +438,26 @@
 #endif
     if (bs->backing_file[0] != '\0') {
         /* if there is a backing file, use it */
+        BlockDriver *back_drv = NULL;
         bs->backing_hd = bdrv_new("");
-        if (!bs->backing_hd) {
-        fail:
-            bdrv_close(bs);
-            return -ENOMEM;
-        }
         path_combine(backing_filename, sizeof(backing_filename),
                      filename, bs->backing_file);
-        if (bdrv_open(bs->backing_hd, backing_filename, 0) < 0)
-            goto fail;
+        if (bs->backing_format[0] != '\0')
+            back_drv = bdrv_find_format(bs->backing_format);
+        ret = bdrv_open2(bs->backing_hd, backing_filename, open_flags,
+                         back_drv);
+        if (ret < 0) {
+            bdrv_close(bs);
+            return ret;
+        }
     }
 
-    /* call the change callback */
-    bs->media_changed = 1;
-    if (bs->change_cb)
-        bs->change_cb(bs->change_opaque);
-
+    if (!bdrv_key_required(bs)) {
+        /* call the change callback */
+        bs->media_changed = 1;
+        if (bs->change_cb)
+            bs->change_cb(bs->change_opaque);
+    }
     return 0;
 }
 
@@ -473,6 +497,20 @@
     qemu_free(bs);
 }
 
+/*
+ * Run consistency checks on an image
+ *
+ * Returns the number of errors or -errno when an internal error occurs
+ */
+int bdrv_check(BlockDriverState *bs)
+{
+    if (bs->drv->bdrv_check == NULL) {
+        return -ENOTSUP;
+    }
+
+    return bs->drv->bdrv_check(bs);
+}
+
 /* commit COW file into the raw image */
 int bdrv_commit(BlockDriverState *bs)
 {
@@ -516,6 +554,34 @@
     return 0;
 }
 
+static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
+                                   size_t size)
+{
+    int64_t len;
+
+    if (!bdrv_is_inserted(bs))
+        return -ENOMEDIUM;
+
+    if (bs->growable)
+        return 0;
+
+    len = bdrv_getlength(bs);
+
+    if (offset < 0)
+        return -EIO;
+
+    if ((offset > len) || (len - offset < size))
+        return -EIO;
+
+    return 0;
+}
+
+static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
+                              int nb_sectors)
+{
+    return bdrv_check_byte_request(bs, sector_num * 512, nb_sectors * 512);
+}
+
 /* return < 0 if error. See bdrv_write() for the return codes */
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors)
@@ -524,31 +590,10 @@
 
     if (!drv)
         return -ENOMEDIUM;
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return -EIO;
 
-    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
-            memcpy(buf, bs->boot_sector_data, 512);
-        sector_num++;
-        nb_sectors--;
-        buf += 512;
-        if (nb_sectors == 0)
-            return 0;
-    }
-    if (drv->bdrv_pread) {
-        int ret, len;
-        len = nb_sectors * 512;
-        ret = drv->bdrv_pread(bs, sector_num * 512, buf, len);
-        if (ret < 0)
-            return ret;
-        else if (ret != len)
-            return -EINVAL;
-        else {
-	    bs->rd_bytes += (unsigned) len;
-	    bs->rd_ops ++;
-            return 0;
-	}
-    } else {
-        return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
-    }
+    return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
 }
 
 /* Return < 0 if error. Important errors are:
@@ -565,29 +610,14 @@
         return -ENOMEDIUM;
     if (bs->read_only)
         return -EACCES;
-    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
-        memcpy(bs->boot_sector_data, buf, 512);
-    }
-    if (drv->bdrv_pwrite) {
-        int ret, len;
-        len = nb_sectors * 512;
-        ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len);
-        if (ret < 0)
-            return ret;
-        else if (ret != len)
-            return -EIO;
-        else {
-	    bs->wr_bytes += (unsigned) len;
-	    bs->wr_ops ++;
-            return 0;
-	}
-    } else {
-        return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
-    }
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return -EIO;
+
+    return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
 }
 
-static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,
-                         uint8_t *buf, int count1)
+int bdrv_pread(BlockDriverState *bs, int64_t offset,
+               void *buf, int count1)
 {
     uint8_t tmp_buf[SECTOR_SIZE];
     int len, nb_sectors, count;
@@ -630,8 +660,8 @@
     return count1;
 }
 
-static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset,
-                          const uint8_t *buf, int count1)
+int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
+                const void *buf, int count1)
 {
     uint8_t tmp_buf[SECTOR_SIZE];
     int len, nb_sectors, count;
@@ -679,36 +709,6 @@
 }
 
 /**
- * Read with byte offsets (needed only for file protocols)
- */
-int bdrv_pread(BlockDriverState *bs, int64_t offset,
-               void *buf1, int count1)
-{
-    BlockDriver *drv = bs->drv;
-
-    if (!drv)
-        return -ENOMEDIUM;
-    if (!drv->bdrv_pread)
-        return bdrv_pread_em(bs, offset, buf1, count1);
-    return drv->bdrv_pread(bs, offset, buf1, count1);
-}
-
-/**
- * Write with byte offsets (needed only for file protocols)
- */
-int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
-                const void *buf1, int count1)
-{
-    BlockDriver *drv = bs->drv;
-
-    if (!drv)
-        return -ENOMEDIUM;
-    if (!drv->bdrv_pwrite)
-        return bdrv_pwrite_em(bs, offset, buf1, count1);
-    return drv->bdrv_pwrite(bs, offset, buf1, count1);
-}
-
-/**
  * Truncate file to 'offset' bytes (needed only for file protocols)
  */
 int bdrv_truncate(BlockDriverState *bs, int64_t offset)
@@ -748,14 +748,120 @@
     *nb_sectors_ptr = length;
 }
 
-/* force a given boot sector. */
-void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
+struct partition {
+        uint8_t boot_ind;           /* 0x80 - active */
+        uint8_t head;               /* starting head */
+        uint8_t sector;             /* starting sector */
+        uint8_t cyl;                /* starting cylinder */
+        uint8_t sys_ind;            /* What partition type */
+        uint8_t end_head;           /* end head */
+        uint8_t end_sector;         /* end sector */
+        uint8_t end_cyl;            /* end cylinder */
+        uint32_t start_sect;        /* starting sector counting from 0 */
+        uint32_t nr_sects;          /* nr of sectors in partition */
+} __attribute__((packed));
+
+/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
+static int guess_disk_lchs(BlockDriverState *bs,
+                           int *pcylinders, int *pheads, int *psectors)
 {
-    bs->boot_sector_enabled = 1;
-    if (size > 512)
-        size = 512;
-    memcpy(bs->boot_sector_data, data, size);
-    memset(bs->boot_sector_data + size, 0, 512 - size);
+    uint8_t buf[512];
+    int ret, i, heads, sectors, cylinders;
+    struct partition *p;
+    uint32_t nr_sects;
+    uint64_t nb_sectors;
+
+    bdrv_get_geometry(bs, &nb_sectors);
+
+    ret = bdrv_read(bs, 0, buf, 1);
+    if (ret < 0)
+        return -1;
+    /* test msdos magic */
+    if (buf[510] != 0x55 || buf[511] != 0xaa)
+        return -1;
+    for(i = 0; i < 4; i++) {
+        p = ((struct partition *)(buf + 0x1be)) + i;
+        nr_sects = le32_to_cpu(p->nr_sects);
+        if (nr_sects && p->end_head) {
+            /* We make the assumption that the partition terminates on
+               a cylinder boundary */
+            heads = p->end_head + 1;
+            sectors = p->end_sector & 63;
+            if (sectors == 0)
+                continue;
+            cylinders = nb_sectors / (heads * sectors);
+            if (cylinders < 1 || cylinders > 16383)
+                continue;
+            *pheads = heads;
+            *psectors = sectors;
+            *pcylinders = cylinders;
+#if 0
+            printf("guessed geometry: LCHS=%d %d %d\n",
+                   cylinders, heads, sectors);
+#endif
+            return 0;
+        }
+    }
+    return -1;
+}
+
+void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs)
+{
+    int translation, lba_detected = 0;
+    int cylinders, heads, secs;
+    uint64_t nb_sectors;
+
+    /* if a geometry hint is available, use it */
+    bdrv_get_geometry(bs, &nb_sectors);
+    bdrv_get_geometry_hint(bs, &cylinders, &heads, &secs);
+    translation = bdrv_get_translation_hint(bs);
+    if (cylinders != 0) {
+        *pcyls = cylinders;
+        *pheads = heads;
+        *psecs = secs;
+    } else {
+        if (guess_disk_lchs(bs, &cylinders, &heads, &secs) == 0) {
+            if (heads > 16) {
+                /* if heads > 16, it means that a BIOS LBA
+                   translation was active, so the default
+                   hardware geometry is OK */
+                lba_detected = 1;
+                goto default_geometry;
+            } else {
+                *pcyls = cylinders;
+                *pheads = heads;
+                *psecs = secs;
+                /* disable any translation to be in sync with
+                   the logical geometry */
+                if (translation == BIOS_ATA_TRANSLATION_AUTO) {
+                    bdrv_set_translation_hint(bs,
+                                              BIOS_ATA_TRANSLATION_NONE);
+                }
+            }
+        } else {
+        default_geometry:
+            /* if no geometry, use a standard physical disk geometry */
+            cylinders = nb_sectors / (16 * 63);
+
+            if (cylinders > 16383)
+                cylinders = 16383;
+            else if (cylinders < 2)
+                cylinders = 2;
+            *pcyls = cylinders;
+            *pheads = 16;
+            *psecs = 63;
+            if ((lba_detected == 1) && (translation == BIOS_ATA_TRANSLATION_AUTO)) {
+                if ((*pcyls * *pheads) <= 131072) {
+                    bdrv_set_translation_hint(bs,
+                                              BIOS_ATA_TRANSLATION_LARGE);
+                } else {
+                    bdrv_set_translation_hint(bs,
+                                              BIOS_ATA_TRANSLATION_LBA);
+                }
+            }
+        }
+        bdrv_set_geometry_hint(bs, *pcyls, *pheads, *psecs);
+    }
 }
 
 void bdrv_set_geometry_hint(BlockDriverState *bs,
@@ -826,6 +932,15 @@
     return bs->encrypted;
 }
 
+int bdrv_key_required(BlockDriverState *bs)
+{
+    BlockDriverState *backing_hd = bs->backing_hd;
+
+    if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key)
+        return 1;
+    return (bs->encrypted && !bs->valid_key);
+}
+
 int bdrv_set_key(BlockDriverState *bs, const char *key)
 {
     int ret;
@@ -838,7 +953,17 @@
     }
     if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
         return -1;
-    return bs->drv->bdrv_set_key(bs, key);
+    ret = bs->drv->bdrv_set_key(bs, key);
+    if (ret < 0) {
+        bs->valid_key = 0;
+    } else if (!bs->valid_key) {
+        bs->valid_key = 1;
+        /* call the change callback now, we skipped it on open */
+        bs->media_changed = 1;
+        if (bs->change_cb)
+            bs->change_cb(bs->change_opaque);
+    }
+    return ret;
 }
 
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
@@ -871,12 +996,12 @@
     return NULL;
 }
 
-void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
+void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), void *opaque)
 {
     BlockDriverState *bs;
 
     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
-        it(opaque, bs->device_name);
+        it(opaque, bs);
     }
 }
 
@@ -887,12 +1012,24 @@
 
 void bdrv_flush(BlockDriverState *bs)
 {
+    if (!bs->drv)
+        return;
     if (bs->drv->bdrv_flush)
         bs->drv->bdrv_flush(bs);
     if (bs->backing_hd)
         bdrv_flush(bs->backing_hd);
 }
 
+void bdrv_flush_all(void)
+{
+    BlockDriverState *bs;
+
+    for (bs = bdrv_first; bs != NULL; bs = bs->next)
+        if (bs->drv && !bdrv_is_read_only(bs) && 
+            (!bdrv_is_removable(bs) || bdrv_is_inserted(bs)))
+            bdrv_flush(bs);
+}
+
 /*
  * Returns true iff the specified sector is present in the disk image. Drivers
  * not implementing the functionality are assumed to not support backing files,
@@ -920,64 +1057,73 @@
     return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
 }
 
-void bdrv_info(void)
+void bdrv_info(Monitor *mon)
 {
     BlockDriverState *bs;
 
     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
-        term_printf("%s:", bs->device_name);
-        term_printf(" type=");
+        monitor_printf(mon, "%s:", bs->device_name);
+        monitor_printf(mon, " type=");
         switch(bs->type) {
         case BDRV_TYPE_HD:
-            term_printf("hd");
+            monitor_printf(mon, "hd");
             break;
         case BDRV_TYPE_CDROM:
-            term_printf("cdrom");
+            monitor_printf(mon, "cdrom");
             break;
         case BDRV_TYPE_FLOPPY:
-            term_printf("floppy");
+            monitor_printf(mon, "floppy");
             break;
         }
-        term_printf(" removable=%d", bs->removable);
+        monitor_printf(mon, " removable=%d", bs->removable);
         if (bs->removable) {
-            term_printf(" locked=%d", bs->locked);
+            monitor_printf(mon, " locked=%d", bs->locked);
         }
         if (bs->drv) {
-            term_printf(" file=");
-	    term_print_filename(bs->filename);
+            monitor_printf(mon, " file=");
+            monitor_print_filename(mon, bs->filename);
             if (bs->backing_file[0] != '\0') {
-                term_printf(" backing_file=");
-		term_print_filename(bs->backing_file);
-	    }
-            term_printf(" ro=%d", bs->read_only);
-            term_printf(" drv=%s", bs->drv->format_name);
-            if (bs->encrypted)
-                term_printf(" encrypted");
+                monitor_printf(mon, " backing_file=");
+                monitor_print_filename(mon, bs->backing_file);
+            }
+            monitor_printf(mon, " ro=%d", bs->read_only);
+            monitor_printf(mon, " drv=%s", bs->drv->format_name);
+            monitor_printf(mon, " encrypted=%d", bdrv_is_encrypted(bs));
         } else {
-            term_printf(" [not inserted]");
+            monitor_printf(mon, " [not inserted]");
         }
-        term_printf("\n");
+        monitor_printf(mon, "\n");
     }
 }
 
 /* The "info blockstats" command. */
-void bdrv_info_stats (void)
+void bdrv_info_stats(Monitor *mon)
 {
     BlockDriverState *bs;
 
     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
-	term_printf ("%s:"
-		     " rd_bytes=%" PRIu64
-		     " wr_bytes=%" PRIu64
-		     " rd_operations=%" PRIu64
-		     " wr_operations=%" PRIu64
-		     "\n",
-		     bs->device_name,
-		     bs->rd_bytes, bs->wr_bytes,
-		     bs->rd_ops, bs->wr_ops);
+        monitor_printf(mon, "%s:"
+                       " rd_bytes=%" PRIu64
+                       " wr_bytes=%" PRIu64
+                       " rd_operations=%" PRIu64
+                       " wr_operations=%" PRIu64
+                       "\n",
+                       bs->device_name,
+                       bs->rd_bytes, bs->wr_bytes,
+                       bs->rd_ops, bs->wr_ops);
     }
 }
 
+const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
+{
+    if (bs->backing_hd && bs->backing_hd->encrypted)
+        return bs->backing_file;
+    else if (bs->encrypted)
+        return bs->filename;
+    else
+        return NULL;
+}
+
 void bdrv_get_backing_filename(BlockDriverState *bs,
                                char *filename, int filename_size)
 {
@@ -996,6 +1142,8 @@
         return -ENOMEDIUM;
     if (!drv->bdrv_write_compressed)
         return -ENOTSUP;
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return -EIO;
     return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
 }
 
@@ -1010,6 +1158,26 @@
     return drv->bdrv_get_info(bs, bdi);
 }
 
+int bdrv_put_buffer(BlockDriverState *bs, const uint8_t *buf, int64_t pos, int size)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_put_buffer)
+        return -ENOTSUP;
+    return drv->bdrv_put_buffer(bs, buf, pos, size);
+}
+
+int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        return -ENOMEDIUM;
+    if (!drv->bdrv_get_buffer)
+        return -ENOTSUP;
+    return drv->bdrv_get_buffer(bs, buf, pos, size);
+}
+
 /**************************************************************/
 /* handling of snapshots */
 
@@ -1133,25 +1301,20 @@
 /**************************************************************/
 /* async I/Os */
 
-BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
-                                uint8_t *buf, int nb_sectors,
-                                BlockDriverCompletionFunc *cb, void *opaque)
+BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
+                                 QEMUIOVector *qiov, int nb_sectors,
+                                 BlockDriverCompletionFunc *cb, void *opaque)
 {
     BlockDriver *drv = bs->drv;
     BlockDriverAIOCB *ret;
 
     if (!drv)
         return NULL;
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return NULL;
 
-    /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
-    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
-        memcpy(buf, bs->boot_sector_data, 512);
-        sector_num++;
-        nb_sectors--;
-        buf += 512;
-    }
-
-    ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);
+    ret = drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,
+                              cb, opaque);
 
     if (ret) {
 	/* Update stats even though technically transfer has not happened. */
@@ -1162,9 +1325,9 @@
     return ret;
 }
 
-BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
-                                 const uint8_t *buf, int nb_sectors,
-                                 BlockDriverCompletionFunc *cb, void *opaque)
+BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
+                                  QEMUIOVector *qiov, int nb_sectors,
+                                  BlockDriverCompletionFunc *cb, void *opaque)
 {
     BlockDriver *drv = bs->drv;
     BlockDriverAIOCB *ret;
@@ -1173,11 +1336,11 @@
         return NULL;
     if (bs->read_only)
         return NULL;
-    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
-        memcpy(bs->boot_sector_data, buf, 512);
-    }
+    if (bdrv_check_request(bs, sector_num, nb_sectors))
+        return NULL;
 
-    ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
+    ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
+                               cb, opaque);
 
     if (ret) {
 	/* Update stats even though technically transfer has not happened. */
@@ -1190,61 +1353,92 @@
 
 void bdrv_aio_cancel(BlockDriverAIOCB *acb)
 {
-    BlockDriver *drv = acb->bs->drv;
-
-    drv->bdrv_aio_cancel(acb);
+    acb->pool->cancel(acb);
 }
 
 
 /**************************************************************/
 /* async block device emulation */
 
-static void bdrv_aio_bh_cb(void *opaque)
-{
-    BlockDriverAIOCBSync *acb = opaque;
-    acb->common.cb(acb->common.opaque, acb->ret);
-    qemu_aio_release(acb);
-}
-
-static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BlockDriverAIOCBSync *acb;
+typedef struct BlockDriverAIOCBSync {
+    BlockDriverAIOCB common;
+    QEMUBH *bh;
     int ret;
-
-    acb = qemu_aio_get(bs, cb, opaque);
-    if (!acb->bh)
-        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
-    ret = bdrv_read(bs, sector_num, buf, nb_sectors);
-    acb->ret = ret;
-    qemu_bh_schedule(acb->bh);
-    return &acb->common;
-}
-
-static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
-        int64_t sector_num, const uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BlockDriverAIOCBSync *acb;
-    int ret;
-
-    acb = qemu_aio_get(bs, cb, opaque);
-    if (!acb->bh)
-        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
-    ret = bdrv_write(bs, sector_num, buf, nb_sectors);
-    acb->ret = ret;
-    qemu_bh_schedule(acb->bh);
-    return &acb->common;
-}
+    /* vector translation state */
+    QEMUIOVector *qiov;
+    uint8_t *bounce;
+    int is_write;
+} BlockDriverAIOCBSync;
 
 static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
 {
     BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
-    qemu_bh_cancel(acb->bh);
+    qemu_bh_delete(acb->bh);
     qemu_aio_release(acb);
 }
 
+static AIOPool bdrv_em_aio_pool = {
+    .aiocb_size         = sizeof(BlockDriverAIOCBSync),
+    .cancel             = bdrv_aio_cancel_em,
+};
+
+static void bdrv_aio_bh_cb(void *opaque)
+{
+    BlockDriverAIOCBSync *acb = opaque;
+
+    if (!acb->is_write)
+        qemu_iovec_from_buffer(acb->qiov, acb->bounce, acb->qiov->size);
+    qemu_vfree(acb->bounce);
+    acb->common.cb(acb->common.opaque, acb->ret);
+    qemu_bh_delete(acb->bh);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
+                                            int64_t sector_num,
+                                            QEMUIOVector *qiov,
+                                            int nb_sectors,
+                                            BlockDriverCompletionFunc *cb,
+                                            void *opaque,
+                                            int is_write)
+
+{
+    BlockDriverAIOCBSync *acb;
+
+    acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
+    acb->is_write = is_write;
+    acb->qiov = qiov;
+    acb->bounce = qemu_blockalign(bs, qiov->size);
+
+    if (!acb->bh)
+        acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+
+    if (is_write) {
+        qemu_iovec_to_buffer(acb->qiov, acb->bounce);
+        acb->ret = bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
+    } else {
+        acb->ret = bdrv_read(bs, sector_num, acb->bounce, nb_sectors);
+    }
+
+    qemu_bh_schedule(acb->bh);
+
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+}
+
+static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+}
+
 /**************************************************************/
 /* sync block device emulation */
 
@@ -1260,10 +1454,15 @@
 {
     int async_ret;
     BlockDriverAIOCB *acb;
+    struct iovec iov;
+    QEMUIOVector qiov;
 
     async_ret = NOT_DONE;
-    acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors,
-                        bdrv_rw_em_cb, &async_ret);
+    iov.iov_base = (void *)buf;
+    iov.iov_len = nb_sectors * 512;
+    qemu_iovec_init_external(&qiov, &iov, 1);
+    acb = bdrv_aio_readv(bs, sector_num, &qiov, nb_sectors,
+        bdrv_rw_em_cb, &async_ret);
     if (acb == NULL)
         return -1;
 
@@ -1279,10 +1478,15 @@
 {
     int async_ret;
     BlockDriverAIOCB *acb;
+    struct iovec iov;
+    QEMUIOVector qiov;
 
     async_ret = NOT_DONE;
-    acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors,
-                         bdrv_rw_em_cb, &async_ret);
+    iov.iov_base = (void *)buf;
+    iov.iov_len = nb_sectors * 512;
+    qemu_iovec_init_external(&qiov, &iov, 1);
+    acb = bdrv_aio_writev(bs, sector_num, &qiov, nb_sectors,
+        bdrv_rw_em_cb, &async_ret);
     if (acb == NULL)
         return -1;
     while (async_ret == NOT_DONE) {
@@ -1293,44 +1497,20 @@
 
 void bdrv_init(void)
 {
-    bdrv_register(&bdrv_raw);
-    bdrv_register(&bdrv_host_device);
-#ifndef _WIN32
-    bdrv_register(&bdrv_cow);
-#endif
-    bdrv_register(&bdrv_qcow);
-#if 0
-    bdrv_register(&bdrv_vmdk);
-#endif
-    bdrv_register(&bdrv_cloop);
-    bdrv_register(&bdrv_dmg);
-#if 0
-    bdrv_register(&bdrv_bochs);
-    bdrv_register(&bdrv_vpc);
-#endif
-    bdrv_register(&bdrv_vvfat);
-#if 0
-    bdrv_register(&bdrv_qcow2);
-    bdrv_register(&bdrv_parallels);
-    bdrv_register(&bdrv_nbd);
-#endif
-    qemu_aio_init();
+    module_call_init(MODULE_INIT_BLOCK);
 }
 
-void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
-                   void *opaque)
+void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
+                   BlockDriverCompletionFunc *cb, void *opaque)
 {
-    BlockDriver *drv;
     BlockDriverAIOCB *acb;
 
-    drv = bs->drv;
-    if (drv->free_aiocb) {
-        acb = drv->free_aiocb;
-        drv->free_aiocb = acb->next;
+    if (pool->free_aiocb) {
+        acb = pool->free_aiocb;
+        pool->free_aiocb = acb->next;
     } else {
-        acb = qemu_mallocz(drv->aiocb_size);
-        if (!acb)
-            return NULL;
+        acb = qemu_mallocz(pool->aiocb_size);
+        acb->pool = pool;
     }
     acb->bs = bs;
     acb->cb = cb;
@@ -1340,10 +1520,10 @@
 
 void qemu_aio_release(void *p)
 {
-    BlockDriverAIOCB *acb = p;
-    BlockDriver *drv = acb->bs->drv;
-    acb->next = drv->free_aiocb;
-    drv->free_aiocb = acb;
+    BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p;
+    AIOPool *pool = acb->pool;
+    acb->next = pool->free_aiocb;
+    pool->free_aiocb = acb;
 }
 
 /**************************************************************/
@@ -1386,11 +1566,15 @@
 /**
  * If eject_flag is TRUE, eject the media. Otherwise, close the tray
  */
-void bdrv_eject(BlockDriverState *bs, int eject_flag)
+int bdrv_eject(BlockDriverState *bs, int eject_flag)
 {
     BlockDriver *drv = bs->drv;
     int ret;
 
+    if (bs->locked) {
+        return -EBUSY;
+    }
+
     if (!drv || !drv->bdrv_eject) {
         ret = -ENOTSUP;
     } else {
@@ -1399,7 +1583,10 @@
     if (ret == -ENOTSUP) {
         if (eject_flag)
             bdrv_close(bs);
+        ret = 0;
     }
+
+    return ret;
 }
 
 int bdrv_is_locked(BlockDriverState *bs)
@@ -1431,3 +1618,19 @@
         return drv->bdrv_ioctl(bs, req, buf);
     return -ENOTSUP;
 }
+
+BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (drv && drv->bdrv_aio_ioctl)
+        return drv->bdrv_aio_ioctl(bs, req, buf, cb, opaque);
+    return NULL;
+}
+
+void *qemu_blockalign(BlockDriverState *bs, size_t size)
+{
+    return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
+}
diff --git a/block.h b/block.h
index 7917eb8..71e87fc 100644
--- a/block.h
+++ b/block.h
@@ -1,23 +1,13 @@
 #ifndef BLOCK_H
 #define BLOCK_H
 
+#include "qemu-aio.h"
+#include "qemu-common.h"
+#include "qemu-option.h"
+
 /* block.c */
 typedef struct BlockDriver BlockDriver;
 
-extern BlockDriver bdrv_raw;
-extern BlockDriver bdrv_host_device;
-extern BlockDriver bdrv_cow;
-extern BlockDriver bdrv_qcow;
-extern BlockDriver bdrv_vmdk;
-extern BlockDriver bdrv_cloop;
-extern BlockDriver bdrv_dmg;
-extern BlockDriver bdrv_bochs;
-extern BlockDriver bdrv_vpc;
-extern BlockDriver bdrv_vvfat;
-extern BlockDriver bdrv_qcow2;
-extern BlockDriver bdrv_parallels;
-extern BlockDriver bdrv_nbd;
-
 typedef struct BlockDriverInfo {
     /* in bytes, 0 if irrelevant */
     int cluster_size;
@@ -45,16 +35,23 @@
                                      use a disk image format on top of
                                      it (default for
                                      bdrv_file_open()) */
-#define BDRV_O_DIRECT      0x0020
+#define BDRV_O_NOCACHE     0x0020 /* do not use the host page cache */
+#define BDRV_O_CACHE_WB    0x0040 /* use write-back caching */
+#define BDRV_O_CACHE_DEF   0x0080 /* use default caching */
 
-void bdrv_info(void);
-void bdrv_info_stats(void);
+#define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_CACHE_DEF)
+
+void bdrv_info(Monitor *mon);
+void bdrv_info_stats(Monitor *mon);
 
 void bdrv_init(void);
 BlockDriver *bdrv_find_format(const char *format_name);
-int bdrv_create(BlockDriver *drv,
-                const char *filename, int64_t size_in_sectors,
-                const char *backing_file, int flags);
+int bdrv_create(BlockDriver *drv, const char* filename,
+    QEMUOptionParameter *options);
+int bdrv_create2(BlockDriver *drv,
+                 const char *filename, int64_t size_in_sectors,
+                 const char *backing_file, const char *backing_format,
+                 int flags);
 BlockDriverState *bdrv_new(const char *device_name);
 void bdrv_delete(BlockDriverState *bs);
 int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
@@ -62,6 +59,7 @@
 int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
                BlockDriver *drv);
 void bdrv_close(BlockDriverState *bs);
+int bdrv_check(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
 int bdrv_write(BlockDriverState *bs, int64_t sector_num,
@@ -73,28 +71,32 @@
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
 void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
+void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
 int bdrv_commit(BlockDriverState *bs);
-void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
+void bdrv_register(BlockDriver *bdrv);
+
 /* async block I/O */
 typedef struct BlockDriverAIOCB BlockDriverAIOCB;
 typedef void BlockDriverCompletionFunc(void *opaque, int ret);
 
-BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
-                                uint8_t *buf, int nb_sectors,
-                                BlockDriverCompletionFunc *cb, void *opaque);
-BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
-                                 const uint8_t *buf, int nb_sectors,
+BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
+                                 QEMUIOVector *iov, int nb_sectors,
                                  BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
+                                  QEMUIOVector *iov, int nb_sectors,
+                                  BlockDriverCompletionFunc *cb, void *opaque);
 void bdrv_aio_cancel(BlockDriverAIOCB *acb);
 
-void qemu_aio_init(void);
-void qemu_aio_flush(void);
-void qemu_aio_wait(void);
-
-int qemu_key_check(BlockDriverState *bs, const char *name);
+/* sg packet commands */
+int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
+BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque);
 
 /* Ensure contents are flushed to disk.  */
 void bdrv_flush(BlockDriverState *bs);
+void bdrv_flush_all(void);
+
 int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
 	int *pnum);
 
@@ -122,14 +124,17 @@
 int bdrv_media_changed(BlockDriverState *bs);
 int bdrv_is_locked(BlockDriverState *bs);
 void bdrv_set_locked(BlockDriverState *bs, int locked);
-void bdrv_eject(BlockDriverState *bs, int eject_flag);
+int bdrv_eject(BlockDriverState *bs, int eject_flag);
 void bdrv_set_change_cb(BlockDriverState *bs,
                         void (*change_cb)(void *opaque), void *opaque);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 BlockDriverState *bdrv_find(const char *name);
-void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque);
+void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs),
+                  void *opaque);
 int bdrv_is_encrypted(BlockDriverState *bs);
+int bdrv_key_required(BlockDriverState *bs);
 int bdrv_set_key(BlockDriverState *bs, const char *key);
+int bdrv_query_missing_keys(void);
 void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
                          void *opaque);
 const char *bdrv_get_device_name(BlockDriverState *bs);
@@ -137,6 +142,7 @@
                           const uint8_t *buf, int nb_sectors);
 int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
 
+const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
 void bdrv_get_backing_filename(BlockDriverState *bs,
                                char *filename, int filename_size);
 int bdrv_snapshot_create(BlockDriverState *bs,
@@ -147,13 +153,16 @@
 int bdrv_snapshot_list(BlockDriverState *bs,
                        QEMUSnapshotInfo **psn_info);
 char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
-int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
 
 char *get_human_readable_size(char *buf, int buf_size, int64_t size);
-// don't remove below comment, it makes integration with upstream sources easier
-//int path_is_absolute(const char *path);
+int path_is_absolute(const char *path);
 void path_combine(char *dest, int dest_size,
                   const char *base_path,
                   const char *filename);
 
+int bdrv_put_buffer(BlockDriverState *bs, const uint8_t *buf,
+                    int64_t pos, int size);
+
+int bdrv_get_buffer(BlockDriverState *bs, uint8_t *buf, int64_t pos, int size);
+
 #endif
diff --git a/block-bochs.c b/block/bochs.c
similarity index 94%
rename from block-bochs.c
rename to block/bochs.c
index b167e0b..bac81c4 100644
--- a/block-bochs.c
+++ b/block/bochs.c
@@ -24,6 +24,7 @@
  */
 #include "qemu-common.h"
 #include "block_int.h"
+#include "module.h"
 
 /**************************************************************/
 
@@ -149,8 +150,6 @@
 
     s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
     s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
-    if (!s->catalog_bitmap)
-	goto fail;
     if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
 	s->catalog_size * 4)
 	goto fail;
@@ -243,12 +242,18 @@
     close(s->fd);
 }
 
-BlockDriver bdrv_bochs = {
-    "bochs",
-    sizeof(BDRVBochsState),
-    bochs_probe,
-    bochs_open,
-    bochs_read,
-    NULL,
-    bochs_close,
+static BlockDriver bdrv_bochs = {
+    .format_name	= "bochs",
+    .instance_size	= sizeof(BDRVBochsState),
+    .bdrv_probe		= bochs_probe,
+    .bdrv_open		= bochs_open,
+    .bdrv_read		= bochs_read,
+    .bdrv_close		= bochs_close,
 };
+
+static void bdrv_bochs_init(void)
+{
+    bdrv_register(&bdrv_bochs);
+}
+
+block_init(bdrv_bochs_init);
diff --git a/block-cloop.c b/block/cloop.c
similarity index 89%
rename from block-cloop.c
rename to block/cloop.c
index 43d3801..06c687e 100644
--- a/block-cloop.c
+++ b/block/cloop.c
@@ -23,6 +23,7 @@
  */
 #include "qemu-common.h"
 #include "block_int.h"
+#include "module.h"
 #include <zlib.h>
 
 typedef struct BDRVCloopState {
@@ -75,8 +76,7 @@
 
     /* read offsets */
     offsets_size=s->n_blocks*sizeof(uint64_t);
-    if(!(s->offsets=(uint64_t*)malloc(offsets_size)))
-	goto cloop_close;
+    s->offsets=(uint64_t*)qemu_malloc(offsets_size);
     if(read(s->fd,s->offsets,offsets_size)<offsets_size)
 	goto cloop_close;
     for(i=0;i<s->n_blocks;i++) {
@@ -89,10 +89,8 @@
     }
 
     /* initialize zlib engine */
-    if(!(s->compressed_block = malloc(max_compressed_block_size+1)))
-	goto cloop_close;
-    if(!(s->uncompressed_block = malloc(s->block_size)))
-	goto cloop_close;
+    s->compressed_block = qemu_malloc(max_compressed_block_size+1);
+    s->uncompressed_block = qemu_malloc(s->block_size);
     if(inflateInit(&s->zstream) != Z_OK)
 	goto cloop_close;
     s->current_block=s->n_blocks;
@@ -156,14 +154,18 @@
     inflateEnd(&s->zstream);
 }
 
-BlockDriver bdrv_cloop = {
-    "cloop",
-    sizeof(BDRVCloopState),
-    cloop_probe,
-    cloop_open,
-    cloop_read,
-    NULL,
-    cloop_close,
+static BlockDriver bdrv_cloop = {
+    .format_name	= "cloop",
+    .instance_size	= sizeof(BDRVCloopState),
+    .bdrv_probe		= cloop_probe,
+    .bdrv_open		= cloop_open,
+    .bdrv_read		= cloop_read,
+    .bdrv_close		= cloop_close,
 };
 
+static void bdrv_cloop_init(void)
+{
+    bdrv_register(&bdrv_cloop);
+}
 
+block_init(bdrv_cloop_init);
diff --git a/block-cow.c b/block/cow.c
similarity index 81%
rename from block-cow.c
rename to block/cow.c
index 9e7b646..84818f1 100644
--- a/block-cow.c
+++ b/block/cow.c
@@ -24,6 +24,7 @@
 #ifndef _WIN32
 #include "qemu-common.h"
 #include "block_int.h"
+#include "module.h"
 #include <sys/mman.h>
 
 /**************************************************************/
@@ -95,10 +96,10 @@
 
     /* mmap the bitmap */
     s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
-    s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
-                              s->cow_bitmap_size,
-                              PROT_READ | PROT_WRITE,
-                              MAP_SHARED, s->fd, 0);
+    s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size),
+                                      s->cow_bitmap_size,
+                                      PROT_READ | PROT_WRITE,
+                                      MAP_SHARED, s->fd, 0);
     if (s->cow_bitmap_addr == MAP_FAILED)
         goto fail;
     s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
@@ -197,19 +198,27 @@
 static void cow_close(BlockDriverState *bs)
 {
     BDRVCowState *s = bs->opaque;
-    munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
+    munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size);
     close(s->fd);
 }
 
-static int cow_create(const char *filename, int64_t image_sectors,
-                      const char *image_filename, int flags)
+static int cow_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd, cow_fd;
     struct cow_header_v2 cow_header;
     struct stat st;
+    int64_t image_sectors = 0;
+    const char *image_filename = NULL;
 
-    if (flags)
-        return -ENOTSUP;
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            image_sectors = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            image_filename = options->value.s;
+        }
+        options++;
+    }
 
     cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
@@ -252,16 +261,39 @@
     fsync(s->fd);
 }
 
-BlockDriver bdrv_cow = {
-    "cow",
-    sizeof(BDRVCowState),
-    cow_probe,
-    cow_open,
-    cow_read,
-    cow_write,
-    cow_close,
-    cow_create,
-    cow_flush,
-    cow_is_allocated,
+static QEMUOptionParameter cow_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    { NULL }
 };
+
+static BlockDriver bdrv_cow = {
+    .format_name	= "cow",
+    .instance_size	= sizeof(BDRVCowState),
+    .bdrv_probe		= cow_probe,
+    .bdrv_open		= cow_open,
+    .bdrv_read		= cow_read,
+    .bdrv_write		= cow_write,
+    .bdrv_close		= cow_close,
+    .bdrv_create	= cow_create,
+    .bdrv_flush		= cow_flush,
+    .bdrv_is_allocated	= cow_is_allocated,
+
+    .create_options = cow_create_options,
+};
+
+static void bdrv_cow_init(void)
+{
+    bdrv_register(&bdrv_cow);
+}
+
+block_init(bdrv_cow_init);
 #endif
diff --git a/block-dmg.c b/block/dmg.c
similarity index 92%
rename from block-dmg.c
rename to block/dmg.c
index 8c9d0da..262560f 100644
--- a/block-dmg.c
+++ b/block/dmg.c
@@ -24,6 +24,7 @@
 #include "qemu-common.h"
 #include "block_int.h"
 #include "bswap.h"
+#include "module.h"
 #include <zlib.h>
 
 typedef struct BDRVDMGState {
@@ -85,14 +86,14 @@
         return -errno;
     bs->read_only = 1;
     s->n_chunks = 0;
-    s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
+    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
 
     /* read offset of info blocks */
     if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
 dmg_close:
 	close(s->fd);
 	/* open raw instead */
-	bs->drv=&bdrv_raw;
+	bs->drv=bdrv_find_format("raw");
 	return bs->drv->bdrv_open(bs, filename, flags);
     }
     info_begin=read_off(s->fd);
@@ -159,10 +160,8 @@
     }
 
     /* initialize zlib engine */
-    if(!(s->compressed_chunk = malloc(max_compressed_size+1)))
-	goto dmg_close;
-    if(!(s->uncompressed_chunk = malloc(512*max_sectors_per_chunk)))
-	goto dmg_close;
+    s->compressed_chunk = qemu_malloc(max_compressed_size+1);
+    s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
     if(inflateInit(&s->zstream) != Z_OK)
 	goto dmg_close;
 
@@ -285,13 +284,18 @@
     inflateEnd(&s->zstream);
 }
 
-BlockDriver bdrv_dmg = {
-    "dmg",
-    sizeof(BDRVDMGState),
-    dmg_probe,
-    dmg_open,
-    dmg_read,
-    NULL,
-    dmg_close,
+static BlockDriver bdrv_dmg = {
+    .format_name	= "dmg",
+    .instance_size	= sizeof(BDRVDMGState),
+    .bdrv_probe		= dmg_probe,
+    .bdrv_open		= dmg_open,
+    .bdrv_read		= dmg_read,
+    .bdrv_close		= dmg_close,
 };
 
+static void bdrv_dmg_init(void)
+{
+    bdrv_register(&bdrv_dmg);
+}
+
+block_init(bdrv_dmg_init);
diff --git a/block-nbd.c b/block/nbd.c
similarity index 91%
rename from block-nbd.c
rename to block/nbd.c
index 5b6cc4f..47d4778 100644
--- a/block-nbd.c
+++ b/block/nbd.c
@@ -28,6 +28,7 @@
 
 #include "qemu-common.h"
 #include "nbd.h"
+#include "module.h"
 
 #include <sys/types.h>
 #include <unistd.h>
@@ -176,14 +177,20 @@
     return s->size;
 }
 
-BlockDriver bdrv_nbd = {
-    "nbd",
-    sizeof(BDRVNBDState),
-    NULL, /* no probe for protocols */
-    nbd_open,
-    nbd_read,
-    nbd_write,
-    nbd_close,
-    .bdrv_getlength = nbd_getlength,
-    .protocol_name = "nbd",
+static BlockDriver bdrv_nbd = {
+    .format_name	= "nbd",
+    .instance_size	= sizeof(BDRVNBDState),
+    .bdrv_open		= nbd_open,
+    .bdrv_read		= nbd_read,
+    .bdrv_write		= nbd_write,
+    .bdrv_close		= nbd_close,
+    .bdrv_getlength	= nbd_getlength,
+    .protocol_name	= "nbd",
 };
+
+static void bdrv_nbd_init(void)
+{
+    bdrv_register(&bdrv_nbd);
+}
+
+block_init(bdrv_nbd_init);
diff --git a/block-parallels.c b/block/parallels.c
similarity index 91%
rename from block-parallels.c
rename to block/parallels.c
index 4654b07..0b64a5c 100644
--- a/block-parallels.c
+++ b/block/parallels.c
@@ -25,6 +25,7 @@
  */
 #include "qemu-common.h"
 #include "block_int.h"
+#include "module.h"
 
 /**************************************************************/
 
@@ -101,8 +102,6 @@
 
     s->catalog_size = le32_to_cpu(ph.catalog_entries);
     s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
-    if (!s->catalog_bitmap)
-	goto fail;
     if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
 	s->catalog_size * 4)
 	goto fail;
@@ -165,12 +164,18 @@
     close(s->fd);
 }
 
-BlockDriver bdrv_parallels = {
-    "parallels",
-    sizeof(BDRVParallelsState),
-    parallels_probe,
-    parallels_open,
-    parallels_read,
-    NULL,
-    parallels_close,
+static BlockDriver bdrv_parallels = {
+    .format_name	= "parallels",
+    .instance_size	= sizeof(BDRVParallelsState),
+    .bdrv_probe		= parallels_probe,
+    .bdrv_open		= parallels_open,
+    .bdrv_read		= parallels_read,
+    .bdrv_close		= parallels_close,
 };
+
+static void bdrv_parallels_init(void)
+{
+    bdrv_register(&bdrv_parallels);
+}
+
+block_init(bdrv_parallels_init);
diff --git a/block-qcow.c b/block/qcow.c
similarity index 79%
rename from block-qcow.c
rename to block/qcow.c
index 1fecf30..55a68a6 100644
--- a/block-qcow.c
+++ b/block/qcow.c
@@ -23,6 +23,7 @@
  */
 #include "qemu-common.h"
 #include "block_int.h"
+#include "module.h"
 #include <zlib.h>
 #include "aes.h"
 
@@ -339,28 +340,33 @@
                 return -1;
         } else {
             cluster_offset = bdrv_getlength(s->hd);
-            /* round to cluster size */
-            cluster_offset = (cluster_offset + s->cluster_size - 1) &
-                ~(s->cluster_size - 1);
-            bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
-            /* if encrypted, we must initialize the cluster
-               content which won't be written */
-            if (s->crypt_method &&
-                (n_end - n_start) < s->cluster_sectors) {
-                uint64_t start_sect;
-                start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
-                memset(s->cluster_data + 512, 0x00, 512);
-                for(i = 0; i < s->cluster_sectors; i++) {
-                    if (i < n_start || i >= n_end) {
-                        encrypt_sectors(s, start_sect + i,
-                                        s->cluster_data,
-                                        s->cluster_data + 512, 1, 1,
-                                        &s->aes_encrypt_key);
-                        if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
-                                        s->cluster_data, 512) != 512)
-                            return -1;
+            if (allocate == 1) {
+                /* round to cluster size */
+                cluster_offset = (cluster_offset + s->cluster_size - 1) &
+                    ~(s->cluster_size - 1);
+                bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
+                /* if encrypted, we must initialize the cluster
+                   content which won't be written */
+                if (s->crypt_method &&
+                    (n_end - n_start) < s->cluster_sectors) {
+                    uint64_t start_sect;
+                    start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
+                    memset(s->cluster_data + 512, 0x00, 512);
+                    for(i = 0; i < s->cluster_sectors; i++) {
+                        if (i < n_start || i >= n_end) {
+                            encrypt_sectors(s, start_sect + i,
+                                            s->cluster_data,
+                                            s->cluster_data + 512, 1, 1,
+                                            &s->aes_encrypt_key);
+                            if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
+                                            s->cluster_data, 512) != 512)
+                                return -1;
+                        }
                     }
                 }
+            } else if (allocate == 2) {
+                cluster_offset |= QCOW_OFLAG_COMPRESSED |
+                    (uint64_t)compressed_size << (63 - s->cluster_bits);
             }
         }
         /* update L2 table */
@@ -482,52 +488,59 @@
 }
 #endif
 
-static int qcow_write(BlockDriverState *bs, int64_t sector_num,
-                     const uint8_t *buf, int nb_sectors)
-{
-    BDRVQcowState *s = bs->opaque;
-    int ret, index_in_cluster, n;
-    uint64_t cluster_offset;
-
-    while (nb_sectors > 0) {
-        index_in_cluster = sector_num & (s->cluster_sectors - 1);
-        n = s->cluster_sectors - index_in_cluster;
-        if (n > nb_sectors)
-            n = nb_sectors;
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
-                                            index_in_cluster,
-                                            index_in_cluster + n);
-        if (!cluster_offset)
-            return -1;
-        if (s->crypt_method) {
-            encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
-                            &s->aes_encrypt_key);
-            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
-                              s->cluster_data, n * 512);
-        } else {
-            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
-        }
-        if (ret != n * 512)
-            return -1;
-        nb_sectors -= n;
-        sector_num += n;
-        buf += n * 512;
-    }
-    s->cluster_cache_offset = -1; /* disable compressed cache */
-    return 0;
-}
-
 typedef struct QCowAIOCB {
     BlockDriverAIOCB common;
     int64_t sector_num;
+    QEMUIOVector *qiov;
     uint8_t *buf;
+    void *orig_buf;
     int nb_sectors;
     int n;
     uint64_t cluster_offset;
     uint8_t *cluster_data;
+    struct iovec hd_iov;
+    QEMUIOVector hd_qiov;
     BlockDriverAIOCB *hd_aiocb;
 } QCowAIOCB;
 
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+    if (acb->hd_aiocb)
+        bdrv_aio_cancel(acb->hd_aiocb);
+    qemu_aio_release(acb);
+}
+
+static AIOPool qcow_aio_pool = {
+    .aiocb_size         = sizeof(QCowAIOCB),
+    .cancel             = qcow_aio_cancel,
+};
+
+static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
+{
+    QCowAIOCB *acb;
+
+    acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->hd_aiocb = NULL;
+    acb->sector_num = sector_num;
+    acb->qiov = qiov;
+    if (qiov->niov > 1) {
+        acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
+        if (is_write)
+            qemu_iovec_to_buffer(qiov, acb->buf);
+    } else {
+        acb->buf = (uint8_t *)qiov->iov->iov_base;
+    }
+    acb->nb_sectors = nb_sectors;
+    acb->n = 0;
+    acb->cluster_offset = 0;
+    return acb;
+}
+
 static void qcow_aio_read_cb(void *opaque, int ret)
 {
     QCowAIOCB *acb = opaque;
@@ -536,12 +549,8 @@
     int index_in_cluster;
 
     acb->hd_aiocb = NULL;
-    if (ret < 0) {
-    fail:
-        acb->common.cb(acb->common.opaque, ret);
-        qemu_aio_release(acb);
-        return;
-    }
+    if (ret < 0)
+        goto done;
 
  redo:
     /* post process the read buffer */
@@ -563,9 +572,8 @@
 
     if (acb->nb_sectors == 0) {
         /* request completed */
-        acb->common.cb(acb->common.opaque, 0);
-        qemu_aio_release(acb);
-        return;
+        ret = 0;
+        goto done;
     }
 
     /* prepare next AIO request */
@@ -579,10 +587,13 @@
     if (!acb->cluster_offset) {
         if (bs->backing_hd) {
             /* read from the base image */
-            acb->hd_aiocb = bdrv_aio_read(bs->backing_hd,
-                acb->sector_num, acb->buf, acb->n, qcow_aio_read_cb, acb);
+            acb->hd_iov.iov_base = (void *)acb->buf;
+            acb->hd_iov.iov_len = acb->n * 512;
+            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+            acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
+                &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
             if (acb->hd_aiocb == NULL)
-                goto fail;
+                goto done;
         } else {
             /* Note: in this case, no need to wait */
             memset(acb->buf, 0, 512 * acb->n);
@@ -591,38 +602,45 @@
     } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
         /* add AIO support for compressed blocks ? */
         if (decompress_cluster(s, acb->cluster_offset) < 0)
-            goto fail;
+            goto done;
         memcpy(acb->buf,
                s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
         goto redo;
     } else {
         if ((acb->cluster_offset & 511) != 0) {
             ret = -EIO;
-            goto fail;
+            goto done;
         }
-        acb->hd_aiocb = bdrv_aio_read(s->hd,
+        acb->hd_iov.iov_base = (void *)acb->buf;
+        acb->hd_iov.iov_len = acb->n * 512;
+        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        acb->hd_aiocb = bdrv_aio_readv(s->hd,
                             (acb->cluster_offset >> 9) + index_in_cluster,
-                            acb->buf, acb->n, qcow_aio_read_cb, acb);
+                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
         if (acb->hd_aiocb == NULL)
-            goto fail;
+            goto done;
     }
+
+    return;
+
+done:
+    if (acb->qiov->niov > 1) {
+        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
+        qemu_vfree(acb->orig_buf);
+    }
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_aio_release(acb);
 }
 
-static BlockDriverAIOCB *qcow_aio_read(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
+static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
     QCowAIOCB *acb;
 
-    acb = qemu_aio_get(bs, cb, opaque);
+    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
     if (!acb)
         return NULL;
-    acb->hd_aiocb = NULL;
-    acb->sector_num = sector_num;
-    acb->buf = buf;
-    acb->nb_sectors = nb_sectors;
-    acb->n = 0;
-    acb->cluster_offset = 0;
 
     qcow_aio_read_cb(acb, 0);
     return &acb->common;
@@ -639,12 +657,8 @@
 
     acb->hd_aiocb = NULL;
 
-    if (ret < 0) {
-    fail:
-        acb->common.cb(acb->common.opaque, ret);
-        qemu_aio_release(acb);
-        return;
-    }
+    if (ret < 0)
+        goto done;
 
     acb->nb_sectors -= acb->n;
     acb->sector_num += acb->n;
@@ -652,9 +666,8 @@
 
     if (acb->nb_sectors == 0) {
         /* request completed */
-        acb->common.cb(acb->common.opaque, 0);
-        qemu_aio_release(acb);
-        return;
+        ret = 0;
+        goto done;
     }
 
     index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
@@ -666,14 +679,14 @@
                                         index_in_cluster + acb->n);
     if (!cluster_offset || (cluster_offset & 511) != 0) {
         ret = -EIO;
-        goto fail;
+        goto done;
     }
     if (s->crypt_method) {
         if (!acb->cluster_data) {
             acb->cluster_data = qemu_mallocz(s->cluster_size);
             if (!acb->cluster_data) {
                 ret = -ENOMEM;
-                goto fail;
+                goto done;
             }
         }
         encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
@@ -682,16 +695,27 @@
     } else {
         src_buf = acb->buf;
     }
-    acb->hd_aiocb = bdrv_aio_write(s->hd,
-                                   (cluster_offset >> 9) + index_in_cluster,
-                                   src_buf, acb->n,
-                                   qcow_aio_write_cb, acb);
+
+    acb->hd_iov.iov_base = (void *)src_buf;
+    acb->hd_iov.iov_len = acb->n * 512;
+    qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+    acb->hd_aiocb = bdrv_aio_writev(s->hd,
+                                    (cluster_offset >> 9) + index_in_cluster,
+                                    &acb->hd_qiov, acb->n,
+                                    qcow_aio_write_cb, acb);
     if (acb->hd_aiocb == NULL)
-        goto fail;
+        goto done;
+    return;
+
+done:
+    if (acb->qiov->niov > 1)
+        qemu_vfree(acb->orig_buf);
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_aio_release(acb);
 }
 
-static BlockDriverAIOCB *qcow_aio_write(BlockDriverState *bs,
-        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
     BDRVQcowState *s = bs->opaque;
@@ -699,27 +723,15 @@
 
     s->cluster_cache_offset = -1; /* disable compressed cache */
 
-    acb = qemu_aio_get(bs, cb, opaque);
+    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
     if (!acb)
         return NULL;
-    acb->hd_aiocb = NULL;
-    acb->sector_num = sector_num;
-    acb->buf = (uint8_t *)buf;
-    acb->nb_sectors = nb_sectors;
-    acb->n = 0;
+
 
     qcow_aio_write_cb(acb, 0);
     return &acb->common;
 }
 
-static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
-{
-    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
-    if (acb->hd_aiocb)
-        bdrv_aio_cancel(acb->hd_aiocb);
-    qemu_aio_release(acb);
-}
-
 static void qcow_close(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
@@ -730,12 +742,26 @@
     bdrv_delete(s->hd);
 }
 
-static int qcow_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
+static int qcow_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd, header_size, backing_filename_len, l1_size, i, shift;
     QCowHeader header;
     uint64_t tmp;
+    int64_t total_size = 0;
+    const char *backing_file = NULL;
+    int flags = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
+            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
+        }
+        options++;
+    }
 
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
     if (fd < 0)
@@ -853,7 +879,7 @@
 
     if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
         /* could not compress: write normal cluster */
-        qcow_write(bs, sector_num, buf, s->cluster_sectors);
+        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
     } else {
         cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
                                             out_len, 0, 0);
@@ -881,24 +907,48 @@
     return 0;
 }
 
-BlockDriver bdrv_qcow = {
-    "qcow",
-    sizeof(BDRVQcowState),
-    qcow_probe,
-    qcow_open,
-    NULL,
-    NULL,
-    qcow_close,
-    qcow_create,
-    qcow_flush,
-    qcow_is_allocated,
-    qcow_set_key,
-    qcow_make_empty,
 
-    .bdrv_aio_read = qcow_aio_read,
-    .bdrv_aio_write = qcow_aio_write,
-    .bdrv_aio_cancel = qcow_aio_cancel,
-    .aiocb_size = sizeof(QCowAIOCB),
-    .bdrv_write_compressed = qcow_write_compressed,
-    .bdrv_get_info = qcow_get_info,
+static QEMUOptionParameter qcow_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    {
+        .name = BLOCK_OPT_ENCRYPT,
+        .type = OPT_FLAG,
+        .help = "Encrypt the image"
+    },
+    { NULL }
 };
+
+static BlockDriver bdrv_qcow = {
+    .format_name	= "qcow",
+    .instance_size	= sizeof(BDRVQcowState),
+    .bdrv_probe		= qcow_probe,
+    .bdrv_open		= qcow_open,
+    .bdrv_close		= qcow_close,
+    .bdrv_create	= qcow_create,
+    .bdrv_flush		= qcow_flush,
+    .bdrv_is_allocated	= qcow_is_allocated,
+    .bdrv_set_key	= qcow_set_key,
+    .bdrv_make_empty	= qcow_make_empty,
+    .bdrv_aio_readv	= qcow_aio_readv,
+    .bdrv_aio_writev	= qcow_aio_writev,
+    .bdrv_write_compressed = qcow_write_compressed,
+    .bdrv_get_info	= qcow_get_info,
+
+    .create_options = qcow_create_options,
+};
+
+static void bdrv_qcow_init(void)
+{
+    bdrv_register(&bdrv_qcow);
+}
+
+block_init(bdrv_qcow_init);
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
new file mode 100644
index 0000000..d349655
--- /dev/null
+++ b/block/qcow2-cluster.c
@@ -0,0 +1,800 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <zlib.h>
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "block/qcow2.h"
+
+int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int new_l1_size, new_l1_size2, ret, i;
+    uint64_t *new_l1_table;
+    uint64_t new_l1_table_offset;
+    uint8_t data[12];
+
+    new_l1_size = s->l1_size;
+    if (min_size <= new_l1_size)
+        return 0;
+    while (min_size > new_l1_size) {
+        new_l1_size = (new_l1_size * 3 + 1) / 2;
+    }
+#ifdef DEBUG_ALLOC2
+    printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size);
+#endif
+
+    new_l1_size2 = sizeof(uint64_t) * new_l1_size;
+    new_l1_table = qemu_mallocz(new_l1_size2);
+    memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
+
+    /* write new table (align to cluster) */
+    new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
+
+    for(i = 0; i < s->l1_size; i++)
+        new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
+    ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
+    if (ret != new_l1_size2)
+        goto fail;
+    for(i = 0; i < s->l1_size; i++)
+        new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
+
+    /* set new table */
+    cpu_to_be32w((uint32_t*)data, new_l1_size);
+    cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,
+                sizeof(data)) != sizeof(data))
+        goto fail;
+    qemu_free(s->l1_table);
+    qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
+    s->l1_table_offset = new_l1_table_offset;
+    s->l1_table = new_l1_table;
+    s->l1_size = new_l1_size;
+    return 0;
+ fail:
+    qemu_free(s->l1_table);
+    return -EIO;
+}
+
+void qcow2_l2_cache_reset(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+
+    memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+    memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
+    memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
+}
+
+static inline int l2_cache_new_entry(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint32_t min_count;
+    int min_index, i;
+
+    /* find a new entry in the least used one */
+    min_index = 0;
+    min_count = 0xffffffff;
+    for(i = 0; i < L2_CACHE_SIZE; i++) {
+        if (s->l2_cache_counts[i] < min_count) {
+            min_count = s->l2_cache_counts[i];
+            min_index = i;
+        }
+    }
+    return min_index;
+}
+
+/*
+ * seek_l2_table
+ *
+ * seek l2_offset in the l2_cache table
+ * if not found, return NULL,
+ * if found,
+ *   increments the l2 cache hit count of the entry,
+ *   if counter overflow, divide by two all counters
+ *   return the pointer to the l2 cache entry
+ *
+ */
+
+static uint64_t *seek_l2_table(BDRVQcowState *s, uint64_t l2_offset)
+{
+    int i, j;
+
+    for(i = 0; i < L2_CACHE_SIZE; i++) {
+        if (l2_offset == s->l2_cache_offsets[i]) {
+            /* increment the hit count */
+            if (++s->l2_cache_counts[i] == 0xffffffff) {
+                for(j = 0; j < L2_CACHE_SIZE; j++) {
+                    s->l2_cache_counts[j] >>= 1;
+                }
+            }
+            return s->l2_cache + (i << s->l2_bits);
+        }
+    }
+    return NULL;
+}
+
+/*
+ * l2_load
+ *
+ * Loads a L2 table into memory. If the table is in the cache, the cache
+ * is used; otherwise the L2 table is loaded from the image file.
+ *
+ * Returns a pointer to the L2 table on success, or NULL if the read from
+ * the image file failed.
+ */
+
+static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    int min_index;
+    uint64_t *l2_table;
+
+    /* seek if the table for the given offset is in the cache */
+
+    l2_table = seek_l2_table(s, l2_offset);
+    if (l2_table != NULL)
+        return l2_table;
+
+    /* not found: load a new entry in the least used one */
+
+    min_index = l2_cache_new_entry(bs);
+    l2_table = s->l2_cache + (min_index << s->l2_bits);
+    if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
+        s->l2_size * sizeof(uint64_t))
+        return NULL;
+    s->l2_cache_offsets[min_index] = l2_offset;
+    s->l2_cache_counts[min_index] = 1;
+
+    return l2_table;
+}
+
+/*
+ * Writes one sector of the L1 table to the disk (can't update single entries
+ * and we really don't want bdrv_pread to perform a read-modify-write)
+ */
+#define L1_ENTRIES_PER_SECTOR (512 / 8)
+static int write_l1_entry(BDRVQcowState *s, int l1_index)
+{
+    uint64_t buf[L1_ENTRIES_PER_SECTOR];
+    int l1_start_index;
+    int i;
+
+    l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
+    for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
+        buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
+    }
+
+    if (bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index,
+        buf, sizeof(buf)) != sizeof(buf))
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * l2_allocate
+ *
+ * Allocate a new l2 entry in the file. If l1_index points to an already
+ * used entry in the L2 table (i.e. we are doing a copy on write for the L2
+ * table) copy the contents of the old L2 table into the newly allocated one.
+ * Otherwise the new table is initialized with zeros.
+ *
+ */
+
+static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    int min_index;
+    uint64_t old_l2_offset;
+    uint64_t *l2_table, l2_offset;
+
+    old_l2_offset = s->l1_table[l1_index];
+
+    /* allocate a new l2 entry */
+
+    l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
+
+    /* update the L1 entry */
+
+    s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
+    if (write_l1_entry(s, l1_index) < 0) {
+        return NULL;
+    }
+
+    /* allocate a new entry in the l2 cache */
+
+    min_index = l2_cache_new_entry(bs);
+    l2_table = s->l2_cache + (min_index << s->l2_bits);
+
+    if (old_l2_offset == 0) {
+        /* if there was no old l2 table, clear the new table */
+        memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+    } else {
+        /* if there was an old l2 table, read it from the disk */
+        if (bdrv_pread(s->hd, old_l2_offset,
+                       l2_table, s->l2_size * sizeof(uint64_t)) !=
+            s->l2_size * sizeof(uint64_t))
+            return NULL;
+    }
+    /* write the l2 table to the file */
+    if (bdrv_pwrite(s->hd, l2_offset,
+                    l2_table, s->l2_size * sizeof(uint64_t)) !=
+        s->l2_size * sizeof(uint64_t))
+        return NULL;
+
+    /* update the l2 cache entry */
+
+    s->l2_cache_offsets[min_index] = l2_offset;
+    s->l2_cache_counts[min_index] = 1;
+
+    return l2_table;
+}
+
+static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
+        uint64_t *l2_table, uint64_t start, uint64_t mask)
+{
+    int i;
+    uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
+
+    if (!offset)
+        return 0;
+
+    for (i = start; i < start + nb_clusters; i++)
+        if (offset + i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
+            break;
+
+	return (i - start);
+}
+
+static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
+{
+    int i = 0;
+
+    while(nb_clusters-- && l2_table[i] == 0)
+        i++;
+
+    return i;
+}
+
+/* The crypt function is compatible with the linux cryptoloop
+   algorithm for < 4 GB images. NOTE: out_buf == in_buf is
+   supported */
+void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
+                           uint8_t *out_buf, const uint8_t *in_buf,
+                           int nb_sectors, int enc,
+                           const AES_KEY *key)
+{
+    union {
+        uint64_t ll[2];
+        uint8_t b[16];
+    } ivec;
+    int i;
+
+    for(i = 0; i < nb_sectors; i++) {
+        ivec.ll[0] = cpu_to_le64(sector_num);
+        ivec.ll[1] = 0;
+        AES_cbc_encrypt(in_buf, out_buf, 512, key,
+                        ivec.b, enc);
+        sector_num++;
+        in_buf += 512;
+        out_buf += 512;
+    }
+}
+
+
+static int qcow_read(BlockDriverState *bs, int64_t sector_num,
+                     uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, index_in_cluster, n, n1;
+    uint64_t cluster_offset;
+
+    while (nb_sectors > 0) {
+        n = nb_sectors;
+        cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, &n);
+        index_in_cluster = sector_num & (s->cluster_sectors - 1);
+        if (!cluster_offset) {
+            if (bs->backing_hd) {
+                /* read from the base image */
+                n1 = qcow2_backing_read1(bs->backing_hd, sector_num, buf, n);
+                if (n1 > 0) {
+                    ret = bdrv_read(bs->backing_hd, sector_num, buf, n1);
+                    if (ret < 0)
+                        return -1;
+                }
+            } else {
+                memset(buf, 0, 512 * n);
+            }
+        } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+            if (qcow2_decompress_cluster(s, cluster_offset) < 0)
+                return -1;
+            memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
+        } else {
+            ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
+            if (ret != n * 512)
+                return -1;
+            if (s->crypt_method) {
+                qcow2_encrypt_sectors(s, sector_num, buf, buf, n, 0,
+                                &s->aes_decrypt_key);
+            }
+        }
+        nb_sectors -= n;
+        sector_num += n;
+        buf += n * 512;
+    }
+    return 0;
+}
+
+static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
+                        uint64_t cluster_offset, int n_start, int n_end)
+{
+    BDRVQcowState *s = bs->opaque;
+    int n, ret;
+
+    n = n_end - n_start;
+    if (n <= 0)
+        return 0;
+    ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n);
+    if (ret < 0)
+        return ret;
+    if (s->crypt_method) {
+        qcow2_encrypt_sectors(s, start_sect + n_start,
+                        s->cluster_data,
+                        s->cluster_data, n, 1,
+                        &s->aes_encrypt_key);
+    }
+    ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start,
+                     s->cluster_data, n);
+    if (ret < 0)
+        return ret;
+    return 0;
+}
+
+
+/*
+ * get_cluster_offset
+ *
+ * For a given offset of the disk image, return cluster offset in
+ * qcow2 file.
+ *
+ * on entry, *num is the number of contiguous clusters we'd like to
+ * access following offset.
+ *
+ * on exit, *num is the number of contiguous clusters we can read.
+ *
+ * Return 1, if the offset is found
+ * Return 0, otherwise.
+ *
+ */
+
+uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
+    int *num)
+{
+    BDRVQcowState *s = bs->opaque;
+    int l1_index, l2_index;
+    uint64_t l2_offset, *l2_table, cluster_offset;
+    int l1_bits, c;
+    int index_in_cluster, nb_available, nb_needed, nb_clusters;
+
+    index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
+    nb_needed = *num + index_in_cluster;
+
+    l1_bits = s->l2_bits + s->cluster_bits;
+
+    /* compute how many bytes there are between the offset and
+     * the end of the l1 entry
+     */
+
+    nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1));
+
+    /* compute the number of available sectors */
+
+    nb_available = (nb_available >> 9) + index_in_cluster;
+
+    if (nb_needed > nb_available) {
+        nb_needed = nb_available;
+    }
+
+    cluster_offset = 0;
+
+    /* seek the the l2 offset in the l1 table */
+
+    l1_index = offset >> l1_bits;
+    if (l1_index >= s->l1_size)
+        goto out;
+
+    l2_offset = s->l1_table[l1_index];
+
+    /* seek the l2 table of the given l2 offset */
+
+    if (!l2_offset)
+        goto out;
+
+    /* load the l2 table in memory */
+
+    l2_offset &= ~QCOW_OFLAG_COPIED;
+    l2_table = l2_load(bs, l2_offset);
+    if (l2_table == NULL)
+        return 0;
+
+    /* find the cluster offset for the given disk offset */
+
+    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    nb_clusters = size_to_clusters(s, nb_needed << 9);
+
+    if (!cluster_offset) {
+        /* how many empty clusters ? */
+        c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
+    } else {
+        /* how many allocated clusters ? */
+        c = count_contiguous_clusters(nb_clusters, s->cluster_size,
+                &l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
+    }
+
+   nb_available = (c * s->cluster_sectors);
+out:
+    if (nb_available > nb_needed)
+        nb_available = nb_needed;
+
+    *num = nb_available - index_in_cluster;
+
+    return cluster_offset & ~QCOW_OFLAG_COPIED;
+}
+
+/*
+ * get_cluster_table
+ *
+ * for a given disk offset, load (and allocate if needed)
+ * the l2 table.
+ *
+ * the l2 table offset in the qcow2 file and the cluster index
+ * in the l2 table are given to the caller.
+ *
+ */
+
+static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
+                             uint64_t **new_l2_table,
+                             uint64_t *new_l2_offset,
+                             int *new_l2_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    int l1_index, l2_index, ret;
+    uint64_t l2_offset, *l2_table;
+
+    /* seek the the l2 offset in the l1 table */
+
+    l1_index = offset >> (s->l2_bits + s->cluster_bits);
+    if (l1_index >= s->l1_size) {
+        ret = qcow2_grow_l1_table(bs, l1_index + 1);
+        if (ret < 0)
+            return 0;
+    }
+    l2_offset = s->l1_table[l1_index];
+
+    /* seek the l2 table of the given l2 offset */
+
+    if (l2_offset & QCOW_OFLAG_COPIED) {
+        /* load the l2 table in memory */
+        l2_offset &= ~QCOW_OFLAG_COPIED;
+        l2_table = l2_load(bs, l2_offset);
+        if (l2_table == NULL)
+            return 0;
+    } else {
+        if (l2_offset)
+            qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+        l2_table = l2_allocate(bs, l1_index);
+        if (l2_table == NULL)
+            return 0;
+        l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
+    }
+
+    /* find the cluster offset for the given disk offset */
+
+    l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+
+    *new_l2_table = l2_table;
+    *new_l2_offset = l2_offset;
+    *new_l2_index = l2_index;
+
+    return 1;
+}
+
+/*
+ * alloc_compressed_cluster_offset
+ *
+ * For a given offset of the disk image, return cluster offset in
+ * qcow2 file.
+ *
+ * If the offset is not found, allocate a new compressed cluster.
+ *
+ * Return the cluster offset if successful,
+ * Return 0, otherwise.
+ *
+ */
+
+uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
+                                               uint64_t offset,
+                                               int compressed_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int l2_index, ret;
+    uint64_t l2_offset, *l2_table, cluster_offset;
+    int nb_csectors;
+
+    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+    if (ret == 0)
+        return 0;
+
+    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+    if (cluster_offset & QCOW_OFLAG_COPIED)
+        return cluster_offset & ~QCOW_OFLAG_COPIED;
+
+    if (cluster_offset)
+        qcow2_free_any_clusters(bs, cluster_offset, 1);
+
+    cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
+    nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
+                  (cluster_offset >> 9);
+
+    cluster_offset |= QCOW_OFLAG_COMPRESSED |
+                      ((uint64_t)nb_csectors << s->csize_shift);
+
+    /* update L2 table */
+
+    /* compressed clusters never have the copied flag */
+
+    l2_table[l2_index] = cpu_to_be64(cluster_offset);
+    if (bdrv_pwrite(s->hd,
+                    l2_offset + l2_index * sizeof(uint64_t),
+                    l2_table + l2_index,
+                    sizeof(uint64_t)) != sizeof(uint64_t))
+        return 0;
+
+    return cluster_offset;
+}
+
+/*
+ * Write L2 table updates to disk, writing whole sectors to avoid a
+ * read-modify-write in bdrv_pwrite
+ */
+#define L2_ENTRIES_PER_SECTOR (512 / 8)
+static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table,
+    uint64_t l2_offset, int l2_index, int num)
+{
+    int l2_start_index = l2_index & ~(L1_ENTRIES_PER_SECTOR - 1);
+    int start_offset = (8 * l2_index) & ~511;
+    int end_offset = (8 * (l2_index + num) + 511) & ~511;
+    size_t len = end_offset - start_offset;
+
+    if (bdrv_pwrite(s->hd, l2_offset + start_offset, &l2_table[l2_start_index],
+        len) != len)
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
+    QCowL2Meta *m)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i, j = 0, l2_index, ret;
+    uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
+
+    if (m->nb_clusters == 0)
+        return 0;
+
+    old_cluster = qemu_malloc(m->nb_clusters * sizeof(uint64_t));
+
+    /* copy content of unmodified sectors */
+    start_sect = (m->offset & ~(s->cluster_size - 1)) >> 9;
+    if (m->n_start) {
+        ret = copy_sectors(bs, start_sect, cluster_offset, 0, m->n_start);
+        if (ret < 0)
+            goto err;
+    }
+
+    if (m->nb_available & (s->cluster_sectors - 1)) {
+        uint64_t end = m->nb_available & ~(uint64_t)(s->cluster_sectors - 1);
+        ret = copy_sectors(bs, start_sect + end, cluster_offset + (end << 9),
+                m->nb_available - end, s->cluster_sectors);
+        if (ret < 0)
+            goto err;
+    }
+
+    ret = -EIO;
+    /* update L2 table */
+    if (!get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index))
+        goto err;
+
+    for (i = 0; i < m->nb_clusters; i++) {
+        /* if two concurrent writes happen to the same unallocated cluster
+	 * each write allocates separate cluster and writes data concurrently.
+	 * The first one to complete updates l2 table with pointer to its
+	 * cluster the second one has to do RMW (which is done above by
+	 * copy_sectors()), update l2 table with its cluster pointer and free
+	 * old cluster. This is what this loop does */
+        if(l2_table[l2_index + i] != 0)
+            old_cluster[j++] = l2_table[l2_index + i];
+
+        l2_table[l2_index + i] = cpu_to_be64((cluster_offset +
+                    (i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
+     }
+
+    if (write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters) < 0) {
+        ret = -1;
+        goto err;
+    }
+
+    for (i = 0; i < j; i++)
+        qcow2_free_any_clusters(bs,
+            be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
+
+    ret = 0;
+err:
+    qemu_free(old_cluster);
+    return ret;
+ }
+
+/*
+ * alloc_cluster_offset
+ *
+ * For a given offset of the disk image, return cluster offset in
+ * qcow2 file.
+ *
+ * If the offset is not found, allocate a new cluster.
+ *
+ * Return the cluster offset if successful,
+ * Return 0, otherwise.
+ *
+ */
+
+uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
+                                    uint64_t offset,
+                                    int n_start, int n_end,
+                                    int *num, QCowL2Meta *m)
+{
+    BDRVQcowState *s = bs->opaque;
+    int l2_index, ret;
+    uint64_t l2_offset, *l2_table, cluster_offset;
+    int nb_clusters, i = 0;
+
+    ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
+    if (ret == 0)
+        return 0;
+
+    nb_clusters = size_to_clusters(s, n_end << 9);
+
+    nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+
+    cluster_offset = be64_to_cpu(l2_table[l2_index]);
+
+    /* We keep all QCOW_OFLAG_COPIED clusters */
+
+    if (cluster_offset & QCOW_OFLAG_COPIED) {
+        nb_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
+                &l2_table[l2_index], 0, 0);
+
+        cluster_offset &= ~QCOW_OFLAG_COPIED;
+        m->nb_clusters = 0;
+
+        goto out;
+    }
+
+    /* for the moment, multiple compressed clusters are not managed */
+
+    if (cluster_offset & QCOW_OFLAG_COMPRESSED)
+        nb_clusters = 1;
+
+    /* how many available clusters ? */
+
+    while (i < nb_clusters) {
+        i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
+                &l2_table[l2_index], i, 0);
+
+        if(be64_to_cpu(l2_table[l2_index + i]))
+            break;
+
+        i += count_contiguous_free_clusters(nb_clusters - i,
+                &l2_table[l2_index + i]);
+
+        cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
+
+        if ((cluster_offset & QCOW_OFLAG_COPIED) ||
+                (cluster_offset & QCOW_OFLAG_COMPRESSED))
+            break;
+    }
+    nb_clusters = i;
+
+    /* allocate a new cluster */
+
+    cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
+
+    /* save info needed for meta data update */
+    m->offset = offset;
+    m->n_start = n_start;
+    m->nb_clusters = nb_clusters;
+
+out:
+    m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
+
+    *num = m->nb_available - n_start;
+
+    return cluster_offset;
+}
+
+static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
+                             const uint8_t *buf, int buf_size)
+{
+    z_stream strm1, *strm = &strm1;
+    int ret, out_len;
+
+    memset(strm, 0, sizeof(*strm));
+
+    strm->next_in = (uint8_t *)buf;
+    strm->avail_in = buf_size;
+    strm->next_out = out_buf;
+    strm->avail_out = out_buf_size;
+
+    ret = inflateInit2(strm, -12);
+    if (ret != Z_OK)
+        return -1;
+    ret = inflate(strm, Z_FINISH);
+    out_len = strm->next_out - out_buf;
+    if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
+        out_len != out_buf_size) {
+        inflateEnd(strm);
+        return -1;
+    }
+    inflateEnd(strm);
+    return 0;
+}
+
+int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
+{
+    int ret, csize, nb_csectors, sector_offset;
+    uint64_t coffset;
+
+    coffset = cluster_offset & s->cluster_offset_mask;
+    if (s->cluster_cache_offset != coffset) {
+        nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
+        sector_offset = coffset & 511;
+        csize = nb_csectors * 512 - sector_offset;
+        ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors);
+        if (ret < 0) {
+            return -1;
+        }
+        if (decompress_buffer(s->cluster_cache, s->cluster_size,
+                              s->cluster_data + sector_offset, csize) < 0) {
+            return -1;
+        }
+        s->cluster_cache_offset = coffset;
+    }
+    return 0;
+}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
new file mode 100644
index 0000000..dd6e293
--- /dev/null
+++ b/block/qcow2-refcount.c
@@ -0,0 +1,854 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "block/qcow2.h"
+
+static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
+static int update_refcount(BlockDriverState *bs,
+                            int64_t offset, int64_t length,
+                            int addend);
+
+/*********************************************************/
+/* refcount handling */
+
+int qcow2_refcount_init(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret, refcount_table_size2, i;
+
+    s->refcount_block_cache = qemu_malloc(s->cluster_size);
+    refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
+    s->refcount_table = qemu_malloc(refcount_table_size2);
+    if (s->refcount_table_size > 0) {
+        ret = bdrv_pread(s->hd, s->refcount_table_offset,
+                         s->refcount_table, refcount_table_size2);
+        if (ret != refcount_table_size2)
+            goto fail;
+        for(i = 0; i < s->refcount_table_size; i++)
+            be64_to_cpus(&s->refcount_table[i]);
+    }
+    return 0;
+ fail:
+    return -ENOMEM;
+}
+
+void qcow2_refcount_close(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    qemu_free(s->refcount_block_cache);
+    qemu_free(s->refcount_table);
+}
+
+
+static int load_refcount_block(BlockDriverState *bs,
+                               int64_t refcount_block_offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+    ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache,
+                     s->cluster_size);
+    if (ret != s->cluster_size)
+        return -EIO;
+    s->refcount_block_cache_offset = refcount_block_offset;
+    return 0;
+}
+
+static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    int refcount_table_index, block_index;
+    int64_t refcount_block_offset;
+
+    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+    if (refcount_table_index >= s->refcount_table_size)
+        return 0;
+    refcount_block_offset = s->refcount_table[refcount_table_index];
+    if (!refcount_block_offset)
+        return 0;
+    if (refcount_block_offset != s->refcount_block_cache_offset) {
+        /* better than nothing: return allocated if read error */
+        if (load_refcount_block(bs, refcount_block_offset) < 0)
+            return 1;
+    }
+    block_index = cluster_index &
+        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+    return be16_to_cpu(s->refcount_block_cache[block_index]);
+}
+
+static int grow_refcount_table(BlockDriverState *bs, int min_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
+    uint64_t *new_table;
+    int64_t table_offset;
+    uint8_t data[12];
+    int old_table_size;
+    int64_t old_table_offset;
+
+    if (min_size <= s->refcount_table_size)
+        return 0;
+    /* compute new table size */
+    refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
+    for(;;) {
+        if (refcount_table_clusters == 0) {
+            refcount_table_clusters = 1;
+        } else {
+            refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
+        }
+        new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
+        if (min_size <= new_table_size)
+            break;
+    }
+#ifdef DEBUG_ALLOC2
+    printf("grow_refcount_table from %d to %d\n",
+           s->refcount_table_size,
+           new_table_size);
+#endif
+    new_table_size2 = new_table_size * sizeof(uint64_t);
+    new_table = qemu_mallocz(new_table_size2);
+    memcpy(new_table, s->refcount_table,
+           s->refcount_table_size * sizeof(uint64_t));
+    for(i = 0; i < s->refcount_table_size; i++)
+        cpu_to_be64s(&new_table[i]);
+    /* Note: we cannot update the refcount now to avoid recursion */
+    table_offset = alloc_clusters_noref(bs, new_table_size2);
+    ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
+    if (ret != new_table_size2)
+        goto fail;
+    for(i = 0; i < s->refcount_table_size; i++)
+        be64_to_cpus(&new_table[i]);
+
+    cpu_to_be64w((uint64_t*)data, table_offset);
+    cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
+                    data, sizeof(data)) != sizeof(data))
+        goto fail;
+    qemu_free(s->refcount_table);
+    old_table_offset = s->refcount_table_offset;
+    old_table_size = s->refcount_table_size;
+    s->refcount_table = new_table;
+    s->refcount_table_size = new_table_size;
+    s->refcount_table_offset = table_offset;
+
+    update_refcount(bs, table_offset, new_table_size2, 1);
+    qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
+    return 0;
+ fail:
+    qcow2_free_clusters(bs, table_offset, new_table_size2);
+    qemu_free(new_table);
+    return -EIO;
+}
+
+
+static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t offset, refcount_block_offset;
+    int ret, refcount_table_index;
+    uint64_t data64;
+
+    /* Find L1 index and grow refcount table if needed */
+    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+    if (refcount_table_index >= s->refcount_table_size) {
+        ret = grow_refcount_table(bs, refcount_table_index + 1);
+        if (ret < 0)
+            return ret;
+    }
+
+    /* Load or allocate the refcount block */
+    refcount_block_offset = s->refcount_table[refcount_table_index];
+    if (!refcount_block_offset) {
+        /* create a new refcount block */
+        /* Note: we cannot update the refcount now to avoid recursion */
+        offset = alloc_clusters_noref(bs, s->cluster_size);
+        memset(s->refcount_block_cache, 0, s->cluster_size);
+        ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
+        if (ret != s->cluster_size)
+            return -EINVAL;
+        s->refcount_table[refcount_table_index] = offset;
+        data64 = cpu_to_be64(offset);
+        ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
+                          refcount_table_index * sizeof(uint64_t),
+                          &data64, sizeof(data64));
+        if (ret != sizeof(data64))
+            return -EINVAL;
+
+        refcount_block_offset = offset;
+        s->refcount_block_cache_offset = offset;
+        update_refcount(bs, offset, s->cluster_size, 1);
+    } else {
+        if (refcount_block_offset != s->refcount_block_cache_offset) {
+            if (load_refcount_block(bs, refcount_block_offset) < 0)
+                return -EIO;
+        }
+    }
+
+    return refcount_block_offset;
+}
+
+#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT)
+static int write_refcount_block_entries(BDRVQcowState *s,
+    int64_t refcount_block_offset, int first_index, int last_index)
+{
+    size_t size;
+
+    first_index &= ~(REFCOUNTS_PER_SECTOR - 1);
+    last_index = (last_index + REFCOUNTS_PER_SECTOR)
+        & ~(REFCOUNTS_PER_SECTOR - 1);
+
+    size = (last_index - first_index) << REFCOUNT_SHIFT;
+    if (bdrv_pwrite(s->hd,
+        refcount_block_offset + (first_index << REFCOUNT_SHIFT),
+        &s->refcount_block_cache[first_index], size) != size)
+    {
+        return -EIO;
+    }
+
+    return 0;
+}
+
+/* XXX: cache several refcount block clusters ? */
+static int update_refcount(BlockDriverState *bs,
+                            int64_t offset, int64_t length,
+                            int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t start, last, cluster_offset;
+    int64_t refcount_block_offset = 0;
+    int64_t table_index = -1, old_table_index;
+    int first_index = -1, last_index = -1;
+
+#ifdef DEBUG_ALLOC2
+    printf("update_refcount: offset=%lld size=%lld addend=%d\n",
+           offset, length, addend);
+#endif
+    if (length <= 0)
+        return -EINVAL;
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + length - 1) & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last;
+        cluster_offset += s->cluster_size)
+    {
+        int block_index, refcount;
+        int64_t cluster_index = cluster_offset >> s->cluster_bits;
+
+        /* Only write refcount block to disk when we are done with it */
+        old_table_index = table_index;
+        table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
+        if ((old_table_index >= 0) && (table_index != old_table_index)) {
+
+            if (write_refcount_block_entries(s, refcount_block_offset,
+                first_index, last_index) < 0)
+            {
+                return -EIO;
+            }
+
+            first_index = -1;
+            last_index = -1;
+        }
+
+        /* Load the refcount block and allocate it if needed */
+        refcount_block_offset = alloc_refcount_block(bs, cluster_index);
+        if (refcount_block_offset < 0) {
+            return refcount_block_offset;
+        }
+
+        /* we can update the count and save it */
+        block_index = cluster_index &
+            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
+        if (first_index == -1 || block_index < first_index) {
+            first_index = block_index;
+        }
+        if (block_index > last_index) {
+            last_index = block_index;
+        }
+
+        refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
+        refcount += addend;
+        if (refcount < 0 || refcount > 0xffff)
+            return -EINVAL;
+        if (refcount == 0 && cluster_index < s->free_cluster_index) {
+            s->free_cluster_index = cluster_index;
+        }
+        s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
+    }
+
+    /* Write last changed block to disk */
+    if (refcount_block_offset != 0) {
+        if (write_refcount_block_entries(s, refcount_block_offset,
+            first_index, last_index) < 0)
+        {
+            return -EIO;
+        }
+    }
+
+    return 0;
+}
+
+/* addend must be 1 or -1 */
+static int update_cluster_refcount(BlockDriverState *bs,
+                                   int64_t cluster_index,
+                                   int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret;
+
+    ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return get_refcount(bs, cluster_index);
+}
+
+
+
+/*********************************************************/
+/* cluster allocation functions */
+
+
+
+/* return < 0 if error */
+static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i, nb_clusters;
+
+    nb_clusters = size_to_clusters(s, size);
+retry:
+    for(i = 0; i < nb_clusters; i++) {
+        int64_t i = s->free_cluster_index++;
+        if (get_refcount(bs, i) != 0)
+            goto retry;
+    }
+#ifdef DEBUG_ALLOC2
+    printf("alloc_clusters: size=%lld -> %lld\n",
+            size,
+            (s->free_cluster_index - nb_clusters) << s->cluster_bits);
+#endif
+    return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
+}
+
+int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
+{
+    int64_t offset;
+
+    offset = alloc_clusters_noref(bs, size);
+    update_refcount(bs, offset, size, 1);
+    return offset;
+}
+
+/* only used to allocate compressed sectors. We try to allocate
+   contiguous sectors. size must be <= cluster_size */
+int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t offset, cluster_offset;
+    int free_in_cluster;
+
+    assert(size > 0 && size <= s->cluster_size);
+    if (s->free_byte_offset == 0) {
+        s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
+    }
+ redo:
+    free_in_cluster = s->cluster_size -
+        (s->free_byte_offset & (s->cluster_size - 1));
+    if (size <= free_in_cluster) {
+        /* enough space in current cluster */
+        offset = s->free_byte_offset;
+        s->free_byte_offset += size;
+        free_in_cluster -= size;
+        if (free_in_cluster == 0)
+            s->free_byte_offset = 0;
+        if ((offset & (s->cluster_size - 1)) != 0)
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+    } else {
+        offset = qcow2_alloc_clusters(bs, s->cluster_size);
+        cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
+        if ((cluster_offset + s->cluster_size) == offset) {
+            /* we are lucky: contiguous data */
+            offset = s->free_byte_offset;
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+            s->free_byte_offset += size;
+        } else {
+            s->free_byte_offset = offset;
+            goto redo;
+        }
+    }
+    return offset;
+}
+
+void qcow2_free_clusters(BlockDriverState *bs,
+                          int64_t offset, int64_t size)
+{
+    update_refcount(bs, offset, size, -1);
+}
+
+/*
+ * free_any_clusters
+ *
+ * free clusters according to its type: compressed or not
+ *
+ */
+
+void qcow2_free_any_clusters(BlockDriverState *bs,
+    uint64_t cluster_offset, int nb_clusters)
+{
+    BDRVQcowState *s = bs->opaque;
+
+    /* free the cluster */
+
+    if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        int nb_csectors;
+        nb_csectors = ((cluster_offset >> s->csize_shift) &
+                       s->csize_mask) + 1;
+        qcow2_free_clusters(bs,
+            (cluster_offset & s->cluster_offset_mask) & ~511,
+            nb_csectors * 512);
+        return;
+    }
+
+    qcow2_free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits);
+
+    return;
+}
+
+
+
+/*********************************************************/
+/* snapshots and image creation */
+
+
+
+void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
+    int64_t size)
+{
+    int refcount;
+    int64_t start, last, cluster_offset;
+    uint16_t *p;
+
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + size - 1)  & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last;
+        cluster_offset += s->cluster_size) {
+        p = &s->refcount_block[cluster_offset >> s->cluster_bits];
+        refcount = be16_to_cpu(*p);
+        refcount++;
+        *p = cpu_to_be16(refcount);
+    }
+}
+
+/* update the refcounts of snapshots and the copied flag */
+int qcow2_update_snapshot_refcount(BlockDriverState *bs,
+    int64_t l1_table_offset, int l1_size, int addend)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
+    int64_t old_offset, old_l2_offset;
+    int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
+
+    qcow2_l2_cache_reset(bs);
+
+    l2_table = NULL;
+    l1_table = NULL;
+    l1_size2 = l1_size * sizeof(uint64_t);
+    l1_allocated = 0;
+    if (l1_table_offset != s->l1_table_offset) {
+        l1_table = qemu_malloc(l1_size2);
+        l1_allocated = 1;
+        if (bdrv_pread(s->hd, l1_table_offset,
+                       l1_table, l1_size2) != l1_size2)
+            goto fail;
+        for(i = 0;i < l1_size; i++)
+            be64_to_cpus(&l1_table[i]);
+    } else {
+        assert(l1_size == s->l1_size);
+        l1_table = s->l1_table;
+        l1_allocated = 0;
+    }
+
+    l2_size = s->l2_size * sizeof(uint64_t);
+    l2_table = qemu_malloc(l2_size);
+    l1_modified = 0;
+    for(i = 0; i < l1_size; i++) {
+        l2_offset = l1_table[i];
+        if (l2_offset) {
+            old_l2_offset = l2_offset;
+            l2_offset &= ~QCOW_OFLAG_COPIED;
+            l2_modified = 0;
+            if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
+                goto fail;
+            for(j = 0; j < s->l2_size; j++) {
+                offset = be64_to_cpu(l2_table[j]);
+                if (offset != 0) {
+                    old_offset = offset;
+                    offset &= ~QCOW_OFLAG_COPIED;
+                    if (offset & QCOW_OFLAG_COMPRESSED) {
+                        nb_csectors = ((offset >> s->csize_shift) &
+                                       s->csize_mask) + 1;
+                        if (addend != 0)
+                            update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
+                                            nb_csectors * 512, addend);
+                        /* compressed clusters are never modified */
+                        refcount = 2;
+                    } else {
+                        if (addend != 0) {
+                            refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
+                        } else {
+                            refcount = get_refcount(bs, offset >> s->cluster_bits);
+                        }
+                    }
+
+                    if (refcount == 1) {
+                        offset |= QCOW_OFLAG_COPIED;
+                    }
+                    if (offset != old_offset) {
+                        l2_table[j] = cpu_to_be64(offset);
+                        l2_modified = 1;
+                    }
+                }
+            }
+            if (l2_modified) {
+                if (bdrv_pwrite(s->hd,
+                                l2_offset, l2_table, l2_size) != l2_size)
+                    goto fail;
+            }
+
+            if (addend != 0) {
+                refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);
+            } else {
+                refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
+            }
+            if (refcount == 1) {
+                l2_offset |= QCOW_OFLAG_COPIED;
+            }
+            if (l2_offset != old_l2_offset) {
+                l1_table[i] = l2_offset;
+                l1_modified = 1;
+            }
+        }
+    }
+    if (l1_modified) {
+        for(i = 0; i < l1_size; i++)
+            cpu_to_be64s(&l1_table[i]);
+        if (bdrv_pwrite(s->hd, l1_table_offset, l1_table,
+                        l1_size2) != l1_size2)
+            goto fail;
+        for(i = 0; i < l1_size; i++)
+            be64_to_cpus(&l1_table[i]);
+    }
+    if (l1_allocated)
+        qemu_free(l1_table);
+    qemu_free(l2_table);
+    return 0;
+ fail:
+    if (l1_allocated)
+        qemu_free(l1_table);
+    qemu_free(l2_table);
+    return -EIO;
+}
+
+
+
+
+/*********************************************************/
+/* refcount checking functions */
+
+
+
+/*
+ * Increases the refcount for a range of clusters in a given refcount table.
+ * This is used to construct a temporary refcount table out of L1 and L2 tables
+ * which can be compared the the refcount table saved in the image.
+ *
+ * Returns the number of errors in the image that were found
+ */
+static int inc_refcounts(BlockDriverState *bs,
+                          uint16_t *refcount_table,
+                          int refcount_table_size,
+                          int64_t offset, int64_t size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t start, last, cluster_offset;
+    int k;
+    int errors = 0;
+
+    if (size <= 0)
+        return 0;
+
+    start = offset & ~(s->cluster_size - 1);
+    last = (offset + size - 1) & ~(s->cluster_size - 1);
+    for(cluster_offset = start; cluster_offset <= last;
+        cluster_offset += s->cluster_size) {
+        k = cluster_offset >> s->cluster_bits;
+        if (k < 0 || k >= refcount_table_size) {
+            fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
+                cluster_offset);
+            errors++;
+        } else {
+            if (++refcount_table[k] == 0) {
+                fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
+                    "\n", cluster_offset);
+                errors++;
+            }
+        }
+    }
+
+    return errors;
+}
+
+/*
+ * Increases the refcount in the given refcount table for the all clusters
+ * referenced in the L2 table. While doing so, performs some checks on L2
+ * entries.
+ *
+ * Returns the number of errors found by the checks or -errno if an internal
+ * error occurred.
+ */
+static int check_refcounts_l2(BlockDriverState *bs,
+    uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset,
+    int check_copied)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l2_table, offset;
+    int i, l2_size, nb_csectors, refcount;
+    int errors = 0;
+
+    /* Read L2 table from disk */
+    l2_size = s->l2_size * sizeof(uint64_t);
+    l2_table = qemu_malloc(l2_size);
+
+    if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
+        goto fail;
+
+    /* Do the actual checks */
+    for(i = 0; i < s->l2_size; i++) {
+        offset = be64_to_cpu(l2_table[i]);
+        if (offset != 0) {
+            if (offset & QCOW_OFLAG_COMPRESSED) {
+                /* Compressed clusters don't have QCOW_OFLAG_COPIED */
+                if (offset & QCOW_OFLAG_COPIED) {
+                    fprintf(stderr, "ERROR: cluster %" PRId64 ": "
+                        "copied flag must never be set for compressed "
+                        "clusters\n", offset >> s->cluster_bits);
+                    offset &= ~QCOW_OFLAG_COPIED;
+                    errors++;
+                }
+
+                /* Mark cluster as used */
+                nb_csectors = ((offset >> s->csize_shift) &
+                               s->csize_mask) + 1;
+                offset &= s->cluster_offset_mask;
+                errors += inc_refcounts(bs, refcount_table,
+                              refcount_table_size,
+                              offset & ~511, nb_csectors * 512);
+            } else {
+                /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
+                if (check_copied) {
+                    uint64_t entry = offset;
+                    offset &= ~QCOW_OFLAG_COPIED;
+                    refcount = get_refcount(bs, offset >> s->cluster_bits);
+                    if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
+                        fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
+                            PRIx64 " refcount=%d\n", entry, refcount);
+                        errors++;
+                    }
+                }
+
+                /* Mark cluster as used */
+                offset &= ~QCOW_OFLAG_COPIED;
+                errors += inc_refcounts(bs, refcount_table,
+                              refcount_table_size,
+                              offset, s->cluster_size);
+
+                /* Correct offsets are cluster aligned */
+                if (offset & (s->cluster_size - 1)) {
+                    fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
+                        "properly aligned; L2 entry corrupted.\n", offset);
+                    errors++;
+                }
+            }
+        }
+    }
+
+    qemu_free(l2_table);
+    return errors;
+
+fail:
+    fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
+    qemu_free(l2_table);
+    return -EIO;
+}
+
+/*
+ * Increases the refcount for the L1 table, its L2 tables and all referenced
+ * clusters in the given refcount table. While doing so, performs some checks
+ * on L1 and L2 entries.
+ *
+ * Returns the number of errors found by the checks or -errno if an internal
+ * error occurred.
+ */
+static int check_refcounts_l1(BlockDriverState *bs,
+                              uint16_t *refcount_table,
+                              int refcount_table_size,
+                              int64_t l1_table_offset, int l1_size,
+                              int check_copied)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t *l1_table, l2_offset, l1_size2;
+    int i, refcount, ret;
+    int errors = 0;
+
+    l1_size2 = l1_size * sizeof(uint64_t);
+
+    /* Mark L1 table as used */
+    errors += inc_refcounts(bs, refcount_table, refcount_table_size,
+                  l1_table_offset, l1_size2);
+
+    /* Read L1 table entries from disk */
+    l1_table = qemu_malloc(l1_size2);
+    if (bdrv_pread(s->hd, l1_table_offset,
+                   l1_table, l1_size2) != l1_size2)
+        goto fail;
+    for(i = 0;i < l1_size; i++)
+        be64_to_cpus(&l1_table[i]);
+
+    /* Do the actual checks */
+    for(i = 0; i < l1_size; i++) {
+        l2_offset = l1_table[i];
+        if (l2_offset) {
+            /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
+            if (check_copied) {
+                refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
+                    >> s->cluster_bits);
+                if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
+                    fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
+                        " refcount=%d\n", l2_offset, refcount);
+                    errors++;
+                }
+            }
+
+            /* Mark L2 table as used */
+            l2_offset &= ~QCOW_OFLAG_COPIED;
+            errors += inc_refcounts(bs, refcount_table,
+                          refcount_table_size,
+                          l2_offset,
+                          s->cluster_size);
+
+            /* L2 tables are cluster aligned */
+            if (l2_offset & (s->cluster_size - 1)) {
+                fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
+                    "cluster aligned; L1 entry corrupted\n", l2_offset);
+                errors++;
+            }
+
+            /* Process and check L2 entries */
+            ret = check_refcounts_l2(bs, refcount_table, refcount_table_size,
+                l2_offset, check_copied);
+            if (ret < 0) {
+                goto fail;
+            }
+            errors += ret;
+        }
+    }
+    qemu_free(l1_table);
+    return errors;
+
+fail:
+    fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
+    qemu_free(l1_table);
+    return -EIO;
+}
+
+/*
+ * Checks an image for refcount consistency.
+ *
+ * Returns 0 if no errors are found, the number of errors in case the image is
+ * detected as corrupted, and -errno when an internal error occured.
+ */
+int qcow2_check_refcounts(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t size;
+    int nb_clusters, refcount1, refcount2, i;
+    QCowSnapshot *sn;
+    uint16_t *refcount_table;
+    int ret, errors = 0;
+
+    size = bdrv_getlength(s->hd);
+    nb_clusters = size_to_clusters(s, size);
+    refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
+
+    /* header */
+    errors += inc_refcounts(bs, refcount_table, nb_clusters,
+                  0, s->cluster_size);
+
+    /* current L1 table */
+    ret = check_refcounts_l1(bs, refcount_table, nb_clusters,
+                       s->l1_table_offset, s->l1_size, 1);
+    if (ret < 0) {
+        return ret;
+    }
+    errors += ret;
+
+    /* snapshots */
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        check_refcounts_l1(bs, refcount_table, nb_clusters,
+                           sn->l1_table_offset, sn->l1_size, 0);
+    }
+    errors += inc_refcounts(bs, refcount_table, nb_clusters,
+                  s->snapshots_offset, s->snapshots_size);
+
+    /* refcount data */
+    errors += inc_refcounts(bs, refcount_table, nb_clusters,
+                  s->refcount_table_offset,
+                  s->refcount_table_size * sizeof(uint64_t));
+    for(i = 0; i < s->refcount_table_size; i++) {
+        int64_t offset;
+        offset = s->refcount_table[i];
+        if (offset != 0) {
+            errors += inc_refcounts(bs, refcount_table, nb_clusters,
+                          offset, s->cluster_size);
+        }
+    }
+
+    /* compare ref counts */
+    for(i = 0; i < nb_clusters; i++) {
+        refcount1 = get_refcount(bs, i);
+        refcount2 = refcount_table[i];
+        if (refcount1 != refcount2) {
+            fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
+                   i, refcount1, refcount2);
+            errors++;
+        }
+    }
+
+    qemu_free(refcount_table);
+
+    return errors;
+}
+
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
new file mode 100644
index 0000000..e1e4d89
--- /dev/null
+++ b/block/qcow2-snapshot.c
@@ -0,0 +1,405 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "block/qcow2.h"
+
+typedef struct __attribute__((packed)) QCowSnapshotHeader {
+    /* header is 8 byte aligned */
+    uint64_t l1_table_offset;
+
+    uint32_t l1_size;
+    uint16_t id_str_size;
+    uint16_t name_size;
+
+    uint32_t date_sec;
+    uint32_t date_nsec;
+
+    uint64_t vm_clock_nsec;
+
+    uint32_t vm_state_size;
+    uint32_t extra_data_size; /* for extension */
+    /* extra data follows */
+    /* id_str follows */
+    /* name follows  */
+} QCowSnapshotHeader;
+
+void qcow2_free_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        qemu_free(s->snapshots[i].name);
+        qemu_free(s->snapshots[i].id_str);
+    }
+    qemu_free(s->snapshots);
+    s->snapshots = NULL;
+    s->nb_snapshots = 0;
+}
+
+int qcow2_read_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshotHeader h;
+    QCowSnapshot *sn;
+    int i, id_str_size, name_size;
+    int64_t offset;
+    uint32_t extra_data_size;
+
+    if (!s->nb_snapshots) {
+        s->snapshots = NULL;
+        s->snapshots_size = 0;
+        return 0;
+    }
+
+    offset = s->snapshots_offset;
+    s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot));
+    for(i = 0; i < s->nb_snapshots; i++) {
+        offset = align_offset(offset, 8);
+        if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h))
+            goto fail;
+        offset += sizeof(h);
+        sn = s->snapshots + i;
+        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
+        sn->l1_size = be32_to_cpu(h.l1_size);
+        sn->vm_state_size = be32_to_cpu(h.vm_state_size);
+        sn->date_sec = be32_to_cpu(h.date_sec);
+        sn->date_nsec = be32_to_cpu(h.date_nsec);
+        sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
+        extra_data_size = be32_to_cpu(h.extra_data_size);
+
+        id_str_size = be16_to_cpu(h.id_str_size);
+        name_size = be16_to_cpu(h.name_size);
+
+        offset += extra_data_size;
+
+        sn->id_str = qemu_malloc(id_str_size + 1);
+        if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
+            goto fail;
+        offset += id_str_size;
+        sn->id_str[id_str_size] = '\0';
+
+        sn->name = qemu_malloc(name_size + 1);
+        if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size)
+            goto fail;
+        offset += name_size;
+        sn->name[name_size] = '\0';
+    }
+    s->snapshots_size = offset - s->snapshots_offset;
+    return 0;
+ fail:
+    qcow2_free_snapshots(bs);
+    return -1;
+}
+
+/* add at the end of the file a new list of snapshots */
+static int qcow_write_snapshots(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    QCowSnapshotHeader h;
+    int i, name_size, id_str_size, snapshots_size;
+    uint64_t data64;
+    uint32_t data32;
+    int64_t offset, snapshots_offset;
+
+    /* compute the size of the snapshots */
+    offset = 0;
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        offset = align_offset(offset, 8);
+        offset += sizeof(h);
+        offset += strlen(sn->id_str);
+        offset += strlen(sn->name);
+    }
+    snapshots_size = offset;
+
+    snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
+    offset = snapshots_offset;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        memset(&h, 0, sizeof(h));
+        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
+        h.l1_size = cpu_to_be32(sn->l1_size);
+        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
+        h.date_sec = cpu_to_be32(sn->date_sec);
+        h.date_nsec = cpu_to_be32(sn->date_nsec);
+        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
+
+        id_str_size = strlen(sn->id_str);
+        name_size = strlen(sn->name);
+        h.id_str_size = cpu_to_be16(id_str_size);
+        h.name_size = cpu_to_be16(name_size);
+        offset = align_offset(offset, 8);
+        if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
+            goto fail;
+        offset += sizeof(h);
+        if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
+            goto fail;
+        offset += id_str_size;
+        if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
+            goto fail;
+        offset += name_size;
+    }
+
+    /* update the various header fields */
+    data64 = cpu_to_be64(snapshots_offset);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
+                    &data64, sizeof(data64)) != sizeof(data64))
+        goto fail;
+    data32 = cpu_to_be32(s->nb_snapshots);
+    if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
+                    &data32, sizeof(data32)) != sizeof(data32))
+        goto fail;
+
+    /* free the old snapshot table */
+    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
+    s->snapshots_offset = snapshots_offset;
+    s->snapshots_size = snapshots_size;
+    return 0;
+ fail:
+    return -1;
+}
+
+static void find_new_snapshot_id(BlockDriverState *bs,
+                                 char *id_str, int id_str_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int i, id, id_max = 0;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn = s->snapshots + i;
+        id = strtoul(sn->id_str, NULL, 10);
+        if (id > id_max)
+            id_max = id;
+    }
+    snprintf(id_str, id_str_size, "%d", id_max + 1);
+}
+
+static int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i;
+
+    for(i = 0; i < s->nb_snapshots; i++) {
+        if (!strcmp(s->snapshots[i].id_str, id_str))
+            return i;
+    }
+    return -1;
+}
+
+static int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i, ret;
+
+    ret = find_snapshot_by_id(bs, name);
+    if (ret >= 0)
+        return ret;
+    for(i = 0; i < s->nb_snapshots; i++) {
+        if (!strcmp(s->snapshots[i].name, name))
+            return i;
+    }
+    return -1;
+}
+
+/* if no id is provided, a new one is constructed */
+int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
+    int i, ret;
+    uint64_t *l1_table = NULL;
+
+    memset(sn, 0, sizeof(*sn));
+
+    if (sn_info->id_str[0] == '\0') {
+        /* compute a new id */
+        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
+    }
+
+    /* check that the ID is unique */
+    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
+        return -ENOENT;
+
+    sn->id_str = qemu_strdup(sn_info->id_str);
+    if (!sn->id_str)
+        goto fail;
+    sn->name = qemu_strdup(sn_info->name);
+    if (!sn->name)
+        goto fail;
+    sn->vm_state_size = sn_info->vm_state_size;
+    sn->date_sec = sn_info->date_sec;
+    sn->date_nsec = sn_info->date_nsec;
+    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
+
+    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
+    if (ret < 0)
+        goto fail;
+
+    /* create the L1 table of the snapshot */
+    sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
+    sn->l1_size = s->l1_size;
+
+    l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+    for(i = 0; i < s->l1_size; i++) {
+        l1_table[i] = cpu_to_be64(s->l1_table[i]);
+    }
+    if (bdrv_pwrite(s->hd, sn->l1_table_offset,
+                    l1_table, s->l1_size * sizeof(uint64_t)) !=
+        (s->l1_size * sizeof(uint64_t)))
+        goto fail;
+    qemu_free(l1_table);
+    l1_table = NULL;
+
+    snapshots1 = qemu_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
+    if (s->snapshots) {
+        memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
+        qemu_free(s->snapshots);
+    }
+    s->snapshots = snapshots1;
+    s->snapshots[s->nb_snapshots++] = *sn;
+
+    if (qcow_write_snapshots(bs) < 0)
+        goto fail;
+#ifdef DEBUG_ALLOC
+    check_refcounts(bs);
+#endif
+    return 0;
+ fail:
+    qemu_free(sn->name);
+    qemu_free(l1_table);
+    return -1;
+}
+
+/* copy the snapshot 'snapshot_name' into the current disk image */
+int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int i, snapshot_index, l1_size2;
+
+    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
+    if (snapshot_index < 0)
+        return -ENOENT;
+    sn = &s->snapshots[snapshot_index];
+
+    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
+        goto fail;
+
+    if (qcow2_grow_l1_table(bs, sn->l1_size) < 0)
+        goto fail;
+
+    s->l1_size = sn->l1_size;
+    l1_size2 = s->l1_size * sizeof(uint64_t);
+    /* copy the snapshot l1 table to the current l1 table */
+    if (bdrv_pread(s->hd, sn->l1_table_offset,
+                   s->l1_table, l1_size2) != l1_size2)
+        goto fail;
+    if (bdrv_pwrite(s->hd, s->l1_table_offset,
+                    s->l1_table, l1_size2) != l1_size2)
+        goto fail;
+    for(i = 0;i < s->l1_size; i++) {
+        be64_to_cpus(&s->l1_table[i]);
+    }
+
+    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
+        goto fail;
+
+#ifdef DEBUG_ALLOC
+    check_refcounts(bs);
+#endif
+    return 0;
+ fail:
+    return -EIO;
+}
+
+int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowSnapshot *sn;
+    int snapshot_index, ret;
+
+    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
+    if (snapshot_index < 0)
+        return -ENOENT;
+    sn = &s->snapshots[snapshot_index];
+
+    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
+    if (ret < 0)
+        return ret;
+    /* must update the copied flag on the current cluster offsets */
+    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
+    if (ret < 0)
+        return ret;
+    qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
+
+    qemu_free(sn->id_str);
+    qemu_free(sn->name);
+    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
+    s->nb_snapshots--;
+    ret = qcow_write_snapshots(bs);
+    if (ret < 0) {
+        /* XXX: restore snapshot if error ? */
+        return ret;
+    }
+#ifdef DEBUG_ALLOC
+    check_refcounts(bs);
+#endif
+    return 0;
+}
+
+int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+{
+    BDRVQcowState *s = bs->opaque;
+    QEMUSnapshotInfo *sn_tab, *sn_info;
+    QCowSnapshot *sn;
+    int i;
+
+    if (!s->nb_snapshots) {
+        *psn_tab = NULL;
+        return s->nb_snapshots;
+    }
+
+    sn_tab = qemu_mallocz(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
+    for(i = 0; i < s->nb_snapshots; i++) {
+        sn_info = sn_tab + i;
+        sn = s->snapshots + i;
+        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
+                sn->id_str);
+        pstrcpy(sn_info->name, sizeof(sn_info->name),
+                sn->name);
+        sn_info->vm_state_size = sn->vm_state_size;
+        sn_info->date_sec = sn->date_sec;
+        sn_info->date_nsec = sn->date_nsec;
+        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
+    }
+    *psn_tab = sn_tab;
+    return s->nb_snapshots;
+}
+
diff --git a/block/qcow2.c b/block/qcow2.c
new file mode 100644
index 0000000..9acbddf
--- /dev/null
+++ b/block/qcow2.c
@@ -0,0 +1,1027 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+#include <zlib.h>
+#include "aes.h"
+#include "block/qcow2.h"
+
+/*
+  Differences with QCOW:
+
+  - Support for multiple incremental snapshots.
+  - Memory management by reference counts.
+  - Clusters which have a reference count of one have the bit
+    QCOW_OFLAG_COPIED to optimize write performance.
+  - Size of compressed clusters is stored in sectors to reduce bit usage
+    in the cluster offsets.
+  - Support for storing additional data (such as the VM state) in the
+    snapshots.
+  - If a backing store is used, the cluster size is not constrained
+    (could be backported to QCOW).
+  - L2 tables have always a size of one cluster.
+*/
+
+//#define DEBUG_ALLOC
+//#define DEBUG_ALLOC2
+//#define DEBUG_EXT
+
+
+typedef struct {
+    uint32_t magic;
+    uint32_t len;
+} QCowExtension;
+#define  QCOW_EXT_MAGIC_END 0
+#define  QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
+
+
+
+static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const QCowHeader *cow_header = (const void *)buf;
+
+    if (buf_size >= sizeof(QCowHeader) &&
+        be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
+        be32_to_cpu(cow_header->version) == QCOW_VERSION)
+        return 100;
+    else
+        return 0;
+}
+
+
+/* 
+ * read qcow2 extension and fill bs
+ * start reading from start_offset
+ * finish reading upon magic of value 0 or when end_offset reached
+ * unknown magic is skipped (future extension this version knows nothing about)
+ * return 0 upon success, non-0 otherwise
+ */
+static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
+                                uint64_t end_offset)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowExtension ext;
+    uint64_t offset;
+
+#ifdef DEBUG_EXT
+    printf("qcow_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
+#endif
+    offset = start_offset;
+    while (offset < end_offset) {
+
+#ifdef DEBUG_EXT
+        /* Sanity check */
+        if (offset > s->cluster_size)
+            printf("qcow_handle_extension: suspicious offset %lu\n", offset);
+
+        printf("attemting to read extended header in offset %lu\n", offset);
+#endif
+
+        if (bdrv_pread(s->hd, offset, &ext, sizeof(ext)) != sizeof(ext)) {
+            fprintf(stderr, "qcow_handle_extension: ERROR: pread fail from offset %llu\n",
+                    (unsigned long long)offset);
+            return 1;
+        }
+        be32_to_cpus(&ext.magic);
+        be32_to_cpus(&ext.len);
+        offset += sizeof(ext);
+#ifdef DEBUG_EXT
+        printf("ext.magic = 0x%x\n", ext.magic);
+#endif
+        switch (ext.magic) {
+        case QCOW_EXT_MAGIC_END:
+            return 0;
+
+        case QCOW_EXT_MAGIC_BACKING_FORMAT:
+            if (ext.len >= sizeof(bs->backing_format)) {
+                fprintf(stderr, "ERROR: ext_backing_format: len=%u too large"
+                        " (>=%zu)\n",
+                        ext.len, sizeof(bs->backing_format));
+                return 2;
+            }
+            if (bdrv_pread(s->hd, offset , bs->backing_format,
+                           ext.len) != ext.len)
+                return 3;
+            bs->backing_format[ext.len] = '\0';
+#ifdef DEBUG_EXT
+            printf("Qcow2: Got format extension %s\n", bs->backing_format);
+#endif
+            offset += ((ext.len + 7) & ~7);
+            break;
+
+        default:
+            /* unknown magic -- just skip it */
+            offset += ((ext.len + 7) & ~7);
+            break;
+        }
+    }
+
+    return 0;
+}
+
+
+static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVQcowState *s = bs->opaque;
+    int len, i, shift, ret;
+    QCowHeader header;
+    uint64_t ext_end;
+
+    /* Performance is terrible right now with cache=writethrough due mainly
+     * to reference count updates.  If the user does not explicitly specify
+     * a caching type, force to writeback caching.
+     */
+    if ((flags & BDRV_O_CACHE_DEF)) {
+        flags |= BDRV_O_CACHE_WB;
+        flags &= ~BDRV_O_CACHE_DEF;
+    }
+    ret = bdrv_file_open(&s->hd, filename, flags);
+    if (ret < 0)
+        return ret;
+    if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header))
+        goto fail;
+    be32_to_cpus(&header.magic);
+    be32_to_cpus(&header.version);
+    be64_to_cpus(&header.backing_file_offset);
+    be32_to_cpus(&header.backing_file_size);
+    be64_to_cpus(&header.size);
+    be32_to_cpus(&header.cluster_bits);
+    be32_to_cpus(&header.crypt_method);
+    be64_to_cpus(&header.l1_table_offset);
+    be32_to_cpus(&header.l1_size);
+    be64_to_cpus(&header.refcount_table_offset);
+    be32_to_cpus(&header.refcount_table_clusters);
+    be64_to_cpus(&header.snapshots_offset);
+    be32_to_cpus(&header.nb_snapshots);
+
+    if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
+        goto fail;
+    if (header.size <= 1 ||
+        header.cluster_bits < MIN_CLUSTER_BITS ||
+        header.cluster_bits > MAX_CLUSTER_BITS)
+        goto fail;
+    if (header.crypt_method > QCOW_CRYPT_AES)
+        goto fail;
+    s->crypt_method_header = header.crypt_method;
+    if (s->crypt_method_header)
+        bs->encrypted = 1;
+    s->cluster_bits = header.cluster_bits;
+    s->cluster_size = 1 << s->cluster_bits;
+    s->cluster_sectors = 1 << (s->cluster_bits - 9);
+    s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
+    s->l2_size = 1 << s->l2_bits;
+    bs->total_sectors = header.size / 512;
+    s->csize_shift = (62 - (s->cluster_bits - 8));
+    s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
+    s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
+    s->refcount_table_offset = header.refcount_table_offset;
+    s->refcount_table_size =
+        header.refcount_table_clusters << (s->cluster_bits - 3);
+
+    s->snapshots_offset = header.snapshots_offset;
+    s->nb_snapshots = header.nb_snapshots;
+
+    /* read the level 1 table */
+    s->l1_size = header.l1_size;
+    shift = s->cluster_bits + s->l2_bits;
+    s->l1_vm_state_index = (header.size + (1LL << shift) - 1) >> shift;
+    /* the L1 table must contain at least enough entries to put
+       header.size bytes */
+    if (s->l1_size < s->l1_vm_state_index)
+        goto fail;
+    s->l1_table_offset = header.l1_table_offset;
+    s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
+    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
+        s->l1_size * sizeof(uint64_t))
+        goto fail;
+    for(i = 0;i < s->l1_size; i++) {
+        be64_to_cpus(&s->l1_table[i]);
+    }
+    /* alloc L2 cache */
+    s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+    s->cluster_cache = qemu_malloc(s->cluster_size);
+    /* one more sector for decompressed data alignment */
+    s->cluster_data = qemu_malloc(QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
+                                  + 512);
+    s->cluster_cache_offset = -1;
+
+    if (qcow2_refcount_init(bs) < 0)
+        goto fail;
+
+    /* read qcow2 extensions */
+    if (header.backing_file_offset)
+        ext_end = header.backing_file_offset;
+    else
+        ext_end = s->cluster_size;
+    if (qcow_read_extensions(bs, sizeof(header), ext_end))
+        goto fail;
+
+    /* read the backing file name */
+    if (header.backing_file_offset != 0) {
+        len = header.backing_file_size;
+        if (len > 1023)
+            len = 1023;
+        if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len)
+            goto fail;
+        bs->backing_file[len] = '\0';
+    }
+    if (qcow2_read_snapshots(bs) < 0)
+        goto fail;
+
+#ifdef DEBUG_ALLOC
+    check_refcounts(bs);
+#endif
+    return 0;
+
+ fail:
+    qcow2_free_snapshots(bs);
+    qcow2_refcount_close(bs);
+    qemu_free(s->l1_table);
+    qemu_free(s->l2_cache);
+    qemu_free(s->cluster_cache);
+    qemu_free(s->cluster_data);
+    bdrv_delete(s->hd);
+    return -1;
+}
+
+static int qcow_set_key(BlockDriverState *bs, const char *key)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint8_t keybuf[16];
+    int len, i;
+
+    memset(keybuf, 0, 16);
+    len = strlen(key);
+    if (len > 16)
+        len = 16;
+    /* XXX: we could compress the chars to 7 bits to increase
+       entropy */
+    for(i = 0;i < len;i++) {
+        keybuf[i] = key[i];
+    }
+    s->crypt_method = s->crypt_method_header;
+
+    if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
+        return -1;
+    if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
+        return -1;
+#if 0
+    /* test */
+    {
+        uint8_t in[16];
+        uint8_t out[16];
+        uint8_t tmp[16];
+        for(i=0;i<16;i++)
+            in[i] = i;
+        AES_encrypt(in, tmp, &s->aes_encrypt_key);
+        AES_decrypt(tmp, out, &s->aes_decrypt_key);
+        for(i = 0; i < 16; i++)
+            printf(" %02x", tmp[i]);
+        printf("\n");
+        for(i = 0; i < 16; i++)
+            printf(" %02x", out[i]);
+        printf("\n");
+    }
+#endif
+    return 0;
+}
+
+static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
+                             int nb_sectors, int *pnum)
+{
+    uint64_t cluster_offset;
+
+    *pnum = nb_sectors;
+    cluster_offset = qcow2_get_cluster_offset(bs, sector_num << 9, pnum);
+
+    return (cluster_offset != 0);
+}
+
+/* handle reading after the end of the backing file */
+int qcow2_backing_read1(BlockDriverState *bs,
+                  int64_t sector_num, uint8_t *buf, int nb_sectors)
+{
+    int n1;
+    if ((sector_num + nb_sectors) <= bs->total_sectors)
+        return nb_sectors;
+    if (sector_num >= bs->total_sectors)
+        n1 = 0;
+    else
+        n1 = bs->total_sectors - sector_num;
+    memset(buf + n1 * 512, 0, 512 * (nb_sectors - n1));
+    return n1;
+}
+
+typedef struct QCowAIOCB {
+    BlockDriverAIOCB common;
+    int64_t sector_num;
+    QEMUIOVector *qiov;
+    uint8_t *buf;
+    void *orig_buf;
+    int nb_sectors;
+    int n;
+    uint64_t cluster_offset;
+    uint8_t *cluster_data;
+    BlockDriverAIOCB *hd_aiocb;
+    struct iovec hd_iov;
+    QEMUIOVector hd_qiov;
+    QEMUBH *bh;
+    QCowL2Meta l2meta;
+} QCowAIOCB;
+
+static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    QCowAIOCB *acb = (QCowAIOCB *)blockacb;
+    if (acb->hd_aiocb)
+        bdrv_aio_cancel(acb->hd_aiocb);
+    qemu_aio_release(acb);
+}
+
+static AIOPool qcow_aio_pool = {
+    .aiocb_size         = sizeof(QCowAIOCB),
+    .cancel             = qcow_aio_cancel,
+};
+
+static void qcow_aio_read_cb(void *opaque, int ret);
+static void qcow_aio_read_bh(void *opaque)
+{
+    QCowAIOCB *acb = opaque;
+    qemu_bh_delete(acb->bh);
+    acb->bh = NULL;
+    qcow_aio_read_cb(opaque, 0);
+}
+
+static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
+{
+    if (acb->bh)
+        return -EIO;
+
+    acb->bh = qemu_bh_new(cb, acb);
+    if (!acb->bh)
+        return -EIO;
+
+    qemu_bh_schedule(acb->bh);
+
+    return 0;
+}
+
+static void qcow_aio_read_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster, n1;
+
+    acb->hd_aiocb = NULL;
+    if (ret < 0)
+        goto done;
+
+    /* post process the read buffer */
+    if (!acb->cluster_offset) {
+        /* nothing to do */
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* nothing to do */
+    } else {
+        if (s->crypt_method) {
+            qcow2_encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
+                            acb->n, 0,
+                            &s->aes_decrypt_key);
+        }
+    }
+
+    acb->nb_sectors -= acb->n;
+    acb->sector_num += acb->n;
+    acb->buf += acb->n * 512;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        ret = 0;
+        goto done;
+    }
+
+    /* prepare next AIO request */
+    acb->n = acb->nb_sectors;
+    acb->cluster_offset =
+        qcow2_get_cluster_offset(bs, acb->sector_num << 9, &acb->n);
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+
+    if (!acb->cluster_offset) {
+        if (bs->backing_hd) {
+            /* read from the base image */
+            n1 = qcow2_backing_read1(bs->backing_hd, acb->sector_num,
+                               acb->buf, acb->n);
+            if (n1 > 0) {
+                acb->hd_iov.iov_base = (void *)acb->buf;
+                acb->hd_iov.iov_len = acb->n * 512;
+                qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+                acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
+                                    &acb->hd_qiov, acb->n,
+				    qcow_aio_read_cb, acb);
+                if (acb->hd_aiocb == NULL)
+                    goto done;
+            } else {
+                ret = qcow_schedule_bh(qcow_aio_read_bh, acb);
+                if (ret < 0)
+                    goto done;
+            }
+        } else {
+            /* Note: in this case, no need to wait */
+            memset(acb->buf, 0, 512 * acb->n);
+            ret = qcow_schedule_bh(qcow_aio_read_bh, acb);
+            if (ret < 0)
+                goto done;
+        }
+    } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
+        /* add AIO support for compressed blocks ? */
+        if (qcow2_decompress_cluster(s, acb->cluster_offset) < 0)
+            goto done;
+        memcpy(acb->buf,
+               s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
+        ret = qcow_schedule_bh(qcow_aio_read_bh, acb);
+        if (ret < 0)
+            goto done;
+    } else {
+        if ((acb->cluster_offset & 511) != 0) {
+            ret = -EIO;
+            goto done;
+        }
+
+        acb->hd_iov.iov_base = (void *)acb->buf;
+        acb->hd_iov.iov_len = acb->n * 512;
+        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+        acb->hd_aiocb = bdrv_aio_readv(s->hd,
+                            (acb->cluster_offset >> 9) + index_in_cluster,
+                            &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
+        if (acb->hd_aiocb == NULL)
+            goto done;
+    }
+
+    return;
+done:
+    if (acb->qiov->niov > 1) {
+        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
+        qemu_vfree(acb->orig_buf);
+    }
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_aio_release(acb);
+}
+
+static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
+{
+    QCowAIOCB *acb;
+
+    acb = qemu_aio_get(&qcow_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->hd_aiocb = NULL;
+    acb->sector_num = sector_num;
+    acb->qiov = qiov;
+    if (qiov->niov > 1) {
+        acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
+        if (is_write)
+            qemu_iovec_to_buffer(qiov, acb->buf);
+    } else {
+        acb->buf = (uint8_t *)qiov->iov->iov_base;
+    }
+    acb->nb_sectors = nb_sectors;
+    acb->n = 0;
+    acb->cluster_offset = 0;
+    acb->l2meta.nb_clusters = 0;
+    return acb;
+}
+
+static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    QCowAIOCB *acb;
+
+    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
+    if (!acb)
+        return NULL;
+
+    qcow_aio_read_cb(acb, 0);
+    return &acb->common;
+}
+
+static void qcow_aio_write_cb(void *opaque, int ret)
+{
+    QCowAIOCB *acb = opaque;
+    BlockDriverState *bs = acb->common.bs;
+    BDRVQcowState *s = bs->opaque;
+    int index_in_cluster;
+    const uint8_t *src_buf;
+    int n_end;
+
+    acb->hd_aiocb = NULL;
+
+    if (ret < 0)
+        goto done;
+
+    if (qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta) < 0) {
+        qcow2_free_any_clusters(bs, acb->cluster_offset, acb->l2meta.nb_clusters);
+        goto done;
+    }
+
+    acb->nb_sectors -= acb->n;
+    acb->sector_num += acb->n;
+    acb->buf += acb->n * 512;
+
+    if (acb->nb_sectors == 0) {
+        /* request completed */
+        ret = 0;
+        goto done;
+    }
+
+    index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
+    n_end = index_in_cluster + acb->nb_sectors;
+    if (s->crypt_method &&
+        n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
+        n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
+
+    acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
+                                          index_in_cluster,
+                                          n_end, &acb->n, &acb->l2meta);
+    if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) {
+        ret = -EIO;
+        goto done;
+    }
+    if (s->crypt_method) {
+        if (!acb->cluster_data) {
+            acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
+                                             s->cluster_size);
+        }
+        qcow2_encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
+                        acb->n, 1, &s->aes_encrypt_key);
+        src_buf = acb->cluster_data;
+    } else {
+        src_buf = acb->buf;
+    }
+    acb->hd_iov.iov_base = (void *)src_buf;
+    acb->hd_iov.iov_len = acb->n * 512;
+    qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
+    acb->hd_aiocb = bdrv_aio_writev(s->hd,
+                                    (acb->cluster_offset >> 9) + index_in_cluster,
+                                    &acb->hd_qiov, acb->n,
+                                    qcow_aio_write_cb, acb);
+    if (acb->hd_aiocb == NULL)
+        goto done;
+
+    return;
+
+done:
+    if (acb->qiov->niov > 1)
+        qemu_vfree(acb->orig_buf);
+    acb->common.cb(acb->common.opaque, ret);
+    qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVQcowState *s = bs->opaque;
+    QCowAIOCB *acb;
+
+    s->cluster_cache_offset = -1; /* disable compressed cache */
+
+    acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
+    if (!acb)
+        return NULL;
+
+    qcow_aio_write_cb(acb, 0);
+    return &acb->common;
+}
+
+static void qcow_close(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    qemu_free(s->l1_table);
+    qemu_free(s->l2_cache);
+    qemu_free(s->cluster_cache);
+    qemu_free(s->cluster_data);
+    qcow2_refcount_close(bs);
+    bdrv_delete(s->hd);
+}
+
+static int get_bits_from_size(size_t size)
+{
+    int res = 0;
+
+    if (size == 0) {
+        return -1;
+    }
+
+    while (size != 1) {
+        /* Not a power of two */
+        if (size & 1) {
+            return -1;
+        }
+
+        size >>= 1;
+        res++;
+    }
+
+    return res;
+}
+
+static int qcow_create2(const char *filename, int64_t total_size,
+                        const char *backing_file, const char *backing_format,
+                        int flags, size_t cluster_size)
+{
+
+    int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
+    int ref_clusters, backing_format_len = 0;
+    QCowHeader header;
+    uint64_t tmp, offset;
+    QCowCreateState s1, *s = &s1;
+    QCowExtension ext_bf = {0, 0};
+
+
+    memset(s, 0, sizeof(*s));
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0)
+        return -1;
+    memset(&header, 0, sizeof(header));
+    header.magic = cpu_to_be32(QCOW_MAGIC);
+    header.version = cpu_to_be32(QCOW_VERSION);
+    header.size = cpu_to_be64(total_size * 512);
+    header_size = sizeof(header);
+    backing_filename_len = 0;
+    if (backing_file) {
+        if (backing_format) {
+            ext_bf.magic = QCOW_EXT_MAGIC_BACKING_FORMAT;
+            backing_format_len = strlen(backing_format);
+            ext_bf.len = (backing_format_len + 7) & ~7;
+            header_size += ((sizeof(ext_bf) + ext_bf.len + 7) & ~7);
+        }
+        header.backing_file_offset = cpu_to_be64(header_size);
+        backing_filename_len = strlen(backing_file);
+        header.backing_file_size = cpu_to_be32(backing_filename_len);
+        header_size += backing_filename_len;
+    }
+
+    /* Cluster size */
+    s->cluster_bits = get_bits_from_size(cluster_size);
+    if (s->cluster_bits < MIN_CLUSTER_BITS ||
+        s->cluster_bits > MAX_CLUSTER_BITS)
+    {
+        fprintf(stderr, "Cluster size must be a power of two between "
+            "%d and %dk\n",
+            1 << MIN_CLUSTER_BITS,
+            1 << (MAX_CLUSTER_BITS - 10));
+        return -EINVAL;
+    }
+    s->cluster_size = 1 << s->cluster_bits;
+
+    header.cluster_bits = cpu_to_be32(s->cluster_bits);
+    header_size = (header_size + 7) & ~7;
+    if (flags & BLOCK_FLAG_ENCRYPT) {
+        header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
+    } else {
+        header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
+    }
+    l2_bits = s->cluster_bits - 3;
+    shift = s->cluster_bits + l2_bits;
+    l1_size = (((total_size * 512) + (1LL << shift) - 1) >> shift);
+    offset = align_offset(header_size, s->cluster_size);
+    s->l1_table_offset = offset;
+    header.l1_table_offset = cpu_to_be64(s->l1_table_offset);
+    header.l1_size = cpu_to_be32(l1_size);
+    offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
+
+    s->refcount_table = qemu_mallocz(s->cluster_size);
+
+    s->refcount_table_offset = offset;
+    header.refcount_table_offset = cpu_to_be64(offset);
+    header.refcount_table_clusters = cpu_to_be32(1);
+    offset += s->cluster_size;
+    s->refcount_block_offset = offset;
+
+    /* count how many refcount blocks needed */
+    tmp = offset >> s->cluster_bits;
+    ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1;
+    for (i=0; i < ref_clusters; i++) {
+        s->refcount_table[i] = cpu_to_be64(offset);
+        offset += s->cluster_size;
+    }
+
+    s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size);
+
+    /* update refcounts */
+    qcow2_create_refcount_update(s, 0, header_size);
+    qcow2_create_refcount_update(s, s->l1_table_offset,
+        l1_size * sizeof(uint64_t));
+    qcow2_create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
+    qcow2_create_refcount_update(s, s->refcount_block_offset,
+        ref_clusters * s->cluster_size);
+
+    /* write all the data */
+    write(fd, &header, sizeof(header));
+    if (backing_file) {
+        if (backing_format_len) {
+            char zero[16];
+            int d = ext_bf.len - backing_format_len;
+
+            memset(zero, 0, sizeof(zero));
+            cpu_to_be32s(&ext_bf.magic);
+            cpu_to_be32s(&ext_bf.len);
+            write(fd, &ext_bf, sizeof(ext_bf));
+            write(fd, backing_format, backing_format_len);
+            if (d>0) {
+                write(fd, zero, d);
+            }
+        }
+        write(fd, backing_file, backing_filename_len);
+    }
+    lseek(fd, s->l1_table_offset, SEEK_SET);
+    tmp = 0;
+    for(i = 0;i < l1_size; i++) {
+        write(fd, &tmp, sizeof(tmp));
+    }
+    lseek(fd, s->refcount_table_offset, SEEK_SET);
+    write(fd, s->refcount_table, s->cluster_size);
+
+    lseek(fd, s->refcount_block_offset, SEEK_SET);
+    write(fd, s->refcount_block, ref_clusters * s->cluster_size);
+
+    qemu_free(s->refcount_table);
+    qemu_free(s->refcount_block);
+    close(fd);
+    return 0;
+}
+
+static int qcow_create(const char *filename, QEMUOptionParameter *options)
+{
+    const char *backing_file = NULL;
+    const char *backing_fmt = NULL;
+    uint64_t sectors = 0;
+    int flags = 0;
+    size_t cluster_size = 65536;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            sectors = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
+            backing_fmt = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
+            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
+        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
+            if (options->value.n) {
+                cluster_size = options->value.n;
+            }
+        }
+        options++;
+    }
+
+    return qcow_create2(filename, sectors, backing_file, backing_fmt, flags,
+        cluster_size);
+}
+
+static int qcow_make_empty(BlockDriverState *bs)
+{
+#if 0
+    /* XXX: not correct */
+    BDRVQcowState *s = bs->opaque;
+    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+    int ret;
+
+    memset(s->l1_table, 0, l1_length);
+    if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
+        return -1;
+    ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
+    if (ret < 0)
+        return ret;
+
+    l2_cache_reset(bs);
+#endif
+    return 0;
+}
+
+/* XXX: put compressed sectors first, then all the cluster aligned
+   tables to avoid losing bytes in alignment */
+static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
+                                 const uint8_t *buf, int nb_sectors)
+{
+    BDRVQcowState *s = bs->opaque;
+    z_stream strm;
+    int ret, out_len;
+    uint8_t *out_buf;
+    uint64_t cluster_offset;
+
+    if (nb_sectors == 0) {
+        /* align end of file to a sector boundary to ease reading with
+           sector based I/Os */
+        cluster_offset = bdrv_getlength(s->hd);
+        cluster_offset = (cluster_offset + 511) & ~511;
+        bdrv_truncate(s->hd, cluster_offset);
+        return 0;
+    }
+
+    if (nb_sectors != s->cluster_sectors)
+        return -EINVAL;
+
+    out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
+
+    /* best compression, small window, no zlib header */
+    memset(&strm, 0, sizeof(strm));
+    ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
+                       Z_DEFLATED, -12,
+                       9, Z_DEFAULT_STRATEGY);
+    if (ret != 0) {
+        qemu_free(out_buf);
+        return -1;
+    }
+
+    strm.avail_in = s->cluster_size;
+    strm.next_in = (uint8_t *)buf;
+    strm.avail_out = s->cluster_size;
+    strm.next_out = out_buf;
+
+    ret = deflate(&strm, Z_FINISH);
+    if (ret != Z_STREAM_END && ret != Z_OK) {
+        qemu_free(out_buf);
+        deflateEnd(&strm);
+        return -1;
+    }
+    out_len = strm.next_out - out_buf;
+
+    deflateEnd(&strm);
+
+    if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
+        /* could not compress: write normal cluster */
+        bdrv_write(bs, sector_num, buf, s->cluster_sectors);
+    } else {
+        cluster_offset = qcow2_alloc_compressed_cluster_offset(bs,
+            sector_num << 9, out_len);
+        if (!cluster_offset)
+            return -1;
+        cluster_offset &= s->cluster_offset_mask;
+        if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
+            qemu_free(out_buf);
+            return -1;
+        }
+    }
+
+    qemu_free(out_buf);
+    return 0;
+}
+
+static void qcow_flush(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    bdrv_flush(s->hd);
+}
+
+static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVQcowState *s = bs->opaque;
+    bdi->cluster_size = s->cluster_size;
+    bdi->vm_state_offset = (int64_t)s->l1_vm_state_index <<
+        (s->cluster_bits + s->l2_bits);
+    return 0;
+}
+
+
+static int qcow_check(BlockDriverState *bs)
+{
+    return qcow2_check_refcounts(bs);
+}
+
+#if 0
+static void dump_refcounts(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t nb_clusters, k, k1, size;
+    int refcount;
+
+    size = bdrv_getlength(s->hd);
+    nb_clusters = size_to_clusters(s, size);
+    for(k = 0; k < nb_clusters;) {
+        k1 = k;
+        refcount = get_refcount(bs, k);
+        k++;
+        while (k < nb_clusters && get_refcount(bs, k) == refcount)
+            k++;
+        printf("%lld: refcount=%d nb=%lld\n", k, refcount, k - k1);
+    }
+}
+#endif
+
+static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf,
+                           int64_t pos, int size)
+{
+    int growable = bs->growable;
+
+    bs->growable = 1;
+    bdrv_pwrite(bs, pos, buf, size);
+    bs->growable = growable;
+
+    return size;
+}
+
+static int qcow_get_buffer(BlockDriverState *bs, uint8_t *buf,
+                           int64_t pos, int size)
+{
+    int growable = bs->growable;
+    int ret;
+
+    bs->growable = 1;
+    ret = bdrv_pread(bs, pos, buf, size);
+    bs->growable = growable;
+
+    return ret;
+}
+
+static QEMUOptionParameter qcow_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FMT,
+        .type = OPT_STRING,
+        .help = "Image format of the base image"
+    },
+    {
+        .name = BLOCK_OPT_ENCRYPT,
+        .type = OPT_FLAG,
+        .help = "Encrypt the image"
+    },
+    {
+        .name = BLOCK_OPT_CLUSTER_SIZE,
+        .type = OPT_SIZE,
+        .help = "qcow2 cluster size"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_qcow2 = {
+    .format_name	= "qcow2",
+    .instance_size	= sizeof(BDRVQcowState),
+    .bdrv_probe		= qcow_probe,
+    .bdrv_open		= qcow_open,
+    .bdrv_close		= qcow_close,
+    .bdrv_create	= qcow_create,
+    .bdrv_flush		= qcow_flush,
+    .bdrv_is_allocated	= qcow_is_allocated,
+    .bdrv_set_key	= qcow_set_key,
+    .bdrv_make_empty	= qcow_make_empty,
+
+    .bdrv_aio_readv	= qcow_aio_readv,
+    .bdrv_aio_writev	= qcow_aio_writev,
+    .bdrv_write_compressed = qcow_write_compressed,
+
+    .bdrv_snapshot_create   = qcow2_snapshot_create,
+    .bdrv_snapshot_goto     = qcow2_snapshot_goto,
+    .bdrv_snapshot_delete   = qcow2_snapshot_delete,
+    .bdrv_snapshot_list     = qcow2_snapshot_list,
+    .bdrv_get_info	= qcow_get_info,
+
+    .bdrv_put_buffer    = qcow_put_buffer,
+    .bdrv_get_buffer    = qcow_get_buffer,
+
+    .create_options = qcow_create_options,
+    .bdrv_check = qcow_check,
+};
+
+static void bdrv_qcow2_init(void)
+{
+    bdrv_register(&bdrv_qcow2);
+}
+
+block_init(bdrv_qcow2_init);
diff --git a/block/qcow2.h b/block/qcow2.h
new file mode 100644
index 0000000..d734003
--- /dev/null
+++ b/block/qcow2.h
@@ -0,0 +1,203 @@
+/*
+ * Block driver for the QCOW version 2 format
+ *
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef BLOCK_QCOW2_H
+#define BLOCK_QCOW2_H
+
+#include "aes.h"
+
+#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+#define QCOW_VERSION 2
+
+#define QCOW_CRYPT_NONE 0
+#define QCOW_CRYPT_AES  1
+
+#define QCOW_MAX_CRYPT_CLUSTERS 32
+
+/* indicate that the refcount of the referenced cluster is exactly one. */
+#define QCOW_OFLAG_COPIED     (1LL << 63)
+/* indicate that the cluster is compressed (they never have the copied flag) */
+#define QCOW_OFLAG_COMPRESSED (1LL << 62)
+
+#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
+
+#define MIN_CLUSTER_BITS 9
+#define MAX_CLUSTER_BITS 16
+
+#define L2_CACHE_SIZE 16
+
+typedef struct QCowHeader {
+    uint32_t magic;
+    uint32_t version;
+    uint64_t backing_file_offset;
+    uint32_t backing_file_size;
+    uint32_t cluster_bits;
+    uint64_t size; /* in bytes */
+    uint32_t crypt_method;
+    uint32_t l1_size; /* XXX: save number of clusters instead ? */
+    uint64_t l1_table_offset;
+    uint64_t refcount_table_offset;
+    uint32_t refcount_table_clusters;
+    uint32_t nb_snapshots;
+    uint64_t snapshots_offset;
+} QCowHeader;
+
+typedef struct QCowSnapshot {
+    uint64_t l1_table_offset;
+    uint32_t l1_size;
+    char *id_str;
+    char *name;
+    uint32_t vm_state_size;
+    uint32_t date_sec;
+    uint32_t date_nsec;
+    uint64_t vm_clock_nsec;
+} QCowSnapshot;
+
+typedef struct BDRVQcowState {
+    BlockDriverState *hd;
+    int cluster_bits;
+    int cluster_size;
+    int cluster_sectors;
+    int l2_bits;
+    int l2_size;
+    int l1_size;
+    int l1_vm_state_index;
+    int csize_shift;
+    int csize_mask;
+    uint64_t cluster_offset_mask;
+    uint64_t l1_table_offset;
+    uint64_t *l1_table;
+    uint64_t *l2_cache;
+    uint64_t l2_cache_offsets[L2_CACHE_SIZE];
+    uint32_t l2_cache_counts[L2_CACHE_SIZE];
+    uint8_t *cluster_cache;
+    uint8_t *cluster_data;
+    uint64_t cluster_cache_offset;
+
+    uint64_t *refcount_table;
+    uint64_t refcount_table_offset;
+    uint32_t refcount_table_size;
+    uint64_t refcount_block_cache_offset;
+    uint16_t *refcount_block_cache;
+    int64_t free_cluster_index;
+    int64_t free_byte_offset;
+
+    uint32_t crypt_method; /* current crypt method, 0 if no key yet */
+    uint32_t crypt_method_header;
+    AES_KEY aes_encrypt_key;
+    AES_KEY aes_decrypt_key;
+    uint64_t snapshots_offset;
+    int snapshots_size;
+    int nb_snapshots;
+    QCowSnapshot *snapshots;
+} BDRVQcowState;
+
+/* XXX: use std qcow open function ? */
+typedef struct QCowCreateState {
+    int cluster_size;
+    int cluster_bits;
+    uint16_t *refcount_block;
+    uint64_t *refcount_table;
+    int64_t l1_table_offset;
+    int64_t refcount_table_offset;
+    int64_t refcount_block_offset;
+} QCowCreateState;
+
+/* XXX This could be private for qcow2-cluster.c */
+typedef struct QCowL2Meta
+{
+    uint64_t offset;
+    int n_start;
+    int nb_available;
+    int nb_clusters;
+} QCowL2Meta;
+
+static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
+{
+    return (size + (s->cluster_size - 1)) >> s->cluster_bits;
+}
+
+static inline int64_t align_offset(int64_t offset, int n)
+{
+    offset = (offset + n - 1) & ~(n - 1);
+    return offset;
+}
+
+
+// FIXME Need qcow2_ prefix to global functions
+
+/* qcow2.c functions */
+int qcow2_backing_read1(BlockDriverState *bs,
+                  int64_t sector_num, uint8_t *buf, int nb_sectors);
+
+/* qcow2-refcount.c functions */
+int qcow2_refcount_init(BlockDriverState *bs);
+void qcow2_refcount_close(BlockDriverState *bs);
+
+int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size);
+int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
+void qcow2_free_clusters(BlockDriverState *bs,
+    int64_t offset, int64_t size);
+void qcow2_free_any_clusters(BlockDriverState *bs,
+    uint64_t cluster_offset, int nb_clusters);
+
+void qcow2_create_refcount_update(QCowCreateState *s, int64_t offset,
+    int64_t size);
+int qcow2_update_snapshot_refcount(BlockDriverState *bs,
+    int64_t l1_table_offset, int l1_size, int addend);
+
+int qcow2_check_refcounts(BlockDriverState *bs);
+
+/* qcow2-cluster.c functions */
+int qcow2_grow_l1_table(BlockDriverState *bs, int min_size);
+void qcow2_l2_cache_reset(BlockDriverState *bs);
+int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
+void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
+                     uint8_t *out_buf, const uint8_t *in_buf,
+                     int nb_sectors, int enc,
+                     const AES_KEY *key);
+
+uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
+    int *num);
+uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
+                              uint64_t offset,
+                              int n_start, int n_end,
+                              int *num, QCowL2Meta *m);
+uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
+                                         uint64_t offset,
+                                         int compressed_size);
+
+int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
+    QCowL2Meta *m);
+
+/* qcow2-snapshot.c functions */
+int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
+int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
+int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
+int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
+
+void qcow2_free_snapshots(BlockDriverState *bs);
+int qcow2_read_snapshots(BlockDriverState *bs);
+
+#endif
diff --git a/block/raw-posix.c b/block/raw-posix.c
new file mode 100644
index 0000000..fa1a394
--- /dev/null
+++ b/block/raw-posix.c
@@ -0,0 +1,1501 @@
+/*
+ * Block driver for RAW files (posix)
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "block_int.h"
+#include "module.h"
+#ifdef CONFIG_AIO
+#include "posix-aio-compat.h"
+#endif
+
+#ifdef CONFIG_COCOA
+#include <paths.h>
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOMediaBSDClient.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+//#include <IOKit/storage/IOCDTypes.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#include <signal.h>
+#include <sys/dkio.h>
+#endif
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+#endif
+#ifdef __FreeBSD__
+#include <signal.h>
+#include <sys/disk.h>
+#include <sys/cdio.h>
+#endif
+
+#ifdef __OpenBSD__
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#endif
+
+#ifdef __DragonFly__
+#include <sys/ioctl.h>
+#include <sys/diskslice.h>
+#endif
+
+//#define DEBUG_FLOPPY
+
+//#define DEBUG_BLOCK
+#if defined(DEBUG_BLOCK)
+#define DEBUG_BLOCK_PRINT(formatCstr, ...) do { if (qemu_log_enabled()) \
+    { qemu_log(formatCstr, ## __VA_ARGS__); qemu_log_flush(); } } while (0)
+#else
+#define DEBUG_BLOCK_PRINT(formatCstr, ...)
+#endif
+
+/* OS X does not have O_DSYNC */
+#ifndef O_DSYNC
+#define O_DSYNC O_SYNC
+#endif
+
+/* Approximate O_DIRECT with O_DSYNC if O_DIRECT isn't available */
+#ifndef O_DIRECT
+#define O_DIRECT O_DSYNC
+#endif
+
+#define FTYPE_FILE   0
+#define FTYPE_CD     1
+#define FTYPE_FD     2
+
+#define ALIGNED_BUFFER_SIZE (32 * 512)
+
+/* if the FD is not accessed during that time (in ms), we try to
+   reopen it to see if the disk has been changed */
+#define FD_OPEN_TIMEOUT 1000
+
+typedef struct BDRVRawState {
+    int fd;
+    int type;
+    unsigned int lseek_err_cnt;
+    int open_flags;
+#if defined(__linux__)
+    /* linux floppy specific */
+    int64_t fd_open_time;
+    int64_t fd_error_time;
+    int fd_got_error;
+    int fd_media_changed;
+#endif
+    uint8_t* aligned_buf;
+} BDRVRawState;
+
+static int posix_aio_init(void);
+
+static int fd_open(BlockDriverState *bs);
+
+#if defined(__FreeBSD__)
+static int cdrom_reopen(BlockDriverState *bs);
+#endif
+
+static int raw_open_common(BlockDriverState *bs, const char *filename,
+                           int bdrv_flags, int open_flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd, ret;
+
+    posix_aio_init();
+
+    s->lseek_err_cnt = 0;
+
+    s->open_flags = open_flags | O_BINARY;
+    s->open_flags &= ~O_ACCMODE;
+    if ((bdrv_flags & BDRV_O_ACCESS) == BDRV_O_RDWR) {
+        s->open_flags |= O_RDWR;
+    } else {
+        s->open_flags |= O_RDONLY;
+        bs->read_only = 1;
+    }
+
+    /* Use O_DSYNC for write-through caching, no flags for write-back caching,
+     * and O_DIRECT for no caching. */
+    if ((bdrv_flags & BDRV_O_NOCACHE))
+        s->open_flags |= O_DIRECT;
+    else if (!(bdrv_flags & BDRV_O_CACHE_WB))
+        s->open_flags |= O_DSYNC;
+
+    s->fd = -1;
+    fd = open(filename, s->open_flags, 0644);
+    if (fd < 0) {
+        ret = -errno;
+        if (ret == -EROFS)
+            ret = -EACCES;
+        return ret;
+    }
+    s->fd = fd;
+    s->aligned_buf = NULL;
+    if ((bdrv_flags & BDRV_O_NOCACHE)) {
+        s->aligned_buf = qemu_blockalign(bs, ALIGNED_BUFFER_SIZE);
+        if (s->aligned_buf == NULL) {
+            ret = -errno;
+            close(fd);
+            return ret;
+        }
+    }
+    return 0;
+}
+
+static int raw_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int open_flags = 0;
+
+    s->type = FTYPE_FILE;
+    if (flags & BDRV_O_CREAT)
+        open_flags = O_CREAT | O_TRUNC;
+
+    return raw_open_common(bs, filename, flags, open_flags);
+}
+
+/* XXX: use host sector size if necessary with:
+#ifdef DIOCGSECTORSIZE
+        {
+            unsigned int sectorsize = 512;
+            if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
+                sectorsize > bufsize)
+                bufsize = sectorsize;
+        }
+#endif
+#ifdef CONFIG_COCOA
+        u_int32_t   blockSize = 512;
+        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
+            bufsize = blockSize;
+        }
+#endif
+*/
+
+/*
+ * offset and count are in bytes, but must be multiples of 512 for files
+ * opened with O_DIRECT. buf must be aligned to 512 bytes then.
+ *
+ * This function may be called without alignment if the caller ensures
+ * that O_DIRECT is not in effect.
+ */
+static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
+                     uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0)
+        return ret;
+
+    if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+        ++(s->lseek_err_cnt);
+        if(s->lseek_err_cnt <= 10) {
+            DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                              "] lseek failed : %d = %s\n",
+                              s->fd, bs->filename, offset, buf, count,
+                              bs->total_sectors, errno, strerror(errno));
+        }
+        return -1;
+    }
+    s->lseek_err_cnt=0;
+
+    ret = read(s->fd, buf, count);
+    if (ret == count)
+        goto label__raw_read__success;
+
+    DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                      "] read failed %d : %d = %s\n",
+                      s->fd, bs->filename, offset, buf, count,
+                      bs->total_sectors, ret, errno, strerror(errno));
+
+    /* Try harder for CDrom. */
+    if (bs->type == BDRV_TYPE_CDROM) {
+        lseek(s->fd, offset, SEEK_SET);
+        ret = read(s->fd, buf, count);
+        if (ret == count)
+            goto label__raw_read__success;
+        lseek(s->fd, offset, SEEK_SET);
+        ret = read(s->fd, buf, count);
+        if (ret == count)
+            goto label__raw_read__success;
+
+        DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                          "] retry read failed %d : %d = %s\n",
+                          s->fd, bs->filename, offset, buf, count,
+                          bs->total_sectors, ret, errno, strerror(errno));
+    }
+
+label__raw_read__success:
+
+    return  (ret < 0) ? -errno : ret;
+}
+
+/*
+ * offset and count are in bytes, but must be multiples of 512 for files
+ * opened with O_DIRECT. buf must be aligned to 512 bytes then.
+ *
+ * This function may be called without alignment if the caller ensures
+ * that O_DIRECT is not in effect.
+ */
+static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset,
+                      const uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0)
+        return -errno;
+
+    if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+        ++(s->lseek_err_cnt);
+        if(s->lseek_err_cnt) {
+            DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%"
+                              PRId64 "] lseek failed : %d = %s\n",
+                              s->fd, bs->filename, offset, buf, count,
+                              bs->total_sectors, errno, strerror(errno));
+        }
+        return -EIO;
+    }
+    s->lseek_err_cnt = 0;
+
+    ret = write(s->fd, buf, count);
+    if (ret == count)
+        goto label__raw_write__success;
+
+    DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                      "] write failed %d : %d = %s\n",
+                      s->fd, bs->filename, offset, buf, count,
+                      bs->total_sectors, ret, errno, strerror(errno));
+
+label__raw_write__success:
+
+    return  (ret < 0) ? -errno : ret;
+}
+
+
+/*
+ * offset and count are in bytes and possibly not aligned. For files opened
+ * with O_DIRECT, necessary alignments are ensured before calling
+ * raw_pread_aligned to do the actual read.
+ */
+static int raw_pread(BlockDriverState *bs, int64_t offset,
+                     uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    int size, ret, shift, sum;
+
+    sum = 0;
+
+    if (s->aligned_buf != NULL)  {
+
+        if (offset & 0x1ff) {
+            /* align offset on a 512 bytes boundary */
+
+            shift = offset & 0x1ff;
+            size = (shift + count + 0x1ff) & ~0x1ff;
+            if (size > ALIGNED_BUFFER_SIZE)
+                size = ALIGNED_BUFFER_SIZE;
+            ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, size);
+            if (ret < 0)
+                return ret;
+
+            size = 512 - shift;
+            if (size > count)
+                size = count;
+            memcpy(buf, s->aligned_buf + shift, size);
+
+            buf += size;
+            offset += size;
+            count -= size;
+            sum += size;
+
+            if (count == 0)
+                return sum;
+        }
+        if (count & 0x1ff || (uintptr_t) buf & 0x1ff) {
+
+            /* read on aligned buffer */
+
+            while (count) {
+
+                size = (count + 0x1ff) & ~0x1ff;
+                if (size > ALIGNED_BUFFER_SIZE)
+                    size = ALIGNED_BUFFER_SIZE;
+
+                ret = raw_pread_aligned(bs, offset, s->aligned_buf, size);
+                if (ret < 0)
+                    return ret;
+
+                size = ret;
+                if (size > count)
+                    size = count;
+
+                memcpy(buf, s->aligned_buf, size);
+
+                buf += size;
+                offset += size;
+                count -= size;
+                sum += size;
+            }
+
+            return sum;
+        }
+    }
+
+    return raw_pread_aligned(bs, offset, buf, count) + sum;
+}
+
+static int raw_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    int ret;
+
+    ret = raw_pread(bs, sector_num * 512, buf, nb_sectors * 512);
+    if (ret == (nb_sectors * 512))
+        ret = 0;
+    return ret;
+}
+
+/*
+ * offset and count are in bytes and possibly not aligned. For files opened
+ * with O_DIRECT, necessary alignments are ensured before calling
+ * raw_pwrite_aligned to do the actual write.
+ */
+static int raw_pwrite(BlockDriverState *bs, int64_t offset,
+                      const uint8_t *buf, int count)
+{
+    BDRVRawState *s = bs->opaque;
+    int size, ret, shift, sum;
+
+    sum = 0;
+
+    if (s->aligned_buf != NULL) {
+
+        if (offset & 0x1ff) {
+            /* align offset on a 512 bytes boundary */
+            shift = offset & 0x1ff;
+            ret = raw_pread_aligned(bs, offset - shift, s->aligned_buf, 512);
+            if (ret < 0)
+                return ret;
+
+            size = 512 - shift;
+            if (size > count)
+                size = count;
+            memcpy(s->aligned_buf + shift, buf, size);
+
+            ret = raw_pwrite_aligned(bs, offset - shift, s->aligned_buf, 512);
+            if (ret < 0)
+                return ret;
+
+            buf += size;
+            offset += size;
+            count -= size;
+            sum += size;
+
+            if (count == 0)
+                return sum;
+        }
+        if (count & 0x1ff || (uintptr_t) buf & 0x1ff) {
+
+            while ((size = (count & ~0x1ff)) != 0) {
+
+                if (size > ALIGNED_BUFFER_SIZE)
+                    size = ALIGNED_BUFFER_SIZE;
+
+                memcpy(s->aligned_buf, buf, size);
+
+                ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, size);
+                if (ret < 0)
+                    return ret;
+
+                buf += ret;
+                offset += ret;
+                count -= ret;
+                sum += ret;
+            }
+            /* here, count < 512 because (count & ~0x1ff) == 0 */
+            if (count) {
+                ret = raw_pread_aligned(bs, offset, s->aligned_buf, 512);
+                if (ret < 0)
+                    return ret;
+                 memcpy(s->aligned_buf, buf, count);
+
+                 ret = raw_pwrite_aligned(bs, offset, s->aligned_buf, 512);
+                 if (ret < 0)
+                     return ret;
+                 if (count < ret)
+                     ret = count;
+
+                 sum += ret;
+            }
+            return sum;
+        }
+    }
+    return raw_pwrite_aligned(bs, offset, buf, count) + sum;
+}
+
+static int raw_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
+{
+    int ret;
+    ret = raw_pwrite(bs, sector_num * 512, buf, nb_sectors * 512);
+    if (ret == (nb_sectors * 512))
+        ret = 0;
+    return ret;
+}
+
+#ifdef CONFIG_AIO
+/***********************************************************/
+/* Unix AIO using POSIX AIO */
+
+typedef struct RawAIOCB {
+    BlockDriverAIOCB common;
+    struct qemu_paiocb aiocb;
+    struct RawAIOCB *next;
+    int ret;
+} RawAIOCB;
+
+typedef struct PosixAioState
+{
+    int rfd, wfd;
+    RawAIOCB *first_aio;
+} PosixAioState;
+
+static void posix_aio_read(void *opaque)
+{
+    PosixAioState *s = opaque;
+    RawAIOCB *acb, **pacb;
+    int ret;
+    ssize_t len;
+
+    /* read all bytes from signal pipe */
+    for (;;) {
+        char bytes[16];
+
+        len = read(s->rfd, bytes, sizeof(bytes));
+        if (len == -1 && errno == EINTR)
+            continue; /* try again */
+        if (len == sizeof(bytes))
+            continue; /* more to read */
+        break;
+    }
+
+    for(;;) {
+        pacb = &s->first_aio;
+        for(;;) {
+            acb = *pacb;
+            if (!acb)
+                goto the_end;
+            ret = qemu_paio_error(&acb->aiocb);
+            if (ret == ECANCELED) {
+                /* remove the request */
+                *pacb = acb->next;
+                qemu_aio_release(acb);
+            } else if (ret != EINPROGRESS) {
+                /* end of aio */
+                if (ret == 0) {
+                    ret = qemu_paio_return(&acb->aiocb);
+                    if (ret == acb->aiocb.aio_nbytes)
+                        ret = 0;
+                    else
+                        ret = -EINVAL;
+                } else {
+                    ret = -ret;
+                }
+                /* remove the request */
+                *pacb = acb->next;
+                /* call the callback */
+                acb->common.cb(acb->common.opaque, ret);
+                qemu_aio_release(acb);
+                break;
+            } else {
+                pacb = &acb->next;
+            }
+        }
+    }
+ the_end: ;
+}
+
+static int posix_aio_flush(void *opaque)
+{
+    PosixAioState *s = opaque;
+    return !!s->first_aio;
+}
+
+static PosixAioState *posix_aio_state;
+
+static void aio_signal_handler(int signum)
+{
+    if (posix_aio_state) {
+        char byte = 0;
+
+        write(posix_aio_state->wfd, &byte, sizeof(byte));
+    }
+
+    qemu_service_io();
+}
+
+static int posix_aio_init(void)
+{
+    struct sigaction act;
+    PosixAioState *s;
+    int fds[2];
+    struct qemu_paioinit ai;
+  
+    if (posix_aio_state)
+        return 0;
+
+    s = qemu_malloc(sizeof(PosixAioState));
+
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
+    act.sa_handler = aio_signal_handler;
+    sigaction(SIGUSR2, &act, NULL);
+
+    s->first_aio = NULL;
+    if (pipe(fds) == -1) {
+        fprintf(stderr, "failed to create pipe\n");
+        return -errno;
+    }
+
+    s->rfd = fds[0];
+    s->wfd = fds[1];
+
+    fcntl(s->rfd, F_SETFL, O_NONBLOCK);
+    fcntl(s->wfd, F_SETFL, O_NONBLOCK);
+
+    qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
+
+    memset(&ai, 0, sizeof(ai));
+    ai.aio_threads = 64;
+    ai.aio_num = 64;
+    qemu_paio_init(&ai);
+
+    posix_aio_state = s;
+
+    return 0;
+}
+
+static void raw_aio_remove(RawAIOCB *acb)
+{
+    RawAIOCB **pacb;
+
+    /* remove the callback from the queue */
+    pacb = &posix_aio_state->first_aio;
+    for(;;) {
+        if (*pacb == NULL) {
+            fprintf(stderr, "raw_aio_remove: aio request not found!\n");
+            break;
+        } else if (*pacb == acb) {
+            *pacb = acb->next;
+            qemu_aio_release(acb);
+            break;
+        }
+        pacb = &(*pacb)->next;
+    }
+}
+
+static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+    int ret;
+    RawAIOCB *acb = (RawAIOCB *)blockacb;
+
+    ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
+    if (ret == QEMU_PAIO_NOTCANCELED) {
+        /* fail safe: if the aio could not be canceled, we wait for
+           it */
+        while (qemu_paio_error(&acb->aiocb) == EINPROGRESS);
+    }
+
+    raw_aio_remove(acb);
+}
+
+static AIOPool raw_aio_pool = {
+    .aiocb_size         = sizeof(RawAIOCB),
+    .cancel             = raw_aio_cancel,
+};
+
+static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int64_t sector_num,
+        QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVRawState *s = bs->opaque;
+    RawAIOCB *acb;
+
+    if (fd_open(bs) < 0)
+        return NULL;
+
+    acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->aiocb.aio_fildes = s->fd;
+    acb->aiocb.ev_signo = SIGUSR2;
+    acb->aiocb.aio_iov = qiov->iov;
+    acb->aiocb.aio_niov = qiov->niov;
+    acb->aiocb.aio_nbytes = nb_sectors * 512;
+    acb->aiocb.aio_offset = sector_num * 512;
+    acb->aiocb.aio_flags = 0;
+
+    /*
+     * If O_DIRECT is used the buffer needs to be aligned on a sector
+     * boundary. Tell the low level code to ensure that in case it's
+     * not done yet.
+     */
+    if (s->aligned_buf)
+        acb->aiocb.aio_flags |= QEMU_AIO_SECTOR_ALIGNED;
+
+    acb->next = posix_aio_state->first_aio;
+    posix_aio_state->first_aio = acb;
+    return acb;
+}
+
+static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    RawAIOCB *acb;
+
+    acb = raw_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque);
+    if (!acb)
+        return NULL;
+    if (qemu_paio_read(&acb->aiocb) < 0) {
+        raw_aio_remove(acb);
+        return NULL;
+    }
+    return &acb->common;
+}
+
+static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    RawAIOCB *acb;
+
+    acb = raw_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque);
+    if (!acb)
+        return NULL;
+    if (qemu_paio_write(&acb->aiocb) < 0) {
+        raw_aio_remove(acb);
+        return NULL;
+    }
+    return &acb->common;
+}
+#else /* CONFIG_AIO */
+static int posix_aio_init(void)
+{
+    return 0;
+}
+#endif /* CONFIG_AIO */
+
+
+static void raw_close(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    if (s->fd >= 0) {
+        close(s->fd);
+        s->fd = -1;
+        if (s->aligned_buf != NULL)
+            qemu_free(s->aligned_buf);
+    }
+}
+
+static int raw_truncate(BlockDriverState *bs, int64_t offset)
+{
+    BDRVRawState *s = bs->opaque;
+    if (s->type != FTYPE_FILE)
+        return -ENOTSUP;
+    if (ftruncate(s->fd, offset) < 0)
+        return -errno;
+    return 0;
+}
+
+#ifdef __OpenBSD__
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+    struct stat st;
+
+    if (fstat(fd, &st))
+        return -1;
+    if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+        struct disklabel dl;
+
+        if (ioctl(fd, DIOCGDINFO, &dl))
+            return -1;
+        return (uint64_t)dl.d_secsize *
+            dl.d_partitions[DISKPART(st.st_rdev)].p_size;
+    } else
+        return st.st_size;
+}
+#else /* !__OpenBSD__ */
+static int64_t  raw_getlength(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+    int64_t size;
+#ifdef HOST_BSD
+    struct stat sb;
+#ifdef __FreeBSD__
+    int reopened = 0;
+#endif
+#endif
+#ifdef __sun__
+    struct dk_minfo minfo;
+    int rv;
+#endif
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0)
+        return ret;
+
+#ifdef HOST_BSD
+#ifdef __FreeBSD__
+again:
+#endif
+    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
+#ifdef DIOCGMEDIASIZE
+	if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
+#elif defined(DIOCGPART)
+        {
+                struct partinfo pi;
+                if (ioctl(fd, DIOCGPART, &pi) == 0)
+                        size = pi.media_size;
+                else
+                        size = 0;
+        }
+        if (size == 0)
+#endif
+#ifdef CONFIG_COCOA
+        size = LONG_LONG_MAX;
+#else
+        size = lseek(fd, 0LL, SEEK_END);
+#endif
+#ifdef __FreeBSD__
+        switch(s->type) {
+        case FTYPE_CD:
+            /* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
+            if (size == 2048LL * (unsigned)-1)
+                size = 0;
+            /* XXX no disc?  maybe we need to reopen... */
+            if (size <= 0 && !reopened && cdrom_reopen(bs) >= 0) {
+                reopened = 1;
+                goto again;
+            }
+        }
+#endif
+    } else
+#endif
+#ifdef __sun__
+    /*
+     * use the DKIOCGMEDIAINFO ioctl to read the size.
+     */
+    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
+    if ( rv != -1 ) {
+        size = minfo.dki_lbsize * minfo.dki_capacity;
+    } else /* there are reports that lseek on some devices
+              fails, but irc discussion said that contingency
+              on contingency was overkill */
+#endif
+    {
+        size = lseek(fd, 0, SEEK_END);
+    }
+    return size;
+}
+#endif
+
+static int raw_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd;
+    int64_t total_size = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        }
+        options++;
+    }
+
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+              0644);
+    if (fd < 0)
+        return -EIO;
+    ftruncate(fd, total_size * 512);
+    close(fd);
+    return 0;
+}
+
+static void raw_flush(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    fsync(s->fd);
+}
+
+
+static QEMUOptionParameter raw_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_raw = {
+    .format_name = "raw",
+    .instance_size = sizeof(BDRVRawState),
+    .bdrv_probe = NULL, /* no probe for protocols */
+    .bdrv_open = raw_open,
+    .bdrv_read = raw_read,
+    .bdrv_write = raw_write,
+    .bdrv_close = raw_close,
+    .bdrv_create = raw_create,
+    .bdrv_flush = raw_flush,
+
+#ifdef CONFIG_AIO
+    .bdrv_aio_readv = raw_aio_readv,
+    .bdrv_aio_writev = raw_aio_writev,
+#endif
+
+    .bdrv_truncate = raw_truncate,
+    .bdrv_getlength = raw_getlength,
+
+    .create_options = raw_create_options,
+};
+
+/***********************************************/
+/* host device */
+
+#ifdef CONFIG_COCOA
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
+static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
+
+kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
+{
+    kern_return_t       kernResult;
+    mach_port_t     masterPort;
+    CFMutableDictionaryRef  classesToMatch;
+
+    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
+    if ( KERN_SUCCESS != kernResult ) {
+        printf( "IOMasterPort returned %d\n", kernResult );
+    }
+
+    classesToMatch = IOServiceMatching( kIOCDMediaClass );
+    if ( classesToMatch == NULL ) {
+        printf( "IOServiceMatching returned a NULL dictionary.\n" );
+    } else {
+    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
+    }
+    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
+    if ( KERN_SUCCESS != kernResult )
+    {
+        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
+    }
+
+    return kernResult;
+}
+
+kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
+{
+    io_object_t     nextMedia;
+    kern_return_t   kernResult = KERN_FAILURE;
+    *bsdPath = '\0';
+    nextMedia = IOIteratorNext( mediaIterator );
+    if ( nextMedia )
+    {
+        CFTypeRef   bsdPathAsCFString;
+    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
+        if ( bsdPathAsCFString ) {
+            size_t devPathLength;
+            strcpy( bsdPath, _PATH_DEV );
+            strcat( bsdPath, "r" );
+            devPathLength = strlen( bsdPath );
+            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
+                kernResult = KERN_SUCCESS;
+            }
+            CFRelease( bsdPathAsCFString );
+        }
+        IOObjectRelease( nextMedia );
+    }
+
+    return kernResult;
+}
+
+#endif
+
+static int hdev_probe_device(const char *filename)
+{
+    struct stat st;
+
+    /* allow a dedicated CD-ROM driver to match with a higher priority */
+    if (strstart(filename, "/dev/cdrom", NULL))
+        return 50;
+
+    if (stat(filename, &st) >= 0 &&
+            (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+        return 100;
+    }
+
+    return 0;
+}
+
+static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+
+#ifdef CONFIG_COCOA
+    if (strstart(filename, "/dev/cdrom", NULL)) {
+        kern_return_t kernResult;
+        io_iterator_t mediaIterator;
+        char bsdPath[ MAXPATHLEN ];
+        int fd;
+
+        kernResult = FindEjectableCDMedia( &mediaIterator );
+        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
+
+        if ( bsdPath[ 0 ] != '\0' ) {
+            strcat(bsdPath,"s0");
+            /* some CDs don't have a partition 0 */
+            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
+            if (fd < 0) {
+                bsdPath[strlen(bsdPath)-1] = '1';
+            } else {
+                close(fd);
+            }
+            filename = bsdPath;
+        }
+
+        if ( mediaIterator )
+            IOObjectRelease( mediaIterator );
+    }
+#endif
+
+    s->type = FTYPE_FILE;
+#if defined(__linux__) && defined(CONFIG_AIO)
+    if (strstart(filename, "/dev/sg", NULL)) {
+        bs->sg = 1;
+    }
+#endif
+
+    return raw_open_common(bs, filename, flags, 0);
+}
+
+#if defined(__linux__)
+/* Note: we do not have a reliable method to detect if the floppy is
+   present. The current method is to try to open the floppy at every
+   I/O and to keep it opened during a few hundreds of ms. */
+static int fd_open(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int last_media_present;
+
+    if (s->type != FTYPE_FD)
+        return 0;
+    last_media_present = (s->fd >= 0);
+    if (s->fd >= 0 &&
+        (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
+        close(s->fd);
+        s->fd = -1;
+#ifdef DEBUG_FLOPPY
+        printf("Floppy closed\n");
+#endif
+    }
+    if (s->fd < 0) {
+        if (s->fd_got_error &&
+            (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
+#ifdef DEBUG_FLOPPY
+            printf("No floppy (open delayed)\n");
+#endif
+            return -EIO;
+        }
+        s->fd = open(bs->filename, s->open_flags & ~O_NONBLOCK);
+        if (s->fd < 0) {
+            s->fd_error_time = qemu_get_clock(rt_clock);
+            s->fd_got_error = 1;
+            if (last_media_present)
+                s->fd_media_changed = 1;
+#ifdef DEBUG_FLOPPY
+            printf("No floppy\n");
+#endif
+            return -EIO;
+        }
+#ifdef DEBUG_FLOPPY
+        printf("Floppy opened\n");
+#endif
+    }
+    if (!last_media_present)
+        s->fd_media_changed = 1;
+    s->fd_open_time = qemu_get_clock(rt_clock);
+    s->fd_got_error = 0;
+    return 0;
+}
+
+static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+{
+    BDRVRawState *s = bs->opaque;
+
+    return ioctl(s->fd, req, buf);
+}
+
+#ifdef CONFIG_AIO
+static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque)
+{
+    BDRVRawState *s = bs->opaque;
+    RawAIOCB *acb;
+
+    if (fd_open(bs) < 0)
+        return NULL;
+
+    acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
+    if (!acb)
+        return NULL;
+    acb->aiocb.aio_fildes = s->fd;
+    acb->aiocb.ev_signo = SIGUSR2;
+    acb->aiocb.aio_offset = 0;
+    acb->aiocb.aio_flags = 0;
+
+    acb->next = posix_aio_state->first_aio;
+    posix_aio_state->first_aio = acb;
+
+    acb->aiocb.aio_ioctl_buf = buf;
+    acb->aiocb.aio_ioctl_cmd = req;
+    if (qemu_paio_ioctl(&acb->aiocb) < 0) {
+        raw_aio_remove(acb);
+        return NULL;
+    }
+
+    return &acb->common;
+}
+#endif
+
+#elif defined(__FreeBSD__)
+static int fd_open(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+
+    /* this is just to ensure s->fd is sane (its called by io ops) */
+    if (s->fd >= 0)
+        return 0;
+    return -EIO;
+}
+#else /* !linux && !FreeBSD */
+
+static int fd_open(BlockDriverState *bs)
+{
+    return 0;
+}
+
+#endif /* !linux && !FreeBSD */
+
+static int hdev_create(const char *filename, QEMUOptionParameter *options)
+{
+    int fd;
+    int ret = 0;
+    struct stat stat_buf;
+    int64_t total_size = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, "size")) {
+            total_size = options->value.n / 512;
+        }
+        options++;
+    }
+
+    fd = open(filename, O_WRONLY | O_BINARY);
+    if (fd < 0)
+        return -EIO;
+
+    if (fstat(fd, &stat_buf) < 0)
+        ret = -EIO;
+    else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
+        ret = -EIO;
+    else if (lseek(fd, 0, SEEK_END) < total_size * 512)
+        ret = -ENOSPC;
+
+    close(fd);
+    return ret;
+}
+
+static BlockDriver bdrv_host_device = {
+    .format_name	= "host_device",
+    .instance_size	= sizeof(BDRVRawState),
+    .bdrv_probe_device	= hdev_probe_device,
+    .bdrv_open		= hdev_open,
+    .bdrv_close		= raw_close,
+    .bdrv_create        = hdev_create,
+    .bdrv_flush		= raw_flush,
+
+#ifdef CONFIG_AIO
+    .bdrv_aio_readv	= raw_aio_readv,
+    .bdrv_aio_writev	= raw_aio_writev,
+#endif
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength	= raw_getlength,
+
+    /* generic scsi device */
+#ifdef __linux__
+    .bdrv_ioctl         = hdev_ioctl,
+#ifdef CONFIG_AIO
+    .bdrv_aio_ioctl     = hdev_aio_ioctl,
+#endif
+#endif
+};
+
+#ifdef __linux__
+static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    posix_aio_init();
+
+    s->type = FTYPE_FD;
+
+    /* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
+    ret = raw_open_common(bs, filename, flags, O_NONBLOCK);
+    if (ret)
+        return ret;
+
+    /* close fd so that we can reopen it as needed */
+    close(s->fd);
+    s->fd = -1;
+    s->fd_media_changed = 1;
+
+    return 0;
+}
+
+static int floppy_probe_device(const char *filename)
+{
+    if (strstart(filename, "/dev/fd", NULL))
+        return 100;
+    return 0;
+}
+
+
+static int floppy_is_inserted(BlockDriverState *bs)
+{
+    return fd_open(bs) >= 0;
+}
+
+static int floppy_media_changed(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    /*
+     * XXX: we do not have a true media changed indication.
+     * It does not work if the floppy is changed without trying to read it.
+     */
+    fd_open(bs);
+    ret = s->fd_media_changed;
+    s->fd_media_changed = 0;
+#ifdef DEBUG_FLOPPY
+    printf("Floppy changed=%d\n", ret);
+#endif
+    return ret;
+}
+
+static int floppy_eject(BlockDriverState *bs, int eject_flag)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd;
+
+    if (s->fd >= 0) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    fd = open(bs->filename, s->open_flags | O_NONBLOCK);
+    if (fd >= 0) {
+        if (ioctl(fd, FDEJECT, 0) < 0)
+            perror("FDEJECT");
+        close(fd);
+    }
+
+    return 0;
+}
+
+static BlockDriver bdrv_host_floppy = {
+    .format_name        = "host_floppy",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device	= floppy_probe_device,
+    .bdrv_open          = floppy_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .bdrv_flush         = raw_flush,
+
+#ifdef CONFIG_AIO
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+#endif
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength	= raw_getlength,
+
+    /* removable device support */
+    .bdrv_is_inserted   = floppy_is_inserted,
+    .bdrv_media_changed = floppy_media_changed,
+    .bdrv_eject         = floppy_eject,
+};
+
+static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+
+    s->type = FTYPE_CD;
+
+    /* open will not fail even if no CD is inserted, so add O_NONBLOCK */
+    return raw_open_common(bs, filename, flags, O_NONBLOCK);
+}
+
+static int cdrom_probe_device(const char *filename)
+{
+    if (strstart(filename, "/dev/cd", NULL))
+        return 100;
+    return 0;
+}
+
+static int cdrom_is_inserted(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+    if (ret == CDS_DISC_OK)
+        return 1;
+    return 0;
+}
+
+static int cdrom_eject(BlockDriverState *bs, int eject_flag)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (eject_flag) {
+        if (ioctl(s->fd, CDROMEJECT, NULL) < 0)
+            perror("CDROMEJECT");
+    } else {
+        if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0)
+            perror("CDROMEJECT");
+    }
+
+    return 0;
+}
+
+static int cdrom_set_locked(BlockDriverState *bs, int locked)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (ioctl(s->fd, CDROM_LOCKDOOR, locked) < 0) {
+        /*
+         * Note: an error can happen if the distribution automatically
+         * mounts the CD-ROM
+         */
+        /* perror("CDROM_LOCKDOOR"); */
+    }
+
+    return 0;
+}
+
+static BlockDriver bdrv_host_cdrom = {
+    .format_name        = "host_cdrom",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device	= cdrom_probe_device,
+    .bdrv_open          = cdrom_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .bdrv_flush         = raw_flush,
+
+#ifdef CONFIG_AIO
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+#endif
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength     = raw_getlength,
+
+    /* removable device support */
+    .bdrv_is_inserted   = cdrom_is_inserted,
+    .bdrv_eject         = cdrom_eject,
+    .bdrv_set_locked    = cdrom_set_locked,
+
+    /* generic scsi device */
+    .bdrv_ioctl         = hdev_ioctl,
+#ifdef CONFIG_AIO
+    .bdrv_aio_ioctl     = hdev_aio_ioctl,
+#endif
+};
+#endif /* __linux__ */
+
+#ifdef __FreeBSD__
+static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVRawState *s = bs->opaque;
+    int ret;
+
+    s->type = FTYPE_CD;
+
+    ret = raw_open_common(bs, filename, flags, 0);
+    if (ret)
+        return ret;
+
+    /* make sure the door isnt locked at this time */
+    ioctl(s->fd, CDIOCALLOW);
+    return 0;
+}
+
+static int cdrom_probe_device(const char *filename)
+{
+    if (strstart(filename, "/dev/cd", NULL) ||
+            strstart(filename, "/dev/acd", NULL))
+        return 100;
+    return 0;
+}
+
+static int cdrom_reopen(BlockDriverState *bs)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd;
+
+    /*
+     * Force reread of possibly changed/newly loaded disc,
+     * FreeBSD seems to not notice sometimes...
+     */
+    if (s->fd >= 0)
+        close(s->fd);
+    fd = open(bs->filename, s->open_flags, 0644);
+    if (fd < 0) {
+        s->fd = -1;
+        return -EIO;
+    }
+    s->fd = fd;
+
+    /* make sure the door isnt locked at this time */
+    ioctl(s->fd, CDIOCALLOW);
+    return 0;
+}
+
+static int cdrom_is_inserted(BlockDriverState *bs)
+{
+    return raw_getlength(bs) > 0;
+}
+
+static int cdrom_eject(BlockDriverState *bs, int eject_flag)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (s->fd < 0)
+        return -ENOTSUP;
+
+    (void) ioctl(s->fd, CDIOCALLOW);
+
+    if (eject_flag) {
+        if (ioctl(s->fd, CDIOCEJECT) < 0)
+            perror("CDIOCEJECT");
+    } else {
+        if (ioctl(s->fd, CDIOCCLOSE) < 0)
+            perror("CDIOCCLOSE");
+    }
+
+    if (cdrom_reopen(bs) < 0)
+        return -ENOTSUP;
+    return 0;
+}
+
+static int cdrom_set_locked(BlockDriverState *bs, int locked)
+{
+    BDRVRawState *s = bs->opaque;
+
+    if (s->fd < 0)
+        return -ENOTSUP;
+    if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
+        /*
+         * Note: an error can happen if the distribution automatically
+         * mounts the CD-ROM
+         */
+        /* perror("CDROM_LOCKDOOR"); */
+    }
+
+    return 0;
+}
+
+static BlockDriver bdrv_host_cdrom = {
+    .format_name        = "host_cdrom",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device	= cdrom_probe_device,
+    .bdrv_open          = cdrom_open,
+    .bdrv_close         = raw_close,
+    .bdrv_create        = hdev_create,
+    .bdrv_flush         = raw_flush,
+
+#ifdef CONFIG_AIO
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+#endif
+
+    .bdrv_read          = raw_read,
+    .bdrv_write         = raw_write,
+    .bdrv_getlength     = raw_getlength,
+
+    /* removable device support */
+    .bdrv_is_inserted   = cdrom_is_inserted,
+    .bdrv_eject         = cdrom_eject,
+    .bdrv_set_locked    = cdrom_set_locked,
+};
+#endif /* __FreeBSD__ */
+
+static void bdrv_raw_init(void)
+{
+    /*
+     * Register all the drivers.  Note that order is important, the driver
+     * registered last will get probed first.
+     */
+    bdrv_register(&bdrv_raw);
+    bdrv_register(&bdrv_host_device);
+#ifdef __linux__
+    bdrv_register(&bdrv_host_floppy);
+    bdrv_register(&bdrv_host_cdrom);
+#endif
+#ifdef __FreeBSD__
+    bdrv_register(&bdrv_host_cdrom);
+#endif
+}
+
+block_init(bdrv_raw_init);
diff --git a/block-raw-win32.c b/block/raw-win32.c
similarity index 63%
rename from block-raw-win32.c
rename to block/raw-win32.c
index 71404ac..72acad5 100644
--- a/block-raw-win32.c
+++ b/block/raw-win32.c
@@ -24,11 +24,10 @@
 #include "qemu-common.h"
 #include "qemu-timer.h"
 #include "block_int.h"
-#include <assert.h>
+#include "module.h"
+#include <windows.h>
 #include <winioctl.h>
 
-//#define WIN32_AIO
-
 #define FTYPE_FILE 0
 #define FTYPE_CD     1
 #define FTYPE_HARDDISK 2
@@ -39,13 +38,6 @@
     char drive_path[16]; /* format: "d:\" */
 } BDRVRawState;
 
-typedef struct RawAIOCB {
-    BlockDriverAIOCB common;
-    HANDLE hEvent;
-    OVERLAPPED ov;
-    int count;
-} RawAIOCB;
-
 int qemu_ftruncate64(int fd, int64_t length)
 {
     LARGE_INTEGER li;
@@ -99,13 +91,11 @@
     } else {
         create_flags = OPEN_EXISTING;
     }
-#ifdef WIN32_AIO
-    overlapped = FILE_FLAG_OVERLAPPED;
-#else
     overlapped = FILE_ATTRIBUTE_NORMAL;
-#endif
-    if (flags & BDRV_O_DIRECT)
+    if ((flags & BDRV_O_NOCACHE))
         overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
+    else if (!(flags & BDRV_O_CACHE_WB))
+        overlapped |= FILE_FLAG_WRITE_THROUGH;
     s->hfile = CreateFile(filename, access_flags,
                           FILE_SHARE_READ, NULL,
                           create_flags, overlapped, NULL);
@@ -119,149 +109,48 @@
     return 0;
 }
 
-static int raw_pread(BlockDriverState *bs, int64_t offset,
-                     uint8_t *buf, int count)
+static int raw_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
 {
     BDRVRawState *s = bs->opaque;
     OVERLAPPED ov;
     DWORD ret_count;
     int ret;
+    int64_t offset = sector_num * 512;
+    int count = nb_sectors * 512;
 
     memset(&ov, 0, sizeof(ov));
     ov.Offset = offset;
     ov.OffsetHigh = offset >> 32;
     ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
-    if (!ret) {
-#ifdef WIN32_AIO
-        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
-        if (!ret)
-            return -EIO;
-        else
-#endif
-            return ret_count;
-    }
+    if (!ret)
+        return ret_count;
+    if (ret_count == count)
+        ret_count = 0;
     return ret_count;
 }
 
-static int raw_pwrite(BlockDriverState *bs, int64_t offset,
-                      const uint8_t *buf, int count)
+static int raw_write(BlockDriverState *bs, int64_t sector_num,
+                     const uint8_t *buf, int nb_sectors)
 {
     BDRVRawState *s = bs->opaque;
     OVERLAPPED ov;
     DWORD ret_count;
     int ret;
+    int64_t offset = sector_num * 512;
+    int count = nb_sectors * 512;
 
     memset(&ov, 0, sizeof(ov));
     ov.Offset = offset;
     ov.OffsetHigh = offset >> 32;
     ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
-    if (!ret) {
-#ifdef WIN32_AIO
-        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
-        if (!ret)
-            return -EIO;
-        else
-#endif
-            return ret_count;
-    }
+    if (!ret)
+        return ret_count;
+    if (ret_count == count)
+        ret_count = 0;
     return ret_count;
 }
 
-#ifdef WIN32_AIO
-static void raw_aio_cb(void *opaque)
-{
-    RawAIOCB *acb = opaque;
-    BlockDriverState *bs = acb->common.bs;
-    BDRVRawState *s = bs->opaque;
-    DWORD ret_count;
-    int ret;
-
-    ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
-    if (!ret || ret_count != acb->count) {
-        acb->common.cb(acb->common.opaque, -EIO);
-    } else {
-        acb->common.cb(acb->common.opaque, 0);
-    }
-}
-
-static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    RawAIOCB *acb;
-    int64_t offset;
-
-    acb = qemu_aio_get(bs, cb, opaque);
-    if (acb->hEvent) {
-        acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-        if (!acb->hEvent) {
-            qemu_aio_release(acb);
-            return NULL;
-        }
-    }
-    memset(&acb->ov, 0, sizeof(acb->ov));
-    offset = sector_num * 512;
-    acb->ov.Offset = offset;
-    acb->ov.OffsetHigh = offset >> 32;
-    acb->ov.hEvent = acb->hEvent;
-    acb->count = nb_sectors * 512;
-    qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
-    return acb;
-}
-
-static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BDRVRawState *s = bs->opaque;
-    RawAIOCB *acb;
-    int ret;
-
-    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
-    if (!acb)
-        return NULL;
-    ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
-    if (!ret) {
-        qemu_aio_release(acb);
-        return NULL;
-    }
-    qemu_aio_release(acb);
-    return (BlockDriverAIOCB *)acb;
-}
-
-static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    BDRVRawState *s = bs->opaque;
-    RawAIOCB *acb;
-    int ret;
-
-    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
-    if (!acb)
-        return NULL;
-    ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
-    if (!ret) {
-        qemu_aio_release(acb);
-        return NULL;
-    }
-    qemu_aio_release(acb);
-    return (BlockDriverAIOCB *)acb;
-}
-
-static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
-{
-    RawAIOCB *acb = (RawAIOCB *)blockacb;
-    BlockDriverState *bs = acb->common.bs;
-    BDRVRawState *s = bs->opaque;
-
-    qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
-    /* XXX: if more than one async I/O it is not correct */
-    CancelIo(s->hfile);
-    qemu_aio_release(acb);
-}
-#endif /* #if WIN32_AIO */
-
 static void raw_flush(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
@@ -277,7 +166,7 @@
 static int raw_truncate(BlockDriverState *bs, int64_t offset)
 {
     BDRVRawState *s = bs->opaque;
-    DWORD low, high;
+    LONG low, high;
 
     low = offset;
     high = offset >> 32;
@@ -299,7 +188,7 @@
 
     switch(s->type) {
     case FTYPE_FILE:
-        l.LowPart = GetFileSize(s->hfile, &l.HighPart);
+        l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart);
         if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
             return -EIO;
         break;
@@ -321,13 +210,18 @@
     return l.QuadPart;
 }
 
-static int raw_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
+static int raw_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
+    int64_t total_size = 0;
 
-    if (flags || backing_file)
-        return -ENOTSUP;
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        }
+        options++;
+    }
 
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
@@ -339,40 +233,28 @@
     return 0;
 }
 
-void qemu_aio_init(void)
-{
-}
+static QEMUOptionParameter raw_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    { NULL }
+};
 
-void qemu_aio_flush(void)
-{
-}
+static BlockDriver bdrv_raw = {
+    .format_name	= "raw",
+    .instance_size	= sizeof(BDRVRawState),
+    .bdrv_open		= raw_open,
+    .bdrv_close		= raw_close,
+    .bdrv_create	= raw_create,
+    .bdrv_flush		= raw_flush,
+    .bdrv_read		= raw_read,
+    .bdrv_write		= raw_write,
+    .bdrv_truncate	= raw_truncate,
+    .bdrv_getlength	= raw_getlength,
 
-void qemu_aio_wait(void)
-{
-    qemu_bh_poll();
-}
-
-BlockDriver bdrv_raw = {
-    "raw",
-    sizeof(BDRVRawState),
-    NULL, /* no probe for protocols */
-    raw_open,
-    NULL,
-    NULL,
-    raw_close,
-    raw_create,
-    raw_flush,
-
-#ifdef WIN32_AIO
-    .bdrv_aio_read = raw_aio_read,
-    .bdrv_aio_write = raw_aio_write,
-    .bdrv_aio_cancel = raw_aio_cancel,
-    .aiocb_size = sizeof(RawAIOCB);
-#endif
-    .bdrv_pread = raw_pread,
-    .bdrv_pwrite = raw_pwrite,
-    .bdrv_truncate = raw_truncate,
-    .bdrv_getlength = raw_getlength,
+    .create_options = raw_create_options,
 };
 
 /***********************************************/
@@ -410,15 +292,29 @@
             return FTYPE_HARDDISK;
         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
         type = GetDriveType(s->drive_path);
-        if (type == DRIVE_CDROM)
+        switch (type) {
+        case DRIVE_REMOVABLE:
+        case DRIVE_FIXED:
+            return FTYPE_HARDDISK;
+        case DRIVE_CDROM:
             return FTYPE_CD;
-        else
+        default:
             return FTYPE_FILE;
+        }
     } else {
         return FTYPE_FILE;
     }
 }
 
+static int hdev_probe_device(const char *filename)
+{
+    if (strstart(filename, "/dev/cdrom", NULL))
+        return 100;
+    if (is_windows_drive(filename))
+        return 100;
+    return 0;
+}
+
 static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
@@ -448,13 +344,11 @@
     }
     create_flags = OPEN_EXISTING;
 
-#ifdef WIN32_AIO
-    overlapped = FILE_FLAG_OVERLAPPED;
-#else
     overlapped = FILE_ATTRIBUTE_NORMAL;
-#endif
-    if (flags & BDRV_O_DIRECT)
+    if ((flags & BDRV_O_NOCACHE))
         overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
+    else if (!(flags & BDRV_O_CACHE_WB))
+        overlapped |= FILE_FLAG_WRITE_THROUGH;
     s->hfile = CreateFile(filename, access_flags,
                           FILE_SHARE_READ, NULL,
                           create_flags, overlapped, NULL);
@@ -503,24 +397,23 @@
 }
 #endif
 
-BlockDriver bdrv_host_device = {
-    "host_device",
-    sizeof(BDRVRawState),
-    NULL, /* no probe for protocols */
-    hdev_open,
-    NULL,
-    NULL,
-    raw_close,
-    NULL,
-    raw_flush,
+static BlockDriver bdrv_host_device = {
+    .format_name	= "host_device",
+    .instance_size	= sizeof(BDRVRawState),
+    .bdrv_probe_device	= hdev_probe_device,
+    .bdrv_open		= hdev_open,
+    .bdrv_close		= raw_close,
+    .bdrv_flush		= raw_flush,
 
-#ifdef WIN32_AIO
-    .bdrv_aio_read = raw_aio_read,
-    .bdrv_aio_write = raw_aio_write,
-    .bdrv_aio_cancel = raw_aio_cancel,
-    .aiocb_size = sizeof(RawAIOCB);
-#endif
-    .bdrv_pread = raw_pread,
-    .bdrv_pwrite = raw_pwrite,
-    .bdrv_getlength = raw_getlength,
+    .bdrv_read		= raw_read,
+    .bdrv_write	        = raw_write,
+    .bdrv_getlength	= raw_getlength,
 };
+
+static void bdrv_raw_init(void)
+{
+    bdrv_register(&bdrv_raw);
+    bdrv_register(&bdrv_host_device);
+}
+
+block_init(bdrv_raw_init);
diff --git a/block-vmdk.c b/block/vmdk.c
similarity index 91%
rename from block-vmdk.c
rename to block/vmdk.c
index 8d67c2f..f21f02b 100644
--- a/block-vmdk.c
+++ b/block/vmdk.c
@@ -25,6 +25,7 @@
 
 #include "qemu-common.h"
 #include "block_int.h"
+#include "module.h"
 
 #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
 #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
@@ -134,7 +135,7 @@
         cid_str_size = sizeof("CID");
     }
 
-    if ((p_name = strstr(desc,cid_str)) != 0) {
+    if ((p_name = strstr(desc,cid_str)) != NULL) {
         p_name += cid_str_size;
         sscanf(p_name,"%x",&cid);
     }
@@ -154,7 +155,7 @@
 
     tmp_str = strstr(desc,"parentCID");
     pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
-    if ((p_name = strstr(desc,"CID")) != 0) {
+    if ((p_name = strstr(desc,"CID")) != NULL) {
         p_name += sizeof("CID");
         snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
         pstrcat(desc, sizeof(desc), tmp_desc);
@@ -239,7 +240,7 @@
     if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE)
         goto fail;
 
-    if ((p_name = strstr(p_desc,"CID")) != 0) {
+    if ((p_name = strstr(p_desc,"CID")) != NULL) {
         p_name += sizeof("CID");
         sscanf(p_name,"%x",&p_cid);
     }
@@ -276,8 +277,6 @@
 
     /* write RGD */
     rgd_buf = qemu_malloc(gd_size);
-    if (!rgd_buf)
-        goto fail;
     if (lseek(p_fd, rgd_offset, SEEK_SET) == -1)
         goto fail_rgd;
     if (read(p_fd, rgd_buf, gd_size) != gd_size)
@@ -290,8 +289,6 @@
 
     /* write GD */
     gd_buf = qemu_malloc(gd_size);
-    if (!gd_buf)
-        goto fail_rgd;
     if (lseek(p_fd, gd_offset, SEEK_SET) == -1)
         goto fail_gd;
     if (read(p_fd, gd_buf, gd_size) != gd_size)
@@ -322,7 +319,7 @@
         bdrv_close(bs->backing_hd);
 }
 
-int parent_open = 0;
+static int parent_open = 0;
 static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
 {
     BDRVVmdkState *s = bs->opaque;
@@ -334,17 +331,17 @@
     if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
         return -1;
 
-    if ((p_name = strstr(desc,"parentFileNameHint")) != 0) {
+    if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) {
         char *end_name;
         struct stat file_buf;
 
         p_name += sizeof("parentFileNameHint") + 1;
-        if ((end_name = strchr(p_name,'\"')) == 0)
+        if ((end_name = strchr(p_name,'\"')) == NULL)
             return -1;
         if ((end_name - p_name) > sizeof (s->hd->backing_file) - 1)
             return -1;
 
-        strncpy(s->hd->backing_file, p_name, end_name - p_name);
+        pstrcpy(s->hd->backing_file, end_name - p_name + 1, p_name);
         if (stat(s->hd->backing_file, &file_buf) != 0) {
             path_combine(parent_img_name, sizeof(parent_img_name),
                          filename, s->hd->backing_file);
@@ -430,8 +427,6 @@
     /* read the L1 table */
     l1_size = s->l1_size * sizeof(uint32_t);
     s->l1_table = qemu_malloc(l1_size);
-    if (!s->l1_table)
-        goto fail;
     if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
         goto fail;
     for(i = 0; i < s->l1_size; i++) {
@@ -440,8 +435,6 @@
 
     if (s->l1_backup_table_offset) {
         s->l1_backup_table = qemu_malloc(l1_size);
-        if (!s->l1_backup_table)
-            goto fail;
         if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
             goto fail;
         for(i = 0; i < s->l1_size; i++) {
@@ -450,8 +443,6 @@
     }
 
     s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
-    if (!s->l2_cache)
-        goto fail;
     return 0;
  fail:
     qemu_free(s->l1_backup_table);
@@ -696,8 +687,7 @@
     return 0;
 }
 
-static int vmdk_create(const char *filename, int64_t total_size,
-                       const char *backing_file, int flags)
+static int vmdk_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd, i;
     VMDK4Header header;
@@ -710,18 +700,33 @@
         "createType=\"monolithicSparse\"\n"
         "\n"
         "# Extent description\n"
-        "RW %lu SPARSE \"%s\"\n"
+        "RW %" PRId64 " SPARSE \"%s\"\n"
         "\n"
         "# The Disk Data Base \n"
         "#DDB\n"
         "\n"
         "ddb.virtualHWVersion = \"%d\"\n"
-        "ddb.geometry.cylinders = \"%lu\"\n"
+        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
         "ddb.geometry.heads = \"16\"\n"
         "ddb.geometry.sectors = \"63\"\n"
         "ddb.adapterType = \"ide\"\n";
     char desc[1024];
     const char *real_filename, *temp_str;
+    int64_t total_size = 0;
+    const char *backing_file = NULL;
+    int flags = 0;
+
+    // Read out options
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
+            flags |= options->value.n ? BLOCK_FLAG_COMPAT6: 0;
+        }
+        options++;
+    }
 
     /* XXX: add support for backing file */
     if (backing_file) {
@@ -792,8 +797,9 @@
     if ((temp_str = strrchr(real_filename, ':')) != NULL)
         real_filename = temp_str + 1;
     snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL),
-             (unsigned long)total_size, real_filename,
-             (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16));
+             total_size, real_filename,
+             (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
+             total_size / (int64_t)(63 * 16));
 
     /* write the descriptor */
     lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
@@ -820,15 +826,44 @@
     bdrv_flush(s->hd);
 }
 
-BlockDriver bdrv_vmdk = {
-    "vmdk",
-    sizeof(BDRVVmdkState),
-    vmdk_probe,
-    vmdk_open,
-    vmdk_read,
-    vmdk_write,
-    vmdk_close,
-    vmdk_create,
-    vmdk_flush,
-    vmdk_is_allocated,
+
+static QEMUOptionParameter vmdk_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    {
+        .name = BLOCK_OPT_BACKING_FILE,
+        .type = OPT_STRING,
+        .help = "File name of a base image"
+    },
+    {
+        .name = BLOCK_OPT_COMPAT6,
+        .type = OPT_FLAG,
+        .help = "VMDK version 6 image"
+    },
+    { NULL }
 };
+
+static BlockDriver bdrv_vmdk = {
+    .format_name	= "vmdk",
+    .instance_size	= sizeof(BDRVVmdkState),
+    .bdrv_probe		= vmdk_probe,
+    .bdrv_open		= vmdk_open,
+    .bdrv_read		= vmdk_read,
+    .bdrv_write		= vmdk_write,
+    .bdrv_close		= vmdk_close,
+    .bdrv_create	= vmdk_create,
+    .bdrv_flush		= vmdk_flush,
+    .bdrv_is_allocated	= vmdk_is_allocated,
+
+    .create_options = vmdk_create_options,
+};
+
+static void bdrv_vmdk_init(void)
+{
+    bdrv_register(&bdrv_vmdk);
+}
+
+block_init(bdrv_vmdk_init);
diff --git a/block/vpc.c b/block/vpc.c
new file mode 100644
index 0000000..ba482e9
--- /dev/null
+++ b/block/vpc.c
@@ -0,0 +1,623 @@
+/*
+ * Block driver for Conectix/Microsoft Virtual PC images
+ *
+ * Copyright (c) 2005 Alex Beregszaszi
+ * Copyright (c) 2009 Kevin Wolf <kwolf@suse.de>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "block_int.h"
+#include "module.h"
+
+/**************************************************************/
+
+#define HEADER_SIZE 512
+
+//#define CACHE
+
+enum vhd_type {
+    VHD_FIXED           = 2,
+    VHD_DYNAMIC         = 3,
+    VHD_DIFFERENCING    = 4,
+};
+
+// Seconds since Jan 1, 2000 0:00:00 (UTC)
+#define VHD_TIMESTAMP_BASE 946684800
+
+// always big-endian
+struct vhd_footer {
+    char        creator[8]; // "conectix"
+    uint32_t    features;
+    uint32_t    version;
+
+    // Offset of next header structure, 0xFFFFFFFF if none
+    uint64_t    data_offset;
+
+    // Seconds since Jan 1, 2000 0:00:00 (UTC)
+    uint32_t    timestamp;
+
+    char        creator_app[4]; // "vpc "
+    uint16_t    major;
+    uint16_t    minor;
+    char        creator_os[4]; // "Wi2k"
+
+    uint64_t    orig_size;
+    uint64_t    size;
+
+    uint16_t    cyls;
+    uint8_t     heads;
+    uint8_t     secs_per_cyl;
+
+    uint32_t    type;
+
+    // Checksum of the Hard Disk Footer ("one's complement of the sum of all
+    // the bytes in the footer without the checksum field")
+    uint32_t    checksum;
+
+    // UUID used to identify a parent hard disk (backing file)
+    uint8_t     uuid[16];
+
+    uint8_t     in_saved_state;
+};
+
+struct vhd_dyndisk_header {
+    char        magic[8]; // "cxsparse"
+
+    // Offset of next header structure, 0xFFFFFFFF if none
+    uint64_t    data_offset;
+
+    // Offset of the Block Allocation Table (BAT)
+    uint64_t    table_offset;
+
+    uint32_t    version;
+    uint32_t    max_table_entries; // 32bit/entry
+
+    // 2 MB by default, must be a power of two
+    uint32_t    block_size;
+
+    uint32_t    checksum;
+    uint8_t     parent_uuid[16];
+    uint32_t    parent_timestamp;
+    uint32_t    reserved;
+
+    // Backing file name (in UTF-16)
+    uint8_t     parent_name[512];
+
+    struct {
+        uint32_t    platform;
+        uint32_t    data_space;
+        uint32_t    data_length;
+        uint32_t    reserved;
+        uint64_t    data_offset;
+    } parent_locator[8];
+};
+
+typedef struct BDRVVPCState {
+    BlockDriverState *hd;
+
+    uint8_t footer_buf[HEADER_SIZE];
+    uint64_t free_data_block_offset;
+    int max_table_entries;
+    uint32_t *pagetable;
+    uint64_t bat_offset;
+    uint64_t last_bitmap_offset;
+
+    uint32_t block_size;
+    uint32_t bitmap_size;
+
+#ifdef CACHE
+    uint8_t *pageentry_u8;
+    uint32_t *pageentry_u32;
+    uint16_t *pageentry_u16;
+
+    uint64_t last_bitmap;
+#endif
+} BDRVVPCState;
+
+static uint32_t vpc_checksum(uint8_t* buf, size_t size)
+{
+    uint32_t res = 0;
+    int i;
+
+    for (i = 0; i < size; i++)
+        res += buf[i];
+
+    return ~res;
+}
+
+
+static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
+	return 100;
+    return 0;
+}
+
+static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVVPCState *s = bs->opaque;
+    int ret, i;
+    struct vhd_footer* footer;
+    struct vhd_dyndisk_header* dyndisk_header;
+    uint8_t buf[HEADER_SIZE];
+    uint32_t checksum;
+
+    ret = bdrv_file_open(&s->hd, filename, flags);
+    if (ret < 0)
+        return ret;
+
+    if (bdrv_pread(s->hd, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
+        goto fail;
+
+    footer = (struct vhd_footer*) s->footer_buf;
+    if (strncmp(footer->creator, "conectix", 8))
+        goto fail;
+
+    checksum = be32_to_cpu(footer->checksum);
+    footer->checksum = 0;
+    if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum)
+        fprintf(stderr, "block-vpc: The header checksum of '%s' is "
+            "incorrect.\n", filename);
+
+    // The visible size of a image in Virtual PC depends on the geometry
+    // rather than on the size stored in the footer (the size in the footer
+    // is too large usually)
+    bs->total_sectors = (int64_t)
+        be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
+
+    if (bdrv_pread(s->hd, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
+            != HEADER_SIZE)
+        goto fail;
+
+    dyndisk_header = (struct vhd_dyndisk_header*) buf;
+
+    if (strncmp(dyndisk_header->magic, "cxsparse", 8))
+        goto fail;
+
+
+    s->block_size = be32_to_cpu(dyndisk_header->block_size);
+    s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
+
+    s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
+    s->pagetable = qemu_malloc(s->max_table_entries * 4);
+
+    s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
+    if (bdrv_pread(s->hd, s->bat_offset, s->pagetable,
+            s->max_table_entries * 4) != s->max_table_entries * 4)
+	    goto fail;
+
+    s->free_data_block_offset =
+        (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
+
+    for (i = 0; i < s->max_table_entries; i++) {
+        be32_to_cpus(&s->pagetable[i]);
+        if (s->pagetable[i] != 0xFFFFFFFF) {
+            int64_t next = (512 * (int64_t) s->pagetable[i]) +
+                s->bitmap_size + s->block_size;
+
+            if (next> s->free_data_block_offset)
+                s->free_data_block_offset = next;
+        }
+    }
+
+    s->last_bitmap_offset = (int64_t) -1;
+
+#ifdef CACHE
+    s->pageentry_u8 = qemu_malloc(512);
+    s->pageentry_u32 = s->pageentry_u8;
+    s->pageentry_u16 = s->pageentry_u8;
+    s->last_pagetable = -1;
+#endif
+
+    return 0;
+ fail:
+    bdrv_delete(s->hd);
+    return -1;
+}
+
+/*
+ * Returns the absolute byte offset of the given sector in the image file.
+ * If the sector is not allocated, -1 is returned instead.
+ *
+ * The parameter write must be 1 if the offset will be used for a write
+ * operation (the block bitmaps is updated then), 0 otherwise.
+ */
+static inline int64_t get_sector_offset(BlockDriverState *bs,
+    int64_t sector_num, int write)
+{
+    BDRVVPCState *s = bs->opaque;
+    uint64_t offset = sector_num * 512;
+    uint64_t bitmap_offset, block_offset;
+    uint32_t pagetable_index, pageentry_index;
+
+    pagetable_index = offset / s->block_size;
+    pageentry_index = (offset % s->block_size) / 512;
+
+    if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
+        return -1; // not allocated
+
+    bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
+    block_offset = bitmap_offset + s->bitmap_size + (512 * pageentry_index);
+
+    // We must ensure that we don't write to any sectors which are marked as
+    // unused in the bitmap. We get away with setting all bits in the block
+    // bitmap each time we write to a new block. This might cause Virtual PC to
+    // miss sparse read optimization, but it's not a problem in terms of
+    // correctness.
+    if (write && (s->last_bitmap_offset != bitmap_offset)) {
+        uint8_t bitmap[s->bitmap_size];
+
+        s->last_bitmap_offset = bitmap_offset;
+        memset(bitmap, 0xff, s->bitmap_size);
+        bdrv_pwrite(s->hd, bitmap_offset, bitmap, s->bitmap_size);
+    }
+
+//    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
+//	sector_num, pagetable_index, pageentry_index,
+//	bitmap_offset, block_offset);
+
+// disabled by reason
+#if 0
+#ifdef CACHE
+    if (bitmap_offset != s->last_bitmap)
+    {
+	lseek(s->fd, bitmap_offset, SEEK_SET);
+
+	s->last_bitmap = bitmap_offset;
+
+	// Scary! Bitmap is stored as big endian 32bit entries,
+	// while we used to look it up byte by byte
+	read(s->fd, s->pageentry_u8, 512);
+	for (i = 0; i < 128; i++)
+	    be32_to_cpus(&s->pageentry_u32[i]);
+    }
+
+    if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
+	return -1;
+#else
+    lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
+
+    read(s->fd, &bitmap_entry, 1);
+
+    if ((bitmap_entry >> (pageentry_index % 8)) & 1)
+	return -1; // not allocated
+#endif
+#endif
+
+    return block_offset;
+}
+
+/*
+ * Writes the footer to the end of the image file. This is needed when the
+ * file grows as it overwrites the old footer
+ *
+ * Returns 0 on success and < 0 on error
+ */
+static int rewrite_footer(BlockDriverState* bs)
+{
+    int ret;
+    BDRVVPCState *s = bs->opaque;
+    int64_t offset = s->free_data_block_offset;
+
+    ret = bdrv_pwrite(s->hd, offset, s->footer_buf, HEADER_SIZE);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+/*
+ * Allocates a new block. This involves writing a new footer and updating
+ * the Block Allocation Table to use the space at the old end of the image
+ * file (overwriting the old footer)
+ *
+ * Returns the sectors' offset in the image file on success and < 0 on error
+ */
+static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
+{
+    BDRVVPCState *s = bs->opaque;
+    int64_t bat_offset;
+    uint32_t index, bat_value;
+    int ret;
+    uint8_t bitmap[s->bitmap_size];
+
+    // Check if sector_num is valid
+    if ((sector_num < 0) || (sector_num > bs->total_sectors))
+        return -1;
+
+    // Write entry into in-memory BAT
+    index = (sector_num * 512) / s->block_size;
+    if (s->pagetable[index] != 0xFFFFFFFF)
+        return -1;
+
+    s->pagetable[index] = s->free_data_block_offset / 512;
+
+    // Initialize the block's bitmap
+    memset(bitmap, 0xff, s->bitmap_size);
+    bdrv_pwrite(s->hd, s->free_data_block_offset, bitmap, s->bitmap_size);
+
+    // Write new footer (the old one will be overwritten)
+    s->free_data_block_offset += s->block_size + s->bitmap_size;
+    ret = rewrite_footer(bs);
+    if (ret < 0)
+        goto fail;
+
+    // Write BAT entry to disk
+    bat_offset = s->bat_offset + (4 * index);
+    bat_value = be32_to_cpu(s->pagetable[index]);
+    ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4);
+    if (ret < 0)
+        goto fail;
+
+    return get_sector_offset(bs, sector_num, 0);
+
+fail:
+    s->free_data_block_offset -= (s->block_size + s->bitmap_size);
+    return -1;
+}
+
+static int vpc_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVVPCState *s = bs->opaque;
+    int ret;
+    int64_t offset;
+
+    while (nb_sectors > 0) {
+        offset = get_sector_offset(bs, sector_num, 0);
+
+        if (offset == -1) {
+            memset(buf, 0, 512);
+        } else {
+            ret = bdrv_pread(s->hd, offset, buf, 512);
+            if (ret != 512)
+                return -1;
+        }
+
+        nb_sectors--;
+        sector_num++;
+        buf += 512;
+    }
+    return 0;
+}
+
+static int vpc_write(BlockDriverState *bs, int64_t sector_num,
+    const uint8_t *buf, int nb_sectors)
+{
+    BDRVVPCState *s = bs->opaque;
+    int64_t offset;
+    int ret;
+
+    while (nb_sectors > 0) {
+        offset = get_sector_offset(bs, sector_num, 1);
+
+        if (offset == -1) {
+            offset = alloc_block(bs, sector_num);
+            if (offset < 0)
+                return -1;
+        }
+
+        ret = bdrv_pwrite(s->hd, offset, buf, 512);
+        if (ret != 512)
+            return -1;
+
+        nb_sectors--;
+        sector_num++;
+        buf += 512;
+    }
+
+    return 0;
+}
+
+
+/*
+ * Calculates the number of cylinders, heads and sectors per cylinder
+ * based on a given number of sectors. This is the algorithm described
+ * in the VHD specification.
+ *
+ * Note that the geometry doesn't always exactly match total_sectors but
+ * may round it down.
+ *
+ * Returns 0 on success, -EFBIG if the size is larger than 127 GB
+ */
+static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
+    uint8_t* heads, uint8_t* secs_per_cyl)
+{
+    uint32_t cyls_times_heads;
+
+    if (total_sectors > 65535 * 16 * 255)
+        return -EFBIG;
+
+    if (total_sectors > 65535 * 16 * 63) {
+        *secs_per_cyl = 255;
+        *heads = 16;
+        cyls_times_heads = total_sectors / *secs_per_cyl;
+    } else {
+        *secs_per_cyl = 17;
+        cyls_times_heads = total_sectors / *secs_per_cyl;
+        *heads = (cyls_times_heads + 1023) / 1024;
+
+        if (*heads < 4)
+            *heads = 4;
+
+        if (cyls_times_heads >= (*heads * 1024) || *heads > 16) {
+            *secs_per_cyl = 31;
+            *heads = 16;
+            cyls_times_heads = total_sectors / *secs_per_cyl;
+        }
+
+        if (cyls_times_heads >= (*heads * 1024)) {
+            *secs_per_cyl = 63;
+            *heads = 16;
+            cyls_times_heads = total_sectors / *secs_per_cyl;
+        }
+    }
+
+    // Note: Rounding up deviates from the Virtual PC behaviour
+    // However, we need this to avoid truncating images in qemu-img convert
+    *cyls = (cyls_times_heads + *heads - 1) / *heads;
+
+    return 0;
+}
+
+static int vpc_create(const char *filename, QEMUOptionParameter *options)
+{
+    uint8_t buf[1024];
+    struct vhd_footer* footer = (struct vhd_footer*) buf;
+    struct vhd_dyndisk_header* dyndisk_header =
+        (struct vhd_dyndisk_header*) buf;
+    int fd, i;
+    uint16_t cyls;
+    uint8_t heads;
+    uint8_t secs_per_cyl;
+    size_t block_size, num_bat_entries;
+    int64_t total_sectors = 0;
+
+    // Read out options
+    while (options && options->name) {
+        if (!strcmp(options->name, "size")) {
+            total_sectors = options->value.n / 512;
+        }
+        options++;
+    }
+
+    // Create the file
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0)
+        return -EIO;
+
+    // Calculate matching total_size and geometry
+    if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl))
+        return -EFBIG;
+    total_sectors = (int64_t) cyls * heads * secs_per_cyl;
+
+    // Prepare the Hard Disk Footer
+    memset(buf, 0, 1024);
+
+    strncpy(footer->creator, "conectix", 8);
+    // TODO Check if "qemu" creator_app is ok for VPC
+    strncpy(footer->creator_app, "qemu", 4);
+    strncpy(footer->creator_os, "Wi2k", 4);
+
+    footer->features = be32_to_cpu(0x02);
+    footer->version = be32_to_cpu(0x00010000);
+    footer->data_offset = be64_to_cpu(HEADER_SIZE);
+    footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
+
+    // Version of Virtual PC 2007
+    footer->major = be16_to_cpu(0x0005);
+    footer->minor =be16_to_cpu(0x0003);
+
+    footer->orig_size = be64_to_cpu(total_sectors * 512);
+    footer->size = be64_to_cpu(total_sectors * 512);
+
+    footer->cyls = be16_to_cpu(cyls);
+    footer->heads = heads;
+    footer->secs_per_cyl = secs_per_cyl;
+
+    footer->type = be32_to_cpu(VHD_DYNAMIC);
+
+    // TODO uuid is missing
+
+    footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
+
+    // Write the footer (twice: at the beginning and at the end)
+    block_size = 0x200000;
+    num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
+
+    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
+        return -EIO;
+
+    if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0)
+        return -EIO;
+    if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
+        return -EIO;
+
+    // Write the initial BAT
+    if (lseek(fd, 3 * 512, SEEK_SET) < 0)
+        return -EIO;
+
+    memset(buf, 0xFF, 512);
+    for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++)
+        if (write(fd, buf, 512) != 512)
+            return -EIO;
+
+
+    // Prepare the Dynamic Disk Header
+    memset(buf, 0, 1024);
+
+    strncpy(dyndisk_header->magic, "cxsparse", 8);
+
+    dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFF);
+    dyndisk_header->table_offset = be64_to_cpu(3 * 512);
+    dyndisk_header->version = be32_to_cpu(0x00010000);
+    dyndisk_header->block_size = be32_to_cpu(block_size);
+    dyndisk_header->max_table_entries = be32_to_cpu(num_bat_entries);
+
+    dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
+
+    // Write the header
+    if (lseek(fd, 512, SEEK_SET) < 0)
+        return -EIO;
+    if (write(fd, buf, 1024) != 1024)
+        return -EIO;
+
+    close(fd);
+    return 0;
+}
+
+static void vpc_close(BlockDriverState *bs)
+{
+    BDRVVPCState *s = bs->opaque;
+    qemu_free(s->pagetable);
+#ifdef CACHE
+    qemu_free(s->pageentry_u8);
+#endif
+    bdrv_delete(s->hd);
+}
+
+static QEMUOptionParameter vpc_create_options[] = {
+    {
+        .name = BLOCK_OPT_SIZE,
+        .type = OPT_SIZE,
+        .help = "Virtual disk size"
+    },
+    { NULL }
+};
+
+static BlockDriver bdrv_vpc = {
+    .format_name	= "vpc",
+    .instance_size	= sizeof(BDRVVPCState),
+    .bdrv_probe		= vpc_probe,
+    .bdrv_open		= vpc_open,
+    .bdrv_read		= vpc_read,
+    .bdrv_write		= vpc_write,
+    .bdrv_close		= vpc_close,
+    .bdrv_create	= vpc_create,
+
+    .create_options = vpc_create_options,
+};
+
+static void bdrv_vpc_init(void)
+{
+    bdrv_register(&bdrv_vpc);
+}
+
+block_init(bdrv_vpc_init);
diff --git a/block-vvfat.c b/block/vvfat.c
similarity index 96%
rename from block-vvfat.c
rename to block/vvfat.c
index 79804a7..1e37b9f 100644
--- a/block-vvfat.c
+++ b/block/vvfat.c
@@ -24,9 +24,9 @@
  */
 #include <sys/stat.h>
 #include <dirent.h>
-#include <assert.h>
 #include "qemu-common.h"
 #include "block_int.h"
+#include "module.h"
 
 #ifndef S_IWGRP
 #define S_IWGRP 0
@@ -78,7 +78,7 @@
 
 static inline void array_init(array_t* array,unsigned int item_size)
 {
-    array->pointer=0;
+    array->pointer = NULL;
     array->size=0;
     array->next=0;
     array->item_size=item_size;
@@ -129,7 +129,7 @@
 	int increment=count*array->item_size;
 	array->pointer=qemu_realloc(array->pointer,array->size+increment);
 	if(!array->pointer)
-	    return 0;
+            return NULL;
 	array->size+=increment;
     }
     memmove(array->pointer+(index+count)*array->item_size,
@@ -159,7 +159,7 @@
     is=array->item_size;
     from=array->pointer+index_from*is;
     to=array->pointer+index_to*is;
-    buf=malloc(is*count);
+    buf=qemu_malloc(is*count);
     memcpy(buf,from,is*count);
 
     if(index_to<index_from)
@@ -509,9 +509,12 @@
     uint8_t chksum=0;
     int i;
 
-    for(i=0;i<11;i++)
-	chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
-	    +(unsigned char)entry->name[i];
+    for(i=0;i<11;i++) {
+        unsigned char c;
+
+        c = (i <= 8) ? entry->name[i] : entry->extension[i-8];
+        chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c;
+    }
 
     return chksum;
 }
@@ -604,8 +607,8 @@
 	unsigned int directory_start, const char* filename, int is_dot)
 {
     int i,j,long_index=s->directory.next;
-    direntry_t* entry=0;
-    direntry_t* entry_long=0;
+    direntry_t* entry = NULL;
+    direntry_t* entry_long = NULL;
 
     if(is_dot) {
 	entry=array_get_next(&(s->directory));
@@ -625,7 +628,7 @@
 
     entry=array_get_next(&(s->directory));
     memset(entry->name,0x20,11);
-    strncpy((char*)entry->name,filename,i);
+    memcpy(entry->name, filename, i);
 
     if(j > 0)
 	for (i = 0; i < 3 && filename[j+1+i]; i++)
@@ -696,7 +699,7 @@
     int first_cluster = mapping->begin;
     int parent_index = mapping->info.dir.parent_mapping_index;
     mapping_t* parent_mapping = (mapping_t*)
-	(parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
+        (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL);
     int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
 
     DIR* dir=opendir(dirname);
@@ -725,8 +728,7 @@
 	if(first_cluster == 0 && (is_dotdot || is_dot))
 	    continue;
 
-	buffer=(char*)malloc(length);
-	assert(buffer);
+	buffer=(char*)qemu_malloc(length);
 	snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
 
 	if(stat(buffer,&st)<0) {
@@ -847,8 +849,7 @@
     memset(&(s->first_sectors[0]),0,0x40*0x200);
 
     s->cluster_size=s->sectors_per_cluster*0x200;
-    s->cluster_buffer=malloc(s->cluster_size);
-    assert(s->cluster_buffer);
+    s->cluster_buffer=qemu_malloc(s->cluster_size);
 
     /*
      * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
@@ -890,7 +891,6 @@
     s->path = mapping->path;
 
     for (i = 0, cluster = 0; i < s->mapping.next; i++) {
-	int j;
 	/* MS-DOS expects the FAT to be 0 for the root directory
 	 * (except for the media byte). */
 	/* LATER TODO: still true for FAT32? */
@@ -923,19 +923,24 @@
 
 	assert(mapping->begin < mapping->end);
 
-	/* fix fat for entry */
-	if (fix_fat) {
-	    for(j = mapping->begin; j < mapping->end - 1; j++)
-		fat_set(s, j, j+1);
-	    fat_set(s, mapping->end - 1, s->max_fat_value);
-	}
-
 	/* next free cluster */
 	cluster = mapping->end;
 
 	if(cluster > s->cluster_count) {
-	    fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
-	    return -1;
+	    fprintf(stderr,"Directory does not fit in FAT%d (capacity %s)\n",
+		    s->fat_type,
+		    s->fat_type == 12 ? s->sector_count == 2880 ? "1.44 MB"
+								: "2.88 MB"
+				      : "504MB");
+	    return -EINVAL;
+	}
+
+	/* fix fat for entry */
+	if (fix_fat) {
+	    int j;
+	    for(j = mapping->begin; j < mapping->end - 1; j++)
+		fat_set(s, j, j+1);
+	    fat_set(s, mapping->end - 1, s->max_fat_value);
 	}
     }
 
@@ -1052,7 +1057,7 @@
 
     i = strrchr(dirname, ':') - dirname;
     assert(i >= 3);
-    if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
+    if (dirname[i-2] == ':' && qemu_isalpha(dirname[i-1]))
 	/* workaround for DOS drive names */
 	dirname += i-1;
     else
@@ -1123,10 +1128,10 @@
     int index=find_mapping_for_cluster_aux(s,cluster_num,0,s->mapping.next);
     mapping_t* mapping;
     if(index>=s->mapping.next)
-	return 0;
+        return NULL;
     mapping=array_get(&(s->mapping),index);
     if(mapping->begin>cluster_num)
-	return 0;
+        return NULL;
     assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
     return mapping;
 }
@@ -1245,7 +1250,7 @@
 	unsigned char* c=(unsigned char*)direntry;
 	int i;
 	for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
-#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
+#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = 0xb0; j++;}
 	    ADD_CHAR(c[i]);
 	for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
 	    ADD_CHAR(c[i]);
@@ -1481,7 +1486,7 @@
 	if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
 	    return -1;
 	else if (s->downcase_short_names)
-	    lfn->name[i] = tolower(direntry->name[i]);
+	    lfn->name[i] = qemu_tolower(direntry->name[i]);
 	else
 	    lfn->name[i] = direntry->name[i];
     }
@@ -1494,7 +1499,7 @@
 	    if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
 		return -2;
 	    else if (s->downcase_short_names)
-		lfn->name[i + j] = tolower(direntry->extension[j]);
+		lfn->name[i + j] = qemu_tolower(direntry->extension[j]);
 	    else
 		lfn->name[i + j] = direntry->extension[j];
 	}
@@ -1724,7 +1729,7 @@
 	int cluster_num, const char* path)
 {
     int ret = 0;
-    unsigned char* cluster = malloc(s->cluster_size);
+    unsigned char* cluster = qemu_malloc(s->cluster_size);
     direntry_t* direntries = (direntry_t*)cluster;
     mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
 
@@ -1776,7 +1781,7 @@
 	}
 
 	for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
-	    int cluster_count;
+	    int cluster_count = 0;
 
 DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
 	    if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
@@ -1865,7 +1870,7 @@
      */
     if (s->fat2 == NULL) {
 	int size = 0x200 * s->sectors_per_fat;
-	s->fat2 = malloc(size);
+	s->fat2 = qemu_malloc(size);
 	memcpy(s->fat2, s->fat.pointer, size);
     }
     check = vvfat_read(s->bs,
@@ -2207,7 +2212,7 @@
     uint32_t first_cluster = c;
     mapping_t* mapping = find_mapping_for_cluster(s, c);
     uint32_t size = filesize_of_direntry(direntry);
-    char* cluster = malloc(s->cluster_size);
+    char* cluster = qemu_malloc(s->cluster_size);
     uint32_t i;
     int fd = 0;
 
@@ -2369,7 +2374,7 @@
 			    mapping_t* m = find_mapping_for_cluster(s,
 				    begin_of_direntry(d));
 			    int l = strlen(m->path);
-			    char* new_path = malloc(l + diff + 1);
+			    char* new_path = qemu_malloc(l + diff + 1);
 
 			    assert(!strncmp(m->path, mapping->path, l2));
 
@@ -2757,23 +2762,29 @@
 }
 
 static BlockDriver vvfat_write_target = {
-    "vvfat_write_target", 0, NULL, NULL, NULL,
-    write_target_commit,
-    write_target_close,
-    NULL, NULL, NULL
+    .format_name        = "vvfat_write_target",
+    .bdrv_write         = write_target_commit,
+    .bdrv_close         = write_target_close,
 };
 
 static int enable_write_target(BDRVVVFATState *s)
 {
+    BlockDriver *bdrv_qcow;
+    QEMUOptionParameter *options;
     int size = sector2cluster(s, s->sector_count);
     s->used_clusters = calloc(size, 1);
 
     array_init(&(s->commits), sizeof(commit_t));
 
-    s->qcow_filename = malloc(1024);
+    s->qcow_filename = qemu_malloc(1024);
     get_tmp_filename(s->qcow_filename, 1024);
-    if (bdrv_create(&bdrv_qcow,
-		s->qcow_filename, s->sector_count, "fat:", 0) < 0)
+
+    bdrv_qcow = bdrv_find_format("qcow");
+    options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
+    set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
+    set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
+
+    if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
 	return -1;
     s->qcow = bdrv_new("");
     if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
@@ -2802,20 +2813,24 @@
         free(s->cluster_buffer);
 }
 
-BlockDriver bdrv_vvfat = {
-    "vvfat",
-    sizeof(BDRVVVFATState),
-    NULL, /* no probe for protocols */
-    vvfat_open,
-    vvfat_read,
-    vvfat_write,
-    vvfat_close,
-    NULL, /* ??? Not sure if we can do any meaningful flushing.  */
-    NULL,
-    vvfat_is_allocated,
-    .protocol_name = "fat",
+static BlockDriver bdrv_vvfat = {
+    .format_name	= "vvfat",
+    .instance_size	= sizeof(BDRVVVFATState),
+    .bdrv_open		= vvfat_open,
+    .bdrv_read		= vvfat_read,
+    .bdrv_write		= vvfat_write,
+    .bdrv_close		= vvfat_close,
+    .bdrv_is_allocated	= vvfat_is_allocated,
+    .protocol_name	= "fat",
 };
 
+static void bdrv_vvfat_init(void)
+{
+    bdrv_register(&bdrv_vvfat);
+}
+
+block_init(bdrv_vvfat_init);
+
 #ifdef DEBUG
 static void checkpoint(void) {
     assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
@@ -2844,4 +2859,3 @@
     print_direntry(NULL);
 }
 #endif
-
diff --git a/block_int.h b/block_int.h
index 137000e..830b7e9 100644
--- a/block_int.h
+++ b/block_int.h
@@ -25,43 +25,51 @@
 #define BLOCK_INT_H
 
 #include "block.h"
+#include "qemu-option.h"
 
 #define BLOCK_FLAG_ENCRYPT	1
 #define BLOCK_FLAG_COMPRESS	2
 #define BLOCK_FLAG_COMPAT6	4
 
+#define BLOCK_OPT_SIZE          "size"
+#define BLOCK_OPT_ENCRYPT       "encryption"
+#define BLOCK_OPT_COMPAT6       "compat6"
+#define BLOCK_OPT_BACKING_FILE  "backing_file"
+#define BLOCK_OPT_BACKING_FMT   "backing_fmt"
+#define BLOCK_OPT_CLUSTER_SIZE  "cluster_size"
+
+typedef struct AIOPool {
+    void (*cancel)(BlockDriverAIOCB *acb);
+    int aiocb_size;
+    BlockDriverAIOCB *free_aiocb;
+} AIOPool;
+
 struct BlockDriver {
     const char *format_name;
     int instance_size;
     int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
+    int (*bdrv_probe_device)(const char *filename);
     int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
     int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
                      uint8_t *buf, int nb_sectors);
     int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
-    int (*bdrv_create)(const char *filename, int64_t total_sectors,
-                       const char *backing_file, int flags);
+    int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
     void (*bdrv_flush)(BlockDriverState *bs);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
     int (*bdrv_make_empty)(BlockDriverState *bs);
     /* aio */
-    BlockDriverAIOCB *(*bdrv_aio_read)(BlockDriverState *bs,
-        int64_t sector_num, uint8_t *buf, int nb_sectors,
+    BlockDriverAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
-    BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs,
-        int64_t sector_num, const uint8_t *buf, int nb_sectors,
+    BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
-    void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
-    int aiocb_size;
 
     const char *protocol_name;
-    int (*bdrv_pread)(BlockDriverState *bs, int64_t offset,
-                      uint8_t *buf, int count);
-    int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset,
-                       const uint8_t *buf, int count);
     int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
     int64_t (*bdrv_getlength)(BlockDriverState *bs);
     int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
@@ -76,6 +84,11 @@
                               QEMUSnapshotInfo **psn_info);
     int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
 
+    int (*bdrv_put_buffer)(BlockDriverState *bs, const uint8_t *buf,
+                           int64_t pos, int size);
+    int (*bdrv_get_buffer)(BlockDriverState *bs, uint8_t *buf,
+                           int64_t pos, int size);
+
     /* removable device specific */
     int (*bdrv_is_inserted)(BlockDriverState *bs);
     int (*bdrv_media_changed)(BlockDriverState *bs);
@@ -84,8 +97,17 @@
 
     /* to control generic scsi devices */
     int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
+    BlockDriverAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs,
+        unsigned long int req, void *buf,
+        BlockDriverCompletionFunc *cb, void *opaque);
 
-    BlockDriverAIOCB *free_aiocb;
+    /* List of options for creating images, terminated by name == NULL */
+    QEMUOptionParameter *create_options;
+
+
+    /* Returns number of errors in image, -errno for internal errors */
+    int (*bdrv_check)(BlockDriverState* bs);
+
     struct BlockDriver *next;
 };
 
@@ -96,6 +118,7 @@
     int removable; /* if true, the media can be removed */
     int locked;    /* if true, the media cannot temporarily be ejected */
     int encrypted; /* if true, the media is encrypted */
+    int valid_key; /* if true, a valid encryption key has been set */
     int sg;        /* if true, the device is a /dev/sg* */
     /* event callback when inserting/removing */
     void (*change_cb)(void *opaque);
@@ -104,12 +127,10 @@
     BlockDriver *drv; /* NULL means no media */
     void *opaque;
 
-    int boot_sector_enabled;
-    uint8_t boot_sector_data[512];
-
     char filename[1024];
     char backing_file[1024]; /* if non zero, the image is a diff of
                                 this file image */
+    char backing_format[16]; /* if non-zero and backing_file exists */
     int is_temporary;
     int media_changed;
 
@@ -124,15 +145,23 @@
     uint64_t rd_ops;
     uint64_t wr_ops;
 
+    /* Whether the disk can expand beyond total_sectors */
+    int growable;
+
+    /* the memory alignment required for the buffers handled by this driver */
+    int buffer_alignment;
+
     /* NOTE: the following infos are only hints for real hardware
        drivers. They are not used by the block driver */
     int cyls, heads, secs, translation;
     int type;
     char device_name[32];
     BlockDriverState *next;
+    void *private;
 };
 
 struct BlockDriverAIOCB {
+    AIOPool *pool;
     BlockDriverState *bs;
     BlockDriverCompletionFunc *cb;
     void *opaque;
@@ -141,10 +170,16 @@
 
 void get_tmp_filename(char *filename, int size);
 
-void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
-                   void *opaque);
+void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
+                   BlockDriverCompletionFunc *cb, void *opaque);
 void qemu_aio_release(void *p);
 
-BlockDriverState *bdrv_first;
+void *qemu_blockalign(BlockDriverState *bs, size_t size);
+
+extern BlockDriverState *bdrv_first;
+
+#ifdef _WIN32
+int is_windows_drive(const char *filename);
+#endif
 
 #endif /* BLOCK_INT_H */
diff --git a/bswap.h b/bswap.h
index 523d805..1dd357e 100644
--- a/bswap.h
+++ b/bswap.h
@@ -5,6 +5,12 @@
 
 #include <inttypes.h>
 
+#ifdef HAVE_MACHINE_BSWAP_H
+#include <sys/endian.h>
+#include <sys/types.h>
+#include <machine/bswap.h>
+#else
+
 #ifdef HAVE_BYTESWAP_H
 #include <byteswap.h>
 #else
@@ -58,6 +64,8 @@
     return bswap_64(x);
 }
 
+#endif /* ! HAVE_MACHINE_BSWAP_H */
+
 static inline void bswap16s(uint16_t *s)
 {
     *s = bswap16(*s);
@@ -126,7 +134,7 @@
 
 /* unaligned versions (optimized for frequent unaligned accesses)*/
 
-#if defined(__i386__) || defined(__powerpc__)
+#if defined(__i386__) || defined(_ARCH_PPC)
 
 #define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
 #define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
@@ -143,7 +151,7 @@
 {
     uint8_t *p1 = (uint8_t *)p;
 
-    p1[0] = v;
+    p1[0] = v & 0xff;
     p1[1] = v >> 8;
 }
 
@@ -151,7 +159,7 @@
 {
     uint8_t *p1 = (uint8_t *)p;
 
-    p1[0] = v;
+    p1[0] = v & 0xff;
     p1[1] = v >> 8;
     p1[2] = v >> 16;
     p1[3] = v >> 24;
@@ -180,7 +188,7 @@
     uint8_t *p1 = (uint8_t *)p;
 
     p1[0] = v >> 8;
-    p1[1] = v;
+    p1[1] = v & 0xff;
 }
 
 static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
@@ -190,7 +198,7 @@
     p1[0] = v >> 24;
     p1[1] = v >> 16;
     p1[2] = v >> 8;
-    p1[3] = v;
+    p1[3] = v & 0xff;
 }
 
 #endif
diff --git a/bt-host.c b/bt-host.c
new file mode 100644
index 0000000..9a06578
--- /dev/null
+++ b/bt-host.c
@@ -0,0 +1,207 @@
+/*
+ * Wrap a host Bluetooth HCI socket in a struct HCIInfo.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "net.h"
+#include "bt-host.h"
+
+#ifndef _WIN32
+# include <errno.h>
+# include <sys/ioctl.h>
+# include <sys/uio.h>
+# ifdef CONFIG_BLUEZ
+#  include <bluetooth/bluetooth.h>
+#  include <bluetooth/hci.h>
+#  include <bluetooth/hci_lib.h>
+# else
+#  include "hw/bt.h"
+#  define HCI_MAX_FRAME_SIZE	1028
+# endif
+
+struct bt_host_hci_s {
+    struct HCIInfo hci;
+    int fd;
+
+    uint8_t hdr[HCI_MAX_FRAME_SIZE];
+    int len;
+};
+
+static void bt_host_send(struct HCIInfo *hci,
+                int type, const uint8_t *data, int len)
+{
+    struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci;
+    uint8_t pkt = type;
+    struct iovec iv[2];
+    int ret;
+
+    iv[0].iov_base = (void *)&pkt;
+    iv[0].iov_len  = 1;
+    iv[1].iov_base = (void *) data;
+    iv[1].iov_len  = len;
+
+    while ((ret = writev(s->fd, iv, 2)) < 0)
+        if (errno != EAGAIN && errno != EINTR) {
+            fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
+                            errno);
+            return;
+        }
+}
+
+static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+    bt_host_send(hci, HCI_COMMAND_PKT, data, len);
+}
+
+static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+    bt_host_send(hci, HCI_ACLDATA_PKT, data, len);
+}
+
+static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+    bt_host_send(hci, HCI_SCODATA_PKT, data, len);
+}
+
+static int bt_host_read_poll(void *opaque)
+{
+    struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
+
+    return !!s->hci.evt_recv;
+}
+
+static void bt_host_read(void *opaque)
+{
+    struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
+    uint8_t *pkt;
+    int pktlen;
+
+    /* Seems that we can't read only the header first and then the amount
+     * of data indicated in the header because Linux will discard everything
+     * that's not been read in one go.  */
+    s->len = read(s->fd, s->hdr, sizeof(s->hdr));
+
+    if (s->len < 0) {
+        fprintf(stderr, "qemu: error %i reading HCI frame\n", errno);
+        return;
+    }
+
+    pkt = s->hdr;
+    while (s->len --)
+        switch (*pkt ++) {
+        case HCI_EVENT_PKT:
+            if (s->len < 2)
+                goto bad_pkt;
+
+            pktlen = MIN(pkt[1] + 2, s->len);
+            s->hci.evt_recv(s->hci.opaque, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+
+            /* TODO: if this is an Inquiry Result event, it's also
+             * interpreted by Linux kernel before we received it, possibly
+             * we should clean the kernel Inquiry cache through
+             * ioctl(s->fd, HCI_INQUIRY, ...).  */
+            break;
+
+        case HCI_ACLDATA_PKT:
+            if (s->len < 4)
+                goto bad_pkt;
+
+            pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
+            s->hci.acl_recv(s->hci.opaque, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+            break;
+
+        case HCI_SCODATA_PKT:
+            if (s->len < 3)
+                goto bad_pkt;
+
+            pktlen = MIN(pkt[2] + 3, s->len);
+            s->len -= pktlen;
+            pkt += pktlen;
+
+        default:
+        bad_pkt:
+            fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
+        }
+}
+
+static int bt_host_bdaddr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
+{
+    return -ENOTSUP;
+}
+
+struct HCIInfo *bt_host_hci(const char *id)
+{
+    struct bt_host_hci_s *s;
+    int fd = -1;
+# ifdef CONFIG_BLUEZ
+    int dev_id = hci_devid(id);
+    struct hci_filter flt;
+
+    if (dev_id < 0) {
+        fprintf(stderr, "qemu: `%s' not available\n", id);
+        return 0;
+    }
+
+    fd = hci_open_dev(dev_id);
+
+    /* XXX: can we ensure nobody else has the device opened?  */
+# endif
+
+    if (fd < 0) {
+        fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
+                        id, strerror(errno), errno);
+        return NULL;
+    }
+
+# ifdef CONFIG_BLUEZ
+    hci_filter_clear(&flt);
+    hci_filter_all_ptypes(&flt);
+    hci_filter_all_events(&flt);
+
+    if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+        fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno);
+        return 0;
+    }
+# endif
+
+    s = qemu_mallocz(sizeof(struct bt_host_hci_s));
+    s->fd = fd;
+    s->hci.cmd_send = bt_host_cmd;
+    s->hci.sco_send = bt_host_sco;
+    s->hci.acl_send = bt_host_acl;
+    s->hci.bdaddr_set = bt_host_bdaddr_set;
+
+    qemu_set_fd_handler2(s->fd, bt_host_read_poll, bt_host_read, NULL, s);
+
+    return &s->hci;
+}
+#else
+struct HCIInfo *bt_host_hci(const char *id)
+{
+    fprintf(stderr, "qemu: bluetooth passthrough not supported (yet)\n");
+
+    return 0;
+}
+#endif
diff --git a/bt-host.h b/bt-host.h
new file mode 100644
index 0000000..f1eff65
--- /dev/null
+++ b/bt-host.h
@@ -0,0 +1,9 @@
+#ifndef BT_HOST_H
+#define BT_HOST_H
+
+struct HCIInfo;
+
+/* bt-host.c */
+struct HCIInfo *bt_host_hci(const char *id);
+
+#endif
diff --git a/bt-vhci.c b/bt-vhci.c
new file mode 100644
index 0000000..ee90f10
--- /dev/null
+++ b/bt-vhci.c
@@ -0,0 +1,169 @@
+/*
+ * Support for host VHCIs inside qemu scatternets.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "net.h"
+#include "hw/bt.h"
+
+#define VHCI_DEV	"/dev/vhci"
+#define VHCI_UDEV	"/dev/hci_vhci"
+
+struct bt_vhci_s {
+    int fd;
+    struct HCIInfo *info;
+
+    uint8_t hdr[4096];
+    int len;
+};
+
+static void vhci_read(void *opaque)
+{
+    struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
+    uint8_t *pkt;
+    int pktlen;
+
+    /* Seems that we can't read only the header first and then the amount
+     * of data indicated in the header because Linux will discard everything
+     * that's not been read in one go.  */
+    s->len = read(s->fd, s->hdr, sizeof(s->hdr));
+
+    if (s->len < 0) {
+        fprintf(stderr, "qemu: error %i reading the PDU\n", errno);
+        return;
+    }
+
+    pkt = s->hdr;
+    while (s->len --)
+        switch (*pkt ++) {
+        case HCI_COMMAND_PKT:
+            if (s->len < 3)
+                goto bad_pkt;
+
+            pktlen = MIN(pkt[2] + 3, s->len);
+            s->info->cmd_send(s->info, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+            break;
+
+        case HCI_ACLDATA_PKT:
+            if (s->len < 4)
+                goto bad_pkt;
+
+            pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
+            s->info->acl_send(s->info, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+            break;
+
+        case HCI_SCODATA_PKT:
+            if (s->len < 3)
+                goto bad_pkt;
+
+            pktlen = MIN(pkt[2] + 3, s->len);
+            s->info->sco_send(s->info, pkt, pktlen);
+            s->len -= pktlen;
+            pkt += pktlen;
+            break;
+
+        default:
+        bad_pkt:
+            fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
+        }
+}
+
+static void vhci_host_send(void *opaque,
+                int type, const uint8_t *data, int len)
+{
+    struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
+#if 0
+    uint8_t pkt = type;
+    struct iovec iv[2];
+
+    iv[0].iov_base = &pkt;
+    iv[0].iov_len  = 1;
+    iv[1].iov_base = (void *) data;
+    iv[1].iov_len  = len;
+
+    while (writev(s->fd, iv, 2) < 0)
+        if (errno != EAGAIN && errno != EINTR) {
+            fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
+                            errno);
+            return;
+        }
+#else
+    /* Apparently VHCI wants us to write everything in one chunk :-(  */
+    static uint8_t buf[4096];
+
+    buf[0] = type;
+    memcpy(buf + 1, data, len);
+
+    while (write(s->fd, buf, len + 1) < 0)
+        if (errno != EAGAIN && errno != EINTR) {
+            fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
+                            errno);
+            return;
+        }
+#endif
+}
+
+static void vhci_out_hci_packet_event(void *opaque,
+                const uint8_t *data, int len)
+{
+    vhci_host_send(opaque, HCI_EVENT_PKT, data, len);
+}
+
+static void vhci_out_hci_packet_acl(void *opaque,
+                const uint8_t *data, int len)
+{
+    vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len);
+}
+
+void bt_vhci_init(struct HCIInfo *info)
+{
+    struct bt_vhci_s *s;
+    int err[2];
+    int fd;
+
+    fd = open(VHCI_DEV, O_RDWR);
+    err[0] = errno;
+    if (fd < 0) {
+        fd = open(VHCI_UDEV, O_RDWR);
+        err[1] = errno;
+    }
+
+    if (fd < 0) {
+        fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
+                        VHCI_DEV, strerror(err[0]), err[0]);
+        fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
+                        VHCI_UDEV, strerror(err[1]), err[1]);
+        exit(-1);
+    }
+
+    s = qemu_mallocz(sizeof(struct bt_vhci_s));
+    s->fd = fd;
+    s->info = info ?: qemu_next_hci();
+    s->info->opaque = s;
+    s->info->evt_recv = vhci_out_hci_packet_event;
+    s->info->acl_recv = vhci_out_hci_packet_acl;
+
+    qemu_set_fd_handler(s->fd, vhci_read, NULL, s);
+}
diff --git a/buffered_file.c b/buffered_file.c
new file mode 100644
index 0000000..364b912
--- /dev/null
+++ b/buffered_file.c
@@ -0,0 +1,261 @@
+/*
+ * QEMU buffered QEMUFile
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "buffered_file.h"
+
+//#define DEBUG_BUFFERED_FILE
+
+typedef struct QEMUFileBuffered
+{
+    BufferedPutFunc *put_buffer;
+    BufferedPutReadyFunc *put_ready;
+    BufferedWaitForUnfreezeFunc *wait_for_unfreeze;
+    BufferedCloseFunc *close;
+    void *opaque;
+    QEMUFile *file;
+    int has_error;
+    int freeze_output;
+    size_t bytes_xfer;
+    size_t xfer_limit;
+    uint8_t *buffer;
+    size_t buffer_size;
+    size_t buffer_capacity;
+    QEMUTimer *timer;
+} QEMUFileBuffered;
+
+#ifdef DEBUG_BUFFERED_FILE
+#define dprintf(fmt, ...) \
+    do { printf("buffered-file: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static void buffered_append(QEMUFileBuffered *s,
+                            const uint8_t *buf, size_t size)
+{
+    if (size > (s->buffer_capacity - s->buffer_size)) {
+        void *tmp;
+
+        dprintf("increasing buffer capacity from %ld by %ld\n",
+                s->buffer_capacity, size + 1024);
+
+        s->buffer_capacity += size + 1024;
+
+        tmp = qemu_realloc(s->buffer, s->buffer_capacity);
+        if (tmp == NULL) {
+            fprintf(stderr, "qemu file buffer expansion failed\n");
+            exit(1);
+        }
+
+        s->buffer = tmp;
+    }
+
+    memcpy(s->buffer + s->buffer_size, buf, size);
+    s->buffer_size += size;
+}
+
+static void buffered_flush(QEMUFileBuffered *s)
+{
+    size_t offset = 0;
+
+    if (s->has_error) {
+        dprintf("flush when error, bailing\n");
+        return;
+    }
+
+    dprintf("flushing %ld byte(s) of data\n", s->buffer_size);
+
+    while (offset < s->buffer_size) {
+        ssize_t ret;
+
+        ret = s->put_buffer(s->opaque, s->buffer + offset,
+                            s->buffer_size - offset);
+        if (ret == -EAGAIN) {
+            dprintf("backend not ready, freezing\n");
+            s->freeze_output = 1;
+            break;
+        }
+
+        if (ret <= 0) {
+            dprintf("error flushing data, %ld\n", ret);
+            s->has_error = 1;
+            break;
+        } else {
+            dprintf("flushed %ld byte(s)\n", ret);
+            offset += ret;
+        }
+    }
+
+    dprintf("flushed %ld of %ld byte(s)\n", offset, s->buffer_size);
+    memmove(s->buffer, s->buffer + offset, s->buffer_size - offset);
+    s->buffer_size -= offset;
+}
+
+static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileBuffered *s = opaque;
+    int offset = 0;
+    ssize_t ret;
+
+    dprintf("putting %ld bytes at %Ld\n", size, pos);
+
+    if (s->has_error) {
+        dprintf("flush when error, bailing\n");
+        return -EINVAL;
+    }
+
+    dprintf("unfreezing output\n");
+    s->freeze_output = 0;
+
+    buffered_flush(s);
+
+    while (!s->freeze_output && offset < size) {
+        if (s->bytes_xfer > s->xfer_limit) {
+            dprintf("transfer limit exceeded when putting\n");
+            break;
+        }
+
+        ret = s->put_buffer(s->opaque, buf + offset, size - offset);
+        if (ret == -EAGAIN) {
+            dprintf("backend not ready, freezing\n");
+            s->freeze_output = 1;
+            break;
+        }
+
+        if (ret <= 0) {
+            dprintf("error putting\n");
+            s->has_error = 1;
+            offset = -EINVAL;
+            break;
+        }
+
+        dprintf("put %ld byte(s)\n", ret);
+        offset += ret;
+        s->bytes_xfer += ret;
+    }
+
+    if (offset >= 0) {
+        dprintf("buffering %ld bytes\n", size - offset);
+        buffered_append(s, buf + offset, size - offset);
+        offset = size;
+    }
+
+    return offset;
+}
+
+static int buffered_close(void *opaque)
+{
+    QEMUFileBuffered *s = opaque;
+    int ret;
+
+    dprintf("closing\n");
+
+    while (!s->has_error && s->buffer_size) {
+        buffered_flush(s);
+        if (s->freeze_output)
+            s->wait_for_unfreeze(s);
+    }
+
+    ret = s->close(s->opaque);
+
+    qemu_del_timer(s->timer);
+    qemu_free_timer(s->timer);
+    qemu_free(s->buffer);
+    qemu_free(s);
+
+    return ret;
+}
+
+static int buffered_rate_limit(void *opaque)
+{
+    QEMUFileBuffered *s = opaque;
+
+    if (s->has_error)
+        return 0;
+
+    if (s->freeze_output)
+        return 1;
+
+    if (s->bytes_xfer > s->xfer_limit)
+        return 1;
+
+    return 0;
+}
+
+static size_t buffered_set_rate_limit(void *opaque, size_t new_rate)
+{
+    QEMUFileBuffered *s = opaque;
+
+    if (s->has_error)
+        goto out;
+
+    s->xfer_limit = new_rate / 10;
+    
+out:
+    return s->xfer_limit;
+}
+
+static void buffered_rate_tick(void *opaque)
+{
+    QEMUFileBuffered *s = opaque;
+
+    if (s->has_error)
+        return;
+
+    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
+
+    if (s->freeze_output)
+        return;
+
+    s->bytes_xfer = 0;
+
+    buffered_flush(s);
+
+    /* Add some checks around this */
+    s->put_ready(s->opaque);
+}
+
+QEMUFile *qemu_fopen_ops_buffered(void *opaque,
+                                  size_t bytes_per_sec,
+                                  BufferedPutFunc *put_buffer,
+                                  BufferedPutReadyFunc *put_ready,
+                                  BufferedWaitForUnfreezeFunc *wait_for_unfreeze,
+                                  BufferedCloseFunc *close)
+{
+    QEMUFileBuffered *s;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->opaque = opaque;
+    s->xfer_limit = bytes_per_sec / 10;
+    s->put_buffer = put_buffer;
+    s->put_ready = put_ready;
+    s->wait_for_unfreeze = wait_for_unfreeze;
+    s->close = close;
+
+    s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL,
+                             buffered_close, buffered_rate_limit,
+                             buffered_set_rate_limit);
+
+    s->timer = qemu_new_timer(rt_clock, buffered_rate_tick, s);
+
+    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 100);
+
+    return s->file;
+}
diff --git a/buffered_file.h b/buffered_file.h
new file mode 100644
index 0000000..98d358b
--- /dev/null
+++ b/buffered_file.h
@@ -0,0 +1,30 @@
+/*
+ * QEMU buffered QEMUFile
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_BUFFERED_FILE_H
+#define QEMU_BUFFERED_FILE_H
+
+#include "hw/hw.h"
+
+typedef ssize_t (BufferedPutFunc)(void *opaque, const void *data, size_t size);
+typedef void (BufferedPutReadyFunc)(void *opaque);
+typedef void (BufferedWaitForUnfreezeFunc)(void *opaque);
+typedef int (BufferedCloseFunc)(void *opaque);
+
+QEMUFile *qemu_fopen_ops_buffered(void *opaque, size_t xfer_limit,
+                                  BufferedPutFunc *put_buffer,
+                                  BufferedPutReadyFunc *put_ready,
+                                  BufferedWaitForUnfreezeFunc *wait_for_unfreeze,
+                                  BufferedCloseFunc *close);
+
+#endif
diff --git a/cache-utils.c b/cache-utils.c
new file mode 100644
index 0000000..45d62c9
--- /dev/null
+++ b/cache-utils.c
@@ -0,0 +1,73 @@
+#include "cache-utils.h"
+
+#if defined(_ARCH_PPC)
+struct qemu_cache_conf qemu_cache_conf = {
+    .dcache_bsize = 16,
+    .icache_bsize = 16
+};
+
+#if defined _AIX
+#include <sys/systemcfg.h>
+
+static void ppc_init_cacheline_sizes(void)
+{
+    qemu_cache_conf.icache_bsize = _system_configuration.icache_line;
+    qemu_cache_conf.dcache_bsize = _system_configuration.dcache_line;
+}
+
+#elif defined __linux__
+
+#define QEMU_AT_NULL        0
+#define QEMU_AT_DCACHEBSIZE 19
+#define QEMU_AT_ICACHEBSIZE 20
+
+static void ppc_init_cacheline_sizes(char **envp)
+{
+    unsigned long *auxv;
+
+    while (*envp++);
+
+    for (auxv = (unsigned long *) envp; *auxv != QEMU_AT_NULL; auxv += 2) {
+        switch (*auxv) {
+        case QEMU_AT_DCACHEBSIZE: qemu_cache_conf.dcache_bsize = auxv[1]; break;
+        case QEMU_AT_ICACHEBSIZE: qemu_cache_conf.icache_bsize = auxv[1]; break;
+        default: break;
+        }
+    }
+}
+
+#elif defined __APPLE__
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+static void ppc_init_cacheline_sizes(void)
+{
+    size_t len;
+    unsigned cacheline;
+    int name[2] = { CTL_HW, HW_CACHELINE };
+
+    len = sizeof(cacheline);
+    if (sysctl(name, 2, &cacheline, &len, NULL, 0)) {
+        perror("sysctl CTL_HW HW_CACHELINE failed");
+    } else {
+        qemu_cache_conf.dcache_bsize = cacheline;
+        qemu_cache_conf.icache_bsize = cacheline;
+    }
+}
+#endif
+
+#ifdef __linux__
+void qemu_cache_utils_init(char **envp)
+{
+    ppc_init_cacheline_sizes(envp);
+}
+#else
+void qemu_cache_utils_init(char **envp)
+{
+    (void) envp;
+    ppc_init_cacheline_sizes();
+}
+#endif
+
+#endif /* _ARCH_PPC */
diff --git a/cache-utils.h b/cache-utils.h
new file mode 100644
index 0000000..b45fde4
--- /dev/null
+++ b/cache-utils.h
@@ -0,0 +1,41 @@
+#ifndef QEMU_CACHE_UTILS_H
+#define QEMU_CACHE_UTILS_H
+
+#if defined(_ARCH_PPC)
+struct qemu_cache_conf {
+    unsigned long dcache_bsize;
+    unsigned long icache_bsize;
+};
+
+extern struct qemu_cache_conf qemu_cache_conf;
+
+extern void qemu_cache_utils_init(char **envp);
+
+/* mildly adjusted code from tcg-dyngen.c */
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    unsigned long p, start1, stop1;
+    unsigned long dsize = qemu_cache_conf.dcache_bsize;
+    unsigned long isize = qemu_cache_conf.icache_bsize;
+
+    start1 = start & ~(dsize - 1);
+    stop1 = (stop + dsize - 1) & ~(dsize - 1);
+    for (p = start1; p < stop1; p += dsize) {
+        asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
+    }
+    asm volatile ("sync" : : : "memory");
+
+    start &= start & ~(isize - 1);
+    stop1 = (stop + isize - 1) & ~(isize - 1);
+    for (p = start1; p < stop1; p += isize) {
+        asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
+    }
+    asm volatile ("sync" : : : "memory");
+    asm volatile ("isync" : : : "memory");
+}
+
+#else
+#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
+#endif
+
+#endif /* QEMU_CACHE_UTILS_H */
diff --git a/console.c b/console.c
index 785710a..52e3e57 100644
--- a/console.c
+++ b/console.c
@@ -28,7 +28,6 @@
 //#define DEBUG_CONSOLE
 #define DEFAULT_BACKSCROLL 512
 #define MAX_CONSOLES 12
-#define DEFAULT_MONITOR_SIZE "800x600"
 
 #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
 #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
@@ -109,7 +108,8 @@
 
 typedef enum {
     GRAPHIC_CONSOLE,
-    TEXT_CONSOLE
+    TEXT_CONSOLE,
+    TEXT_CONSOLE_FIXED_SIZE
 } console_type_t;
 
 /* ??? This is mis-named.
@@ -138,6 +138,11 @@
     TextCell *cells;
     int text_x[2], text_y[2], cursor_invalidate;
 
+    int update_x0;
+    int update_y0;
+    int update_x1;
+    int update_y1;
+
     enum TTYState state;
     int esc_params[MAX_ESC_PARAMS];
     int nb_esc_params;
@@ -189,7 +194,7 @@
 {
     unsigned int r, g, b, color;
 
-    switch(ds->depth) {
+    switch(ds_get_bits_per_pixel(ds)) {
 #if 0
     case 8:
         r = (rgba >> 16) & 0xff;
@@ -226,9 +231,9 @@
     uint8_t *d, *d1;
     int x, y, bpp;
 
-    bpp = (ds->depth + 7) >> 3;
-    d1 = ds->data +
-        ds->linesize * posy + bpp * posx;
+    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
+    d1 = ds_get_data(ds) +
+        ds_get_linesize(ds) * posy + bpp * posx;
     for (y = 0; y < height; y++) {
         d = d1;
         switch(bpp) {
@@ -251,7 +256,7 @@
             }
             break;
         }
-        d1 += ds->linesize;
+        d1 += ds_get_linesize(ds);
     }
 }
 
@@ -262,27 +267,27 @@
     uint8_t *d;
     int wb, y, bpp;
 
-    bpp = (ds->depth + 7) >> 3;
+    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
     wb = w * bpp;
     if (yd <= ys) {
-        s = ds->data +
-            ds->linesize * ys + bpp * xs;
-        d = ds->data +
-            ds->linesize * yd + bpp * xd;
+        s = ds_get_data(ds) +
+            ds_get_linesize(ds) * ys + bpp * xs;
+        d = ds_get_data(ds) +
+            ds_get_linesize(ds) * yd + bpp * xd;
         for (y = 0; y < h; y++) {
             memmove(d, s, wb);
-            d += ds->linesize;
-            s += ds->linesize;
+            d += ds_get_linesize(ds);
+            s += ds_get_linesize(ds);
         }
     } else {
-        s = ds->data +
-            ds->linesize * (ys + h - 1) + bpp * xs;
-        d = ds->data +
-            ds->linesize * (yd + h - 1) + bpp * xd;
+        s = ds_get_data(ds) +
+            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
+        d = ds_get_data(ds) +
+            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
        for (y = 0; y < h; y++) {
             memmove(d, s, wb);
-            d -= ds->linesize;
-            s -= ds->linesize;
+            d -= ds_get_linesize(ds);
+            s -= ds_get_linesize(ds);
         }
     }
 }
@@ -372,7 +377,7 @@
 
 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
 {
-    switch(ds->depth) {
+    switch(ds_get_bits_per_pixel(ds)) {
     case 8:
         col |= col << 8;
         col |= col << 16;
@@ -442,13 +447,13 @@
         bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
     }
 
-    bpp = (ds->depth + 7) >> 3;
-    d = ds->data +
-        ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
-    linesize = ds->linesize;
+    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
+    d = ds_get_data(ds) +
+        ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
+    linesize = ds_get_linesize(ds);
     font_ptr = vgafont16 + FONT_HEIGHT * ch;
     xorcol = bgcol ^ fgcol;
-    switch(ds->depth) {
+    switch(ds_get_bits_per_pixel(ds)) {
     case 8:
         for(i = 0; i < FONT_HEIGHT; i++) {
             font_data = *font_ptr++;
@@ -536,13 +541,25 @@
     s->text_y[1] = MAX(s->text_y[1], y);
 }
 
+static void invalidate_xy(TextConsole *s, int x, int y)
+{
+    if (s->update_x0 > x * FONT_WIDTH)
+        s->update_x0 = x * FONT_WIDTH;
+    if (s->update_y0 > y * FONT_HEIGHT)
+        s->update_y0 = y * FONT_HEIGHT;
+    if (s->update_x1 < (x + 1) * FONT_WIDTH)
+        s->update_x1 = (x + 1) * FONT_WIDTH;
+    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
+        s->update_y1 = (y + 1) * FONT_HEIGHT;
+}
+
 static void update_xy(TextConsole *s, int x, int y)
 {
     TextCell *c;
     int y1, y2;
 
     if (s == active_console) {
-        if (!s->ds->depth) {
+        if (!ds_get_bits_per_pixel(s->ds)) {
             text_update_xy(s, x, y);
             return;
         }
@@ -555,8 +572,7 @@
             c = &s->cells[y1 * s->width + x];
             vga_putcharxy(s->ds, x, y2, c->ch,
                           &(c->t_attrib));
-            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
-                       FONT_WIDTH, FONT_HEIGHT);
+            invalidate_xy(s, x, y2);
         }
     }
 }
@@ -569,7 +585,7 @@
     if (s == active_console) {
         int x = s->x;
 
-        if (!s->ds->depth) {
+        if (!ds_get_bits_per_pixel(s->ds)) {
             s->cursor_invalidate = 1;
             return;
         }
@@ -590,8 +606,7 @@
             } else {
                 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
             }
-            dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
-                       FONT_WIDTH, FONT_HEIGHT);
+            invalidate_xy(s, x, y);
         }
     }
 }
@@ -603,7 +618,7 @@
 
     if (s != active_console)
         return;
-    if (!s->ds->depth) {
+    if (!ds_get_bits_per_pixel(s->ds)) {
         s->text_x[0] = 0;
         s->text_y[0] = 0;
         s->text_x[1] = s->width - 1;
@@ -612,7 +627,7 @@
         return;
     }
 
-    vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
+    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
                   color_table[0][COLOR_BLACK]);
     y1 = s->y_displayed;
     for(y = 0; y < s->height; y++) {
@@ -625,8 +640,8 @@
         if (++y1 == s->total_height)
             y1 = 0;
     }
-    dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
     console_show_cursor(s, 1);
+    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
 }
 
 static void console_scroll(int ydelta)
@@ -688,7 +703,7 @@
             c++;
         }
         if (s == active_console && s->y_displayed == s->y_base) {
-            if (!s->ds->depth) {
+            if (!ds_get_bits_per_pixel(s->ds)) {
                 s->text_x[0] = 0;
                 s->text_y[0] = 0;
                 s->text_x[1] = s->width - 1;
@@ -702,8 +717,10 @@
             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
                           s->width * FONT_WIDTH, FONT_HEIGHT,
                           color_table[0][s->t_attrib_default.bgcol]);
-            dpy_update(s->ds, 0, 0,
-                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
+            s->update_x0 = 0;
+            s->update_y0 = 0;
+            s->update_x1 = s->width * FONT_WIDTH;
+            s->update_y1 = s->height * FONT_HEIGHT;
         }
     }
 }
@@ -1043,12 +1060,19 @@
 
     if (index >= MAX_CONSOLES)
         return;
+    active_console->g_width = ds_get_width(active_console->ds);
+    active_console->g_height = ds_get_height(active_console->ds);
     s = consoles[index];
     if (s) {
+        DisplayState *ds = s->ds;
         active_console = s;
-        if (s->g_width && s->g_height
-            && (s->g_width != s->ds->width || s->g_height != s->ds->height))
-            dpy_resize(s->ds, s->g_width, s->g_height);
+        if (ds_get_bits_per_pixel(s->ds)) {
+            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
+        } else {
+            s->ds->surface->width = s->width;
+            s->ds->surface->height = s->height;
+        }
+        dpy_resize(s->ds);
         vga_hw_invalidate();
     }
 }
@@ -1058,11 +1082,20 @@
     TextConsole *s = chr->opaque;
     int i;
 
+    s->update_x0 = s->width * FONT_WIDTH;
+    s->update_y0 = s->height * FONT_HEIGHT;
+    s->update_x1 = 0;
+    s->update_y1 = 0;
     console_show_cursor(s, 0);
     for(i = 0; i < len; i++) {
         console_putchar(s, buf[i]);
     }
     console_show_cursor(s, 1);
+    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
+        dpy_update(s->ds, s->update_x0, s->update_y0,
+                   s->update_x1 - s->update_x0,
+                   s->update_y1 - s->update_y0);
+    }
     return len;
 }
 
@@ -1156,7 +1189,11 @@
 static void text_console_invalidate(void *opaque)
 {
     TextConsole *s = (TextConsole *) opaque;
-
+    if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
+        s->g_width = ds_get_width(s->ds);
+        s->g_height = ds_get_height(s->ds);
+        text_console_resize(s);
+    }
     console_refresh(s);
 }
 
@@ -1187,6 +1224,18 @@
     }
 }
 
+static TextConsole *get_graphic_console(DisplayState *ds)
+{
+    int i;
+    TextConsole *s;
+    for (i = 0; i < nb_consoles; i++) {
+        s = consoles[i];
+        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
+            return s;
+    }
+    return NULL;
+}
+
 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
 {
     TextConsole *s;
@@ -1195,9 +1244,6 @@
     if (nb_consoles >= MAX_CONSOLES)
         return NULL;
     s = qemu_mallocz(sizeof(TextConsole));
-    if (!s) {
-        return NULL;
-    }
     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
         (console_type == GRAPHIC_CONSOLE))) {
         active_console = s;
@@ -1214,27 +1260,38 @@
             consoles[i] = consoles[i - 1];
         }
         consoles[i] = s;
+        nb_consoles++;
     }
     return s;
 }
 
-TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
-                                  vga_hw_invalidate_ptr invalidate,
-                                  vga_hw_screen_dump_ptr screen_dump,
-                                  vga_hw_text_update_ptr text_update,
-                                  void *opaque)
+DisplayState *graphic_console_init(vga_hw_update_ptr update,
+                                   vga_hw_invalidate_ptr invalidate,
+                                   vga_hw_screen_dump_ptr screen_dump,
+                                   vga_hw_text_update_ptr text_update,
+                                   void *opaque)
 {
     TextConsole *s;
+    DisplayState *ds;
+
+    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
+    ds->allocator = &default_allocator; 
+    ds->surface = qemu_create_displaysurface(ds, 640, 480);
 
     s = new_console(ds, GRAPHIC_CONSOLE);
-    if (!s)
-      return NULL;
+    if (s == NULL) {
+        qemu_free_displaysurface(ds);
+        qemu_free(ds);
+        return NULL;
+    }
     s->hw_update = update;
     s->hw_invalidate = invalidate;
     s->hw_screen_dump = screen_dump;
     s->hw_text_update = text_update;
     s->hw = opaque;
-    return s;
+
+    register_displaystate(ds);
+    return ds;
 }
 
 int is_graphic_console(void)
@@ -1242,36 +1299,38 @@
     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
 }
 
+int is_fixedsize_console(void)
+{
+    return active_console && active_console->console_type != TEXT_CONSOLE;
+}
+
 void console_color_init(DisplayState *ds)
 {
     int i, j;
     for (j = 0; j < 2; j++) {
         for (i = 0; i < 8; i++) {
-            color_table[j][i] = col_expand(ds, 
+            color_table[j][i] = col_expand(ds,
                    vga_get_color(ds, color_table_rgb[j][i]));
         }
     }
 }
 
-CharDriverState *text_console_init(DisplayState *ds, const char *p)
+static int n_text_consoles;
+static CharDriverState *text_consoles[128];
+static char *text_console_strs[128];
+
+static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
 {
-    CharDriverState *chr;
     TextConsole *s;
     unsigned width;
     unsigned height;
     static int color_inited;
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
-    s = new_console(ds, TEXT_CONSOLE);
+    s = new_console(ds, (p == NULL) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
     if (!s) {
         free(chr);
-        return NULL;
+        return;
     }
-    if (!p)
-        p = DEFAULT_MONITOR_SIZE;
-
     chr->opaque = s;
     chr->chr_write = console_puts;
     chr->chr_send_event = console_send_event;
@@ -1280,6 +1339,7 @@
     s->out_fifo.buf = s->out_fifo_buf;
     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
+    s->ds = ds;
 
     if (!color_inited) {
         color_inited = 1;
@@ -1290,9 +1350,9 @@
     s->total_height = DEFAULT_BACKSCROLL;
     s->x = 0;
     s->y = 0;
-    width = s->ds->width;
-    height = s->ds->height;
-    if (p != 0) {
+    width = ds_get_width(s->ds);
+    height = ds_get_height(s->ds);
+    if (p != NULL) {
         width = strtoul(p, (char **)&p, 10);
         if (*p == 'C') {
             p++;
@@ -1322,24 +1382,235 @@
     s->t_attrib_default.unvisible = 0;
     s->t_attrib_default.fgcol = COLOR_WHITE;
     s->t_attrib_default.bgcol = COLOR_BLACK;
-
     /* set current text attributes to default */
     s->t_attrib = s->t_attrib_default;
     text_console_resize(s);
 
     qemu_chr_reset(chr);
+    if (chr->init)
+        chr->init(chr);
+}
+
+CharDriverState *text_console_init(const char *p)
+{
+    CharDriverState *chr;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+
+    if (n_text_consoles == 128) {
+        fprintf(stderr, "Too many text consoles\n");
+        exit(1);
+    }
+    text_consoles[n_text_consoles] = chr;
+    text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
+    n_text_consoles++;
 
     return chr;
 }
 
-void qemu_console_resize(QEMUConsole *console, int width, int height)
+void text_consoles_set_display(DisplayState *ds)
 {
-    if (console->g_width != width || console->g_height != height
-        || !console->ds->data) {
-        console->g_width = width;
-        console->g_height = height;
-        if (active_console == console) {
-            dpy_resize(console->ds, width, height);
-        }
+    int i;
+
+    for (i = 0; i < n_text_consoles; i++) {
+        text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
+        qemu_free(text_console_strs[i]);
     }
+
+    n_text_consoles = 0;
+}
+
+void qemu_console_resize(DisplayState *ds, int width, int height)
+{
+    TextConsole *s = get_graphic_console(ds);
+    if (!s) return;
+
+    s->g_width = width;
+    s->g_height = height;
+    if (is_graphic_console()) {
+        ds->surface = qemu_resize_displaysurface(ds, width, height);
+        dpy_resize(ds);
+    }
+}
+
+void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
+                       int dst_x, int dst_y, int w, int h)
+{
+    if (is_graphic_console()) {
+        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
+    }
+}
+
+PixelFormat qemu_different_endianness_pixelformat(int bpp)
+{
+    PixelFormat pf;
+
+    memset(&pf, 0x00, sizeof(PixelFormat));
+
+    pf.bits_per_pixel = bpp;
+    pf.bytes_per_pixel = bpp / 8;
+    pf.depth = bpp == 32 ? 24 : bpp;
+
+    switch (bpp) {
+        case 24:
+            pf.rmask = 0x000000FF;
+            pf.gmask = 0x0000FF00;
+            pf.bmask = 0x00FF0000;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.rshift = 0;
+            pf.gshift = 8;
+            pf.bshift = 16;
+            pf.rbits = 8;
+            pf.gbits = 8;
+            pf.bbits = 8;
+            break;
+        case 32:
+            pf.rmask = 0x0000FF00;
+            pf.gmask = 0x00FF0000;
+            pf.bmask = 0xFF000000;
+            pf.amask = 0x00000000;
+            pf.amax = 255;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.ashift = 0;
+            pf.rshift = 8;
+            pf.gshift = 16;
+            pf.bshift = 24;
+            pf.rbits = 8;
+            pf.gbits = 8;
+            pf.bbits = 8;
+            pf.abits = 8;
+            break;
+        default:
+            break;
+    }
+    return pf;
+}
+
+PixelFormat qemu_default_pixelformat(int bpp)
+{
+    PixelFormat pf;
+
+    memset(&pf, 0x00, sizeof(PixelFormat));
+
+    pf.bits_per_pixel = bpp;
+    pf.bytes_per_pixel = bpp / 8;
+    pf.depth = bpp == 32 ? 24 : bpp;
+
+    switch (bpp) {
+        case 16:
+            pf.rmask = 0x0000F800;
+            pf.gmask = 0x000007E0;
+            pf.bmask = 0x0000001F;
+            pf.rmax = 31;
+            pf.gmax = 63;
+            pf.bmax = 31;
+            pf.rshift = 11;
+            pf.gshift = 5;
+            pf.bshift = 0;
+            pf.rbits = 5;
+            pf.gbits = 6;
+            pf.bbits = 5;
+            break;
+        case 24:
+            pf.rmask = 0x00FF0000;
+            pf.gmask = 0x0000FF00;
+            pf.bmask = 0x000000FF;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.rshift = 16;
+            pf.gshift = 8;
+            pf.bshift = 0;
+            pf.rbits = 8;
+            pf.gbits = 8;
+            pf.bbits = 8;
+        case 32:
+            pf.rmask = 0x00FF0000;
+            pf.gmask = 0x0000FF00;
+            pf.bmask = 0x000000FF;
+            pf.amax = 255;
+            pf.rmax = 255;
+            pf.gmax = 255;
+            pf.bmax = 255;
+            pf.ashift = 24;
+            pf.rshift = 16;
+            pf.gshift = 8;
+            pf.bshift = 0;
+            pf.rbits = 8;
+            pf.gbits = 8;
+            pf.bbits = 8;
+            pf.abits = 8;
+            break;
+        default:
+            break;
+    }
+    return pf;
+}
+
+DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = width * 4;
+    surface->pf = qemu_default_pixelformat(32);
+#ifdef WORDS_BIGENDIAN
+    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+    surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
+
+    return surface;
+}
+
+DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
+                                          int width, int height)
+{
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = width * 4;
+    surface->pf = qemu_default_pixelformat(32);
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
+    else
+        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
+#ifdef WORDS_BIGENDIAN
+    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
+#else
+    surface->flags = QEMU_ALLOCATED_FLAG;
+#endif
+
+    return surface;
+}
+
+DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
+                                              int linesize, uint8_t *data)
+{
+    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
+
+    surface->width = width;
+    surface->height = height;
+    surface->linesize = linesize;
+    surface->pf = qemu_default_pixelformat(bpp);
+#ifdef WORDS_BIGENDIAN
+    surface->flags = QEMU_BIG_ENDIAN_FLAG;
+#endif
+    surface->data = data;
+
+    return surface;
+}
+
+void defaultallocator_free_displaysurface(DisplaySurface *surface)
+{
+    if (surface == NULL)
+        return;
+    if (surface->flags & QEMU_ALLOCATED_FLAG)
+        qemu_free(surface->data);
+    qemu_free(surface);
 }
diff --git a/console.h b/console.h
index 52dc4d8..9222115 100644
--- a/console.h
+++ b/console.h
@@ -43,7 +43,7 @@
 void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
 int kbd_mouse_is_absolute(void);
 
-struct mouse_transform_info_s {
+struct MouseTransformInfo {
     /* Touchscreen resolution */
     int x;
     int y;
@@ -51,8 +51,8 @@
     int a[7];
 };
 
-void do_info_mice(void);
-void do_mouse_set(int index);
+void do_info_mice(Monitor *mon);
+void do_mouse_set(Monitor *mon, int index);
 
 /* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
    constants) */
@@ -81,45 +81,207 @@
 
 /* consoles */
 
-struct DisplayState {
-    uint8_t *data;
-    int linesize;
-    int depth;
-    int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */
+#define QEMU_BIG_ENDIAN_FLAG    0x01
+#define QEMU_ALLOCATED_FLAG     0x02
+
+struct PixelFormat {
+    uint8_t bits_per_pixel;
+    uint8_t bytes_per_pixel;
+    uint8_t depth; /* color depth in bits */
+    uint32_t rmask, gmask, bmask, amask;
+    uint8_t rshift, gshift, bshift, ashift;
+    uint8_t rmax, gmax, bmax, amax;
+    uint8_t rbits, gbits, bbits, abits;
+};
+
+struct DisplaySurface {
+    uint8_t flags;
     int width;
     int height;
-    void *opaque;
-    struct QEMUTimer *gui_timer;
+    int linesize;        /* bytes per line */
+    uint8_t *data;
+
+    struct PixelFormat pf;
+};
+
+struct DisplayChangeListener {
+    int idle;
     uint64_t gui_timer_interval;
-    int idle; /* there is nothing to update (window invisible), set by vnc/sdl */
 
     void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
-    void (*dpy_resize)(struct DisplayState *s, int w, int h);
+    void (*dpy_resize)(struct DisplayState *s);
+    void (*dpy_setdata)(struct DisplayState *s);
     void (*dpy_refresh)(struct DisplayState *s);
     void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y,
                      int dst_x, int dst_y, int w, int h);
     void (*dpy_fill)(struct DisplayState *s, int x, int y,
                      int w, int h, uint32_t c);
     void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
+
+    struct DisplayChangeListener *next;
+};
+
+struct DisplayAllocator {
+    DisplaySurface* (*create_displaysurface)(int width, int height);
+    DisplaySurface* (*resize_displaysurface)(DisplaySurface *surface, int width, int height);
+    void (*free_displaysurface)(DisplaySurface *surface);
+};
+
+struct DisplayState {
+    struct DisplaySurface *surface;
+    void *opaque;
+    struct QEMUTimer *gui_timer;
+
+    struct DisplayAllocator* allocator;
+    struct DisplayChangeListener* listeners;
+
     void (*mouse_set)(int x, int y, int on);
     void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
                           uint8_t *image, uint8_t *mask);
+
+    struct DisplayState *next;
 };
 
+void register_displaystate(DisplayState *ds);
+DisplayState *get_displaystate(void);
+DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
+                                                int linesize, uint8_t *data);
+PixelFormat qemu_different_endianness_pixelformat(int bpp);
+PixelFormat qemu_default_pixelformat(int bpp);
+
+extern struct DisplayAllocator default_allocator;
+DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da);
+DisplaySurface* defaultallocator_create_displaysurface(int width, int height);
+DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface, int width, int height);
+void defaultallocator_free_displaysurface(DisplaySurface *surface);
+
+static inline DisplaySurface* qemu_create_displaysurface(DisplayState *ds, int width, int height)
+{
+    return ds->allocator->create_displaysurface(width, height);    
+}
+
+static inline DisplaySurface* qemu_resize_displaysurface(DisplayState *ds, int width, int height)
+{
+    return ds->allocator->resize_displaysurface(ds->surface, width, height);
+}
+
+static inline void qemu_free_displaysurface(DisplayState *ds)
+{
+    ds->allocator->free_displaysurface(ds->surface);
+}
+
+static inline int is_surface_bgr(DisplaySurface *surface)
+{
+    if (surface->pf.bits_per_pixel == 32 && surface->pf.rshift == 0)
+        return 1;
+    else
+        return 0;
+}
+
+static inline int is_buffer_shared(DisplaySurface *surface)
+{
+    return (!(surface->flags & QEMU_ALLOCATED_FLAG));
+}
+
+static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
+{
+    dcl->next = ds->listeners;
+    ds->listeners = dcl;
+}
+
 static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
 {
-    s->dpy_update(s, x, y, w, h);
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        dcl->dpy_update(s, x, y, w, h);
+        dcl = dcl->next;
+    }
 }
 
-static inline void dpy_resize(DisplayState *s, int w, int h)
+static inline void dpy_resize(DisplayState *s)
 {
-    s->dpy_resize(s, w, h);
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        dcl->dpy_resize(s);
+        dcl = dcl->next;
+    }
 }
 
-static inline void dpy_cursor(DisplayState *s, int x, int y)
+static inline void dpy_setdata(DisplayState *s)
 {
-    if (s->dpy_text_cursor)
-        s->dpy_text_cursor(s, x, y);
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_setdata) dcl->dpy_setdata(s);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_refresh(DisplayState *s)
+{
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_refresh) dcl->dpy_refresh(s);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_copy(struct DisplayState *s, int src_x, int src_y,
+                             int dst_x, int dst_y, int w, int h) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_copy)
+            dcl->dpy_copy(s, src_x, src_y, dst_x, dst_y, w, h);
+        else /* TODO */
+            dcl->dpy_update(s, dst_x, dst_y, w, h);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_fill(struct DisplayState *s, int x, int y,
+                             int w, int h, uint32_t c) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_fill) dcl->dpy_fill(s, x, y, w, h, c);
+        dcl = dcl->next;
+    }
+}
+
+static inline void dpy_cursor(struct DisplayState *s, int x, int y) {
+    struct DisplayChangeListener *dcl = s->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_text_cursor) dcl->dpy_text_cursor(s, x, y);
+        dcl = dcl->next;
+    }
+}
+
+static inline int ds_get_linesize(DisplayState *ds)
+{
+    return ds->surface->linesize;
+}
+
+static inline uint8_t* ds_get_data(DisplayState *ds)
+{
+    return ds->surface->data;
+}
+
+static inline int ds_get_width(DisplayState *ds)
+{
+    return ds->surface->width;
+}
+
+static inline int ds_get_height(DisplayState *ds)
+{
+    return ds->surface->height;
+}
+
+static inline int ds_get_bits_per_pixel(DisplayState *ds)
+{
+    return ds->surface->pf.bits_per_pixel;
+}
+
+static inline int ds_get_bytes_per_pixel(DisplayState *ds)
+{
+    return ds->surface->pf.bytes_per_pixel;
 }
 
 typedef unsigned long console_ch_t;
@@ -133,21 +295,26 @@
 typedef void (*vga_hw_screen_dump_ptr)(void *, const char *);
 typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *);
 
-TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
-                                  vga_hw_invalidate_ptr invalidate,
-                                  vga_hw_screen_dump_ptr screen_dump,
-                                  vga_hw_text_update_ptr text_update,
-                                  void *opaque);
+DisplayState *graphic_console_init(vga_hw_update_ptr update,
+                                   vga_hw_invalidate_ptr invalidate,
+                                   vga_hw_screen_dump_ptr screen_dump,
+                                   vga_hw_text_update_ptr text_update,
+                                   void *opaque);
+
 void vga_hw_update(void);
 void vga_hw_invalidate(void);
 void vga_hw_screen_dump(const char *filename);
 void vga_hw_text_update(console_ch_t *chardata);
 
 int is_graphic_console(void);
-CharDriverState *text_console_init(DisplayState *ds, const char *p);
+int is_fixedsize_console(void);
+CharDriverState *text_console_init(const char *p);
+void text_consoles_set_display(DisplayState *ds);
 void console_select(unsigned int index);
 void console_color_init(DisplayState *ds);
-void qemu_console_resize(QEMUConsole *console, int width, int height);
+void qemu_console_resize(DisplayState *ds, int width, int height);
+void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
+                       int dst_x, int dst_y, int w, int h);
 
 /* sdl.c */
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
@@ -160,36 +327,10 @@
 void vnc_display_close(DisplayState *ds);
 int vnc_display_open(DisplayState *ds, const char *display);
 int vnc_display_password(DisplayState *ds, const char *password);
-void do_info_vnc(void);
+void do_info_vnc(Monitor *mon);
+char *vnc_display_local_addr(DisplayState *ds);
 
 /* curses.c */
 void curses_display_init(DisplayState *ds, int full_screen);
 
-/* x_keymap.c */
-extern uint8_t _translate_keycode(const int key);
-
-/* FIXME: term_printf et al should probably go elsewhere so everything
-   does not need to include console.h  */
-/* monitor.c */
-void monitor_init(CharDriverState *hd, int show_banner);
-void term_puts(const char *str);
-void term_vprintf(const char *fmt, va_list ap);
-void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
-void term_print_filename(const char *filename);
-void term_flush(void);
-void term_print_help(void);
-void monitor_readline(const char *prompt, int is_password,
-                      char *buf, int buf_size);
-
-/* readline.c */
-typedef void ReadLineFunc(void *opaque, const char *str);
-
-extern int completion_index;
-void add_completion(const char *str);
-void readline_handle_byte(int ch);
-void readline_find_completion(const char *cmdline);
-const char *readline_get_history(unsigned int index);
-void readline_start(const char *prompt, int is_password,
-                    ReadLineFunc *readline_func, void *opaque);
-
 #endif
diff --git a/cpu-all.h b/cpu-all.h
index 8f4cb3c..48a9a2c 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -15,14 +15,13 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #ifndef CPU_ALL_H
 #define CPU_ALL_H
 
-#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__)
-#define WORDS_ALIGNED
-#endif
+#include "qemu-common.h"
+#include "cpu-common.h"
 
 /* some important defines:
  *
@@ -37,7 +36,6 @@
  * TARGET_WORDS_BIGENDIAN : same for target cpu
  */
 
-#include "bswap.h"
 #include "softfloat.h"
 
 #if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
@@ -206,12 +204,12 @@
  *   user   : user mode access using soft MMU
  *   kernel : kernel mode access using soft MMU
  */
-static inline int ldub_p(void *ptr)
+static inline int ldub_p(const void *ptr)
 {
     return *(uint8_t *)ptr;
 }
 
-static inline int ldsb_p(void *ptr)
+static inline int ldsb_p(const void *ptr)
 {
     return *(int8_t *)ptr;
 }
@@ -227,45 +225,45 @@
 #if defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
 
 /* conservative code for little endian unaligned accesses */
-static inline int lduw_le_p(void *ptr)
+static inline int lduw_le_p(const void *ptr)
 {
-#ifdef __powerpc__
+#ifdef _ARCH_PPC
     int val;
     __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
     return val;
 #else
-    uint8_t *p = ptr;
+    const uint8_t *p = ptr;
     return p[0] | (p[1] << 8);
 #endif
 }
 
-static inline int ldsw_le_p(void *ptr)
+static inline int ldsw_le_p(const void *ptr)
 {
-#ifdef __powerpc__
+#ifdef _ARCH_PPC
     int val;
     __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
     return (int16_t)val;
 #else
-    uint8_t *p = ptr;
+    const uint8_t *p = ptr;
     return (int16_t)(p[0] | (p[1] << 8));
 #endif
 }
 
-static inline int ldl_le_p(void *ptr)
+static inline int ldl_le_p(const void *ptr)
 {
-#ifdef __powerpc__
+#ifdef _ARCH_PPC
     int val;
     __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
     return val;
 #else
-    uint8_t *p = ptr;
+    const uint8_t *p = ptr;
     return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
 #endif
 }
 
-static inline uint64_t ldq_le_p(void *ptr)
+static inline uint64_t ldq_le_p(const void *ptr)
 {
-    uint8_t *p = ptr;
+    const uint8_t *p = ptr;
     uint32_t v1, v2;
     v1 = ldl_le_p(p);
     v2 = ldl_le_p(p + 4);
@@ -274,7 +272,7 @@
 
 static inline void stw_le_p(void *ptr, int v)
 {
-#ifdef __powerpc__
+#ifdef _ARCH_PPC
     __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
 #else
     uint8_t *p = ptr;
@@ -285,7 +283,7 @@
 
 static inline void stl_le_p(void *ptr, int v)
 {
-#ifdef __powerpc__
+#ifdef _ARCH_PPC
     __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
 #else
     uint8_t *p = ptr;
@@ -305,7 +303,7 @@
 
 /* float access */
 
-static inline float32 ldfl_le_p(void *ptr)
+static inline float32 ldfl_le_p(const void *ptr)
 {
     union {
         float32 f;
@@ -325,7 +323,7 @@
     stl_le_p(ptr, u.i);
 }
 
-static inline float64 ldfq_le_p(void *ptr)
+static inline float64 ldfq_le_p(const void *ptr)
 {
     CPU_DoubleU u;
     u.l.lower = ldl_le_p(ptr);
@@ -343,22 +341,22 @@
 
 #else
 
-static inline int lduw_le_p(void *ptr)
+static inline int lduw_le_p(const void *ptr)
 {
     return *(uint16_t *)ptr;
 }
 
-static inline int ldsw_le_p(void *ptr)
+static inline int ldsw_le_p(const void *ptr)
 {
     return *(int16_t *)ptr;
 }
 
-static inline int ldl_le_p(void *ptr)
+static inline int ldl_le_p(const void *ptr)
 {
     return *(uint32_t *)ptr;
 }
 
-static inline uint64_t ldq_le_p(void *ptr)
+static inline uint64_t ldq_le_p(const void *ptr)
 {
     return *(uint64_t *)ptr;
 }
@@ -375,23 +373,17 @@
 
 static inline void stq_le_p(void *ptr, uint64_t v)
 {
-#if defined(__i386__) && __GNUC__ >= 4
-    const union { uint64_t v; uint32_t p[2]; } x = { .v = v };
-    ((uint32_t *)ptr)[0] = x.p[0];
-    ((uint32_t *)ptr)[1] = x.p[1];
-#else
     *(uint64_t *)ptr = v;
-#endif
 }
 
 /* float access */
 
-static inline float32 ldfl_le_p(void *ptr)
+static inline float32 ldfl_le_p(const void *ptr)
 {
     return *(float32 *)ptr;
 }
 
-static inline float64 ldfq_le_p(void *ptr)
+static inline float64 ldfq_le_p(const void *ptr)
 {
     return *(float64 *)ptr;
 }
@@ -409,7 +401,7 @@
 
 #if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
 
-static inline int lduw_be_p(void *ptr)
+static inline int lduw_be_p(const void *ptr)
 {
 #if defined(__i386__)
     int val;
@@ -419,12 +411,12 @@
                   : "m" (*(uint16_t *)ptr));
     return val;
 #else
-    uint8_t *b = (uint8_t *) ptr;
+    const uint8_t *b = ptr;
     return ((b[0] << 8) | b[1]);
 #endif
 }
 
-static inline int ldsw_be_p(void *ptr)
+static inline int ldsw_be_p(const void *ptr)
 {
 #if defined(__i386__)
     int val;
@@ -434,12 +426,12 @@
                   : "m" (*(uint16_t *)ptr));
     return (int16_t)val;
 #else
-    uint8_t *b = (uint8_t *) ptr;
+    const uint8_t *b = ptr;
     return (int16_t)((b[0] << 8) | b[1]);
 #endif
 }
 
-static inline int ldl_be_p(void *ptr)
+static inline int ldl_be_p(const void *ptr)
 {
 #if defined(__i386__) || defined(__x86_64__)
     int val;
@@ -449,12 +441,12 @@
                   : "m" (*(uint32_t *)ptr));
     return val;
 #else
-    uint8_t *b = (uint8_t *) ptr;
+    const uint8_t *b = ptr;
     return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
 #endif
 }
 
-static inline uint64_t ldq_be_p(void *ptr)
+static inline uint64_t ldq_be_p(const void *ptr)
 {
     uint32_t a,b;
     a = ldl_be_p(ptr);
@@ -500,7 +492,7 @@
 
 /* float access */
 
-static inline float32 ldfl_be_p(void *ptr)
+static inline float32 ldfl_be_p(const void *ptr)
 {
     union {
         float32 f;
@@ -520,7 +512,7 @@
     stl_be_p(ptr, u.i);
 }
 
-static inline float64 ldfq_be_p(void *ptr)
+static inline float64 ldfq_be_p(const void *ptr)
 {
     CPU_DoubleU u;
     u.l.upper = ldl_be_p(ptr);
@@ -538,22 +530,22 @@
 
 #else
 
-static inline int lduw_be_p(void *ptr)
+static inline int lduw_be_p(const void *ptr)
 {
     return *(uint16_t *)ptr;
 }
 
-static inline int ldsw_be_p(void *ptr)
+static inline int ldsw_be_p(const void *ptr)
 {
     return *(int16_t *)ptr;
 }
 
-static inline int ldl_be_p(void *ptr)
+static inline int ldl_be_p(const void *ptr)
 {
     return *(uint32_t *)ptr;
 }
 
-static inline uint64_t ldq_be_p(void *ptr)
+static inline uint64_t ldq_be_p(const void *ptr)
 {
     return *(uint64_t *)ptr;
 }
@@ -575,12 +567,12 @@
 
 /* float access */
 
-static inline float32 ldfl_be_p(void *ptr)
+static inline float32 ldfl_be_p(const void *ptr)
 {
     return *(float32 *)ptr;
 }
 
-static inline float64 ldfq_be_p(void *ptr)
+static inline float64 ldfq_be_p(const void *ptr)
 {
     return *(float64 *)ptr;
 }
@@ -627,6 +619,9 @@
 /* MMU memory access macros */
 
 #if defined(CONFIG_USER_ONLY)
+#include <assert.h>
+#include "qemu-types.h"
+
 /* On some host systems the guest address space is reserved on the host.
  * This allows the guest address space to be offset to a convenient location.
  */
@@ -635,7 +630,16 @@
 
 /* All direct uses of g2h and h2g need to go away for usermode softmmu.  */
 #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
-#define h2g(x) ((target_ulong)((unsigned long)(x) - GUEST_BASE))
+#define h2g(x) ({ \
+    unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \
+    /* Check if given address fits target address space */ \
+    assert(__ret == (abi_ulong)__ret); \
+    (abi_ulong)__ret; \
+})
+#define h2g_valid(x) ({ \
+    unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \
+    (__guest == (abi_ulong)__guest); \
+})
 
 #define saddr(x) g2h(x)
 #define laddr(x) g2h(x)
@@ -731,12 +735,15 @@
 #define PAGE_RESERVED  0x0020
 
 void page_dump(FILE *f);
+int walk_memory_regions(void *,
+    int (*fn)(void *, unsigned long, unsigned long, unsigned long));
 int page_get_flags(target_ulong address);
 void page_set_flags(target_ulong start, target_ulong end, int flags);
 int page_check_range(target_ulong start, target_ulong len, int flags);
 
 void cpu_exec_init_all(unsigned long tb_size);
 CPUState *cpu_copy(CPUState *env);
+CPUState *qemu_get_cpu(int cpu);
 
 void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
@@ -745,15 +752,13 @@
                           int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                           int flags);
 
-void cpu_abort(CPUState *env, const char *fmt, ...)
-    __attribute__ ((__format__ (__printf__, 2, 3)))
-    __attribute__ ((__noreturn__));
+void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...)
+    __attribute__ ((__format__ (__printf__, 2, 3)));
 extern CPUState *first_cpu;
 extern CPUState *cpu_single_env;
 extern int64_t qemu_icount;
 extern int use_icount;
 
-#define CPU_INTERRUPT_EXIT   0x01 /* wants exit from main loop */
 #define CPU_INTERRUPT_HARD   0x02 /* hardware interrupt pending */
 #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
 #define CPU_INTERRUPT_TIMER  0x08 /* internal timer exception pending */
@@ -767,12 +772,30 @@
 void cpu_interrupt(CPUState *s, int mask);
 void cpu_reset_interrupt(CPUState *env, int mask);
 
-int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type);
-int cpu_watchpoint_remove(CPUState *env, target_ulong addr);
-void cpu_watchpoint_remove_all(CPUState *env);
-int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
-int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
-void cpu_breakpoint_remove_all(CPUState *env);
+void cpu_exit(CPUState *s);
+
+int qemu_cpu_has_work(CPUState *env);
+
+/* Breakpoint/watchpoint flags */
+#define BP_MEM_READ           0x01
+#define BP_MEM_WRITE          0x02
+#define BP_MEM_ACCESS         (BP_MEM_READ | BP_MEM_WRITE)
+#define BP_STOP_BEFORE_ACCESS 0x04
+#define BP_WATCHPOINT_HIT     0x08
+#define BP_GDB                0x10
+#define BP_CPU                0x20
+
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+                          CPUBreakpoint **breakpoint);
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags);
+void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint);
+void cpu_breakpoint_remove_all(CPUState *env, int mask);
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags, CPUWatchpoint **watchpoint);
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr,
+                          target_ulong len, int flags);
+void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint);
+void cpu_watchpoint_remove_all(CPUState *env, int mask);
 
 #define SSTEP_ENABLE  0x1  /* Enable simulated HW single stepping */
 #define SSTEP_NOIRQ   0x2  /* Do not use IRQ while single stepping */
@@ -795,6 +818,7 @@
 #define CPU_LOG_PCALL      (1 << 6)
 #define CPU_LOG_IOPORT     (1 << 7)
 #define CPU_LOG_TB_CPU     (1 << 8)
+#define CPU_LOG_RESET      (1 << 9)
 
 /* define log items */
 typedef struct CPULogItem {
@@ -803,7 +827,7 @@
     const char *help;
 } CPULogItem;
 
-extern CPULogItem cpu_log_items[];
+extern const CPULogItem cpu_log_items[];
 
 void cpu_set_log(int log_flags);
 void cpu_set_log_filename(const char *filename);
@@ -822,20 +846,12 @@
 int cpu_inl(CPUState *env, int addr);
 #endif
 
-/* address in the RAM (different from a physical address) */
-#ifdef USE_KQEMU
-typedef uint32_t ram_addr_t;
-#else
-typedef unsigned long ram_addr_t;
-#endif
-
 /* memory API */
 
-extern ram_addr_t phys_ram_size;
 extern int phys_ram_fd;
-extern uint8_t *phys_ram_base;
 extern uint8_t *phys_ram_dirty;
 extern ram_addr_t ram_size;
+extern ram_addr_t last_ram_offset;
 
 /* physical memory access */
 
@@ -843,19 +859,8 @@
    3 flags.  The ROMD code stores the page ram offset in iotlb entry, 
    so only a limited number of ids are avaiable.  */
 
-#define IO_MEM_SHIFT       3
 #define IO_MEM_NB_ENTRIES  (1 << (TARGET_PAGE_BITS  - IO_MEM_SHIFT))
 
-#define IO_MEM_RAM         (0 << IO_MEM_SHIFT) /* hardcoded offset */
-#define IO_MEM_ROM         (1 << IO_MEM_SHIFT) /* hardcoded offset */
-#define IO_MEM_UNASSIGNED  (2 << IO_MEM_SHIFT)
-#define IO_MEM_NOTDIRTY    (3 << IO_MEM_SHIFT)
-
-/* Acts like a ROM when read and like a device when written.  */
-#define IO_MEM_ROMD        (1)
-#define IO_MEM_SUBPAGE     (2)
-#define IO_MEM_SUBWIDTH    (4)
-
 /* Flags stored in the low bits of the TLB virtual address.  These are
    defined so that fast path ram access is all zeros.  */
 /* Zero if TLB entry is valid.  */
@@ -866,52 +871,13 @@
 /* Set if TLB entry is an IO callback.  */
 #define TLB_MMIO        (1 << 5)
 
-typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
-typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
-
-void cpu_register_physical_memory(target_phys_addr_t start_addr,
-                                  ram_addr_t size,
-                                  ram_addr_t phys_offset);
-ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr);
-ram_addr_t qemu_ram_alloc(ram_addr_t);
-void qemu_ram_free(ram_addr_t addr);
-int cpu_register_io_memory(int io_index,
-                           CPUReadMemoryFunc **mem_read,
-                           CPUWriteMemoryFunc **mem_write,
-                           void *opaque);
-CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
-CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);
-
-void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
-                            int len, int is_write);
-static inline void cpu_physical_memory_read(target_phys_addr_t addr,
-                                            uint8_t *buf, int len)
-{
-    cpu_physical_memory_rw(addr, buf, len, 0);
-}
-static inline void cpu_physical_memory_write(target_phys_addr_t addr,
-                                             const uint8_t *buf, int len)
-{
-    cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
-}
-uint32_t ldub_phys(target_phys_addr_t addr);
-uint32_t lduw_phys(target_phys_addr_t addr);
-uint32_t ldl_phys(target_phys_addr_t addr);
-uint64_t ldq_phys(target_phys_addr_t addr);
-void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
-void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
-void stb_phys(target_phys_addr_t addr, uint32_t val);
-void stw_phys(target_phys_addr_t addr, uint32_t val);
-void stl_phys(target_phys_addr_t addr, uint32_t val);
-void stq_phys(target_phys_addr_t addr, uint64_t val);
-
-void cpu_physical_memory_write_rom(target_phys_addr_t addr,
-                                   const uint8_t *buf, int len);
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write);
 
-#define VGA_DIRTY_FLAG  0x01
-#define CODE_DIRTY_FLAG 0x02
+#define VGA_DIRTY_FLAG       0x01
+#define CODE_DIRTY_FLAG      0x02
+#define KQEMU_DIRTY_FLAG     0x04
+#define MIGRATION_DIRTY_FLAG 0x08
 
 /* read dirty bit (return 0 or 1) */
 static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
@@ -934,38 +900,54 @@
                                      int dirty_flags);
 void cpu_tlb_update_dirty(CPUState *env);
 
+int cpu_physical_memory_set_dirty_tracking(int enable);
+
+int cpu_physical_memory_get_dirty_tracking(void);
+
+int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr);
+
 void dump_exec_info(FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
 
+/* Coalesced MMIO regions are areas where write operations can be reordered.
+ * This usually implies that write operations are side-effect free.  This allows
+ * batching which can make a major impact on performance when using
+ * virtualization.
+ */
+void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
+
+void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
+
 /*******************************************/
 /* host CPU ticks (if available) */
 
-#if defined(__powerpc__)
-
-static inline uint32_t get_tbl(void)
-{
-    uint32_t tbl;
-    asm volatile("mftb %0" : "=r" (tbl));
-    return tbl;
-}
-
-static inline uint32_t get_tbu(void)
-{
-	uint32_t tbl;
-	asm volatile("mftbu %0" : "=r" (tbl));
-	return tbl;
-}
+#if defined(_ARCH_PPC)
 
 static inline int64_t cpu_get_real_ticks(void)
 {
-    uint32_t l, h, h1;
-    /* NOTE: we test if wrapping has occurred */
-    do {
-        h = get_tbu();
-        l = get_tbl();
-        h1 = get_tbu();
-    } while (h != h1);
-    return ((int64_t)h << 32) | l;
+    int64_t retval;
+#ifdef _ARCH_PPC64
+    /* This reads timebase in one 64bit go and includes Cell workaround from:
+       http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html
+     */
+    __asm__ __volatile__ (
+        "mftb    %0\n\t"
+        "cmpwi   %0,0\n\t"
+        "beq-    $-8"
+        : "=r" (retval));
+#else
+    /* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */
+    unsigned long junk;
+    __asm__ __volatile__ (
+        "mftbu   %1\n\t"
+        "mftb    %L0\n\t"
+        "mftbu   %0\n\t"
+        "cmpw    %0,%1\n\t"
+        "bne     $-16"
+        : "=r" (retval), "=r" (junk));
+#endif
+    return retval;
 }
 
 #elif defined(__i386__)
diff --git a/cpu-common.h b/cpu-common.h
new file mode 100644
index 0000000..8f89325
--- /dev/null
+++ b/cpu-common.h
@@ -0,0 +1,95 @@
+#ifndef CPU_COMMON_H
+#define CPU_COMMON_H 1
+
+/* CPU interfaces that are target indpendent.  */
+
+#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__)
+#define WORDS_ALIGNED
+#endif
+
+#include "bswap.h"
+
+/* address in the RAM (different from a physical address) */
+#ifdef CONFIG_KQEMU
+/* FIXME: This is wrong.  */
+typedef uint32_t ram_addr_t;
+#else
+typedef unsigned long ram_addr_t;
+#endif
+
+/* memory API */
+
+typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
+typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
+
+void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+                                         ram_addr_t size,
+                                         ram_addr_t phys_offset,
+                                         ram_addr_t region_offset);
+static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
+                                                ram_addr_t size,
+                                                ram_addr_t phys_offset)
+{
+    cpu_register_physical_memory_offset(start_addr, size, phys_offset, 0);
+}
+
+ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr);
+ram_addr_t qemu_ram_alloc(ram_addr_t);
+void qemu_ram_free(ram_addr_t addr);
+/* This should only be used for ram local to a device.  */
+void *qemu_get_ram_ptr(ram_addr_t addr);
+/* This should not be used by devices.  */
+ram_addr_t qemu_ram_addr_from_host(void *ptr);
+
+int cpu_register_io_memory(CPUReadMemoryFunc **mem_read,
+                           CPUWriteMemoryFunc **mem_write,
+                           void *opaque);
+void cpu_unregister_io_memory(int table_address);
+
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
+                            int len, int is_write);
+static inline void cpu_physical_memory_read(target_phys_addr_t addr,
+                                            uint8_t *buf, int len)
+{
+    cpu_physical_memory_rw(addr, buf, len, 0);
+}
+static inline void cpu_physical_memory_write(target_phys_addr_t addr,
+                                             const uint8_t *buf, int len)
+{
+    cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
+}
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+                              target_phys_addr_t *plen,
+                              int is_write);
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+                               int is_write, target_phys_addr_t access_len);
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
+void cpu_unregister_map_client(void *cookie);
+
+uint32_t ldub_phys(target_phys_addr_t addr);
+uint32_t lduw_phys(target_phys_addr_t addr);
+uint32_t ldl_phys(target_phys_addr_t addr);
+uint64_t ldq_phys(target_phys_addr_t addr);
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
+void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
+void stb_phys(target_phys_addr_t addr, uint32_t val);
+void stw_phys(target_phys_addr_t addr, uint32_t val);
+void stl_phys(target_phys_addr_t addr, uint32_t val);
+void stq_phys(target_phys_addr_t addr, uint64_t val);
+
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+                                   const uint8_t *buf, int len);
+
+#define IO_MEM_SHIFT       3
+
+#define IO_MEM_RAM         (0 << IO_MEM_SHIFT) /* hardcoded offset */
+#define IO_MEM_ROM         (1 << IO_MEM_SHIFT) /* hardcoded offset */
+#define IO_MEM_UNASSIGNED  (2 << IO_MEM_SHIFT)
+#define IO_MEM_NOTDIRTY    (3 << IO_MEM_SHIFT)
+
+/* Acts like a ROM when read and like a device when written.  */
+#define IO_MEM_ROMD        (1)
+#define IO_MEM_SUBPAGE     (2)
+#define IO_MEM_SUBWIDTH    (4)
+
+#endif /* !CPU_COMMON_H */
diff --git a/cpu-defs.h b/cpu-defs.h
index 108d395..e57064f 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -15,28 +15,29 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #ifndef CPU_DEFS_H
 #define CPU_DEFS_H
 
+#if 0 /* ANDROID */
+#ifndef NEED_CPU_H
+#error cpu.h included from common code
+#endif
+#endif /* ANDROID */
+
 #include "config.h"
 #include <setjmp.h>
 #include <inttypes.h>
+#include <signal.h>
 #include "osdep.h"
+#include "sys-queue.h"
+#include "targphys.h"
 
 #ifndef TARGET_LONG_BITS
 #error TARGET_LONG_BITS must be defined before including this header
 #endif
 
-#ifndef TARGET_PHYS_ADDR_BITS
-#if TARGET_LONG_BITS >= HOST_LONG_BITS
-#define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
-#else
-#define TARGET_PHYS_ADDR_BITS HOST_LONG_BITS
-#endif
-#endif
-
 #define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
 
 /* target_ulong is the type of a virtual address */
@@ -56,30 +57,12 @@
 #error TARGET_LONG_SIZE undefined
 #endif
 
-/* target_phys_addr_t is the type of a physical address (its size can
-   be different from 'target_ulong'). We have sizeof(target_phys_addr)
-   = max(sizeof(unsigned long),
-   sizeof(size_of_target_physical_address)) because we must pass a
-   host pointer to memory operations in some cases */
-
-#if TARGET_PHYS_ADDR_BITS == 32
-typedef uint32_t target_phys_addr_t;
-#define TARGET_FMT_plx "%08x"
-#elif TARGET_PHYS_ADDR_BITS == 64
-typedef uint64_t target_phys_addr_t;
-#define TARGET_FMT_plx "%016" PRIx64
-#else
-#error TARGET_PHYS_ADDR_BITS undefined
-#endif
-
 #define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
 
 #define EXCP_INTERRUPT 	0x10000 /* async interruption */
 #define EXCP_HLT        0x10001 /* hlt instruction reached */
 #define EXCP_DEBUG      0x10002 /* cpu stopped after a breakpoint or singlestep */
 #define EXCP_HALTED     0x10003 /* cpu is halted (waiting for external event) */
-#define MAX_BREAKPOINTS 32
-#define MAX_WATCHPOINTS 32
 
 #define TB_JMP_CACHE_BITS 12
 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
@@ -112,7 +95,7 @@
     target_ulong addr_write;
     target_ulong addr_code;
     /* Addend to virtual address to get physical address.  IO accesses
-       use the correcponding iotlb value.  */
+       use the corresponding iotlb value.  */
 #if TARGET_PHYS_ADDR_BITS == 64
     /* on i386 Linux make sure it is aligned */
     target_phys_addr_t addend __attribute__((aligned(8)));
@@ -138,6 +121,22 @@
 } icount_decr_u16;
 #endif
 
+struct kvm_run;
+struct KVMState;
+
+typedef struct CPUBreakpoint {
+    target_ulong pc;
+    int flags; /* BP_* */
+    TAILQ_ENTRY(CPUBreakpoint) entry;
+} CPUBreakpoint;
+
+typedef struct CPUWatchpoint {
+    target_ulong vaddr;
+    target_ulong len_mask;
+    int flags; /* BP_* */
+    TAILQ_ENTRY(CPUWatchpoint) entry;
+} CPUWatchpoint;
+
 #define CPU_TEMP_BUF_NLONGS 128
 #define CPU_COMMON                                                      \
     struct TranslationBlock *current_tb; /* currently executing TB  */  \
@@ -150,7 +149,10 @@
     target_ulong mem_io_vaddr; /* target virtual addr at which the      \
                                      memory was accessed */             \
     uint32_t halted; /* Nonzero if the CPU is in suspend state */       \
+    uint32_t stop;   /* Stop request */                                 \
+    uint32_t stopped; /* Artificially stopped */                        \
     uint32_t interrupt_request;                                         \
+    volatile sig_atomic_t exit_request;                                 \
     /* The meaning of the MMU modes is defined in the target code. */   \
     CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE];                  \
     target_phys_addr_t iotlb[NB_MMU_MODES][CPU_TLB_SIZE];               \
@@ -170,29 +172,32 @@
                                                                         \
     /* from this point: preserved by CPU reset */                       \
     /* ice debug support */                                             \
-    target_ulong breakpoints[MAX_BREAKPOINTS];                          \
-    int nb_breakpoints;                                                 \
+    TAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints;            \
     int singlestep_enabled;                                             \
                                                                         \
-    struct {                                                            \
-        target_ulong vaddr;                                             \
-        int type; /* PAGE_READ/PAGE_WRITE */                            \
-    } watchpoint[MAX_WATCHPOINTS];                                      \
-    int nb_watchpoints;                                                 \
-    int watchpoint_hit;                                                 \
+    TAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints;            \
+    CPUWatchpoint *watchpoint_hit;                                      \
+                                                                        \
+    struct GDBRegisterState *gdb_regs;                                  \
                                                                         \
     /* Core interrupt code */                                           \
     jmp_buf jmp_env;                                                    \
     int exception_index;                                                \
                                                                         \
-    int user_mode_only;                                                 \
-                                                                        \
-    void *next_cpu; /* next CPU sharing TB cache */                     \
+    CPUState *next_cpu; /* next CPU sharing TB cache */                 \
     int cpu_index; /* CPU index (informative) */                        \
+    uint32_t host_tid; /* host thread ID */                             \
+    int numa_node; /* NUMA node this cpu is belonging to  */            \
     int running; /* Nonzero if cpu is currently running(usermode).  */  \
     /* user data */                                                     \
     void *opaque;                                                       \
                                                                         \
-    const char *cpu_model_str;
+    uint32_t created;                                                   \
+    struct QemuThread *thread;                                          \
+    struct QemuCond *halt_cond;                                         \
+    const char *cpu_model_str;                                          \
+    struct KVMState *kvm_state;                                         \
+    struct kvm_run *kvm_run;                                            \
+    int kvm_fd;
 
 #endif
diff --git a/cpu-exec.c b/cpu-exec.c
index 8637e2a..8734337 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -15,13 +15,13 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include "config.h"
-#define CPU_NO_GLOBAL_REGS
 #include "exec.h"
 #include "disas.h"
 #include "tcg.h"
+#include "kvm.h"
 
 #if !defined(CONFIG_SOFTMMU)
 #undef EAX
@@ -34,8 +34,10 @@
 #undef EDI
 #undef EIP
 #include <signal.h>
+#ifdef __linux__
 #include <sys/ucontext.h>
 #endif
+#endif
 
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
 // Work around ugly bugs in glibc that mangle global register contents
@@ -48,6 +50,11 @@
 //#define DEBUG_EXEC
 //#define DEBUG_SIGNAL
 
+int qemu_cpu_has_work(CPUState *env)
+{
+    return cpu_has_work(env);
+}
+
 void cpu_loop_exit(void)
 {
     /* NOTE: the register at this point must be saved by hand because
@@ -56,17 +63,17 @@
     longjmp(env->jmp_env, 1);
 }
 
-#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
-#define reg_T2
-#endif
-
 /* exit the current TB from a signal handler. The host registers are
    restored in a state compatible with the CPU emulator
  */
 void cpu_resume_from_signal(CPUState *env1, void *puc)
 {
 #if !defined(CONFIG_SOFTMMU)
+#ifdef __linux__
     struct ucontext *uc = puc;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#endif
 #endif
 
     env = env1;
@@ -76,9 +83,14 @@
 #if !defined(CONFIG_SOFTMMU)
     if (puc) {
         /* XXX: use siglongjmp ? */
+#ifdef __linux__
         sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+#elif defined(__OpenBSD__)
+        sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
+#endif
     }
 #endif
+    env->exception_index = -1;
     longjmp(env->jmp_env, 1);
 }
 
@@ -103,7 +115,7 @@
     if ((next_tb & 3) == 2) {
         /* Restore PC.  This may happen if async event occurs before
            the TB starts executing.  */
-        CPU_PC_FROM_TB(env, tb);
+        cpu_pc_from_tb(env, tb);
     }
     tb_phys_invalidate(tb, -1);
     tb_free(tb);
@@ -162,71 +174,12 @@
 {
     TranslationBlock *tb;
     target_ulong cs_base, pc;
-    uint64_t flags;
+    int flags;
 
     /* we record a subset of the CPU state. It will
        always be the same before a given translated block
        is executed. */
-#if defined(TARGET_I386)
-    flags = env->hflags;
-    flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
-    cs_base = env->segs[R_CS].base;
-    pc = cs_base + env->eip;
-#elif defined(TARGET_ARM)
-    flags = env->thumb | (env->vfp.vec_len << 1)
-            | (env->vfp.vec_stride << 4);
-    if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
-        flags |= (1 << 6);
-    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
-        flags |= (1 << 7);
-    flags |= (env->condexec_bits << 8);
-    cs_base = 0;
-    pc = env->regs[15];
-#elif defined(TARGET_SPARC)
-#ifdef TARGET_SPARC64
-    // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
-    flags = ((env->pstate & PS_AM) << 2)
-        | (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
-        | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
-#else
-    // FPU enable . Supervisor
-    flags = (env->psref << 4) | env->psrs;
-#endif
-    cs_base = env->npc;
-    pc = env->pc;
-#elif defined(TARGET_PPC)
-    flags = env->hflags;
-    cs_base = 0;
-    pc = env->nip;
-#elif defined(TARGET_MIPS)
-    flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
-    cs_base = 0;
-    pc = env->active_tc.PC;
-#elif defined(TARGET_M68K)
-    flags = (env->fpcr & M68K_FPCR_PREC)  /* Bit  6 */
-            | (env->sr & SR_S)            /* Bit  13 */
-            | ((env->macsr >> 4) & 0xf);  /* Bits 0-3 */
-    cs_base = 0;
-    pc = env->pc;
-#elif defined(TARGET_SH4)
-    flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
-                    | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME))   /* Bits  0- 3 */
-            | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR))  /* Bits 19-21 */
-            | (env->sr & (SR_MD | SR_RB));                     /* Bits 29-30 */
-    cs_base = 0;
-    pc = env->pc;
-#elif defined(TARGET_ALPHA)
-    flags = env->ps;
-    cs_base = 0;
-    pc = env->pc;
-#elif defined(TARGET_CRIS)
-    flags = env->pregs[PR_CCS] & (P_FLAG | U_FLAG | X_FLAG);
-    flags |= env->dslot;
-    cs_base = 0;
-    pc = env->pc;
-#else
-#error unsupported CPU
-#endif
+    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
     if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                  tb->flags != flags)) {
@@ -235,6 +188,28 @@
     return tb;
 }
 
+static CPUDebugExcpHandler *debug_excp_handler;
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+{
+    CPUDebugExcpHandler *old_handler = debug_excp_handler;
+
+    debug_excp_handler = handler;
+    return old_handler;
+}
+
+static void cpu_handle_debug_exception(CPUState *env)
+{
+    CPUWatchpoint *wp;
+
+    if (!env->watchpoint_hit)
+        TAILQ_FOREACH(wp, &env->watchpoints, entry)
+            wp->flags &= ~BP_WATCHPOINT_HIT;
+
+    if (debug_excp_handler)
+        debug_excp_handler(env);
+}
+
 /* main execution loop */
 
 int cpu_exec(CPUState *env1)
@@ -271,6 +246,7 @@
 #elif defined(TARGET_ALPHA)
 #elif defined(TARGET_ARM)
 #elif defined(TARGET_PPC)
+#elif defined(TARGET_MICROBLAZE)
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_CRIS)
@@ -283,14 +259,22 @@
     /* prepare setjmp context for exception handling */
     for(;;) {
         if (setjmp(env->jmp_env) == 0) {
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+#undef env
+                    env = cpu_single_env;
+#define env cpu_single_env
+#endif
             env->current_tb = NULL;
             /* if an exception is pending, we execute it here */
             if (env->exception_index >= 0) {
                 if (env->exception_index >= EXCP_INTERRUPT) {
                     /* exit request from the cpu execution loop */
                     ret = env->exception_index;
+                    if (ret == EXCP_DEBUG)
+                        cpu_handle_debug_exception(env);
                     break;
-                } else if (env->user_mode_only) {
+                } else {
+#if defined(CONFIG_USER_ONLY)
                     /* if user mode only, we simulate a fake exception
                        which will be handled outside the cpu execution
                        loop */
@@ -304,7 +288,7 @@
 #endif
                     ret = env->exception_index;
                     break;
-                } else {
+#else
 #if defined(TARGET_I386)
                     /* simulate a real cpu exception. On i386, it can
                        trigger new exceptions, but we do not handle
@@ -317,6 +301,8 @@
                     env->old_exception = -1;
 #elif defined(TARGET_PPC)
                     do_interrupt(env);
+#elif defined(TARGET_MICROBLAZE)
+                    do_interrupt(env);
 #elif defined(TARGET_MIPS)
                     do_interrupt(env);
 #elif defined(TARGET_SPARC)
@@ -332,13 +318,14 @@
 #elif defined(TARGET_M68K)
                     do_interrupt(0);
 #endif
+#endif
                 }
                 env->exception_index = -1;
             }
-#ifdef USE_KQEMU
-            if (kqemu_is_ok(env) && env->interrupt_request == 0) {
+#ifdef CONFIG_KQEMU
+            if (kqemu_is_ok(env) && env->interrupt_request == 0 && env->exit_request == 0) {
                 int ret;
-                env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
+                env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
                 ret = kqemu_cpu_exec(env);
                 /* put eflags in CPU temporary format */
                 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
@@ -351,7 +338,7 @@
                 } else if (ret == 2) {
                     /* softmmu execution needed */
                 } else {
-                    if (env->interrupt_request != 0) {
+                    if (env->interrupt_request != 0 || env->exit_request != 0) {
                         /* hardware interrupt will be executed just after */
                     } else {
                         /* otherwise, we restart */
@@ -361,18 +348,30 @@
             }
 #endif
 
+            if (kvm_enabled()) {
+                kvm_cpu_exec(env);
+                longjmp(env->jmp_env, 1);
+            }
+
             next_tb = 0; /* force lookup of first TB */
             for(;;) {
                 interrupt_request = env->interrupt_request;
-                if (unlikely(interrupt_request) &&
-                    likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
+                if (unlikely(interrupt_request)) {
+                    if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
+                        /* Mask out external interrupts for this step. */
+                        interrupt_request &= ~(CPU_INTERRUPT_HARD |
+                                               CPU_INTERRUPT_FIQ |
+                                               CPU_INTERRUPT_SMI |
+                                               CPU_INTERRUPT_NMI);
+                    }
                     if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                         env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                         env->exception_index = EXCP_DEBUG;
                         cpu_loop_exit();
                     }
 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
-    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
+    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
+    defined(TARGET_MICROBLAZE)
                     if (interrupt_request & CPU_INTERRUPT_HALT) {
                         env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                         env->halted = 1;
@@ -404,9 +403,12 @@
                             svm_check_intercept(SVM_EXIT_INTR);
                             env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
                             intno = cpu_get_pic_interrupt(env);
-                            if (loglevel & CPU_LOG_TB_IN_ASM) {
-                                fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
-                            }
+                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+#undef env
+                    env = cpu_single_env;
+#define env cpu_single_env
+#endif
                             do_interrupt(intno, 0, 0, 0, 1);
                             /* ensure that no TB jump will be modified as
                                the program flow was changed */
@@ -418,11 +420,10 @@
                             int intno;
                             /* FIXME: this should respect TPR */
                             svm_check_intercept(SVM_EXIT_VINTR);
-                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
                             intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
-                            if (loglevel & CPU_LOG_TB_IN_ASM)
-                                fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
+                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
                             do_interrupt(intno, 0, 0, 0, 1);
+                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
                             next_tb = 0;
 #endif
                         }
@@ -439,6 +440,15 @@
                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
                         next_tb = 0;
                     }
+#elif defined(TARGET_MICROBLAZE)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD)
+                        && (env->sregs[SR_MSR] & MSR_IE)
+                        && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
+                        && !(env->iflags & (D_FLAG | IMM_FLAG))) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #elif defined(TARGET_MIPS)
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                         (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
@@ -542,40 +552,42 @@
                            the program flow was changed */
                         next_tb = 0;
                     }
-                    if (interrupt_request & CPU_INTERRUPT_EXIT) {
-                        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
-                        env->exception_index = EXCP_INTERRUPT;
-                        cpu_loop_exit();
-                    }
+                }
+                if (unlikely(env->exit_request)) {
+                    env->exit_request = 0;
+                    env->exception_index = EXCP_INTERRUPT;
+                    cpu_loop_exit();
                 }
 #ifdef DEBUG_EXEC
-                if ((loglevel & CPU_LOG_TB_CPU)) {
+                if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
                     /* restore flags in standard format */
                     regs_to_env();
 #if defined(TARGET_I386)
-                    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
-                    cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
+                    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
+                    log_cpu_state(env, X86_DUMP_CCOP);
                     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
 #elif defined(TARGET_ARM)
-                    cpu_dump_state(env, logfile, fprintf, 0);
+                    log_cpu_state(env, 0);
 #elif defined(TARGET_SPARC)
-                    cpu_dump_state(env, logfile, fprintf, 0);
+                    log_cpu_state(env, 0);
 #elif defined(TARGET_PPC)
-                    cpu_dump_state(env, logfile, fprintf, 0);
+                    log_cpu_state(env, 0);
 #elif defined(TARGET_M68K)
                     cpu_m68k_flush_flags(env, env->cc_op);
                     env->cc_op = CC_OP_FLAGS;
                     env->sr = (env->sr & 0xffe0)
                               | env->cc_dest | (env->cc_x << 4);
-                    cpu_dump_state(env, logfile, fprintf, 0);
+                    log_cpu_state(env, 0);
+#elif defined(TARGET_MICROBLAZE)
+                    log_cpu_state(env, 0);
 #elif defined(TARGET_MIPS)
-                    cpu_dump_state(env, logfile, fprintf, 0);
+                    log_cpu_state(env, 0);
 #elif defined(TARGET_SH4)
-		    cpu_dump_state(env, logfile, fprintf, 0);
+		    log_cpu_state(env, 0);
 #elif defined(TARGET_ALPHA)
-                    cpu_dump_state(env, logfile, fprintf, 0);
+                    log_cpu_state(env, 0);
 #elif defined(TARGET_CRIS)
-                    cpu_dump_state(env, logfile, fprintf, 0);
+                    log_cpu_state(env, 0);
 #else
 #error unsupported target CPU
 #endif
@@ -593,18 +605,16 @@
                     tb_invalidated_flag = 0;
                 }
 #ifdef DEBUG_EXEC
-                if ((loglevel & CPU_LOG_EXEC)) {
-                    fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
-                            (long)tb->tc_ptr, tb->pc,
-                            lookup_symbol(tb->pc));
-                }
+                qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
+                             (long)tb->tc_ptr, tb->pc,
+                             lookup_symbol(tb->pc));
 #endif
                 /* see if we can patch the calling TB. When the TB
                    spans two pages, we cannot safely do a direct
                    jump. */
                 {
                     if (next_tb != 0 &&
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
                         (env->kqemu_enabled != 2) &&
 #endif
                         tb->page_addr[1] == -1) {
@@ -613,6 +623,14 @@
                 }
                 spin_unlock(&tb_lock);
                 env->current_tb = tb;
+
+                /* cpu_interrupt might be called while translating the
+                   TB, but before it is linked into a potentially
+                   infinite loop and becomes env->current_tb. Avoid
+                   starting execution if there is a pending interrupt. */
+                if (unlikely (env->exit_request))
+                    env->current_tb = NULL;
+
                 while (env->current_tb) {
                     tc_ptr = tb->tc_ptr;
                 /* execute the generated code */
@@ -628,7 +646,7 @@
                         int insns_left;
                         tb = (TranslationBlock *)(long)(next_tb & ~3);
                         /* Restore PC.  */
-                        CPU_PC_FROM_TB(env, tb);
+                        cpu_pc_from_tb(env, tb);
                         insns_left = env->icount_decr.u32;
                         if (env->icount_extra && insns_left >= 0) {
                             /* Refill decrementer and continue execution.  */
@@ -653,7 +671,7 @@
                 }
                 /* reset soft MMU for next block (it can currently
                    only be set by a memory fault) */
-#if defined(USE_KQEMU)
+#if defined(CONFIG_KQEMU)
 #define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
                 if (kqemu_is_ok(env) &&
                     (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
@@ -669,7 +687,7 @@
 
 #if defined(TARGET_I386)
     /* restore flags in standard format */
-    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
+    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
 #elif defined(TARGET_ARM)
     /* XXX: Save/restore host fpu exception state?.  */
 #elif defined(TARGET_SPARC)
@@ -679,6 +697,7 @@
     env->cc_op = CC_OP_FLAGS;
     env->sr = (env->sr & 0xffe0)
               | env->cc_dest | (env->cc_x << 4);
+#elif defined(TARGET_MICROBLAZE)
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
 #elif defined(TARGET_ALPHA)
@@ -927,7 +946,7 @@
     /* we restore the process signal mask as the sigreturn should
        do it (XXX: use sigsetjmp) */
         sigprocmask(SIG_SETMASK, old_set, NULL);
-        do_raise_exception_err(env->exception_index, env->error_code);
+        cpu_loop_exit();
     } else {
         /* activate soft MMU for this block */
         cpu_resume_from_signal(env, puc);
@@ -1016,7 +1035,57 @@
     /* we restore the process signal mask as the sigreturn should
        do it (XXX: use sigsetjmp) */
         sigprocmask(SIG_SETMASK, old_set, NULL);
-        do_raise_exception_err(env->exception_index, env->error_code);
+        cpu_loop_exit();
+    } else {
+        /* activate soft MMU for this block */
+        cpu_resume_from_signal(env, puc);
+    }
+    /* never comes here */
+    return 1;
+}
+
+#elif defined (TARGET_MICROBLAZE)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+                                    int is_write, sigset_t *old_set,
+                                    void *puc)
+{
+    TranslationBlock *tb;
+    int ret;
+
+    if (cpu_single_env)
+        env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+           pc, address, is_write, *(unsigned long *)old_set);
+#endif
+    /* XXX: locking issue */
+    if (is_write && page_unprotect(h2g(address), pc, puc)) {
+        return 1;
+    }
+
+    /* see if it is an MMU fault */
+    ret = cpu_mb_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
+    if (ret < 0)
+        return 0; /* not an MMU fault */
+    if (ret == 0)
+        return 1; /* the MMU fault was handled without causing real CPU fault */
+
+    /* now we have a real cpu fault */
+    tb = tb_find_pc(pc);
+    if (tb) {
+        /* the PC is inside the translated code. It means that we have
+           a virtual CPU fault */
+        cpu_restore_state(tb, env, pc, puc);
+    }
+    if (ret == 1) {
+#if 0
+        printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
+               env->PC, env->error_code, tb);
+#endif
+    /* we restore the process signal mask as the sigreturn should
+       do it (XXX: use sigsetjmp) */
+        sigprocmask(SIG_SETMASK, old_set, NULL);
+        cpu_loop_exit();
     } else {
         /* activate soft MMU for this block */
         cpu_resume_from_signal(env, puc);
@@ -1167,17 +1236,28 @@
 # define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
 # define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
 # define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
+# define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined(__OpenBSD__)
+# define EIP_sig(context)     ((context)->sc_eip)
+# define TRAP_sig(context)    ((context)->sc_trapno)
+# define ERROR_sig(context)   ((context)->sc_err)
+# define MASK_sig(context)    ((context)->sc_mask)
 #else
 # define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
 # define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
 # define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
+# define MASK_sig(context)    ((context)->uc_sigmask)
 #endif
 
 int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
     siginfo_t *info = pinfo;
+#if defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#else
     struct ucontext *uc = puc;
+#endif
     unsigned long pc;
     int trapno;
 
@@ -1192,26 +1272,49 @@
     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                              trapno == 0xe ?
                              (ERROR_sig(uc) >> 1) & 1 : 0,
-                             &uc->uc_sigmask, puc);
+                             &MASK_sig(uc), puc);
 }
 
 #elif defined(__x86_64__)
 
+#ifdef __NetBSD__
+#define PC_sig(context)       _UC_MACHINE_PC(context)
+#define TRAP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
+#define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
+#define MASK_sig(context)     ((context)->uc_sigmask)
+#elif defined(__OpenBSD__)
+#define PC_sig(context)       ((context)->sc_rip)
+#define TRAP_sig(context)     ((context)->sc_trapno)
+#define ERROR_sig(context)    ((context)->sc_err)
+#define MASK_sig(context)     ((context)->sc_mask)
+#else
+#define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
+#define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
+#define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
+#define MASK_sig(context)     ((context)->uc_sigmask)
+#endif
+
 int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
     siginfo_t *info = pinfo;
-    struct ucontext *uc = puc;
     unsigned long pc;
+#ifdef __NetBSD__
+    ucontext_t *uc = puc;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+#else
+    struct ucontext *uc = puc;
+#endif
 
-    pc = uc->uc_mcontext.gregs[REG_RIP];
+    pc = PC_sig(uc);
     return handle_cpu_signal(pc, (unsigned long)info->si_addr,
-                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
-                             (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
-                             &uc->uc_sigmask, puc);
+                             TRAP_sig(uc) == 0xe ?
+                             (ERROR_sig(uc) >> 1) & 1 : 0,
+                             &MASK_sig(uc), puc);
 }
 
-#elif defined(__powerpc__)
+#elif defined(_ARCH_PPC)
 
 /***********************************************************************
  * signal context platform-specific definitions
@@ -1328,9 +1431,15 @@
     /* XXX: is there a standard glibc define ? */
     unsigned long pc = regs[1];
 #else
+#ifdef __linux__
     struct sigcontext *sc = puc;
     unsigned long pc = sc->sigc_regs.tpc;
     void *sigmask = (void *)sc->sigc_mask;
+#elif defined(__OpenBSD__)
+    struct sigcontext *uc = puc;
+    unsigned long pc = uc->sc_pc;
+    void *sigmask = (void *)(long)uc->sc_mask;
+#endif
 #endif
 
     /* XXX: need kernel patch to get write flag faster */
@@ -1339,12 +1448,24 @@
     if ((insn >> 30) == 3) {
       switch((insn >> 19) & 0x3f) {
       case 0x05: // stb
+      case 0x15: // stba
       case 0x06: // sth
+      case 0x16: // stha
       case 0x04: // st
+      case 0x14: // sta
       case 0x07: // std
+      case 0x17: // stda
+      case 0x0e: // stx
+      case 0x1e: // stxa
       case 0x24: // stf
+      case 0x34: // stfa
       case 0x27: // stdf
+      case 0x37: // stdfa
+      case 0x26: // stqf
+      case 0x36: // stqfa
       case 0x25: // stfsr
+      case 0x3c: // casa
+      case 0x3e: // casxa
 	is_write = 1;
 	break;
       }
diff --git a/curses.c b/curses.c
index 96b6e49..8aae818 100644
--- a/curses.c
+++ b/curses.c
@@ -21,11 +21,6 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-
-#include "qemu-common.h"
-#include "console.h"
-#include "sysemu.h"
-
 #include <curses.h>
 
 #ifndef _WIN32
@@ -38,6 +33,10 @@
 #define resize_term resizeterm
 #endif
 
+#include "qemu-common.h"
+#include "console.h"
+#include "sysemu.h"
+
 #define FONT_HEIGHT 16
 #define FONT_WIDTH 8
 
@@ -60,7 +59,7 @@
 
 static void curses_calc_pad(void)
 {
-    if (is_graphic_console()) {
+    if (is_fixedsize_console()) {
         width = gwidth;
         height = gheight;
     } else {
@@ -97,15 +96,17 @@
     }
 }
 
-static void curses_resize(DisplayState *ds, int w, int h)
+static void curses_resize(DisplayState *ds)
 {
-    if (w == gwidth && h == gheight)
+    if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
         return;
 
-    gwidth = w;
-    gheight = h;
+    gwidth = ds_get_width(ds);
+    gheight = ds_get_height(ds);
 
     curses_calc_pad();
+    ds->surface->width = width * FONT_WIDTH;
+    ds->surface->height = height * FONT_HEIGHT;
 }
 
 #ifndef _WIN32
@@ -156,7 +157,6 @@
 /* generic keyboard conversion */
 
 #include "curses_keys.h"
-#include "keymaps.c"
 
 static kbd_layout_t *kbd_layout = 0;
 static int keycode2keysym[CURSES_KEYS];
@@ -169,8 +169,8 @@
         clear();
         refresh();
         curses_calc_pad();
-        ds->width = FONT_WIDTH * width;
-        ds->height = FONT_HEIGHT * height;
+        ds->surface->width = FONT_WIDTH * width;
+        ds->surface->height = FONT_HEIGHT * height;
         vga_hw_invalidate();
         invalidate = 0;
     }
@@ -197,8 +197,8 @@
             refresh();
             curses_calc_pad();
             curses_update(ds, 0, 0, width, height);
-            ds->width = FONT_WIDTH * width;
-            ds->height = FONT_HEIGHT * height;
+            ds->surface->width = FONT_WIDTH * width;
+            ds->surface->height = FONT_HEIGHT * height;
             continue;
         }
 #endif
@@ -309,7 +309,7 @@
         keyboard_layout = "en-us";
 #endif
     if(keyboard_layout) {
-        kbd_layout = init_keyboard_layout(keyboard_layout);
+        kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
         if (!kbd_layout)
             exit(1);
     }
@@ -338,6 +338,7 @@
 
 void curses_display_init(DisplayState *ds, int full_screen)
 {
+    DisplayChangeListener *dcl;
 #ifndef _WIN32
     if (!isatty(1)) {
         fprintf(stderr, "We need a terminal output\n");
@@ -357,18 +358,17 @@
 #endif
 #endif
 
-    ds->data = (void *) screen;
-    ds->linesize = 0;
-    ds->depth = 0;
-    ds->width = 640;
-    ds->height = 400;
-    ds->dpy_update = curses_update;
-    ds->dpy_resize = curses_resize;
-    ds->dpy_refresh = curses_refresh;
-    ds->dpy_text_cursor = curses_cursor_position;
+    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
+    dcl->dpy_update = curses_update;
+    dcl->dpy_resize = curses_resize;
+    dcl->dpy_refresh = curses_refresh;
+    dcl->dpy_text_cursor = curses_cursor_position;
+    register_displaychangelistener(ds, dcl);
+    qemu_free_displaysurface(ds);
+    ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
 
     invalidate = 1;
 
     /* Standard VGA initial text mode dimensions */
-    curses_resize(ds, 80, 25);
+    curses_resize(ds);
 }
diff --git a/curses_keys.h b/curses_keys.h
index 27f9cd8..4c6f3db 100644
--- a/curses_keys.h
+++ b/curses_keys.h
@@ -21,6 +21,10 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+
+#include "keymaps.h"
+
+
 #define KEY_RELEASE         0x80
 #define KEY_MASK            0x7f
 #define SHIFT_CODE          0x2a
@@ -37,7 +41,7 @@
 
 #define CURSES_KEYS         KEY_MAX     /* KEY_MAX defined in <curses.h> */
 
-int curses2keycode[CURSES_KEYS] = {
+static const int curses2keycode[CURSES_KEYS] = {
     [0 ... (CURSES_KEYS - 1)] = -1,
 
     [0x01b] = 1, /* Escape */
@@ -192,7 +196,7 @@
     [0x014] = 20 | CNTRL, /* Control + t */
     [0x019] = 21 | CNTRL, /* Control + y */
     [0x015] = 22 | CNTRL, /* Control + u */
-    [0x009] = 23 | CNTRL, /* Control + i */
+    /* Control + i collides with Tab */
     [0x00f] = 24 | CNTRL, /* Control + o */
     [0x010] = 25 | CNTRL, /* Control + p */
 
@@ -202,7 +206,7 @@
     [0x006] = 33 | CNTRL, /* Control + f */
     [0x007] = 34 | CNTRL, /* Control + g */
     [0x008] = 35 | CNTRL, /* Control + h */
-    [0x00a] = 36 | CNTRL, /* Control + j */
+    /* Control + j collides with Return */
     [0x00b] = 37 | CNTRL, /* Control + k */
     [0x00c] = 38 | CNTRL, /* Control + l */
 
@@ -216,7 +220,7 @@
 
 };
 
-int curses2keysym[CURSES_KEYS] = {
+static const int curses2keysym[CURSES_KEYS] = {
     [0 ... (CURSES_KEYS - 1)] = -1,
 
     ['\n'] = '\n',
@@ -239,12 +243,7 @@
 
 };
 
-typedef struct {
-	const char* name;
-	int keysym;
-} name2keysym_t;
-
-static name2keysym_t name2keysym[] = {
+static const name2keysym_t name2keysym[] = {
     /* Plain ASCII */
     { "space", 0x020 },
     { "exclam", 0x021 },
diff --git a/cutils.c b/cutils.c
index b256286..0623cf7 100644
--- a/cutils.c
+++ b/cutils.c
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 #include "qemu-common.h"
+#include "host-utils.h"
 
 void pstrcpy(char *buf, int buf_size, const char *str)
 {
@@ -72,7 +73,7 @@
     p = str;
     q = val;
     while (*q != '\0') {
-        if (toupper(*p) != toupper(*q))
+        if (qemu_toupper(*p) != qemu_toupper(*q))
             return 0;
         p++;
         q++;
@@ -96,42 +97,85 @@
     return t;
 }
 
-void *get_mmap_addr(unsigned long size)
+int qemu_fls(int i)
 {
-    return NULL;
+    return 32 - clz32(i);
 }
 
-void qemu_free(void *ptr)
+/* io vectors */
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
 {
-    free(ptr);
+    qiov->iov = qemu_malloc(alloc_hint * sizeof(struct iovec));
+    qiov->niov = 0;
+    qiov->nalloc = alloc_hint;
+    qiov->size = 0;
 }
 
-void *qemu_malloc(size_t size)
+void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov)
 {
-    return malloc(size);
+    int i;
+
+    qiov->iov = iov;
+    qiov->niov = niov;
+    qiov->nalloc = -1;
+    qiov->size = 0;
+    for (i = 0; i < niov; i++)
+        qiov->size += iov[i].iov_len;
 }
 
-void *qemu_mallocz(size_t size)
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
 {
-    void *ptr;
-    ptr = qemu_malloc(size);
-    if (!ptr)
-        return NULL;
-    memset(ptr, 0, size);
-    return ptr;
+    assert(qiov->nalloc != -1);
+
+    if (qiov->niov == qiov->nalloc) {
+        qiov->nalloc = 2 * qiov->nalloc + 1;
+        qiov->iov = qemu_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
+    }
+    qiov->iov[qiov->niov].iov_base = base;
+    qiov->iov[qiov->niov].iov_len = len;
+    qiov->size += len;
+    ++qiov->niov;
 }
 
-void *qemu_realloc(void*  ptr, size_t size)
+void qemu_iovec_destroy(QEMUIOVector *qiov)
 {
-    return realloc(ptr, size);
+    assert(qiov->nalloc != -1);
+
+    qemu_free(qiov->iov);
 }
 
-char *qemu_strdup(const char *str)
+void qemu_iovec_reset(QEMUIOVector *qiov)
 {
-    char *ptr;
-    ptr = qemu_malloc(strlen(str) + 1);
-    if (!ptr)
-        return NULL;
-    strcpy(ptr, str);
-    return ptr;
+    assert(qiov->nalloc != -1);
+
+    qiov->niov = 0;
+    qiov->size = 0;
+}
+
+void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf)
+{
+    uint8_t *p = (uint8_t *)buf;
+    int i;
+
+    for (i = 0; i < qiov->niov; ++i) {
+        memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
+        p += qiov->iov[i].iov_len;
+    }
+}
+
+void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count)
+{
+    const uint8_t *p = (const uint8_t *)buf;
+    size_t copy;
+    int i;
+
+    for (i = 0; i < qiov->niov && count; ++i) {
+        copy = count;
+        if (copy > qiov->iov[i].iov_len)
+            copy = qiov->iov[i].iov_len;
+        memcpy(qiov->iov[i].iov_base, p, copy);
+        p     += copy;
+        count -= copy;
+    }
 }
diff --git a/d3des.c b/d3des.c
index 6e8a02e..60c840e 100644
--- a/d3des.c
+++ b/d3des.c
@@ -63,9 +63,8 @@
 	40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
 	43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
 
-void deskey(key, edf)	/* Thanks to James Gillogly & Phil Karn! */
-unsigned char *key;
-int edf;
+/* Thanks to James Gillogly & Phil Karn! */
+void deskey(unsigned char *key, int edf)
 {
 	register int i, j, l, m, n;
 	unsigned char pc1m[56], pcr[56];
@@ -100,8 +99,7 @@
 	return;
 	}
 
-static void cookey(raw1)
-register unsigned long *raw1;
+static void cookey(register unsigned long *raw1)
 {
 	register unsigned long *cook, *raw0;
 	unsigned long dough[32];
@@ -123,8 +121,7 @@
 	return;
 	}
 
-void cpkey(into)
-register unsigned long *into;
+void cpkey(register unsigned long *into)
 {
 	register unsigned long *from, *endp;
 
@@ -133,8 +130,7 @@
 	return;
 	}
 
-void usekey(from)
-register unsigned long *from;
+void usekey(register unsigned long *from)
 {
 	register unsigned long *to, *endp;
 
@@ -143,8 +139,7 @@
 	return;
 	}
 
-void des(inblock, outblock)
-unsigned char *inblock, *outblock;
+void des(unsigned char *inblock, unsigned char *outblock)
 {
 	unsigned long work[2];
 
@@ -154,9 +149,7 @@
 	return;
 	}
 
-static void scrunch(outof, into)
-register unsigned char *outof;
-register unsigned long *into;
+static void scrunch(register unsigned char *outof, register unsigned long *into)
 {
 	*into	 = (*outof++ & 0xffL) << 24;
 	*into	|= (*outof++ & 0xffL) << 16;
@@ -169,9 +162,7 @@
 	return;
 	}
 
-static void unscrun(outof, into)
-register unsigned long *outof;
-register unsigned char *into;
+static void unscrun(register unsigned long *outof, register unsigned char *into)
 {
 	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
 	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
@@ -184,7 +175,7 @@
 	return;
 	}
 
-static unsigned long SP1[64] = {
+static const unsigned long SP1[64] = {
 	0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
 	0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
 	0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
@@ -202,7 +193,7 @@
 	0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
 	0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
 
-static unsigned long SP2[64] = {
+static const unsigned long SP2[64] = {
 	0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
 	0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
 	0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
@@ -220,7 +211,7 @@
 	0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
 	0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
 
-static unsigned long SP3[64] = {
+static const unsigned long SP3[64] = {
 	0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
 	0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
 	0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
@@ -238,7 +229,7 @@
 	0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
 	0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
 
-static unsigned long SP4[64] = {
+static const unsigned long SP4[64] = {
 	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
 	0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
 	0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
@@ -256,7 +247,7 @@
 	0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
 	0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
 
-static unsigned long SP5[64] = {
+static const unsigned long SP5[64] = {
 	0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
 	0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
 	0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
@@ -274,7 +265,7 @@
 	0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
 	0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
 
-static unsigned long SP6[64] = {
+static const unsigned long SP6[64] = {
 	0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
 	0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
 	0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
@@ -292,7 +283,7 @@
 	0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
 	0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
 
-static unsigned long SP7[64] = {
+static const unsigned long SP7[64] = {
 	0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
 	0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
 	0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
@@ -310,7 +301,7 @@
 	0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
 	0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
 
-static unsigned long SP8[64] = {
+static const unsigned long SP8[64] = {
 	0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
 	0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
 	0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
@@ -328,8 +319,7 @@
 	0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
 	0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
 
-static void desfunc(block, keys)
-register unsigned long *block, *keys;
+static void desfunc(register unsigned long *block, register unsigned long *keys)
 {
 	register unsigned long fval, work, right, leftt;
 	register int round;
diff --git a/def-helper.h b/def-helper.h
new file mode 100644
index 0000000..d57ea4d
--- /dev/null
+++ b/def-helper.h
@@ -0,0 +1,220 @@
+/* Helper file for declaring TCG helper functions.
+   Should be included at the start and end of target-foo/helper.h.
+
+   Targets should use DEF_HELPER_N and DEF_HELPER_FLAGS_N to declare helper
+   functions.  Names should be specified without the helper_ prefix, and
+   the return and argument types specified.  3 basic types are understood
+   (i32, i64 and ptr).  Additional aliases are provided for convenience and
+   to match the types used by the C helper implementation.
+
+   The target helper.h should be included in all files that use/define
+   helper functions.  THis will ensure that function prototypes are
+   consistent.  In addition it should be included an extra two times for
+   helper.c, defining:
+    GEN_HELPER 1 to produce op generation functions (gen_helper_*)
+    GEN_HELPER 2 to do runtime registration helper functions.
+ */
+
+#ifndef DEF_HELPER_H
+#define DEF_HELPER_H 1
+
+#define HELPER(name) glue(helper_, name)
+
+#define GET_TCGV_i32 GET_TCGV_I32
+#define GET_TCGV_i64 GET_TCGV_I64
+#define GET_TCGV_ptr GET_TCGV_PTR
+
+/* Some types that make sense in C, but not for TCG.  */
+#define dh_alias_i32 i32
+#define dh_alias_s32 i32
+#define dh_alias_int i32
+#define dh_alias_i64 i64
+#define dh_alias_s64 i64
+#define dh_alias_f32 i32
+#define dh_alias_f64 i64
+#if TARGET_LONG_BITS == 32
+#define dh_alias_tl i32
+#else
+#define dh_alias_tl i64
+#endif
+#define dh_alias_ptr ptr
+#define dh_alias_void void
+#define dh_alias_env ptr
+#define dh_alias(t) glue(dh_alias_, t)
+
+#define dh_ctype_i32 uint32_t
+#define dh_ctype_s32 int32_t
+#define dh_ctype_int int
+#define dh_ctype_i64 uint64_t
+#define dh_ctype_s64 int64_t
+#define dh_ctype_f32 float32
+#define dh_ctype_f64 float64
+#define dh_ctype_tl target_ulong
+#define dh_ctype_ptr void *
+#define dh_ctype_void void
+#define dh_ctype_env CPUState *
+#define dh_ctype(t) dh_ctype_##t
+
+/* We can't use glue() here because it falls foul of C preprocessor
+   recursive expansion rules.  */
+#define dh_retvar_decl0_void void
+#define dh_retvar_decl0_i32 TCGv_i32 retval
+#define dh_retvar_decl0_i64 TCGv_i64 retval
+#define dh_retvar_decl0_ptr TCGv_iptr retval
+#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
+
+#define dh_retvar_decl_void
+#define dh_retvar_decl_i32 TCGv_i32 retval,
+#define dh_retvar_decl_i64 TCGv_i64 retval,
+#define dh_retvar_decl_ptr TCGv_iptr retval,
+#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
+
+#define dh_retvar_void TCG_CALL_DUMMY_ARG
+#define dh_retvar_i32 GET_TCGV_i32(retval)
+#define dh_retvar_i64 GET_TCGV_i64(retval)
+#define dh_retvar_ptr GET_TCGV_ptr(retval)
+#define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
+
+#define dh_is_64bit_void 0
+#define dh_is_64bit_i32 0
+#define dh_is_64bit_i64 1
+#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64)
+#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
+
+#define dh_arg(t, n) \
+  args[n - 1] = glue(GET_TCGV_, dh_alias(t))(glue(arg, n)); \
+  sizemask |= dh_is_64bit(t) << n
+
+#define dh_arg_decl(t, n) glue(TCGv_, dh_alias(t)) glue(arg, n)
+
+
+#define DEF_HELPER_0(name, ret) \
+    DEF_HELPER_FLAGS_0(name, 0, ret)
+#define DEF_HELPER_1(name, ret, t1) \
+    DEF_HELPER_FLAGS_1(name, 0, ret, t1)
+#define DEF_HELPER_2(name, ret, t1, t2) \
+    DEF_HELPER_FLAGS_2(name, 0, ret, t1, t2)
+#define DEF_HELPER_3(name, ret, t1, t2, t3) \
+    DEF_HELPER_FLAGS_3(name, 0, ret, t1, t2, t3)
+#define DEF_HELPER_4(name, ret, t1, t2, t3, t4) \
+    DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4)
+
+#endif /* DEF_HELPER_H */
+
+#ifndef GEN_HELPER
+/* Function prototypes.  */
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret) \
+dh_ctype(ret) HELPER(name) (void);
+
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1));
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2));
+
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3));
+
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
+                                   dh_ctype(t4));
+
+#undef GEN_HELPER
+#define GEN_HELPER -1
+
+#elif GEN_HELPER == 1
+/* Gen functions.  */
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \
+{ \
+  int sizemask; \
+  sizemask = dh_is_64bit(ret); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 0, NULL); \
+}
+
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1)) \
+{ \
+  TCGArg args[1]; \
+  int sizemask; \
+  sizemask = dh_is_64bit(ret); \
+  dh_arg(t1, 1); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 1, args); \
+}
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
+    dh_arg_decl(t2, 2)) \
+{ \
+  TCGArg args[2]; \
+  int sizemask; \
+  sizemask = dh_is_64bit(ret); \
+  dh_arg(t1, 1); \
+  dh_arg(t2, 2); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 2, args); \
+}
+
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
+    dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \
+{ \
+  TCGArg args[3]; \
+  int sizemask; \
+  sizemask = dh_is_64bit(ret); \
+  dh_arg(t1, 1); \
+  dh_arg(t2, 2); \
+  dh_arg(t3, 3); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 3, args); \
+}
+
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
+    dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \
+{ \
+  TCGArg args[4]; \
+  int sizemask; \
+  sizemask = dh_is_64bit(ret); \
+  dh_arg(t1, 1); \
+  dh_arg(t2, 2); \
+  dh_arg(t3, 3); \
+  dh_arg(t4, 4); \
+  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 4, args); \
+}
+
+#undef GEN_HELPER
+#define GEN_HELPER -1
+
+#elif GEN_HELPER == 2
+/* Register helpers.  */
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret) \
+tcg_register_helper(HELPER(name), #name);
+
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
+DEF_HELPER_FLAGS_0(name, flags, ret)
+
+#undef GEN_HELPER
+#define GEN_HELPER -1
+
+#elif GEN_HELPER == -1
+/* Undefine macros.  */
+
+#undef DEF_HELPER_FLAGS_0
+#undef DEF_HELPER_FLAGS_1
+#undef DEF_HELPER_FLAGS_2
+#undef DEF_HELPER_FLAGS_3
+#undef DEF_HELPER_FLAGS_4
+#undef GEN_HELPER
+
+#endif
diff --git a/device_tree.c b/device_tree.c
new file mode 100644
index 0000000..cc91606
--- /dev/null
+++ b/device_tree.c
@@ -0,0 +1,109 @@
+/*
+ * Functions to help device tree manipulation using libfdt.
+ * It also provides functions to read entries from device tree proc
+ * interface.
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors: Jerone Young <jyoung5@us.ibm.com>
+ *          Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "device_tree.h"
+
+#include <libfdt.h>
+
+void *load_device_tree(const char *filename_path, int *sizep)
+{
+    int dt_size;
+    int dt_file_load_size;
+    int ret;
+    void *fdt = NULL;
+
+    *sizep = 0;
+    dt_size = get_image_size(filename_path);
+    if (dt_size < 0) {
+        printf("Unable to get size of device tree file '%s'\n",
+            filename_path);
+        goto fail;
+    }
+
+    /* Expand to 2x size to give enough room for manipulation.  */
+    dt_size *= 2;
+    /* First allocate space in qemu for device tree */
+    fdt = qemu_mallocz(dt_size);
+
+    dt_file_load_size = load_image(filename_path, fdt);
+    if (dt_file_load_size < 0) {
+        printf("Unable to open device tree file '%s'\n",
+               filename_path);
+        goto fail;
+    }
+
+    ret = fdt_open_into(fdt, fdt, dt_size);
+    if (ret) {
+        printf("Unable to copy device tree in memory\n");
+        goto fail;
+    }
+
+    /* Check sanity of device tree */
+    if (fdt_check_header(fdt)) {
+        printf ("Device tree file loaded into memory is invalid: %s\n",
+            filename_path);
+        goto fail;
+    }
+    *sizep = dt_size;
+    return fdt;
+
+fail:
+    qemu_free(fdt);
+    return NULL;
+}
+
+int qemu_devtree_setprop(void *fdt, const char *node_path,
+                         const char *property, uint32_t *val_array, int size)
+{
+    int offset;
+
+    offset = fdt_path_offset(fdt, node_path);
+    if (offset < 0)
+        return offset;
+
+    return fdt_setprop(fdt, offset, property, val_array, size);
+}
+
+int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
+                              const char *property, uint32_t val)
+{
+    int offset;
+
+    offset = fdt_path_offset(fdt, node_path);
+    if (offset < 0)
+        return offset;
+
+    return fdt_setprop_cell(fdt, offset, property, val);
+}
+
+int qemu_devtree_setprop_string(void *fdt, const char *node_path,
+                                const char *property, const char *string)
+{
+    int offset;
+
+    offset = fdt_path_offset(fdt, node_path);
+    if (offset < 0)
+        return offset;
+
+    return fdt_setprop_string(fdt, offset, property, string);
+}
diff --git a/device_tree.h b/device_tree.h
new file mode 100644
index 0000000..f05c4e7
--- /dev/null
+++ b/device_tree.h
@@ -0,0 +1,26 @@
+/*
+ * Header with function prototypes to help device tree manipulation using
+ * libfdt. It also provides functions to read entries from device tree proc
+ * interface.
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors: Jerone Young <jyoung5@us.ibm.com>
+ *          Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#ifndef __DEVICE_TREE_H__
+#define __DEVICE_TREE_H__
+
+void *load_device_tree(const char *filename_path, int *sizep);
+
+int qemu_devtree_setprop(void *fdt, const char *node_path,
+                         const char *property, uint32_t *val_array, int size);
+int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
+                              const char *property, uint32_t val);
+int qemu_devtree_setprop_string(void *fdt, const char *node_path,
+                                const char *property, const char *string);
+
+#endif /* __DEVICE_TREE_H__ */
diff --git a/dis-asm.h b/dis-asm.h
index 1ba86dd..251c490 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -142,6 +142,7 @@
 #define bfd_mach_ppc64         1
 #define bfd_mach_ppc_403       403
 #define bfd_mach_ppc_403gc     4030
+#define bfd_mach_ppc_e500      500
 #define bfd_mach_ppc_505       505
 #define bfd_mach_ppc_601       601
 #define bfd_mach_ppc_602       602
@@ -217,6 +218,7 @@
 #define bfd_mach_cris_v0_v10   255
 #define bfd_mach_cris_v32      32
 #define bfd_mach_cris_v10_v32  1032
+  bfd_arch_microblaze, /* Xilinx MicroBlaze.  */
   bfd_arch_last
   };
 #define bfd_mach_s390_31 31
@@ -399,6 +401,7 @@
 extern int print_insn_ppc		PARAMS ((bfd_vma, disassemble_info*));
 extern int print_insn_s390		PARAMS ((bfd_vma, disassemble_info*));
 extern int print_insn_crisv32           PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_microblaze        PARAMS ((bfd_vma, disassemble_info*));
 
 #if 0
 /* Fetch the disassembler for a given BFD, if that support is available.  */
diff --git a/disas.c b/disas.c
index a8bc8ad..af5a9ea 100644
--- a/disas.c
+++ b/disas.c
@@ -14,11 +14,8 @@
 /* Get LENGTH bytes from info's buffer, at target address memaddr.
    Transfer them to myaddr.  */
 int
-buffer_read_memory (memaddr, myaddr, length, info)
-     bfd_vma memaddr;
-     bfd_byte *myaddr;
-     int length;
-     struct disassemble_info *info;
+buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
+                   struct disassemble_info *info)
 {
     if (memaddr < info->buffer_vma
         || memaddr + length > info->buffer_vma + info->buffer_length)
@@ -36,20 +33,14 @@
                     int length,
                     struct disassemble_info *info)
 {
-    int i;
-    for(i = 0; i < length; i++) {
-        myaddr[i] = ldub_code(memaddr + i);
-    }
+    cpu_memory_rw_debug(cpu_single_env, memaddr, myaddr, length, 0);
     return 0;
 }
 
 /* Print an error message.  We can assume that this is in response to
    an error return from buffer_read_memory.  */
 void
-perror_memory (status, memaddr, info)
-     int status;
-     bfd_vma memaddr;
-     struct disassemble_info *info;
+perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
 {
   if (status != EIO)
     /* Can't happen.  */
@@ -69,9 +60,7 @@
    addresses).  */
 
 void
-generic_print_address (addr, info)
-     bfd_vma addr;
-     struct disassemble_info *info;
+generic_print_address (bfd_vma addr, struct disassemble_info *info)
 {
     (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
 }
@@ -79,9 +68,7 @@
 /* Just return the given address.  */
 
 int
-generic_symbol_at_address (addr, info)
-     bfd_vma addr;
-     struct disassemble_info * info;
+generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
 {
   return 1;
 }
@@ -208,13 +195,16 @@
 #elif defined(TARGET_CRIS)
     disasm_info.mach = bfd_mach_cris_v32;
     print_insn = print_insn_crisv32;
+#elif defined(TARGET_MICROBLAZE)
+    disasm_info.mach = bfd_arch_microblaze;
+    print_insn = print_insn_microblaze;
 #else
     fprintf(out, "0x" TARGET_FMT_lx
 	    ": Asm output not supported on this arch\n", code);
     return;
 #endif
 
-    for (pc = code; pc < code + size; pc += count) {
+    for (pc = code; size > 0; pc += count, size -= count) {
 	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
 	count = print_insn(pc, &disasm_info);
 #if 0
@@ -232,6 +222,13 @@
 	fprintf(out, "\n");
 	if (count < 0)
 	    break;
+        if (size < count) {
+            fprintf(out,
+                    "Disassembler disagrees with translator over instruction "
+                    "decoding\n"
+                    "Please report this to qemu-devel@nongnu.org\n");
+            break;
+        }
     }
 }
 
@@ -260,7 +257,7 @@
 #elif defined(__x86_64__)
     disasm_info.mach = bfd_mach_x86_64;
     print_insn = print_insn_i386;
-#elif defined(__powerpc__)
+#elif defined(_ARCH_PPC)
     print_insn = print_insn_ppc;
 #elif defined(__alpha__)
     print_insn = print_insn_alpha;
@@ -286,7 +283,7 @@
 	    (long) code);
     return;
 #endif
-    for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
+    for (pc = (unsigned long)code; size > 0; pc += count, size -= count) {
 	fprintf(out, "0x%08lx:  ", pc);
 #ifdef __arm__
         /* since data is included in the code, it is better to
@@ -303,39 +300,22 @@
 /* Look up symbol for debugging purpose.  Returns "" if unknown. */
 const char *lookup_symbol(target_ulong orig_addr)
 {
-    unsigned int i;
-    /* Hack, because we know this is x86. */
-    Elf32_Sym *sym;
+    const char *symbol = "";
     struct syminfo *s;
-    target_ulong addr;
 
     for (s = syminfos; s; s = s->next) {
-	sym = s->disas_symtab;
-	for (i = 0; i < s->disas_num_syms; i++) {
-	    if (sym[i].st_shndx == SHN_UNDEF
-		|| sym[i].st_shndx >= SHN_LORESERVE)
-		continue;
-
-	    if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
-		continue;
-
-	    addr = sym[i].st_value;
-#if defined(TARGET_ARM) || defined (TARGET_MIPS)
-            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
-            addr &= ~(target_ulong)1;
-#endif
-	    if (orig_addr >= addr
-		&& orig_addr < addr + sym[i].st_size)
-		return s->disas_strtab + sym[i].st_name;
-	}
+        symbol = s->lookup_symbol(s, orig_addr);
+        if (symbol[0] != '\0') {
+            break;
+        }
     }
-    return "";
+
+    return symbol;
 }
 
 #if !defined(CONFIG_USER_ONLY)
 
-void term_vprintf(const char *fmt, va_list ap);
-void term_printf(const char *fmt, ...);
+#include "monitor.h"
 
 static int monitor_disas_is_physical;
 static CPUState *monitor_disas_env;
@@ -356,19 +336,19 @@
 {
     va_list ap;
     va_start(ap, fmt);
-    term_vprintf(fmt, ap);
+    monitor_vprintf((Monitor *)stream, fmt, ap);
     va_end(ap);
     return 0;
 }
 
-void monitor_disas(CPUState *env,
+void monitor_disas(Monitor *mon, CPUState *env,
                    target_ulong pc, int nb_insn, int is_physical, int flags)
 {
     int count, i;
     struct disassemble_info disasm_info;
     int (*print_insn)(bfd_vma pc, disassemble_info *info);
 
-    INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
+    INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf);
 
     monitor_disas_env = env;
     monitor_disas_is_physical = is_physical;
@@ -414,15 +394,15 @@
     print_insn = print_insn_little_mips;
 #endif
 #else
-    term_printf("0x" TARGET_FMT_lx
-		": Asm output not supported on this arch\n", pc);
+    monitor_printf(mon, "0x" TARGET_FMT_lx
+                   ": Asm output not supported on this arch\n", pc);
     return;
 #endif
 
     for(i = 0; i < nb_insn; i++) {
-	term_printf("0x" TARGET_FMT_lx ":  ", pc);
+	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
 	count = print_insn(pc, &disasm_info);
-	term_printf("\n");
+	monitor_printf(mon, "\n");
 	if (count < 0)
 	    break;
         pc += count;
diff --git a/disas.h b/disas.h
index ee0a79c..0789b57 100644
--- a/disas.h
+++ b/disas.h
@@ -1,21 +1,39 @@
 #ifndef _QEMU_DISAS_H
 #define _QEMU_DISAS_H
 
+#include "qemu-common.h"
+
 /* Disassemble this for me please... (debugging). */
 void disas(FILE *out, void *code, unsigned long size);
 void target_disas(FILE *out, target_ulong code, target_ulong size, int flags);
-void monitor_disas(CPUState *env,
+
+/* The usual mess... FIXME: Remove this condition once dyngen-exec.h is gone */
+#ifndef __DYNGEN_EXEC_H__
+void monitor_disas(Monitor *mon, CPUState *env,
                    target_ulong pc, int nb_insn, int is_physical, int flags);
+#endif
 
 /* Look up symbol for debugging purpose.  Returns "" if unknown. */
 const char *lookup_symbol(target_ulong orig_addr);
 
-/* Filled in by elfload.c.  Simplistic, but will do for now. */
-extern struct syminfo {
+struct syminfo;
+struct elf32_sym;
+struct elf64_sym;
+
+typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_ulong orig_addr);
+
+struct syminfo {
+    lookup_symbol_t lookup_symbol;
     unsigned int disas_num_syms;
-    void *disas_symtab;
+    union {
+      struct elf32_sym *elf32;
+      struct elf64_sym *elf64;
+    } disas_symtab;
     const char *disas_strtab;
     struct syminfo *next;
-} *syminfos;
+};
+
+/* Filled in by elfload.c.  Simplistic, but will do for now. */
+extern struct syminfo *syminfos;
 
 #endif /* _QEMU_DISAS_H */
diff --git a/distrib/update-audio.sh b/distrib/update-audio.sh
index 56bada2..79d1650 100755
--- a/distrib/update-audio.sh
+++ b/distrib/update-audio.sh
@@ -8,16 +8,16 @@
 # assumes this script is located in the 'distrib' sub-directory
 cd `dirname $0`
 cd ..
+. android/build/common.sh
 
-locate_depot_files ()
-{
-    root=$(p4 where $1) || (
-        echo "you need to map $1 into your workspace to build an emulator source release package"
-        exit 3
-    )
-    root=$(echo $root | cut -d" " -f3 | sed -e "s%/\.\.\.%%")
-    echo $root
-}
+check_android_build
+if [ $IN_ANDROID_BUILD != yes ] ; then
+    echo "Sorry, this script can only be run from a full Android build tree"
+    exit 1
+fi
+
+force_32bit_binaries
+locate_android_prebuilt
 
 # find the prebuilt directory
 OS=`uname -s`
@@ -87,9 +87,8 @@
 
 # now do a p4 edit, a copy and ask for submission
 #
-TARGET=$PREBUILT/emulator/libqemu-audio.a
+TARGET=$ANDROID_PREBUILT/emulator/libqemu-audio.a
 
-p4 edit $TARGET || (echo "could not p4 edit $TARGET" && exit 3)
 cp -f $source $TARGET
-echo "please do: p4 submit $TARGET"
+echo "ok, file copied to $TARGET"
 
diff --git a/dma-helpers.c b/dma-helpers.c
new file mode 100644
index 0000000..712ed89
--- /dev/null
+++ b/dma-helpers.c
@@ -0,0 +1,184 @@
+/*
+ * DMA helper functions
+ *
+ * Copyright (c) 2009 Red Hat
+ *
+ * This work is licensed under the terms of the GNU General Public License
+ * (GNU GPL), version 2 or later.
+ */
+
+#include "dma.h"
+#include "block_int.h"
+
+void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint)
+{
+    qsg->sg = qemu_malloc(alloc_hint * sizeof(ScatterGatherEntry));
+    qsg->nsg = 0;
+    qsg->nalloc = alloc_hint;
+    qsg->size = 0;
+}
+
+void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
+                     target_phys_addr_t len)
+{
+    if (qsg->nsg == qsg->nalloc) {
+        qsg->nalloc = 2 * qsg->nalloc + 1;
+        qsg->sg = qemu_realloc(qsg->sg, qsg->nalloc * sizeof(ScatterGatherEntry));
+    }
+    qsg->sg[qsg->nsg].base = base;
+    qsg->sg[qsg->nsg].len = len;
+    qsg->size += len;
+    ++qsg->nsg;
+}
+
+void qemu_sglist_destroy(QEMUSGList *qsg)
+{
+    qemu_free(qsg->sg);
+}
+
+typedef struct {
+    BlockDriverAIOCB common;
+    BlockDriverState *bs;
+    BlockDriverAIOCB *acb;
+    QEMUSGList *sg;
+    uint64_t sector_num;
+    int is_write;
+    int sg_cur_index;
+    target_phys_addr_t sg_cur_byte;
+    QEMUIOVector iov;
+    QEMUBH *bh;
+} DMAAIOCB;
+
+static void dma_bdrv_cb(void *opaque, int ret);
+
+static void reschedule_dma(void *opaque)
+{
+    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
+
+    qemu_bh_delete(dbs->bh);
+    dbs->bh = NULL;
+    dma_bdrv_cb(opaque, 0);
+}
+
+static void continue_after_map_failure(void *opaque)
+{
+    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
+
+    dbs->bh = qemu_bh_new(reschedule_dma, dbs);
+    qemu_bh_schedule(dbs->bh);
+}
+
+static void dma_bdrv_unmap(DMAAIOCB *dbs)
+{
+    int i;
+
+    for (i = 0; i < dbs->iov.niov; ++i) {
+        cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base,
+                                  dbs->iov.iov[i].iov_len, !dbs->is_write,
+                                  dbs->iov.iov[i].iov_len);
+    }
+}
+
+static void dma_bdrv_cb(void *opaque, int ret)
+{
+    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
+    target_phys_addr_t cur_addr, cur_len;
+    void *mem;
+
+    dbs->acb = NULL;
+    dbs->sector_num += dbs->iov.size / 512;
+    dma_bdrv_unmap(dbs);
+    qemu_iovec_reset(&dbs->iov);
+
+    if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
+        dbs->common.cb(dbs->common.opaque, ret);
+        qemu_iovec_destroy(&dbs->iov);
+        qemu_aio_release(dbs);
+        return;
+    }
+
+    while (dbs->sg_cur_index < dbs->sg->nsg) {
+        cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
+        cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
+        mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->is_write);
+        if (!mem)
+            break;
+        qemu_iovec_add(&dbs->iov, mem, cur_len);
+        dbs->sg_cur_byte += cur_len;
+        if (dbs->sg_cur_byte == dbs->sg->sg[dbs->sg_cur_index].len) {
+            dbs->sg_cur_byte = 0;
+            ++dbs->sg_cur_index;
+        }
+    }
+
+    if (dbs->iov.size == 0) {
+        cpu_register_map_client(dbs, continue_after_map_failure);
+        return;
+    }
+
+    if (dbs->is_write) {
+        dbs->acb = bdrv_aio_writev(dbs->bs, dbs->sector_num, &dbs->iov,
+                                   dbs->iov.size / 512, dma_bdrv_cb, dbs);
+    } else {
+        dbs->acb = bdrv_aio_readv(dbs->bs, dbs->sector_num, &dbs->iov,
+                                  dbs->iov.size / 512, dma_bdrv_cb, dbs);
+    }
+    if (!dbs->acb) {
+        dma_bdrv_unmap(dbs);
+        qemu_iovec_destroy(&dbs->iov);
+        return;
+    }
+}
+
+static void dma_aio_cancel(BlockDriverAIOCB *acb)
+{
+    DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
+
+    if (dbs->acb) {
+        bdrv_aio_cancel(dbs->acb);
+    }
+}
+
+static AIOPool dma_aio_pool = {
+    .aiocb_size         = sizeof(DMAAIOCB),
+    .cancel             = dma_aio_cancel,
+};
+
+static BlockDriverAIOCB *dma_bdrv_io(
+    BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
+    BlockDriverCompletionFunc *cb, void *opaque,
+    int is_write)
+{
+    DMAAIOCB *dbs =  qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
+
+    dbs->acb = NULL;
+    dbs->bs = bs;
+    dbs->sg = sg;
+    dbs->sector_num = sector_num;
+    dbs->sg_cur_index = 0;
+    dbs->sg_cur_byte = 0;
+    dbs->is_write = is_write;
+    dbs->bh = NULL;
+    qemu_iovec_init(&dbs->iov, sg->nsg);
+    dma_bdrv_cb(dbs, 0);
+    if (!dbs->acb) {
+        qemu_aio_release(dbs);
+        return NULL;
+    }
+    return &dbs->common;
+}
+
+
+BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
+                                QEMUSGList *sg, uint64_t sector,
+                                void (*cb)(void *opaque, int ret), void *opaque)
+{
+    return dma_bdrv_io(bs, sg, sector, cb, opaque, 0);
+}
+
+BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
+                                 QEMUSGList *sg, uint64_t sector,
+                                 void (*cb)(void *opaque, int ret), void *opaque)
+{
+    return dma_bdrv_io(bs, sg, sector, cb, opaque, 1);
+}
diff --git a/dma.h b/dma.h
new file mode 100644
index 0000000..f3bb275
--- /dev/null
+++ b/dma.h
@@ -0,0 +1,41 @@
+/*
+ * DMA helper functions
+ *
+ * Copyright (c) 2009 Red Hat
+ *
+ * This work is licensed under the terms of the GNU General Public License
+ * (GNU GPL), version 2 or later.
+ */
+
+#ifndef DMA_H
+#define DMA_H
+
+#include <stdio.h>
+//#include "cpu.h"
+#include "hw/hw.h"
+#include "block.h"
+
+typedef struct {
+    target_phys_addr_t base;
+    target_phys_addr_t len;
+} ScatterGatherEntry;
+
+typedef struct {
+    ScatterGatherEntry *sg;
+    int nsg;
+    int nalloc;
+    target_phys_addr_t size;
+} QEMUSGList;
+
+void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint);
+void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
+                     target_phys_addr_t len);
+void qemu_sglist_destroy(QEMUSGList *qsg);
+
+BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
+                                QEMUSGList *sg, uint64_t sector,
+                                BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
+                                 QEMUSGList *sg, uint64_t sector,
+                                 BlockDriverCompletionFunc *cb, void *opaque);
+#endif
diff --git a/dyngen-exec.h b/dyngen-exec.h
index 9260b6f..c9841df 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #if !defined(__DYNGEN_EXEC_H__)
 #define __DYNGEN_EXEC_H__
@@ -31,58 +31,16 @@
    point because host CPU registers are used as global variables. Some
    host headers do not allow that. */
 #include <stddef.h>
+#include <stdint.h>
 
 #ifdef __OpenBSD__
 #include <sys/types.h>
-#else
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-// Linux/Sparc64 defines uint64_t
-#if !(defined (__sparc_v9__) && defined(__linux__)) && !(defined(__APPLE__) && defined(__x86_64__))
-/* XXX may be done for all 64 bits targets ? */
-#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) || defined(__powerpc64__)
-typedef unsigned long uint64_t;
-#else
-typedef unsigned long long uint64_t;
-#endif
-#endif
-
-/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
-   prior to this and will cause an error in compliation, conflicting
-   with /usr/include/sys/int_types.h, line 75 */
-#ifndef __sun__
-typedef signed char int8_t;
-#endif
-typedef signed short int16_t;
-typedef signed int int32_t;
-// Linux/Sparc64 defines int64_t
-#if !(defined (__sparc_v9__) && defined(__linux__)) && !(defined(__APPLE__) && defined(__x86_64__))
-#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) || defined(__powerpc64__)
-typedef signed long int64_t;
-#else
-typedef signed long long int64_t;
-#endif
-#endif
 #endif
 
 /* XXX: This may be wrong for 64-bit ILP32 hosts.  */
 typedef void * host_reg_t;
 
-#define INT8_MIN		(-128)
-#define INT16_MIN		(-32767-1)
-#define INT32_MIN		(-2147483647-1)
-#define INT64_MIN		(-(int64_t)(9223372036854775807)-1)
-#define INT8_MAX		(127)
-#define INT16_MAX		(32767)
-#define INT32_MAX		(2147483647)
-#define INT64_MAX		((int64_t)(9223372036854775807))
-#define UINT8_MAX		(255)
-#define UINT16_MAX		(65535)
-#define UINT32_MAX		(4294967295U)
-#define UINT64_MAX		((uint64_t)(18446744073709551615))
-
-#ifdef _BSD
+#ifdef HOST_BSD
 typedef struct __sFILE FILE;
 #else
 typedef struct FILE FILE;
@@ -97,57 +55,31 @@
 #define AREG0 "ebp"
 #define AREG1 "ebx"
 #define AREG2 "esi"
-#define AREG3 "edi"
 #elif defined(__x86_64__)
 #define AREG0 "r14"
 #define AREG1 "r15"
 #define AREG2 "r12"
-#define AREG3 "r13"
-//#define AREG4 "rbp"
-//#define AREG5 "rbx"
-#elif defined(__powerpc__)
+#elif defined(_ARCH_PPC)
 #define AREG0 "r27"
 #define AREG1 "r24"
 #define AREG2 "r25"
-#define AREG3 "r26"
-/* XXX: suppress this hack */
-#if defined(CONFIG_USER_ONLY)
-#define AREG4 "r16"
-#define AREG5 "r17"
-#define AREG6 "r18"
-#define AREG7 "r19"
-#define AREG8 "r20"
-#define AREG9 "r21"
-#define AREG10 "r22"
-#define AREG11 "r23"
-#endif
 #elif defined(__arm__)
 #define AREG0 "r7"
 #define AREG1 "r4"
 #define AREG2 "r5"
-#define AREG3 "r6"
 #elif defined(__hppa__)
 #define AREG0 "r17"
 #define AREG1 "r14"
 #define AREG2 "r15"
-#define AREG3 "r16"
 #elif defined(__mips__)
 #define AREG0 "fp"
 #define AREG1 "s0"
 #define AREG2 "s1"
-#define AREG3 "s2"
-#define AREG4 "s3"
-#define AREG5 "s4"
-#define AREG6 "s5"
-#define AREG7 "s6"
-#define AREG8 "s7"
 #elif defined(__sparc__)
 #ifdef HOST_SOLARIS
 #define AREG0 "g2"
 #define AREG1 "g3"
 #define AREG2 "g4"
-#define AREG3 "g5"
-#define AREG4 "g6"
 #else
 #ifdef __sparc_v9__
 #define AREG0 "g5"
@@ -157,139 +89,35 @@
 #define AREG0 "g6"
 #define AREG1 "g1"
 #define AREG2 "g2"
-#define AREG3 "g3"
-#define AREG4 "l0"
-#define AREG5 "l1"
-#define AREG6 "l2"
-#define AREG7 "l3"
-#define AREG8 "l4"
-#define AREG9 "l5"
-#define AREG10 "l6"
-#define AREG11 "l7"
 #endif
 #endif
 #elif defined(__s390__)
 #define AREG0 "r10"
 #define AREG1 "r7"
 #define AREG2 "r8"
-#define AREG3 "r9"
 #elif defined(__alpha__)
 /* Note $15 is the frame pointer, so anything in op-i386.c that would
    require a frame pointer, like alloca, would probably loose.  */
 #define AREG0 "$15"
 #define AREG1 "$9"
 #define AREG2 "$10"
-#define AREG3 "$11"
-#define AREG4 "$12"
-#define AREG5 "$13"
-#define AREG6 "$14"
 #elif defined(__mc68000)
 #define AREG0 "%a5"
 #define AREG1 "%a4"
 #define AREG2 "%d7"
-#define AREG3 "%d6"
-#define AREG4 "%d5"
 #elif defined(__ia64__)
 #define AREG0 "r7"
 #define AREG1 "r4"
 #define AREG2 "r5"
-#define AREG3 "r6"
 #else
 #error unsupported CPU
 #endif
 
-/* force GCC to generate only one epilog at the end of the function */
-#define FORCE_RET() __asm__ __volatile__("" : : : "memory");
-
-#ifndef OPPROTO
-#define OPPROTO
-#endif
-
 #define xglue(x, y) x ## y
 #define glue(x, y) xglue(x, y)
 #define stringify(s)	tostring(s)
 #define tostring(s)	#s
 
-#if defined(__alpha__) || defined(__s390__)
-/* the symbols are considered non exported so a br immediate is generated */
-#define __hidden __attribute__((visibility("hidden")))
-#else
-#define __hidden
-#endif
-
-#if defined(__alpha__)
-/* Suggested by Richard Henderson. This will result in code like
-        ldah $0,__op_param1($29)        !gprelhigh
-        lda $0,__op_param1($0)          !gprellow
-   We can then conveniently change $29 to $31 and adapt the offsets to
-   emit the appropriate constant.  */
-extern int __op_param1 __hidden;
-extern int __op_param2 __hidden;
-extern int __op_param3 __hidden;
-#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
-#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
-#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
-#elif defined(__s390__)
-extern int __op_param1 __hidden;
-extern int __op_param2 __hidden;
-extern int __op_param3 __hidden;
-#define PARAM1 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param1) "; l %0,0(%0)" : "=r"(_r) : ); _r; })
-#define PARAM2 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param2) "; l %0,0(%0)" : "=r"(_r) : ); _r; })
-#define PARAM3 ({ int _r; asm("bras %0,8; .long " ASM_NAME(__op_param3) "; l %0,0(%0)" : "=r"(_r) : ); _r; })
-#else
-#if defined(__APPLE__)
-static int __op_param1, __op_param2, __op_param3;
-#else
-extern int __op_param1, __op_param2, __op_param3;
-#endif
-#define PARAM1 ((long)(&__op_param1))
-#define PARAM2 ((long)(&__op_param2))
-#define PARAM3 ((long)(&__op_param3))
-#endif /* !defined(__alpha__) */
-
-extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
-
-#if defined(_WIN32) || defined(__APPLE__)
-#define ASM_NAME(x) "_" #x
-#else
-#define ASM_NAME(x) #x
-#endif
-
-#if defined(__i386__)
-#define EXIT_TB() asm volatile ("ret")
-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
-#elif defined(__x86_64__)
-#define EXIT_TB() asm volatile ("ret")
-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
-#elif defined(__powerpc__)
-#define EXIT_TB() asm volatile ("blr")
-#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
-#elif defined(__s390__)
-#define EXIT_TB() asm volatile ("br %r14")
-#define GOTO_LABEL_PARAM(n) asm volatile ("larl %r7,12; l %r7,0(%r7); br %r7; .long " ASM_NAME(__op_gen_label) #n)
-#elif defined(__alpha__)
-#define EXIT_TB() asm volatile ("ret")
-#elif defined(__ia64__)
-#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
-#define GOTO_LABEL_PARAM(n) asm volatile ("br.sptk.many " \
-					  ASM_NAME(__op_gen_label) #n)
-#elif defined(__sparc__)
-#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop")
-#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n ";nop")
-#elif defined(__arm__)
-#define EXIT_TB() asm volatile ("b exec_loop")
-#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
-#elif defined(__mc68000)
-#define EXIT_TB() asm volatile ("rts")
-#elif defined(__mips__)
-#define EXIT_TB() asm volatile ("jr $ra")
-#define GOTO_LABEL_PARAM(n) asm volatile (".set noat; la $1, " ASM_NAME(__op_gen_label) #n "; jr $1; .set at")
-#elif defined(__hppa__)
-#define GOTO_LABEL_PARAM(n) asm volatile ("b,n " ASM_NAME(__op_gen_label) #n)
-#else
-#error unsupported CPU
-#endif
-
 /* The return address may point to the start of the next instruction.
    Subtracting one gets us the call instruction itself.  */
 #if defined(__s390__)
diff --git a/elf.h b/elf.h
index 861f1d3..b042002 100644
--- a/elf.h
+++ b/elf.h
@@ -119,6 +119,8 @@
  */
 #define EM_S390_OLD     0xA390
 
+#define EM_XILINX_MICROBLAZE    0xBAAB
+
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL		0
 #define DT_NEEDED	1
@@ -1079,7 +1081,23 @@
 #define	EI_CLASS	4
 #define	EI_DATA		5
 #define	EI_VERSION	6
-#define	EI_PAD		7
+#define	EI_OSABI	7
+#define	EI_PAD		8
+
+#define ELFOSABI_NONE           0       /* UNIX System V ABI */
+#define ELFOSABI_SYSV           0       /* Alias.  */
+#define ELFOSABI_HPUX           1       /* HP-UX */
+#define ELFOSABI_NETBSD         2       /* NetBSD.  */
+#define ELFOSABI_LINUX          3       /* Linux.  */
+#define ELFOSABI_SOLARIS        6       /* Sun Solaris.  */
+#define ELFOSABI_AIX            7       /* IBM AIX.  */
+#define ELFOSABI_IRIX           8       /* SGI Irix.  */
+#define ELFOSABI_FREEBSD        9       /* FreeBSD.  */
+#define ELFOSABI_TRU64          10      /* Compaq TRU64 UNIX.  */
+#define ELFOSABI_MODESTO        11      /* Novell Modesto.  */
+#define ELFOSABI_OPENBSD        12      /* OpenBSD.  */
+#define ELFOSABI_ARM            97      /* ARM */
+#define ELFOSABI_STANDALONE     255     /* Standalone (embedded) application */
 
 #define	ELFMAG0		0x7f		/* EI_MAG */
 #define	ELFMAG1		'E'
@@ -1106,6 +1124,7 @@
 #define NT_PRFPREG	2
 #define NT_PRPSINFO	3
 #define NT_TASKSTRUCT	4
+#define NT_AUXV		6
 #define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
 
 
diff --git a/elf_ops.h b/elf_ops.h
index 6126565..72cd83e 100644
--- a/elf_ops.h
+++ b/elf_ops.h
@@ -60,13 +60,48 @@
     return NULL;
 }
 
+static int glue(symfind, SZ)(const void *s0, const void *s1)
+{
+    struct elf_sym *key = (struct elf_sym *)s0;
+    struct elf_sym *sym = (struct elf_sym *)s1;
+    int result = 0;
+    if (key->st_value < sym->st_value) {
+        result = -1;
+    } else if (key->st_value > sym->st_value + sym->st_size) {
+        result = 1;
+    }
+    return result;
+}
+
+static const char *glue(lookup_symbol, SZ)(struct syminfo *s, target_ulong orig_addr)
+{
+    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
+    struct elf_sym key;
+    struct elf_sym *sym;
+
+    key.st_value = orig_addr;
+
+    sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ));
+    if (sym != 0) {
+        return s->disas_strtab + sym->st_name;
+    }
+
+    return "";
+}
+
+static int glue(symcmp, SZ)(const void *s0, const void *s1)
+{
+    struct elf_sym *sym0 = (struct elf_sym *)s0;
+    struct elf_sym *sym1 = (struct elf_sym *)s1;
+    return (sym0->st_value < sym1->st_value)
+        ? -1
+        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
+}
+
 static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
 {
     struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
     struct elf_sym *syms = NULL;
-#if (SZ == 64)
-    struct elf32_sym *syms32 = NULL;
-#endif
     struct syminfo *s;
     int nsyms, i;
     char *str = NULL;
@@ -90,21 +125,32 @@
         goto fail;
 
     nsyms = symtab->sh_size / sizeof(struct elf_sym);
-#if (SZ == 64)
-    syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym));
-#endif
-    for (i = 0; i < nsyms; i++) {
+
+    i = 0;
+    while (i < nsyms) {
         if (must_swab)
             glue(bswap_sym, SZ)(&syms[i]);
-#if (SZ == 64)
-	syms32[i].st_name = syms[i].st_name;
-	syms32[i].st_info = syms[i].st_info;
-	syms32[i].st_other = syms[i].st_other;
-	syms32[i].st_shndx = syms[i].st_shndx;
-	syms32[i].st_value = syms[i].st_value & 0xffffffff;
-	syms32[i].st_size = syms[i].st_size & 0xffffffff;
+        /* We are only interested in function symbols.
+           Throw everything else away.  */
+        if (syms[i].st_shndx == SHN_UNDEF ||
+                syms[i].st_shndx >= SHN_LORESERVE ||
+                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+            nsyms--;
+            if (i < nsyms) {
+                syms[i] = syms[nsyms];
+            }
+            continue;
+        }
+#if defined(TARGET_ARM) || defined (TARGET_MIPS)
+        /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
+        syms[i].st_value &= ~(target_ulong)1;
 #endif
+        i++;
     }
+    syms = qemu_realloc(syms, nsyms * sizeof(*syms));
+
+    qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
+
     /* String table */
     if (symtab->sh_link >= ehdr->e_shnum)
         goto fail;
@@ -112,16 +158,12 @@
 
     str = load_at(fd, strtab->sh_offset, strtab->sh_size);
     if (!str)
-	goto fail;
+        goto fail;
 
     /* Commit */
     s = qemu_mallocz(sizeof(*s));
-#if (SZ == 64)
-    s->disas_symtab = syms32;
-    qemu_free(syms);
-#else
-    s->disas_symtab = syms;
-#endif
+    s->lookup_symbol = glue(lookup_symbol, SZ);
+    glue(s->disas_symtab.elf, SZ) = syms;
     s->disas_num_syms = nsyms;
     s->disas_strtab = str;
     s->next = syminfos;
@@ -129,16 +171,13 @@
     qemu_free(shdr_table);
     return 0;
  fail:
-#if (SZ == 64)
-    qemu_free(syms32);
-#endif
     qemu_free(syms);
     qemu_free(str);
     qemu_free(shdr_table);
     return -1;
 }
 
-static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
+static int glue(load_elf, SZ)(int fd, int64_t address_offset,
                               int must_swab, uint64_t *pentry,
                               uint64_t *lowaddr, uint64_t *highaddr)
 {
@@ -146,7 +185,7 @@
     struct elf_phdr *phdr = NULL, *ph;
     int size, i, total_size;
     elf_word mem_size;
-    uint64_t addr, low = 0, high = 0;
+    uint64_t addr, low = (uint64_t)-1, high = 0;
     uint8_t *data = NULL;
 
     if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
@@ -155,8 +194,21 @@
         glue(bswap_ehdr, SZ)(&ehdr);
     }
 
-    if (ELF_MACHINE != ehdr.e_machine)
-        goto fail;
+    switch (ELF_MACHINE) {
+        case EM_PPC64:
+            if (EM_PPC64 != ehdr.e_machine)
+                if (EM_PPC != ehdr.e_machine)
+                    goto fail;
+            break;
+        case EM_X86_64:
+            if (EM_X86_64 != ehdr.e_machine)
+                if (EM_386 != ehdr.e_machine)
+                    goto fail;
+            break;
+        default:
+            if (ELF_MACHINE != ehdr.e_machine)
+                goto fail;
+    }
 
     if (pentry)
    	*pentry = (uint64_t)(elf_sword)ehdr.e_entry;
@@ -190,14 +242,16 @@
                 if (read(fd, data, ph->p_filesz) != ph->p_filesz)
                     goto fail;
             }
-            addr = ph->p_vaddr + virt_to_phys_addend;
+            /* address_offset is hack for kernel images that are
+               linked at the wrong physical address.  */
+            addr = ph->p_paddr + address_offset;
 
             cpu_physical_memory_write_rom(addr, data, mem_size);
 
             total_size += mem_size;
-            if (!low || addr < low)
+            if (addr < low)
                 low = addr;
-            if (!high || (addr + mem_size) > high)
+            if ((addr + mem_size) > high)
                 high = addr + mem_size;
 
             qemu_free(data);
diff --git a/exec-all.h b/exec-all.h
index a223bff..0a240ee 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -15,9 +15,14 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 
+#ifndef _EXEC_ALL_H_
+#define _EXEC_ALL_H_
+
+#include "qemu-common.h"
+
 /* allow to see translation results - the slowdown should be negligible, so we leave it */
 #define DEBUG_DISAS
 
@@ -33,7 +38,7 @@
 #define MAX_OP_PER_INSTR 64
 /* A Call op needs up to 6 + 2N parameters (N = number of arguments).  */
 #define MAX_OPC_PARAM 10
-#define OPC_BUF_SIZE 512
+#define OPC_BUF_SIZE 2048
 #define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
 
 /* Maximum size a TCG op can expand to.  This is complicated because a
@@ -52,11 +57,6 @@
 extern target_ulong gen_opc_jump_pc[2];
 extern uint32_t gen_opc_hflags[OPC_BUF_SIZE];
 
-typedef void (GenOpFunc)(void);
-typedef void (GenOpFunc1)(long);
-typedef void (GenOpFunc2)(long, long);
-typedef void (GenOpFunc3)(long, long, long);
-
 #include "qemu-log.h"
 
 void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
@@ -80,6 +80,7 @@
                               target_ulong pc, target_ulong cs_base, int flags,
                               int cflags);
 void cpu_exec_init(CPUState *env);
+void QEMU_NORETURN cpu_loop_exit(void);
 int page_unprotect(target_ulong address, unsigned long pc, void *puc);
 void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
                                    int is_cpu_write_access);
@@ -114,7 +115,7 @@
 #define CODE_GEN_AVG_BLOCK_SIZE 64
 #endif
 
-#if defined(__powerpc__) || defined(__x86_64__) || defined(__arm__)
+#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__)
 #define USE_DIRECT_JUMP
 #endif
 #if defined(__i386__) && !defined(_WIN32)
@@ -194,7 +195,7 @@
 
 #if defined(USE_DIRECT_JUMP)
 
-#if defined(__powerpc__)
+#if defined(_ARCH_PPC)
 extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr);
 #define tb_set_jmp_target1 ppc_tb_set_jmp_target
 #elif defined(__i386__) || defined(__x86_64__)
@@ -207,18 +208,26 @@
 #elif defined(__arm__)
 static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
 {
+#if QEMU_GNUC_PREREQ(4, 1)
+    void __clear_cache(char *beg, char *end);
+#else
     register unsigned long _beg __asm ("a1");
     register unsigned long _end __asm ("a2");
     register unsigned long _flg __asm ("a3");
+#endif
 
     /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */
     *(uint32_t *)jmp_addr |= ((addr - (jmp_addr + 8)) >> 2) & 0xffffff;
 
+#if QEMU_GNUC_PREREQ(4, 1)
+    __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4);
+#else
     /* flush icache */
     _beg = jmp_addr;
     _end = jmp_addr + 4;
     _flg = 0;
     __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
+#endif
 }
 #endif
 
@@ -261,20 +270,6 @@
 
 TranslationBlock *tb_find_pc(unsigned long pc_ptr);
 
-#if defined(_WIN32)
-#define ASM_DATA_SECTION ".section \".data\"\n"
-#define ASM_PREVIOUS_SECTION ".section .text\n"
-#elif defined(__APPLE__)
-#define ASM_DATA_SECTION ".data\n"
-#define ASM_PREVIOUS_SECTION ".text\n"
-#else
-#define ASM_DATA_SECTION ".section \".data\"\n"
-#define ASM_PREVIOUS_SECTION ".previous\n"
-#endif
-
-#define ASM_OP_LABEL_NAME(n, opname) \
-    ASM_NAME(__op_label) #n "." ASM_NAME(opname)
-
 extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
 extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
@@ -326,6 +321,7 @@
 static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
 {
     int mmu_idx, page_index, pd;
+    void *p;
 
     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     mmu_idx = cpu_mmu_index(env1);
@@ -336,12 +332,14 @@
     pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
     if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
 #if defined(TARGET_SPARC) || defined(TARGET_MIPS)
-        do_unassigned_access(addr, 0, 1, 0);
+        do_unassigned_access(addr, 0, 1, 0, 4);
 #else
         cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
 #endif
     }
-    return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base;
+    p = (void *)(unsigned long)addr
+        + env1->tlb_table[mmu_idx][page_index].addend;
+    return qemu_ram_addr_from_host(p);
 }
 
 /* Deterministic execution requires that IO only be performed on the last
@@ -359,7 +357,7 @@
 }
 #endif
 
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
 #define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
 
 #define MSR_QPI_COMMBASE 0xfabe0010
@@ -377,6 +375,9 @@
 
 extern uint32_t kqemu_comm_base;
 
+extern ram_addr_t kqemu_phys_ram_size;
+extern uint8_t *kqemu_phys_ram_base;
+
 static inline int kqemu_is_ok(CPUState *env)
 {
     return(env->kqemu_enabled &&
@@ -390,3 +391,12 @@
 }
 
 #endif
+
+typedef void (CPUDebugExcpHandler)(CPUState *env);
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
+
+/* vl.c */
+extern int singlestep;
+
+#endif
diff --git a/exec.c b/exec.c
index 547801b..d33a3c0 100644
--- a/exec.c
+++ b/exec.c
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include "config.h"
 #ifdef _WIN32
@@ -38,6 +38,8 @@
 #include "qemu-common.h"
 #include "tcg.h"
 #include "hw/hw.h"
+#include "osdep.h"
+#include "kvm.h"
 #if defined(CONFIG_USER_ONLY)
 #include <qemu.h>
 #endif
@@ -61,9 +63,6 @@
 
 #define SMC_BITMAP_USE_THRESHOLD 10
 
-#define MMAP_AREA_START        0x00000000
-#define MMAP_AREA_END          0xa8000000
-
 #if defined(TARGET_SPARC64)
 #define TARGET_PHYS_ADDR_SPACE_BITS 41
 #elif defined(TARGET_SPARC)
@@ -73,19 +72,19 @@
 #define TARGET_VIRT_ADDR_SPACE_BITS 42
 #elif defined(TARGET_PPC64)
 #define TARGET_PHYS_ADDR_SPACE_BITS 42
-#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
+#elif defined(TARGET_X86_64) && !defined(CONFIG_KQEMU)
 #define TARGET_PHYS_ADDR_SPACE_BITS 42
-#elif defined(TARGET_I386) && !defined(USE_KQEMU)
+#elif defined(TARGET_I386) && !defined(CONFIG_KQEMU)
 #define TARGET_PHYS_ADDR_SPACE_BITS 36
 #else
 /* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
 #define TARGET_PHYS_ADDR_SPACE_BITS 32
 #endif
 
-TranslationBlock *tbs;
+static TranslationBlock *tbs;
 int code_gen_max_blocks;
 TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
-int nb_tbs;
+static int nb_tbs;
 /* any access to the tbs or the page table must use this lock */
 spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
 
@@ -102,18 +101,29 @@
 #endif
 
 uint8_t code_gen_prologue[1024] code_gen_section;
-uint8_t *code_gen_buffer;
-unsigned long code_gen_buffer_size;
+static uint8_t *code_gen_buffer;
+static unsigned long code_gen_buffer_size;
 /* threshold to flush the translated code buffer */
-unsigned long code_gen_buffer_max_size; 
+static unsigned long code_gen_buffer_max_size;
 uint8_t *code_gen_ptr;
 
 #if !defined(CONFIG_USER_ONLY)
-ram_addr_t phys_ram_size;
 int phys_ram_fd;
-uint8_t *phys_ram_base;
 uint8_t *phys_ram_dirty;
-static ram_addr_t phys_ram_alloc_offset = 0;
+static int in_migration;
+
+typedef struct RAMBlock {
+    uint8_t *host;
+    ram_addr_t offset;
+    ram_addr_t length;
+    struct RAMBlock *next;
+} RAMBlock;
+
+static RAMBlock *ram_blocks;
+/* TODO: When we implement (and use) ram deallocation (e.g. for hotplug)
+   then we can no longer assume contiguous ram offsets, and external uses
+   of this variable will break.  */
+ram_addr_t last_ram_offset;
 #endif
 
 CPUState *first_cpu;
@@ -143,6 +153,7 @@
 typedef struct PhysPageDesc {
     /* offset in host memory of the page + io_index in the low bits */
     ram_addr_t phys_offset;
+    ram_addr_t region_offset;
 } PhysPageDesc;
 
 #define L2_BITS 10
@@ -166,7 +177,7 @@
 
 /* XXX: for system emulation, it could just be an array */
 static PageDesc *l1_map[L1_SIZE];
-PhysPageDesc **l1_phys_map;
+static PhysPageDesc **l1_phys_map;
 
 #if !defined(CONFIG_USER_ONLY)
 static void io_mem_init(void);
@@ -175,12 +186,12 @@
 CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
 CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
 void *io_mem_opaque[IO_MEM_NB_ENTRIES];
-static int io_mem_nb;
+static char io_mem_used[IO_MEM_NB_ENTRIES];
 static int io_mem_watch;
 #endif
 
 /* log support */
-const char *logfilename = "/tmp/qemu.log";
+static const char *logfilename = "/tmp/qemu.log";
 FILE *logfile;
 int loglevel;
 static int log_append = 0;
@@ -196,6 +207,7 @@
     CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
     CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
     void *opaque[TARGET_PAGE_SIZE][2][4];
+    ram_addr_t region_offset[TARGET_PAGE_SIZE][2][4];
 } subpage_t;
 
 #ifdef _WIN32
@@ -231,7 +243,6 @@
 #ifdef _WIN32
     {
         SYSTEM_INFO system_info;
-        DWORD old_protect;
 
         GetSystemInfo(&system_info);
         qemu_real_host_page_size = system_info.dwPageSize;
@@ -301,14 +312,13 @@
     if (!p) {
         /* allocate if not found */
 #if defined(CONFIG_USER_ONLY)
-        unsigned long addr;
         size_t len = sizeof(PageDesc) * L2_SIZE;
         /* Don't use qemu_malloc because it may recurse.  */
         p = mmap(0, len, PROT_READ | PROT_WRITE,
                  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
         *lp = p;
-        addr = h2g(p);
-        if (addr == (target_ulong)addr) {
+        if (h2g_valid(p)) {
+            unsigned long addr = h2g(p);
             page_set_flags(addr & TARGET_PAGE_MASK,
                            TARGET_PAGE_ALIGN(addr + len),
                            PAGE_RESERVED); 
@@ -365,8 +375,10 @@
             return NULL;
         pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
         *lp = pd;
-        for (i = 0; i < L2_SIZE; i++)
+        for (i = 0; i < L2_SIZE; i++) {
           pd[i].phys_offset = IO_MEM_UNASSIGNED;
+          pd[i].region_offset = (index + i) << TARGET_PAGE_BITS;
+        }
     }
     return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
 }
@@ -387,7 +399,7 @@
 #define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
 
 #if defined(CONFIG_USER_ONLY)
-/* Currently it is not recommanded to allocate big chunks of data in
+/* Currently it is not recommended to allocate big chunks of data in
    user mode. It will change when a dedicated libc will be used */
 #define USE_STATIC_CODE_GEN_BUFFER
 #endif
@@ -409,8 +421,8 @@
         /* in user mode, phys_ram_size is not meaningful */
         code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
 #else
-        /* XXX: needs ajustments */
-        code_gen_buffer_size = (int)(phys_ram_size / 4);
+        /* XXX: needs adjustments */
+        code_gen_buffer_size = (unsigned long)(ram_size / 4);
 #endif
     }
     if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
@@ -434,6 +446,12 @@
         start = (void *) 0x60000000UL;
         if (code_gen_buffer_size > (512 * 1024 * 1024))
             code_gen_buffer_size = (512 * 1024 * 1024);
+#elif defined(__arm__)
+        /* Map the buffer below 32M, so we can use direct calls and branches */
+        flags |= MAP_FIXED;
+        start = (void *) 0x01000000UL;
+        if (code_gen_buffer_size > 16 * 1024 * 1024)
+            code_gen_buffer_size = 16 * 1024 * 1024;
 #endif
         code_gen_buffer = mmap(start, code_gen_buffer_size,
                                PROT_WRITE | PROT_READ | PROT_EXEC,
@@ -443,12 +461,30 @@
             exit(1);
         }
     }
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+    {
+        int flags;
+        void *addr = NULL;
+        flags = MAP_PRIVATE | MAP_ANONYMOUS;
+#if defined(__x86_64__)
+        /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
+         * 0x40000000 is free */
+        flags |= MAP_FIXED;
+        addr = (void *)0x40000000;
+        /* Cannot map more than that */
+        if (code_gen_buffer_size > (800 * 1024 * 1024))
+            code_gen_buffer_size = (800 * 1024 * 1024);
+#endif
+        code_gen_buffer = mmap(addr, code_gen_buffer_size,
+                               PROT_WRITE | PROT_READ | PROT_EXEC, 
+                               flags, -1, 0);
+        if (code_gen_buffer == MAP_FAILED) {
+            fprintf(stderr, "Could not allocate dynamic translator buffer\n");
+            exit(1);
+        }
+    }
 #else
     code_gen_buffer = qemu_malloc(code_gen_buffer_size);
-    if (!code_gen_buffer) {
-        fprintf(stderr, "Could not allocate dynamic translator buffer\n");
-        exit(1);
-    }
     map_exec(code_gen_buffer, code_gen_buffer_size);
 #endif
 #endif /* !USE_STATIC_CODE_GEN_BUFFER */
@@ -481,6 +517,8 @@
 {
     CPUState *env = opaque;
 
+    cpu_synchronize_state(env, 0);
+
     qemu_put_be32s(f, &env->halted);
     qemu_put_be32s(f, &env->interrupt_request);
 }
@@ -494,27 +532,52 @@
 
     qemu_get_be32s(f, &env->halted);
     qemu_get_be32s(f, &env->interrupt_request);
+    /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
+       version_id is increased. */
+    env->interrupt_request &= ~0x01;
     tlb_flush(env, 1);
+    cpu_synchronize_state(env, 1);
 
     return 0;
 }
 #endif
 
+CPUState *qemu_get_cpu(int cpu)
+{
+    CPUState *env = first_cpu;
+
+    while (env) {
+        if (env->cpu_index == cpu)
+            break;
+        env = env->next_cpu;
+    }
+
+    return env;
+}
+
 void cpu_exec_init(CPUState *env)
 {
     CPUState **penv;
     int cpu_index;
 
+#if defined(CONFIG_USER_ONLY)
+    cpu_list_lock();
+#endif
     env->next_cpu = NULL;
     penv = &first_cpu;
     cpu_index = 0;
     while (*penv != NULL) {
-        penv = (CPUState **)&(*penv)->next_cpu;
+        penv = &(*penv)->next_cpu;
         cpu_index++;
     }
     env->cpu_index = cpu_index;
-    env->nb_watchpoints = 0;
+    env->numa_node = 0;
+    TAILQ_INIT(&env->breakpoints);
+    TAILQ_INIT(&env->watchpoints);
     *penv = env;
+#if defined(CONFIG_USER_ONLY)
+    cpu_list_unlock();
+#endif
 #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
     register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
                     cpu_common_save, cpu_common_load, env);
@@ -615,7 +678,7 @@
     }
 }
 
-void tb_jmp_check(TranslationBlock *tb)
+static void tb_jmp_check(TranslationBlock *tb)
 {
     TranslationBlock *tb1;
     unsigned int n1;
@@ -793,8 +856,6 @@
     TranslationBlock *tb;
 
     p->code_bitmap = qemu_mallocz(TARGET_PAGE_SIZE / 8);
-    if (!p->code_bitmap)
-        return;
 
     tb = p->first_tb;
     while (tb != NULL) {
@@ -866,12 +927,19 @@
 void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
                                    int is_cpu_write_access)
 {
-    int n, current_tb_modified, current_tb_not_found, current_flags;
+    TranslationBlock *tb, *tb_next, *saved_tb;
     CPUState *env = cpu_single_env;
-    PageDesc *p;
-    TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
     target_ulong tb_start, tb_end;
-    target_ulong current_pc, current_cs_base;
+    PageDesc *p;
+    int n;
+#ifdef TARGET_HAS_PRECISE_SMC
+    int current_tb_not_found = is_cpu_write_access;
+    TranslationBlock *current_tb = NULL;
+    int current_tb_modified = 0;
+    target_ulong current_pc = 0;
+    target_ulong current_cs_base = 0;
+    int current_flags = 0;
+#endif /* TARGET_HAS_PRECISE_SMC */
 
     p = page_find(start >> TARGET_PAGE_BITS);
     if (!p)
@@ -885,12 +953,6 @@
 
     /* we remove all the TBs in the range [start, end[ */
     /* XXX: see if in some cases it could be faster to invalidate all the code */
-    current_tb_not_found = is_cpu_write_access;
-    current_tb_modified = 0;
-    current_tb = NULL; /* avoid warning */
-    current_pc = 0; /* avoid warning */
-    current_cs_base = 0; /* avoid warning */
-    current_flags = 0; /* avoid warning */
     tb = p->first_tb;
     while (tb != NULL) {
         n = (long)tb & 3;
@@ -927,14 +989,8 @@
                 current_tb_modified = 1;
                 cpu_restore_state(current_tb, env,
                                   env->mem_io_pc, NULL);
-#if defined(TARGET_I386)
-                current_flags = env->hflags;
-                current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
-                current_cs_base = (target_ulong)env->segs[R_CS].base;
-                current_pc = current_cs_base + env->eip;
-#else
-#error unsupported CPU
-#endif
+                cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
+                                     &current_flags);
             }
 #endif /* TARGET_HAS_PRECISE_SMC */
             /* we need to do that to handle the case where a signal
@@ -981,12 +1037,10 @@
     int offset, b;
 #if 0
     if (1) {
-        if (loglevel) {
-            fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
-                   cpu_single_env->mem_io_vaddr, len,
-                   cpu_single_env->eip,
-                   cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
-        }
+        qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
+                  cpu_single_env->mem_io_vaddr, len,
+                  cpu_single_env->eip,
+                  cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
     }
 #endif
     p = page_find(start >> TARGET_PAGE_BITS);
@@ -1007,12 +1061,16 @@
 static void tb_invalidate_phys_page(target_phys_addr_t addr,
                                     unsigned long pc, void *puc)
 {
-    int n, current_flags, current_tb_modified;
-    target_ulong current_pc, current_cs_base;
+    TranslationBlock *tb;
     PageDesc *p;
-    TranslationBlock *tb, *current_tb;
+    int n;
 #ifdef TARGET_HAS_PRECISE_SMC
+    TranslationBlock *current_tb = NULL;
     CPUState *env = cpu_single_env;
+    int current_tb_modified = 0;
+    target_ulong current_pc = 0;
+    target_ulong current_cs_base = 0;
+    int current_flags = 0;
 #endif
 
     addr &= TARGET_PAGE_MASK;
@@ -1020,11 +1078,6 @@
     if (!p)
         return;
     tb = p->first_tb;
-    current_tb_modified = 0;
-    current_tb = NULL;
-    current_pc = 0; /* avoid warning */
-    current_cs_base = 0; /* avoid warning */
-    current_flags = 0; /* avoid warning */
 #ifdef TARGET_HAS_PRECISE_SMC
     if (tb && pc != 0) {
         current_tb = tb_find_pc(pc);
@@ -1044,14 +1097,8 @@
 
             current_tb_modified = 1;
             cpu_restore_state(current_tb, env, pc, puc);
-#if defined(TARGET_I386)
-            current_flags = env->hflags;
-            current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
-            current_cs_base = (target_ulong)env->segs[R_CS].base;
-            current_pc = current_cs_base + env->eip;
-#else
-#error unsupported CPU
-#endif
+            cpu_get_tb_cpu_state(env, &current_pc, &current_cs_base,
+                                 &current_flags);
         }
 #endif /* TARGET_HAS_PRECISE_SMC */
         tb_phys_invalidate(tb, addr);
@@ -1291,107 +1338,143 @@
 #endif
 
 /* Add a watchpoint.  */
-int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type)
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags, CPUWatchpoint **watchpoint)
 {
-    int i;
+    target_ulong len_mask = ~(len - 1);
+    CPUWatchpoint *wp;
 
-    for (i = 0; i < env->nb_watchpoints; i++) {
-        if (addr == env->watchpoint[i].vaddr)
-            return 0;
+    /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
+    if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
+        fprintf(stderr, "qemu: tried to set invalid watchpoint at "
+                TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
+        return -EINVAL;
     }
-    if (env->nb_watchpoints >= MAX_WATCHPOINTS)
-        return -1;
+    wp = qemu_malloc(sizeof(*wp));
 
-    i = env->nb_watchpoints++;
-    env->watchpoint[i].vaddr = addr;
-    env->watchpoint[i].type = type;
+    wp->vaddr = addr;
+    wp->len_mask = len_mask;
+    wp->flags = flags;
+
+    /* keep all GDB-injected watchpoints in front */
+    if (flags & BP_GDB)
+        TAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
+    else
+        TAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
+
     tlb_flush_page(env, addr);
-    /* FIXME: This flush is needed because of the hack to make memory ops
-       terminate the TB.  It can be removed once the proper IO trap and
-       re-execute bits are in.  */
-    tb_flush(env);
-    return i;
+
+    if (watchpoint)
+        *watchpoint = wp;
+    return 0;
 }
 
-/* Remove a watchpoint.  */
-int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
+/* Remove a specific watchpoint.  */
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags)
 {
-    int i;
+    target_ulong len_mask = ~(len - 1);
+    CPUWatchpoint *wp;
 
-    for (i = 0; i < env->nb_watchpoints; i++) {
-        if (addr == env->watchpoint[i].vaddr) {
-            env->nb_watchpoints--;
-            env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
-            tlb_flush_page(env, addr);
+    TAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        if (addr == wp->vaddr && len_mask == wp->len_mask
+                && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
+            cpu_watchpoint_remove_by_ref(env, wp);
             return 0;
         }
     }
-    return -1;
+    return -ENOENT;
 }
 
-/* Remove all watchpoints. */
-void cpu_watchpoint_remove_all(CPUState *env) {
-    int i;
+/* Remove a specific watchpoint by reference.  */
+void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
+{
+    TAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
 
-    for (i = 0; i < env->nb_watchpoints; i++) {
-        tlb_flush_page(env, env->watchpoint[i].vaddr);
+    tlb_flush_page(env, watchpoint->vaddr);
+
+    qemu_free(watchpoint);
+}
+
+/* Remove all matching watchpoints.  */
+void cpu_watchpoint_remove_all(CPUState *env, int mask)
+{
+    CPUWatchpoint *wp, *next;
+
+    TAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
+        if (wp->flags & mask)
+            cpu_watchpoint_remove_by_ref(env, wp);
     }
-    env->nb_watchpoints = 0;
 }
 
-/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
-   breakpoint is reached */
-int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
+/* Add a breakpoint.  */
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+                          CPUBreakpoint **breakpoint)
 {
 #if defined(TARGET_HAS_ICE)
-    int i;
+    CPUBreakpoint *bp;
 
-    for(i = 0; i < env->nb_breakpoints; i++) {
-        if (env->breakpoints[i] == pc)
+    bp = qemu_malloc(sizeof(*bp));
+
+    bp->pc = pc;
+    bp->flags = flags;
+
+    /* keep all GDB-injected breakpoints in front */
+    if (flags & BP_GDB)
+        TAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
+    else
+        TAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
+
+    breakpoint_invalidate(env, pc);
+
+    if (breakpoint)
+        *breakpoint = bp;
+    return 0;
+#else
+    return -ENOSYS;
+#endif
+}
+
+/* Remove a specific breakpoint.  */
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
+{
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp;
+
+    TAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        if (bp->pc == pc && bp->flags == flags) {
+            cpu_breakpoint_remove_by_ref(env, bp);
             return 0;
+        }
     }
-
-    if (env->nb_breakpoints >= MAX_BREAKPOINTS)
-        return -1;
-    env->breakpoints[env->nb_breakpoints++] = pc;
-
-    breakpoint_invalidate(env, pc);
-    return 0;
+    return -ENOENT;
 #else
-    return -1;
+    return -ENOSYS;
 #endif
 }
 
-/* remove all breakpoints */
-void cpu_breakpoint_remove_all(CPUState *env) {
-#if defined(TARGET_HAS_ICE)
-    int i;
-    for(i = 0; i < env->nb_breakpoints; i++) {
-        breakpoint_invalidate(env, env->breakpoints[i]);
-    }
-    env->nb_breakpoints = 0;
-#endif
-}
-
-/* remove a breakpoint */
-int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
+/* Remove a specific breakpoint by reference.  */
+void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
 {
 #if defined(TARGET_HAS_ICE)
-    int i;
-    for(i = 0; i < env->nb_breakpoints; i++) {
-        if (env->breakpoints[i] == pc)
-            goto found;
-    }
-    return -1;
- found:
-    env->nb_breakpoints--;
-    if (i < env->nb_breakpoints)
-      env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
+    TAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
 
-    breakpoint_invalidate(env, pc);
-    return 0;
-#else
-    return -1;
+    breakpoint_invalidate(env, breakpoint->pc);
+
+    qemu_free(breakpoint);
+#endif
+}
+
+/* Remove all matching breakpoints. */
+void cpu_breakpoint_remove_all(CPUState *env, int mask)
+{
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp, *next;
+
+    TAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
+        if (bp->flags & mask)
+            cpu_breakpoint_remove_by_ref(env, bp);
+    }
 #endif
 }
 
@@ -1402,9 +1485,13 @@
 #if defined(TARGET_HAS_ICE)
     if (env->singlestep_enabled != enabled) {
         env->singlestep_enabled = enabled;
-        /* must flush all the translated code to avoid inconsistancies */
-        /* XXX: only flush what is necessary */
-        tb_flush(env);
+        if (kvm_enabled())
+            kvm_update_guest_debug(env, 0);
+        else {
+            /* must flush all the translated code to avoid inconsistencies */
+            /* XXX: only flush what is necessary */
+            tb_flush(env);
+        }
     }
 #endif
 }
@@ -1422,7 +1509,7 @@
 #if !defined(CONFIG_SOFTMMU)
         /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
         {
-            static uint8_t logfile_buf[4096];
+            static char logfile_buf[4096];
             setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
         }
 #else
@@ -1446,46 +1533,58 @@
     cpu_set_log(loglevel);
 }
 
-/* mask must never be zero, except for A20 change call */
-void cpu_interrupt(CPUState *env, int mask)
+static void cpu_unlink_tb(CPUState *env)
 {
-#if !defined(USE_NPTL)
-    TranslationBlock *tb;
-    static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
-#endif
-    int old_mask;
-
-    old_mask = env->interrupt_request;
-    /* FIXME: This is probably not threadsafe.  A different thread could
-       be in the middle of a read-modify-write operation.  */
-    env->interrupt_request |= mask;
 #if defined(USE_NPTL)
     /* FIXME: TB unchaining isn't SMP safe.  For now just ignore the
        problem and hope the cpu will stop of its own accord.  For userspace
        emulation this often isn't actually as bad as it sounds.  Often
        signals are used primarily to interrupt blocking syscalls.  */
 #else
+    TranslationBlock *tb;
+    static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
+
+    tb = env->current_tb;
+    /* if the cpu is currently executing code, we must unlink it and
+       all the potentially executing TB */
+    if (tb && !testandset(&interrupt_lock)) {
+        env->current_tb = NULL;
+        tb_reset_jump_recursive(tb);
+        resetlock(&interrupt_lock);
+    }
+#endif
+}
+
+/* mask must never be zero, except for A20 change call */
+void cpu_interrupt(CPUState *env, int mask)
+{
+    int old_mask;
+
+    old_mask = env->interrupt_request;
+    env->interrupt_request |= mask;
+
+#ifndef CONFIG_USER_ONLY
+    /*
+     * If called from iothread context, wake the target cpu in
+     * case its halted.
+     */
+    if (!qemu_cpu_self(env)) {
+        qemu_cpu_kick(env);
+        return;
+    }
+#endif
+
     if (use_icount) {
         env->icount_decr.u16.high = 0xffff;
 #ifndef CONFIG_USER_ONLY
-        /* CPU_INTERRUPT_EXIT isn't a real interrupt.  It just means
-           an async event happened and we need to process it.  */
         if (!can_do_io(env)
-            && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
+            && (mask & ~old_mask) != 0) {
             cpu_abort(env, "Raised interrupt while not in I/O function");
         }
 #endif
     } else {
-        tb = env->current_tb;
-        /* if the cpu is currently executing code, we must unlink it and
-           all the potentially executing TB */
-        if (tb && !testandset(&interrupt_lock)) {
-            env->current_tb = NULL;
-            tb_reset_jump_recursive(tb);
-            resetlock(&interrupt_lock);
-        }
+        cpu_unlink_tb(env);
     }
-#endif
 }
 
 void cpu_reset_interrupt(CPUState *env, int mask)
@@ -1493,7 +1592,13 @@
     env->interrupt_request &= ~mask;
 }
 
-CPULogItem cpu_log_items[] = {
+void cpu_exit(CPUState *env)
+{
+    env->exit_request = 1;
+    cpu_unlink_tb(env);
+}
+
+const CPULogItem cpu_log_items[] = {
     { CPU_LOG_TB_OUT_ASM, "out_asm",
       "show generated host assembly code for each compiled TB" },
     { CPU_LOG_TB_IN_ASM, "in_asm",
@@ -1515,6 +1620,8 @@
 #ifdef TARGET_I386
     { CPU_LOG_PCALL, "pcall",
       "show protected mode far calls/returns/exceptions" },
+    { CPU_LOG_RESET, "cpu_reset",
+      "show CPU state before CPU resets" },
 #endif
 #ifdef DEBUG_IOPORT
     { CPU_LOG_IOPORT, "ioport",
@@ -1533,7 +1640,7 @@
 /* takes a comma separated list of log masks. Return 0 if error. */
 int cpu_str_to_log_mask(const char *str)
 {
-    CPULogItem *item;
+    const CPULogItem *item;
     int mask;
     const char *p, *p1;
 
@@ -1578,17 +1685,17 @@
 #else
     cpu_dump_state(env, stderr, fprintf, 0);
 #endif
-    if (logfile) {
-        fprintf(logfile, "qemu: fatal: ");
-        vfprintf(logfile, fmt, ap2);
-        fprintf(logfile, "\n");
+    if (qemu_log_enabled()) {
+        qemu_log("qemu: fatal: ");
+        qemu_log_vprintf(fmt, ap2);
+        qemu_log("\n");
 #ifdef TARGET_I386
-        cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
+        log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
 #else
-        cpu_dump_state(env, logfile, fprintf, 0);
+        log_cpu_state(env, 0);
 #endif
-        fflush(logfile);
-        fclose(logfile);
+        qemu_log_flush();
+        qemu_log_close();
     }
     va_end(ap2);
     va_end(ap);
@@ -1598,12 +1705,34 @@
 CPUState *cpu_copy(CPUState *env)
 {
     CPUState *new_env = cpu_init(env->cpu_model_str);
-    /* preserve chaining and index */
     CPUState *next_cpu = new_env->next_cpu;
     int cpu_index = new_env->cpu_index;
+#if defined(TARGET_HAS_ICE)
+    CPUBreakpoint *bp;
+    CPUWatchpoint *wp;
+#endif
+
     memcpy(new_env, env, sizeof(CPUState));
+
+    /* Preserve chaining and index. */
     new_env->next_cpu = next_cpu;
     new_env->cpu_index = cpu_index;
+
+    /* Clone all break/watchpoints.
+       Note: Once we support ptrace with hw-debug register access, make sure
+       BP_CPU break/watchpoints are handled correctly on clone. */
+    TAILQ_INIT(&env->breakpoints);
+    TAILQ_INIT(&env->watchpoints);
+#if defined(TARGET_HAS_ICE)
+    TAILQ_FOREACH(bp, &env->breakpoints, entry) {
+        cpu_breakpoint_insert(new_env, bp->pc, bp->flags, NULL);
+    }
+    TAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        cpu_watchpoint_insert(new_env, wp->vaddr, (~wp->len_mask) + 1,
+                              wp->flags, NULL);
+    }
+#endif
+
     return new_env;
 }
 
@@ -1638,27 +1767,17 @@
     env->current_tb = NULL;
 
     for(i = 0; i < CPU_TLB_SIZE; i++) {
-        env->tlb_table[0][i].addr_read = -1;
-        env->tlb_table[0][i].addr_write = -1;
-        env->tlb_table[0][i].addr_code = -1;
-        env->tlb_table[1][i].addr_read = -1;
-        env->tlb_table[1][i].addr_write = -1;
-        env->tlb_table[1][i].addr_code = -1;
-#if (NB_MMU_MODES >= 3)
-        env->tlb_table[2][i].addr_read = -1;
-        env->tlb_table[2][i].addr_write = -1;
-        env->tlb_table[2][i].addr_code = -1;
-#if (NB_MMU_MODES == 4)
-        env->tlb_table[3][i].addr_read = -1;
-        env->tlb_table[3][i].addr_write = -1;
-        env->tlb_table[3][i].addr_code = -1;
-#endif
-#endif
+        int mmu_idx;
+        for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+            env->tlb_table[mmu_idx][i].addr_read = -1;
+            env->tlb_table[mmu_idx][i].addr_write = -1;
+            env->tlb_table[mmu_idx][i].addr_code = -1;
+        }
     }
 
     memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
 
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     if (env->kqemu_enabled) {
         kqemu_flush(env, flush_global);
     }
@@ -1683,6 +1802,7 @@
 void tlb_flush_page(CPUState *env, target_ulong addr)
 {
     int i;
+    int mmu_idx;
 
 #if defined(DEBUG_TLB)
     printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
@@ -1693,18 +1813,12 @@
 
     addr &= TARGET_PAGE_MASK;
     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-    tlb_flush_entry(&env->tlb_table[0][i], addr);
-    tlb_flush_entry(&env->tlb_table[1][i], addr);
-#if (NB_MMU_MODES >= 3)
-    tlb_flush_entry(&env->tlb_table[2][i], addr);
-#if (NB_MMU_MODES == 4)
-    tlb_flush_entry(&env->tlb_table[3][i], addr);
-#endif
-#endif
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++)
+        tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr);
 
     tlb_flush_jmp_cache(env, addr);
 
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     if (env->kqemu_enabled) {
         kqemu_flush_page(env, addr);
     }
@@ -1740,6 +1854,7 @@
     }
 }
 
+/* Note: start and end must be within the same ram block.  */
 void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
                                      int dirty_flags)
 {
@@ -1755,7 +1870,7 @@
     if (length == 0)
         return;
     len = length >> TARGET_PAGE_BITS;
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     /* XXX: should not depend on cpu context */
     env = first_cpu;
     if (env->kqemu_enabled) {
@@ -1774,30 +1889,57 @@
 
     /* we modify the TLB cache so that the dirty bit will be set again
        when accessing the range */
-    start1 = start + (unsigned long)phys_ram_base;
-    for(env = first_cpu; env != NULL; env = env->next_cpu) {
-        for(i = 0; i < CPU_TLB_SIZE; i++)
-            tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
-        for(i = 0; i < CPU_TLB_SIZE; i++)
-            tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
-#if (NB_MMU_MODES >= 3)
-        for(i = 0; i < CPU_TLB_SIZE; i++)
-            tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
-#if (NB_MMU_MODES == 4)
-        for(i = 0; i < CPU_TLB_SIZE; i++)
-            tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
-#endif
-#endif
+    start1 = (unsigned long)qemu_get_ram_ptr(start);
+    /* Chek that we don't span multiple blocks - this breaks the
+       address comparisons below.  */
+    if ((unsigned long)qemu_get_ram_ptr(end - 1) - start1
+            != (end - 1) - start) {
+        abort();
     }
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        int mmu_idx;
+        for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+            for(i = 0; i < CPU_TLB_SIZE; i++)
+                tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
+                                      start1, length);
+        }
+    }
+}
+
+int cpu_physical_memory_set_dirty_tracking(int enable)
+{
+    in_migration = enable;
+    if (kvm_enabled()) {
+        return kvm_set_migration_log(enable);
+    }
+    return 0;
+}
+
+int cpu_physical_memory_get_dirty_tracking(void)
+{
+    return in_migration;
+}
+
+int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr)
+{
+    int ret = 0;
+
+    if (kvm_enabled())
+        ret = kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
+    return ret;
 }
 
 static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
 {
     ram_addr_t ram_addr;
+    void *p;
 
     if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
-        ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
-            tlb_entry->addend - (unsigned long)phys_ram_base;
+        p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+            + tlb_entry->addend);
+        ram_addr = qemu_ram_addr_from_host(p);
         if (!cpu_physical_memory_is_dirty(ram_addr)) {
             tlb_entry->addr_write |= TLB_NOTDIRTY;
         }
@@ -1808,18 +1950,11 @@
 void cpu_tlb_update_dirty(CPUState *env)
 {
     int i;
-    for(i = 0; i < CPU_TLB_SIZE; i++)
-        tlb_update_dirty(&env->tlb_table[0][i]);
-    for(i = 0; i < CPU_TLB_SIZE; i++)
-        tlb_update_dirty(&env->tlb_table[1][i]);
-#if (NB_MMU_MODES >= 3)
-    for(i = 0; i < CPU_TLB_SIZE; i++)
-        tlb_update_dirty(&env->tlb_table[2][i]);
-#if (NB_MMU_MODES == 4)
-    for(i = 0; i < CPU_TLB_SIZE; i++)
-        tlb_update_dirty(&env->tlb_table[3][i]);
-#endif
-#endif
+    int mmu_idx;
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+        for(i = 0; i < CPU_TLB_SIZE; i++)
+            tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
+    }
 }
 
 static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
@@ -1833,17 +1968,12 @@
 static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
 {
     int i;
+    int mmu_idx;
 
     vaddr &= TARGET_PAGE_MASK;
     i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-    tlb_set_dirty1(&env->tlb_table[0][i], vaddr);
-    tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
-#if (NB_MMU_MODES >= 3)
-    tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
-#if (NB_MMU_MODES == 4)
-    tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
-#endif
-#endif
+    for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++)
+        tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr);
 }
 
 /* add a new TLB entry. At most one entry for a given virtual address
@@ -1862,7 +1992,7 @@
     target_phys_addr_t addend;
     int ret;
     CPUTLBEntry *te;
-    int i;
+    CPUWatchpoint *wp;
     target_phys_addr_t iotlb;
 
     p = phys_page_find(paddr >> TARGET_PAGE_BITS);
@@ -1882,7 +2012,7 @@
         /* IO memory case (romd handled later) */
         address |= TLB_MMIO;
     }
-    addend = (target_phys_addr_t)phys_ram_base + (pd & TARGET_PAGE_MASK);
+    addend = (unsigned long)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK);
     if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
         /* Normal RAM.  */
         iotlb = pd & TARGET_PAGE_MASK;
@@ -1891,20 +2021,25 @@
         else
             iotlb |= IO_MEM_ROM;
     } else {
-        /* IO handlers are currently passed a phsical address.
+        /* IO handlers are currently passed a physical address.
            It would be nice to pass an offset from the base address
            of that region.  This would avoid having to special case RAM,
            and avoid full address decoding in every device.
            We can't use the high bits of pd for this because
            IO_MEM_ROMD uses these as a ram address.  */
-        iotlb = (pd & ~TARGET_PAGE_MASK) + paddr;
+        iotlb = (pd & ~TARGET_PAGE_MASK);
+        if (p) {
+            iotlb += p->region_offset;
+        } else {
+            iotlb += paddr;
+        }
     }
 
     code_address = address;
     /* Make accesses to pages with watchpoints go via the
        watchpoint trap routines.  */
-    for (i = 0; i < env->nb_watchpoints; i++) {
-        if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
+    TAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
             iotlb = io_mem_watch + paddr;
             /* TODO: The memory case can be optimized by not trapping
                reads of pages with a write breakpoint.  */
@@ -1961,36 +2096,36 @@
     return 0;
 }
 
-/* dump memory mappings */
-void page_dump(FILE *f)
+/*
+ * Walks guest process memory "regions" one by one
+ * and calls callback function 'fn' for each region.
+ */
+int walk_memory_regions(void *priv,
+    int (*fn)(void *, unsigned long, unsigned long, unsigned long))
 {
     unsigned long start, end;
+    PageDesc *p = NULL;
     int i, j, prot, prot1;
-    PageDesc *p;
+    int rc = 0;
 
-    fprintf(f, "%-8s %-8s %-8s %s\n",
-            "start", "end", "size", "prot");
-    start = -1;
-    end = -1;
+    start = end = -1;
     prot = 0;
-    for(i = 0; i <= L1_SIZE; i++) {
-        if (i < L1_SIZE)
-            p = l1_map[i];
-        else
-            p = NULL;
-        for(j = 0;j < L2_SIZE; j++) {
-            if (!p)
-                prot1 = 0;
-            else
-                prot1 = p[j].flags;
+
+    for (i = 0; i <= L1_SIZE; i++) {
+        p = (i < L1_SIZE) ? l1_map[i] : NULL;
+        for (j = 0; j < L2_SIZE; j++) {
+            prot1 = (p == NULL) ? 0 : p[j].flags;
+            /*
+             * "region" is one continuous chunk of memory
+             * that has same protection flags set.
+             */
             if (prot1 != prot) {
                 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
                 if (start != -1) {
-                    fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
-                            start, end, end - start,
-                            prot & PAGE_READ ? 'r' : '-',
-                            prot & PAGE_WRITE ? 'w' : '-',
-                            prot & PAGE_EXEC ? 'x' : '-');
+                    rc = (*fn)(priv, start, end, prot);
+                    /* callback can stop iteration by returning != 0 */
+                    if (rc != 0)
+                        return (rc);
                 }
                 if (prot1 != 0)
                     start = end;
@@ -1998,10 +2133,33 @@
                     start = -1;
                 prot = prot1;
             }
-            if (!p)
+            if (p == NULL)
                 break;
         }
     }
+    return (rc);
+}
+
+static int dump_region(void *priv, unsigned long start,
+    unsigned long end, unsigned long prot)
+{
+    FILE *f = (FILE *)priv;
+
+    (void) fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
+        start, end, end - start,
+        ((prot & PAGE_READ) ? 'r' : '-'),
+        ((prot & PAGE_WRITE) ? 'w' : '-'),
+        ((prot & PAGE_EXEC) ? 'x' : '-'));
+
+    return (0);
+}
+
+/* dump memory mappings */
+void page_dump(FILE *f)
+{
+    (void) fprintf(f, "%-8s %-8s %-8s %s\n",
+            "start", "end", "size", "prot");
+    walk_memory_regions(f, dump_region);
 }
 
 int page_get_flags(target_ulong address)
@@ -2015,7 +2173,7 @@
 }
 
 /* modify the flags of a page and invalidate the code if
-   necessary. The flag PAGE_WRITE_ORG is positionned automatically
+   necessary. The flag PAGE_WRITE_ORG is positioned automatically
    depending on PAGE_WRITE */
 void page_set_flags(target_ulong start, target_ulong end, int flags)
 {
@@ -2050,12 +2208,13 @@
     target_ulong end;
     target_ulong addr;
 
+    if (start + len < start)
+        /* we've wrapped around */
+        return -1;
+
     end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
     start = start & TARGET_PAGE_MASK;
 
-    if( end < start )
-        /* we've wrapped around */
-        return -1;
     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
         p = page_find(addr >> TARGET_PAGE_BITS);
         if( !p )
@@ -2081,7 +2240,7 @@
 }
 
 /* called from signal handler: invalidate the code and unprotect the
-   page. Return TRUE if the fault was succesfully handled. */
+   page. Return TRUE if the fault was successfully handled. */
 int page_unprotect(target_ulong address, unsigned long pc, void *puc)
 {
     unsigned int page_index, prot, pindex;
@@ -2136,10 +2295,11 @@
 #endif /* defined(CONFIG_USER_ONLY) */
 
 #if !defined(CONFIG_USER_ONLY)
+
 static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
-                             ram_addr_t memory);
+                             ram_addr_t memory, ram_addr_t region_offset);
 static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
-                           ram_addr_t orig_memory);
+                           ram_addr_t orig_memory, ram_addr_t region_offset);
 #define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
                       need_subpage)                                     \
     do {                                                                \
@@ -2162,10 +2322,15 @@
 
 /* register physical memory. 'size' must be a multiple of the target
    page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
-   io memory page */
-void cpu_register_physical_memory(target_phys_addr_t start_addr,
-                                  ram_addr_t size,
-                                  ram_addr_t phys_offset)
+   io memory page.  The address used when calling the IO function is
+   the offset from the start of the region, plus region_offset.  Both
+   start_addr and region_offset are rounded down to a page boundary
+   before calculating this offset.  This should not be a problem unless
+   the low bits of start_addr and region_offset differ.  */
+void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
+                                         ram_addr_t size,
+                                         ram_addr_t phys_offset,
+                                         ram_addr_t region_offset)
 {
     target_phys_addr_t addr, end_addr;
     PhysPageDesc *p;
@@ -2173,13 +2338,20 @@
     ram_addr_t orig_size = size;
     void *subpage;
 
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     /* XXX: should not depend on cpu context */
     env = first_cpu;
     if (env->kqemu_enabled) {
         kqemu_set_phys_mem(start_addr, size, phys_offset);
     }
 #endif
+    if (kvm_enabled())
+        kvm_set_phys_mem(start_addr, size, phys_offset);
+
+    if (phys_offset == IO_MEM_UNASSIGNED) {
+        region_offset = start_addr;
+    }
+    region_offset &= TARGET_PAGE_MASK;
     size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
     end_addr = start_addr + (target_phys_addr_t)size;
     for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
@@ -2194,12 +2366,15 @@
             if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
                 if (!(orig_memory & IO_MEM_SUBPAGE)) {
                     subpage = subpage_init((addr & TARGET_PAGE_MASK),
-                                           &p->phys_offset, orig_memory);
+                                           &p->phys_offset, orig_memory,
+                                           p->region_offset);
                 } else {
                     subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
                                             >> IO_MEM_SHIFT];
                 }
-                subpage_register(subpage, start_addr2, end_addr2, phys_offset);
+                subpage_register(subpage, start_addr2, end_addr2, phys_offset,
+                                 region_offset);
+                p->region_offset = 0;
             } else {
                 p->phys_offset = phys_offset;
                 if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
@@ -2209,10 +2384,11 @@
         } else {
             p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
             p->phys_offset = phys_offset;
+            p->region_offset = region_offset;
             if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
-                (phys_offset & IO_MEM_ROMD))
+                (phys_offset & IO_MEM_ROMD)) {
                 phys_offset += TARGET_PAGE_SIZE;
-            else {
+            } else {
                 target_phys_addr_t start_addr2, end_addr2;
                 int need_subpage = 0;
 
@@ -2221,12 +2397,15 @@
 
                 if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
                     subpage = subpage_init((addr & TARGET_PAGE_MASK),
-                                           &p->phys_offset, IO_MEM_UNASSIGNED);
+                                           &p->phys_offset, IO_MEM_UNASSIGNED,
+                                           addr & TARGET_PAGE_MASK);
                     subpage_register(subpage, start_addr2, end_addr2,
-                                     phys_offset);
+                                     phys_offset, region_offset);
+                    p->region_offset = 0;
                 }
             }
         }
+        region_offset += TARGET_PAGE_SIZE;
     }
 
     /* since each CPU stores ram addresses in its TLB cache, we must
@@ -2248,22 +2427,145 @@
     return p->phys_offset;
 }
 
+void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+    if (kvm_enabled())
+        kvm_coalesce_mmio_region(addr, size);
+}
+
+void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
+{
+    if (kvm_enabled())
+        kvm_uncoalesce_mmio_region(addr, size);
+}
+
+#ifdef CONFIG_KQEMU
 /* XXX: better than nothing */
-ram_addr_t qemu_ram_alloc(ram_addr_t size)
+static ram_addr_t kqemu_ram_alloc(ram_addr_t size)
 {
     ram_addr_t addr;
-    if ((phys_ram_alloc_offset + size) > phys_ram_size) {
-        fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 "\n",
-                (uint64_t)size, (uint64_t)phys_ram_size);
+    if ((last_ram_offset + size) > kqemu_phys_ram_size) {
+        fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 ")\n",
+                (uint64_t)size, (uint64_t)kqemu_phys_ram_size);
         abort();
     }
-    addr = phys_ram_alloc_offset;
-    phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
+    addr = last_ram_offset;
+    last_ram_offset = TARGET_PAGE_ALIGN(last_ram_offset + size);
     return addr;
 }
+#endif
+
+ram_addr_t qemu_ram_alloc(ram_addr_t size)
+{
+    RAMBlock *new_block;
+
+#ifdef CONFIG_KQEMU
+    if (kqemu_phys_ram_base) {
+        return kqemu_ram_alloc(size);
+    }
+#endif
+
+    size = TARGET_PAGE_ALIGN(size);
+    new_block = qemu_malloc(sizeof(*new_block));
+
+    new_block->host = qemu_vmalloc(size);
+    new_block->offset = last_ram_offset;
+    new_block->length = size;
+
+    new_block->next = ram_blocks;
+    ram_blocks = new_block;
+
+    phys_ram_dirty = qemu_realloc(phys_ram_dirty,
+        (last_ram_offset + size) >> TARGET_PAGE_BITS);
+    memset(phys_ram_dirty + (last_ram_offset >> TARGET_PAGE_BITS),
+           0xff, size >> TARGET_PAGE_BITS);
+
+    last_ram_offset += size;
+
+    if (kvm_enabled())
+        kvm_setup_guest_memory(new_block->host, size);
+
+    return new_block->offset;
+}
 
 void qemu_ram_free(ram_addr_t addr)
 {
+    /* TODO: implement this.  */
+}
+
+/* Return a host pointer to ram allocated with qemu_ram_alloc.
+   With the exception of the softmmu code in this file, this should
+   only be used for local memory (e.g. video ram) that the device owns,
+   and knows it isn't going to access beyond the end of the block.
+
+   It should not be used for general purpose DMA.
+   Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
+ */
+void *qemu_get_ram_ptr(ram_addr_t addr)
+{
+    RAMBlock *prev;
+    RAMBlock **prevp;
+    RAMBlock *block;
+
+#ifdef CONFIG_KQEMU
+    if (kqemu_phys_ram_base) {
+        return kqemu_phys_ram_base + addr;
+    }
+#endif
+
+    prev = NULL;
+    prevp = &ram_blocks;
+    block = ram_blocks;
+    while (block && (block->offset > addr
+                     || block->offset + block->length <= addr)) {
+        if (prev)
+          prevp = &prev->next;
+        prev = block;
+        block = block->next;
+    }
+    if (!block) {
+        fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+        abort();
+    }
+    /* Move this entry to to start of the list.  */
+    if (prev) {
+        prev->next = block->next;
+        block->next = *prevp;
+        *prevp = block;
+    }
+    return block->host + (addr - block->offset);
+}
+
+/* Some of the softmmu routines need to translate from a host pointer
+   (typically a TLB entry) back to a ram offset.  */
+ram_addr_t qemu_ram_addr_from_host(void *ptr)
+{
+    RAMBlock *prev;
+    RAMBlock **prevp;
+    RAMBlock *block;
+    uint8_t *host = ptr;
+
+#ifdef CONFIG_KQEMU
+    if (kqemu_phys_ram_base) {
+        return host - kqemu_phys_ram_base;
+    }
+#endif
+
+    prev = NULL;
+    prevp = &ram_blocks;
+    block = ram_blocks;
+    while (block && (block->host > host
+                     || block->host + block->length <= host)) {
+        if (prev)
+          prevp = &prev->next;
+        prev = block;
+        block = block->next;
+    }
+    if (!block) {
+        fprintf(stderr, "Bad ram pointer %p\n", ptr);
+        abort();
+    }
+    return block->offset + (host - block->host);
 }
 
 static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -2271,10 +2573,30 @@
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
 #endif
-#ifdef TARGET_SPARC
-    do_unassigned_access(addr, 0, 0, 0);
-#elif defined(TARGET_CRIS)
-    do_unassigned_access(addr, 0, 0, 0);
+#if defined(TARGET_SPARC)
+    do_unassigned_access(addr, 0, 0, 0, 1);
+#endif
+    return 0;
+}
+
+static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
+#endif
+#if defined(TARGET_SPARC)
+    do_unassigned_access(addr, 0, 0, 0, 2);
+#endif
+    return 0;
+}
+
+static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
+#endif
+#if defined(TARGET_SPARC)
+    do_unassigned_access(addr, 0, 0, 0, 4);
 #endif
     return 0;
 }
@@ -2284,23 +2606,41 @@
 #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
 #endif
-#ifdef TARGET_SPARC
-    do_unassigned_access(addr, 1, 0, 0);
-#elif defined(TARGET_CRIS)
-    do_unassigned_access(addr, 1, 0, 0);
+#if defined(TARGET_SPARC)
+    do_unassigned_access(addr, 1, 0, 0, 1);
+#endif
+}
+
+static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
+#endif
+#if defined(TARGET_SPARC)
+    do_unassigned_access(addr, 1, 0, 0, 2);
+#endif
+}
+
+static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
+#endif
+#if defined(TARGET_SPARC)
+    do_unassigned_access(addr, 1, 0, 0, 4);
 #endif
 }
 
 static CPUReadMemoryFunc *unassigned_mem_read[3] = {
     unassigned_mem_readb,
-    unassigned_mem_readb,
-    unassigned_mem_readb,
+    unassigned_mem_readw,
+    unassigned_mem_readl,
 };
 
 static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
     unassigned_mem_writeb,
-    unassigned_mem_writeb,
-    unassigned_mem_writeb,
+    unassigned_mem_writew,
+    unassigned_mem_writel,
 };
 
 static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
@@ -2314,8 +2654,8 @@
         dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
 #endif
     }
-    stb_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
+    stb_p(qemu_get_ram_ptr(ram_addr), val);
+#ifdef CONFIG_KQEMU
     if (cpu_single_env->kqemu_enabled &&
         (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
         kqemu_modify_page(cpu_single_env, ram_addr);
@@ -2339,8 +2679,8 @@
         dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
 #endif
     }
-    stw_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
+    stw_p(qemu_get_ram_ptr(ram_addr), val);
+#ifdef CONFIG_KQEMU
     if (cpu_single_env->kqemu_enabled &&
         (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
         kqemu_modify_page(cpu_single_env, ram_addr);
@@ -2364,8 +2704,8 @@
         dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
 #endif
     }
-    stl_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
+    stl_p(qemu_get_ram_ptr(ram_addr), val);
+#ifdef CONFIG_KQEMU
     if (cpu_single_env->kqemu_enabled &&
         (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
         kqemu_modify_page(cpu_single_env, ram_addr);
@@ -2391,19 +2731,46 @@
 };
 
 /* Generate a debug exception if a watchpoint has been hit.  */
-static void check_watchpoint(int offset, int flags)
+static void check_watchpoint(int offset, int len_mask, int flags)
 {
     CPUState *env = cpu_single_env;
+    target_ulong pc, cs_base;
+    TranslationBlock *tb;
     target_ulong vaddr;
-    int i;
+    CPUWatchpoint *wp;
+    int cpu_flags;
 
+    if (env->watchpoint_hit) {
+        /* We re-entered the check after replacing the TB. Now raise
+         * the debug interrupt so that is will trigger after the
+         * current instruction. */
+        cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
+        return;
+    }
     vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
-    for (i = 0; i < env->nb_watchpoints; i++) {
-        if (vaddr == env->watchpoint[i].vaddr
-                && (env->watchpoint[i].type & flags)) {
-            env->watchpoint_hit = i + 1;
-            cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
-            break;
+    TAILQ_FOREACH(wp, &env->watchpoints, entry) {
+        if ((vaddr == (wp->vaddr & len_mask) ||
+             (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
+            wp->flags |= BP_WATCHPOINT_HIT;
+            if (!env->watchpoint_hit) {
+                env->watchpoint_hit = wp;
+                tb = tb_find_pc(env->mem_io_pc);
+                if (!tb) {
+                    cpu_abort(env, "check_watchpoint: could not find TB for "
+                              "pc=%p", (void *)env->mem_io_pc);
+                }
+                cpu_restore_state(tb, env, env->mem_io_pc, NULL);
+                tb_phys_invalidate(tb, -1);
+                if (wp->flags & BP_STOP_BEFORE_ACCESS) {
+                    env->exception_index = EXCP_DEBUG;
+                } else {
+                    cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
+                    tb_gen_code(env, pc, cs_base, cpu_flags, 1);
+                }
+                cpu_resume_from_signal(env, NULL);
+            }
+        } else {
+            wp->flags &= ~BP_WATCHPOINT_HIT;
         }
     }
 }
@@ -2413,40 +2780,40 @@
    phys routines.  */
 static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
 {
-    check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
     return ldub_phys(addr);
 }
 
 static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
 {
-    check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
     return lduw_phys(addr);
 }
 
 static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
 {
-    check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
     return ldl_phys(addr);
 }
 
 static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
                              uint32_t val)
 {
-    check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
     stb_phys(addr, val);
 }
 
 static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
                              uint32_t val)
 {
-    check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
     stw_phys(addr, val);
 }
 
 static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
                              uint32_t val)
 {
-    check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
     stl_phys(addr, val);
 }
 
@@ -2468,12 +2835,13 @@
     uint32_t ret;
     unsigned int idx;
 
-    idx = SUBPAGE_IDX(addr - mmio->base);
+    idx = SUBPAGE_IDX(addr);
 #if defined(DEBUG_SUBPAGE)
     printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
            mmio, len, addr, idx);
 #endif
-    ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
+    ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len],
+                                       addr + mmio->region_offset[idx][0][len]);
 
     return ret;
 }
@@ -2483,12 +2851,14 @@
 {
     unsigned int idx;
 
-    idx = SUBPAGE_IDX(addr - mmio->base);
+    idx = SUBPAGE_IDX(addr);
 #if defined(DEBUG_SUBPAGE)
     printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
            mmio, len, addr, idx, value);
 #endif
-    (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
+    (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len],
+                                  addr + mmio->region_offset[idx][1][len],
+                                  value);
 }
 
 static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
@@ -2558,7 +2928,7 @@
 };
 
 static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
-                             ram_addr_t memory)
+                             ram_addr_t memory, ram_addr_t region_offset)
 {
     int idx, eidx;
     unsigned int i;
@@ -2577,10 +2947,12 @@
             if (io_mem_read[memory][i]) {
                 mmio->mem_read[idx][i] = &io_mem_read[memory][i];
                 mmio->opaque[idx][0][i] = io_mem_opaque[memory];
+                mmio->region_offset[idx][0][i] = region_offset;
             }
             if (io_mem_write[memory][i]) {
                 mmio->mem_write[idx][i] = &io_mem_write[memory][i];
                 mmio->opaque[idx][1][i] = io_mem_opaque[memory];
+                mmio->region_offset[idx][1][i] = region_offset;
             }
         }
     }
@@ -2589,60 +2961,59 @@
 }
 
 static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
-                           ram_addr_t orig_memory)
+                           ram_addr_t orig_memory, ram_addr_t region_offset)
 {
     subpage_t *mmio;
     int subpage_memory;
 
     mmio = qemu_mallocz(sizeof(subpage_t));
-    if (mmio != NULL) {
-        mmio->base = base;
-        subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
+
+    mmio->base = base;
+    subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
 #if defined(DEBUG_SUBPAGE)
-        printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
-               mmio, base, TARGET_PAGE_SIZE, subpage_memory);
+    printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
+           mmio, base, TARGET_PAGE_SIZE, subpage_memory);
 #endif
-        *phys = subpage_memory | IO_MEM_SUBPAGE;
-        subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
-    }
+    *phys = subpage_memory | IO_MEM_SUBPAGE;
+    subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory,
+                         region_offset);
 
     return mmio;
 }
 
-static void io_mem_init(void)
+static int get_free_io_mem_idx(void)
 {
-    cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
-    cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
-    cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
-    io_mem_nb = 5;
+    int i;
 
-    io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
-                                          watch_mem_write, NULL);
-    /* alloc dirty bits array */
-    phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
-    memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
+    for (i = 0; i<IO_MEM_NB_ENTRIES; i++)
+        if (!io_mem_used[i]) {
+            io_mem_used[i] = 1;
+            return i;
+        }
+
+    return -1;
 }
 
 /* mem_read and mem_write are arrays of functions containing the
    function to access byte (index 0), word (index 1) and dword (index
-   2). Functions can be omitted with a NULL function pointer. The
-   registered functions may be modified dynamically later.
+   2). Functions can be omitted with a NULL function pointer.
    If io_index is non zero, the corresponding io zone is
    modified. If it is zero, a new io zone is allocated. The return
    value can be used with cpu_register_physical_memory(). (-1) is
    returned if error. */
-int cpu_register_io_memory(int io_index,
-                           CPUReadMemoryFunc **mem_read,
-                           CPUWriteMemoryFunc **mem_write,
-                           void *opaque)
+static int cpu_register_io_memory_fixed(int io_index,
+                                        CPUReadMemoryFunc **mem_read,
+                                        CPUWriteMemoryFunc **mem_write,
+                                        void *opaque)
 {
     int i, subwidth = 0;
 
     if (io_index <= 0) {
-        if (io_mem_nb >= IO_MEM_NB_ENTRIES)
-            return -1;
-        io_index = io_mem_nb++;
+        io_index = get_free_io_mem_idx();
+        if (io_index == -1)
+            return io_index;
     } else {
+        io_index >>= IO_MEM_SHIFT;
         if (io_index >= IO_MEM_NB_ENTRIES)
             return -1;
     }
@@ -2657,14 +3028,45 @@
     return (io_index << IO_MEM_SHIFT) | subwidth;
 }
 
-CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
+int cpu_register_io_memory(CPUReadMemoryFunc **mem_read,
+                           CPUWriteMemoryFunc **mem_write,
+                           void *opaque)
 {
-    return io_mem_write[io_index >> IO_MEM_SHIFT];
+    return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
 }
 
-CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
+void cpu_unregister_io_memory(int io_table_address)
 {
-    return io_mem_read[io_index >> IO_MEM_SHIFT];
+    int i;
+    int io_index = io_table_address >> IO_MEM_SHIFT;
+
+    for (i=0;i < 3; i++) {
+        io_mem_read[io_index][i] = unassigned_mem_read[i];
+        io_mem_write[io_index][i] = unassigned_mem_write[i];
+    }
+    io_mem_opaque[io_index] = NULL;
+    io_mem_used[io_index] = 0;
+}
+
+static void io_mem_init(void)
+{
+    int i;
+
+    cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, unassigned_mem_write, NULL);
+    cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, unassigned_mem_write, NULL);
+    cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, notdirty_mem_write, NULL);
+    for (i=0; i<5; i++)
+        io_mem_used[i] = 1;
+
+    io_mem_watch = cpu_register_io_memory(watch_mem_read,
+                                          watch_mem_write, NULL);
+#ifdef CONFIG_KQEMU
+    if (kqemu_phys_ram_base) {
+        /* alloc dirty bits array */
+        phys_ram_dirty = qemu_vmalloc(kqemu_phys_ram_size >> TARGET_PAGE_BITS);
+        memset(phys_ram_dirty, 0xff, kqemu_phys_ram_size >> TARGET_PAGE_BITS);
+    }
+#endif
 }
 
 #endif /* !defined(CONFIG_USER_ONLY) */
@@ -2736,30 +3138,33 @@
 
         if (is_write) {
             if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+                target_phys_addr_t addr1 = addr;
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+                if (p)
+                    addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
                 /* XXX: could force cpu_single_env to NULL to avoid
                    potential bugs */
-                if (l >= 4 && ((addr & 3) == 0)) {
+                if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit write access */
                     val = ldl_p(buf);
-                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
                     l = 4;
-                } else if (l >= 2 && ((addr & 1) == 0)) {
+                } else if (l >= 2 && ((addr1 & 1) == 0)) {
                     /* 16 bit write access */
                     val = lduw_p(buf);
-                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
+                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
                     l = 2;
                 } else {
                     /* 8 bit write access */
                     val = ldub_p(buf);
-                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
+                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
                     l = 1;
                 }
             } else {
                 unsigned long addr1;
                 addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
                 /* RAM case */
-                ptr = phys_ram_base + addr1;
+                ptr = qemu_get_ram_ptr(addr1);
                 memcpy(ptr, buf, l);
                 if (!cpu_physical_memory_is_dirty(addr1)) {
                     /* invalidate code */
@@ -2772,27 +3177,30 @@
         } else {
             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
                 !(pd & IO_MEM_ROMD)) {
+                target_phys_addr_t addr1 = addr;
                 /* I/O case */
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
-                if (l >= 4 && ((addr & 3) == 0)) {
+                if (p)
+                    addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+                if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit read access */
-                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
                     stl_p(buf, val);
                     l = 4;
-                } else if (l >= 2 && ((addr & 1) == 0)) {
+                } else if (l >= 2 && ((addr1 & 1) == 0)) {
                     /* 16 bit read access */
-                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
+                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
                     stw_p(buf, val);
                     l = 2;
                 } else {
                     /* 8 bit read access */
-                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
+                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
                     stb_p(buf, val);
                     l = 1;
                 }
             } else {
                 /* RAM case */
-                ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+                ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
                     (addr & ~TARGET_PAGE_MASK);
                 memcpy(buf, ptr, l);
             }
@@ -2833,7 +3241,7 @@
             unsigned long addr1;
             addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
             /* ROM/RAM case */
-            ptr = phys_ram_base + addr1;
+            ptr = qemu_get_ram_ptr(addr1);
             memcpy(ptr, buf, l);
         }
         len -= l;
@@ -2842,6 +3250,148 @@
     }
 }
 
+typedef struct {
+    void *buffer;
+    target_phys_addr_t addr;
+    target_phys_addr_t len;
+} BounceBuffer;
+
+static BounceBuffer bounce;
+
+typedef struct MapClient {
+    void *opaque;
+    void (*callback)(void *opaque);
+    LIST_ENTRY(MapClient) link;
+} MapClient;
+
+static LIST_HEAD(map_client_list, MapClient) map_client_list
+    = LIST_HEAD_INITIALIZER(map_client_list);
+
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
+{
+    MapClient *client = qemu_malloc(sizeof(*client));
+
+    client->opaque = opaque;
+    client->callback = callback;
+    LIST_INSERT_HEAD(&map_client_list, client, link);
+    return client;
+}
+
+void cpu_unregister_map_client(void *_client)
+{
+    MapClient *client = (MapClient *)_client;
+
+    LIST_REMOVE(client, link);
+}
+
+static void cpu_notify_map_clients(void)
+{
+    MapClient *client;
+
+    while (!LIST_EMPTY(&map_client_list)) {
+        client = LIST_FIRST(&map_client_list);
+        client->callback(client->opaque);
+        LIST_REMOVE(client, link);
+    }
+}
+
+/* Map a physical memory region into a host virtual address.
+ * May map a subset of the requested range, given by and returned in *plen.
+ * May return NULL if resources needed to perform the mapping are exhausted.
+ * Use only for reads OR writes - not for read-modify-write operations.
+ * Use cpu_register_map_client() to know when retrying the map operation is
+ * likely to succeed.
+ */
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+                              target_phys_addr_t *plen,
+                              int is_write)
+{
+    target_phys_addr_t len = *plen;
+    target_phys_addr_t done = 0;
+    int l;
+    uint8_t *ret = NULL;
+    uint8_t *ptr;
+    target_phys_addr_t page;
+    unsigned long pd;
+    PhysPageDesc *p;
+    unsigned long addr1;
+
+    while (len > 0) {
+        page = addr & TARGET_PAGE_MASK;
+        l = (page + TARGET_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        p = phys_page_find(page >> TARGET_PAGE_BITS);
+        if (!p) {
+            pd = IO_MEM_UNASSIGNED;
+        } else {
+            pd = p->phys_offset;
+        }
+
+        if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+            if (done || bounce.buffer) {
+                break;
+            }
+            bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
+            bounce.addr = addr;
+            bounce.len = l;
+            if (!is_write) {
+                cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
+            }
+            ptr = bounce.buffer;
+        } else {
+            addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+            ptr = qemu_get_ram_ptr(addr1);
+        }
+        if (!done) {
+            ret = ptr;
+        } else if (ret + done != ptr) {
+            break;
+        }
+
+        len -= l;
+        addr += l;
+        done += l;
+    }
+    *plen = done;
+    return ret;
+}
+
+/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
+ * Will also mark the memory as dirty if is_write == 1.  access_len gives
+ * the amount of memory that was actually read or written by the caller.
+ */
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+                               int is_write, target_phys_addr_t access_len)
+{
+    if (buffer != bounce.buffer) {
+        if (is_write) {
+            ram_addr_t addr1 = qemu_ram_addr_from_host(buffer);
+            while (access_len) {
+                unsigned l;
+                l = TARGET_PAGE_SIZE;
+                if (l > access_len)
+                    l = access_len;
+                if (!cpu_physical_memory_is_dirty(addr1)) {
+                    /* invalidate code */
+                    tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
+                    /* set dirty bit */
+                    phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
+                        (0xff & ~CODE_DIRTY_FLAG);
+                }
+                addr1 += l;
+                access_len -= l;
+            }
+        }
+        return;
+    }
+    if (is_write) {
+        cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
+    }
+    qemu_free(bounce.buffer);
+    bounce.buffer = NULL;
+    cpu_notify_map_clients();
+}
 
 /* warning: addr must be aligned */
 uint32_t ldl_phys(target_phys_addr_t addr)
@@ -2863,10 +3413,12 @@
         !(pd & IO_MEM_ROMD)) {
         /* I/O case */
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
         val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
     } else {
         /* RAM case */
-        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+        ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
         val = ldl_p(ptr);
     }
@@ -2893,6 +3445,8 @@
         !(pd & IO_MEM_ROMD)) {
         /* I/O case */
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
 #ifdef TARGET_WORDS_BIGENDIAN
         val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
         val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
@@ -2902,7 +3456,7 @@
 #endif
     } else {
         /* RAM case */
-        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+        ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
         val = ldq_p(ptr);
     }
@@ -2944,11 +3498,23 @@
 
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
     } else {
-        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
-            (addr & ~TARGET_PAGE_MASK);
+        unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+        ptr = qemu_get_ram_ptr(addr1);
         stl_p(ptr, val);
+
+        if (unlikely(in_migration)) {
+            if (!cpu_physical_memory_is_dirty(addr1)) {
+                /* invalidate code */
+                tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
+                /* set dirty bit */
+                phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
+                    (0xff & ~CODE_DIRTY_FLAG);
+            }
+        }
     }
 }
 
@@ -2968,6 +3534,8 @@
 
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
 #ifdef TARGET_WORDS_BIGENDIAN
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
@@ -2976,7 +3544,7 @@
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
 #endif
     } else {
-        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+        ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
         stq_p(ptr, val);
     }
@@ -2999,12 +3567,14 @@
 
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+        if (p)
+            addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
     } else {
         unsigned long addr1;
         addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
         /* RAM case */
-        ptr = phys_ram_base + addr1;
+        ptr = qemu_get_ram_ptr(addr1);
         stl_p(ptr, val);
         if (!cpu_physical_memory_is_dirty(addr1)) {
             /* invalidate code */
@@ -3039,7 +3609,7 @@
 
 #endif
 
-/* virtual memory access for debug */
+/* virtual memory access for debug (includes writing to ROM) */
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write)
 {
@@ -3056,8 +3626,13 @@
         l = (page + TARGET_PAGE_SIZE) - addr;
         if (l > len)
             l = len;
-        cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
-                               buf, l, is_write);
+        phys_addr += (addr & ~TARGET_PAGE_MASK);
+#if !defined(CONFIG_USER_ONLY)
+        if (is_write)
+            cpu_physical_memory_write_rom(phys_addr, buf, l);
+        else
+#endif
+            cpu_physical_memory_rw(phys_addr, buf, l, is_write);
         len -= l;
         buf += l;
         addr += l;
diff --git a/feature_to_c.sh b/feature_to_c.sh
new file mode 100755
index 0000000..bce77b6
--- /dev/null
+++ b/feature_to_c.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+# Convert text files to compilable C arrays.
+#
+# Copyright (C) 2007 Free Software Foundation, Inc.
+#
+# This file is part of GDB.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+output=$1
+shift
+
+if test -z "$output" || test -z "$1"; then
+  echo "Usage: $0 OUTPUTFILE INPUTFILE..."
+  exit 1
+fi
+
+if test -e "$output"; then
+  echo "Output file \"$output\" already exists; refusing to overwrite."
+  exit 1
+fi
+
+for input; do
+  arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'`
+
+  ${AWK:-awk} 'BEGIN { n = 0
+      print "static const char '$arrayname'[] = {"
+      for (i = 0; i < 255; i++)
+        _ord_[sprintf("%c", i)] = i
+    } {
+      split($0, line, "");
+      printf "  "
+      for (i = 1; i <= length($0); i++) {
+        c = line[i]
+        if (c == "'\''") {
+          printf "'\''\\'\'''\'', "
+        } else if (c == "\\") {
+          printf "'\''\\\\'\'', "
+        } else if (_ord_[c] >= 32 && _ord_[c] < 127) {
+	  printf "'\''%s'\'', ", c
+        } else {
+          printf "'\''\\%03o'\'', ", _ord_[c]
+        }
+        if (i % 10 == 0)
+          printf "\n   "
+      }
+      printf "'\''\\n'\'', \n"
+    } END {
+      print "  0 };"
+    }' < $input >> $output
+done
+
+echo >> $output
+echo "extern const char *const xml_builtin[][2];" >> $output
+echo "const char *const xml_builtin[][2] = {" >> $output
+
+for input; do
+  basename=`echo $input | sed 's,.*/,,'`
+  arrayname=xml_feature_`echo $input | sed 's,.*/,,; s/[-.]/_/g'`
+  echo "  { \"$basename\", $arrayname }," >> $output
+done
+
+echo "  { 0, 0 }" >> $output
+echo "};" >> $output
diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h
index 2c8f18b..7838228 100644
--- a/fpu/softfloat-macros.h
+++ b/fpu/softfloat-macros.h
@@ -590,12 +590,12 @@
 
     index = ( a>>27 ) & 15;
     if ( aExp & 1 ) {
-        z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
+        z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ (int)index ];
         z = ( ( a / z )<<14 ) + ( z<<15 );
         a >>= 1;
     }
     else {
-        z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
+        z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ (int)index ];
         z = a / z + z;
         z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
         if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
@@ -717,4 +717,3 @@
     return ( a0 != b0 ) || ( a1 != b1 );
 
 }
-
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index e58551f..2af07a3 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -2,11 +2,15 @@
    context is supported */
 #include "softfloat.h"
 #include <math.h>
+#if defined(HOST_SOLARIS)
+#include <fenv.h>
+#endif
 
 void set_float_rounding_mode(int val STATUS_PARAM)
 {
     STATUS(float_rounding_mode) = val;
-#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
+#if defined(HOST_BSD) && !defined(__APPLE__) ||         \
+    (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
     fpsetround(val);
 #elif defined(__arm__)
     /* nothing to do */
@@ -22,7 +26,7 @@
 }
 #endif
 
-#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
+#if defined(HOST_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
 #define lrint(d)		((int32_t)rint(d))
 #define llrint(d)		((int64_t)rint(d))
 #define lrintf(f)		((int32_t)rint(f))
@@ -51,10 +55,10 @@
 #endif
 #endif
 
-#if defined(__powerpc__)
+#if defined(_ARCH_PPC)
 
 /* correct (but slow) PowerPC rint() (glibc version is incorrect) */
-double qemu_rint(double x)
+static double qemu_rint(double x)
 {
     double y = 4503599627370496.0;
     if (fabs(x) >= y)
@@ -220,25 +224,25 @@
 int float32_compare( float32 a, float32 b STATUS_PARAM )
 {
     if (a < b) {
-        return -1;
+        return float_relation_less;
     } else if (a == b) {
-        return 0;
+        return float_relation_equal;
     } else if (a > b) {
-        return 1;
+        return float_relation_greater;
     } else {
-        return 2;
+        return float_relation_unordered;
     }
 }
 int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
 {
     if (isless(a, b)) {
-        return -1;
+        return float_relation_less;
     } else if (a == b) {
-        return 0;
+        return float_relation_equal;
     } else if (isgreater(a, b)) {
-        return 1;
+        return float_relation_greater;
     } else {
-        return 2;
+        return float_relation_unordered;
     }
 }
 int float32_is_signaling_nan( float32 a1)
@@ -250,6 +254,15 @@
     return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
 }
 
+int float32_is_nan( float32 a1 )
+{
+    float32u u;
+    uint64_t a;
+    u.f = a1;
+    a = u.i;
+    return ( 0xFF800000 < ( a<<1 ) );
+}
+
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE double-precision conversion routines.
 *----------------------------------------------------------------------------*/
@@ -382,25 +395,25 @@
 int float64_compare( float64 a, float64 b STATUS_PARAM )
 {
     if (a < b) {
-        return -1;
+        return float_relation_less;
     } else if (a == b) {
-        return 0;
+        return float_relation_equal;
     } else if (a > b) {
-        return 1;
+        return float_relation_greater;
     } else {
-        return 2;
+        return float_relation_unordered;
     }
 }
 int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
 {
     if (isless(a, b)) {
-        return -1;
+        return float_relation_less;
     } else if (a == b) {
-        return 0;
+        return float_relation_equal;
     } else if (isgreater(a, b)) {
-        return 1;
+        return float_relation_greater;
     } else {
-        return 2;
+        return float_relation_unordered;
     }
 }
 int float64_is_signaling_nan( float64 a1)
@@ -422,7 +435,7 @@
     u.f = a1;
     a = u.i;
 
-    return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
+    return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) );
 
 }
 
@@ -474,30 +487,43 @@
 int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
 {
     if (a < b) {
-        return -1;
+        return float_relation_less;
     } else if (a == b) {
-        return 0;
+        return float_relation_equal;
     } else if (a > b) {
-        return 1;
+        return float_relation_greater;
     } else {
-        return 2;
+        return float_relation_unordered;
     }
 }
 int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
 {
     if (isless(a, b)) {
-        return -1;
+        return float_relation_less;
     } else if (a == b) {
-        return 0;
+        return float_relation_equal;
     } else if (isgreater(a, b)) {
-        return 1;
+        return float_relation_greater;
     } else {
-        return 2;
+        return float_relation_unordered;
     }
 }
 int floatx80_is_signaling_nan( floatx80 a1)
 {
     floatx80u u;
+    uint64_t aLow;
+    u.f = a1;
+
+    aLow = u.i.low & ~ LIT64( 0x4000000000000000 );
+    return
+           ( ( u.i.high & 0x7FFF ) == 0x7FFF )
+        && (bits64) ( aLow<<1 )
+        && ( u.i.low == aLow );
+}
+
+int floatx80_is_nan( floatx80 a1 )
+{
+    floatx80u u;
     u.f = a1;
     return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 );
 }
diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h
index 379d49d..a28c769 100644
--- a/fpu/softfloat-native.h
+++ b/fpu/softfloat-native.h
@@ -1,15 +1,14 @@
 /* Native implementation of soft float functions */
 #include <math.h>
 
-#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
+#if (defined(HOST_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
 #include <ieeefp.h>
 #define fabsf(f) ((float)fabs(f))
 #else
 #include <fenv.h>
 #endif
 
-#ifdef __OpenBSD__
-/* Get OpenBSD version number */
+#if defined(__OpenBSD__) || defined(__NetBSD__)
 #include <sys/param.h>
 #endif
 
@@ -21,7 +20,7 @@
  *   are defined in <iso/math_c99.h> with a compiler directive
  */
 #if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) \
-                                                        && (__GNUC__ <= 4))) \
+                                                        && (__GNUC__ < 4))) \
     || (defined(__OpenBSD__) && (OpenBSD < 200811))
 /*
  * C99 7.12.3 classification macros
@@ -35,6 +34,25 @@
 #define unordered(x, y) (isnan(x) || isnan(y))
 #endif
 
+#ifdef __NetBSD__
+#ifndef isgreater
+#define isgreater(x, y)		__builtin_isgreater(x, y)
+#endif
+#ifndef isgreaterequal
+#define isgreaterequal(x, y)	__builtin_isgreaterequal(x, y)
+#endif
+#ifndef isless
+#define isless(x, y)		__builtin_isless(x, y)
+#endif
+#ifndef islessequal
+#define islessequal(x, y)	__builtin_islessequal(x, y)
+#endif
+#ifndef isunordered
+#define isunordered(x, y)	__builtin_isunordered(x, y)
+#endif
+#endif
+
+
 #define isnormal(x)             (fpclass(x) >= FP_NZERO)
 #define isgreater(x, y)         ((!unordered(x, y)) && ((x) > (y)))
 #define isgreaterequal(x, y)    ((!unordered(x, y)) && ((x) >= (y)))
@@ -93,7 +111,7 @@
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE floating-point rounding mode.
 *----------------------------------------------------------------------------*/
-#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
+#if (defined(HOST_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
 #if defined(__OpenBSD__)
 #define FE_RM FP_RM
 #define FE_RP FP_RP
@@ -122,9 +140,9 @@
 #endif
 
 typedef struct float_status {
-    signed char float_rounding_mode;
+    int float_rounding_mode;
 #ifdef FLOATX80
-    signed char floatx80_rounding_precision;
+    int floatx80_rounding_precision;
 #endif
 } float_status;
 
@@ -228,6 +246,7 @@
 int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
 int float32_is_signaling_nan( float32 );
+int float32_is_nan( float32 );
 
 INLINE float32 float32_abs(float32 a)
 {
@@ -239,6 +258,23 @@
     return -a;
 }
 
+INLINE float32 float32_is_infinity(float32 a)
+{
+    return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE float32 float32_is_neg(float32 a)
+{
+    float32u u;
+    u.f = a;
+    return u.i >> 31;
+}
+
+INLINE float32 float32_is_zero(float32 a)
+{
+    return fpclassify(a) == FP_ZERO;
+}
+
 INLINE float32 float32_scalbn(float32 a, int n)
 {
     return scalbnf(a, n);
@@ -331,6 +367,23 @@
     return -a;
 }
 
+INLINE float64 float64_is_infinity(float64 a)
+{
+    return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE float64 float64_is_neg(float64 a)
+{
+    float64u u;
+    u.f = a;
+    return u.i >> 63;
+}
+
+INLINE float64 float64_is_zero(float64 a)
+{
+    return fpclassify(a) == FP_ZERO;
+}
+
 INLINE float64 float64_scalbn(float64 a, int n)
 {
     return scalbn(a, n);
@@ -406,6 +459,7 @@
 int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
 int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_is_signaling_nan( floatx80 );
+int floatx80_is_nan( floatx80 );
 
 INLINE floatx80 floatx80_abs(floatx80 a)
 {
@@ -417,6 +471,23 @@
     return -a;
 }
 
+INLINE floatx80 floatx80_is_infinity(floatx80 a)
+{
+    return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE floatx80 floatx80_is_neg(floatx80 a)
+{
+    floatx80u u;
+    u.f = a;
+    return u.i.high >> 15;
+}
+
+INLINE floatx80 floatx80_is_zero(floatx80 a)
+{
+    return fpclassify(a) == FP_ZERO;
+}
+
 INLINE floatx80 floatx80_scalbn(floatx80 a, int n)
 {
     return scalbnl(a, n);
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 93fe06e..f607e19 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -37,12 +37,6 @@
 #endif
 
 /*----------------------------------------------------------------------------
-| Underflow tininess-detection mode, statically initialized to default value.
-| (The declaration in `softfloat.h' must match the `int8' type here.)
-*----------------------------------------------------------------------------*/
-int8 float_detect_tininess = float_tininess_after_rounding;
-
-/*----------------------------------------------------------------------------
 | Raises the exceptions specified by `flags'.  Floating-point traps can be
 | defined here if desired.  It is currently not possible for such a trap
 | to substitute a result value.  If traps are not implemented, this routine
@@ -67,7 +61,7 @@
 *----------------------------------------------------------------------------*/
 #if defined(TARGET_SPARC)
 #define float32_default_nan make_float32(0x7FFFFFFF)
-#elif defined(TARGET_POWERPC)
+#elif defined(TARGET_POWERPC) || defined(TARGET_ARM)
 #define float32_default_nan make_float32(0x7FC00000)
 #elif defined(TARGET_HPPA)
 #define float32_default_nan make_float32(0x7FA00000)
@@ -150,6 +144,9 @@
     flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
     bits32 av, bv, res;
 
+    if ( STATUS(default_nan_mode) )
+        return float32_default_nan;
+
     aIsNaN = float32_is_nan( a );
     aIsSignalingNaN = float32_is_signaling_nan( a );
     bIsNaN = float32_is_nan( b );
@@ -169,7 +166,7 @@
         res = bIsNaN ? bv : av;
     }
     else if ( aIsNaN ) {
-        if ( bIsSignalingNaN | ! bIsNaN )
+        if ( bIsSignalingNaN || ! bIsNaN )
             res = av;
         else {
  returnLargerSignificand:
@@ -192,7 +189,7 @@
 *----------------------------------------------------------------------------*/
 #if defined(TARGET_SPARC)
 #define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
-#elif defined(TARGET_POWERPC)
+#elif defined(TARGET_POWERPC) || defined(TARGET_ARM)
 #define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
 #elif defined(TARGET_HPPA)
 #define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 ))
@@ -282,6 +279,9 @@
     flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
     bits64 av, bv, res;
 
+    if ( STATUS(default_nan_mode) )
+        return float64_default_nan;
+
     aIsNaN = float64_is_nan( a );
     aIsSignalingNaN = float64_is_signaling_nan( a );
     bIsNaN = float64_is_nan( b );
@@ -301,7 +301,7 @@
         res = bIsNaN ? bv : av;
     }
     else if ( aIsNaN ) {
-        if ( bIsSignalingNaN | ! bIsNaN )
+        if ( bIsSignalingNaN || ! bIsNaN )
             res = av;
         else {
  returnLargerSignificand:
@@ -418,6 +418,12 @@
 {
     flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
 
+    if ( STATUS(default_nan_mode) ) {
+        a.low = floatx80_default_nan_low;
+        a.high = floatx80_default_nan_high;
+        return a;
+    }
+
     aIsNaN = floatx80_is_nan( a );
     aIsSignalingNaN = floatx80_is_signaling_nan( a );
     bIsNaN = floatx80_is_nan( b );
@@ -435,7 +441,7 @@
         return bIsNaN ? b : a;
     }
     else if ( aIsNaN ) {
-        if ( bIsSignalingNaN | ! bIsNaN ) return a;
+        if ( bIsSignalingNaN || ! bIsNaN ) return a;
  returnLargerSignificand:
         if ( a.low < b.low ) return b;
         if ( b.low < a.low ) return a;
@@ -538,6 +544,12 @@
 {
     flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
 
+    if ( STATUS(default_nan_mode) ) {
+        a.low = float128_default_nan_low;
+        a.high = float128_default_nan_high;
+        return a;
+    }
+
     aIsNaN = float128_is_nan( a );
     aIsSignalingNaN = float128_is_signaling_nan( a );
     bIsNaN = float128_is_nan( b );
@@ -555,7 +567,7 @@
         return bIsNaN ? b : a;
     }
     else if ( aIsNaN ) {
-        if ( bIsSignalingNaN | ! bIsNaN ) return a;
+        if ( bIsSignalingNaN || ! bIsNaN ) return a;
  returnLargerSignificand:
         if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
         if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 3ec1e0d..4d58744 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -30,6 +30,8 @@
 
 =============================================================================*/
 
+/* FIXME: Flush-To-Zero only effects results.  Denormal inputs should also
+   be flushed to zero.  */
 #include "softfloat.h"
 
 /*----------------------------------------------------------------------------
@@ -294,6 +296,7 @@
             return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
         }
         if ( zExp < 0 ) {
+            if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -457,6 +460,7 @@
             return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
         }
         if ( zExp < 0 ) {
+            if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -635,6 +639,7 @@
             goto overflow;
         }
         if ( zExp <= 0 ) {
+            if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 );
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < 0 )
@@ -965,6 +970,7 @@
             return packFloat128( zSign, 0x7FFF, 0, 0 );
         }
         if ( zExp < 0 ) {
+            if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -1637,7 +1643,10 @@
             if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
             return a;
         }
-        if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+        if ( aExp == 0 ) {
+            if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
+            return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+        }
         zSig = 0x40000000 + aSig + bSig;
         zExp = aExp;
         goto roundAndPack;
@@ -2048,6 +2057,53 @@
 }
 
 /*----------------------------------------------------------------------------
+| Returns the binary log of the single-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float32 float32_log2( float32 a STATUS_PARAM )
+{
+    flag aSign, zSign;
+    int16 aExp;
+    bits32 aSig, zSig, i;
+
+    aSig = extractFloat32Frac( a );
+    aExp = extractFloat32Exp( a );
+    aSign = extractFloat32Sign( a );
+
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat32( 1, 0xFF, 0 );
+        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( aSign ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float32_default_nan;
+    }
+    if ( aExp == 0xFF ) {
+        if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR );
+        return a;
+    }
+
+    aExp -= 0x7F;
+    aSig |= 0x00800000;
+    zSign = aExp < 0;
+    zSig = aExp << 23;
+
+    for (i = 1 << 22; i > 0; i >>= 1) {
+        aSig = ( (bits64)aSig * aSig ) >> 23;
+        if ( aSig & 0x01000000 ) {
+            aSig >>= 1;
+            zSig |= i;
+        }
+    }
+
+    if ( zSign )
+        zSig = -zSig;
+
+    return normalizeRoundAndPackFloat32( zSign, 0x85, zSig STATUS_VAR );
+}
+
+/*----------------------------------------------------------------------------
 | Returns 1 if the single-precision floating-point value `a' is equal to
 | the corresponding value `b', and 0 otherwise.  The comparison is performed
 | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
@@ -2595,7 +2651,10 @@
             if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
             return a;
         }
-        if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+        if ( aExp == 0 ) {
+            if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
+            return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+        }
         zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
         zExp = aExp;
         goto roundAndPack;
@@ -2994,6 +3053,52 @@
 }
 
 /*----------------------------------------------------------------------------
+| Returns the binary log of the double-precision floating-point value `a'.
+| The operation is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float64 float64_log2( float64 a STATUS_PARAM )
+{
+    flag aSign, zSign;
+    int16 aExp;
+    bits64 aSig, aSig0, aSig1, zSig, i;
+
+    aSig = extractFloat64Frac( a );
+    aExp = extractFloat64Exp( a );
+    aSign = extractFloat64Sign( a );
+
+    if ( aExp == 0 ) {
+        if ( aSig == 0 ) return packFloat64( 1, 0x7FF, 0 );
+        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
+    }
+    if ( aSign ) {
+        float_raise( float_flag_invalid STATUS_VAR);
+        return float64_default_nan;
+    }
+    if ( aExp == 0x7FF ) {
+        if ( aSig ) return propagateFloat64NaN( a, float64_zero STATUS_VAR );
+        return a;
+    }
+
+    aExp -= 0x3FF;
+    aSig |= LIT64( 0x0010000000000000 );
+    zSign = aExp < 0;
+    zSig = (bits64)aExp << 52;
+    for (i = 1LL << 51; i > 0; i >>= 1) {
+        mul64To128( aSig, aSig, &aSig0, &aSig1 );
+        aSig = ( aSig0 << 12 ) | ( aSig1 >> 52 );
+        if ( aSig & LIT64( 0x0020000000000000 ) ) {
+            aSig >>= 1;
+            zSig |= i;
+        }
+    }
+
+    if ( zSign )
+        zSig = -zSig;
+    return normalizeRoundAndPackFloat64( zSign, 0x408, zSig STATUS_VAR );
+}
+
+/*----------------------------------------------------------------------------
 | Returns 1 if the double-precision floating-point value `a' is equal to the
 | corresponding value `b', and 0 otherwise.  The comparison is performed
 | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
@@ -4597,7 +4702,10 @@
             return a;
         }
         add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
-        if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
+        if ( aExp == 0 ) {
+            if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
+            return packFloat128( zSign, 0, zSig0, zSig1 );
+        }
         zSig2 = 0;
         zSig0 |= LIT64( 0x0002000000000000 );
         zExp = aExp;
@@ -4987,7 +5095,7 @@
         sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
     } while ( 0 <= (sbits64) aSig0 );
     add128(
-        aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
+        aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 );
     if (    ( sigMean0 < 0 )
          || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
         aSig0 = alternateASig0;
@@ -5479,8 +5587,14 @@
     if ( aExp == 0xFF ) {
         return a;
     }
-    aExp += n;
-    return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
+    if ( aExp != 0 )
+        aSig |= 0x00800000;
+    else if ( aSig == 0 )
+        return a;
+
+    aExp += n - 1;
+    aSig <<= 7;
+    return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
 }
 
 float64 float64_scalbn( float64 a, int n STATUS_PARAM )
@@ -5496,8 +5610,14 @@
     if ( aExp == 0x7FF ) {
         return a;
     }
-    aExp += n;
-    return roundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
+    if ( aExp != 0 )
+        aSig |= LIT64( 0x0010000000000000 );
+    else if ( aSig == 0 )
+        return a;
+
+    aExp += n - 1;
+    aSig <<= 10;
+    return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
 }
 
 #ifdef FLOATX80
@@ -5514,9 +5634,12 @@
     if ( aExp == 0x7FF ) {
         return a;
     }
+    if (aExp == 0 && aSig == 0)
+        return a;
+
     aExp += n;
-    return roundAndPackFloatx80( STATUS(floatx80_rounding_precision),
-                                 aSign, aExp, aSig, 0 STATUS_VAR );
+    return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision),
+                                          aSign, aExp, aSig, 0 STATUS_VAR );
 }
 #endif
 
@@ -5534,8 +5657,14 @@
     if ( aExp == 0x7FFF ) {
         return a;
     }
-    aExp += n;
-    return roundAndPackFloat128( aSign, aExp, aSig0, aSig1, 0 STATUS_VAR );
+    if ( aExp != 0 )
+        aSig0 |= LIT64( 0x0001000000000000 );
+    else if ( aSig0 == 0 && aSig1 == 0 )
+        return a;
+
+    aExp += n - 1;
+    return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1
+                                          STATUS_VAR );
 
 }
 #endif
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 5f95d06..850a01f 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -50,8 +50,10 @@
 typedef uint8_t flag;
 typedef uint8_t uint8;
 typedef int8_t int8;
+#ifndef _AIX
 typedef int uint16;
 typedef int int16;
+#endif
 typedef unsigned int uint32;
 typedef signed int int32;
 typedef uint64_t uint64;
@@ -88,7 +90,7 @@
 #define FLOAT128
 #else
 /* native float support */
-#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD)
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(HOST_BSD)
 #define FLOATX80
 #endif
 #endif /* !CONFIG_SOFTFLOAT */
@@ -188,10 +190,20 @@
 #ifdef FLOATX80
     signed char floatx80_rounding_precision;
 #endif
+    flag flush_to_zero;
+    flag default_nan_mode;
 } float_status;
 
 void set_float_rounding_mode(int val STATUS_PARAM);
 void set_float_exception_flags(int val STATUS_PARAM);
+INLINE void set_flush_to_zero(flag val STATUS_PARAM)
+{
+    STATUS(flush_to_zero) = val;
+}
+INLINE void set_default_nan_mode(flag val STATUS_PARAM)
+{
+    STATUS(default_nan_mode) = val;
+}
 INLINE int get_float_exception_flags(float_status *status)
 {
     return STATUS(float_exception_flags);
@@ -257,6 +269,7 @@
 float32 float32_div( float32, float32 STATUS_PARAM );
 float32 float32_rem( float32, float32 STATUS_PARAM );
 float32 float32_sqrt( float32 STATUS_PARAM );
+float32 float32_log2( float32 STATUS_PARAM );
 int float32_eq( float32, float32 STATUS_PARAM );
 int float32_le( float32, float32 STATUS_PARAM );
 int float32_lt( float32, float32 STATUS_PARAM );
@@ -279,7 +292,23 @@
     return make_float32(float32_val(a) ^ 0x80000000);
 }
 
+INLINE int float32_is_infinity(float32 a)
+{
+    return (float32_val(a) & 0x7fffffff) == 0x7f800000;
+}
+
+INLINE int float32_is_neg(float32 a)
+{
+    return float32_val(a) >> 31;
+}
+
+INLINE int float32_is_zero(float32 a)
+{
+    return (float32_val(a) & 0x7fffffff) == 0;
+}
+
 #define float32_zero make_float32(0)
+#define float32_one make_float32(0x3f800000)
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE double-precision conversion routines.
@@ -311,6 +340,7 @@
 float64 float64_div( float64, float64 STATUS_PARAM );
 float64 float64_rem( float64, float64 STATUS_PARAM );
 float64 float64_sqrt( float64 STATUS_PARAM );
+float64 float64_log2( float64 STATUS_PARAM );
 int float64_eq( float64, float64 STATUS_PARAM );
 int float64_le( float64, float64 STATUS_PARAM );
 int float64_lt( float64, float64 STATUS_PARAM );
@@ -333,7 +363,23 @@
     return make_float64(float64_val(a) ^ 0x8000000000000000LL);
 }
 
+INLINE int float64_is_infinity(float64 a)
+{
+    return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL;
+}
+
+INLINE int float64_is_neg(float64 a)
+{
+    return float64_val(a) >> 63;
+}
+
+INLINE int float64_is_zero(float64 a)
+{
+    return (float64_val(a) & 0x7fffffffffffffffLL) == 0;
+}
+
 #define float64_zero make_float64(0)
+#define float64_one make_float64(0x3ff0000000000000LL)
 
 #ifdef FLOATX80
 
@@ -382,6 +428,21 @@
     return a;
 }
 
+INLINE int floatx80_is_infinity(floatx80 a)
+{
+    return (a.high & 0x7fff) == 0x7fff && a.low == 0;
+}
+
+INLINE int floatx80_is_neg(floatx80 a)
+{
+    return a.high >> 15;
+}
+
+INLINE int floatx80_is_zero(floatx80 a)
+{
+    return (a.high & 0x7fff) == 0 && a.low == 0;
+}
+
 #endif
 
 #ifdef FLOAT128
@@ -433,6 +494,21 @@
     return a;
 }
 
+INLINE int float128_is_infinity(float128 a)
+{
+    return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0;
+}
+
+INLINE int float128_is_neg(float128 a)
+{
+    return a.high >> 63;
+}
+
+INLINE int float128_is_zero(float128 a)
+{
+    return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
+}
+
 #endif
 
 #else /* CONFIG_SOFTFLOAT */
diff --git a/gdb-xml/arm-core.xml b/gdb-xml/arm-core.xml
new file mode 100644
index 0000000..6012f34
--- /dev/null
+++ b/gdb-xml/arm-core.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.core">
+  <reg name="r0" bitsize="32"/>
+  <reg name="r1" bitsize="32"/>
+  <reg name="r2" bitsize="32"/>
+  <reg name="r3" bitsize="32"/>
+  <reg name="r4" bitsize="32"/>
+  <reg name="r5" bitsize="32"/>
+  <reg name="r6" bitsize="32"/>
+  <reg name="r7" bitsize="32"/>
+  <reg name="r8" bitsize="32"/>
+  <reg name="r9" bitsize="32"/>
+  <reg name="r10" bitsize="32"/>
+  <reg name="r11" bitsize="32"/>
+  <reg name="r12" bitsize="32"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+  <reg name="lr" bitsize="32"/>
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+
+  <!-- The CPSR is register 25, rather than register 16, because
+       the FPA registers historically were placed between the PC
+       and the CPSR in the "g" packet.  -->
+  <reg name="cpsr" bitsize="32" regnum="25"/>
+</feature>
diff --git a/gdb-xml/arm-neon.xml b/gdb-xml/arm-neon.xml
new file mode 100644
index 0000000..ce3ee03
--- /dev/null
+++ b/gdb-xml/arm-neon.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <vector id="neon_uint8x8" type="uint8" count="8"/>
+  <vector id="neon_uint16x4" type="uint16" count="4"/>
+  <vector id="neon_uint32x2" type="uint32" count="2"/>
+  <vector id="neon_float32x2" type="ieee_single" count="2"/>
+  <union id="neon_d">
+    <field name="u8" type="neon_uint8x8"/>
+    <field name="u16" type="neon_uint16x4"/>
+    <field name="u32" type="neon_uint32x2"/>
+    <field name="u64" type="uint64"/>
+    <field name="f32" type="neon_float32x2"/>
+    <field name="f64" type="ieee_double"/>
+  </union>
+  <vector id="neon_uint8x16" type="uint8" count="16"/>
+  <vector id="neon_uint16x8" type="uint16" count="8"/>
+  <vector id="neon_uint32x4" type="uint32" count="4"/>
+  <vector id="neon_uint64x2" type="uint64" count="2"/>
+  <vector id="neon_float32x4" type="ieee_single" count="4"/>
+  <vector id="neon_float64x2" type="ieee_double" count="2"/>
+  <union id="neon_q">
+    <field name="u8" type="neon_uint8x16"/>
+    <field name="u16" type="neon_uint16x8"/>
+    <field name="u32" type="neon_uint32x4"/>
+    <field name="u64" type="neon_uint64x2"/>
+    <field name="f32" type="neon_float32x4"/>
+    <field name="f64" type="neon_float64x2"/>
+  </union>
+  <reg name="d0" bitsize="64" type="neon_d"/>
+  <reg name="d1" bitsize="64" type="neon_d"/>
+  <reg name="d2" bitsize="64" type="neon_d"/>
+  <reg name="d3" bitsize="64" type="neon_d"/>
+  <reg name="d4" bitsize="64" type="neon_d"/>
+  <reg name="d5" bitsize="64" type="neon_d"/>
+  <reg name="d6" bitsize="64" type="neon_d"/>
+  <reg name="d7" bitsize="64" type="neon_d"/>
+  <reg name="d8" bitsize="64" type="neon_d"/>
+  <reg name="d9" bitsize="64" type="neon_d"/>
+  <reg name="d10" bitsize="64" type="neon_d"/>
+  <reg name="d11" bitsize="64" type="neon_d"/>
+  <reg name="d12" bitsize="64" type="neon_d"/>
+  <reg name="d13" bitsize="64" type="neon_d"/>
+  <reg name="d14" bitsize="64" type="neon_d"/>
+  <reg name="d15" bitsize="64" type="neon_d"/>
+  <reg name="d16" bitsize="64" type="neon_d"/>
+  <reg name="d17" bitsize="64" type="neon_d"/>
+  <reg name="d18" bitsize="64" type="neon_d"/>
+  <reg name="d19" bitsize="64" type="neon_d"/>
+  <reg name="d20" bitsize="64" type="neon_d"/>
+  <reg name="d21" bitsize="64" type="neon_d"/>
+  <reg name="d22" bitsize="64" type="neon_d"/>
+  <reg name="d23" bitsize="64" type="neon_d"/>
+  <reg name="d24" bitsize="64" type="neon_d"/>
+  <reg name="d25" bitsize="64" type="neon_d"/>
+  <reg name="d26" bitsize="64" type="neon_d"/>
+  <reg name="d27" bitsize="64" type="neon_d"/>
+  <reg name="d28" bitsize="64" type="neon_d"/>
+  <reg name="d29" bitsize="64" type="neon_d"/>
+  <reg name="d30" bitsize="64" type="neon_d"/>
+  <reg name="d31" bitsize="64" type="neon_d"/>
+
+  <reg name="q0" bitsize="128" type="neon_q"/>
+  <reg name="q1" bitsize="128" type="neon_q"/>
+  <reg name="q2" bitsize="128" type="neon_q"/>
+  <reg name="q3" bitsize="128" type="neon_q"/>
+  <reg name="q4" bitsize="128" type="neon_q"/>
+  <reg name="q5" bitsize="128" type="neon_q"/>
+  <reg name="q6" bitsize="128" type="neon_q"/>
+  <reg name="q7" bitsize="128" type="neon_q"/>
+  <reg name="q8" bitsize="128" type="neon_q"/>
+  <reg name="q9" bitsize="128" type="neon_q"/>
+  <reg name="q10" bitsize="128" type="neon_q"/>
+  <reg name="q10" bitsize="128" type="neon_q"/>
+  <reg name="q12" bitsize="128" type="neon_q"/>
+  <reg name="q13" bitsize="128" type="neon_q"/>
+  <reg name="q14" bitsize="128" type="neon_q"/>
+  <reg name="q15" bitsize="128" type="neon_q"/>
+
+  <reg name="fpsid" bitsize="32" type="int" group="float"/>
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+  <reg name="fpexc" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/gdb-xml/arm-vfp.xml b/gdb-xml/arm-vfp.xml
new file mode 100644
index 0000000..b20881e
--- /dev/null
+++ b/gdb-xml/arm-vfp.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <reg name="d0" bitsize="64" type="float"/>
+  <reg name="d1" bitsize="64" type="float"/>
+  <reg name="d2" bitsize="64" type="float"/>
+  <reg name="d3" bitsize="64" type="float"/>
+  <reg name="d4" bitsize="64" type="float"/>
+  <reg name="d5" bitsize="64" type="float"/>
+  <reg name="d6" bitsize="64" type="float"/>
+  <reg name="d7" bitsize="64" type="float"/>
+  <reg name="d8" bitsize="64" type="float"/>
+  <reg name="d9" bitsize="64" type="float"/>
+  <reg name="d10" bitsize="64" type="float"/>
+  <reg name="d11" bitsize="64" type="float"/>
+  <reg name="d12" bitsize="64" type="float"/>
+  <reg name="d13" bitsize="64" type="float"/>
+  <reg name="d14" bitsize="64" type="float"/>
+  <reg name="d15" bitsize="64" type="float"/>
+
+  <reg name="fpsid" bitsize="32" type="int" group="float"/>
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+  <reg name="fpexc" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/gdb-xml/arm-vfp3.xml b/gdb-xml/arm-vfp3.xml
new file mode 100644
index 0000000..227afd8
--- /dev/null
+++ b/gdb-xml/arm-vfp3.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+  <reg name="d0" bitsize="64" type="float"/>
+  <reg name="d1" bitsize="64" type="float"/>
+  <reg name="d2" bitsize="64" type="float"/>
+  <reg name="d3" bitsize="64" type="float"/>
+  <reg name="d4" bitsize="64" type="float"/>
+  <reg name="d5" bitsize="64" type="float"/>
+  <reg name="d6" bitsize="64" type="float"/>
+  <reg name="d7" bitsize="64" type="float"/>
+  <reg name="d8" bitsize="64" type="float"/>
+  <reg name="d9" bitsize="64" type="float"/>
+  <reg name="d10" bitsize="64" type="float"/>
+  <reg name="d11" bitsize="64" type="float"/>
+  <reg name="d12" bitsize="64" type="float"/>
+  <reg name="d13" bitsize="64" type="float"/>
+  <reg name="d14" bitsize="64" type="float"/>
+  <reg name="d15" bitsize="64" type="float"/>
+  <reg name="d16" bitsize="64" type="float"/>
+  <reg name="d17" bitsize="64" type="float"/>
+  <reg name="d18" bitsize="64" type="float"/>
+  <reg name="d19" bitsize="64" type="float"/>
+  <reg name="d20" bitsize="64" type="float"/>
+  <reg name="d21" bitsize="64" type="float"/>
+  <reg name="d22" bitsize="64" type="float"/>
+  <reg name="d23" bitsize="64" type="float"/>
+  <reg name="d24" bitsize="64" type="float"/>
+  <reg name="d25" bitsize="64" type="float"/>
+  <reg name="d26" bitsize="64" type="float"/>
+  <reg name="d27" bitsize="64" type="float"/>
+  <reg name="d28" bitsize="64" type="float"/>
+  <reg name="d29" bitsize="64" type="float"/>
+  <reg name="d30" bitsize="64" type="float"/>
+  <reg name="d31" bitsize="64" type="float"/>
+
+  <reg name="fpsid" bitsize="32" type="int" group="float"/>
+  <reg name="fpscr" bitsize="32" type="int" group="float"/>
+  <reg name="fpexc" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/gdb-xml/cf-core.xml b/gdb-xml/cf-core.xml
new file mode 100644
index 0000000..b90af30
--- /dev/null
+++ b/gdb-xml/cf-core.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.coldfire.core">
+  <reg name="d0" bitsize="32"/>
+  <reg name="d1" bitsize="32"/>
+  <reg name="d2" bitsize="32"/>
+  <reg name="d3" bitsize="32"/>
+  <reg name="d4" bitsize="32"/>
+  <reg name="d5" bitsize="32"/>
+  <reg name="d6" bitsize="32"/>
+  <reg name="d7" bitsize="32"/>
+  <reg name="a0" bitsize="32" type="data_ptr"/>
+  <reg name="a1" bitsize="32" type="data_ptr"/>
+  <reg name="a2" bitsize="32" type="data_ptr"/>
+  <reg name="a3" bitsize="32" type="data_ptr"/>
+  <reg name="a4" bitsize="32" type="data_ptr"/>
+  <reg name="a5" bitsize="32" type="data_ptr"/>
+  <reg name="fp" bitsize="32" type="data_ptr"/>
+  <reg name="sp" bitsize="32" type="data_ptr"/>
+
+  <reg name="ps" bitsize="32"/>
+  <reg name="pc" bitsize="32" type="code_ptr"/>
+
+</feature>
diff --git a/gdb-xml/cf-fp.xml b/gdb-xml/cf-fp.xml
new file mode 100644
index 0000000..bf71c32
--- /dev/null
+++ b/gdb-xml/cf-fp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.coldfire.fp">
+  <reg name="fp0" bitsize="64" type="float" group="float"/>
+  <reg name="fp1" bitsize="64" type="float" group="float"/>
+  <reg name="fp2" bitsize="64" type="float" group="float"/>
+  <reg name="fp3" bitsize="64" type="float" group="float"/>
+  <reg name="fp4" bitsize="64" type="float" group="float"/>
+  <reg name="fp5" bitsize="64" type="float" group="float"/>
+  <reg name="fp6" bitsize="64" type="float" group="float"/>
+  <reg name="fp7" bitsize="64" type="float" group="float"/>
+
+  
+  <reg name="fpcontrol" bitsize="32" group="float"/>
+  <reg name="fpstatus" bitsize="32" group="float"/>,
+  <reg name="fpiaddr" bitsize="32" type="code_ptr" group="float"/>
+</feature>
diff --git a/gdb-xml/power-altivec.xml b/gdb-xml/power-altivec.xml
new file mode 100644
index 0000000..84f4d27
--- /dev/null
+++ b/gdb-xml/power-altivec.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.altivec">
+  <vector id="v4f" type="ieee_single" count="4"/>
+  <vector id="v4i32" type="int32" count="4"/>
+  <vector id="v8i16" type="int16" count="8"/>
+  <vector id="v16i8" type="int8" count="16"/>
+  <union id="vec128">
+    <field name="uint128" type="uint128"/>
+    <field name="v4_float" type="v4f"/>
+    <field name="v4_int32" type="v4i32"/>
+    <field name="v8_int16" type="v8i16"/>
+    <field name="v16_int8" type="v16i8"/>
+  </union>
+
+  <reg name="vr0" bitsize="128" type="vec128"/>
+  <reg name="vr1" bitsize="128" type="vec128"/>
+  <reg name="vr2" bitsize="128" type="vec128"/>
+  <reg name="vr3" bitsize="128" type="vec128"/>
+  <reg name="vr4" bitsize="128" type="vec128"/>
+  <reg name="vr5" bitsize="128" type="vec128"/>
+  <reg name="vr6" bitsize="128" type="vec128"/>
+  <reg name="vr7" bitsize="128" type="vec128"/>
+  <reg name="vr8" bitsize="128" type="vec128"/>
+  <reg name="vr9" bitsize="128" type="vec128"/>
+  <reg name="vr10" bitsize="128" type="vec128"/>
+  <reg name="vr11" bitsize="128" type="vec128"/>
+  <reg name="vr12" bitsize="128" type="vec128"/>
+  <reg name="vr13" bitsize="128" type="vec128"/>
+  <reg name="vr14" bitsize="128" type="vec128"/>
+  <reg name="vr15" bitsize="128" type="vec128"/>
+  <reg name="vr16" bitsize="128" type="vec128"/>
+  <reg name="vr17" bitsize="128" type="vec128"/>
+  <reg name="vr18" bitsize="128" type="vec128"/>
+  <reg name="vr19" bitsize="128" type="vec128"/>
+  <reg name="vr20" bitsize="128" type="vec128"/>
+  <reg name="vr21" bitsize="128" type="vec128"/>
+  <reg name="vr22" bitsize="128" type="vec128"/>
+  <reg name="vr23" bitsize="128" type="vec128"/>
+  <reg name="vr24" bitsize="128" type="vec128"/>
+  <reg name="vr25" bitsize="128" type="vec128"/>
+  <reg name="vr26" bitsize="128" type="vec128"/>
+  <reg name="vr27" bitsize="128" type="vec128"/>
+  <reg name="vr28" bitsize="128" type="vec128"/>
+  <reg name="vr29" bitsize="128" type="vec128"/>
+  <reg name="vr30" bitsize="128" type="vec128"/>
+  <reg name="vr31" bitsize="128" type="vec128"/>
+
+  <reg name="vscr" bitsize="32" group="vector"/>
+  <reg name="vrsave" bitsize="32" group="vector"/>
+</feature>
diff --git a/gdb-xml/power-core.xml b/gdb-xml/power-core.xml
new file mode 100644
index 0000000..dae13a6
--- /dev/null
+++ b/gdb-xml/power-core.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core">
+  <reg name="r0" bitsize="32" type="uint32"/>
+  <reg name="r1" bitsize="32" type="uint32"/>
+  <reg name="r2" bitsize="32" type="uint32"/>
+  <reg name="r3" bitsize="32" type="uint32"/>
+  <reg name="r4" bitsize="32" type="uint32"/>
+  <reg name="r5" bitsize="32" type="uint32"/>
+  <reg name="r6" bitsize="32" type="uint32"/>
+  <reg name="r7" bitsize="32" type="uint32"/>
+  <reg name="r8" bitsize="32" type="uint32"/>
+  <reg name="r9" bitsize="32" type="uint32"/>
+  <reg name="r10" bitsize="32" type="uint32"/>
+  <reg name="r11" bitsize="32" type="uint32"/>
+  <reg name="r12" bitsize="32" type="uint32"/>
+  <reg name="r13" bitsize="32" type="uint32"/>
+  <reg name="r14" bitsize="32" type="uint32"/>
+  <reg name="r15" bitsize="32" type="uint32"/>
+  <reg name="r16" bitsize="32" type="uint32"/>
+  <reg name="r17" bitsize="32" type="uint32"/>
+  <reg name="r18" bitsize="32" type="uint32"/>
+  <reg name="r19" bitsize="32" type="uint32"/>
+  <reg name="r20" bitsize="32" type="uint32"/>
+  <reg name="r21" bitsize="32" type="uint32"/>
+  <reg name="r22" bitsize="32" type="uint32"/>
+  <reg name="r23" bitsize="32" type="uint32"/>
+  <reg name="r24" bitsize="32" type="uint32"/>
+  <reg name="r25" bitsize="32" type="uint32"/>
+  <reg name="r26" bitsize="32" type="uint32"/>
+  <reg name="r27" bitsize="32" type="uint32"/>
+  <reg name="r28" bitsize="32" type="uint32"/>
+  <reg name="r29" bitsize="32" type="uint32"/>
+  <reg name="r30" bitsize="32" type="uint32"/>
+  <reg name="r31" bitsize="32" type="uint32"/>
+
+  <reg name="pc" bitsize="32" type="code_ptr" regnum="64"/>
+  <reg name="msr" bitsize="32" type="uint32"/>
+  <reg name="cr" bitsize="32" type="uint32"/>
+  <reg name="lr" bitsize="32" type="code_ptr"/>
+  <reg name="ctr" bitsize="32" type="uint32"/>
+  <reg name="xer" bitsize="32" type="uint32"/>
+  <!-- HACK: The way the QEMU GDB stub code is currently written requires
+       the "integer" registers from the XML file to span the entirety of
+       NUM_CORE_REGS that non-XML-aware GDB requires.  Otherwise, XML-aware
+       GDB thinks that "coprocessor" registers from XML, such as the
+       floating-point registers, have register numbers less than
+       NUM_CORE_REGS.  This can lead to problems.  Work around it by using
+       an unnamed register as padding; NUM_CORE_REGS on Power is 71 and
+       this register is 70.  It would be fpscr for non-XML-aware GDB.  -->
+  <reg name="" bitsize="32" type="uint32"/>
+</feature>
diff --git a/gdb-xml/power-fpu.xml b/gdb-xml/power-fpu.xml
new file mode 100644
index 0000000..d1ca3a3
--- /dev/null
+++ b/gdb-xml/power-fpu.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.fpu">
+  <reg name="f0" bitsize="64" type="ieee_double"/>
+  <reg name="f1" bitsize="64" type="ieee_double"/>
+  <reg name="f2" bitsize="64" type="ieee_double"/>
+  <reg name="f3" bitsize="64" type="ieee_double"/>
+  <reg name="f4" bitsize="64" type="ieee_double"/>
+  <reg name="f5" bitsize="64" type="ieee_double"/>
+  <reg name="f6" bitsize="64" type="ieee_double"/>
+  <reg name="f7" bitsize="64" type="ieee_double"/>
+  <reg name="f8" bitsize="64" type="ieee_double"/>
+  <reg name="f9" bitsize="64" type="ieee_double"/>
+  <reg name="f10" bitsize="64" type="ieee_double"/>
+  <reg name="f11" bitsize="64" type="ieee_double"/>
+  <reg name="f12" bitsize="64" type="ieee_double"/>
+  <reg name="f13" bitsize="64" type="ieee_double"/>
+  <reg name="f14" bitsize="64" type="ieee_double"/>
+  <reg name="f15" bitsize="64" type="ieee_double"/>
+  <reg name="f16" bitsize="64" type="ieee_double"/>
+  <reg name="f17" bitsize="64" type="ieee_double"/>
+  <reg name="f18" bitsize="64" type="ieee_double"/>
+  <reg name="f19" bitsize="64" type="ieee_double"/>
+  <reg name="f20" bitsize="64" type="ieee_double"/>
+  <reg name="f21" bitsize="64" type="ieee_double"/>
+  <reg name="f22" bitsize="64" type="ieee_double"/>
+  <reg name="f23" bitsize="64" type="ieee_double"/>
+  <reg name="f24" bitsize="64" type="ieee_double"/>
+  <reg name="f25" bitsize="64" type="ieee_double"/>
+  <reg name="f26" bitsize="64" type="ieee_double"/>
+  <reg name="f27" bitsize="64" type="ieee_double"/>
+  <reg name="f28" bitsize="64" type="ieee_double"/>
+  <reg name="f29" bitsize="64" type="ieee_double"/>
+  <reg name="f30" bitsize="64" type="ieee_double"/>
+  <reg name="f31" bitsize="64" type="ieee_double"/>
+
+  <reg name="fpscr" bitsize="32" group="float"/>
+</feature>
diff --git a/gdb-xml/power-spe.xml b/gdb-xml/power-spe.xml
new file mode 100644
index 0000000..1ec15d6
--- /dev/null
+++ b/gdb-xml/power-spe.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.spe">
+  <reg name="ev0h" bitsize="32"/>
+  <reg name="ev1h" bitsize="32"/>
+  <reg name="ev2h" bitsize="32"/>
+  <reg name="ev3h" bitsize="32"/>
+  <reg name="ev4h" bitsize="32"/>
+  <reg name="ev5h" bitsize="32"/>
+  <reg name="ev6h" bitsize="32"/>
+  <reg name="ev7h" bitsize="32"/>
+  <reg name="ev8h" bitsize="32"/>
+  <reg name="ev9h" bitsize="32"/>
+  <reg name="ev10h" bitsize="32"/>
+  <reg name="ev11h" bitsize="32"/>
+  <reg name="ev12h" bitsize="32"/>
+  <reg name="ev13h" bitsize="32"/>
+  <reg name="ev14h" bitsize="32"/>
+  <reg name="ev15h" bitsize="32"/>
+  <reg name="ev16h" bitsize="32"/>
+  <reg name="ev17h" bitsize="32"/>
+  <reg name="ev18h" bitsize="32"/>
+  <reg name="ev19h" bitsize="32"/>
+  <reg name="ev20h" bitsize="32"/>
+  <reg name="ev21h" bitsize="32"/>
+  <reg name="ev22h" bitsize="32"/>
+  <reg name="ev23h" bitsize="32"/>
+  <reg name="ev24h" bitsize="32"/>
+  <reg name="ev25h" bitsize="32"/>
+  <reg name="ev26h" bitsize="32"/>
+  <reg name="ev27h" bitsize="32"/>
+  <reg name="ev28h" bitsize="32"/>
+  <reg name="ev29h" bitsize="32"/>
+  <reg name="ev30h" bitsize="32"/>
+  <reg name="ev31h" bitsize="32"/>
+
+  <reg name="acc" bitsize="64"/>
+  <reg name="spefscr" bitsize="32"/>
+</feature>
diff --git a/gdb-xml/power64-core.xml b/gdb-xml/power64-core.xml
new file mode 100644
index 0000000..fef42e4
--- /dev/null
+++ b/gdb-xml/power64-core.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core">
+  <reg name="r0" bitsize="64" type="uint64"/>
+  <reg name="r1" bitsize="64" type="uint64"/>
+  <reg name="r2" bitsize="64" type="uint64"/>
+  <reg name="r3" bitsize="64" type="uint64"/>
+  <reg name="r4" bitsize="64" type="uint64"/>
+  <reg name="r5" bitsize="64" type="uint64"/>
+  <reg name="r6" bitsize="64" type="uint64"/>
+  <reg name="r7" bitsize="64" type="uint64"/>
+  <reg name="r8" bitsize="64" type="uint64"/>
+  <reg name="r9" bitsize="64" type="uint64"/>
+  <reg name="r10" bitsize="64" type="uint64"/>
+  <reg name="r11" bitsize="64" type="uint64"/>
+  <reg name="r12" bitsize="64" type="uint64"/>
+  <reg name="r13" bitsize="64" type="uint64"/>
+  <reg name="r14" bitsize="64" type="uint64"/>
+  <reg name="r15" bitsize="64" type="uint64"/>
+  <reg name="r16" bitsize="64" type="uint64"/>
+  <reg name="r17" bitsize="64" type="uint64"/>
+  <reg name="r18" bitsize="64" type="uint64"/>
+  <reg name="r19" bitsize="64" type="uint64"/>
+  <reg name="r20" bitsize="64" type="uint64"/>
+  <reg name="r21" bitsize="64" type="uint64"/>
+  <reg name="r22" bitsize="64" type="uint64"/>
+  <reg name="r23" bitsize="64" type="uint64"/>
+  <reg name="r24" bitsize="64" type="uint64"/>
+  <reg name="r25" bitsize="64" type="uint64"/>
+  <reg name="r26" bitsize="64" type="uint64"/>
+  <reg name="r27" bitsize="64" type="uint64"/>
+  <reg name="r28" bitsize="64" type="uint64"/>
+  <reg name="r29" bitsize="64" type="uint64"/>
+  <reg name="r30" bitsize="64" type="uint64"/>
+  <reg name="r31" bitsize="64" type="uint64"/>
+
+  <reg name="pc" bitsize="64" type="code_ptr" regnum="64"/>
+  <reg name="msr" bitsize="64" type="uint64"/>
+  <reg name="cr" bitsize="32" type="uint32"/>
+  <reg name="lr" bitsize="64" type="code_ptr"/>
+  <reg name="ctr" bitsize="64" type="uint64"/>
+  <reg name="xer" bitsize="32" type="uint32"/>
+  <!-- HACK: The way the QEMU GDB stub code is currently written requires
+       the "integer" registers from the XML file to span the entirety of
+       NUM_CORE_REGS that non-XML-aware GDB requires.  Otherwise, XML-aware
+       GDB thinks that "coprocessor" registers from XML, such as the
+       floating-point registers, have register numbers less than
+       NUM_CORE_REGS.  This can lead to problems.  Work around it by using
+       an unnamed register as padding; NUM_CORE_REGS on Power is 71 and
+       this register is 70.  It would be fpscr for non-XML-aware GDB.  -->
+  <reg name="" bitsize="32" type="uint32"/>
+</feature>
diff --git a/gdbstub.c b/gdbstub.c
index 7923dba..9bd4375 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -15,9 +15,10 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include "config.h"
+#include "qemu-common.h"
 #ifdef CONFIG_USER_ONLY
 #include <stdlib.h>
 #include <stdio.h>
@@ -29,29 +30,242 @@
 
 #include "qemu.h"
 #else
-#include "qemu-common.h"
+#include "monitor.h"
 #include "qemu-char.h"
 #include "sysemu.h"
-#include "cpu.h"
 #include "gdbstub.h"
 #endif
 
+#define MAX_PACKET_LENGTH 4096
+
 #include "qemu_socket.h"
-#ifdef _WIN32
-/* XXX: these constants may be independent of the host ones even for Unix */
-#ifndef SIGTRAP
-#define SIGTRAP 5
-#endif
-#ifndef SIGINT
-#define SIGINT 2
-#endif
+#include "kvm.h"
+
+
+enum {
+    GDB_SIGNAL_0 = 0,
+    GDB_SIGNAL_INT = 2,
+    GDB_SIGNAL_TRAP = 5,
+    GDB_SIGNAL_UNKNOWN = 143
+};
+
+#ifdef CONFIG_USER_ONLY
+
+/* Map target signal numbers to GDB protocol signal numbers and vice
+ * versa.  For user emulation's currently supported systems, we can
+ * assume most signals are defined.
+ */
+
+static int gdb_signal_table[] = {
+    0,
+    TARGET_SIGHUP,
+    TARGET_SIGINT,
+    TARGET_SIGQUIT,
+    TARGET_SIGILL,
+    TARGET_SIGTRAP,
+    TARGET_SIGABRT,
+    -1, /* SIGEMT */
+    TARGET_SIGFPE,
+    TARGET_SIGKILL,
+    TARGET_SIGBUS,
+    TARGET_SIGSEGV,
+    TARGET_SIGSYS,
+    TARGET_SIGPIPE,
+    TARGET_SIGALRM,
+    TARGET_SIGTERM,
+    TARGET_SIGURG,
+    TARGET_SIGSTOP,
+    TARGET_SIGTSTP,
+    TARGET_SIGCONT,
+    TARGET_SIGCHLD,
+    TARGET_SIGTTIN,
+    TARGET_SIGTTOU,
+    TARGET_SIGIO,
+    TARGET_SIGXCPU,
+    TARGET_SIGXFSZ,
+    TARGET_SIGVTALRM,
+    TARGET_SIGPROF,
+    TARGET_SIGWINCH,
+    -1, /* SIGLOST */
+    TARGET_SIGUSR1,
+    TARGET_SIGUSR2,
+#ifdef TARGET_SIGPWR
+    TARGET_SIGPWR,
 #else
-#include <signal.h>
+    -1,
 #endif
+    -1, /* SIGPOLL */
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+#ifdef __SIGRTMIN
+    __SIGRTMIN + 1,
+    __SIGRTMIN + 2,
+    __SIGRTMIN + 3,
+    __SIGRTMIN + 4,
+    __SIGRTMIN + 5,
+    __SIGRTMIN + 6,
+    __SIGRTMIN + 7,
+    __SIGRTMIN + 8,
+    __SIGRTMIN + 9,
+    __SIGRTMIN + 10,
+    __SIGRTMIN + 11,
+    __SIGRTMIN + 12,
+    __SIGRTMIN + 13,
+    __SIGRTMIN + 14,
+    __SIGRTMIN + 15,
+    __SIGRTMIN + 16,
+    __SIGRTMIN + 17,
+    __SIGRTMIN + 18,
+    __SIGRTMIN + 19,
+    __SIGRTMIN + 20,
+    __SIGRTMIN + 21,
+    __SIGRTMIN + 22,
+    __SIGRTMIN + 23,
+    __SIGRTMIN + 24,
+    __SIGRTMIN + 25,
+    __SIGRTMIN + 26,
+    __SIGRTMIN + 27,
+    __SIGRTMIN + 28,
+    __SIGRTMIN + 29,
+    __SIGRTMIN + 30,
+    __SIGRTMIN + 31,
+    -1, /* SIGCANCEL */
+    __SIGRTMIN,
+    __SIGRTMIN + 32,
+    __SIGRTMIN + 33,
+    __SIGRTMIN + 34,
+    __SIGRTMIN + 35,
+    __SIGRTMIN + 36,
+    __SIGRTMIN + 37,
+    __SIGRTMIN + 38,
+    __SIGRTMIN + 39,
+    __SIGRTMIN + 40,
+    __SIGRTMIN + 41,
+    __SIGRTMIN + 42,
+    __SIGRTMIN + 43,
+    __SIGRTMIN + 44,
+    __SIGRTMIN + 45,
+    __SIGRTMIN + 46,
+    __SIGRTMIN + 47,
+    __SIGRTMIN + 48,
+    __SIGRTMIN + 49,
+    __SIGRTMIN + 50,
+    __SIGRTMIN + 51,
+    __SIGRTMIN + 52,
+    __SIGRTMIN + 53,
+    __SIGRTMIN + 54,
+    __SIGRTMIN + 55,
+    __SIGRTMIN + 56,
+    __SIGRTMIN + 57,
+    __SIGRTMIN + 58,
+    __SIGRTMIN + 59,
+    __SIGRTMIN + 60,
+    __SIGRTMIN + 61,
+    __SIGRTMIN + 62,
+    __SIGRTMIN + 63,
+    __SIGRTMIN + 64,
+    __SIGRTMIN + 65,
+    __SIGRTMIN + 66,
+    __SIGRTMIN + 67,
+    __SIGRTMIN + 68,
+    __SIGRTMIN + 69,
+    __SIGRTMIN + 70,
+    __SIGRTMIN + 71,
+    __SIGRTMIN + 72,
+    __SIGRTMIN + 73,
+    __SIGRTMIN + 74,
+    __SIGRTMIN + 75,
+    __SIGRTMIN + 76,
+    __SIGRTMIN + 77,
+    __SIGRTMIN + 78,
+    __SIGRTMIN + 79,
+    __SIGRTMIN + 80,
+    __SIGRTMIN + 81,
+    __SIGRTMIN + 82,
+    __SIGRTMIN + 83,
+    __SIGRTMIN + 84,
+    __SIGRTMIN + 85,
+    __SIGRTMIN + 86,
+    __SIGRTMIN + 87,
+    __SIGRTMIN + 88,
+    __SIGRTMIN + 89,
+    __SIGRTMIN + 90,
+    __SIGRTMIN + 91,
+    __SIGRTMIN + 92,
+    __SIGRTMIN + 93,
+    __SIGRTMIN + 94,
+    __SIGRTMIN + 95,
+    -1, /* SIGINFO */
+    -1, /* UNKNOWN */
+    -1, /* DEFAULT */
+    -1,
+    -1,
+    -1,
+    -1,
+    -1,
+    -1
+#endif
+};
+#else
+/* In system mode we only need SIGINT and SIGTRAP; other signals
+   are not yet supported.  */
+
+enum {
+    TARGET_SIGINT = 2,
+    TARGET_SIGTRAP = 5
+};
+
+static int gdb_signal_table[] = {
+    -1,
+    -1,
+    TARGET_SIGINT,
+    -1,
+    -1,
+    TARGET_SIGTRAP
+};
+#endif
+
+#ifdef CONFIG_USER_ONLY
+static int target_signal_to_gdb (int sig)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++)
+        if (gdb_signal_table[i] == sig)
+            return i;
+    return GDB_SIGNAL_UNKNOWN;
+}
+#endif
+
+static int gdb_signal_to_target (int sig)
+{
+    if (sig < ARRAY_SIZE (gdb_signal_table))
+        return gdb_signal_table[sig];
+    else
+        return -1;
+}
 
 //#define DEBUG_GDB
 
+typedef struct GDBRegisterState {
+    int base_reg;
+    int num_regs;
+    gdb_reg_cb get_reg;
+    gdb_reg_cb set_reg;
+    const char *xml;
+    struct GDBRegisterState *next;
+} GDBRegisterState;
+
 enum RSState {
+    RS_INACTIVE,
     RS_IDLE,
     RS_GETLINE,
     RS_CHKSUM1,
@@ -59,12 +273,14 @@
     RS_SYSCALL,
 };
 typedef struct GDBState {
-    CPUState *env; /* current CPU */
+    CPUState *c_cpu; /* current CPU for step/continue ops */
+    CPUState *g_cpu; /* current CPU for other ops */
+    CPUState *query_cpu; /* for q{f|s}ThreadInfo */
     enum RSState state; /* parsing state */
-    char line_buf[4096];
+    char line_buf[MAX_PACKET_LENGTH];
     int line_buf_index;
     int line_csum;
-    uint8_t last_packet[4100];
+    uint8_t last_packet[MAX_PACKET_LENGTH + 4];
     int last_packet_len;
     int signal;
 #ifdef CONFIG_USER_ONLY
@@ -72,6 +288,7 @@
     int running_state;
 #else
     CharDriverState *chr;
+    CharDriverState *mon_chr;
 #endif
 } GDBState;
 
@@ -80,27 +297,31 @@
  */
 static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
 
+static GDBState *gdbserver_state;
+
+/* This is an ugly hack to cope with both new and old gdb.
+   If gdb sends qXfer:features:read then assume we're talking to a newish
+   gdb that understands target descriptions.  */
+static int gdb_has_xml;
+
 #ifdef CONFIG_USER_ONLY
 /* XXX: This is not thread safe.  Do we care?  */
 static int gdbserver_fd = -1;
 
-/* XXX: remove this hack.  */
-static GDBState gdbserver_state;
-
 static int get_char(GDBState *s)
 {
     uint8_t ch;
     int ret;
 
     for(;;) {
-        ret = socket_recv(s->fd, &ch, 1);
+        ret = recv(s->fd, &ch, 1, 0);
         if (ret < 0) {
             if (errno == ECONNRESET)
                 s->fd = -1;
             if (errno != EINTR && errno != EAGAIN)
                 return -1;
         } else if (ret == 0) {
-            socket_close(s->fd);
+            close(s->fd);
             s->fd = -1;
             return -1;
         } else {
@@ -111,11 +332,9 @@
 }
 #endif
 
-/* GDB stub state for use by semihosting syscalls.  */
-static GDBState *gdb_syscall_state;
 static gdb_syscall_complete_cb gdb_current_syscall_cb;
 
-enum {
+static enum {
     GDB_SYS_UNKNOWN,
     GDB_SYS_ENABLED,
     GDB_SYS_DISABLED,
@@ -126,8 +345,8 @@
 int use_gdb_syscalls(void)
 {
     if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
-        gdb_syscall_mode = (gdb_syscall_state ? GDB_SYS_ENABLED
-                                              : GDB_SYS_DISABLED);
+        gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
+                                            : GDB_SYS_DISABLED);
     }
     return gdb_syscall_mode == GDB_SYS_ENABLED;
 }
@@ -148,7 +367,7 @@
     int ret;
 
     while (len > 0) {
-        ret = socket_send(s->fd, buf, len);
+        ret = send(s->fd, buf, len, 0);
         if (ret < 0) {
             if (errno != EINTR && errno != EAGAIN)
                 return;
@@ -206,19 +425,14 @@
 }
 
 /* return -1 if error, 0 if OK */
-static int put_packet(GDBState *s, const char *buf)
+static int put_packet_binary(GDBState *s, const char *buf, int len)
 {
-    int len, csum, i;
+    int csum, i;
     uint8_t *p;
 
-#ifdef DEBUG_GDB
-    printf("reply='%s'\n", buf);
-#endif
-
     for(;;) {
         p = s->last_packet;
         *(p++) = '$';
-        len = strlen(buf);
         memcpy(p, buf, len);
         p += len;
         csum = 0;
@@ -245,522 +459,558 @@
     return 0;
 }
 
+/* return -1 if error, 0 if OK */
+static int put_packet(GDBState *s, const char *buf)
+{
+#ifdef DEBUG_GDB
+    printf("reply='%s'\n", buf);
+#endif
+
+    return put_packet_binary(s, buf, strlen(buf));
+}
+
+/* The GDB remote protocol transfers values in target byte order.  This means
+   we can use the raw memory access routines to access the value buffer.
+   Conveniently, these also handle the case where the buffer is mis-aligned.
+ */
+#define GET_REG8(val) do { \
+    stb_p(mem_buf, val); \
+    return 1; \
+    } while(0)
+#define GET_REG16(val) do { \
+    stw_p(mem_buf, val); \
+    return 2; \
+    } while(0)
+#define GET_REG32(val) do { \
+    stl_p(mem_buf, val); \
+    return 4; \
+    } while(0)
+#define GET_REG64(val) do { \
+    stq_p(mem_buf, val); \
+    return 8; \
+    } while(0)
+
+#if TARGET_LONG_BITS == 64
+#define GET_REGL(val) GET_REG64(val)
+#define ldtul_p(addr) ldq_p(addr)
+#else
+#define GET_REGL(val) GET_REG32(val)
+#define ldtul_p(addr) ldl_p(addr)
+#endif
+
 #if defined(TARGET_I386)
 
 #ifdef TARGET_X86_64
-static const uint8_t gdb_x86_64_regs[16] = {
+static const int gpr_map[16] = {
     R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP,
-    8, 9, 10, 11, 12, 13, 14, 15,
+    8, 9, 10, 11, 12, 13, 14, 15
 };
-#endif
-
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
-{
-    int i, fpus, nb_regs;
-    uint8_t *p;
-
-    p = mem_buf;
-#ifdef TARGET_X86_64
-    if (env->hflags & HF_CS64_MASK) {
-        nb_regs = 16;
-        for(i = 0; i < 16; i++) {
-            *(uint64_t *)p = tswap64(env->regs[gdb_x86_64_regs[i]]);
-            p += 8;
-        }
-        *(uint64_t *)p = tswap64(env->eip);
-        p += 8;
-    } else
-#endif
-    {
-        nb_regs = 8;
-        for(i = 0; i < 8; i++) {
-            *(uint32_t *)p = tswap32(env->regs[i]);
-            p += 4;
-        }
-        *(uint32_t *)p = tswap32(env->eip);
-        p += 4;
-    }
-
-    *(uint32_t *)p = tswap32(env->eflags);
-    p += 4;
-    *(uint32_t *)p = tswap32(env->segs[R_CS].selector);
-    p += 4;
-    *(uint32_t *)p = tswap32(env->segs[R_SS].selector);
-    p += 4;
-    *(uint32_t *)p = tswap32(env->segs[R_DS].selector);
-    p += 4;
-    *(uint32_t *)p = tswap32(env->segs[R_ES].selector);
-    p += 4;
-    *(uint32_t *)p = tswap32(env->segs[R_FS].selector);
-    p += 4;
-    *(uint32_t *)p = tswap32(env->segs[R_GS].selector);
-    p += 4;
-    for(i = 0; i < 8; i++) {
-        /* XXX: convert floats */
-#ifdef USE_X86LDOUBLE
-        memcpy(p, &env->fpregs[i], 10);
 #else
-        memset(p, 0, 10);
+static const int gpr_map[8] = {0, 1, 2, 3, 4, 5, 6, 7};
 #endif
-        p += 10;
+
+#define NUM_CORE_REGS (CPU_NB_REGS * 2 + 25)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < CPU_NB_REGS) {
+        GET_REGL(env->regs[gpr_map[n]]);
+    } else if (n >= CPU_NB_REGS + 8 && n < CPU_NB_REGS + 16) {
+        /* FIXME: byteswap float values.  */
+#ifdef USE_X86LDOUBLE
+        memcpy(mem_buf, &env->fpregs[n - (CPU_NB_REGS + 8)], 10);
+#else
+        memset(mem_buf, 0, 10);
+#endif
+        return 10;
+    } else if (n >= CPU_NB_REGS + 24) {
+        n -= CPU_NB_REGS + 24;
+        if (n < CPU_NB_REGS) {
+            stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0));
+            stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1));
+            return 16;
+        } else if (n == CPU_NB_REGS) {
+            GET_REG32(env->mxcsr);
+        } 
+    } else {
+        n -= CPU_NB_REGS;
+        switch (n) {
+        case 0: GET_REGL(env->eip);
+        case 1: GET_REG32(env->eflags);
+        case 2: GET_REG32(env->segs[R_CS].selector);
+        case 3: GET_REG32(env->segs[R_SS].selector);
+        case 4: GET_REG32(env->segs[R_DS].selector);
+        case 5: GET_REG32(env->segs[R_ES].selector);
+        case 6: GET_REG32(env->segs[R_FS].selector);
+        case 7: GET_REG32(env->segs[R_GS].selector);
+        /* 8...15 x87 regs.  */
+        case 16: GET_REG32(env->fpuc);
+        case 17: GET_REG32((env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11);
+        case 18: GET_REG32(0); /* ftag */
+        case 19: GET_REG32(0); /* fiseg */
+        case 20: GET_REG32(0); /* fioff */
+        case 21: GET_REG32(0); /* foseg */
+        case 22: GET_REG32(0); /* fooff */
+        case 23: GET_REG32(0); /* fop */
+        /* 24+ xmm regs.  */
+        }
     }
-    *(uint32_t *)p = tswap32(env->fpuc); /* fctrl */
-    p += 4;
-    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
-    *(uint32_t *)p = tswap32(fpus); /* fstat */
-    p += 4;
-    *(uint32_t *)p = 0; /* ftag */
-    p += 4;
-    *(uint32_t *)p = 0; /* fiseg */
-    p += 4;
-    *(uint32_t *)p = 0; /* fioff */
-    p += 4;
-    *(uint32_t *)p = 0; /* foseg */
-    p += 4;
-    *(uint32_t *)p = 0; /* fooff */
-    p += 4;
-    *(uint32_t *)p = 0; /* fop */
-    p += 4;
-    for(i = 0; i < nb_regs; i++) {
-        *(uint64_t *)p = tswap64(env->xmm_regs[i].XMM_Q(0));
-        p += 8;
-        *(uint64_t *)p = tswap64(env->xmm_regs[i].XMM_Q(1));
-        p += 8;
-    }
-    *(uint32_t *)p = tswap32(env->mxcsr);
-    p += 4;
-    return p - mem_buf;
+    return 0;
 }
 
-static inline void cpu_gdb_load_seg(CPUState *env, const uint8_t **pp, 
-                                    int sreg)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int i)
 {
-    const uint8_t *p;
-    uint32_t sel;
-    p = *pp;
-    sel = tswap32(*(uint32_t *)p);
-    p += 4;
-    if (sel != env->segs[sreg].selector) {
+    uint32_t tmp;
+
+    if (i < CPU_NB_REGS) {
+        env->regs[gpr_map[i]] = ldtul_p(mem_buf);
+        return sizeof(target_ulong);
+    } else if (i >= CPU_NB_REGS + 8 && i < CPU_NB_REGS + 16) {
+        i -= CPU_NB_REGS + 8;
+#ifdef USE_X86LDOUBLE
+        memcpy(&env->fpregs[i], mem_buf, 10);
+#endif
+        return 10;
+    } else if (i >= CPU_NB_REGS + 24) {
+        i -= CPU_NB_REGS + 24;
+        if (i < CPU_NB_REGS) {
+            env->xmm_regs[i].XMM_Q(0) = ldq_p(mem_buf);
+            env->xmm_regs[i].XMM_Q(1) = ldq_p(mem_buf + 8);
+            return 16;
+        } else if (i == CPU_NB_REGS) {
+            env->mxcsr = ldl_p(mem_buf);
+            return 4;
+        }
+    } else {
+        i -= CPU_NB_REGS;
+        switch (i) {
+        case 0: env->eip = ldtul_p(mem_buf); return sizeof(target_ulong);
+        case 1: env->eflags = ldl_p(mem_buf); return 4;
 #if defined(CONFIG_USER_ONLY)
-        cpu_x86_load_seg(env, sreg, sel);
+#define LOAD_SEG(index, sreg)\
+            tmp = ldl_p(mem_buf);\
+            if (tmp != env->segs[sreg].selector)\
+                cpu_x86_load_seg(env, sreg, tmp);
 #else
-        /* XXX: do it with a debug function which does not raise an
-           exception */
+/* FIXME: Honor segment registers.  Needs to avoid raising an exception
+   when the selector is invalid.  */
+#define LOAD_SEG(index, sreg) do {} while(0)
 #endif
-    }
-    *pp = p;
-}
-
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
-{
-    const uint8_t *p = mem_buf;
-    int i, nb_regs;
-    uint16_t fpus;
-
-#ifdef TARGET_X86_64
-    if (env->hflags & HF_CS64_MASK) {
-        nb_regs = 16;
-        for(i = 0; i < 16; i++) {
-            env->regs[gdb_x86_64_regs[i]] = tswap64(*(uint64_t *)p);
-            p += 8;
+        case 2: LOAD_SEG(10, R_CS); return 4;
+        case 3: LOAD_SEG(11, R_SS); return 4;
+        case 4: LOAD_SEG(12, R_DS); return 4;
+        case 5: LOAD_SEG(13, R_ES); return 4;
+        case 6: LOAD_SEG(14, R_FS); return 4;
+        case 7: LOAD_SEG(15, R_GS); return 4;
+        /* 8...15 x87 regs.  */
+        case 16: env->fpuc = ldl_p(mem_buf); return 4;
+        case 17:
+                 tmp = ldl_p(mem_buf);
+                 env->fpstt = (tmp >> 11) & 7;
+                 env->fpus = tmp & ~0x3800;
+                 return 4;
+        case 18: /* ftag */ return 4;
+        case 19: /* fiseg */ return 4;
+        case 20: /* fioff */ return 4;
+        case 21: /* foseg */ return 4;
+        case 22: /* fooff */ return 4;
+        case 23: /* fop */ return 4;
+        /* 24+ xmm regs.  */
         }
-        env->eip = tswap64(*(uint64_t *)p);
-        p += 8;
-    } else
-#endif
-    {
-        nb_regs = 8;
-        for(i = 0; i < 8; i++) {
-            env->regs[i] = tswap32(*(uint32_t *)p);
-            p += 4;
-        }
-        env->eip = tswap32(*(uint32_t *)p);
-        p += 4;
     }
-    env->eflags = tswap32(*(uint32_t *)p);
-    p += 4;
-    cpu_gdb_load_seg(env, &p, R_CS);
-    cpu_gdb_load_seg(env, &p, R_SS);
-    cpu_gdb_load_seg(env, &p, R_DS);
-    cpu_gdb_load_seg(env, &p, R_ES);
-    cpu_gdb_load_seg(env, &p, R_FS);
-    cpu_gdb_load_seg(env, &p, R_GS);
-    
-    /* FPU state */
-    for(i = 0; i < 8; i++) {
-        /* XXX: convert floats */
-#ifdef USE_X86LDOUBLE
-        memcpy(&env->fpregs[i], p, 10);
-#endif
-        p += 10;
-    }
-    env->fpuc = tswap32(*(uint32_t *)p); /* fctrl */
-    p += 4;
-    fpus = tswap32(*(uint32_t *)p);
-    p += 4;
-    env->fpstt = (fpus >> 11) & 7;
-    env->fpus = fpus & ~0x3800;
-    p += 4 * 6;
-    
-    if (size >= ((p - mem_buf) + 16 * nb_regs + 4)) {
-        /* SSE state */
-        for(i = 0; i < nb_regs; i++) {
-            env->xmm_regs[i].XMM_Q(0) = tswap64(*(uint64_t *)p);
-            p += 8;
-            env->xmm_regs[i].XMM_Q(1) = tswap64(*(uint64_t *)p);
-            p += 8;
-        }
-        env->mxcsr = tswap32(*(uint32_t *)p);
-        p += 4;
-    }
+    /* Unrecognised register.  */
+    return 0;
 }
 
 #elif defined (TARGET_PPC)
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+
+/* Old gdb always expects FP registers.  Newer (xml-aware) gdb only
+   expects whatever the target description contains.  Due to a
+   historical mishap the FP registers appear in between core integer
+   regs and PC, MSR, CR, and so forth.  We hack round this by giving the
+   FP regs zero size when talking to a newer gdb.  */
+#define NUM_CORE_REGS 71
+#if defined (TARGET_PPC64)
+#define GDB_CORE_XML "power64-core.xml"
+#else
+#define GDB_CORE_XML "power-core.xml"
+#endif
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    uint32_t *registers = (uint32_t *)mem_buf, tmp;
-    int i;
-
-    /* fill in gprs */
-    for(i = 0; i < 32; i++) {
-        registers[i] = tswapl(env->gpr[i]);
+    if (n < 32) {
+        /* gprs */
+        GET_REGL(env->gpr[n]);
+    } else if (n < 64) {
+        /* fprs */
+        if (gdb_has_xml)
+            return 0;
+        stfq_p(mem_buf, env->fpr[n-32]);
+        return 8;
+    } else {
+        switch (n) {
+        case 64: GET_REGL(env->nip);
+        case 65: GET_REGL(env->msr);
+        case 66:
+            {
+                uint32_t cr = 0;
+                int i;
+                for (i = 0; i < 8; i++)
+                    cr |= env->crf[i] << (32 - ((i + 1) * 4));
+                GET_REG32(cr);
+            }
+        case 67: GET_REGL(env->lr);
+        case 68: GET_REGL(env->ctr);
+        case 69: GET_REGL(env->xer);
+        case 70:
+            {
+                if (gdb_has_xml)
+                    return 0;
+                GET_REG32(0); /* fpscr */
+            }
+        }
     }
-    /* fill in fprs */
-    for (i = 0; i < 32; i++) {
-        registers[(i * 2) + 32] = tswapl(*((uint32_t *)&env->fpr[i]));
-	registers[(i * 2) + 33] = tswapl(*((uint32_t *)&env->fpr[i] + 1));
-    }
-    /* nip, msr, ccr, lnk, ctr, xer, mq */
-    registers[96] = tswapl(env->nip);
-    registers[97] = tswapl(env->msr);
-    tmp = 0;
-    for (i = 0; i < 8; i++)
-        tmp |= env->crf[i] << (32 - ((i + 1) * 4));
-    registers[98] = tswapl(tmp);
-    registers[99] = tswapl(env->lr);
-    registers[100] = tswapl(env->ctr);
-    registers[101] = tswapl(ppc_load_xer(env));
-    registers[102] = 0;
-
-    return 103 * 4;
+    return 0;
 }
 
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    uint32_t *registers = (uint32_t *)mem_buf;
-    int i;
-
-    /* fill in gprs */
-    for (i = 0; i < 32; i++) {
-        env->gpr[i] = tswapl(registers[i]);
+    if (n < 32) {
+        /* gprs */
+        env->gpr[n] = ldtul_p(mem_buf);
+        return sizeof(target_ulong);
+    } else if (n < 64) {
+        /* fprs */
+        if (gdb_has_xml)
+            return 0;
+        env->fpr[n-32] = ldfq_p(mem_buf);
+        return 8;
+    } else {
+        switch (n) {
+        case 64:
+            env->nip = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 65:
+            ppc_store_msr(env, ldtul_p(mem_buf));
+            return sizeof(target_ulong);
+        case 66:
+            {
+                uint32_t cr = ldl_p(mem_buf);
+                int i;
+                for (i = 0; i < 8; i++)
+                    env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
+                return 4;
+            }
+        case 67:
+            env->lr = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 68:
+            env->ctr = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 69:
+            env->xer = ldtul_p(mem_buf);
+            return sizeof(target_ulong);
+        case 70:
+            /* fpscr */
+            if (gdb_has_xml)
+                return 0;
+            return 4;
+        }
     }
-    /* fill in fprs */
-    for (i = 0; i < 32; i++) {
-        *((uint32_t *)&env->fpr[i]) = tswapl(registers[(i * 2) + 32]);
-	*((uint32_t *)&env->fpr[i] + 1) = tswapl(registers[(i * 2) + 33]);
-    }
-    /* nip, msr, ccr, lnk, ctr, xer, mq */
-    env->nip = tswapl(registers[96]);
-    ppc_store_msr(env, tswapl(registers[97]));
-    registers[98] = tswapl(registers[98]);
-    for (i = 0; i < 8; i++)
-        env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
-    env->lr = tswapl(registers[99]);
-    env->ctr = tswapl(registers[100]);
-    ppc_store_xer(env, tswapl(registers[101]));
+    return 0;
 }
+
 #elif defined (TARGET_SPARC)
-#ifdef TARGET_ABI32
-#define tswap_abi(val) tswap32(val &0xffffffff)
-#else
-#define tswap_abi(val) tswapl(val)
-#endif
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
-{
-#ifdef TARGET_ABI32
-    abi_ulong *registers = (abi_ulong *)mem_buf;
-#else
-    target_ulong *registers = (target_ulong *)mem_buf;
-#endif
-    int i;
 
-    /* fill in g0..g7 */
-    for(i = 0; i < 8; i++) {
-        registers[i] = tswap_abi(env->gregs[i]);
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+#define NUM_CORE_REGS 86
+#else
+#define NUM_CORE_REGS 72
+#endif
+
+#ifdef TARGET_ABI32
+#define GET_REGA(val) GET_REG32(val)
+#else
+#define GET_REGA(val) GET_REGL(val)
+#endif
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 8) {
+        /* g0..g7 */
+        GET_REGA(env->gregs[n]);
     }
-    /* fill in register window */
-    for(i = 0; i < 24; i++) {
-        registers[i + 8] = tswap_abi(env->regwptr[i]);
+    if (n < 32) {
+        /* register window */
+        GET_REGA(env->regwptr[n - 8]);
     }
-#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
-    /* fill in fprs */
-    for (i = 0; i < 32; i++) {
-        registers[i + 32] = tswap_abi(*((uint32_t *)&env->fpr[i]));
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+    if (n < 64) {
+        /* fprs */
+        GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
     }
     /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
-    registers[64] = tswap_abi(env->y);
-    {
-        uint32_t tmp;
-
-        tmp = GET_PSR(env);
-        registers[65] = tswap32(tmp);
+    switch (n) {
+    case 64: GET_REGA(env->y);
+    case 65: GET_REGA(GET_PSR(env));
+    case 66: GET_REGA(env->wim);
+    case 67: GET_REGA(env->tbr);
+    case 68: GET_REGA(env->pc);
+    case 69: GET_REGA(env->npc);
+    case 70: GET_REGA(env->fsr);
+    case 71: GET_REGA(0); /* csr */
+    default: GET_REGA(0);
     }
-    registers[66] = tswap_abi(env->wim);
-    registers[67] = tswap_abi(env->tbr);
-    registers[68] = tswap_abi(env->pc);
-    registers[69] = tswap_abi(env->npc);
-    registers[70] = tswap_abi(env->fsr);
-    registers[71] = 0; /* csr */
-    registers[72] = 0;
-    return 73 * sizeof(uint32_t);
 #else
-    /* fill in fprs */
-    for (i = 0; i < 64; i += 2) {
-	uint64_t tmp;
-
-        tmp = ((uint64_t)*(uint32_t *)&env->fpr[i]) << 32;
-        tmp |= *(uint32_t *)&env->fpr[i + 1];
-        registers[i / 2 + 32] = tswap64(tmp);
+    if (n < 64) {
+        /* f0-f31 */
+        GET_REG32(*((uint32_t *)&env->fpr[n - 32]));
     }
-    registers[64] = tswapl(env->pc);
-    registers[65] = tswapl(env->npc);
-    registers[66] = tswapl(((uint64_t)GET_CCR(env) << 32) |
+    if (n < 80) {
+        /* f32-f62 (double width, even numbers only) */
+        uint64_t val;
+
+        val = (uint64_t)*((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) << 32;
+        val |= *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]);
+        GET_REG64(val);
+    }
+    switch (n) {
+    case 80: GET_REGL(env->pc);
+    case 81: GET_REGL(env->npc);
+    case 82: GET_REGL(((uint64_t)GET_CCR(env) << 32) |
                            ((env->asi & 0xff) << 24) |
                            ((env->pstate & 0xfff) << 8) |
                            GET_CWP64(env));
-    registers[67] = tswapl(env->fsr);
-    registers[68] = tswapl(env->fprs);
-    registers[69] = tswapl(env->y);
-    return 70 * sizeof(target_ulong);
+    case 83: GET_REGL(env->fsr);
+    case 84: GET_REGL(env->fprs);
+    case 85: GET_REGL(env->y);
+    }
 #endif
+    return 0;
 }
 
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-#ifdef TARGET_ABI32
-    abi_ulong *registers = (abi_ulong *)mem_buf;
+#if defined(TARGET_ABI32)
+    abi_ulong tmp;
+
+    tmp = ldl_p(mem_buf);
 #else
-    target_ulong *registers = (target_ulong *)mem_buf;
+    target_ulong tmp;
+
+    tmp = ldtul_p(mem_buf);
 #endif
-    int i;
 
-    /* fill in g0..g7 */
-    for(i = 0; i < 7; i++) {
-        env->gregs[i] = tswap_abi(registers[i]);
+    if (n < 8) {
+        /* g0..g7 */
+        env->gregs[n] = tmp;
+    } else if (n < 32) {
+        /* register window */
+        env->regwptr[n - 8] = tmp;
     }
-    /* fill in register window */
-    for(i = 0; i < 24; i++) {
-        env->regwptr[i] = tswap_abi(registers[i + 8]);
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+    else if (n < 64) {
+        /* fprs */
+        *((uint32_t *)&env->fpr[n - 32]) = tmp;
+    } else {
+        /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
+        switch (n) {
+        case 64: env->y = tmp; break;
+        case 65: PUT_PSR(env, tmp); break;
+        case 66: env->wim = tmp; break;
+        case 67: env->tbr = tmp; break;
+        case 68: env->pc = tmp; break;
+        case 69: env->npc = tmp; break;
+        case 70: env->fsr = tmp; break;
+        default: return 0;
+        }
     }
-#if !defined(TARGET_SPARC64) || defined(TARGET_ABI32)
-    /* fill in fprs */
-    for (i = 0; i < 32; i++) {
-        *((uint32_t *)&env->fpr[i]) = tswap_abi(registers[i + 32]);
-    }
-    /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
-    env->y = tswap_abi(registers[64]);
-    PUT_PSR(env, tswap_abi(registers[65]));
-    env->wim = tswap_abi(registers[66]);
-    env->tbr = tswap_abi(registers[67]);
-    env->pc = tswap_abi(registers[68]);
-    env->npc = tswap_abi(registers[69]);
-    env->fsr = tswap_abi(registers[70]);
+    return 4;
 #else
-    for (i = 0; i < 64; i += 2) {
-        uint64_t tmp;
-
-        tmp = tswap64(registers[i / 2 + 32]);
-	*((uint32_t *)&env->fpr[i]) = tmp >> 32;
-	*((uint32_t *)&env->fpr[i + 1]) = tmp & 0xffffffff;
+    else if (n < 64) {
+        /* f0-f31 */
+        env->fpr[n] = ldfl_p(mem_buf);
+        return 4;
+    } else if (n < 80) {
+        /* f32-f62 (double width, even numbers only) */
+        *((uint32_t *)&env->fpr[(n - 64) * 2 + 32]) = tmp >> 32;
+        *((uint32_t *)&env->fpr[(n - 64) * 2 + 33]) = tmp;
+    } else {
+        switch (n) {
+        case 80: env->pc = tmp; break;
+        case 81: env->npc = tmp; break;
+        case 82:
+	    PUT_CCR(env, tmp >> 32);
+	    env->asi = (tmp >> 24) & 0xff;
+	    env->pstate = (tmp >> 8) & 0xfff;
+	    PUT_CWP64(env, tmp & 0xff);
+	    break;
+        case 83: env->fsr = tmp; break;
+        case 84: env->fprs = tmp; break;
+        case 85: env->y = tmp; break;
+        default: return 0;
+        }
     }
-    env->pc = tswapl(registers[64]);
-    env->npc = tswapl(registers[65]);
-    {
-        uint64_t tmp = tswapl(registers[66]);
-
-        PUT_CCR(env, tmp >> 32);
-        env->asi = (tmp >> 24) & 0xff;
-        env->pstate = (tmp >> 8) & 0xfff;
-        PUT_CWP64(env, tmp & 0xff);
-    }
-    env->fsr = tswapl(registers[67]);
-    env->fprs = tswapl(registers[68]);
-    env->y = tswapl(registers[69]);
+    return 8;
 #endif
 }
-#undef tswap_abi
 #elif defined (TARGET_ARM)
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+
+/* Old gdb always expect FPA registers.  Newer (xml-aware) gdb only expect
+   whatever the target description contains.  Due to a historical mishap
+   the FPA registers appear in between core integer regs and the CPSR.
+   We hack round this by giving the FPA regs zero size when talking to a
+   newer gdb.  */
+#define NUM_CORE_REGS 26
+#define GDB_CORE_XML "arm-core.xml"
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    int i;
-    uint8_t *ptr;
-
-    ptr = mem_buf;
-    /* 16 core integer registers (4 bytes each).  */
-    for (i = 0; i < 16; i++)
-      {
-        *(uint32_t *)ptr = tswapl(env->regs[i]);
-        ptr += 4;
-      }
-    /* 8 FPA registers (12 bytes each), FPS (4 bytes).
-       Not yet implemented.  */
-    memset (ptr, 0, 8 * 12 + 4);
-    ptr += 8 * 12 + 4;
-    /* CPSR (4 bytes).  */
-    *(uint32_t *)ptr = tswapl (cpsr_read(env));
-    ptr += 4;
-
-    return ptr - mem_buf;
+    if (n < 16) {
+        /* Core integer register.  */
+        GET_REG32(env->regs[n]);
+    }
+    if (n < 24) {
+        /* FPA registers.  */
+        if (gdb_has_xml)
+            return 0;
+        memset(mem_buf, 0, 12);
+        return 12;
+    }
+    switch (n) {
+    case 24:
+        /* FPA status register.  */
+        if (gdb_has_xml)
+            return 0;
+        GET_REG32(0);
+    case 25:
+        /* CPSR */
+        GET_REG32(cpsr_read(env));
+    }
+    /* Unknown register.  */
+    return 0;
 }
 
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    int i;
-    uint8_t *ptr;
+    uint32_t tmp;
 
-    ptr = mem_buf;
-    /* Core integer registers.  */
-    for (i = 0; i < 16; i++)
-      {
-        env->regs[i] = tswapl(*(uint32_t *)ptr);
-        ptr += 4;
-      }
-    /* Ignore FPA regs and scr.  */
-    ptr += 8 * 12 + 4;
-    cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff);
+    tmp = ldl_p(mem_buf);
+
+    /* Mask out low bit of PC to workaround gdb bugs.  This will probably
+       cause problems if we ever implement the Jazelle DBX extensions.  */
+    if (n == 15)
+        tmp &= ~1;
+
+    if (n < 16) {
+        /* Core integer register.  */
+        env->regs[n] = tmp;
+        return 4;
+    }
+    if (n < 24) { /* 16-23 */
+        /* FPA registers (ignored).  */
+        if (gdb_has_xml)
+            return 0;
+        return 12;
+    }
+    switch (n) {
+    case 24:
+        /* FPA status register (ignored).  */
+        if (gdb_has_xml)
+            return 0;
+        return 4;
+    case 25:
+        /* CPSR */
+        cpsr_write (env, tmp, 0xffffffff);
+        return 4;
+    }
+    /* Unknown register.  */
+    return 0;
 }
+
 #elif defined (TARGET_M68K)
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+
+#define NUM_CORE_REGS 18
+
+#define GDB_CORE_XML "cf-core.xml"
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    int i;
-    uint8_t *ptr;
-    CPU_DoubleU u;
-
-    ptr = mem_buf;
-    /* D0-D7 */
-    for (i = 0; i < 8; i++) {
-        *(uint32_t *)ptr = tswapl(env->dregs[i]);
-        ptr += 4;
+    if (n < 8) {
+        /* D0-D7 */
+        GET_REG32(env->dregs[n]);
+    } else if (n < 16) {
+        /* A0-A7 */
+        GET_REG32(env->aregs[n - 8]);
+    } else {
+	switch (n) {
+        case 16: GET_REG32(env->sr);
+        case 17: GET_REG32(env->pc);
+        }
     }
-    /* A0-A7 */
-    for (i = 0; i < 8; i++) {
-        *(uint32_t *)ptr = tswapl(env->aregs[i]);
-        ptr += 4;
-    }
-    *(uint32_t *)ptr = tswapl(env->sr);
-    ptr += 4;
-    *(uint32_t *)ptr = tswapl(env->pc);
-    ptr += 4;
-    /* F0-F7.  The 68881/68040 have 12-bit extended precision registers.
-       ColdFire has 8-bit double precision registers.  */
-    for (i = 0; i < 8; i++) {
-        u.d = env->fregs[i];
-        *(uint32_t *)ptr = tswap32(u.l.upper);
-        *(uint32_t *)ptr = tswap32(u.l.lower);
-    }
-    /* FP control regs (not implemented).  */
-    memset (ptr, 0, 3 * 4);
-    ptr += 3 * 4;
-
-    return ptr - mem_buf;
+    /* FP registers not included here because they vary between
+       ColdFire and m68k.  Use XML bits for these.  */
+    return 0;
 }
 
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    int i;
-    uint8_t *ptr;
-    CPU_DoubleU u;
+    uint32_t tmp;
 
-    ptr = mem_buf;
-    /* D0-D7 */
-    for (i = 0; i < 8; i++) {
-        env->dregs[i] = tswapl(*(uint32_t *)ptr);
-        ptr += 4;
+    tmp = ldl_p(mem_buf);
+
+    if (n < 8) {
+        /* D0-D7 */
+        env->dregs[n] = tmp;
+    } else if (n < 8) {
+        /* A0-A7 */
+        env->aregs[n - 8] = tmp;
+    } else {
+        switch (n) {
+        case 16: env->sr = tmp; break;
+        case 17: env->pc = tmp; break;
+        default: return 0;
+        }
     }
-    /* A0-A7 */
-    for (i = 0; i < 8; i++) {
-        env->aregs[i] = tswapl(*(uint32_t *)ptr);
-        ptr += 4;
-    }
-    env->sr = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
-    env->pc = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
-    /* F0-F7.  The 68881/68040 have 12-bit extended precision registers.
-       ColdFire has 8-bit double precision registers.  */
-    for (i = 0; i < 8; i++) {
-        u.l.upper = tswap32(*(uint32_t *)ptr);
-        u.l.lower = tswap32(*(uint32_t *)ptr);
-        env->fregs[i] = u.d;
-    }
-    /* FP control regs (not implemented).  */
-    ptr += 3 * 4;
+    return 4;
 }
 #elif defined (TARGET_MIPS)
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+
+#define NUM_CORE_REGS 73
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    int i;
-    uint8_t *ptr;
-
-    ptr = mem_buf;
-    for (i = 0; i < 32; i++)
-      {
-        *(target_ulong *)ptr = tswapl(env->active_tc.gpr[i]);
-        ptr += sizeof(target_ulong);
-      }
-
-    *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Status);
-    ptr += sizeof(target_ulong);
-
-    *(target_ulong *)ptr = tswapl(env->active_tc.LO[0]);
-    ptr += sizeof(target_ulong);
-
-    *(target_ulong *)ptr = tswapl(env->active_tc.HI[0]);
-    ptr += sizeof(target_ulong);
-
-    *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr);
-    ptr += sizeof(target_ulong);
-
-    *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_Cause);
-    ptr += sizeof(target_ulong);
-
-    *(target_ulong *)ptr = tswapl(env->active_tc.PC);
-    ptr += sizeof(target_ulong);
-
-    if (env->CP0_Config1 & (1 << CP0C1_FP))
-      {
-        for (i = 0; i < 32; i++)
-          {
+    if (n < 32) {
+        GET_REGL(env->active_tc.gpr[n]);
+    }
+    if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+        if (n >= 38 && n < 70) {
             if (env->CP0_Status & (1 << CP0St_FR))
-              *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].d);
+		GET_REGL(env->active_fpu.fpr[n - 38].d);
             else
-              *(target_ulong *)ptr = tswap32(env->fpu->fpr[i].w[FP_ENDIAN_IDX]);
-            ptr += sizeof(target_ulong);
-          }
+		GET_REGL(env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]);
+        }
+        switch (n) {
+        case 70: GET_REGL((int32_t)env->active_fpu.fcr31);
+        case 71: GET_REGL((int32_t)env->active_fpu.fcr0);
+        }
+    }
+    switch (n) {
+    case 32: GET_REGL((int32_t)env->CP0_Status);
+    case 33: GET_REGL(env->active_tc.LO[0]);
+    case 34: GET_REGL(env->active_tc.HI[0]);
+    case 35: GET_REGL(env->CP0_BadVAddr);
+    case 36: GET_REGL((int32_t)env->CP0_Cause);
+    case 37: GET_REGL(env->active_tc.PC);
+    case 72: GET_REGL(0); /* fp */
+    case 89: GET_REGL((int32_t)env->CP0_PRid);
+    }
+    if (n >= 73 && n <= 88) {
+	/* 16 embedded regs.  */
+	GET_REGL(0);
+    }
 
-        *(target_ulong *)ptr = (int32_t)tswap32(env->fpu->fcr31);
-        ptr += sizeof(target_ulong);
-
-        *(target_ulong *)ptr = (int32_t)tswap32(env->fpu->fcr0);
-        ptr += sizeof(target_ulong);
-      }
-
-    /* "fp", pseudo frame pointer. Not yet implemented in gdb. */
-    *(target_ulong *)ptr = 0;
-    ptr += sizeof(target_ulong);
-
-    /* Registers for embedded use, we just pad them. */
-    for (i = 0; i < 16; i++)
-      {
-        *(target_ulong *)ptr = 0;
-        ptr += sizeof(target_ulong);
-      }
-
-    /* Processor ID. */
-    *(target_ulong *)ptr = (int32_t)tswap32(env->CP0_PRid);
-    ptr += sizeof(target_ulong);
-
-    return ptr - mem_buf;
+    return 0;
 }
 
 /* convert MIPS rounding mode in FCR31 to IEEE library */
@@ -772,204 +1022,582 @@
     float_round_down
   };
 #define RESTORE_ROUNDING_MODE \
-    set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status)
+    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
 
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-    int i;
-    uint8_t *ptr;
+    target_ulong tmp;
 
-    ptr = mem_buf;
-    for (i = 0; i < 32; i++)
-      {
-        env->active_tc.gpr[i] = tswapl(*(target_ulong *)ptr);
-        ptr += sizeof(target_ulong);
-      }
+    tmp = ldtul_p(mem_buf);
 
-    env->CP0_Status = tswapl(*(target_ulong *)ptr);
-    ptr += sizeof(target_ulong);
-
-    env->active_tc.LO[0] = tswapl(*(target_ulong *)ptr);
-    ptr += sizeof(target_ulong);
-
-    env->active_tc.HI[0] = tswapl(*(target_ulong *)ptr);
-    ptr += sizeof(target_ulong);
-
-    env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr);
-    ptr += sizeof(target_ulong);
-
-    env->CP0_Cause = tswapl(*(target_ulong *)ptr);
-    ptr += sizeof(target_ulong);
-
-    env->active_tc.PC = tswapl(*(target_ulong *)ptr);
-    ptr += sizeof(target_ulong);
-
-    if (env->CP0_Config1 & (1 << CP0C1_FP))
-      {
-        for (i = 0; i < 32; i++)
-          {
+    if (n < 32) {
+        env->active_tc.gpr[n] = tmp;
+        return sizeof(target_ulong);
+    }
+    if (env->CP0_Config1 & (1 << CP0C1_FP)
+            && n >= 38 && n < 73) {
+        if (n < 70) {
             if (env->CP0_Status & (1 << CP0St_FR))
-              env->fpu->fpr[i].d = tswapl(*(target_ulong *)ptr);
+              env->active_fpu.fpr[n - 38].d = tmp;
             else
-              env->fpu->fpr[i].w[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr);
-            ptr += sizeof(target_ulong);
-          }
-
-        env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0xFF83FFFF;
-        ptr += sizeof(target_ulong);
-
-        /* The remaining registers are assumed to be read-only. */
-
-        /* set rounding mode */
-        RESTORE_ROUNDING_MODE;
-
+              env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
+        }
+        switch (n) {
+        case 70:
+            env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
+            /* set rounding mode */
+            RESTORE_ROUNDING_MODE;
 #ifndef CONFIG_SOFTFLOAT
-        /* no floating point exception for native float */
-        SET_FP_ENABLE(env->fcr31, 0);
+            /* no floating point exception for native float */
+            SET_FP_ENABLE(env->active_fpu.fcr31, 0);
 #endif
-      }
+            break;
+        case 71: env->active_fpu.fcr0 = tmp; break;
+        }
+        return sizeof(target_ulong);
+    }
+    switch (n) {
+    case 32: env->CP0_Status = tmp; break;
+    case 33: env->active_tc.LO[0] = tmp; break;
+    case 34: env->active_tc.HI[0] = tmp; break;
+    case 35: env->CP0_BadVAddr = tmp; break;
+    case 36: env->CP0_Cause = tmp; break;
+    case 37: env->active_tc.PC = tmp; break;
+    case 72: /* fp, ignored */ break;
+    default: 
+	if (n > 89)
+	    return 0;
+	/* Other registers are readonly.  Ignore writes.  */
+	break;
+    }
+
+    return sizeof(target_ulong);
 }
 #elif defined (TARGET_SH4)
 
 /* Hint: Use "set architecture sh4" in GDB to see fpu registers */
+/* FIXME: We should use XML for this.  */
 
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+#define NUM_CORE_REGS 59
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-  uint32_t *ptr = (uint32_t *)mem_buf;
-  int i;
+    if (n < 8) {
+        if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+            GET_REGL(env->gregs[n + 16]);
+        } else {
+            GET_REGL(env->gregs[n]);
+        }
+    } else if (n < 16) {
+        GET_REGL(env->gregs[n - 8]);
+    } else if (n >= 25 && n < 41) {
+	GET_REGL(env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
+    } else if (n >= 43 && n < 51) {
+	GET_REGL(env->gregs[n - 43]);
+    } else if (n >= 51 && n < 59) {
+	GET_REGL(env->gregs[n - (51 - 16)]);
+    }
+    switch (n) {
+    case 16: GET_REGL(env->pc);
+    case 17: GET_REGL(env->pr);
+    case 18: GET_REGL(env->gbr);
+    case 19: GET_REGL(env->vbr);
+    case 20: GET_REGL(env->mach);
+    case 21: GET_REGL(env->macl);
+    case 22: GET_REGL(env->sr);
+    case 23: GET_REGL(env->fpul);
+    case 24: GET_REGL(env->fpscr);
+    case 41: GET_REGL(env->ssr);
+    case 42: GET_REGL(env->spc);
+    }
 
-#define SAVE(x) *ptr++=tswapl(x)
-  if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
-      for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]);
-  } else {
-      for (i = 0; i < 8; i++) SAVE(env->gregs[i]);
-  }
-  for (i = 8; i < 16; i++) SAVE(env->gregs[i]);
-  SAVE (env->pc);
-  SAVE (env->pr);
-  SAVE (env->gbr);
-  SAVE (env->vbr);
-  SAVE (env->mach);
-  SAVE (env->macl);
-  SAVE (env->sr);
-  SAVE (env->fpul);
-  SAVE (env->fpscr);
-  for (i = 0; i < 16; i++)
-      SAVE(env->fregs[i + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
-  SAVE (env->ssr);
-  SAVE (env->spc);
-  for (i = 0; i < 8; i++) SAVE(env->gregs[i]);
-  for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]);
-  return ((uint8_t *)ptr - mem_buf);
+    return 0;
 }
 
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-  uint32_t *ptr = (uint32_t *)mem_buf;
-  int i;
+    uint32_t tmp;
 
-#define LOAD(x) (x)=*ptr++;
-  if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
-      for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]);
-  } else {
-      for (i = 0; i < 8; i++) LOAD(env->gregs[i]);
-  }
-  for (i = 8; i < 16; i++) LOAD(env->gregs[i]);
-  LOAD (env->pc);
-  LOAD (env->pr);
-  LOAD (env->gbr);
-  LOAD (env->vbr);
-  LOAD (env->mach);
-  LOAD (env->macl);
-  LOAD (env->sr);
-  LOAD (env->fpul);
-  LOAD (env->fpscr);
-  for (i = 0; i < 16; i++)
-      LOAD(env->fregs[i + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
-  LOAD (env->ssr);
-  LOAD (env->spc);
-  for (i = 0; i < 8; i++) LOAD(env->gregs[i]);
-  for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]);
+    tmp = ldl_p(mem_buf);
+
+    if (n < 8) {
+        if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
+            env->gregs[n + 16] = tmp;
+        } else {
+            env->gregs[n] = tmp;
+        }
+	return 4;
+    } else if (n < 16) {
+        env->gregs[n - 8] = tmp;
+	return 4;
+    } else if (n >= 25 && n < 41) {
+	env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)] = tmp;
+    } else if (n >= 43 && n < 51) {
+	env->gregs[n - 43] = tmp;
+	return 4;
+    } else if (n >= 51 && n < 59) {
+	env->gregs[n - (51 - 16)] = tmp;
+	return 4;
+    }
+    switch (n) {
+    case 16: env->pc = tmp;
+    case 17: env->pr = tmp;
+    case 18: env->gbr = tmp;
+    case 19: env->vbr = tmp;
+    case 20: env->mach = tmp;
+    case 21: env->macl = tmp;
+    case 22: env->sr = tmp;
+    case 23: env->fpul = tmp;
+    case 24: env->fpscr = tmp;
+    case 41: env->ssr = tmp;
+    case 42: env->spc = tmp;
+    default: return 0;
+    }
+
+    return 4;
+}
+#elif defined (TARGET_MICROBLAZE)
+
+#define NUM_CORE_REGS (32 + 5)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+	GET_REG32(env->regs[n]);
+    } else {
+	GET_REG32(env->sregs[n - 32]);
+    }
+    return 0;
+}
+
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    uint32_t tmp;
+
+    if (n > NUM_CORE_REGS)
+	return 0;
+
+    tmp = ldl_p(mem_buf);
+
+    if (n < 32) {
+	env->regs[n] = tmp;
+    } else {
+	env->sregs[n - 32] = tmp;
+    }
+    return 4;
 }
 #elif defined (TARGET_CRIS)
 
-static int cris_save_32 (unsigned char *d, uint32_t value)
+#define NUM_CORE_REGS 49
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-	*d++ = (value);
-	*d++ = (value >>= 8);
-	*d++ = (value >>= 8);
-	*d++ = (value >>= 8);
-	return 4;
-}
-static int cris_save_16 (unsigned char *d, uint32_t value)
-{
-	*d++ = (value);
-	*d++ = (value >>= 8);
-	return 2;
-}
-static int cris_save_8 (unsigned char *d, uint32_t value)
-{
-	*d++ = (value);
-	return 1;
+    uint8_t srs;
+
+    srs = env->pregs[PR_SRS];
+    if (n < 16) {
+	GET_REG32(env->regs[n]);
+    }
+
+    if (n >= 21 && n < 32) {
+	GET_REG32(env->pregs[n - 16]);
+    }
+    if (n >= 33 && n < 49) {
+	GET_REG32(env->sregs[srs][n - 33]);
+    }
+    switch (n) {
+    case 16: GET_REG8(env->pregs[0]);
+    case 17: GET_REG8(env->pregs[1]);
+    case 18: GET_REG32(env->pregs[2]);
+    case 19: GET_REG8(srs);
+    case 20: GET_REG16(env->pregs[4]);
+    case 32: GET_REG32(env->pc);
+    }
+
+    return 0;
 }
 
-/* FIXME: this will bug on archs not supporting unaligned word accesses.  */
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-  uint8_t *ptr = mem_buf;
-  uint8_t srs;
-  int i;
+    uint32_t tmp;
 
-  for (i = 0; i < 16; i++)
-	  ptr += cris_save_32 (ptr, env->regs[i]);
+    if (n > 49)
+	return 0;
 
-  srs = env->pregs[PR_SRS];
+    tmp = ldl_p(mem_buf);
 
-  ptr += cris_save_8 (ptr, env->pregs[0]);
-  ptr += cris_save_8 (ptr, env->pregs[1]);
-  ptr += cris_save_32 (ptr, env->pregs[2]);
-  ptr += cris_save_8 (ptr, srs);
-  ptr += cris_save_16 (ptr, env->pregs[4]);
+    if (n < 16) {
+	env->regs[n] = tmp;
+    }
 
-  for (i = 5; i < 16; i++)
-	  ptr += cris_save_32 (ptr, env->pregs[i]);
+    if (n >= 21 && n < 32) {
+	env->pregs[n - 16] = tmp;
+    }
 
-  ptr += cris_save_32 (ptr, env->pc);
+    /* FIXME: Should support function regs be writable?  */
+    switch (n) {
+    case 16: return 1;
+    case 17: return 1;
+    case 18: env->pregs[PR_PID] = tmp; break;
+    case 19: return 1;
+    case 20: return 2;
+    case 32: env->pc = tmp; break;
+    }
 
-  for (i = 0; i < 16; i++)
-	  ptr += cris_save_32 (ptr, env->sregs[srs][i]);
+    return 4;
+}
+#elif defined (TARGET_ALPHA)
 
-  return ((uint8_t *)ptr - mem_buf);
+#define NUM_CORE_REGS 65
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 31) {
+       GET_REGL(env->ir[n]);
+    }
+    else if (n == 31) {
+       GET_REGL(0);
+    }
+    else if (n<63) {
+       uint64_t val;
+
+       val=*((uint64_t *)&env->fir[n-32]);
+       GET_REGL(val);
+    }
+    else if (n==63) {
+       GET_REGL(env->fpcr);
+    }
+    else if (n==64) {
+       GET_REGL(env->pc);
+    }
+    else {
+       GET_REGL(0);
+    }
+
+    return 0;
 }
 
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
-  uint32_t *ptr = (uint32_t *)mem_buf;
-  int i;
+    target_ulong tmp;
+    tmp = ldtul_p(mem_buf);
 
-#define LOAD(x) (x)=*ptr++;
-  for (i = 0; i < 16; i++) LOAD(env->regs[i]);
-  LOAD (env->pc);
+    if (n < 31) {
+        env->ir[n] = tmp;
+    }
+
+    if (n > 31 && n < 63) {
+        env->fir[n - 32] = ldfl_p(mem_buf);
+    }
+
+    if (n == 64 ) {
+       env->pc=tmp;
+    }
+
+    return 8;
 }
 #else
-static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+
+#define NUM_CORE_REGS 0
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
 {
     return 0;
 }
 
-static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 {
+    return 0;
 }
 
 #endif
 
-static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
+static int num_g_regs = NUM_CORE_REGS;
+
+#ifdef GDB_CORE_XML
+/* Encode data using the encoding for 'x' packets.  */
+static int memtox(char *buf, const char *mem, int len)
 {
+    char *p = buf;
+    char c;
+
+    while (len--) {
+        c = *(mem++);
+        switch (c) {
+        case '#': case '$': case '*': case '}':
+            *(p++) = '}';
+            *(p++) = c ^ 0x20;
+            break;
+        default:
+            *(p++) = c;
+            break;
+        }
+    }
+    return p - buf;
+}
+
+static const char *get_feature_xml(const char *p, const char **newp)
+{
+    extern const char *const xml_builtin[][2];
+    size_t len;
+    int i;
+    const char *name;
+    static char target_xml[1024];
+
+    len = 0;
+    while (p[len] && p[len] != ':')
+        len++;
+    *newp = p + len;
+
+    name = NULL;
+    if (strncmp(p, "target.xml", len) == 0) {
+        /* Generate the XML description for this CPU.  */
+        if (!target_xml[0]) {
+            GDBRegisterState *r;
+
+            snprintf(target_xml, sizeof(target_xml),
+                     "<?xml version=\"1.0\"?>"
+                     "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+                     "<target>"
+                     "<xi:include href=\"%s\"/>",
+                     GDB_CORE_XML);
+
+            for (r = first_cpu->gdb_regs; r; r = r->next) {
+                pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
+                pstrcat(target_xml, sizeof(target_xml), r->xml);
+                pstrcat(target_xml, sizeof(target_xml), "\"/>");
+            }
+            pstrcat(target_xml, sizeof(target_xml), "</target>");
+        }
+        return target_xml;
+    }
+    for (i = 0; ; i++) {
+        name = xml_builtin[i][0];
+        if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len))
+            break;
+    }
+    return name ? xml_builtin[i][1] : NULL;
+}
+#endif
+
+static int gdb_read_register(CPUState *env, uint8_t *mem_buf, int reg)
+{
+    GDBRegisterState *r;
+
+    if (reg < NUM_CORE_REGS)
+        return cpu_gdb_read_register(env, mem_buf, reg);
+
+    for (r = env->gdb_regs; r; r = r->next) {
+        if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+            return r->get_reg(env, mem_buf, reg - r->base_reg);
+        }
+    }
+    return 0;
+}
+
+static int gdb_write_register(CPUState *env, uint8_t *mem_buf, int reg)
+{
+    GDBRegisterState *r;
+
+    if (reg < NUM_CORE_REGS)
+        return cpu_gdb_write_register(env, mem_buf, reg);
+
+    for (r = env->gdb_regs; r; r = r->next) {
+        if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
+            return r->set_reg(env, mem_buf, reg - r->base_reg);
+        }
+    }
+    return 0;
+}
+
+/* Register a supplemental set of CPU registers.  If g_pos is nonzero it
+   specifies the first register number and these registers are included in
+   a standard "g" packet.  Direction is relative to gdb, i.e. get_reg is
+   gdb reading a CPU register, and set_reg is gdb modifying a CPU register.
+ */
+
+void gdb_register_coprocessor(CPUState * env,
+                             gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+                             int num_regs, const char *xml, int g_pos)
+{
+    GDBRegisterState *s;
+    GDBRegisterState **p;
+    static int last_reg = NUM_CORE_REGS;
+
+    s = (GDBRegisterState *)qemu_mallocz(sizeof(GDBRegisterState));
+    s->base_reg = last_reg;
+    s->num_regs = num_regs;
+    s->get_reg = get_reg;
+    s->set_reg = set_reg;
+    s->xml = xml;
+    p = &env->gdb_regs;
+    while (*p) {
+        /* Check for duplicates.  */
+        if (strcmp((*p)->xml, xml) == 0)
+            return;
+        p = &(*p)->next;
+    }
+    /* Add to end of list.  */
+    last_reg += num_regs;
+    *p = s;
+    if (g_pos) {
+        if (g_pos != s->base_reg) {
+            fprintf(stderr, "Error: Bad gdb register numbering for '%s'\n"
+                    "Expected %d got %d\n", xml, g_pos, s->base_reg);
+        } else {
+            num_g_regs = last_reg;
+        }
+    }
+}
+
+#ifndef CONFIG_USER_ONLY
+static const int xlat_gdb_type[] = {
+    [GDB_WATCHPOINT_WRITE]  = BP_GDB | BP_MEM_WRITE,
+    [GDB_WATCHPOINT_READ]   = BP_GDB | BP_MEM_READ,
+    [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
+};
+#endif
+
+static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
+{
+    CPUState *env;
+    int err = 0;
+
+    if (kvm_enabled())
+        return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+
+    switch (type) {
+    case GDB_BREAKPOINT_SW:
+    case GDB_BREAKPOINT_HW:
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
+            if (err)
+                break;
+        }
+        return err;
+#ifndef CONFIG_USER_ONLY
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_ACCESS:
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type],
+                                        NULL);
+            if (err)
+                break;
+        }
+        return err;
+#endif
+    default:
+        return -ENOSYS;
+    }
+}
+
+static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
+{
+    CPUState *env;
+    int err = 0;
+
+    if (kvm_enabled())
+        return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+
+    switch (type) {
+    case GDB_BREAKPOINT_SW:
+    case GDB_BREAKPOINT_HW:
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_breakpoint_remove(env, addr, BP_GDB);
+            if (err)
+                break;
+        }
+        return err;
+#ifndef CONFIG_USER_ONLY
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_ACCESS:
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            err = cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]);
+            if (err)
+                break;
+        }
+        return err;
+#endif
+    default:
+        return -ENOSYS;
+    }
+}
+
+static void gdb_breakpoint_remove_all(void)
+{
+    CPUState *env;
+
+    if (kvm_enabled()) {
+        kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
+        return;
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_breakpoint_remove_all(env, BP_GDB);
+#ifndef CONFIG_USER_ONLY
+        cpu_watchpoint_remove_all(env, BP_GDB);
+#endif
+    }
+}
+
+static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+{
+#if defined(TARGET_I386)
+    s->c_cpu->eip = pc;
+    cpu_synchronize_state(s->c_cpu, 1);
+#elif defined (TARGET_PPC)
+    s->c_cpu->nip = pc;
+#elif defined (TARGET_SPARC)
+    s->c_cpu->pc = pc;
+    s->c_cpu->npc = pc + 4;
+#elif defined (TARGET_ARM)
+    s->c_cpu->regs[15] = pc;
+#elif defined (TARGET_SH4)
+    s->c_cpu->pc = pc;
+#elif defined (TARGET_MIPS)
+    s->c_cpu->active_tc.PC = pc;
+#elif defined (TARGET_MICROBLAZE)
+    s->c_cpu->sregs[SR_PC] = pc;
+#elif defined (TARGET_CRIS)
+    s->c_cpu->pc = pc;
+#elif defined (TARGET_ALPHA)
+    s->c_cpu->pc = pc;
+#endif
+}
+
+static inline int gdb_id(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY) && defined(USE_NPTL)
+    return env->host_tid;
+#else
+    return env->cpu_index + 1;
+#endif
+}
+
+static CPUState *find_cpu(uint32_t thread_id)
+{
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (gdb_id(env) == thread_id) {
+            return env;
+        }
+    }
+
+    return NULL;
+}
+
+static int gdb_handle_packet(GDBState *s, const char *line_buf)
+{
+    CPUState *env;
     const char *p;
-    int ch, reg_size, type;
-    char buf[4096];
-    uint8_t mem_buf[4096];
-    uint32_t *registers;
+    uint32_t thread;
+    int ch, reg_size, type, res;
+    char buf[MAX_PACKET_LENGTH];
+    uint8_t mem_buf[MAX_PACKET_LENGTH];
+    uint8_t *registers;
     target_ulong addr, len;
 
 #ifdef DEBUG_GDB
@@ -980,39 +1608,27 @@
     switch(ch) {
     case '?':
         /* TODO: Make this return the correct value for user-mode.  */
-        snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
+        snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
+                 gdb_id(s->c_cpu));
         put_packet(s, buf);
         /* Remove all the breakpoints when this query is issued,
          * because gdb is doing and initial connect and the state
          * should be cleaned up.
          */
-        cpu_breakpoint_remove_all(env);
-        cpu_watchpoint_remove_all(env);
+        gdb_breakpoint_remove_all();
         break;
     case 'c':
         if (*p != '\0') {
             addr = strtoull(p, (char **)&p, 16);
-#if defined(TARGET_I386)
-            env->eip = addr;
-#elif defined (TARGET_PPC)
-            env->nip = addr;
-#elif defined (TARGET_SPARC)
-            env->pc = addr;
-            env->npc = addr + 4;
-#elif defined (TARGET_ARM)
-            env->regs[15] = addr;
-#elif defined (TARGET_SH4)
-            env->pc = addr;
-#elif defined (TARGET_MIPS)
-            env->active_tc.PC = addr;
-#elif defined (TARGET_CRIS)
-            env->pc = addr;
-#endif
+            gdb_set_cpu_pc(s, addr);
         }
+        s->signal = 0;
         gdb_continue(s);
 	return RS_IDLE;
     case 'C':
-        s->signal = strtoul(p, (char **)&p, 16);
+        s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
+        if (s->signal == -1)
+            s->signal = 0;
         gdb_continue(s);
         return RS_IDLE;
     case 'k':
@@ -1021,32 +1637,16 @@
         exit(0);
     case 'D':
         /* Detach packet */
-        cpu_breakpoint_remove_all(env);
-        cpu_watchpoint_remove_all(env);
+        gdb_breakpoint_remove_all();
         gdb_continue(s);
         put_packet(s, "OK");
         break;
     case 's':
         if (*p != '\0') {
             addr = strtoull(p, (char **)&p, 16);
-#if defined(TARGET_I386)
-            env->eip = addr;
-#elif defined (TARGET_PPC)
-            env->nip = addr;
-#elif defined (TARGET_SPARC)
-            env->pc = addr;
-            env->npc = addr + 4;
-#elif defined (TARGET_ARM)
-            env->regs[15] = addr;
-#elif defined (TARGET_SH4)
-            env->pc = addr;
-#elif defined (TARGET_MIPS)
-            env->active_tc.PC = addr;
-#elif defined (TARGET_CRIS)
-            env->pc = addr;
-#endif
+            gdb_set_cpu_pc(s, addr);
         }
-        cpu_single_step(env, sstep_flags);
+        cpu_single_step(s->c_cpu, sstep_flags);
         gdb_continue(s);
 	return RS_IDLE;
     case 'F':
@@ -1065,7 +1665,7 @@
                 p++;
             type = *p;
             if (gdb_current_syscall_cb)
-                gdb_current_syscall_cb(s->env, ret, err);
+                gdb_current_syscall_cb(s->c_cpu, ret, err);
             if (type == 'C') {
                 put_packet(s, "T02");
             } else {
@@ -1074,15 +1674,25 @@
         }
         break;
     case 'g':
-        reg_size = cpu_gdb_read_registers(env, mem_buf);
-        memtohex(buf, mem_buf, reg_size);
+        cpu_synchronize_state(s->g_cpu, 0);
+        len = 0;
+        for (addr = 0; addr < num_g_regs; addr++) {
+            reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr);
+            len += reg_size;
+        }
+        memtohex(buf, mem_buf, len);
         put_packet(s, buf);
         break;
     case 'G':
-        registers = (void *)mem_buf;
+        registers = mem_buf;
         len = strlen(p) / 2;
         hextomem((uint8_t *)registers, p, len);
-        cpu_gdb_write_registers(env, mem_buf, len);
+        for (addr = 0; addr < num_g_regs && len > 0; addr++) {
+            reg_size = gdb_write_register(s->g_cpu, registers, addr);
+            len -= reg_size;
+            registers += reg_size;
+        }
+        cpu_synchronize_state(s->g_cpu, 1);
         put_packet(s, "OK");
         break;
     case 'm':
@@ -1090,7 +1700,7 @@
         if (*p == ',')
             p++;
         len = strtoull(p, NULL, 16);
-        if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) {
+        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 0) != 0) {
             put_packet (s, "E14");
         } else {
             memtohex(buf, mem_buf, len);
@@ -1105,50 +1715,38 @@
         if (*p == ':')
             p++;
         hextomem(mem_buf, p, len);
-        if (cpu_memory_rw_debug(env, addr, mem_buf, len, 1) != 0)
+        if (cpu_memory_rw_debug(s->g_cpu, addr, mem_buf, len, 1) != 0)
             put_packet(s, "E14");
         else
             put_packet(s, "OK");
         break;
-    case 'Z':
-        type = strtoul(p, (char **)&p, 16);
-        if (*p == ',')
-            p++;
+    case 'p':
+        /* Older gdb are really dumb, and don't use 'g' if 'p' is avaialable.
+           This works, but can be very slow.  Anything new enough to
+           understand XML also knows how to use this properly.  */
+        if (!gdb_has_xml)
+            goto unknown_command;
         addr = strtoull(p, (char **)&p, 16);
-        if (*p == ',')
-            p++;
-        len = strtoull(p, (char **)&p, 16);
-        switch (type) {
-        case 0:
-        case 1:
-            if (cpu_breakpoint_insert(env, addr) < 0)
-                goto breakpoint_error;
-            put_packet(s, "OK");
-            break;
-#ifndef CONFIG_USER_ONLY
-        case 2:
-            type = PAGE_WRITE;
-            goto insert_watchpoint;
-        case 3:
-            type = PAGE_READ;
-            goto insert_watchpoint;
-        case 4:
-            type = PAGE_READ | PAGE_WRITE;
-        insert_watchpoint:
-            if (cpu_watchpoint_insert(env, addr, type) < 0)
-                goto breakpoint_error;
-            put_packet(s, "OK");
-            break;
-#endif
-        default:
-            put_packet(s, "");
-            break;
+        reg_size = gdb_read_register(s->g_cpu, mem_buf, addr);
+        if (reg_size) {
+            memtohex(buf, mem_buf, reg_size);
+            put_packet(s, buf);
+        } else {
+            put_packet(s, "E14");
         }
         break;
-    breakpoint_error:
-        put_packet(s, "E22");
+    case 'P':
+        if (!gdb_has_xml)
+            goto unknown_command;
+        addr = strtoull(p, (char **)&p, 16);
+        if (*p == '=')
+            p++;
+        reg_size = strlen(p) / 2;
+        hextomem(mem_buf, p, reg_size);
+        gdb_write_register(s->g_cpu, mem_buf, addr);
+        put_packet(s, "OK");
         break;
-
+    case 'Z':
     case 'z':
         type = strtoul(p, (char **)&p, 16);
         if (*p == ',')
@@ -1157,16 +1755,51 @@
         if (*p == ',')
             p++;
         len = strtoull(p, (char **)&p, 16);
-        if (type == 0 || type == 1) {
-            cpu_breakpoint_remove(env, addr);
-            put_packet(s, "OK");
-#ifndef CONFIG_USER_ONLY
-        } else if (type >= 2 || type <= 4) {
-            cpu_watchpoint_remove(env, addr);
-            put_packet(s, "OK");
-#endif
-        } else {
+        if (ch == 'Z')
+            res = gdb_breakpoint_insert(addr, len, type);
+        else
+            res = gdb_breakpoint_remove(addr, len, type);
+        if (res >= 0)
+             put_packet(s, "OK");
+        else if (res == -ENOSYS)
             put_packet(s, "");
+        else
+            put_packet(s, "E22");
+        break;
+    case 'H':
+        type = *p++;
+        thread = strtoull(p, (char **)&p, 16);
+        if (thread == -1 || thread == 0) {
+            put_packet(s, "OK");
+            break;
+        }
+        env = find_cpu(thread);
+        if (env == NULL) {
+            put_packet(s, "E22");
+            break;
+        }
+        switch (type) {
+        case 'c':
+            s->c_cpu = env;
+            put_packet(s, "OK");
+            break;
+        case 'g':
+            s->g_cpu = env;
+            put_packet(s, "OK");
+            break;
+        default:
+             put_packet(s, "E22");
+             break;
+        }
+        break;
+    case 'T':
+        thread = strtoull(p, (char **)&p, 16);
+        env = find_cpu(thread);
+
+        if (env != NULL) {
+            put_packet(s, "OK");
+        } else {
+            put_packet(s, "E22");
         }
         break;
     case 'q':
@@ -1194,10 +1827,39 @@
             sstep_flags = type;
             put_packet(s, "OK");
             break;
+        } else if (strcmp(p,"C") == 0) {
+            /* "Current thread" remains vague in the spec, so always return
+             *  the first CPU (gdb returns the first thread). */
+            put_packet(s, "QC1");
+            break;
+        } else if (strcmp(p,"fThreadInfo") == 0) {
+            s->query_cpu = first_cpu;
+            goto report_cpuinfo;
+        } else if (strcmp(p,"sThreadInfo") == 0) {
+        report_cpuinfo:
+            if (s->query_cpu) {
+                snprintf(buf, sizeof(buf), "m%x", gdb_id(s->query_cpu));
+                put_packet(s, buf);
+                s->query_cpu = s->query_cpu->next_cpu;
+            } else
+                put_packet(s, "l");
+            break;
+        } else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
+            thread = strtoull(p+16, (char **)&p, 16);
+            env = find_cpu(thread);
+            if (env != NULL) {
+                cpu_synchronize_state(env, 0);
+                len = snprintf((char *)mem_buf, sizeof(mem_buf),
+                               "CPU#%d [%s]", env->cpu_index,
+                               env->halted ? "halted " : "running");
+                memtohex(buf, mem_buf, len);
+                put_packet(s, buf);
+            }
+            break;
         }
-#ifdef CONFIG_LINUX_USER
+#ifdef CONFIG_USER_ONLY
         else if (strncmp(p, "Offsets", 7) == 0) {
-            TaskState *ts = env->opaque;
+            TaskState *ts = s->c_cpu->opaque;
 
             snprintf(buf, sizeof(buf),
                      "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
@@ -1208,9 +1870,75 @@
             put_packet(s, buf);
             break;
         }
+#else /* !CONFIG_USER_ONLY */
+        else if (strncmp(p, "Rcmd,", 5) == 0) {
+            int len = strlen(p + 5);
+
+            if ((len % 2) != 0) {
+                put_packet(s, "E01");
+                break;
+            }
+            hextomem(mem_buf, p + 5, len);
+            len = len / 2;
+            mem_buf[len++] = 0;
+            qemu_chr_read(s->mon_chr, mem_buf, len);
+            put_packet(s, "OK");
+            break;
+        }
+#endif /* !CONFIG_USER_ONLY */
+        if (strncmp(p, "Supported", 9) == 0) {
+            snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH);
+#ifdef GDB_CORE_XML
+            pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
 #endif
-        /* Fall through.  */
+            put_packet(s, buf);
+            break;
+        }
+#ifdef GDB_CORE_XML
+        if (strncmp(p, "Xfer:features:read:", 19) == 0) {
+            const char *xml;
+            target_ulong total_len;
+
+            gdb_has_xml = 1;
+            p += 19;
+            xml = get_feature_xml(p, &p);
+            if (!xml) {
+                snprintf(buf, sizeof(buf), "E00");
+                put_packet(s, buf);
+                break;
+            }
+
+            if (*p == ':')
+                p++;
+            addr = strtoul(p, (char **)&p, 16);
+            if (*p == ',')
+                p++;
+            len = strtoul(p, (char **)&p, 16);
+
+            total_len = strlen(xml);
+            if (addr > total_len) {
+                snprintf(buf, sizeof(buf), "E00");
+                put_packet(s, buf);
+                break;
+            }
+            if (len > (MAX_PACKET_LENGTH - 5) / 2)
+                len = (MAX_PACKET_LENGTH - 5) / 2;
+            if (len < total_len - addr) {
+                buf[0] = 'm';
+                len = memtox(buf + 1, xml + addr, len);
+            } else {
+                buf[0] = 'l';
+                len = memtox(buf + 1, xml + addr, total_len - addr);
+            }
+            put_packet_binary(s, buf, len + 1);
+            break;
+        }
+#endif
+        /* Unrecognised 'q' command.  */
+        goto unknown_command;
+
     default:
+    unknown_command:
         /* put empty packet */
         buf[0] = '\0';
         put_packet(s, buf);
@@ -1219,38 +1947,55 @@
     return RS_IDLE;
 }
 
-extern void tb_flush(CPUState *env);
+void gdb_set_stop_cpu(CPUState *env)
+{
+    gdbserver_state->c_cpu = env;
+    gdbserver_state->g_cpu = env;
+}
 
 #ifndef CONFIG_USER_ONLY
-static void gdb_vm_stopped(void *opaque, int reason)
+static void gdb_vm_state_change(void *opaque, int running, int reason)
 {
-    GDBState *s = opaque;
+    GDBState *s = gdbserver_state;
+    CPUState *env = s->c_cpu;
     char buf[256];
+    const char *type;
     int ret;
 
-    if (s->state == RS_SYSCALL)
+    if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) ||
+        s->state == RS_INACTIVE || s->state == RS_SYSCALL)
         return;
 
     /* disable single step if it was enable */
-    cpu_single_step(s->env, 0);
+    cpu_single_step(env, 0);
 
     if (reason == EXCP_DEBUG) {
-        if (s->env->watchpoint_hit) {
-            snprintf(buf, sizeof(buf), "T%02xwatch:" TARGET_FMT_lx ";",
-                     SIGTRAP,
-                     s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr);
+        if (env->watchpoint_hit) {
+            switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) {
+            case BP_MEM_READ:
+                type = "r";
+                break;
+            case BP_MEM_ACCESS:
+                type = "a";
+                break;
+            default:
+                type = "";
+                break;
+            }
+            snprintf(buf, sizeof(buf),
+                     "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
+                     GDB_SIGNAL_TRAP, gdb_id(env), type,
+                     env->watchpoint_hit->vaddr);
             put_packet(s, buf);
-            s->env->watchpoint_hit = 0;
+            env->watchpoint_hit = NULL;
             return;
         }
-	tb_flush(s->env);
-        ret = SIGTRAP;
-    } else if (reason == EXCP_INTERRUPT) {
-        ret = SIGINT;
+	tb_flush(env);
+        ret = GDB_SIGNAL_TRAP;
     } else {
-        ret = 0;
+        ret = GDB_SIGNAL_INT;
     }
-    snprintf(buf, sizeof(buf), "S%02x", ret);
+    snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, gdb_id(env));
     put_packet(s, buf);
 }
 #endif
@@ -1269,7 +2014,7 @@
     uint64_t i64;
     GDBState *s;
 
-    s = gdb_syscall_state;
+    s = gdbserver_state;
     if (!s)
         return;
     gdb_current_syscall_cb = cb;
@@ -1314,15 +2059,14 @@
     va_end(va);
     put_packet(s, buf);
 #ifdef CONFIG_USER_ONLY
-    gdb_handlesig(s->env, 0);
+    gdb_handlesig(s->c_cpu, 0);
 #else
-    cpu_interrupt(s->env, CPU_INTERRUPT_EXIT);
+    cpu_exit(s->c_cpu);
 #endif
 }
 
 static void gdb_read_byte(GDBState *s, int ch)
 {
-    CPUState *env = s->env;
     int i, csum;
     uint8_t reply;
 
@@ -1388,7 +2132,7 @@
             } else {
                 reply = '+';
                 put_buffer(s, &reply, 1);
-                s->state = gdb_handle_packet(s, env, s->line_buf);
+                s->state = gdb_handle_packet(s, s->line_buf);
             }
             break;
         default:
@@ -1399,13 +2143,26 @@
 
 #ifdef CONFIG_USER_ONLY
 int
+gdb_queuesig (void)
+{
+    GDBState *s;
+
+    s = gdbserver_state;
+
+    if (gdbserver_fd < 0 || s->fd < 0)
+        return 0;
+    else
+        return 1;
+}
+
+int
 gdb_handlesig (CPUState *env, int sig)
 {
   GDBState *s;
   char buf[256];
   int n;
 
-  s = &gdbserver_state;
+  s = gdbserver_state;
   if (gdbserver_fd < 0 || s->fd < 0)
     return sig;
 
@@ -1415,7 +2172,7 @@
 
   if (sig != 0)
     {
-      snprintf(buf, sizeof(buf), "S%02x", sig);
+      snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig));
       put_packet(s, buf);
     }
   /* put_packet() might have detected that the peer terminated the 
@@ -1453,7 +2210,7 @@
   GDBState *s;
   char buf[4];
 
-  s = &gdbserver_state;
+  s = gdbserver_state;
   if (gdbserver_fd < 0 || s->fd < 0)
     return;
 
@@ -1461,15 +2218,31 @@
   put_packet(s, buf);
 }
 
+/* Tell the remote gdb that the process has exited due to SIG.  */
+void gdb_signalled(CPUState *env, int sig)
+{
+  GDBState *s;
+  char buf[4];
 
-static void gdb_accept(void *opaque)
+  s = gdbserver_state;
+  if (gdbserver_fd < 0 || s->fd < 0)
+    return;
+
+  snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
+  put_packet(s, buf);
+}
+
+static void gdb_accept(void)
 {
     GDBState *s;
-    int       fd;
+    struct sockaddr_in sockaddr;
+    socklen_t len;
+    int val, fd;
 
     for(;;) {
-        fd = socket_accept(gdbserver_fd, NULL);
-        if (fd < 0) {
+        len = sizeof(sockaddr);
+        fd = accept(gdbserver_fd, (struct sockaddr *)&sockaddr, &len);
+        if (fd < 0 && errno != EINTR) {
             perror("accept");
             return;
         } else if (fd >= 0) {
@@ -1478,42 +2251,46 @@
     }
 
     /* set short latency */
-    socket_set_lowlatency(fd);
-    
-    s = &gdbserver_state;
-    memset (s, 0, sizeof (GDBState));
-    s->env = first_cpu; /* XXX: allow to change CPU */
+    val = 1;
+    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+
+    s = qemu_mallocz(sizeof(GDBState));
+    s->c_cpu = first_cpu;
+    s->g_cpu = first_cpu;
     s->fd = fd;
+    gdb_has_xml = 0;
 
-    gdb_syscall_state = s;
+    gdbserver_state = s;
 
-    socket_set_nonblock(fd);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
 }
 
 static int gdbserver_open(int port)
 {
-    SockAddress  sockaddr;
+    struct sockaddr_in sockaddr;
     int fd, val, ret;
 
-    fd = socket_create_inet( SOCKET_STREAM );
+    fd = socket(PF_INET, SOCK_STREAM, 0);
     if (fd < 0) {
         perror("socket");
         return -1;
     }
 
     /* allow fast reuse */
-    socket_set_xreuseaddr(fd);
+    val = 1;
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
 
-    sock_address_init_inet( &sockaddr, SOCK_ADDRESS_INET_ANY, port );
-    ret = socket_bind(fd, &sockaddr);
+    sockaddr.sin_family = AF_INET;
+    sockaddr.sin_port = htons(port);
+    sockaddr.sin_addr.s_addr = 0;
+    ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
     if (ret < 0) {
         perror("bind");
         return -1;
     }
-    ret = socket_listen(fd, 0);
+    ret = listen(fd, 0);
     if (ret < 0) {
         perror("listen");
-        socket_close(fd);
         return -1;
     }
     return fd;
@@ -1525,22 +2302,35 @@
     if (gdbserver_fd < 0)
         return -1;
     /* accept connections */
-    gdb_accept (NULL);
+    gdb_accept();
     return 0;
 }
+
+/* Disable gdb stub for child processes.  */
+void gdbserver_fork(CPUState *env)
+{
+    GDBState *s = gdbserver_state;
+    if (gdbserver_fd < 0 || s->fd < 0)
+      return;
+    close(s->fd);
+    s->fd = -1;
+    cpu_breakpoint_remove_all(env, BP_GDB);
+    cpu_watchpoint_remove_all(env, BP_GDB);
+}
 #else
 static int gdb_chr_can_receive(void *opaque)
 {
-  return 1;
+  /* We can handle an arbitrarily large amount of data.
+   Pick the maximum packet size, which is as good as anything.  */
+  return MAX_PACKET_LENGTH;
 }
 
 static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
 {
-    GDBState *s = opaque;
     int i;
 
     for (i = 0; i < size; i++) {
-        gdb_read_byte(s, buf[i]);
+        gdb_read_byte(gdbserver_state, buf[i]);
     }
 }
 
@@ -1549,45 +2339,106 @@
     switch (event) {
     case CHR_EVENT_RESET:
         vm_stop(EXCP_INTERRUPT);
-        gdb_syscall_state = opaque;
+        gdb_has_xml = 0;
         break;
     default:
         break;
     }
 }
 
-int gdbserver_start(const char *port)
+static void gdb_monitor_output(GDBState *s, const char *msg, int len)
+{
+    char buf[MAX_PACKET_LENGTH];
+
+    buf[0] = 'O';
+    if (len > (MAX_PACKET_LENGTH/2) - 1)
+        len = (MAX_PACKET_LENGTH/2) - 1;
+    memtohex(buf + 1, (uint8_t *)msg, len);
+    put_packet(s, buf);
+}
+
+static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    const char *p = (const char *)buf;
+    int max_sz;
+
+    max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
+    for (;;) {
+        if (len <= max_sz) {
+            gdb_monitor_output(gdbserver_state, p, len);
+            break;
+        }
+        gdb_monitor_output(gdbserver_state, p, max_sz);
+        p += max_sz;
+        len -= max_sz;
+    }
+    return len;
+}
+
+#ifndef _WIN32
+static void gdb_sigterm_handler(int signal)
+{
+    if (vm_running)
+        vm_stop(EXCP_INTERRUPT);
+}
+#endif
+
+int gdbserver_start(const char *device)
 {
     GDBState *s;
-    char gdbstub_port_name[128];
-    int port_num;
-    char *p;
-    CharDriverState *chr;
+    char gdbstub_device_name[128];
+    CharDriverState *chr = NULL;
+    CharDriverState *mon_chr;
 
-    if (!port || !*port)
-      return -1;
+    if (!device)
+        return -1;
+    if (strcmp(device, "none") != 0) {
+        if (strstart(device, "tcp:", NULL)) {
+            /* enforce required TCP attributes */
+            snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
+                     "%s,nowait,nodelay,server", device);
+            device = gdbstub_device_name;
+        }
+#ifndef _WIN32
+        else if (strcmp(device, "stdio") == 0) {
+            struct sigaction act;
 
-    port_num = strtol(port, &p, 10);
-    if (*p == 0) {
-        /* A numeric value is interpreted as a port number.  */
-        snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
-                 "tcp::%d,nowait,nodelay,server", port_num);
-        port = gdbstub_port_name;
+            memset(&act, 0, sizeof(act));
+            act.sa_handler = gdb_sigterm_handler;
+            sigaction(SIGINT, &act, NULL);
+        }
+#endif
+        chr = qemu_chr_open("gdb", device, NULL);
+        if (!chr)
+            return -1;
+
+        qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
+                              gdb_chr_event, NULL);
     }
 
-    chr = qemu_chr_open(port);
-    if (!chr)
-        return -1;
-
-    s = qemu_mallocz(sizeof(GDBState));
+    s = gdbserver_state;
     if (!s) {
-        return -1;
+        s = qemu_mallocz(sizeof(GDBState));
+        gdbserver_state = s;
+
+        qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
+
+        /* Initialize a monitor terminal for gdb */
+        mon_chr = qemu_mallocz(sizeof(*mon_chr));
+        mon_chr->chr_write = gdb_monitor_write;
+        monitor_init(mon_chr, 0);
+    } else {
+        if (s->chr)
+            qemu_chr_close(s->chr);
+        mon_chr = s->mon_chr;
+        memset(s, 0, sizeof(GDBState));
     }
-    s->env = first_cpu; /* XXX: allow to change CPU */
+    s->c_cpu = first_cpu;
+    s->g_cpu = first_cpu;
     s->chr = chr;
-    qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
-                          gdb_chr_event, s);
-    qemu_add_vm_stop_handler(gdb_vm_stopped, s);
+    s->state = chr ? RS_IDLE : RS_INACTIVE;
+    s->mon_chr = mon_chr;
+
     return 0;
 }
 #endif
diff --git a/gdbstub.h b/gdbstub.h
index ba65f93..5740041 100644
--- a/gdbstub.h
+++ b/gdbstub.h
@@ -3,17 +3,33 @@
 
 #define DEFAULT_GDBSTUB_PORT "1234"
 
+/* GDB breakpoint/watchpoint types */
+#define GDB_BREAKPOINT_SW        0
+#define GDB_BREAKPOINT_HW        1
+#define GDB_WATCHPOINT_WRITE     2
+#define GDB_WATCHPOINT_READ      3
+#define GDB_WATCHPOINT_ACCESS    4
+
 typedef void (*gdb_syscall_complete_cb)(CPUState *env,
                                         target_ulong ret, target_ulong err);
 
 void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
 int use_gdb_syscalls(void);
+void gdb_set_stop_cpu(CPUState *env);
 #ifdef CONFIG_USER_ONLY
+int gdb_queuesig (void);
 int gdb_handlesig (CPUState *, int);
 void gdb_exit(CPUState *, int);
+void gdb_signalled(CPUState *, int);
 int gdbserver_start(int);
+void gdbserver_fork(CPUState *);
 #else
 int gdbserver_start(const char *port);
 #endif
+/* Get or set a register.  Returns the size of the register.  */
+typedef int (*gdb_reg_cb)(CPUState *env, uint8_t *buf, int reg);
+void gdb_register_coprocessor(CPUState *env,
+                              gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+                              int num_regs, const char *xml, int g_pos);
 
 #endif
diff --git a/gen-charmap.py b/gen-charmap.py
index 3c86350..418201b 100644
--- a/gen-charmap.py
+++ b/gen-charmap.py
@@ -56,8 +56,12 @@
              'SEMICOLON': 'Semicolon',
              'APOSTROPHE': 'Apostrophe',
              'SPACE': 'Space',
-             'ENTER': 'Enter',
-             'TAB': 'Tab'
+             'ENTER': 'Newline',
+             'TAB': 'Tab',
+             'STAR': 'Star',
+             'POUND': 'Pound',
+             'PLUS': 'Plus',
+             'DEL': 'Del'
            }
 
 entries = []
@@ -86,6 +90,18 @@
     if not m:
         print "character expected in: " + line
         return -1
+    disp = quote(m.group(1))
+    line = m.group(2)
+    m = match_char_or_hex(line)
+    if not m:
+        print "character expected in: " + line
+        return -1
+    number = quote(m.group(1))
+    line = m.group(2)
+    m = match_char_or_hex(line)
+    if not m:
+        print "character expected in: " + line
+        return -1
     base = quote(m.group(1))
     line = m.group(2)
     m = match_char_or_hex(line)
@@ -105,12 +121,6 @@
         print "character expected in: " + line
         return -1
     caps_fn = quote(m.group(1))
-    line = m.group(2)
-    m = match_char_or_hex(line)
-    if not m:
-        print "character expected in: " + line
-        return -1
-    number = quote(m.group(1))
 
     if specials.has_key(keycode):
         keycode = specials[keycode]
diff --git a/gen-icount.h b/gen-icount.h
index 61545f1..d4524d6 100644
--- a/gen-icount.h
+++ b/gen-icount.h
@@ -5,7 +5,7 @@
 
 static inline void gen_icount_start(void)
 {
-    TCGv count;
+    TCGv_i32 count;
 
     if (!use_icount)
         return;
@@ -15,7 +15,7 @@
        count needs to live over the conditional branch.  To workaround this
        we allow the target to supply a convenient register temporary.  */
 #ifndef ICOUNT_TEMP
-    count = tcg_temp_local_new(TCG_TYPE_I32);
+    count = tcg_temp_local_new_i32();
 #else
     count = ICOUNT_TEMP;
 #endif
@@ -27,7 +27,7 @@
     tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label);
     tcg_gen_st16_i32(count, cpu_env, offsetof(CPUState, icount_decr.u16.low));
 #ifndef ICOUNT_TEMP
-    tcg_temp_free(count);
+    tcg_temp_free_i32(count);
 #endif
 }
 
@@ -42,15 +42,14 @@
 
 static void inline gen_io_start(void)
 {
-    TCGv tmp = tcg_const_i32(1);
+    TCGv_i32 tmp = tcg_const_i32(1);
     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io));
-    tcg_temp_free(tmp);
+    tcg_temp_free_i32(tmp);
 }
 
 static inline void gen_io_end(void)
 {
-    TCGv tmp = tcg_const_i32(0);
+    TCGv_i32 tmp = tcg_const_i32(0);
     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, can_do_io));
-    tcg_temp_free(tmp);
+    tcg_temp_free_i32(tmp);
 }
-
diff --git a/host-utils.h b/host-utils.h
index b1e799e..2128615 100644
--- a/host-utils.h
+++ b/host-utils.h
@@ -47,14 +47,16 @@
 void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
 #endif
 
-/* Note that some of those functions may end up calling libgcc functions,
-   depending on the host machine. It is up to the target emulation to
-   cope with that. */
-
 /* Binary search for leading zeros.  */
 
 static always_inline int clz32(uint32_t val)
 {
+#if QEMU_GNUC_PREREQ(3, 4)
+    if (val)
+        return __builtin_clz(val);
+    else
+        return 32;
+#else
     int cnt = 0;
 
     if (!(val & 0xFFFF0000U)) {
@@ -81,6 +83,7 @@
         cnt++;
     }
     return cnt;
+#endif
 }
 
 static always_inline int clo32(uint32_t val)
@@ -90,6 +93,12 @@
 
 static always_inline int clz64(uint64_t val)
 {
+#if QEMU_GNUC_PREREQ(3, 4)
+    if (val)
+        return __builtin_clzll(val);
+    else
+        return 64;
+#else
     int cnt = 0;
 
     if (!(val >> 32)) {
@@ -99,6 +108,7 @@
     }
 
     return cnt + clz32(val);
+#endif
 }
 
 static always_inline int clo64(uint64_t val)
@@ -106,45 +116,58 @@
     return clz64(~val);
 }
 
-static always_inline int ctz32 (uint32_t val)
+static always_inline int ctz32(uint32_t val)
 {
+#if QEMU_GNUC_PREREQ(3, 4)
+    if (val)
+        return __builtin_ctz(val);
+    else
+        return 32;
+#else
     int cnt;
 
     cnt = 0;
     if (!(val & 0x0000FFFFUL)) {
-         cnt += 16;
+        cnt += 16;
         val >>= 16;
-     }
+    }
     if (!(val & 0x000000FFUL)) {
-         cnt += 8;
+        cnt += 8;
         val >>= 8;
-     }
+    }
     if (!(val & 0x0000000FUL)) {
-         cnt += 4;
+        cnt += 4;
         val >>= 4;
-     }
+    }
     if (!(val & 0x00000003UL)) {
-         cnt += 2;
+        cnt += 2;
         val >>= 2;
-     }
+    }
     if (!(val & 0x00000001UL)) {
-         cnt++;
+        cnt++;
         val >>= 1;
-     }
+    }
     if (!(val & 0x00000001UL)) {
-         cnt++;
-     }
+        cnt++;
+    }
 
-     return cnt;
- }
- 
-static always_inline int cto32 (uint32_t val)
- {
+    return cnt;
+#endif
+}
+
+static always_inline int cto32(uint32_t val)
+{
     return ctz32(~val);
 }
 
-static always_inline int ctz64 (uint64_t val)
+static always_inline int ctz64(uint64_t val)
 {
+#if QEMU_GNUC_PREREQ(3, 4)
+    if (val)
+        return __builtin_ctz(val);
+    else
+        return 64;
+#else
     int cnt;
 
     cnt = 0;
@@ -154,14 +177,15 @@
     }
 
     return cnt + ctz32(val);
+#endif
 }
 
-static always_inline int cto64 (uint64_t val)
+static always_inline int cto64(uint64_t val)
 {
     return ctz64(~val);
 }
 
-static always_inline int ctpop8 (uint8_t val)
+static always_inline int ctpop8(uint8_t val)
 {
     val = (val & 0x55) + ((val >> 1) & 0x55);
     val = (val & 0x33) + ((val >> 2) & 0x33);
@@ -170,7 +194,7 @@
     return val;
 }
 
-static always_inline int ctpop16 (uint16_t val)
+static always_inline int ctpop16(uint16_t val)
 {
     val = (val & 0x5555) + ((val >> 1) & 0x5555);
     val = (val & 0x3333) + ((val >> 2) & 0x3333);
@@ -180,8 +204,11 @@
     return val;
 }
 
-static always_inline int ctpop32 (uint32_t val)
+static always_inline int ctpop32(uint32_t val)
 {
+#if QEMU_GNUC_PREREQ(3, 4)
+    return __builtin_popcount(val);
+#else
     val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
     val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
     val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
@@ -189,10 +216,14 @@
     val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
 
     return val;
+#endif
 }
 
-static always_inline int ctpop64 (uint64_t val)
+static always_inline int ctpop64(uint64_t val)
 {
+#if QEMU_GNUC_PREREQ(3, 4)
+    return __builtin_popcountll(val);
+#else
     val = (val & 0x5555555555555555ULL) + ((val >>  1) & 0x5555555555555555ULL);
     val = (val & 0x3333333333333333ULL) + ((val >>  2) & 0x3333333333333333ULL);
     val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) & 0x0f0f0f0f0f0f0f0fULL);
@@ -201,4 +232,5 @@
     val = (val & 0x00000000ffffffffULL) + ((val >> 32) & 0x00000000ffffffffULL);
 
     return val;
+#endif
 }
diff --git a/hostregs_helper.h b/hostregs_helper.h
index 4fdf8ad..c206baf 100644
--- a/hostregs_helper.h
+++ b/hostregs_helper.h
@@ -15,12 +15,12 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 
-/* The GCC global register vairable extension is used to reserve some
-   host registers for use by dyngen.  However only the core parts of the
-   translation engine are compiled with these settings.  We must manually
+/* The GCC global register variable extension is used to reserve some
+   host registers for use by generated code.  However only the core parts of
+   the translation engine are compiled with these settings.  We must manually
    save/restore these registers when called from regular code.
    It is not sufficient to save/restore T0 et. al. as these may be declared
    with a datatype smaller than the actual register.  */
@@ -57,42 +57,6 @@
 DO_REG(2)
 #endif
 
-#ifdef AREG3
-DO_REG(3)
-#endif
-
-#ifdef AREG4
-DO_REG(4)
-#endif
-
-#ifdef AREG5
-DO_REG(5)
-#endif
-
-#ifdef AREG6
-DO_REG(6)
-#endif
-
-#ifdef AREG7
-DO_REG(7)
-#endif
-
-#ifdef AREG8
-DO_REG(8)
-#endif
-
-#ifdef AREG9
-DO_REG(9)
-#endif
-
-#ifdef AREG10
-DO_REG(10)
-#endif
-
-#ifdef AREG11
-DO_REG(11)
-#endif
-
 #undef SAVE_HOST_REGS
 #undef DECLARE_HOST_REGS
 #undef DO_REG
diff --git a/hw/android_arm.c b/hw/android_arm.c
index b178dad..32f6925 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -19,6 +19,7 @@
 #include "android/globals.h"
 #include "audio/audio.h"
 #include "arm-misc.h"
+#include "console.h"
 
 #define ARM_CPU_SAVE_VERSION  1
 
@@ -49,9 +50,8 @@
     return state;
 }
 #endif
-
-static void android_arm_init(ram_addr_t ram_size, int vga_ram_size,
-    const char *boot_device, DisplayState *ds, 
+static void android_arm_init_(ram_addr_t ram_size,
+    const char *boot_device,
     const char *kernel_filename, 
     const char *kernel_cmdline,
     const char *initrd_filename,
@@ -62,15 +62,17 @@
     qemu_irq *goldfish_pic;
     int i;
     struct arm_boot_info  info;
+    ram_addr_t ram_offset;
+    DisplayState*  ds = get_displaystate();
 
     if (!cpu_model)
         cpu_model = "arm926";
 
     env = cpu_init(cpu_model);
-
     register_savevm( "cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, env );
 
-    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+    ram_offset = qemu_ram_alloc(ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
 
     cpu_pic = arm_pic_init_cpu(env);
     goldfish_pic = goldfish_interrupt_init(0xff000000, cpu_pic[ARM_PIC_CPU_IRQ], cpu_pic[ARM_PIC_CPU_FIQ]);
@@ -109,7 +111,6 @@
 
     goldfish_fb_init(ds, 0);
 #ifdef HAS_AUDIO
-    AUD_init();
     goldfish_audio_init(0xff004000, 0, audio_input_source);
 #endif
     {
@@ -160,8 +161,16 @@
 QEMUMachine android_arm_machine = {
     "android_arm",
     "ARM Android Emulator",
-    android_arm_init,
+    android_arm_init_,
     0,
     0,
+    1,
     NULL
 };
+
+static void android_arm_init(void)
+{
+    qemu_register_machine(&android_arm_machine);
+}
+
+machine_init(android_arm_init);
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 707e699..7523d44 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -29,21 +29,15 @@
     const char *kernel_cmdline;
     const char *initrd_filename;
     target_phys_addr_t loader_start;
+    target_phys_addr_t smp_loader_start;
     int nb_cpus;
     int board_id;
     int (*atag_board)(struct arm_boot_info *info, void *p);
 };
 void arm_load_kernel(CPUState *env, struct arm_boot_info *info);
 
-/* armv7m_nvic.c */
-
 /* Multiplication factor to convert from system clock ticks to qemu timer
    ticks.  */
-int system_clock_scale;
-qemu_irq *armv7m_nvic_init(CPUState *env);
-
-/* stellaris_enent.c */
-void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq);
+extern int system_clock_scale;
 
 #endif /* !ARM_MISC_H */
-
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 5990961..acfa67e 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -53,124 +53,135 @@
     /* TODO:  Reset secondary CPUs.  */
 }
 
-static void set_kernel_args(struct arm_boot_info *info,
-                int initrd_size, void *base)
-{
-    uint32_t *p;
+#define WRITE_WORD(p, value) do { \
+    stl_phys_notdirty(p, value);  \
+    p += 4;                       \
+} while (0)
 
-    p = (uint32_t *)(base + KERNEL_ARGS_ADDR);
+static void set_kernel_args(struct arm_boot_info *info,
+                int initrd_size, target_phys_addr_t base)
+{
+    target_phys_addr_t p;
+
+    p = base + KERNEL_ARGS_ADDR;
     /* ATAG_CORE */
-    stl_raw(p++, 5);
-    stl_raw(p++, 0x54410001);
-    stl_raw(p++, 1);
-    stl_raw(p++, 0x1000);
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 5);
+    WRITE_WORD(p, 0x54410001);
+    WRITE_WORD(p, 1);
+    WRITE_WORD(p, 0x1000);
+    WRITE_WORD(p, 0);
     /* ATAG_MEM */
     /* TODO: handle multiple chips on one ATAG list */
-    stl_raw(p++, 4);
-    stl_raw(p++, 0x54410002);
-    stl_raw(p++, info->ram_size);
-    stl_raw(p++, info->loader_start);
+    WRITE_WORD(p, 4);
+    WRITE_WORD(p, 0x54410002);
+    WRITE_WORD(p, info->ram_size);
+    WRITE_WORD(p, info->loader_start);
     if (initrd_size) {
         /* ATAG_INITRD2 */
-        stl_raw(p++, 4);
-        stl_raw(p++, 0x54420005);
-        stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR);
-        stl_raw(p++, initrd_size);
+        WRITE_WORD(p, 4);
+        WRITE_WORD(p, 0x54420005);
+        WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
+        WRITE_WORD(p, initrd_size);
     }
     if (info->kernel_cmdline && *info->kernel_cmdline) {
         /* ATAG_CMDLINE */
         int cmdline_size;
 
         cmdline_size = strlen(info->kernel_cmdline);
-        memcpy(p + 2, info->kernel_cmdline, cmdline_size + 1);
+        cpu_physical_memory_write(p + 8, (void *)info->kernel_cmdline,
+                                  cmdline_size + 1);
         cmdline_size = (cmdline_size >> 2) + 1;
-        stl_raw(p++, cmdline_size + 2);
-        stl_raw(p++, 0x54410009);
-        p += cmdline_size;
+        WRITE_WORD(p, cmdline_size + 2);
+        WRITE_WORD(p, 0x54410009);
+        p += cmdline_size * 4;
     }
     if (info->atag_board) {
         /* ATAG_BOARD */
         int atag_board_len;
+        uint8_t atag_board_buf[0x1000];
 
-        atag_board_len = (info->atag_board(info, p + 2) + 3) >> 2;
-        stl_raw(p++, 2 + atag_board_len);
-        stl_raw(p++, 0x414f4d50);
+        atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3;
+        WRITE_WORD(p, (atag_board_len + 8) >> 2);
+        WRITE_WORD(p, 0x414f4d50);
+        cpu_physical_memory_write(p, atag_board_buf, atag_board_len);
         p += atag_board_len;
     }
     /* ATAG_END */
-    stl_raw(p++, 0);
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
 }
 
 static void set_kernel_args_old(struct arm_boot_info *info,
-                int initrd_size, void *base)
+                int initrd_size, target_phys_addr_t base)
 {
-    uint32_t *p;
-    unsigned char *s;
+    target_phys_addr_t p;
+    const char *s;
+
 
     /* see linux/include/asm-arm/setup.h */
-    p = (uint32_t *)(base + KERNEL_ARGS_ADDR);
+    p = base + KERNEL_ARGS_ADDR;
     /* page_size */
-    stl_raw(p++, 4096);
+    WRITE_WORD(p, 4096);
     /* nr_pages */
-    stl_raw(p++, info->ram_size / 4096);
+    WRITE_WORD(p, info->ram_size / 4096);
     /* ramdisk_size */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
 #define FLAG_READONLY	1
 #define FLAG_RDLOAD	4
 #define FLAG_RDPROMPT	8
     /* flags */
-    stl_raw(p++, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
+    WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
     /* rootdev */
-    stl_raw(p++, (31 << 8) | 0);	/* /dev/mtdblock0 */
+    WRITE_WORD(p, (31 << 8) | 0);	/* /dev/mtdblock0 */
     /* video_num_cols */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* video_num_rows */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* video_x */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* video_y */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* memc_control_reg */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* unsigned char sounddefault */
     /* unsigned char adfsdrives */
     /* unsigned char bytes_per_char_h */
     /* unsigned char bytes_per_char_v */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* pages_in_bank[4] */
-    stl_raw(p++, 0);
-    stl_raw(p++, 0);
-    stl_raw(p++, 0);
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
+    WRITE_WORD(p, 0);
     /* pages_in_vram */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* initrd_start */
     if (initrd_size)
-        stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR);
+        WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
     else
-        stl_raw(p++, 0);
+        WRITE_WORD(p, 0);
     /* initrd_size */
-    stl_raw(p++, initrd_size);
+    WRITE_WORD(p, initrd_size);
     /* rd_start */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* system_rev */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* system_serial_low */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* system_serial_high */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* mem_fclk_21285 */
-    stl_raw(p++, 0);
+    WRITE_WORD(p, 0);
     /* zero unused fields */
-    memset(p, 0, 256 + 1024 -
-           (p - ((uint32_t *)(base + KERNEL_ARGS_ADDR))));
-    s = base + KERNEL_ARGS_ADDR + 256 + 1024;
-    if (info->kernel_cmdline)
-        strcpy (s, info->kernel_cmdline);
-    else
-        stb_raw(s, 0);
+    while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) {
+        WRITE_WORD(p, 0);
+    }
+    s = info->kernel_cmdline;
+    if (s) {
+        cpu_physical_memory_write(p, (void *)s, strlen(s) + 1);
+    } else {
+        WRITE_WORD(p, 0);
+    }
 }
 
 void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
@@ -181,8 +192,6 @@
     int is_linux = 0;
     uint64_t elf_entry;
     target_ulong entry;
-    uint32_t pd;
-    void *loader_phys;
 
     /* Load the kernel.  */
     if (!info->kernel_filename) {
@@ -194,23 +203,20 @@
         if (info->nb_cpus == 0)
             info->nb_cpus = 1;
         env->boot_info = info;
-        qemu_register_reset(main_cpu_reset, env);
+        qemu_register_reset(main_cpu_reset, 0, env);
     }
 
-    pd = cpu_get_physical_page_desc(info->loader_start);
-    loader_phys = phys_ram_base + (pd & TARGET_PAGE_MASK) +
-            (info->loader_start & ~TARGET_PAGE_MASK);
-
     /* Assume that raw images are linux kernels, and ELF images are not.  */
     kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL);
     entry = elf_entry;
     if (kernel_size < 0) {
-        kernel_size = load_uboot(info->kernel_filename, &entry, &is_linux);
+        kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
+                                  &is_linux);
     }
     if (kernel_size < 0) {
-        kernel_size = load_image(info->kernel_filename,
-                                 loader_phys + KERNEL_LOAD_ADDR);
         entry = info->loader_start + KERNEL_LOAD_ADDR;
+        kernel_size = load_image_targphys(info->kernel_filename, entry,
+                                          ram_size - KERNEL_LOAD_ADDR);
         is_linux = 1;
     }
     if (kernel_size < 0) {
@@ -224,8 +230,10 @@
         env->thumb = entry & 1;
     } else {
         if (info->initrd_filename) {
-            initrd_size = load_image(info->initrd_filename,
-                                     loader_phys + INITRD_LOAD_ADDR);
+            initrd_size = load_image_targphys(info->initrd_filename,
+                                              info->loader_start
+                                              + INITRD_LOAD_ADDR,
+                                              ram_size - INITRD_LOAD_ADDR);
             if (initrd_size < 0) {
                 fprintf(stderr, "qemu: could not load initrd '%s'\n",
                         info->initrd_filename);
@@ -238,14 +246,17 @@
         bootloader[2] |= (info->board_id >> 8) & 0xff;
         bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
         bootloader[6] = entry;
-        for (n = 0; n < sizeof(bootloader) / 4; n++)
-            stl_raw(loader_phys + (n * 4), bootloader[n]);
-        if (info->nb_cpus > 1)
-            for (n = 0; n < sizeof(smpboot) / 4; n++)
-                stl_raw(loader_phys + info->ram_size + (n * 4), smpboot[n]);
+        for (n = 0; n < sizeof(bootloader) / 4; n++) {
+            stl_phys_notdirty(info->loader_start + (n * 4), bootloader[n]);
+        }
+        if (info->nb_cpus > 1) {
+            for (n = 0; n < sizeof(smpboot) / 4; n++) {
+                stl_phys_notdirty(info->smp_loader_start + (n * 4), smpboot[n]);
+            }
+        }
         if (old_param)
-            set_kernel_args_old(info, initrd_size, loader_phys);
+            set_kernel_args_old(info, initrd_size, info->loader_start);
         else
-            set_kernel_args(info, initrd_size, loader_phys);
+            set_kernel_args(info, initrd_size, info->loader_start);
     }
 }
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 54e99f4..563397d 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -14,26 +14,27 @@
 //#define DEBUG_GIC
 
 #ifdef DEBUG_GIC
-#define DPRINTF(fmt, args...) \
-do { printf("arm_gic: " fmt , ##args); } while (0)
+#define DPRINTF(fmt, ...) \
+do { printf("arm_gic: " fmt , ## __VA_ARGS__); } while (0)
 #else
-#define DPRINTF(fmt, args...) do {} while(0)
+#define DPRINTF(fmt, ...) do {} while(0)
 #endif
 
 #ifdef NVIC
 static const uint8_t gic_id[] =
 { 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };
-#define GIC_DIST_OFFSET 0
 /* The NVIC has 16 internal vectors.  However these are not exposed
    through the normal GIC interface.  */
 #define GIC_BASE_IRQ    32
 #else
 static const uint8_t gic_id[] =
 { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-#define GIC_DIST_OFFSET 0x1000
 #define GIC_BASE_IRQ    0
 #endif
 
+#define FROM_SYSBUSGIC(type, dev) \
+    DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))
+
 typedef struct gic_irq_state
 {
     /* ??? The documentation seems to imply the enable bits are global, even
@@ -41,7 +42,7 @@
     unsigned enabled:1;
     unsigned pending:NCPU;
     unsigned active:NCPU;
-    unsigned level:1;
+    unsigned level:NCPU;
     unsigned model:1; /* 0 = N:N, 1 = 1:N */
     unsigned trigger:1; /* nonzero = edge triggered.  */
 } gic_irq_state;
@@ -76,7 +77,7 @@
 
 typedef struct gic_state
 {
-    uint32_t base;
+    SysBusDevice busdev;
     qemu_irq parent_irq[NCPU];
     int enabled;
     int cpu_enabled[NCPU];
@@ -94,10 +95,7 @@
     int running_priority[NCPU];
     int current_pending[NCPU];
 
-    qemu_irq *in;
-#ifdef NVIC
-    void *nvic;
-#endif
+    int iomemtype;
 } gic_state;
 
 /* TODO: Many places that call this routine could be optimized.  */
@@ -252,7 +250,6 @@
 
     cpu = gic_get_current_cpu();
     cm = 1 << cpu;
-    offset -= s->base + GIC_DIST_OFFSET;
     if (offset < 0x100) {
 #ifndef NVIC
         if (offset == 0)
@@ -347,7 +344,7 @@
     }
     return res;
 bad_reg:
-    cpu_abort(cpu_single_env, "gic_dist_readb: Bad offset %x\n", (int)offset);
+    hw_error("gic_dist_readb: Bad offset %x\n", (int)offset);
     return 0;
 }
 
@@ -365,9 +362,9 @@
 #ifdef NVIC
     gic_state *s = (gic_state *)opaque;
     uint32_t addr;
-    addr = offset - s->base;
+    addr = offset;
     if (addr < 0x100 || addr > 0xd00)
-        return nvic_readl(s->nvic, addr);
+        return nvic_readl(s, addr);
 #endif
     val = gic_dist_readw(opaque, offset);
     val |= gic_dist_readw(opaque, offset + 2) << 16;
@@ -383,7 +380,6 @@
     int cpu;
 
     cpu = gic_get_current_cpu();
-    offset -= s->base + GIC_DIST_OFFSET;
     if (offset < 0x100) {
 #ifdef NVIC
         goto bad_reg;
@@ -510,7 +506,7 @@
     gic_update(s);
     return;
 bad_reg:
-    cpu_abort(cpu_single_env, "gic_dist_writeb: Bad offset %x\n", (int)offset);
+    hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset);
 }
 
 static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
@@ -526,13 +522,13 @@
     gic_state *s = (gic_state *)opaque;
 #ifdef NVIC
     uint32_t addr;
-    addr = offset - s->base;
+    addr = offset;
     if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
-        nvic_writel(s->nvic, addr, value);
+        nvic_writel(s, addr, value);
         return;
     }
 #endif
-    if (offset - s->base == GIC_DIST_OFFSET + 0xf00) {
+    if (offset == 0xf00) {
         int cpu;
         int irq;
         int mask;
@@ -592,8 +588,7 @@
     case 0x18: /* Highest Pending Interrupt */
         return s->current_pending[cpu];
     default:
-        cpu_abort(cpu_single_env, "gic_cpu_read: Bad offset %x\n",
-                  (int)offset);
+        hw_error("gic_cpu_read: Bad offset %x\n", (int)offset);
         return 0;
     }
 }
@@ -614,8 +609,7 @@
     case 0x10: /* End Of Interrupt */
         return gic_complete_irq(s, cpu, value & 0x3ff);
     default:
-        cpu_abort(cpu_single_env, "gic_cpu_write: Bad offset %x\n",
-                  (int)offset);
+        hw_error("gic_cpu_write: Bad offset %x\n", (int)offset);
         return;
     }
     gic_update(s);
@@ -723,25 +717,16 @@
     return 0;
 }
 
-static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq)
+static void gic_init(gic_state *s)
 {
-    gic_state *s;
-    int iomemtype;
     int i;
 
-    s = (gic_state *)qemu_mallocz(sizeof(gic_state));
-    if (!s)
-        return NULL;
-    s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ);
+    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
     for (i = 0; i < NCPU; i++) {
-        s->parent_irq[i] = parent_irq[i];
+        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
     }
-    iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
-                                       gic_dist_writefn, s);
-    cpu_register_physical_memory(base + GIC_DIST_OFFSET, 0x00001000,
-                                 iomemtype);
-    s->base = base;
+    s->iomemtype = cpu_register_io_memory(gic_dist_readfn,
+                                          gic_dist_writefn, s);
     gic_reset(s);
     register_savevm("arm_gic", -1, 1, gic_save, gic_load, s);
-    return s;
 }
diff --git a/hw/arm_pic.c b/hw/arm_pic.c
index 1fe55b7..f44568c 100644
--- a/hw/arm_pic.c
+++ b/hw/arm_pic.c
@@ -8,14 +8,15 @@
  */
 
 #include "hw.h"
+#include "pc.h"
 #include "arm-misc.h"
 
 /* Stub functions for hardware that doesn't exist.  */
-void pic_info(void)
+void pic_info(Monitor *mon)
 {
 }
 
-void irq_info(void)
+void irq_info(Monitor *mon)
 {
 }
 
@@ -38,7 +39,7 @@
             cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
         break;
     default:
-        cpu_abort(env, "arm_pic_cpu_handler: Bad interrput line %d\n", irq);
+        hw_error("arm_pic_cpu_handler: Bad interrput line %d\n", irq);
     }
 }
 
diff --git a/hw/armv7m.c b/hw/armv7m.c
index b2bad3c..297a3e1 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -7,18 +7,18 @@
  * This code is licenced under the GPL.
  */
 
-#include "hw.h"
+#include "sysbus.h"
 #include "arm-misc.h"
 #include "sysemu.h"
 
 /* Bitbanded IO.  Each word corresponds to a single bit.  */
 
 /* Get the byte address of the real memory for a bitband acess.  */
-static inline uint32_t bitband_addr(uint32_t addr)
+static inline uint32_t bitband_addr(void * opaque, uint32_t addr)
 {
     uint32_t res;
 
-    res = addr & 0xe0000000;
+    res = *(uint32_t *)opaque;
     res |= (addr & 0x1ffffff) >> 5;
     return res;
 
@@ -27,7 +27,7 @@
 static uint32_t bitband_readb(void *opaque, target_phys_addr_t offset)
 {
     uint8_t v;
-    cpu_physical_memory_read(bitband_addr(offset), &v, 1);
+    cpu_physical_memory_read(bitband_addr(opaque, offset), &v, 1);
     return (v & (1 << ((offset >> 2) & 7))) != 0;
 }
 
@@ -37,7 +37,7 @@
     uint32_t addr;
     uint8_t mask;
     uint8_t v;
-    addr = bitband_addr(offset);
+    addr = bitband_addr(opaque, offset);
     mask = (1 << ((offset >> 2) & 7));
     cpu_physical_memory_read(addr, &v, 1);
     if (value & 1)
@@ -52,7 +52,7 @@
     uint32_t addr;
     uint16_t mask;
     uint16_t v;
-    addr = bitband_addr(offset) & ~1;
+    addr = bitband_addr(opaque, offset) & ~1;
     mask = (1 << ((offset >> 2) & 15));
     mask = tswap16(mask);
     cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
@@ -65,7 +65,7 @@
     uint32_t addr;
     uint16_t mask;
     uint16_t v;
-    addr = bitband_addr(offset) & ~1;
+    addr = bitband_addr(opaque, offset) & ~1;
     mask = (1 << ((offset >> 2) & 15));
     mask = tswap16(mask);
     cpu_physical_memory_read(addr, (uint8_t *)&v, 2);
@@ -81,7 +81,7 @@
     uint32_t addr;
     uint32_t mask;
     uint32_t v;
-    addr = bitband_addr(offset) & ~3;
+    addr = bitband_addr(opaque, offset) & ~3;
     mask = (1 << ((offset >> 2) & 31));
     mask = tswap32(mask);
     cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
@@ -94,7 +94,7 @@
     uint32_t addr;
     uint32_t mask;
     uint32_t v;
-    addr = bitband_addr(offset) & ~3;
+    addr = bitband_addr(opaque, offset) & ~3;
     mask = (1 << ((offset >> 2) & 31));
     mask = tswap32(mask);
     cpu_physical_memory_read(addr, (uint8_t *)&v, 4);
@@ -117,14 +117,35 @@
    bitband_writel
 };
 
-static void armv7m_bitband_init(void)
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t base;
+} BitBandState;
+
+static void bitband_init(SysBusDevice *dev)
 {
+    BitBandState *s = FROM_SYSBUS(BitBandState, dev);
     int iomemtype;
 
-    iomemtype = cpu_register_io_memory(0, bitband_readfn, bitband_writefn,
-                                       NULL);
-    cpu_register_physical_memory(0x22000000, 0x02000000, iomemtype);
-    cpu_register_physical_memory(0x42000000, 0x02000000, iomemtype);
+    s->base = qdev_get_prop_int(&dev->qdev, "base", 0);
+    iomemtype = cpu_register_io_memory(bitband_readfn, bitband_writefn,
+                                       &s->base);
+    sysbus_init_mmio(dev, 0x02000000, iomemtype);
+}
+
+static void armv7m_bitband_init(void)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "ARM,bitband-memory");
+    qdev_set_prop_int(dev, "base", 0x20000000);
+    qdev_init(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000);
+
+    dev = qdev_create(NULL, "ARM,bitband-memory");
+    qdev_set_prop_int(dev, "base", 0x40000000);
+    qdev_init(dev);
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000);
 }
 
 /* Board init.  */
@@ -136,11 +157,15 @@
                       const char *kernel_filename, const char *cpu_model)
 {
     CPUState *env;
-    qemu_irq *pic;
+    DeviceState *nvic;
+    /* FIXME: make this local state.  */
+    static qemu_irq pic[64];
+    qemu_irq *cpu_pic;
     uint32_t pc;
     int image_size;
     uint64_t entry;
     uint64_t lowaddr;
+    int i;
 
     flash_size *= 1024;
     sram_size *= 1024;
@@ -166,16 +191,24 @@
 #endif
 
     /* Flash programming is done via the SCU, so pretend it is ROM.  */
-    cpu_register_physical_memory(0, flash_size, IO_MEM_ROM);
+    cpu_register_physical_memory(0, flash_size,
+                                 qemu_ram_alloc(flash_size) | IO_MEM_ROM);
     cpu_register_physical_memory(0x20000000, sram_size,
-                                 flash_size + IO_MEM_RAM);
+                                 qemu_ram_alloc(sram_size) | IO_MEM_RAM);
     armv7m_bitband_init();
 
-    pic = armv7m_nvic_init(env);
+    nvic = qdev_create(NULL, "armv7m_nvic");
+    env->v7m.nvic = nvic;
+    qdev_init(nvic);
+    cpu_pic = arm_pic_init_cpu(env);
+    sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]);
+    for (i = 0; i < 64; i++) {
+        pic[i] = qdev_get_gpio_in(nvic, i);
+    }
 
     image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
     if (image_size < 0) {
-        image_size = load_image(kernel_filename, phys_ram_base);
+        image_size = load_image_targphys(kernel_filename, 0, flash_size);
 	lowaddr = 0;
     }
     if (image_size < 0) {
@@ -188,8 +221,8 @@
        regular ROM image and perform the normal CPU reset sequence.
        Otherwise jump directly to the entry point.  */
     if (lowaddr == 0) {
-	env->regs[13] = tswap32(*(uint32_t *)phys_ram_base);
-	pc = tswap32(*(uint32_t *)(phys_ram_base + 4));
+	env->regs[13] = ldl_phys(0);
+	pc = ldl_phys(4);
     } else {
 	pc = entry;
     }
@@ -199,8 +232,16 @@
     /* Hack to map an additional page of ram at the top of the address
        space.  This stops qemu complaining about executing code outside RAM
        when returning from an exception.  */
-    cpu_register_physical_memory(0xfffff000, 0x1000, IO_MEM_RAM + ram_size);
+    cpu_register_physical_memory(0xfffff000, 0x1000,
+                                 qemu_ram_alloc(0x1000) | IO_MEM_RAM);
 
     return pic;
 }
 
+static void armv7m_register_devices(void)
+{
+    sysbus_register_dev("ARM,bitband-memory", sizeof(BitBandState),
+                        bitband_init);
+}
+
+device_init(armv7m_register_devices)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index c55c958..f789c78 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -10,7 +10,7 @@
  * NVIC.  Much of that is also implemented here.
  */
 
-#include "hw.h"
+#include "sysbus.h"
 #include "qemu-timer.h"
 #include "arm-misc.h"
 
@@ -33,13 +33,13 @@
 #include "arm_gic.c"
 
 typedef struct {
+    gic_state gic;
     struct {
         uint32_t control;
         uint32_t reload;
         int64_t tick;
         QEMUTimer *timer;
     } systick;
-    gic_state *gic;
 } nvic_state;
 
 /* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
@@ -50,6 +50,8 @@
 #define SYSTICK_CLKSOURCE (1 << 2)
 #define SYSTICK_COUNTFLAG (1 << 16)
 
+int system_clock_scale;
+
 /* Conversion factor from qemu timer to SysTick frequencies.  */
 static inline int64_t systick_scale(nvic_state *s)
 {
@@ -89,7 +91,7 @@
     nvic_state *s = (nvic_state *)opaque;
     if (irq >= 16)
         irq += 16;
-    gic_set_pending_private(s->gic, 0, irq);
+    gic_set_pending_private(&s->gic, 0, irq);
 }
 
 /* Make pending IRQ active.  */
@@ -98,9 +100,9 @@
     nvic_state *s = (nvic_state *)opaque;
     uint32_t irq;
 
-    irq = gic_acknowledge_irq(s->gic, 0);
+    irq = gic_acknowledge_irq(&s->gic, 0);
     if (irq == 1023)
-        cpu_abort(cpu_single_env, "Interrupt but no vector\n");
+        hw_error("Interrupt but no vector\n");
     if (irq >= 32)
         irq -= 16;
     return irq;
@@ -111,7 +113,7 @@
     nvic_state *s = (nvic_state *)opaque;
     if (irq >= 16)
         irq += 16;
-    gic_complete_irq(s->gic, 0, irq);
+    gic_complete_irq(&s->gic, 0, irq);
 }
 
 static uint32_t nvic_readl(void *opaque, uint32_t offset)
@@ -151,35 +153,35 @@
         return cpu_single_env->cp15.c0_cpuid;
     case 0xd04: /* Interrypt Control State.  */
         /* VECTACTIVE */
-        val = s->gic->running_irq[0];
+        val = s->gic.running_irq[0];
         if (val == 1023) {
             val = 0;
         } else if (val >= 32) {
             val -= 16;
         }
         /* RETTOBASE */
-        if (s->gic->running_irq[0] == 1023
-                || s->gic->last_active[s->gic->running_irq[0]][0] == 1023) {
+        if (s->gic.running_irq[0] == 1023
+                || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
             val |= (1 << 11);
         }
         /* VECTPENDING */
-        if (s->gic->current_pending[0] != 1023)
-            val |= (s->gic->current_pending[0] << 12);
+        if (s->gic.current_pending[0] != 1023)
+            val |= (s->gic.current_pending[0] << 12);
         /* ISRPENDING */
         for (irq = 32; irq < GIC_NIRQ; irq++) {
-            if (s->gic->irq_state[irq].pending) {
+            if (s->gic.irq_state[irq].pending) {
                 val |= (1 << 22);
                 break;
             }
         }
         /* PENDSTSET */
-        if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending)
+        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
             val |= (1 << 26);
         /* PENDSVSET */
-        if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending)
+        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
             val |= (1 << 28);
         /* NMIPENDSET */
-        if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending)
+        if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
             val |= (1 << 31);
         return val;
     case 0xd08: /* Vector Table Offset.  */
@@ -195,32 +197,31 @@
     case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
         irq = offset - 0xd14;
         val = 0;
-        val = s->gic->priority1[irq++][0];
-        val = s->gic->priority1[irq++][0] << 8;
-        val = s->gic->priority1[irq++][0] << 16;
-        val = s->gic->priority1[irq][0] << 24;
+        val = s->gic.priority1[irq++][0];
+        val = s->gic.priority1[irq++][0] << 8;
+        val = s->gic.priority1[irq++][0] << 16;
+        val = s->gic.priority1[irq][0] << 24;
         return val;
     case 0xd24: /* System Handler Status.  */
         val = 0;
-        if (s->gic->irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
-        if (s->gic->irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
-        if (s->gic->irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
-        if (s->gic->irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
-        if (s->gic->irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
-        if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
-        if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
-        if (s->gic->irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
-        if (s->gic->irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
-        if (s->gic->irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
-        if (s->gic->irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
-        if (s->gic->irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
-        if (s->gic->irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
-        if (s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
+        if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
+        if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
+        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
+        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
+        if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
         return val;
     case 0xd28: /* Configurable Fault Status.  */
         /* TODO: Implement Fault Status.  */
-        cpu_abort(cpu_single_env,
-                  "Not implemented: Configurable Fault Status.");
+        hw_error("Not implemented: Configurable Fault Status.");
         return 0;
     case 0xd2c: /* Hard Fault Status.  */
     case 0xd30: /* Debug Fault Status.  */
@@ -258,7 +259,7 @@
     /* TODO: Implement debug registers.  */
     default:
     bad_reg:
-        cpu_abort(cpu_single_env, "NVIC: Bad read offset 0x%x\n", offset);
+        hw_error("NVIC: Bad read offset 0x%x\n", offset);
     }
 }
 
@@ -306,14 +307,14 @@
         if (value & (1 << 28)) {
             armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
         } else if (value & (1 << 27)) {
-            s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
-            gic_update(s->gic);
+            s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
+            gic_update(&s->gic);
         }
         if (value & (1 << 26)) {
             armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
         } else if (value & (1 << 25)) {
-            s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
-            gic_update(s->gic);
+            s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
+            gic_update(&s->gic);
         }
         break;
     case 0xd08: /* Vector Table Offset.  */
@@ -322,10 +323,10 @@
     case 0xd0c: /* Application Interrupt/Reset Control.  */
         if ((value >> 16) == 0x05fa) {
             if (value & 2) {
-                cpu_abort(cpu_single_env, "VECTCLRACTIVE not implemented");
+                hw_error("VECTCLRACTIVE not implemented");
             }
             if (value & 5) {
-                cpu_abort(cpu_single_env, "System reset");
+                hw_error("System reset");
             }
         }
         break;
@@ -337,19 +338,19 @@
         {
             int irq;
             irq = offset - 0xd14;
-            s->gic->priority1[irq++][0] = value & 0xff;
-            s->gic->priority1[irq++][0] = (value >> 8) & 0xff;
-            s->gic->priority1[irq++][0] = (value >> 16) & 0xff;
-            s->gic->priority1[irq][0] = (value >> 24) & 0xff;
-            gic_update(s->gic);
+            s->gic.priority1[irq++][0] = value & 0xff;
+            s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
+            s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
+            s->gic.priority1[irq][0] = (value >> 24) & 0xff;
+            gic_update(&s->gic);
         }
         break;
     case 0xd24: /* System Handler Control.  */
         /* TODO: Real hardware allows you to set/clear the active bits
            under some circumstances.  We don't implement this.  */
-        s->gic->irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
-        s->gic->irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
-        s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
         break;
     case 0xd28: /* Configurable Fault Status.  */
     case 0xd2c: /* Hard Fault Status.  */
@@ -360,7 +361,7 @@
         goto bad_reg;
     default:
     bad_reg:
-        cpu_abort(cpu_single_env, "NVIC: Bad write offset 0x%x\n", offset);
+        hw_error("NVIC: Bad write offset 0x%x\n", offset);
     }
 }
 
@@ -389,19 +390,19 @@
     return 0;
 }
 
-qemu_irq *armv7m_nvic_init(CPUState *env)
+static void armv7m_nvic_init(SysBusDevice *dev)
 {
-    nvic_state *s;
-    qemu_irq *parent;
+    nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
 
-    parent = arm_pic_init_cpu(env);
-    s = (nvic_state *)qemu_mallocz(sizeof(nvic_state));
-    s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]);
-    s->gic->nvic = s;
+    gic_init(&s->gic);
+    cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype);
     s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s);
-    if (env->v7m.nvic)
-        cpu_abort(env, "CPU can only have one NVIC\n");
-    env->v7m.nvic = s;
     register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s);
-    return s->gic->in;
 }
+
+static void armv7m_nvic_register_devices(void)
+{
+    sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
+}
+
+device_init(armv7m_nvic_register_devices)
diff --git a/hw/audiodev.h b/hw/audiodev.h
index 5f4a211..39a729b 100644
--- a/hw/audiodev.h
+++ b/hw/audiodev.h
@@ -1,17 +1,17 @@
 /* es1370.c */
-int es1370_init (PCIBus *bus, AudioState *s);
+int es1370_init(PCIBus *bus);
 
 /* sb16.c */
-int SB16_init (AudioState *s, qemu_irq *pic);
+int SB16_init(qemu_irq *pic);
 
 /* adlib.c */
-int Adlib_init (AudioState *s, qemu_irq *pic);
+int Adlib_init(qemu_irq *pic);
 
 /* gus.c */
-int GUS_init (AudioState *s, qemu_irq *pic);
+int GUS_init(qemu_irq *pic);
 
 /* ac97.c */
-int ac97_init (PCIBus *buf, AudioState *s);
+int ac97_init(PCIBus *buf);
 
 /* cs4231a.c */
-int cs4231a_init (AudioState *s, qemu_irq *pic);
+int cs4231a_init(qemu_irq *pic);
diff --git a/hw/boards.h b/hw/boards.h
index cfb7c42..4a71e56 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -3,8 +3,8 @@
 #ifndef HW_BOARDS_H
 #define HW_BOARDS_H
 
-typedef void QEMUMachineInitFunc(ram_addr_t ram_size, int vga_ram_size,
-                                 const char *boot_device, DisplayState *ds,
+typedef void QEMUMachineInitFunc(ram_addr_t ram_size,
+                                 const char *boot_device,
                                  const char *kernel_filename,
                                  const char *kernel_cmdline,
                                  const char *initrd_filename,
@@ -14,107 +14,15 @@
     const char *name;
     const char *desc;
     QEMUMachineInitFunc *init;
-#define RAMSIZE_FIXED	(1 << 0)
-    ram_addr_t ram_require;
-    int nodisk_ok;
+    int use_scsi;
+    int max_cpus;
+    int is_default;
     struct QEMUMachine *next;
 } QEMUMachine;
 
 int qemu_register_machine(QEMUMachine *m);
-void register_machines(void);
 
-/* Axis ETRAX.  */
-extern QEMUMachine bareetraxfs_machine;
-
-/* pc.c */
-extern QEMUMachine pc_machine;
-extern QEMUMachine isapc_machine;
-
-/* ppc.c */
-extern QEMUMachine prep_machine;
-extern QEMUMachine core99_machine;
-extern QEMUMachine heathrow_machine;
-extern QEMUMachine ref405ep_machine;
-extern QEMUMachine taihu_machine;
-
-/* mips_r4k.c */
-extern QEMUMachine mips_machine;
-
-/* mips_jazz.c */
-extern QEMUMachine mips_magnum_machine;
-extern QEMUMachine mips_pica61_machine;
-
-/* mips_malta.c */
-extern QEMUMachine mips_malta_machine;
-
-/* mips_mipssim.c */
-extern QEMUMachine mips_mipssim_machine;
-
-/* shix.c */
-extern QEMUMachine shix_machine;
-
-/* r2d.c */
-extern QEMUMachine r2d_machine;
-
-/* sun4m.c */
-extern QEMUMachine ss5_machine, ss10_machine, ss600mp_machine, ss20_machine;
-extern QEMUMachine voyager_machine, ss_lx_machine, ss4_machine, scls_machine;
-extern QEMUMachine sbook_machine;
-extern QEMUMachine ss2_machine;
-extern QEMUMachine ss1000_machine, ss2000_machine;
-
-/* sun4u.c */
-extern QEMUMachine sun4u_machine;
-extern QEMUMachine sun4v_machine;
-
-/* integratorcp.c */
-extern QEMUMachine integratorcp_machine;
-
-/* versatilepb.c */
-extern QEMUMachine versatilepb_machine;
-extern QEMUMachine versatileab_machine;
-
-/* realview.c */
-extern QEMUMachine realview_machine;
-
-/* spitz.c */
-extern QEMUMachine akitapda_machine;
-extern QEMUMachine spitzpda_machine;
-extern QEMUMachine borzoipda_machine;
-extern QEMUMachine terrierpda_machine;
-
-/* palm.c */
-extern QEMUMachine palmte_machine;
-
-/* nseries.c */
-extern QEMUMachine n800_machine;
-extern QEMUMachine n810_machine;
-
-/* gumstix.c */
-extern QEMUMachine connex_machine;
-extern QEMUMachine verdex_machine;
-
-/* stellaris.c */
-extern QEMUMachine lm3s811evb_machine;
-extern QEMUMachine lm3s6965evb_machine;
-
-/* an5206.c */
-extern QEMUMachine an5206_machine;
-
-/* mcf5208.c */
-extern QEMUMachine mcf5208evb_machine;
-
-/* dummy_m68k.c */
-extern QEMUMachine dummy_m68k_machine;
-
-/* mainstone.c */
-extern QEMUMachine mainstone2_machine;
-
-/* musicpal.c */
-extern QEMUMachine musicpal_machine;
-
-/* tosa.c */
-extern QEMUMachine tosapda_machine;
+extern QEMUMachine *current_machine;
 
 /* android_arm.c */
 extern QEMUMachine android_arm_machine;
diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c
new file mode 100644
index 0000000..183441b
--- /dev/null
+++ b/hw/bt-hci-csr.c
@@ -0,0 +1,455 @@
+/*
+ * Bluetooth serial HCI transport.
+ * CSR41814 HCI with H4p vendor extensions.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "qemu-timer.h"
+#include "irq.h"
+#include "sysemu.h"
+#include "net.h"
+#include "bt.h"
+
+struct csrhci_s {
+    int enable;
+    qemu_irq *pins;
+    int pin_state;
+    int modem_state;
+    CharDriverState chr;
+#define FIFO_LEN	4096
+    int out_start;
+    int out_len;
+    int out_size;
+    uint8_t outfifo[FIFO_LEN * 2];
+    uint8_t inpkt[FIFO_LEN];
+    int in_len;
+    int in_hdr;
+    int in_data;
+    QEMUTimer *out_tm;
+    int64_t baud_delay;
+
+    bdaddr_t bd_addr;
+    struct HCIInfo *hci;
+};
+
+/* H4+ packet types */
+enum {
+    H4_CMD_PKT   = 1,
+    H4_ACL_PKT   = 2,
+    H4_SCO_PKT   = 3,
+    H4_EVT_PKT   = 4,
+    H4_NEG_PKT   = 6,
+    H4_ALIVE_PKT = 7,
+};
+
+/* CSR41814 negotiation start magic packet */
+static const uint8_t csrhci_neg_packet[] = {
+    H4_NEG_PKT, 10,
+    0x00, 0xa0, 0x01, 0x00, 0x00,
+    0x4c, 0x00, 0x96, 0x00, 0x00,
+};
+
+/* CSR41814 vendor-specific command OCFs */
+enum {
+    OCF_CSR_SEND_FIRMWARE = 0x000,
+};
+
+static inline void csrhci_fifo_wake(struct csrhci_s *s)
+{
+    if (!s->enable || !s->out_len)
+        return;
+
+    /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
+    if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) &&
+                    s->chr.chr_read) {
+        s->chr.chr_read(s->chr.handler_opaque,
+                        s->outfifo + s->out_start ++, 1);
+        s->out_len --;
+        if (s->out_start >= s->out_size) {
+            s->out_start = 0;
+            s->out_size = FIFO_LEN;
+        }
+    }
+
+    if (s->out_len)
+        qemu_mod_timer(s->out_tm, qemu_get_clock(vm_clock) + s->baud_delay);
+}
+
+#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
+static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
+{
+    int off = s->out_start + s->out_len;
+
+    /* TODO: do the padding here, i.e. align len */
+    s->out_len += len;
+
+    if (off < FIFO_LEN) {
+        if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) {
+            fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
+            exit(-1);
+        }
+        return s->outfifo + off;
+    }
+
+    if (s->out_len > s->out_size) {
+        fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
+        exit(-1);
+    }
+
+    return s->outfifo + off - s->out_size;
+}
+
+static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s,
+                int type, int len)
+{
+    uint8_t *ret = csrhci_out_packetz(s, len + 2);
+
+    *ret ++ = type;
+    *ret ++ = len;
+
+    return ret;
+}
+
+static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s,
+                int evt, int len)
+{
+    uint8_t *ret = csrhci_out_packetz(s,
+                    len + 1 + sizeof(struct hci_event_hdr));
+
+    *ret ++ = H4_EVT_PKT;
+    ((struct hci_event_hdr *) ret)->evt = evt;
+    ((struct hci_event_hdr *) ret)->plen = len;
+
+    return ret + sizeof(struct hci_event_hdr);
+}
+
+static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf,
+                uint8_t *data, int len)
+{
+    int offset;
+    uint8_t *rpkt;
+
+    switch (ocf) {
+    case OCF_CSR_SEND_FIRMWARE:
+        /* Check if this is the bd_address packet */
+        if (len >= 18 + 8 && data[12] == 0x01 && data[13] == 0x00) {
+            offset = 18;
+            s->bd_addr.b[0] = data[offset + 7];	/* Beyond cmd packet end(!?) */
+            s->bd_addr.b[1] = data[offset + 6];
+            s->bd_addr.b[2] = data[offset + 4];
+            s->bd_addr.b[3] = data[offset + 0];
+            s->bd_addr.b[4] = data[offset + 3];
+            s->bd_addr.b[5] = data[offset + 2];
+
+            s->hci->bdaddr_set(s->hci, s->bd_addr.b);
+            fprintf(stderr, "%s: bd_address loaded from firmware: "
+                            "%02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
+                            s->bd_addr.b[0], s->bd_addr.b[1], s->bd_addr.b[2],
+                            s->bd_addr.b[3], s->bd_addr.b[4], s->bd_addr.b[5]);
+        }
+
+        rpkt = csrhci_out_packet_event(s, EVT_VENDOR, 11);
+        /* Status bytes: no error */
+        rpkt[9] = 0x00;
+        rpkt[10] = 0x00;
+        break;
+
+    default:
+        fprintf(stderr, "%s: got a bad CMD packet\n", __FUNCTION__);
+        return;
+    }
+
+    csrhci_fifo_wake(s);
+}
+
+static void csrhci_in_packet(struct csrhci_s *s, uint8_t *pkt)
+{
+    uint8_t *rpkt;
+    int opc;
+
+    switch (*pkt ++) {
+    case H4_CMD_PKT:
+        opc = le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode);
+        if (cmd_opcode_ogf(opc) == OGF_VENDOR_CMD) {
+            csrhci_in_packet_vendor(s, cmd_opcode_ocf(opc),
+                            pkt + sizeof(struct hci_command_hdr),
+                            s->in_len - sizeof(struct hci_command_hdr) - 1);
+            return;
+        }
+
+        /* TODO: if the command is OCF_READ_LOCAL_COMMANDS or the likes,
+         * we need to send it to the HCI layer and then add our supported
+         * commands to the returned mask (such as OGF_VENDOR_CMD).  With
+         * bt-hci.c we could just have hooks for this kind of commands but
+         * we can't with bt-host.c.  */
+
+        s->hci->cmd_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_EVT_PKT:
+        goto bad_pkt;
+
+    case H4_ACL_PKT:
+        s->hci->acl_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_SCO_PKT:
+        s->hci->sco_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_NEG_PKT:
+        if (s->in_hdr != sizeof(csrhci_neg_packet) ||
+                        memcmp(pkt - 1, csrhci_neg_packet, s->in_hdr)) {
+            fprintf(stderr, "%s: got a bad NEG packet\n", __FUNCTION__);
+            return;
+        }
+        pkt += 2;
+
+        rpkt = csrhci_out_packet_csr(s, H4_NEG_PKT, 10);
+
+        *rpkt ++ = 0x20;	/* Operational settings negotation Ok */
+        memcpy(rpkt, pkt, 7); rpkt += 7;
+        *rpkt ++ = 0xff;
+        *rpkt ++ = 0xff;
+        break;
+
+    case H4_ALIVE_PKT:
+        if (s->in_hdr != 4 || pkt[1] != 0x55 || pkt[2] != 0x00) {
+            fprintf(stderr, "%s: got a bad ALIVE packet\n", __FUNCTION__);
+            return;
+        }
+
+        rpkt = csrhci_out_packet_csr(s, H4_ALIVE_PKT, 2);
+
+        *rpkt ++ = 0xcc;
+        *rpkt ++ = 0x00;
+        break;
+
+    default:
+    bad_pkt:
+        /* TODO: error out */
+        fprintf(stderr, "%s: got a bad packet\n", __FUNCTION__);
+        break;
+    }
+
+    csrhci_fifo_wake(s);
+}
+
+static int csrhci_header_len(const uint8_t *pkt)
+{
+    switch (pkt[0]) {
+    case H4_CMD_PKT:
+        return HCI_COMMAND_HDR_SIZE;
+    case H4_EVT_PKT:
+        return HCI_EVENT_HDR_SIZE;
+    case H4_ACL_PKT:
+        return HCI_ACL_HDR_SIZE;
+    case H4_SCO_PKT:
+        return HCI_SCO_HDR_SIZE;
+    case H4_NEG_PKT:
+        return pkt[1] + 1;
+    case H4_ALIVE_PKT:
+        return 3;
+    }
+
+    exit(-1);
+}
+
+static int csrhci_data_len(const uint8_t *pkt)
+{
+    switch (*pkt ++) {
+    case H4_CMD_PKT:
+        /* It seems that vendor-specific command packets for H4+ are all
+         * one byte longer than indicated in the standard header.  */
+        if (le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode) == 0xfc00)
+            return (((struct hci_command_hdr *) pkt)->plen + 1) & ~1;
+
+        return ((struct hci_command_hdr *) pkt)->plen;
+    case H4_EVT_PKT:
+        return ((struct hci_event_hdr *) pkt)->plen;
+    case H4_ACL_PKT:
+        return le16_to_cpu(((struct hci_acl_hdr *) pkt)->dlen);
+    case H4_SCO_PKT:
+        return ((struct hci_sco_hdr *) pkt)->dlen;
+    case H4_NEG_PKT:
+    case H4_ALIVE_PKT:
+        return 0;
+    }
+
+    exit(-1);
+}
+
+static int csrhci_write(struct CharDriverState *chr,
+                const uint8_t *buf, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    int plen = s->in_len;
+
+    if (!s->enable)
+        return 0;
+
+    s->in_len += len;
+    memcpy(s->inpkt + plen, buf, len);
+
+    while (1) {
+        if (s->in_len >= 2 && plen < 2)
+            s->in_hdr = csrhci_header_len(s->inpkt) + 1;
+
+        if (s->in_len >= s->in_hdr && plen < s->in_hdr)
+            s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr;
+
+        if (s->in_len >= s->in_data) {
+            csrhci_in_packet(s, s->inpkt);
+
+            memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data);
+            s->in_len -= s->in_data;
+            s->in_hdr = INT_MAX;
+            s->in_data = INT_MAX;
+            plen = 0;
+        } else
+            break;
+    }
+
+    return len;
+}
+
+static void csrhci_out_hci_packet_event(void *opaque,
+                const uint8_t *data, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);	/* Align */
+
+    *pkt ++ = H4_EVT_PKT;
+    memcpy(pkt, data, len);
+
+    csrhci_fifo_wake(s);
+}
+
+static void csrhci_out_hci_packet_acl(void *opaque,
+                const uint8_t *data, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);	/* Align */
+
+    *pkt ++ = H4_ACL_PKT;
+    pkt[len & ~1] = 0;
+    memcpy(pkt, data, len);
+
+    csrhci_fifo_wake(s);
+}
+
+static int csrhci_ioctl(struct CharDriverState *chr, int cmd, void *arg)
+{
+    QEMUSerialSetParams *ssp;
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    int prev_state = s->modem_state;
+
+    switch (cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        ssp = (QEMUSerialSetParams *) arg;
+        s->baud_delay = ticks_per_sec / ssp->speed;
+        /* Moments later... (but shorter than 100ms) */
+        s->modem_state |= CHR_TIOCM_CTS;
+        break;
+
+    case CHR_IOCTL_SERIAL_GET_TIOCM:
+        *(int *) arg = s->modem_state;
+        break;
+
+    case CHR_IOCTL_SERIAL_SET_TIOCM:
+        s->modem_state = *(int *) arg;
+        if (~s->modem_state & prev_state & CHR_TIOCM_RTS)
+            s->modem_state &= ~CHR_TIOCM_CTS;
+        break;
+
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void csrhci_reset(struct csrhci_s *s)
+{
+    s->out_len = 0;
+    s->out_size = FIFO_LEN;
+    s->in_len = 0;
+    s->baud_delay = ticks_per_sec;
+    s->enable = 0;
+    s->in_hdr = INT_MAX;
+    s->in_data = INT_MAX;
+
+    s->modem_state = 0;
+    /* After a while... (but sooner than 10ms) */
+    s->modem_state |= CHR_TIOCM_CTS;
+
+    memset(&s->bd_addr, 0, sizeof(bdaddr_t));
+}
+
+static void csrhci_out_tick(void *opaque)
+{
+    csrhci_fifo_wake((struct csrhci_s *) opaque);
+}
+
+static void csrhci_pins(void *opaque, int line, int level)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    int state = s->pin_state;
+
+    s->pin_state &= ~(1 << line);
+    s->pin_state |= (!!level) << line;
+
+    if ((state & ~s->pin_state) & (1 << csrhci_pin_reset)) {
+        /* TODO: Disappear from lower layers */
+        csrhci_reset(s);
+    }
+
+    if (s->pin_state == 3 && state != 3) {
+        s->enable = 1;
+        /* TODO: Wake lower layers up */
+    }
+}
+
+qemu_irq *csrhci_pins_get(CharDriverState *chr)
+{
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+
+    return s->pins;
+}
+
+CharDriverState *uart_hci_init(qemu_irq wakeup)
+{
+    struct csrhci_s *s = (struct csrhci_s *)
+            qemu_mallocz(sizeof(struct csrhci_s));
+
+    s->chr.opaque = s;
+    s->chr.chr_write = csrhci_write;
+    s->chr.chr_ioctl = csrhci_ioctl;
+
+    s->hci = qemu_next_hci();
+    s->hci->opaque = s;
+    s->hci->evt_recv = csrhci_out_hci_packet_event;
+    s->hci->acl_recv = csrhci_out_hci_packet_acl;
+
+    s->out_tm = qemu_new_timer(vm_clock, csrhci_out_tick, s);
+    s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
+    csrhci_reset(s);
+
+    return &s->chr;
+}
diff --git a/hw/bt-hci.c b/hw/bt-hci.c
new file mode 100644
index 0000000..a5902b0
--- /dev/null
+++ b/hw/bt-hci.c
@@ -0,0 +1,2228 @@
+/*
+ * QEMU Bluetooth HCI logic.
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "net.h"
+#include "bt.h"
+
+struct bt_hci_s {
+    uint8_t *(*evt_packet)(void *opaque);
+    void (*evt_submit)(void *opaque, int len);
+    void *opaque;
+    uint8_t evt_buf[256];
+
+    uint8_t acl_buf[4096];
+    int acl_len;
+
+    uint16_t asb_handle;
+    uint16_t psb_handle;
+
+    int last_cmd;	/* Note: Always little-endian */
+
+    struct bt_device_s *conn_req_host;
+
+    struct {
+        int inquire;
+        int periodic;
+        int responses_left;
+        int responses;
+        QEMUTimer *inquiry_done;
+        QEMUTimer *inquiry_next;
+        int inquiry_length;
+        int inquiry_period;
+        int inquiry_mode;
+
+#define HCI_HANDLE_OFFSET	0x20
+#define HCI_HANDLES_MAX		0x10
+        struct bt_hci_master_link_s {
+            struct bt_link_s *link;
+            void (*lmp_acl_data)(struct bt_link_s *link,
+                            const uint8_t *data, int start, int len);
+            QEMUTimer *acl_mode_timer;
+        } handle[HCI_HANDLES_MAX];
+        uint32_t role_bmp;
+        int last_handle;
+        int connecting;
+        bdaddr_t awaiting_bdaddr[HCI_HANDLES_MAX];
+    } lm;
+
+    uint8_t event_mask[8];
+    uint16_t voice_setting;	/* Notw: Always little-endian */
+    uint16_t conn_accept_tout;
+    QEMUTimer *conn_accept_timer;
+
+    struct HCIInfo info;
+    struct bt_device_s device;
+};
+
+#define DEFAULT_RSSI_DBM	20
+
+#define hci_from_info(ptr)	container_of((ptr), struct bt_hci_s, info)
+#define hci_from_device(ptr)	container_of((ptr), struct bt_hci_s, device)
+
+struct bt_hci_link_s {
+    struct bt_link_s btlink;
+    uint16_t handle;	/* Local */
+};
+
+/* LMP layer emulation */
+#if 0
+static void bt_submit_lmp(struct bt_device_s *bt, int length, uint8_t *data)
+{
+    int resp, resplen, error, op, tr;
+    uint8_t respdata[17];
+
+    if (length < 1)
+        return;
+
+    tr = *data & 1;
+    op = *(data ++) >> 1;
+    resp = LMP_ACCEPTED;
+    resplen = 2;
+    respdata[1] = op;
+    error = 0;
+    length --;
+
+    if (op >= 0x7c) {	/* Extended opcode */
+        op |= *(data ++) << 8;
+        resp = LMP_ACCEPTED_EXT;
+        resplen = 4;
+        respdata[0] = op >> 8;
+        respdata[1] = op & 0xff;
+        length --;
+    }
+
+    switch (op) {
+    case LMP_ACCEPTED:
+        /* data[0]	Op code
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_ACCEPTED_EXT:
+        /* data[0]	Escape op code
+         * data[1]	Extended op code
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_NOT_ACCEPTED:
+        /* data[0]	Op code
+         * data[1]	Error code
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_NOT_ACCEPTED_EXT:
+        /* data[0]	Op code
+         * data[1]	Extended op code
+         * data[2]	Error code
+         */
+        if (length < 3) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_HOST_CONNECTION_REQ:
+        break;
+
+    case LMP_SETUP_COMPLETE:
+        resp = LMP_SETUP_COMPLETE;
+        resplen = 1;
+        bt->setup = 1;
+        break;
+
+    case LMP_DETACH:
+        /* data[0]	Error code
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        bt->setup = 0;
+        resp = 0;
+        break;
+
+    case LMP_SUPERVISION_TIMEOUT:
+        /* data[0,1]	Supervision timeout
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_QUALITY_OF_SERVICE:
+        resp = 0;
+        /* Fall through */
+    case LMP_QOS_REQ:
+        /* data[0,1]	Poll interval
+         * data[2]	N(BC)
+         */
+        if (length < 3) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_MAX_SLOT:
+        resp = 0;
+        /* Fall through */
+    case LMP_MAX_SLOT_REQ:
+        /* data[0]	Max slots
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_AU_RAND:
+    case LMP_IN_RAND:
+    case LMP_COMB_KEY:
+        /* data[0-15]	Random number
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_AU_RAND) {
+            if (bt->key_present) {
+                resp = LMP_SRES;
+                resplen = 5;
+                /* XXX: [Part H] Section 6.1 on page 801 */
+            } else {
+                error = HCI_PIN_OR_KEY_MISSING;
+                goto not_accepted;
+            }
+        } else if (op == LMP_IN_RAND) {
+            error = HCI_PAIRING_NOT_ALLOWED;
+            goto not_accepted;
+        } else {
+            /* XXX: [Part H] Section 3.2 on page 779 */
+            resp = LMP_UNIT_KEY;
+            resplen = 17;
+            memcpy(respdata + 1, bt->key, 16);
+
+            error = HCI_UNIT_LINK_KEY_USED;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_UNIT_KEY:
+        /* data[0-15]	Key
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        memcpy(bt->key, data, 16);
+        bt->key_present = 1;
+        break;
+
+    case LMP_SRES:
+        /* data[0-3]	Authentication response
+         */
+        if (length < 4) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_CLKOFFSET_REQ:
+        resp = LMP_CLKOFFSET_RES;
+        resplen = 3;
+        respdata[1] = 0x33;
+        respdata[2] = 0x33;
+        break;
+
+    case LMP_CLKOFFSET_RES:
+        /* data[0,1]	Clock offset
+         * (Slave to master only)
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_VERSION_REQ:
+    case LMP_VERSION_RES:
+        /* data[0]	VersNr
+         * data[1,2]	CompId
+         * data[3,4]	SubVersNr
+         */
+        if (length < 5) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_VERSION_REQ) {
+            resp = LMP_VERSION_RES;
+            resplen = 6;
+            respdata[1] = 0x20;
+            respdata[2] = 0xff;
+            respdata[3] = 0xff;
+            respdata[4] = 0xff;
+            respdata[5] = 0xff;
+        } else
+            resp = 0;
+        break;
+
+    case LMP_FEATURES_REQ:
+    case LMP_FEATURES_RES:
+        /* data[0-7]	Features
+         */
+        if (length < 8) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_FEATURES_REQ) {
+            resp = LMP_FEATURES_RES;
+            resplen = 9;
+            respdata[1] = (bt->lmp_caps >> 0) & 0xff;
+            respdata[2] = (bt->lmp_caps >> 8) & 0xff;
+            respdata[3] = (bt->lmp_caps >> 16) & 0xff;
+            respdata[4] = (bt->lmp_caps >> 24) & 0xff;
+            respdata[5] = (bt->lmp_caps >> 32) & 0xff;
+            respdata[6] = (bt->lmp_caps >> 40) & 0xff;
+            respdata[7] = (bt->lmp_caps >> 48) & 0xff;
+            respdata[8] = (bt->lmp_caps >> 56) & 0xff;
+        } else
+            resp = 0;
+        break;
+
+    case LMP_NAME_REQ:
+        /* data[0]	Name offset
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = LMP_NAME_RES;
+        resplen = 17;
+        respdata[1] = data[0];
+        respdata[2] = strlen(bt->lmp_name);
+        memset(respdata + 3, 0x00, 14);
+        if (respdata[2] > respdata[1])
+            memcpy(respdata + 3, bt->lmp_name + respdata[1],
+                            respdata[2] - respdata[1]);
+        break;
+
+    case LMP_NAME_RES:
+        /* data[0]	Name offset
+         * data[1]	Name length
+         * data[2-15]	Name fragment
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    default:
+        error = HCI_UNKNOWN_LMP_PDU;
+        /* Fall through */
+    not_accepted:
+        if (op >> 8) {
+            resp = LMP_NOT_ACCEPTED_EXT;
+            resplen = 5;
+            respdata[0] = op >> 8;
+            respdata[1] = op & 0xff;
+            respdata[2] = error;
+        } else {
+            resp = LMP_NOT_ACCEPTED;
+            resplen = 3;
+            respdata[0] = op & 0xff;
+            respdata[1] = error;
+        }
+    }
+
+    if (resp == 0)
+        return;
+
+    if (resp >> 8) {
+        respdata[0] = resp >> 8;
+        respdata[1] = resp & 0xff;
+    } else
+        respdata[0] = resp & 0xff;
+
+    respdata[0] <<= 1;
+    respdata[0] |= tr;
+}
+
+static void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *data)
+{
+    struct bt_device_s *slave;
+    if (length < 1)
+        return;
+
+    slave = 0;
+#if 0
+    slave = net->slave;
+#endif
+
+    switch (data[0] & 3) {
+    case LLID_ACLC:
+        bt_submit_lmp(slave, length - 1, data + 1);
+        break;
+    case LLID_ACLU_START:
+#if 0
+        bt_sumbit_l2cap(slave, length - 1, data + 1, (data[0] >> 2) & 1);
+        breka;
+#endif
+    default:
+    case LLID_ACLU_CONT:
+        break;
+    }
+}
+#endif
+
+/* HCI layer emulation */
+
+/* Note: we could ignore endiannes because unswapped handles will still
+ * be valid as connection identifiers for the guest - they don't have to
+ * be continuously allocated.  We do it though, to preserve similar
+ * behaviour between hosts.  Some things, like the BD_ADDR cannot be
+ * preserved though (for example if a real hci is used).  */
+#ifdef WORDS_BIGENDIAN
+# define HNDL(raw)	bswap16(raw)
+#else
+# define HNDL(raw)	(raw)
+#endif
+
+static const uint8_t bt_event_reserved_mask[8] = {
+    0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00,
+};
+
+static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci,
+                int evt, int len)
+{
+    uint8_t *packet, mask;
+    int mask_byte;
+
+    if (len > 255) {
+        fprintf(stderr, "%s: HCI event params too long (%ib)\n",
+                        __FUNCTION__, len);
+        exit(-1);
+    }
+
+    mask_byte = (evt - 1) >> 3;
+    mask = 1 << ((evt - 1) & 3);
+    if (mask & bt_event_reserved_mask[mask_byte] & ~hci->event_mask[mask_byte])
+        return NULL;
+
+    packet = hci->evt_packet(hci->opaque);
+    packet[0] = evt;
+    packet[1] = len;
+
+    return &packet[2];
+}
+
+static inline void bt_hci_event(struct bt_hci_s *hci, int evt,
+                void *params, int len)
+{
+    uint8_t *packet = bt_hci_event_start(hci, evt, len);
+
+    if (!packet)
+        return;
+
+    if (len)
+        memcpy(packet, params, len);
+
+    hci->evt_submit(hci->opaque, len + 2);
+}
+
+static inline void bt_hci_event_status(struct bt_hci_s *hci, int status)
+{
+    evt_cmd_status params = {
+        .status	= status,
+        .ncmd	= 1,
+        .opcode	= hci->last_cmd,
+    };
+
+    bt_hci_event(hci, EVT_CMD_STATUS, &params, EVT_CMD_STATUS_SIZE);
+}
+
+static inline void bt_hci_event_complete(struct bt_hci_s *hci,
+                void *ret, int len)
+{
+    uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE,
+                    len + EVT_CMD_COMPLETE_SIZE);
+    evt_cmd_complete *params = (evt_cmd_complete *) packet;
+
+    if (!packet)
+        return;
+
+    params->ncmd	= 1;
+    params->opcode	= hci->last_cmd;
+    if (len)
+        memcpy(&packet[EVT_CMD_COMPLETE_SIZE], ret, len);
+
+    hci->evt_submit(hci->opaque, len + EVT_CMD_COMPLETE_SIZE + 2);
+}
+
+static void bt_hci_inquiry_done(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+    uint8_t status = HCI_SUCCESS;
+
+    if (!hci->lm.periodic)
+        hci->lm.inquire = 0;
+
+    /* The specification is inconsistent about this one.  Page 565 reads
+     * "The event parameters of Inquiry Complete event will have a summary
+     * of the result from the Inquiry process, which reports the number of
+     * nearby Bluetooth devices that responded [so hci->responses].", but
+     * Event Parameters (see page 729) has only Status.  */
+    bt_hci_event(hci, EVT_INQUIRY_COMPLETE, &status, 1);
+}
+
+static void bt_hci_inquiry_result_standard(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    inquiry_info params = {
+        .num_responses		= 1,
+        .bdaddr			= BAINIT(&slave->bd_addr),
+        .pscan_rep_mode		= 0x00,	/* R0 */
+        .pscan_period_mode	= 0x00,	/* P0 - deprecated */
+        .pscan_mode		= 0x00,	/* Standard scan - deprecated */
+        .dev_class[0]		= slave->class[0],
+        .dev_class[1]		= slave->class[1],
+        .dev_class[2]		= slave->class[2],
+        /* TODO: return the clkoff *differenece* */
+        .clock_offset		= slave->clkoff,	/* Note: no swapping */
+    };
+
+    bt_hci_event(hci, EVT_INQUIRY_RESULT, &params, INQUIRY_INFO_SIZE);
+}
+
+static void bt_hci_inquiry_result_with_rssi(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    inquiry_info_with_rssi params = {
+        .num_responses		= 1,
+        .bdaddr			= BAINIT(&slave->bd_addr),
+        .pscan_rep_mode		= 0x00,	/* R0 */
+        .pscan_period_mode	= 0x00,	/* P0 - deprecated */
+        .dev_class[0]		= slave->class[0],
+        .dev_class[1]		= slave->class[1],
+        .dev_class[2]		= slave->class[2],
+        /* TODO: return the clkoff *differenece* */
+        .clock_offset		= slave->clkoff,	/* Note: no swapping */
+        .rssi			= DEFAULT_RSSI_DBM,
+    };
+
+    bt_hci_event(hci, EVT_INQUIRY_RESULT_WITH_RSSI,
+                    &params, INQUIRY_INFO_WITH_RSSI_SIZE);
+}
+
+static void bt_hci_inquiry_result(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    if (!slave->inquiry_scan || !hci->lm.responses_left)
+        return;
+
+    hci->lm.responses_left --;
+    hci->lm.responses ++;
+
+    switch (hci->lm.inquiry_mode) {
+    case 0x00:
+        bt_hci_inquiry_result_standard(hci, slave);
+        return;
+    case 0x01:
+        bt_hci_inquiry_result_with_rssi(hci, slave);
+        return;
+    default:
+        fprintf(stderr, "%s: bad inquiry mode %02x\n", __FUNCTION__,
+                        hci->lm.inquiry_mode);
+        exit(-1);
+    }
+}
+
+static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period)
+{
+    qemu_mod_timer(timer, qemu_get_clock(vm_clock) +
+                    muldiv64(period << 7, ticks_per_sec, 100));
+}
+
+static void bt_hci_inquiry_start(struct bt_hci_s *hci, int length)
+{
+    struct bt_device_s *slave;
+
+    hci->lm.inquiry_length = length;
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        /* Don't uncover ourselves.  */
+        if (slave != &hci->device)
+            bt_hci_inquiry_result(hci, slave);
+
+    /* TODO: register for a callback on a new device's addition to the
+     * scatternet so that if it's added before inquiry_length expires,
+     * an Inquiry Result is generated immediately.  Alternatively re-loop
+     * through the devices on the inquiry_length expiration and report
+     * devices not seen before.  */
+    if (hci->lm.responses_left)
+        bt_hci_mod_timer_1280ms(hci->lm.inquiry_done, hci->lm.inquiry_length);
+    else
+        bt_hci_inquiry_done(hci);
+
+    if (hci->lm.periodic)
+        bt_hci_mod_timer_1280ms(hci->lm.inquiry_next, hci->lm.inquiry_period);
+}
+
+static void bt_hci_inquiry_next(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+
+    hci->lm.responses_left += hci->lm.responses;
+    hci->lm.responses = 0;
+    bt_hci_inquiry_start(hci,  hci->lm.inquiry_length);
+}
+
+static inline int bt_hci_handle_bad(struct bt_hci_s *hci, uint16_t handle)
+{
+    return !(handle & HCI_HANDLE_OFFSET) ||
+            handle >= (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX) ||
+            !hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+}
+
+static inline int bt_hci_role_master(struct bt_hci_s *hci, uint16_t handle)
+{
+    return !!(hci->lm.role_bmp & (1 << (handle & ~HCI_HANDLE_OFFSET)));
+}
+
+static inline struct bt_device_s *bt_hci_remote_dev(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    struct bt_link_s *link = hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+
+    return bt_hci_role_master(hci, handle) ? link->slave : link->host;
+}
+
+static void bt_hci_mode_tick(void *opaque);
+static void bt_hci_lmp_link_establish(struct bt_hci_s *hci,
+                struct bt_link_s *link, int master)
+{
+    hci->lm.handle[hci->lm.last_handle].link = link;
+
+    if (master) {
+        /* We are the master side of an ACL link */
+        hci->lm.role_bmp |= 1 << hci->lm.last_handle;
+
+        hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
+                link->slave->lmp_acl_data;
+    } else {
+        /* We are the slave side of an ACL link */
+        hci->lm.role_bmp &= ~(1 << hci->lm.last_handle);
+
+        hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
+                link->host->lmp_acl_resp;
+    }
+
+    /* Mode */
+    if (master) {
+        link->acl_mode = acl_active;
+        hci->lm.handle[hci->lm.last_handle].acl_mode_timer =
+                qemu_new_timer(vm_clock, bt_hci_mode_tick, link);
+    }
+}
+
+static void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle)
+{
+    handle &= ~HCI_HANDLE_OFFSET;
+    hci->lm.handle[handle].link = NULL;
+
+    if (bt_hci_role_master(hci, handle)) {
+        qemu_del_timer(hci->lm.handle[handle].acl_mode_timer);
+        qemu_free_timer(hci->lm.handle[handle].acl_mode_timer);
+    }
+}
+
+static int bt_hci_connect(struct bt_hci_s *hci, bdaddr_t *bdaddr)
+{
+    struct bt_device_s *slave;
+    struct bt_link_s link;
+
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
+            break;
+    if (!slave || slave == &hci->device)
+        return -ENODEV;
+
+    bacpy(&hci->lm.awaiting_bdaddr[hci->lm.connecting ++], &slave->bd_addr);
+
+    link.slave = slave;
+    link.host = &hci->device;
+    link.slave->lmp_connection_request(&link);	/* Always last */
+
+    return 0;
+}
+
+static void bt_hci_connection_reject(struct bt_hci_s *hci,
+                struct bt_device_s *host, uint8_t because)
+{
+    struct bt_link_s link = {
+        .slave	= &hci->device,
+        .host	= host,
+        /* Rest uninitialised */
+    };
+
+    host->reject_reason = because;
+    host->lmp_connection_complete(&link);
+}
+
+static void bt_hci_connection_reject_event(struct bt_hci_s *hci,
+                bdaddr_t *bdaddr)
+{
+    evt_conn_complete params;
+
+    params.status	= HCI_NO_CONNECTION;
+    params.handle	= 0;
+    bacpy(&params.bdaddr, bdaddr);
+    params.link_type	= ACL_LINK;
+    params.encr_mode	= 0x00;		/* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_connection_accept(struct bt_hci_s *hci,
+                struct bt_device_s *host)
+{
+    struct bt_hci_link_s *link = qemu_mallocz(sizeof(struct bt_hci_link_s));
+    evt_conn_complete params;
+    uint16_t handle;
+    uint8_t status = HCI_SUCCESS;
+    int tries = HCI_HANDLES_MAX;
+
+    /* Make a connection handle */
+    do {
+        while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
+            hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
+        handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
+    } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
+            tries);
+
+    if (!tries) {
+        qemu_free(link);
+        bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES);
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    link->btlink.slave	= &hci->device;
+    link->btlink.host	= host;
+    link->handle = handle;
+
+    /* Link established */
+    bt_hci_lmp_link_establish(hci, &link->btlink, 0);
+
+complete:
+    params.status	= status;
+    params.handle	= HNDL(handle);
+    bacpy(&params.bdaddr, &host->bd_addr);
+    params.link_type	= ACL_LINK;
+    params.encr_mode	= 0x00;		/* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+
+    /* Neets to be done at the very end because it can trigger a (nested)
+     * disconnected, in case the other and had cancelled the request
+     * locally.  */
+    if (status == HCI_SUCCESS) {
+        host->reject_reason = 0;
+        host->lmp_connection_complete(&link->btlink);
+    }
+}
+
+static void bt_hci_lmp_connection_request(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->slave);
+    evt_conn_request params;
+
+    if (hci->conn_req_host) {
+        bt_hci_connection_reject(hci, link->host,
+                                 HCI_REJECTED_LIMITED_RESOURCES);
+        return;
+    }
+    hci->conn_req_host = link->host;
+    /* TODO: if masked and auto-accept, then auto-accept,
+     * if masked and not auto-accept, then auto-reject */
+    /* TODO: kick the hci->conn_accept_timer, timeout after
+     * hci->conn_accept_tout * 0.625 msec */
+
+    bacpy(&params.bdaddr, &link->host->bd_addr);
+    memcpy(&params.dev_class, &link->host->class, sizeof(params.dev_class));
+    params.link_type	= ACL_LINK;
+    bt_hci_event(hci, EVT_CONN_REQUEST, &params, EVT_CONN_REQUEST_SIZE);
+    return;
+}
+
+static void bt_hci_conn_accept_timeout(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+
+    if (!hci->conn_req_host)
+        /* Already accepted or rejected.  If the other end cancelled the
+         * connection request then we still have to reject or accept it
+         * and then we'll get a disconnect.  */
+        return;
+
+    /* TODO */
+}
+
+/* Remove from the list of devices which we wanted to connect to and
+ * are awaiting a response from.  If the callback sees a response from
+ * a device which is not on the list it will assume it's a connection
+ * that's been cancelled by the host in the meantime and immediately
+ * try to detach the link and send a Connection Complete.  */
+static int bt_hci_lmp_connection_ready(struct bt_hci_s *hci,
+                bdaddr_t *bdaddr)
+{
+    int i;
+
+    for (i = 0; i < hci->lm.connecting; i ++)
+        if (!bacmp(&hci->lm.awaiting_bdaddr[i], bdaddr)) {
+            if (i < -- hci->lm.connecting)
+                bacpy(&hci->lm.awaiting_bdaddr[i],
+                                &hci->lm.awaiting_bdaddr[hci->lm.connecting]);
+            return 0;
+        }
+
+    return 1;
+}
+
+static void bt_hci_lmp_connection_complete(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->host);
+    evt_conn_complete params;
+    uint16_t handle;
+    uint8_t status = HCI_SUCCESS;
+    int tries = HCI_HANDLES_MAX;
+
+    if (bt_hci_lmp_connection_ready(hci, &link->slave->bd_addr)) {
+        if (!hci->device.reject_reason)
+            link->slave->lmp_disconnect_slave(link);
+        handle = 0;
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    if (hci->device.reject_reason) {
+        handle = 0;
+        status = hci->device.reject_reason;
+        goto complete;
+    }
+
+    /* Make a connection handle */
+    do {
+        while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
+            hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
+        handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
+    } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
+            tries);
+
+    if (!tries) {
+        link->slave->lmp_disconnect_slave(link);
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    /* Link established */
+    link->handle = handle;
+    bt_hci_lmp_link_establish(hci, link, 1);
+
+complete:
+    params.status	= status;
+    params.handle	= HNDL(handle);
+    params.link_type	= ACL_LINK;
+    bacpy(&params.bdaddr, &link->slave->bd_addr);
+    params.encr_mode	= 0x00;		/* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_disconnect(struct bt_hci_s *hci,
+                uint16_t handle, int reason)
+{
+    struct bt_link_s *btlink =
+            hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+    struct bt_hci_link_s *link;
+    evt_disconn_complete params;
+
+    if (bt_hci_role_master(hci, handle)) {
+        btlink->slave->reject_reason = reason;
+        btlink->slave->lmp_disconnect_slave(btlink);
+        /* The link pointer is invalid from now on */
+
+        goto complete;
+    }
+
+    btlink->host->reject_reason = reason;
+    btlink->host->lmp_disconnect_master(btlink);
+
+    /* We are the slave, we get to clean this burden */
+    link = (struct bt_hci_link_s *) btlink;
+    qemu_free(link);
+
+complete:
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.reason	= HCI_CONNECTION_TERMINATED;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+/* TODO: use only one function */
+static void bt_hci_lmp_disconnect_host(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->host);
+    uint16_t handle = link->handle;
+    evt_disconn_complete params;
+
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.reason	= hci->device.reject_reason;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+    struct bt_hci_s *hci = hci_from_device(btlink->slave);
+    uint16_t handle = link->handle;
+    evt_disconn_complete params;
+
+    qemu_free(link);
+
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.reason	= hci->device.reject_reason;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr)
+{
+    struct bt_device_s *slave;
+    evt_remote_name_req_complete params;
+    int len;
+
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
+            break;
+    if (!slave)
+        return -ENODEV;
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status       = HCI_SUCCESS;
+    bacpy(&params.bdaddr, &slave->bd_addr);
+    len = snprintf(params.name, sizeof(params.name),
+                    "%s", slave->lmp_name ?: "");
+    memset(params.name + len, 0, sizeof(params.name) - len);
+    bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE,
+                    &params, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_features_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    struct bt_device_s *slave;
+    evt_read_remote_features_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    slave = bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.features[0]	= (slave->lmp_caps >>  0) & 0xff;
+    params.features[1]	= (slave->lmp_caps >>  8) & 0xff;
+    params.features[2]	= (slave->lmp_caps >> 16) & 0xff;
+    params.features[3]	= (slave->lmp_caps >> 24) & 0xff;
+    params.features[4]	= (slave->lmp_caps >> 32) & 0xff;
+    params.features[5]	= (slave->lmp_caps >> 40) & 0xff;
+    params.features[6]	= (slave->lmp_caps >> 48) & 0xff;
+    params.features[7]	= (slave->lmp_caps >> 56) & 0xff;
+    bt_hci_event(hci, EVT_READ_REMOTE_FEATURES_COMPLETE,
+                    &params, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_version_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    struct bt_device_s *slave;
+    evt_read_remote_version_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    slave = bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    params.lmp_ver	= 0x03;
+    params.manufacturer	= cpu_to_le16(0xa000);
+    params.lmp_subver	= cpu_to_le16(0xa607);
+    bt_hci_event(hci, EVT_READ_REMOTE_VERSION_COMPLETE,
+                    &params, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_clkoffset_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    struct bt_device_s *slave;
+    evt_read_clock_offset_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    slave = bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status	= HCI_SUCCESS;
+    params.handle	= HNDL(handle);
+    /* TODO: return the clkoff *differenece* */
+    params.clock_offset	= slave->clkoff;	/* Note: no swapping */
+    bt_hci_event(hci, EVT_READ_CLOCK_OFFSET_COMPLETE,
+                    &params, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static void bt_hci_event_mode(struct bt_hci_s *hci, struct bt_link_s *link,
+                uint16_t handle)
+{
+    evt_mode_change params = {
+        .status		= HCI_SUCCESS,
+        .handle		= HNDL(handle),
+        .mode		= link->acl_mode,
+        .interval	= cpu_to_le16(link->acl_interval),
+    };
+
+    bt_hci_event(hci, EVT_MODE_CHANGE, &params, EVT_MODE_CHANGE_SIZE);
+}
+
+static void bt_hci_lmp_mode_change_master(struct bt_hci_s *hci,
+                struct bt_link_s *link, int mode, uint16_t interval)
+{
+    link->acl_mode = mode;
+    link->acl_interval = interval;
+
+    bt_hci_event_mode(hci, link, link->handle);
+
+    link->slave->lmp_mode_change(link);
+}
+
+static void bt_hci_lmp_mode_change_slave(struct bt_link_s *btlink)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+    struct bt_hci_s *hci = hci_from_device(btlink->slave);
+
+    bt_hci_event_mode(hci, btlink, link->handle);
+}
+
+static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle,
+                int interval, int mode)
+{
+    struct bt_hci_master_link_s *link;
+
+    if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
+        return -ENODEV;
+
+    link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
+    if (link->link->acl_mode != acl_active) {
+        bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
+        return 0;
+    }
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    qemu_mod_timer(link->acl_mode_timer, qemu_get_clock(vm_clock) +
+                            muldiv64(interval * 625, ticks_per_sec, 1000000));
+    bt_hci_lmp_mode_change_master(hci, link->link, mode, interval);
+
+    return 0;
+}
+
+static int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode)
+{
+    struct bt_hci_master_link_s *link;
+
+    if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
+        return -ENODEV;
+
+    link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
+    if (link->link->acl_mode != mode) {
+        bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
+
+        return 0;
+    }
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    qemu_del_timer(link->acl_mode_timer);
+    bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0);
+
+    return 0;
+}
+
+static void bt_hci_mode_tick(void *opaque)
+{
+    struct bt_link_s *link = opaque;
+    struct bt_hci_s *hci = hci_from_device(link->host);
+
+    bt_hci_lmp_mode_change_master(hci, link, acl_active, 0);
+}
+
+static void bt_hci_reset(struct bt_hci_s *hci)
+{
+    hci->acl_len = 0;
+    hci->last_cmd = 0;
+    hci->lm.connecting = 0;
+
+    hci->event_mask[0] = 0xff;
+    hci->event_mask[1] = 0xff;
+    hci->event_mask[2] = 0xff;
+    hci->event_mask[3] = 0xff;
+    hci->event_mask[4] = 0xff;
+    hci->event_mask[5] = 0x1f;
+    hci->event_mask[6] = 0x00;
+    hci->event_mask[7] = 0x00;
+    hci->device.inquiry_scan = 0;
+    hci->device.page_scan = 0;
+    if (hci->device.lmp_name)
+        qemu_free((void *) hci->device.lmp_name);
+    hci->device.lmp_name = NULL;
+    hci->device.class[0] = 0x00;
+    hci->device.class[1] = 0x00;
+    hci->device.class[2] = 0x00;
+    hci->voice_setting = 0x0000;
+    hci->conn_accept_tout = 0x1f40;
+    hci->lm.inquiry_mode = 0x00;
+
+    hci->psb_handle = 0x000;
+    hci->asb_handle = 0x000;
+
+    /* XXX: qemu_del_timer(sl->acl_mode_timer); for all links */
+    qemu_del_timer(hci->lm.inquiry_done);
+    qemu_del_timer(hci->lm.inquiry_next);
+    qemu_del_timer(hci->conn_accept_timer);
+}
+
+static void bt_hci_read_local_version_rp(struct bt_hci_s *hci)
+{
+    read_local_version_rp lv = {
+        .status		= HCI_SUCCESS,
+        .hci_ver	= 0x03,
+        .hci_rev	= cpu_to_le16(0xa607),
+        .lmp_ver	= 0x03,
+        .manufacturer	= cpu_to_le16(0xa000),
+        .lmp_subver	= cpu_to_le16(0xa607),
+    };
+
+    bt_hci_event_complete(hci, &lv, READ_LOCAL_VERSION_RP_SIZE);
+}
+
+static void bt_hci_read_local_commands_rp(struct bt_hci_s *hci)
+{
+    read_local_commands_rp lc = {
+        .status		= HCI_SUCCESS,
+        .commands	= {
+            /* Keep updated! */
+            /* Also, keep in sync with hci->device.lmp_caps in bt_new_hci */
+            0xbf, 0x80, 0xf9, 0x03, 0xb2, 0xc0, 0x03, 0xc3,
+            0x00, 0x0f, 0x80, 0x00, 0xc0, 0x00, 0xe8, 0x13,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        },
+    };
+
+    bt_hci_event_complete(hci, &lc, READ_LOCAL_COMMANDS_RP_SIZE);
+}
+
+static void bt_hci_read_local_features_rp(struct bt_hci_s *hci)
+{
+    read_local_features_rp lf = {
+        .status		= HCI_SUCCESS,
+        .features	= {
+            (hci->device.lmp_caps >>  0) & 0xff,
+            (hci->device.lmp_caps >>  8) & 0xff,
+            (hci->device.lmp_caps >> 16) & 0xff,
+            (hci->device.lmp_caps >> 24) & 0xff,
+            (hci->device.lmp_caps >> 32) & 0xff,
+            (hci->device.lmp_caps >> 40) & 0xff,
+            (hci->device.lmp_caps >> 48) & 0xff,
+            (hci->device.lmp_caps >> 56) & 0xff,
+        },
+    };
+
+    bt_hci_event_complete(hci, &lf, READ_LOCAL_FEATURES_RP_SIZE);
+}
+
+static void bt_hci_read_local_ext_features_rp(struct bt_hci_s *hci, int page)
+{
+    read_local_ext_features_rp lef = {
+        .status		= HCI_SUCCESS,
+        .page_num	= page,
+        .max_page_num	= 0x00,
+        .features	= {
+            /* Keep updated! */
+            0x5f, 0x35, 0x85, 0x7e, 0x9b, 0x19, 0x00, 0x80,
+        },
+    };
+    if (page)
+        memset(lef.features, 0, sizeof(lef.features));
+
+    bt_hci_event_complete(hci, &lef, READ_LOCAL_EXT_FEATURES_RP_SIZE);
+}
+
+static void bt_hci_read_buffer_size_rp(struct bt_hci_s *hci)
+{
+    read_buffer_size_rp bs = {
+        /* This can be made configurable, for one standard USB dongle HCI
+         * the four values are cpu_to_le16(0x0180), 0x40,
+         * cpu_to_le16(0x0008), cpu_to_le16(0x0008).  */
+        .status		= HCI_SUCCESS,
+        .acl_mtu	= cpu_to_le16(0x0200),
+        .sco_mtu	= 0,
+        .acl_max_pkt	= cpu_to_le16(0x0001),
+        .sco_max_pkt	= cpu_to_le16(0x0000),
+    };
+
+    bt_hci_event_complete(hci, &bs, READ_BUFFER_SIZE_RP_SIZE);
+}
+
+/* Deprecated in V2.0 (page 661) */
+static void bt_hci_read_country_code_rp(struct bt_hci_s *hci)
+{
+    read_country_code_rp cc ={
+        .status		= HCI_SUCCESS,
+        .country_code	= 0x00,	/* North America & Europe^1 and Japan */
+    };
+
+    bt_hci_event_complete(hci, &cc, READ_COUNTRY_CODE_RP_SIZE);
+
+    /* ^1. Except France, sorry */
+}
+
+static void bt_hci_read_bd_addr_rp(struct bt_hci_s *hci)
+{
+    read_bd_addr_rp ba = {
+        .status = HCI_SUCCESS,
+        .bdaddr = BAINIT(&hci->device.bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &ba, READ_BD_ADDR_RP_SIZE);
+}
+
+static int bt_hci_link_quality_rp(struct bt_hci_s *hci, uint16_t handle)
+{
+    read_link_quality_rp lq = {
+        .status		= HCI_SUCCESS,
+        .handle		= HNDL(handle),
+        .link_quality	= 0xff,
+    };
+
+    if (bt_hci_handle_bad(hci, handle))
+        lq.status = HCI_NO_CONNECTION;
+
+    bt_hci_event_complete(hci, &lq, READ_LINK_QUALITY_RP_SIZE);
+    return 0;
+}
+
+/* Generate a Command Complete event with only the Status parameter */
+static inline void bt_hci_event_complete_status(struct bt_hci_s *hci,
+                uint8_t status)
+{
+    bt_hci_event_complete(hci, &status, 1);
+}
+
+static inline void bt_hci_event_complete_conn_cancel(struct bt_hci_s *hci,
+                uint8_t status, bdaddr_t *bd_addr)
+{
+    create_conn_cancel_rp params = {
+        .status = status,
+        .bdaddr = BAINIT(bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &params, CREATE_CONN_CANCEL_RP_SIZE);
+}
+
+static inline void bt_hci_event_auth_complete(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    evt_auth_complete params = {
+        .status = HCI_SUCCESS,
+        .handle = HNDL(handle),
+    };
+
+    bt_hci_event(hci, EVT_AUTH_COMPLETE, &params, EVT_AUTH_COMPLETE_SIZE);
+}
+
+static inline void bt_hci_event_encrypt_change(struct bt_hci_s *hci,
+                uint16_t handle, uint8_t mode)
+{
+    evt_encrypt_change params = {
+        .status		= HCI_SUCCESS,
+        .handle		= HNDL(handle),
+        .encrypt	= mode,
+    };
+
+    bt_hci_event(hci, EVT_ENCRYPT_CHANGE, &params, EVT_ENCRYPT_CHANGE_SIZE);
+}
+
+static inline void bt_hci_event_complete_name_cancel(struct bt_hci_s *hci,
+                bdaddr_t *bd_addr)
+{
+    remote_name_req_cancel_rp params = {
+        .status = HCI_INVALID_PARAMETERS,
+        .bdaddr = BAINIT(bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &params, REMOTE_NAME_REQ_CANCEL_RP_SIZE);
+}
+
+static inline void bt_hci_event_read_remote_ext_features(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    evt_read_remote_ext_features_complete params = {
+        .status = HCI_UNSUPPORTED_FEATURE,
+        .handle = HNDL(handle),
+        /* Rest uninitialised */
+    };
+
+    bt_hci_event(hci, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE,
+                    &params, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE);
+}
+
+static inline void bt_hci_event_complete_lmp_handle(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    read_lmp_handle_rp params = {
+        .status		= HCI_NO_CONNECTION,
+        .handle		= HNDL(handle),
+        .reserved	= 0,
+        /* Rest uninitialised */
+    };
+
+    bt_hci_event_complete(hci, &params, READ_LMP_HANDLE_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_role_discovery(struct bt_hci_s *hci,
+                int status, uint16_t handle, int master)
+{
+    role_discovery_rp params = {
+        .status		= status,
+        .handle		= HNDL(handle),
+        .role		= master ? 0x00 : 0x01,
+    };
+
+    bt_hci_event_complete(hci, &params, ROLE_DISCOVERY_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_flush(struct bt_hci_s *hci,
+                int status, uint16_t handle)
+{
+    flush_rp params = {
+        .status		= status,
+        .handle		= HNDL(handle),
+    };
+
+    bt_hci_event_complete(hci, &params, FLUSH_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci)
+{
+    read_local_name_rp params;
+    params.status = HCI_SUCCESS;
+    memset(params.name, 0, sizeof(params.name));
+    if (hci->device.lmp_name)
+        strncpy(params.name, hci->device.lmp_name, sizeof(params.name));
+
+    bt_hci_event_complete(hci, &params, READ_LOCAL_NAME_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_conn_accept_timeout(
+                struct bt_hci_s *hci)
+{
+    read_conn_accept_timeout_rp params = {
+        .status		= HCI_SUCCESS,
+        .timeout	= cpu_to_le16(hci->conn_accept_tout),
+    };
+
+    bt_hci_event_complete(hci, &params, READ_CONN_ACCEPT_TIMEOUT_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_scan_enable(struct bt_hci_s *hci)
+{
+    read_scan_enable_rp params = {
+        .status = HCI_SUCCESS,
+        .enable =
+                (hci->device.inquiry_scan ? SCAN_INQUIRY : 0) |
+                (hci->device.page_scan ? SCAN_PAGE : 0),
+    };
+
+    bt_hci_event_complete(hci, &params, READ_SCAN_ENABLE_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_local_class(struct bt_hci_s *hci)
+{
+    read_class_of_dev_rp params;
+
+    params.status = HCI_SUCCESS;
+    memcpy(params.dev_class, hci->device.class, sizeof(params.dev_class));
+
+    bt_hci_event_complete(hci, &params, READ_CLASS_OF_DEV_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_voice_setting(struct bt_hci_s *hci)
+{
+    read_voice_setting_rp params = {
+        .status		= HCI_SUCCESS,
+        .voice_setting	= hci->voice_setting,	/* Note: no swapping */
+    };
+
+    bt_hci_event_complete(hci, &params, READ_VOICE_SETTING_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_inquiry_mode(
+                struct bt_hci_s *hci)
+{
+    read_inquiry_mode_rp params = {
+        .status		= HCI_SUCCESS,
+        .mode		= hci->lm.inquiry_mode,
+    };
+
+    bt_hci_event_complete(hci, &params, READ_INQUIRY_MODE_RP_SIZE);
+}
+
+static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci,
+                uint16_t handle, int packets)
+{
+    uint16_t buf[EVT_NUM_COMP_PKTS_SIZE(1) / 2 + 1];
+    evt_num_comp_pkts *params = (void *) ((uint8_t *) buf + 1);
+
+    params->num_hndl			= 1;
+    params->connection->handle		= HNDL(handle);
+    params->connection->num_packets	= cpu_to_le16(packets);
+
+    bt_hci_event(hci, EVT_NUM_COMP_PKTS, params, EVT_NUM_COMP_PKTS_SIZE(1));
+}
+
+static void bt_submit_hci(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    uint16_t cmd;
+    int paramlen, i;
+
+    if (length < HCI_COMMAND_HDR_SIZE)
+        goto short_hci;
+
+    memcpy(&hci->last_cmd, data, 2);
+
+    cmd = (data[1] << 8) | data[0];
+    paramlen = data[2];
+    if (cmd_opcode_ogf(cmd) == 0 || cmd_opcode_ocf(cmd) == 0)	/* NOP */
+        return;
+
+    data += HCI_COMMAND_HDR_SIZE;
+    length -= HCI_COMMAND_HDR_SIZE;
+
+    if (paramlen > length)
+        return;
+
+#define PARAM(cmd, param)	(((cmd##_cp *) data)->param)
+#define PARAM16(cmd, param)	le16_to_cpup(&PARAM(cmd, param))
+#define PARAMHANDLE(cmd)	HNDL(PARAM(cmd, handle))
+#define LENGTH_CHECK(cmd)	if (length < sizeof(cmd##_cp)) goto short_hci
+    /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp
+     * needs to be updated every time a command is implemented here!  */
+    switch (cmd) {
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY):
+        LENGTH_CHECK(inquiry);
+
+        if (PARAM(inquiry, length) < 1) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquire = 1;
+        hci->lm.periodic = 0;
+        hci->lm.responses_left = PARAM(inquiry, num_rsp) ?: INT_MAX;
+        hci->lm.responses = 0;
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_inquiry_start(hci, PARAM(inquiry, length));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
+        if (!hci->lm.inquire || hci->lm.periodic) {
+            fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
+                            "the Inquiry command has been issued, a Command "
+                            "Status event has been received for the Inquiry "
+                            "command, and before the Inquiry Complete event "
+                            "occurs", __FUNCTION__);
+            bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
+            break;
+        }
+
+        hci->lm.inquire = 0;
+        qemu_del_timer(hci->lm.inquiry_done);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY):
+        LENGTH_CHECK(periodic_inquiry);
+
+        if (!(PARAM(periodic_inquiry, length) <
+                                PARAM16(periodic_inquiry, min_period) &&
+                                PARAM16(periodic_inquiry, min_period) <
+                                PARAM16(periodic_inquiry, max_period)) ||
+                        PARAM(periodic_inquiry, length) < 1 ||
+                        PARAM16(periodic_inquiry, min_period) < 2 ||
+                        PARAM16(periodic_inquiry, max_period) < 3) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquire = 1;
+        hci->lm.periodic = 1;
+        hci->lm.responses_left = PARAM(periodic_inquiry, num_rsp);
+        hci->lm.responses = 0;
+        hci->lm.inquiry_period = PARAM16(periodic_inquiry, max_period);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        bt_hci_inquiry_start(hci, PARAM(periodic_inquiry, length));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY):
+        if (!hci->lm.inquire || !hci->lm.periodic) {
+            fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
+                            "the Inquiry command has been issued, a Command "
+                            "Status event has been received for the Inquiry "
+                            "command, and before the Inquiry Complete event "
+                            "occurs", __FUNCTION__);
+            bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
+            break;
+        }
+        hci->lm.inquire = 0;
+        qemu_del_timer(hci->lm.inquiry_done);
+        qemu_del_timer(hci->lm.inquiry_next);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN):
+        LENGTH_CHECK(create_conn);
+
+        if (hci->lm.connecting >= HCI_HANDLES_MAX) {
+            bt_hci_event_status(hci, HCI_REJECTED_LIMITED_RESOURCES);
+            break;
+        }
+        bt_hci_event_status(hci, HCI_SUCCESS);
+
+        if (bt_hci_connect(hci, &PARAM(create_conn, bdaddr)))
+            bt_hci_connection_reject_event(hci, &PARAM(create_conn, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_DISCONNECT):
+        LENGTH_CHECK(disconnect);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(disconnect))) {
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_disconnect(hci, PARAMHANDLE(disconnect),
+                        PARAM(disconnect, reason));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL):
+        LENGTH_CHECK(create_conn_cancel);
+
+        if (bt_hci_lmp_connection_ready(hci,
+                                &PARAM(create_conn_cancel, bdaddr))) {
+            for (i = 0; i < HCI_HANDLES_MAX; i ++)
+                if (bt_hci_role_master(hci, i) && hci->lm.handle[i].link &&
+                                !bacmp(&hci->lm.handle[i].link->slave->bd_addr,
+                                        &PARAM(create_conn_cancel, bdaddr)))
+                   break;
+
+            bt_hci_event_complete_conn_cancel(hci, i < HCI_HANDLES_MAX ?
+                            HCI_ACL_CONNECTION_EXISTS : HCI_NO_CONNECTION,
+                            &PARAM(create_conn_cancel, bdaddr));
+        } else
+            bt_hci_event_complete_conn_cancel(hci, HCI_SUCCESS,
+                            &PARAM(create_conn_cancel, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ):
+        LENGTH_CHECK(accept_conn_req);
+
+        if (!hci->conn_req_host ||
+                        bacmp(&PARAM(accept_conn_req, bdaddr),
+                                &hci->conn_req_host->bd_addr)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_connection_accept(hci, hci->conn_req_host);
+        hci->conn_req_host = NULL;
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REJECT_CONN_REQ):
+        LENGTH_CHECK(reject_conn_req);
+
+        if (!hci->conn_req_host ||
+                        bacmp(&PARAM(reject_conn_req, bdaddr),
+                                &hci->conn_req_host->bd_addr)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_connection_reject(hci, hci->conn_req_host,
+                        PARAM(reject_conn_req, reason));
+        bt_hci_connection_reject_event(hci, &hci->conn_req_host->bd_addr);
+        hci->conn_req_host = NULL;
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_AUTH_REQUESTED):
+        LENGTH_CHECK(auth_requested);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(auth_requested)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_auth_complete(hci, PARAMHANDLE(auth_requested));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT):
+        LENGTH_CHECK(set_conn_encrypt);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(set_conn_encrypt)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_encrypt_change(hci,
+                            PARAMHANDLE(set_conn_encrypt),
+                            PARAM(set_conn_encrypt, encrypt));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ):
+        LENGTH_CHECK(remote_name_req);
+
+        if (bt_hci_name_req(hci, &PARAM(remote_name_req, bdaddr)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL):
+        LENGTH_CHECK(remote_name_req_cancel);
+
+        bt_hci_event_complete_name_cancel(hci,
+                        &PARAM(remote_name_req_cancel, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES):
+        LENGTH_CHECK(read_remote_features);
+
+        if (bt_hci_features_req(hci, PARAMHANDLE(read_remote_features)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_EXT_FEATURES):
+        LENGTH_CHECK(read_remote_ext_features);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(read_remote_ext_features)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_read_remote_ext_features(hci,
+                            PARAMHANDLE(read_remote_ext_features));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_VERSION):
+        LENGTH_CHECK(read_remote_version);
+
+        if (bt_hci_version_req(hci, PARAMHANDLE(read_remote_version)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_CLOCK_OFFSET):
+        LENGTH_CHECK(read_clock_offset);
+
+        if (bt_hci_clkoffset_req(hci, PARAMHANDLE(read_clock_offset)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_LMP_HANDLE):
+        LENGTH_CHECK(read_lmp_handle);
+
+        /* TODO: */
+        bt_hci_event_complete_lmp_handle(hci, PARAMHANDLE(read_lmp_handle));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_HOLD_MODE):
+        LENGTH_CHECK(hold_mode);
+
+        if (PARAM16(hold_mode, min_interval) >
+                        PARAM16(hold_mode, max_interval) ||
+                        PARAM16(hold_mode, min_interval) < 0x0002 ||
+                        PARAM16(hold_mode, max_interval) > 0xff00 ||
+                        (PARAM16(hold_mode, min_interval) & 1) ||
+                        (PARAM16(hold_mode, max_interval) & 1)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        if (bt_hci_mode_change(hci, PARAMHANDLE(hold_mode),
+                                PARAM16(hold_mode, max_interval),
+                                acl_hold))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_PARK_MODE):
+        LENGTH_CHECK(park_mode);
+
+        if (PARAM16(park_mode, min_interval) >
+                        PARAM16(park_mode, max_interval) ||
+                        PARAM16(park_mode, min_interval) < 0x000e ||
+                        (PARAM16(park_mode, min_interval) & 1) ||
+                        (PARAM16(park_mode, max_interval) & 1)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        if (bt_hci_mode_change(hci, PARAMHANDLE(park_mode),
+                                PARAM16(park_mode, max_interval),
+                                acl_parked))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_EXIT_PARK_MODE):
+        LENGTH_CHECK(exit_park_mode);
+
+        if (bt_hci_mode_cancel(hci, PARAMHANDLE(exit_park_mode),
+                                acl_parked))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_ROLE_DISCOVERY):
+        LENGTH_CHECK(role_discovery);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(role_discovery)))
+            bt_hci_event_complete_role_discovery(hci,
+                            HCI_NO_CONNECTION, PARAMHANDLE(role_discovery), 0);
+        else
+            bt_hci_event_complete_role_discovery(hci,
+                            HCI_SUCCESS, PARAMHANDLE(role_discovery),
+                            bt_hci_role_master(hci,
+                                    PARAMHANDLE(role_discovery)));
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_MASK):
+        LENGTH_CHECK(set_event_mask);
+
+        memcpy(hci->event_mask, PARAM(set_event_mask, mask), 8);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET):
+        bt_hci_reset(hci);
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_FLT):
+        if (length >= 1 && PARAM(set_event_flt, flt_type) == FLT_CLEAR_ALL)
+            /* No length check */;
+        else
+            LENGTH_CHECK(set_event_flt);
+
+        /* Filters are not implemented */
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_FLUSH):
+        LENGTH_CHECK(flush);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(flush)))
+            bt_hci_event_complete_flush(hci,
+                            HCI_NO_CONNECTION, PARAMHANDLE(flush));
+        else {
+            /* TODO: ordering? */
+            bt_hci_event(hci, EVT_FLUSH_OCCURRED,
+                            &PARAM(flush, handle),
+                            EVT_FLUSH_OCCURRED_SIZE);
+            bt_hci_event_complete_flush(hci,
+                            HCI_SUCCESS, PARAMHANDLE(flush));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
+        LENGTH_CHECK(change_local_name);
+
+        if (hci->device.lmp_name)
+            qemu_free((void *) hci->device.lmp_name);
+        hci->device.lmp_name = qemu_strndup(PARAM(change_local_name, name),
+                        sizeof(PARAM(change_local_name, name)));
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME):
+        bt_hci_event_complete_read_local_name(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CONN_ACCEPT_TIMEOUT):
+        bt_hci_event_complete_read_conn_accept_timeout(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CONN_ACCEPT_TIMEOUT):
+        /* TODO */
+        LENGTH_CHECK(write_conn_accept_timeout);
+
+        if (PARAM16(write_conn_accept_timeout, timeout) < 0x0001 ||
+                        PARAM16(write_conn_accept_timeout, timeout) > 0xb540) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->conn_accept_tout = PARAM16(write_conn_accept_timeout, timeout);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):
+        bt_hci_event_complete_read_scan_enable(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
+        LENGTH_CHECK(write_scan_enable);
+
+        /* TODO: check that the remaining bits are all 0 */
+        hci->device.inquiry_scan =
+                !!(PARAM(write_scan_enable, scan_enable) & SCAN_INQUIRY);
+        hci->device.page_scan =
+                !!(PARAM(write_scan_enable, scan_enable) & SCAN_PAGE);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV):
+        bt_hci_event_complete_read_local_class(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
+        LENGTH_CHECK(write_class_of_dev);
+
+        memcpy(hci->device.class, PARAM(write_class_of_dev, dev_class),
+                        sizeof(PARAM(write_class_of_dev, dev_class)));
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_VOICE_SETTING):
+        bt_hci_event_complete_voice_setting(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING):
+        LENGTH_CHECK(write_voice_setting);
+
+        hci->voice_setting = PARAM(write_voice_setting, voice_setting);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_HOST_NUMBER_OF_COMPLETED_PACKETS):
+        if (length < data[0] * 2 + 1)
+            goto short_hci;
+
+        for (i = 0; i < data[0]; i ++)
+            if (bt_hci_handle_bad(hci,
+                                    data[i * 2 + 1] | (data[i * 2 + 2] << 8)))
+                bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQUIRY_MODE):
+        /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x40)
+         * else
+         *     goto unknown_command */
+        bt_hci_event_complete_read_inquiry_mode(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE):
+        /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x80)
+         * else
+         *     goto unknown_command */
+        LENGTH_CHECK(write_inquiry_mode);
+
+        if (PARAM(write_inquiry_mode, mode) > 0x01) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquiry_mode = PARAM(write_inquiry_mode, mode);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
+        bt_hci_read_local_version_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_COMMANDS):
+        bt_hci_read_local_commands_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES):
+        bt_hci_read_local_features_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES):
+        LENGTH_CHECK(read_local_ext_features);
+
+        bt_hci_read_local_ext_features_rp(hci,
+                        PARAM(read_local_ext_features, page_num));
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE):
+        bt_hci_read_buffer_size_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_COUNTRY_CODE):
+        bt_hci_read_country_code_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR):
+        bt_hci_read_bd_addr_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_STATUS_PARAM, OCF_READ_LINK_QUALITY):
+        LENGTH_CHECK(read_link_quality);
+
+        bt_hci_link_quality_rp(hci, PARAMHANDLE(read_link_quality));
+        break;
+
+    default:
+        bt_hci_event_status(hci, HCI_UNKNOWN_COMMAND);
+        break;
+
+    short_hci:
+        fprintf(stderr, "%s: HCI packet too short (%iB)\n",
+                        __FUNCTION__, length);
+        bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+        break;
+    }
+}
+
+/* We could perform fragmentation here, we can't do "recombination" because
+ * at this layer the length of the payload is not know ahead, so we only
+ * know that a packet contained the last fragment of the SDU when the next
+ * SDU starts.  */
+static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle,
+                const uint8_t *data, int start, int len)
+{
+    struct hci_acl_hdr *pkt = (void *) hci->acl_buf;
+
+    /* TODO: packet flags */
+    /* TODO: avoid memcpy'ing */
+
+    if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) {
+        fprintf(stderr, "%s: can't take ACL packets %i bytes long\n",
+                        __FUNCTION__, len);
+        return;
+    }
+    memcpy(hci->acl_buf + HCI_ACL_HDR_SIZE, data, len);
+
+    pkt->handle = cpu_to_le16(
+                    acl_handle_pack(handle, start ? ACL_START : ACL_CONT));
+    pkt->dlen = cpu_to_le16(len);
+    hci->info.acl_recv(hci->info.opaque,
+                    hci->acl_buf, len + HCI_ACL_HDR_SIZE);
+}
+
+static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink,
+                const uint8_t *data, int start, int len)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+
+    bt_hci_lmp_acl_data(hci_from_device(btlink->slave),
+                    link->handle, data, start, len);
+}
+
+static void bt_hci_lmp_acl_data_host(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    bt_hci_lmp_acl_data(hci_from_device(link->host),
+                    link->handle, data, start, len);
+}
+
+static void bt_submit_acl(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    uint16_t handle;
+    int datalen, flags;
+    struct bt_link_s *link;
+
+    if (length < HCI_ACL_HDR_SIZE) {
+        fprintf(stderr, "%s: ACL packet too short (%iB)\n",
+                        __FUNCTION__, length);
+        return;
+    }
+
+    handle = acl_handle((data[1] << 8) | data[0]);
+    flags = acl_flags((data[1] << 8) | data[0]);
+    datalen = (data[3] << 8) | data[2];
+    data += HCI_ACL_HDR_SIZE;
+    length -= HCI_ACL_HDR_SIZE;
+
+    if (bt_hci_handle_bad(hci, handle)) {
+        fprintf(stderr, "%s: invalid ACL handle %03x\n",
+                        __FUNCTION__, handle);
+        /* TODO: signal an error */
+        return;
+    }
+    handle &= ~HCI_HANDLE_OFFSET;
+
+    if (datalen > length) {
+        fprintf(stderr, "%s: ACL packet too short (%iB < %iB)\n",
+                        __FUNCTION__, length, datalen);
+        return;
+    }
+
+    link = hci->lm.handle[handle].link;
+
+    if ((flags & ~3) == ACL_ACTIVE_BCAST) {
+        if (!hci->asb_handle)
+            hci->asb_handle = handle;
+        else if (handle != hci->asb_handle) {
+            fprintf(stderr, "%s: Bad handle %03x in Active Slave Broadcast\n",
+                            __FUNCTION__, handle);
+            /* TODO: signal an error */
+            return;
+        }
+
+        /* TODO */
+    }
+
+    if ((flags & ~3) == ACL_PICO_BCAST) {
+        if (!hci->psb_handle)
+            hci->psb_handle = handle;
+        else if (handle != hci->psb_handle) {
+            fprintf(stderr, "%s: Bad handle %03x in Parked Slave Broadcast\n",
+                            __FUNCTION__, handle);
+            /* TODO: signal an error */
+            return;
+        }
+
+        /* TODO */
+    }
+
+    /* TODO: increase counter and send EVT_NUM_COMP_PKTS */
+    bt_hci_event_num_comp_pkts(hci, handle | HCI_HANDLE_OFFSET, 1);
+
+    /* Do this last as it can trigger further events even in this HCI */
+    hci->lm.handle[handle].lmp_acl_data(link, data,
+                    (flags & 3) == ACL_START, length);
+}
+
+static void bt_submit_sco(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    struct bt_link_s *link;
+    uint16_t handle;
+    int datalen;
+
+    if (length < 3)
+        return;
+
+    handle = acl_handle((data[1] << 8) | data[0]);
+    datalen = data[2];
+    data += 3;
+    length -= 3;
+
+    if (bt_hci_handle_bad(hci, handle)) {
+        fprintf(stderr, "%s: invalid SCO handle %03x\n",
+                        __FUNCTION__, handle);
+        return;
+    }
+    handle &= ~HCI_HANDLE_OFFSET;
+
+    if (datalen > length) {
+        fprintf(stderr, "%s: SCO packet too short (%iB < %iB)\n",
+                        __FUNCTION__, length, datalen);
+        return;
+    }
+
+    link = hci->lm.handle[handle].link;
+    /* TODO */
+
+    /* TODO: increase counter and send EVT_NUM_COMP_PKTS if synchronous
+     * Flow Control is enabled.
+     * (See Read/Write_Synchronous_Flow_Control_Enable on page 513 and
+     * page 514.)  */
+}
+
+static uint8_t *bt_hci_evt_packet(void *opaque)
+{
+    /* TODO: allocate a packet from upper layer */
+    struct bt_hci_s *s = opaque;
+
+    return s->evt_buf;
+}
+
+static void bt_hci_evt_submit(void *opaque, int len)
+{
+    /* TODO: notify upper layer */
+    struct bt_hci_s *s = opaque;
+
+    s->info.evt_recv(s->info.opaque, s->evt_buf, len);
+}
+
+static int bt_hci_bdaddr_set(struct HCIInfo *info, const uint8_t *bd_addr)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+
+    bacpy(&hci->device.bd_addr, (const bdaddr_t *) bd_addr);
+    return 0;
+}
+
+static void bt_hci_done(struct HCIInfo *info);
+static void bt_hci_destroy(struct bt_device_s *dev)
+{
+    struct bt_hci_s *hci = hci_from_device(dev);
+
+    bt_hci_done(&hci->info);
+}
+
+struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net)
+{
+    struct bt_hci_s *s = qemu_mallocz(sizeof(struct bt_hci_s));
+
+    s->lm.inquiry_done = qemu_new_timer(vm_clock, bt_hci_inquiry_done, s);
+    s->lm.inquiry_next = qemu_new_timer(vm_clock, bt_hci_inquiry_next, s);
+    s->conn_accept_timer =
+            qemu_new_timer(vm_clock, bt_hci_conn_accept_timeout, s);
+
+    s->evt_packet = bt_hci_evt_packet;
+    s->evt_submit = bt_hci_evt_submit;
+    s->opaque = s;
+
+    bt_device_init(&s->device, net);
+    s->device.lmp_connection_request = bt_hci_lmp_connection_request;
+    s->device.lmp_connection_complete = bt_hci_lmp_connection_complete;
+    s->device.lmp_disconnect_master = bt_hci_lmp_disconnect_host;
+    s->device.lmp_disconnect_slave = bt_hci_lmp_disconnect_slave;
+    s->device.lmp_acl_data = bt_hci_lmp_acl_data_slave;
+    s->device.lmp_acl_resp = bt_hci_lmp_acl_data_host;
+    s->device.lmp_mode_change = bt_hci_lmp_mode_change_slave;
+
+    /* Keep updated! */
+    /* Also keep in sync with supported commands bitmask in
+     * bt_hci_read_local_commands_rp */
+    s->device.lmp_caps = 0x8000199b7e85355fll;
+
+    bt_hci_reset(s);
+
+    s->info.cmd_send = bt_submit_hci;
+    s->info.sco_send = bt_submit_sco;
+    s->info.acl_send = bt_submit_acl;
+    s->info.bdaddr_set = bt_hci_bdaddr_set;
+
+    s->device.handle_destroy = bt_hci_destroy;
+
+    return &s->info;
+}
+
+static void bt_hci_done(struct HCIInfo *info)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    int handle;
+
+    bt_device_done(&hci->device);
+
+    if (hci->device.lmp_name)
+        qemu_free((void *) hci->device.lmp_name);
+
+    /* Be gentle and send DISCONNECT to all connected peers and those
+     * currently waiting for us to accept or reject a connection request.
+     * This frees the links.  */
+    if (hci->conn_req_host) {
+        bt_hci_connection_reject(hci,
+                                 hci->conn_req_host, HCI_OE_POWER_OFF);
+        return;
+    }
+
+    for (handle = HCI_HANDLE_OFFSET;
+                    handle < (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX); handle ++)
+        if (!bt_hci_handle_bad(hci, handle))
+            bt_hci_disconnect(hci, handle, HCI_OE_POWER_OFF);
+
+    /* TODO: this is not enough actually, there may be slaves from whom
+     * we have requested a connection who will soon (or not) respond with
+     * an accept or a reject, so we should also check if hci->lm.connecting
+     * is non-zero and if so, avoid freeing the hci but otherwise disappear
+     * from all qemu social life (e.g. stop scanning and request to be
+     * removed from s->device.net) and arrange for
+     * s->device.lmp_connection_complete to free the remaining bits once
+     * hci->lm.awaiting_bdaddr[] is empty.  */
+
+    qemu_free_timer(hci->lm.inquiry_done);
+    qemu_free_timer(hci->lm.inquiry_next);
+    qemu_free_timer(hci->conn_accept_timer);
+
+    qemu_free(hci);
+}
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
new file mode 100644
index 0000000..af0c3d5
--- /dev/null
+++ b/hw/bt-hid.c
@@ -0,0 +1,571 @@
+/*
+ * QEMU Bluetooth HID Profile wrapper for USB HID.
+ *
+ * Copyright (C) 2007-2008 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "qemu-common.h"
+#include "usb.h"
+#include "bt.h"
+
+enum hid_transaction_req {
+    BT_HANDSHAKE			= 0x0,
+    BT_HID_CONTROL			= 0x1,
+    BT_GET_REPORT			= 0x4,
+    BT_SET_REPORT			= 0x5,
+    BT_GET_PROTOCOL			= 0x6,
+    BT_SET_PROTOCOL			= 0x7,
+    BT_GET_IDLE				= 0x8,
+    BT_SET_IDLE				= 0x9,
+    BT_DATA				= 0xa,
+    BT_DATC				= 0xb,
+};
+
+enum hid_transaction_handshake {
+    BT_HS_SUCCESSFUL			= 0x0,
+    BT_HS_NOT_READY			= 0x1,
+    BT_HS_ERR_INVALID_REPORT_ID		= 0x2,
+    BT_HS_ERR_UNSUPPORTED_REQUEST	= 0x3,
+    BT_HS_ERR_INVALID_PARAMETER		= 0x4,
+    BT_HS_ERR_UNKNOWN			= 0xe,
+    BT_HS_ERR_FATAL			= 0xf,
+};
+
+enum hid_transaction_control {
+    BT_HC_NOP				= 0x0,
+    BT_HC_HARD_RESET			= 0x1,
+    BT_HC_SOFT_RESET			= 0x2,
+    BT_HC_SUSPEND			= 0x3,
+    BT_HC_EXIT_SUSPEND			= 0x4,
+    BT_HC_VIRTUAL_CABLE_UNPLUG		= 0x5,
+};
+
+enum hid_protocol {
+    BT_HID_PROTO_BOOT			= 0,
+    BT_HID_PROTO_REPORT			= 1,
+};
+
+enum hid_boot_reportid {
+    BT_HID_BOOT_INVALID			= 0,
+    BT_HID_BOOT_KEYBOARD,
+    BT_HID_BOOT_MOUSE,
+};
+
+enum hid_data_pkt {
+    BT_DATA_OTHER			= 0,
+    BT_DATA_INPUT,
+    BT_DATA_OUTPUT,
+    BT_DATA_FEATURE,
+};
+
+#define BT_HID_MTU			48
+
+/* HID interface requests */
+#define GET_REPORT			0xa101
+#define GET_IDLE			0xa102
+#define GET_PROTOCOL			0xa103
+#define SET_REPORT			0x2109
+#define SET_IDLE			0x210a
+#define SET_PROTOCOL			0x210b
+
+struct bt_hid_device_s {
+    struct bt_l2cap_device_s btdev;
+    struct bt_l2cap_conn_params_s *control;
+    struct bt_l2cap_conn_params_s *interrupt;
+    USBDevice *usbdev;
+
+    int proto;
+    int connected;
+    int data_type;
+    int intr_state;
+    struct {
+        int len;
+        uint8_t buffer[1024];
+    } dataother, datain, dataout, feature, intrdataout;
+    enum {
+        bt_state_ready,
+        bt_state_transaction,
+        bt_state_suspend,
+    } state;
+};
+
+static void bt_hid_reset(struct bt_hid_device_s *s)
+{
+    struct bt_scatternet_s *net = s->btdev.device.net;
+
+    /* Go as far as... */
+    bt_l2cap_device_done(&s->btdev);
+    bt_l2cap_device_init(&s->btdev, net);
+
+    s->usbdev->handle_reset(s->usbdev);
+    s->proto = BT_HID_PROTO_REPORT;
+    s->state = bt_state_ready;
+    s->dataother.len = 0;
+    s->datain.len = 0;
+    s->dataout.len = 0;
+    s->feature.len = 0;
+    s->intrdataout.len = 0;
+    s->intr_state = 0;
+}
+
+static int bt_hid_out(struct bt_hid_device_s *s)
+{
+    USBPacket p;
+
+    if (s->data_type == BT_DATA_OUTPUT) {
+        p.pid = USB_TOKEN_OUT;
+        p.devep = 1;
+        p.data = s->dataout.buffer;
+        p.len = s->dataout.len;
+        s->dataout.len = s->usbdev->handle_data(s->usbdev, &p);
+
+        return s->dataout.len;
+    }
+
+    if (s->data_type == BT_DATA_FEATURE) {
+        /* XXX:
+         * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
+         * or a SET_REPORT? */
+        p.devep = 0;
+    }
+
+    return -1;
+}
+
+static int bt_hid_in(struct bt_hid_device_s *s)
+{
+    USBPacket p;
+
+    p.pid = USB_TOKEN_IN;
+    p.devep = 1;
+    p.data = s->datain.buffer;
+    p.len = sizeof(s->datain.buffer);
+    s->datain.len = s->usbdev->handle_data(s->usbdev, &p);
+
+    return s->datain.len;
+}
+
+static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result)
+{
+    *s->control->sdu_out(s->control, 1) =
+            (BT_HANDSHAKE << 4) | result;
+    s->control->sdu_submit(s->control);
+}
+
+static void bt_hid_send_control(struct bt_hid_device_s *s, int operation)
+{
+    *s->control->sdu_out(s->control, 1) =
+            (BT_HID_CONTROL << 4) | operation;
+    s->control->sdu_submit(s->control);
+}
+
+static void bt_hid_disconnect(struct bt_hid_device_s *s)
+{
+    /* Disconnect s->control and s->interrupt */
+}
+
+static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
+                const uint8_t *data, int len)
+{
+    uint8_t *pkt, hdr = (BT_DATA << 4) | type;
+    int plen;
+
+    do {
+        plen = MIN(len, ch->remote_mtu - 1);
+        pkt = ch->sdu_out(ch, plen + 1);
+
+        pkt[0] = hdr;
+        if (plen)
+            memcpy(pkt + 1, data, plen);
+        ch->sdu_submit(ch);
+
+        len -= plen;
+        data += plen;
+        hdr = (BT_DATC << 4) | type;
+    } while (plen == ch->remote_mtu - 1);
+}
+
+static void bt_hid_control_transaction(struct bt_hid_device_s *s,
+                const uint8_t *data, int len)
+{
+    uint8_t type, parameter;
+    int rlen, ret = -1;
+    if (len < 1)
+        return;
+
+    type = data[0] >> 4;
+    parameter = data[0] & 0xf;
+
+    switch (type) {
+    case BT_HANDSHAKE:
+    case BT_DATA:
+        switch (parameter) {
+        default:
+            /* These are not expected to be sent this direction.  */
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+        }
+        break;
+
+    case BT_HID_CONTROL:
+        if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG &&
+                                s->state == bt_state_transaction)) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        switch (parameter) {
+        case BT_HC_NOP:
+            break;
+        case BT_HC_HARD_RESET:
+        case BT_HC_SOFT_RESET:
+            bt_hid_reset(s);
+            break;
+        case BT_HC_SUSPEND:
+            if (s->state == bt_state_ready)
+                s->state = bt_state_suspend;
+            else
+                ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_HC_EXIT_SUSPEND:
+            if (s->state == bt_state_suspend)
+                s->state = bt_state_ready;
+            else
+                ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_HC_VIRTUAL_CABLE_UNPLUG:
+            bt_hid_disconnect(s);
+            break;
+        default:
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+        }
+        break;
+
+    case BT_GET_REPORT:
+        /* No ReportIDs declared.  */
+        if (((parameter & 8) && len != 3) ||
+                        (!(parameter & 8) && len != 1) ||
+                        s->state != bt_state_ready) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        if (parameter & 8)
+            rlen = data[2] | (data[3] << 8);
+        else
+            rlen = INT_MAX;
+        switch (parameter & 3) {
+        case BT_DATA_OTHER:
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_DATA_INPUT:
+            /* Here we can as well poll s->usbdev */
+            bt_hid_send_data(s->control, BT_DATA_INPUT,
+                            s->datain.buffer, MIN(rlen, s->datain.len));
+            break;
+        case BT_DATA_OUTPUT:
+            bt_hid_send_data(s->control, BT_DATA_OUTPUT,
+                            s->dataout.buffer, MIN(rlen, s->dataout.len));
+            break;
+        case BT_DATA_FEATURE:
+            bt_hid_send_data(s->control, BT_DATA_FEATURE,
+                            s->feature.buffer, MIN(rlen, s->feature.len));
+            break;
+        }
+        break;
+
+    case BT_SET_REPORT:
+        if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready ||
+                        (parameter & 3) == BT_DATA_OTHER ||
+                        (parameter & 3) == BT_DATA_INPUT) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        s->data_type = parameter & 3;
+        if (s->data_type == BT_DATA_OUTPUT) {
+            s->dataout.len = len - 1;
+            memcpy(s->dataout.buffer, data + 1, s->dataout.len);
+        } else {
+            s->feature.len = len - 1;
+            memcpy(s->feature.buffer, data + 1, s->feature.len);
+        }
+        if (len == BT_HID_MTU)
+            s->state = bt_state_transaction;
+        else
+            bt_hid_out(s);
+        break;
+
+    case BT_GET_PROTOCOL:
+        if (len != 1 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        *s->control->sdu_out(s->control, 1) = s->proto;
+        s->control->sdu_submit(s->control);
+        break;
+
+    case BT_SET_PROTOCOL:
+        if (len != 1 || s->state == bt_state_transaction ||
+                        (parameter != BT_HID_PROTO_BOOT &&
+                         parameter != BT_HID_PROTO_REPORT)) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        s->proto = parameter;
+        s->usbdev->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0,
+                                  NULL);
+        ret = BT_HS_SUCCESSFUL;
+        break;
+
+    case BT_GET_IDLE:
+        if (len != 1 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        s->usbdev->handle_control(s->usbdev, GET_IDLE, 0, 0, 1,
+                        s->control->sdu_out(s->control, 1));
+        s->control->sdu_submit(s->control);
+        break;
+
+    case BT_SET_IDLE:
+        if (len != 2 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+
+        /* We don't need to know about the Idle Rate here really,
+         * so just pass it on to the device.  */
+        ret = s->usbdev->handle_control(s->usbdev,
+                        SET_IDLE, data[1], 0, 0, NULL) ?
+                BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
+        /* XXX: Does this generate a handshake? */
+        break;
+
+    case BT_DATC:
+        if (len > BT_HID_MTU || s->state != bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        if (s->data_type == BT_DATA_OUTPUT) {
+            memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1);
+            s->dataout.len += len - 1;
+        } else {
+            memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1);
+            s->feature.len += len - 1;
+        }
+        if (len < BT_HID_MTU) {
+            bt_hid_out(s);
+            s->state = bt_state_ready;
+        }
+        break;
+
+    default:
+        ret = BT_HS_ERR_UNSUPPORTED_REQUEST;
+    }
+
+    if (ret != -1)
+        bt_hid_send_handshake(s, ret);
+}
+
+static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    bt_hid_control_transaction(hid, data, len);
+}
+
+static void bt_hid_datain(void *opaque)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    /* If suspended, wake-up and send a wake-up event first.  We might
+     * want to also inspect the input report and ignore event like
+     * mouse movements until a button event occurs.  */
+    if (hid->state == bt_state_suspend) {
+        hid->state = bt_state_ready;
+    }
+
+    if (bt_hid_in(hid) > 0)
+        /* TODO: when in boot-mode precede any Input reports with the ReportID
+         * byte, here and in GetReport/SetReport on the Control channel.  */
+        bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
+                        hid->datain.buffer, hid->datain.len);
+}
+
+static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    if (len > BT_HID_MTU || len < 1)
+        goto bad;
+    if ((data[0] & 3) != BT_DATA_OUTPUT)
+        goto bad;
+    if ((data[0] >> 4) == BT_DATA) {
+        if (hid->intr_state)
+            goto bad;
+
+        hid->data_type = BT_DATA_OUTPUT;
+        hid->intrdataout.len = 0;
+    } else if ((data[0] >> 4) == BT_DATC) {
+        if (!hid->intr_state)
+            goto bad;
+    } else
+        goto bad;
+
+    memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1);
+    hid->intrdataout.len += len - 1;
+    hid->intr_state = (len == BT_HID_MTU);
+    if (!hid->intr_state) {
+        memcpy(hid->dataout.buffer, hid->intrdataout.buffer,
+                        hid->dataout.len = hid->intrdataout.len);
+        bt_hid_out(hid);
+    }
+
+    return;
+bad:
+    fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
+                    __FUNCTION__);
+}
+
+/* "Virtual cable" plug/unplug event.  */
+static void bt_hid_connected_update(struct bt_hid_device_s *hid)
+{
+    int prev = hid->connected;
+
+    hid->connected = hid->control && hid->interrupt;
+
+    /* Stop page-/inquiry-scanning when a host is connected.  */
+    hid->btdev.device.page_scan = !hid->connected;
+    hid->btdev.device.inquiry_scan = !hid->connected;
+
+    if (hid->connected && !prev) {
+        hid->usbdev->handle_reset(hid->usbdev);
+        hid->proto = BT_HID_PROTO_REPORT;
+    }
+
+    /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
+     * isn't destroyed yet, in case we're being called from handle_destroy) */
+}
+
+static void bt_hid_close_control(void *opaque)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    hid->control = NULL;
+    bt_hid_connected_update(hid);
+}
+
+static void bt_hid_close_interrupt(void *opaque)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    hid->interrupt = NULL;
+    bt_hid_connected_update(hid);
+}
+
+static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->control)
+        return 1;
+
+    hid->control = params;
+    hid->control->opaque = hid;
+    hid->control->close = bt_hid_close_control;
+    hid->control->sdu_in = bt_hid_control_sdu;
+
+    bt_hid_connected_update(hid);
+
+    return 0;
+}
+
+static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->interrupt)
+        return 1;
+
+    hid->interrupt = params;
+    hid->interrupt->opaque = hid;
+    hid->interrupt->close = bt_hid_close_interrupt;
+    hid->interrupt->sdu_in = bt_hid_interrupt_sdu;
+
+    bt_hid_connected_update(hid);
+
+    return 0;
+}
+
+static void bt_hid_destroy(struct bt_device_s *dev)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->connected)
+        bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
+    bt_l2cap_device_done(&hid->btdev);
+
+    hid->usbdev->handle_destroy(hid->usbdev);
+
+    qemu_free(hid);
+}
+
+enum peripheral_minor_class {
+    class_other		= 0 << 4,
+    class_keyboard	= 1 << 4,
+    class_pointing	= 2 << 4,
+    class_combo		= 3 << 4,
+};
+
+static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
+                USBDevice *dev, enum peripheral_minor_class minor)
+{
+    struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
+    uint32_t class =
+            /* Format type */
+            (0 << 0) |
+            /* Device class */
+            (minor << 2) |
+            (5 << 8) |  /* "Peripheral" */
+            /* Service classes */
+            (1 << 13) | /* Limited discoverable mode */
+            (1 << 19);  /* Capturing device (?) */
+
+    bt_l2cap_device_init(&s->btdev, net);
+    bt_l2cap_sdp_init(&s->btdev);
+    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL,
+                    BT_HID_MTU, bt_hid_new_control_ch);
+    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
+                    BT_HID_MTU, bt_hid_new_interrupt_ch);
+
+    s->usbdev = dev;
+    s->btdev.device.lmp_name = s->usbdev->devname;
+    usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
+
+    s->btdev.device.handle_destroy = bt_hid_destroy;
+
+    s->btdev.device.class[0] = (class >>  0) & 0xff;
+    s->btdev.device.class[1] = (class >>  8) & 0xff;
+    s->btdev.device.class[2] = (class >> 16) & 0xff;
+
+    return &s->btdev.device;
+}
+
+struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
+{
+    return bt_hid_init(net, usb_keyboard_init(), class_keyboard);
+}
diff --git a/hw/bt-l2cap.c b/hw/bt-l2cap.c
new file mode 100644
index 0000000..b22b761
--- /dev/null
+++ b/hw/bt-l2cap.c
@@ -0,0 +1,1364 @@
+/*
+ * QEMU Bluetooth L2CAP logic.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "bt.h"
+
+#define L2CAP_CID_MAX	0x100	/* Between 0x40 and 0x10000 */
+
+struct l2cap_instance_s {
+    struct bt_link_s *link;
+    struct bt_l2cap_device_s *dev;
+    int role;
+
+    uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
+    int frame_in_len;
+
+    uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
+    int frame_out_len;
+
+    /* Signalling channel timers.  They exist per-request but we can make
+     * sure we have no more than one outstanding request at any time.  */
+    QEMUTimer *rtx;
+    QEMUTimer *ertx;
+
+    int last_id;
+    int next_id;
+
+    struct l2cap_chan_s {
+        struct bt_l2cap_conn_params_s params;
+
+        void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid,
+                        const l2cap_hdr *hdr, int len);
+        int mps;
+        int min_mtu;
+
+        struct l2cap_instance_s *l2cap;
+
+        /* Only allocated channels */
+        uint16_t remote_cid;
+#define L2CAP_CFG_INIT	2
+#define L2CAP_CFG_ACC	1
+        int config_req_id; /* TODO: handle outgoing requests generically */
+        int config;
+
+        /* Only connection-oriented channels.  Note: if we allow the tx and
+         * rx traffic to be in different modes at any time, we need two.  */
+        int mode;
+
+        /* Only flow-controlled, connection-oriented channels */
+        uint8_t sdu[65536]; /* TODO: dynamically allocate */
+        int len_cur, len_total;
+        int rexmit;
+        int monitor_timeout;
+        QEMUTimer *monitor_timer;
+        QEMUTimer *retransmission_timer;
+    } *cid[L2CAP_CID_MAX];
+    /* The channel state machine states map as following:
+     * CLOSED           -> !cid[N]
+     * WAIT_CONNECT     -> never occurs
+     * WAIT_CONNECT_RSP -> never occurs
+     * CONFIG           -> cid[N] && config < 3
+     *   WAIT_CONFIG         -> never occurs, cid[N] && config == 0 && !config_r
+     *   WAIT_SEND_CONFIG    -> never occurs, cid[N] && config == 1 && !config_r
+     *   WAIT_CONFIG_REQ_RSP -> cid[N] && config == 0 && config_req_id
+     *   WAIT_CONFIG_RSP     -> cid[N] && config == 1 && config_req_id
+     *   WAIT_CONFIG_REQ     -> cid[N] && config == 2
+     * OPEN             -> cid[N] && config == 3
+     * WAIT_DISCONNECT  -> never occurs
+     */
+
+    struct l2cap_chan_s signalling_ch;
+    struct l2cap_chan_s group_ch;
+};
+
+struct slave_l2cap_instance_s {
+    struct bt_link_s link;	/* Underlying logical link (ACL) */
+    struct l2cap_instance_s l2cap;
+};
+
+struct bt_l2cap_psm_s {
+    int psm;
+    int min_mtu;
+    int (*new_channel)(struct bt_l2cap_device_s *device,
+                    struct bt_l2cap_conn_params_s *params);
+    struct bt_l2cap_psm_s *next;
+};
+
+static const uint16_t l2cap_fcs16_table[256] = {
+    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
+    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
+    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
+    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
+    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
+    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
+    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
+    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
+    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
+    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
+    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
+    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
+    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
+    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
+    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
+    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
+    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
+    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
+    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
+    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
+    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
+    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
+    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
+    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
+    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
+};
+
+static uint16_t l2cap_fcs16(const uint8_t *message, int len)
+{
+    uint16_t fcs = 0x0000;
+
+    while (len --)
+#if 0
+    {
+        int i;
+
+        fcs ^= *message ++;
+        for (i = 8; i; -- i)
+            if (fcs & 1)
+                fcs = (fcs >> 1) ^ 0xa001;
+            else
+                fcs = (fcs >> 1);
+    }
+#else
+        fcs = (fcs >> 8) ^ l2cap_fcs16_table[(fcs ^ *message ++) & 0xff];
+#endif
+
+    return fcs;
+}
+
+/* L2CAP layer logic (protocol) */
+
+static void l2cap_retransmission_timer_update(struct l2cap_chan_s *ch)
+{
+#if 0
+    if (ch->mode != L2CAP_MODE_BASIC && ch->rexmit)
+        qemu_mod_timer(ch->retransmission_timer);
+    else
+        qemu_del_timer(ch->retransmission_timer);
+#endif
+}
+
+static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch)
+{
+#if 0
+    if (ch->mode != L2CAP_MODE_BASIC && !ch->rexmit)
+        qemu_mod_timer(ch->monitor_timer);
+    else
+        qemu_del_timer(ch->monitor_timer);
+#endif
+}
+
+static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id,
+                uint16_t reason, const void *data, int plen)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_cmd_rej *params;
+    uint16_t len;
+
+    reason = cpu_to_le16(reason);
+    len = cpu_to_le16(L2CAP_CMD_REJ_SIZE + plen);
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE + plen);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_COMMAND_REJ;
+    hdr->ident = id;
+    memcpy(&hdr->len, &len, sizeof(hdr->len));
+    memcpy(&params->reason, &reason, sizeof(reason));
+    if (plen)
+       memcpy(pkt + L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE, data, plen);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_command_reject_cid(struct l2cap_instance_s *l2cap, int id,
+                uint16_t reason, uint16_t dcid, uint16_t scid)
+{
+    l2cap_cmd_rej_cid params = {
+        .dcid = dcid,
+        .scid = scid,
+    };
+
+    l2cap_command_reject(l2cap, id, reason, &params, L2CAP_CMD_REJ_CID_SIZE);
+}
+
+static void l2cap_connection_response(struct l2cap_instance_s *l2cap,
+                int dcid, int scid, int result, int status)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conn_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONN_RSP_SIZE);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_CONN_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONN_RSP_SIZE);
+
+    params->dcid = cpu_to_le16(dcid);
+    params->scid = cpu_to_le16(scid);
+    params->result = cpu_to_le16(result);
+    params->status = cpu_to_le16(status);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_configuration_request(struct l2cap_instance_s *l2cap,
+                int dcid, int flag, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conf_req *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONF_REQ_SIZE(len));
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    /* TODO: unify the id sequencing */
+    l2cap->last_id = l2cap->next_id;
+    l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
+
+    hdr->code = L2CAP_CONF_REQ;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONF_REQ_SIZE(len));
+
+    params->dcid = cpu_to_le16(dcid);
+    params->flags = cpu_to_le16(flag);
+    if (len)
+        memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_configuration_response(struct l2cap_instance_s *l2cap,
+                int scid, int flag, int result, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conf_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONF_RSP_SIZE(len));
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_CONF_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONF_RSP_SIZE(len));
+
+    params->scid = cpu_to_le16(scid);
+    params->flags = cpu_to_le16(flag);
+    params->result = cpu_to_le16(result);
+    if (len)
+        memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap,
+                int dcid, int scid)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_disconn_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_DISCONN_RSP_SIZE);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_DISCONN_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_DISCONN_RSP_SIZE);
+
+    params->dcid = cpu_to_le16(dcid);
+    params->scid = cpu_to_le16(scid);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_echo_response(struct l2cap_instance_s *l2cap,
+                const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    uint8_t *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + len);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_ECHO_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(len);
+
+    memcpy(params, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type,
+                int result, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_info_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + len);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_INFO_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_INFO_RSP_SIZE + len);
+
+    params->type = cpu_to_le16(type);
+    params->result = cpu_to_le16(result);
+    if (len)
+       memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len);
+static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms);
+#if 0
+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len);
+static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm);
+#endif
+static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len);
+static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len);
+
+static int l2cap_cid_new(struct l2cap_instance_s *l2cap)
+{
+    int i;
+
+    for (i = L2CAP_CID_ALLOC; i < L2CAP_CID_MAX; i ++)
+        if (!l2cap->cid[i])
+            return i;
+
+    return L2CAP_CID_INVALID;
+}
+
+static inline struct bt_l2cap_psm_s *l2cap_psm(
+                struct bt_l2cap_device_s *device, int psm)
+{
+    struct bt_l2cap_psm_s *ret = device->first_psm;
+
+    while (ret && ret->psm != psm)
+        ret = ret->next;
+
+    return ret;
+}
+
+static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap,
+                int psm, int source_cid)
+{
+    struct l2cap_chan_s *ch = NULL;
+    struct bt_l2cap_psm_s *psm_info;
+    int result, status;
+    int cid = l2cap_cid_new(l2cap);
+
+    if (cid) {
+        /* See what the channel is to be used for.. */
+        psm_info = l2cap_psm(l2cap->dev, psm);
+
+        if (psm_info) {
+            /* Device supports this use-case.  */
+            ch = qemu_mallocz(sizeof(*ch));
+            ch->params.sdu_out = l2cap_bframe_out;
+            ch->params.sdu_submit = l2cap_bframe_submit;
+            ch->frame_in = l2cap_bframe_in;
+            ch->mps = 65536;
+            ch->min_mtu = MAX(48, psm_info->min_mtu);
+            ch->params.remote_mtu = MAX(672, ch->min_mtu);
+            ch->remote_cid = source_cid;
+            ch->mode = L2CAP_MODE_BASIC;
+            ch->l2cap = l2cap;
+
+            /* Does it feel like opening yet another channel though?  */
+            if (!psm_info->new_channel(l2cap->dev, &ch->params)) {
+                l2cap->cid[cid] = ch;
+
+                result = L2CAP_CR_SUCCESS;
+                status = L2CAP_CS_NO_INFO;
+            } else {
+                qemu_free(ch);
+
+                result = L2CAP_CR_NO_MEM;
+                status = L2CAP_CS_NO_INFO;
+            }
+        } else {
+            result = L2CAP_CR_BAD_PSM;
+            status = L2CAP_CS_NO_INFO;
+        }
+    } else {
+        result = L2CAP_CR_NO_MEM;
+        status = L2CAP_CS_NO_INFO;
+    }
+
+    l2cap_connection_response(l2cap, cid, source_cid, result, status);
+
+    return ch;
+}
+
+static void l2cap_channel_close(struct l2cap_instance_s *l2cap,
+                int cid, int source_cid)
+{
+    struct l2cap_chan_s *ch = NULL;
+
+    /* According to Volume 3, section 6.1.1, pg 1048 of BT Core V2.0, a
+     * connection in CLOSED state still responds with a L2CAP_DisconnectRsp
+     * message on an L2CAP_DisconnectReq event.  */
+    if (unlikely(cid < L2CAP_CID_ALLOC)) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, source_cid);
+        return;
+    }
+    if (likely(cid >= L2CAP_CID_ALLOC && cid < L2CAP_CID_MAX))
+        ch = l2cap->cid[cid];
+
+    if (likely(ch)) {
+        if (ch->remote_cid != source_cid) {
+            fprintf(stderr, "%s: Ignoring a Disconnection Request with the "
+                            "invalid SCID %04x.\n", __FUNCTION__, source_cid);
+            return;
+        }
+
+        l2cap->cid[cid] = NULL;
+
+        ch->params.close(ch->params.opaque);
+        qemu_free(ch);
+    }
+
+    l2cap_disconnection_response(l2cap, cid, source_cid);
+}
+
+static void l2cap_channel_config_null(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch)
+{
+    l2cap_configuration_request(l2cap, ch->remote_cid, 0, NULL, 0);
+    ch->config_req_id = l2cap->last_id;
+    ch->config &= ~L2CAP_CFG_INIT;
+}
+
+static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch)
+{
+    /* Use all default channel options and terminate negotiation.  */
+    l2cap_channel_config_null(l2cap, ch);
+}
+
+static int l2cap_channel_config(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch, int flag,
+                const uint8_t *data, int len)
+{
+    l2cap_conf_opt *opt;
+    l2cap_conf_opt_qos *qos;
+    uint32_t val;
+    uint8_t rsp[len];
+    int result = L2CAP_CONF_SUCCESS;
+
+    data = memcpy(rsp, data, len);
+    while (len) {
+        opt = (void *) data;
+
+        if (len < L2CAP_CONF_OPT_SIZE ||
+                        len < L2CAP_CONF_OPT_SIZE + opt->len) {
+            result = L2CAP_CONF_REJECT;
+            break;
+        }
+        data += L2CAP_CONF_OPT_SIZE + opt->len;
+        len -= L2CAP_CONF_OPT_SIZE + opt->len;
+
+        switch (opt->type & 0x7f) {
+        case L2CAP_CONF_MTU:
+            if (opt->len != 2) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* MTU */
+            val = le16_to_cpup((void *) opt->val);
+            if (val < ch->min_mtu) {
+                cpu_to_le16w((void *) opt->val, ch->min_mtu);
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+
+            ch->params.remote_mtu = val;
+            break;
+
+        case L2CAP_CONF_FLUSH_TO:
+            if (opt->len != 2) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* Flush Timeout */
+            val = le16_to_cpup((void *) opt->val);
+            if (val < 0x0001) {
+                opt->val[0] = 0xff;
+                opt->val[1] = 0xff;
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+            break;
+
+        case L2CAP_CONF_QOS:
+            if (opt->len != L2CAP_CONF_OPT_QOS_SIZE) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+            qos = (void *) opt->val;
+
+            /* Flags */
+            val = qos->flags;
+            if (val) {
+                qos->flags = 0;
+                result = L2CAP_CONF_UNACCEPT;
+            }
+
+            /* Service type */
+            val = qos->service_type;
+            if (val != L2CAP_CONF_QOS_BEST_EFFORT &&
+                            val != L2CAP_CONF_QOS_NO_TRAFFIC) {
+                qos->service_type = L2CAP_CONF_QOS_BEST_EFFORT;
+                result = L2CAP_CONF_UNACCEPT;
+            }
+
+            if (val != L2CAP_CONF_QOS_NO_TRAFFIC) {
+                /* XXX: These values should possibly be calculated
+                 * based on LM / baseband properties also.  */
+
+                /* Token rate */
+                val = le32_to_cpu(qos->token_rate);
+                if (val == L2CAP_CONF_QOS_WILDCARD)
+                    qos->token_rate = cpu_to_le32(0x100000);
+
+                /* Token bucket size */
+                val = le32_to_cpu(qos->token_bucket_size);
+                if (val == L2CAP_CONF_QOS_WILDCARD)
+                    qos->token_bucket_size = cpu_to_le32(65500);
+
+                /* Any Peak bandwidth value is correct to return as-is */
+                /* Any Access latency value is correct to return as-is */
+                /* Any Delay variation value is correct to return as-is */
+            }
+            break;
+
+        case L2CAP_CONF_RFC:
+            if (opt->len != 9) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* Mode */
+            val = opt->val[0];
+            switch (val) {
+            case L2CAP_MODE_BASIC:
+                ch->mode = val;
+                ch->frame_in = l2cap_bframe_in;
+
+                /* All other parameters shall be ignored */
+                break;
+
+            case L2CAP_MODE_RETRANS:
+            case L2CAP_MODE_FLOWCTL:
+                ch->mode = val;
+                ch->frame_in = l2cap_iframe_in;
+                /* Note: most of these parameters refer to incoming traffic
+                 * so we don't need to save them as long as we can accept
+                 * incoming PDUs at any values of the parameters.  */
+
+                /* TxWindow size */
+                val = opt->val[1];
+                if (val < 1 || val > 32) {
+                    opt->val[1] = 32;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+
+                /* MaxTransmit */
+                val = opt->val[2];
+                if (val < 1) {
+                    opt->val[2] = 1;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+
+                /* Remote Retransmission time-out shouldn't affect local
+                 * operation (?) */
+
+                /* The Monitor time-out drives the local Monitor timer (?),
+                 * so save the value.  */
+                val = (opt->val[6] << 8) | opt->val[5];
+                if (val < 30) {
+                    opt->val[5] = 100 & 0xff;
+                    opt->val[6] = 100 >> 8;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+                ch->monitor_timeout = val;
+                l2cap_monitor_timer_update(ch);
+
+                /* MPS */
+                val = (opt->val[8] << 8) | opt->val[7];
+                if (val < ch->min_mtu) {
+                    opt->val[7] = ch->min_mtu & 0xff;
+                    opt->val[8] = ch->min_mtu >> 8;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+                ch->mps = val;
+                break;
+
+            default:
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+            break;
+
+        default:
+            if (!(opt->type >> 7))
+                result = L2CAP_CONF_UNKNOWN;
+            break;
+        }
+
+        if (result != L2CAP_CONF_SUCCESS)
+            break;	/* XXX: should continue? */
+    }
+
+    l2cap_configuration_response(l2cap, ch->remote_cid,
+                    flag, result, rsp, len);
+
+    return result == L2CAP_CONF_SUCCESS && !flag;
+}
+
+static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap,
+                int flag, int cid, const uint8_t *data, int len)
+{
+    struct l2cap_chan_s *ch;
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, 0x0000);
+        return;
+    }
+    ch = l2cap->cid[cid];
+
+    /* From OPEN go to WAIT_CONFIG_REQ and from WAIT_CONFIG_REQ_RSP to
+     * WAIT_CONFIG_REQ_RSP.  This is assuming the transition chart for OPEN
+     * on pg 1053, section 6.1.5, volume 3 of BT Core V2.0 has a mistake
+     * and on options-acceptable we go back to OPEN and otherwise to
+     * WAIT_CONFIG_REQ and not the other way.  */
+    ch->config &= ~L2CAP_CFG_ACC;
+
+    if (l2cap_channel_config(l2cap, ch, flag, data, len))
+        /* Go to OPEN or WAIT_CONFIG_RSP */
+        ch->config |= L2CAP_CFG_ACC;
+
+    /* TODO: if the incoming traffic flow control or retransmission mode
+     * changed then we probably need to also generate the
+     * ConfigureChannel_Req event and set the outgoing traffic to the same
+     * mode.  */
+    if (!(ch->config & L2CAP_CFG_INIT) && (ch->config & L2CAP_CFG_ACC) &&
+                    !ch->config_req_id)
+        l2cap_channel_config_req_event(l2cap, ch);
+}
+
+static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap,
+                int result, int flag, int cid, const uint8_t *data, int len)
+{
+    struct l2cap_chan_s *ch;
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, 0x0000);
+        return 0;
+    }
+    ch = l2cap->cid[cid];
+
+    if (ch->config_req_id != l2cap->last_id)
+        return 1;
+    ch->config_req_id = 0;
+
+    if (result == L2CAP_CONF_SUCCESS) {
+        if (!flag)
+            ch->config |= L2CAP_CFG_INIT;
+        else
+            l2cap_channel_config_null(l2cap, ch);
+    } else
+        /* Retry until we succeed */
+        l2cap_channel_config_req_event(l2cap, ch);
+
+    return 0;
+}
+
+static void l2cap_channel_open_req_msg(struct l2cap_instance_s *l2cap,
+                int psm, int source_cid)
+{
+    struct l2cap_chan_s *ch = l2cap_channel_open(l2cap, psm, source_cid);
+
+    if (!ch)
+        return;
+
+    /* Optional */
+    if (!(ch->config & L2CAP_CFG_INIT) && !ch->config_req_id)
+        l2cap_channel_config_req_event(l2cap, ch);
+}
+
+static void l2cap_info(struct l2cap_instance_s *l2cap, int type)
+{
+    uint8_t data[4];
+    int len = 0;
+    int result = L2CAP_IR_SUCCESS;
+
+    switch (type) {
+    case L2CAP_IT_CL_MTU:
+        data[len ++] = l2cap->group_ch.mps & 0xff;
+        data[len ++] = l2cap->group_ch.mps >> 8;
+        break;
+
+    case L2CAP_IT_FEAT_MASK:
+        /* (Prematurely) report Flow control and Retransmission modes.  */
+        data[len ++] = 0x03;
+        data[len ++] = 0x00;
+        data[len ++] = 0x00;
+        data[len ++] = 0x00;
+        break;
+
+    default:
+        result = L2CAP_IR_NOTSUPP;
+    }
+
+    l2cap_info_response(l2cap, type, result, data, len);
+}
+
+static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id,
+                const uint8_t *params, int len)
+{
+    int err;
+
+#if 0
+    /* TODO: do the IDs really have to be in sequence?  */
+    if (!id || (id != l2cap->last_id && id != l2cap->next_id)) {
+        fprintf(stderr, "%s: out of sequence command packet ignored.\n",
+                        __FUNCTION__);
+        return;
+    }
+#else
+    l2cap->next_id = id;
+#endif
+    if (id == l2cap->next_id) {
+        l2cap->last_id = l2cap->next_id;
+        l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
+    } else {
+        /* TODO: Need to re-send the same response, without re-executing
+         * the corresponding command!  */
+    }
+
+    switch (code) {
+    case L2CAP_COMMAND_REJ:
+        if (unlikely(len != 2 && len != 4 && len != 6)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue commands other than Command Reject currently.  */
+        fprintf(stderr, "%s: stray Command Reject (%02x, %04x) "
+                        "packet, ignoring.\n", __FUNCTION__, id,
+                        le16_to_cpu(((l2cap_cmd_rej *) params)->reason));
+        break;
+
+    case L2CAP_CONN_REQ:
+        if (unlikely(len != L2CAP_CONN_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_open_req_msg(l2cap,
+                        le16_to_cpu(((l2cap_conn_req *) params)->psm),
+                        le16_to_cpu(((l2cap_conn_req *) params)->scid));
+        break;
+
+    case L2CAP_CONN_RSP:
+        if (unlikely(len != L2CAP_CONN_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Connection Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Connection Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_CONF_REQ:
+        if (unlikely(len < L2CAP_CONF_REQ_SIZE(0))) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_config_req_msg(l2cap,
+                        le16_to_cpu(((l2cap_conf_req *) params)->flags) & 1,
+                        le16_to_cpu(((l2cap_conf_req *) params)->dcid),
+                        ((l2cap_conf_req *) params)->data,
+                        len - L2CAP_CONF_REQ_SIZE(0));
+        break;
+
+    case L2CAP_CONF_RSP:
+        if (unlikely(len < L2CAP_CONF_RSP_SIZE(0))) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        if (l2cap_channel_config_rsp_msg(l2cap,
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->result),
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->flags) & 1,
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->scid),
+                        ((l2cap_conf_rsp *) params)->data,
+                        len - L2CAP_CONF_RSP_SIZE(0)))
+            fprintf(stderr, "%s: unexpected Configure Response (%02x) "
+                            "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_DISCONN_REQ:
+        if (unlikely(len != L2CAP_DISCONN_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_close(l2cap,
+                        le16_to_cpu(((l2cap_disconn_req *) params)->dcid),
+                        le16_to_cpu(((l2cap_disconn_req *) params)->scid));
+        break;
+
+    case L2CAP_DISCONN_RSP:
+        if (unlikely(len != L2CAP_DISCONN_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Disconnection Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Disconnection Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_ECHO_REQ:
+        l2cap_echo_response(l2cap, params, len);
+        break;
+
+    case L2CAP_ECHO_RSP:
+        /* We never issue Echo Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Echo Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_INFO_REQ:
+        if (unlikely(len != L2CAP_INFO_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_info(l2cap, le16_to_cpu(((l2cap_info_req *) params)->type));
+        break;
+
+    case L2CAP_INFO_RSP:
+        if (unlikely(len != L2CAP_INFO_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Information Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Information Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    default:
+        err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+    reject:
+        l2cap_command_reject(l2cap, id, err, 0, 0);
+        break;
+    }
+}
+
+static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable)
+{
+    ch->rexmit = enable;
+
+    l2cap_retransmission_timer_update(ch);
+    l2cap_monitor_timer_update(ch);
+}
+
+/* Command frame SDU */
+static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len)
+{
+    struct l2cap_instance_s *l2cap = opaque;
+    const l2cap_cmd_hdr *hdr;
+    int clen;
+
+    while (len) {
+        hdr = (void *) data;
+        if (len < L2CAP_CMD_HDR_SIZE)
+            /* TODO: signal an error */
+            return;
+        len -= L2CAP_CMD_HDR_SIZE;
+        data += L2CAP_CMD_HDR_SIZE;
+
+        clen = le16_to_cpu(hdr->len);
+        if (len < clen) {
+            l2cap_command_reject(l2cap, hdr->ident,
+                            L2CAP_REJ_CMD_NOT_UNDERSTOOD, 0, 0);
+            break;
+        }
+
+        l2cap_command(l2cap, hdr->code, hdr->ident, data, clen);
+        len -= clen;
+        data += clen;
+    }
+}
+
+/* Group frame SDU */
+static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len)
+{
+}
+
+/* Supervisory frame */
+static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl)
+{
+}
+
+/* Basic L2CAP mode Information frame */
+static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len)
+{
+    /* We have a full SDU, no further processing */
+    ch->params.sdu_in(ch->params.opaque, hdr->data, len);
+}
+
+/* Flow Control and Retransmission mode frame */
+static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len)
+{
+    uint16_t fcs = le16_to_cpup((void *) (hdr->data + len - 2));
+
+    if (len < 4)
+        goto len_error;
+    if (l2cap_fcs16((const uint8_t *) hdr, L2CAP_HDR_SIZE + len - 2) != fcs)
+        goto fcs_error;
+
+    if ((hdr->data[0] >> 7) == ch->rexmit)
+        l2cap_rexmit_enable(ch, !(hdr->data[0] >> 7));
+
+    if (hdr->data[0] & 1) {
+        if (len != 4)
+            /* TODO: Signal an error? */;
+            return;
+
+        return l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data));
+    }
+
+    switch (hdr->data[1] >> 6) {	/* SAR */
+    case L2CAP_SAR_NO_SEG:
+        if (ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        return ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4);
+
+    case L2CAP_SAR_START:
+        if (ch->len_total || len < 6)
+            goto seg_error;
+        if (len - 6 > ch->mps)
+            goto len_error;
+
+        ch->len_total = le16_to_cpup((void *) (hdr->data + 2));
+        if (len >= 6 + ch->len_total)
+            goto seg_error;
+
+        ch->len_cur = len - 6;
+        memcpy(ch->sdu, hdr->data + 4, ch->len_cur);
+        break;
+
+    case L2CAP_SAR_END:
+        if (!ch->len_total || ch->len_cur + len - 4 < ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
+        return ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total);
+
+    case L2CAP_SAR_CONT:
+        if (!ch->len_total || ch->len_cur + len - 4 >= ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
+        ch->len_cur += len - 4;
+        break;
+
+    seg_error:
+    len_error:	/* TODO */
+    fcs_error:	/* TODO */
+        ch->len_cur = 0;
+        ch->len_total = 0;
+        break;
+    }
+}
+
+static void l2cap_frame_in(struct l2cap_instance_s *l2cap,
+                const l2cap_hdr *frame)
+{
+    uint16_t cid = le16_to_cpu(frame->cid);
+    uint16_t len = le16_to_cpu(frame->len);
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        fprintf(stderr, "%s: frame addressed to a non-existent L2CAP "
+                        "channel %04x received.\n", __FUNCTION__, cid);
+        return;
+    }
+
+    l2cap->cid[cid]->frame_in(l2cap->cid[cid], cid, frame, len);
+}
+
+/* "Recombination" */
+static void l2cap_pdu_in(struct l2cap_instance_s *l2cap,
+                const uint8_t *data, int len)
+{
+    const l2cap_hdr *hdr = (void *) l2cap->frame_in;
+
+    if (unlikely(len + l2cap->frame_in_len > sizeof(l2cap->frame_in))) {
+        if (l2cap->frame_in_len < sizeof(l2cap->frame_in)) {
+            memcpy(l2cap->frame_in + l2cap->frame_in_len, data,
+                            sizeof(l2cap->frame_in) - l2cap->frame_in_len);
+            l2cap->frame_in_len = sizeof(l2cap->frame_in);
+            /* TODO: truncate */
+            l2cap_frame_in(l2cap, hdr);
+        }
+
+        return;
+    }
+
+    memcpy(l2cap->frame_in + l2cap->frame_in_len, data, len);
+    l2cap->frame_in_len += len;
+
+    if (len >= L2CAP_HDR_SIZE)
+        if (len >= L2CAP_HDR_SIZE + le16_to_cpu(hdr->len))
+            l2cap_frame_in(l2cap, hdr);
+            /* There is never a start of a new PDU in the same ACL packet, so
+             * no need to memmove the remaining payload and loop.  */
+}
+
+static inline uint8_t *l2cap_pdu_out(struct l2cap_instance_s *l2cap,
+                uint16_t cid, uint16_t len)
+{
+    l2cap_hdr *hdr = (void *) l2cap->frame_out;
+
+    l2cap->frame_out_len = len + L2CAP_HDR_SIZE;
+
+    hdr->cid = cpu_to_le16(cid);
+    hdr->len = cpu_to_le16(len);
+
+    return l2cap->frame_out + L2CAP_HDR_SIZE;
+}
+
+static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap)
+{
+    /* TODO: Fragmentation */
+    (l2cap->role ?
+     l2cap->link->slave->lmp_acl_data : l2cap->link->host->lmp_acl_resp)
+            (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len);
+}
+
+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
+
+    if (len > chan->params.remote_mtu) {
+        fprintf(stderr, "%s: B-Frame for CID %04x longer than %i octets.\n",
+                        __FUNCTION__,
+                        chan->remote_cid, chan->params.remote_mtu);
+        exit(-1);
+    }
+
+    return l2cap_pdu_out(chan->l2cap, chan->remote_cid, len);
+}
+
+static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parms;
+
+    return l2cap_pdu_submit(chan->l2cap);
+}
+
+#if 0
+/* Stub: Only used if an emulated device requests outgoing flow control */
+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
+
+    if (len > chan->params.remote_mtu) {
+        /* TODO: slice into segments and queue each segment as a separate
+         * I-Frame in a FIFO of I-Frames, local to the CID.  */
+    } else {
+        /* TODO: add to the FIFO of I-Frames, local to the CID.  */
+        /* Possibly we need to return a pointer to a contiguous buffer
+         * for now and then memcpy from it into FIFOs in l2cap_iframe_submit
+         * while segmenting at the same time.  */
+    }
+    return 0;
+}
+
+static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm)
+{
+    /* TODO: If flow control indicates clear to send, start submitting the
+     * invidual I-Frames from the FIFO, but don't remove them from there.
+     * Kick the appropriate timer until we get an S-Frame, and only then
+     * remove from FIFO or resubmit and re-kick the timer if the timer
+     * expired.  */
+}
+#endif
+
+static void l2cap_init(struct l2cap_instance_s *l2cap,
+                struct bt_link_s *link, int role)
+{
+    l2cap->link = link;
+    l2cap->role = role;
+    l2cap->dev = (struct bt_l2cap_device_s *)
+            (role ? link->host : link->slave);
+
+    l2cap->next_id = 1;
+
+    /* Establish the signalling channel */
+    l2cap->signalling_ch.params.sdu_in = l2cap_cframe_in;
+    l2cap->signalling_ch.params.sdu_out = l2cap_bframe_out;
+    l2cap->signalling_ch.params.sdu_submit = l2cap_bframe_submit;
+    l2cap->signalling_ch.params.opaque = l2cap;
+    l2cap->signalling_ch.params.remote_mtu = 48;
+    l2cap->signalling_ch.remote_cid = L2CAP_CID_SIGNALLING;
+    l2cap->signalling_ch.frame_in = l2cap_bframe_in;
+    l2cap->signalling_ch.mps = 65536;
+    l2cap->signalling_ch.min_mtu = 48;
+    l2cap->signalling_ch.mode = L2CAP_MODE_BASIC;
+    l2cap->signalling_ch.l2cap = l2cap;
+    l2cap->cid[L2CAP_CID_SIGNALLING] = &l2cap->signalling_ch;
+
+    /* Establish the connection-less data channel */
+    l2cap->group_ch.params.sdu_in = l2cap_gframe_in;
+    l2cap->group_ch.params.opaque = l2cap;
+    l2cap->group_ch.frame_in = l2cap_bframe_in;
+    l2cap->group_ch.mps = 65533;
+    l2cap->group_ch.l2cap = l2cap;
+    l2cap->group_ch.remote_cid = L2CAP_CID_INVALID;
+    l2cap->cid[L2CAP_CID_GROUP] = &l2cap->group_ch;
+}
+
+static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect)
+{
+    int cid;
+
+    /* Don't send DISCONNECT if we are currently handling a DISCONNECT
+     * sent from the other side.  */
+    if (send_disconnect) {
+        if (l2cap->role)
+            l2cap->dev->device.lmp_disconnect_slave(l2cap->link);
+            /* l2cap->link is invalid from now on.  */
+        else
+            l2cap->dev->device.lmp_disconnect_master(l2cap->link);
+    }
+
+    for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++)
+        if (l2cap->cid[cid]) {
+            l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque);
+            free(l2cap->cid[cid]);
+        }
+
+    if (l2cap->role)
+        qemu_free(l2cap);
+    else
+        qemu_free(l2cap->link);
+}
+
+/* L2CAP glue to lower layers in bluetooth stack (LMP) */
+
+static void l2cap_lmp_connection_request(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->slave;
+    struct slave_l2cap_instance_s *l2cap;
+
+    /* Always accept - we only get called if (dev->device->page_scan).  */
+
+    l2cap = qemu_mallocz(sizeof(struct slave_l2cap_instance_s));
+    l2cap->link.slave = &dev->device;
+    l2cap->link.host = link->host;
+    l2cap_init(&l2cap->l2cap, &l2cap->link, 0);
+
+    /* Always at the end */
+    link->host->reject_reason = 0;
+    link->host->lmp_connection_complete(&l2cap->link);
+}
+
+/* Stub */
+static void l2cap_lmp_connection_complete(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap;
+
+    if (dev->device.reject_reason) {
+        /* Signal to upper layer */
+        return;
+    }
+
+    l2cap = qemu_mallocz(sizeof(struct l2cap_instance_s));
+    l2cap_init(l2cap, link, 1);
+
+    link->acl_mode = acl_active;
+
+    /* Signal to upper layer */
+}
+
+/* Stub */
+static void l2cap_lmp_disconnect_host(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap =
+            /* TODO: Retrieve from upper layer */ (void *) dev;
+
+    /* Signal to upper layer */
+
+    l2cap_teardown(l2cap, 0);
+}
+
+static void l2cap_lmp_disconnect_slave(struct bt_link_s *link)
+{
+    struct slave_l2cap_instance_s *l2cap =
+            (struct slave_l2cap_instance_s *) link;
+
+    l2cap_teardown(&l2cap->l2cap, 0);
+}
+
+static void l2cap_lmp_acl_data_slave(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    struct slave_l2cap_instance_s *l2cap =
+            (struct slave_l2cap_instance_s *) link;
+
+    if (start)
+        l2cap->l2cap.frame_in_len = 0;
+
+    l2cap_pdu_in(&l2cap->l2cap, data, len);
+}
+
+/* Stub */
+static void l2cap_lmp_acl_data_host(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap =
+            /* TODO: Retrieve from upper layer */ (void *) dev;
+
+    if (start)
+        l2cap->frame_in_len = 0;
+
+    l2cap_pdu_in(l2cap, data, len);
+}
+
+static void l2cap_dummy_destroy(struct bt_device_s *dev)
+{
+    struct bt_l2cap_device_s *l2cap_dev = (struct bt_l2cap_device_s *) dev;
+
+    bt_l2cap_device_done(l2cap_dev);
+}
+
+void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
+                struct bt_scatternet_s *net)
+{
+    bt_device_init(&dev->device, net);
+
+    dev->device.lmp_connection_request = l2cap_lmp_connection_request;
+    dev->device.lmp_connection_complete = l2cap_lmp_connection_complete;
+    dev->device.lmp_disconnect_master = l2cap_lmp_disconnect_host;
+    dev->device.lmp_disconnect_slave = l2cap_lmp_disconnect_slave;
+    dev->device.lmp_acl_data = l2cap_lmp_acl_data_slave;
+    dev->device.lmp_acl_resp = l2cap_lmp_acl_data_host;
+
+    dev->device.handle_destroy = l2cap_dummy_destroy;
+}
+
+void bt_l2cap_device_done(struct bt_l2cap_device_s *dev)
+{
+    bt_device_done(&dev->device);
+
+    /* Should keep a list of all instances and go through it and
+     * invoke l2cap_teardown() for each.  */
+}
+
+void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, int min_mtu,
+                int (*new_channel)(struct bt_l2cap_device_s *dev,
+                        struct bt_l2cap_conn_params_s *params))
+{
+    struct bt_l2cap_psm_s *new_psm = l2cap_psm(dev, psm);
+
+    if (new_psm) {
+        fprintf(stderr, "%s: PSM %04x already registered for device `%s'.\n",
+                        __FUNCTION__, psm, dev->device.lmp_name);
+        exit(-1);
+    }
+
+    new_psm = qemu_mallocz(sizeof(*new_psm));
+    new_psm->psm = psm;
+    new_psm->min_mtu = min_mtu;
+    new_psm->new_channel = new_channel;
+    new_psm->next = dev->first_psm;
+    dev->first_psm = new_psm;
+}
diff --git a/hw/bt-sdp.c b/hw/bt-sdp.c
new file mode 100644
index 0000000..992de0e
--- /dev/null
+++ b/hw/bt-sdp.c
@@ -0,0 +1,968 @@
+/*
+ * Service Discover Protocol server for QEMU L2CAP devices
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "qemu-common.h"
+#include "bt.h"
+
+struct bt_l2cap_sdp_state_s {
+    struct bt_l2cap_conn_params_s *channel;
+
+    struct sdp_service_record_s {
+        int match;
+
+        int *uuid;
+        int uuids;
+        struct sdp_service_attribute_s {
+            int match;
+
+            int attribute_id;
+            int len;
+            void *pair;
+        } *attribute_list;
+        int attributes;
+    } *service_list;
+    int services;
+};
+
+static ssize_t sdp_datalen(const uint8_t **element, ssize_t *left)
+{
+    size_t len = *(*element) ++ & SDP_DSIZE_MASK;
+
+    if (!*left)
+        return -1;
+    (*left) --;
+
+    if (len < SDP_DSIZE_NEXT1)
+        return 1 << len;
+    else if (len == SDP_DSIZE_NEXT1) {
+        if (*left < 1)
+            return -1;
+        (*left) --;
+
+        return *(*element) ++;
+    } else if (len == SDP_DSIZE_NEXT2) {
+        if (*left < 2)
+            return -1;
+        (*left) -= 2;
+
+        len = (*(*element) ++) << 8;
+        return len | (*(*element) ++);
+    } else {
+        if (*left < 4)
+            return -1;
+        (*left) -= 4;
+
+        len = (*(*element) ++) << 24;
+        len |= (*(*element) ++) << 16;
+        len |= (*(*element) ++) << 8;
+        return len | (*(*element) ++);
+    }
+}
+
+static const uint8_t bt_base_uuid[12] = {
+    0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+};
+
+static int sdp_uuid_match(struct sdp_service_record_s *record,
+                const uint8_t *uuid, ssize_t datalen)
+{
+    int *lo, hi, val;
+
+    if (datalen == 16 || datalen == 4) {
+        if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12))
+            return 0;
+
+        if (uuid[0] | uuid[1])
+            return 0;
+        uuid += 2;
+    }
+
+    val = (uuid[0] << 8) | uuid[1];
+    lo = record->uuid;
+    hi = record->uuids;
+    while (hi >>= 1)
+        if (lo[hi] <= val)
+            lo += hi;
+
+    return *lo == val;
+}
+
+#define CONTINUATION_PARAM_SIZE	(1 + sizeof(int))
+#define MAX_PDU_OUT_SIZE	96	/* Arbitrary */
+#define PDU_HEADER_SIZE		5
+#define MAX_RSP_PARAM_SIZE	(MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \
+                CONTINUATION_PARAM_SIZE)
+
+static int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp,
+                const uint8_t **req, ssize_t *len)
+{
+    size_t datalen;
+    int i;
+
+    if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID)
+        return 1;
+
+    datalen = sdp_datalen(req, len);
+    if (datalen != 2 && datalen != 4 && datalen != 16)
+        return 1;
+
+    for (i = 0; i < sdp->services; i ++)
+        if (sdp_uuid_match(&sdp->service_list[i], *req, datalen))
+            sdp->service_list[i].match = 1;
+
+    (*req) += datalen;
+    (*len) -= datalen;
+
+    return 0;
+}
+
+static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, count, start, end, max;
+    int32_t handle;
+
+    /* Perform the search */
+    for (i = 0; i < sdp->services; i ++)
+        sdp->service_list[i].match = 0;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 3)
+        return -SDP_INVALID_SYNTAX;
+    end = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1);
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    len = 4;
+    count = 0;
+    end = start;
+    for (i = 0; i < sdp->services; i ++)
+        if (sdp->service_list[i].match) {
+            if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) {
+                handle = i;
+                memcpy(rsp + len, &handle, 4);
+                len += 4;
+                end = count + 1;
+            }
+
+            count ++;
+        }
+
+    rsp[0] = count >> 8;
+    rsp[1] = count & 0xff;
+    rsp[2] = (end - start) >> 8;
+    rsp[3] = (end - start) & 0xff;
+
+    if (end < count) {
+        rsp[len ++] = sizeof(int);
+        memcpy(rsp + len, &end, sizeof(int));
+        len += 4;
+    } else
+        rsp[len ++] = 0;
+
+    return len;
+}
+
+static int sdp_attr_match(struct sdp_service_record_s *record,
+                const uint8_t **req, ssize_t *len)
+{
+    int i, start, end;
+
+    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
+        (*req) ++;
+        if (*len < 3)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = start;
+        *len -= 3;
+    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
+        (*req) ++;
+        if (*len < 5)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = (*(*req) ++) << 8;
+        end |= *(*req) ++;
+        *len -= 5;
+    } else
+        return 1;
+
+    for (i = 0; i < record->attributes; i ++)
+        if (record->attribute_list[i].attribute_id >= start &&
+                        record->attribute_list[i].attribute_id <= end)
+            record->attribute_list[i].match = 1;
+
+    return 0;
+}
+
+static ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, start, end, max;
+    int32_t handle;
+    struct sdp_service_record_s *record;
+    uint8_t *lst;
+
+    /* Perform the search */
+    if (len < 7)
+        return -SDP_INVALID_SYNTAX;
+    memcpy(&handle, req, 4);
+    req += 4;
+    len -= 4;
+
+    if (handle < 0 || handle > sdp->services)
+        return -SDP_INVALID_RECORD_HANDLE;
+    record = &sdp->service_list[handle];
+
+    for (i = 0; i < record->attributes; i ++)
+        record->attribute_list[i].match = 0;
+
+    max = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+    if (max < 0x0007)
+        return -SDP_INVALID_SYNTAX;
+
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_attr_match(record, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_attr_match(record, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1)
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    lst = rsp + 2;
+    max = MIN(max, MAX_RSP_PARAM_SIZE);
+    len = 3 - start;
+    end = 0;
+    for (i = 0; i < record->attributes; i ++)
+        if (record->attribute_list[i].match) {
+            if (len >= 0 && len + record->attribute_list[i].len < max) {
+                memcpy(lst + len, record->attribute_list[i].pair,
+                                record->attribute_list[i].len);
+                end = len + record->attribute_list[i].len;
+            }
+            len += record->attribute_list[i].len;
+        }
+    if (0 >= start) {
+       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+       lst[1] = (len + start - 3) >> 8;
+       lst[2] = (len + start - 3) & 0xff;
+    }
+
+    rsp[0] = end >> 8;
+    rsp[1] = end & 0xff;
+
+    if (end < len) {
+        len = end + start;
+        lst[end ++] = sizeof(int);
+        memcpy(lst + end, &len, sizeof(int));
+        end += sizeof(int);
+    } else
+        lst[end ++] = 0;
+
+    return end + 2;
+}
+
+static int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp,
+                const uint8_t **req, ssize_t *len)
+{
+    int i, j, start, end;
+    struct sdp_service_record_s *record;
+
+    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
+        (*req) ++;
+        if (*len < 3)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = start;
+        *len -= 3;
+    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
+        (*req) ++;
+        if (*len < 5)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = (*(*req) ++) << 8;
+        end |= *(*req) ++;
+        *len -= 5;
+    } else
+        return 1;
+
+    for (i = 0; i < sdp->services; i ++)
+        if ((record = &sdp->service_list[i])->match)
+            for (j = 0; j < record->attributes; j ++)
+                if (record->attribute_list[j].attribute_id >= start &&
+                                record->attribute_list[j].attribute_id <= end)
+                    record->attribute_list[j].match = 1;
+
+    return 0;
+}
+
+static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, j, start, end, max;
+    struct sdp_service_record_s *record;
+    uint8_t *lst;
+
+    /* Perform the search */
+    for (i = 0; i < sdp->services; i ++) {
+        sdp->service_list[i].match = 0;
+            for (j = 0; j < sdp->service_list[i].attributes; j ++)
+                sdp->service_list[i].attribute_list[j].match = 0;
+    }
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 3)
+        return -SDP_INVALID_SYNTAX;
+    max = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+    if (max < 0x0007)
+        return -SDP_INVALID_SYNTAX;
+
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_attr_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_attr_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1)
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    /* This assumes empty attribute lists are never to be returned even
+     * for matching Service Records.  In practice this shouldn't happen
+     * as the requestor will usually include the always present
+     * ServiceRecordHandle AttributeID in AttributeIDList.  */
+    lst = rsp + 2;
+    max = MIN(max, MAX_RSP_PARAM_SIZE);
+    len = 3 - start;
+    end = 0;
+    for (i = 0; i < sdp->services; i ++)
+        if ((record = &sdp->service_list[i])->match) {
+            len += 3;
+            seqlen = len;
+            for (j = 0; j < record->attributes; j ++)
+                if (record->attribute_list[j].match) {
+                    if (len >= 0)
+                        if (len + record->attribute_list[j].len < max) {
+                            memcpy(lst + len, record->attribute_list[j].pair,
+                                            record->attribute_list[j].len);
+                            end = len + record->attribute_list[j].len;
+                        }
+                    len += record->attribute_list[j].len;
+                }
+            if (seqlen == len)
+                len -= 3;
+            else if (seqlen >= 3 && seqlen < max) {
+                lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+                lst[seqlen - 2] = (len - seqlen) >> 8;
+                lst[seqlen - 1] = (len - seqlen) & 0xff;
+            }
+        }
+    if (len == 3 - start)
+        len -= 3;
+    else if (0 >= start) {
+       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+       lst[1] = (len + start - 3) >> 8;
+       lst[2] = (len + start - 3) & 0xff;
+    }
+
+    rsp[0] = end >> 8;
+    rsp[1] = end & 0xff;
+
+    if (end < len) {
+        len = end + start;
+        lst[end ++] = sizeof(int);
+        memcpy(lst + end, &len, sizeof(int));
+        end += sizeof(int);
+    } else
+        lst[end ++] = 0;
+
+    return end + 2;
+}
+
+static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_l2cap_sdp_state_s *sdp = opaque;
+    enum bt_sdp_cmd pdu_id;
+    uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out;
+    int transaction_id, plen;
+    int err = 0;
+    int rsp_len = 0;
+
+    if (len < 5) {
+        fprintf(stderr, "%s: short SDP PDU (%iB).\n", __FUNCTION__, len);
+        return;
+    }
+
+    pdu_id = *data ++;
+    transaction_id = (data[0] << 8) | data[1];
+    plen = (data[2] << 8) | data[3];
+    data += 4;
+    len -= 5;
+
+    if (len != plen) {
+        fprintf(stderr, "%s: wrong SDP PDU length (%iB != %iB).\n",
+                        __FUNCTION__, plen, len);
+        err = SDP_INVALID_PDU_SIZE;
+        goto respond;
+    }
+
+    switch (pdu_id) {
+    case SDP_SVC_SEARCH_REQ:
+        rsp_len = sdp_svc_search(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_SEARCH_RSP;
+        break;
+
+    case SDP_SVC_ATTR_REQ:
+        rsp_len = sdp_attr_get(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_ATTR_RSP;
+        break;
+
+    case SDP_SVC_SEARCH_ATTR_REQ:
+        rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
+        break;
+
+    case SDP_ERROR_RSP:
+    case SDP_SVC_ATTR_RSP:
+    case SDP_SVC_SEARCH_RSP:
+    case SDP_SVC_SEARCH_ATTR_RSP:
+    default:
+        fprintf(stderr, "%s: unexpected SDP PDU ID %02x.\n",
+                        __FUNCTION__, pdu_id);
+        err = SDP_INVALID_SYNTAX;
+        break;
+    }
+
+    if (rsp_len < 0) {
+        err = -rsp_len;
+        rsp_len = 0;
+    }
+
+respond:
+    if (err) {
+        pdu_id = SDP_ERROR_RSP;
+        rsp[rsp_len ++] = err >> 8;
+        rsp[rsp_len ++] = err & 0xff;
+    }
+
+    sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE);
+
+    sdu_out[0] = pdu_id;
+    sdu_out[1] = transaction_id >> 8;
+    sdu_out[2] = transaction_id & 0xff;
+    sdu_out[3] = rsp_len >> 8;
+    sdu_out[4] = rsp_len & 0xff;
+    memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len);
+
+    sdp->channel->sdu_submit(sdp->channel);
+}
+
+static void bt_l2cap_sdp_close_ch(void *opaque)
+{
+    struct bt_l2cap_sdp_state_s *sdp = opaque;
+    int i;
+
+    for (i = 0; i < sdp->services; i ++) {
+        qemu_free(sdp->service_list[i].attribute_list->pair);
+        qemu_free(sdp->service_list[i].attribute_list);
+        qemu_free(sdp->service_list[i].uuid);
+    }
+    qemu_free(sdp->service_list);
+    qemu_free(sdp);
+}
+
+struct sdp_def_service_s {
+    uint16_t class_uuid;
+    struct sdp_def_attribute_s {
+        uint16_t id;
+        struct sdp_def_data_element_s {
+            uint8_t type;
+            union {
+                uint32_t uint;
+                const char *str;
+                struct sdp_def_data_element_s *list;
+            } value;
+        } data;
+    } attributes[];
+};
+
+/* Calculate a safe byte count to allocate that will store the given
+ * element, at the same time count elements of a UUID type.  */
+static int sdp_attr_max_size(struct sdp_def_data_element_s *element,
+                int *uuids)
+{
+    int type = element->type & ~SDP_DSIZE_MASK;
+    int len;
+
+    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID ||
+                    type == SDP_DTYPE_BOOL) {
+        if (type == SDP_DTYPE_UUID)
+            (*uuids) ++;
+        return 1 + (1 << (element->type & SDP_DSIZE_MASK));
+    }
+
+    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
+        if (element->type & SDP_DSIZE_MASK) {
+            for (len = 0; element->value.str[len] |
+                            element->value.str[len + 1]; len ++);
+            return len;
+        } else
+            return 2 + strlen(element->value.str);
+    }
+
+    if (type != SDP_DTYPE_SEQ)
+        exit(-1);
+    len = 2;
+    element = element->value.list;
+    while (element->type)
+        len += sdp_attr_max_size(element ++, uuids);
+    if (len > 255)
+        exit (-1);
+
+    return len;
+}
+
+static int sdp_attr_write(uint8_t *data,
+                struct sdp_def_data_element_s *element, int **uuid)
+{
+    int type = element->type & ~SDP_DSIZE_MASK;
+    int len = 0;
+
+    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) {
+        data[len ++] = element->type;
+        if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1)
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) {
+            data[len ++] = (element->value.uint >>  8) & 0xff;
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) {
+            data[len ++] = (element->value.uint >>  24) & 0xff;
+            data[len ++] = (element->value.uint >>  16) & 0xff;
+            data[len ++] = (element->value.uint >>  8) & 0xff;
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        }
+
+        return len;
+    }
+
+    if (type == SDP_DTYPE_UUID) {
+        *(*uuid) ++ = element->value.uint;
+
+        data[len ++] = element->type;
+        data[len ++] = (element->value.uint >>  24) & 0xff;
+        data[len ++] = (element->value.uint >>  16) & 0xff;
+        data[len ++] = (element->value.uint >>  8) & 0xff;
+        data[len ++] = (element->value.uint >>  0) & 0xff;
+        memcpy(data + len, bt_base_uuid, 12);
+
+        return len + 12;
+    }
+
+    data[0] = type | SDP_DSIZE_NEXT1;
+    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
+        if (element->type & SDP_DSIZE_MASK)
+            for (len = 0; element->value.str[len] |
+                            element->value.str[len + 1]; len ++);
+        else
+            len = strlen(element->value.str);
+        memcpy(data + 2, element->value.str, data[1] = len);
+
+        return len + 2;
+    }
+
+    len = 2;
+    element = element->value.list;
+    while (element->type)
+        len += sdp_attr_write(data + len, element ++, uuid);
+    data[1] = len - 2;
+
+    return len;
+}
+
+static int sdp_attributeid_compare(const struct sdp_service_attribute_s *a,
+                const struct sdp_service_attribute_s *b)
+{
+    return (int) b->attribute_id - a->attribute_id;
+}
+
+static int sdp_uuid_compare(const int *a, const int *b)
+{
+    return *a - *b;
+}
+
+static void sdp_service_record_build(struct sdp_service_record_s *record,
+                struct sdp_def_service_s *def, int handle)
+{
+    int len = 0;
+    uint8_t *data;
+    int *uuid;
+
+    record->uuids = 0;
+    while (def->attributes[record->attributes].data.type) {
+        len += 3;
+        len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
+                        &record->uuids);
+    }
+    record->uuids = 1 << ffs(record->uuids - 1);
+    record->attribute_list =
+            qemu_mallocz(record->attributes * sizeof(*record->attribute_list));
+    record->uuid =
+            qemu_mallocz(record->uuids * sizeof(*record->uuid));
+    data = qemu_malloc(len);
+
+    record->attributes = 0;
+    uuid = record->uuid;
+    while (def->attributes[record->attributes].data.type) {
+        record->attribute_list[record->attributes].pair = data;
+
+        len = 0;
+        data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2;
+        data[len ++] = def->attributes[record->attributes].id >> 8;
+        data[len ++] = def->attributes[record->attributes].id & 0xff;
+        len += sdp_attr_write(data + len,
+                        &def->attributes[record->attributes].data, &uuid);
+
+        /* Special case: assign a ServiceRecordHandle in sequence */
+        if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE)
+            def->attributes[record->attributes].data.value.uint = handle;
+        /* Note: we could also assign a ServiceDescription based on
+         * sdp->device.device->lmp_name.  */
+
+        record->attribute_list[record->attributes ++].len = len;
+        data += len;
+    }
+
+    /* Sort the attribute list by the AttributeID */
+    qsort(record->attribute_list, record->attributes,
+                    sizeof(*record->attribute_list),
+                    (void *) sdp_attributeid_compare);
+    /* Sort the searchable UUIDs list for bisection */
+    qsort(record->uuid, record->uuids,
+                    sizeof(*record->uuid),
+                    (void *) sdp_uuid_compare);
+}
+
+static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
+                struct sdp_def_service_s **service)
+{
+    sdp->services = 0;
+    while (service[sdp->services])
+        sdp->services ++;
+    sdp->service_list =
+            qemu_mallocz(sdp->services * sizeof(*sdp->service_list));
+
+    sdp->services = 0;
+    while (*service) {
+        sdp_service_record_build(&sdp->service_list[sdp->services],
+                        *service, sdp->services);
+        service ++;
+        sdp->services ++;
+    }
+}
+
+#define LAST { .type = 0 }
+#define SERVICE(name, attrs)				\
+    static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \
+        .attributes = { attrs { .data = LAST } },	\
+    };
+#define ATTRIBUTE(attrid, val)	{ .id = glue(SDP_ATTR_, attrid), .data = val },
+#define UINT8(val)	{				\
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_1,	\
+        .value.uint = val,				\
+    },
+#define UINT16(val)	{				\
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_2,	\
+        .value.uint = val,				\
+    },
+#define UINT32(val)	{				\
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_4,	\
+        .value.uint = val,				\
+    },
+#define UUID128(val)	{				\
+        .type       = SDP_DTYPE_UUID | SDP_DSIZE_16,	\
+        .value.uint = val,				\
+    },
+#define TRUE	{				\
+        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,	\
+        .value.uint = 1,				\
+    },
+#define FALSE	{				\
+        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,	\
+        .value.uint = 0,				\
+    },
+#define STRING(val)	{				\
+        .type       = SDP_DTYPE_STRING,			\
+        .value.str  = val,				\
+    },
+#define ARRAY(...)	{				\
+        .type       = SDP_DTYPE_STRING | SDP_DSIZE_2,	\
+        .value.str  = (char []) { __VA_ARGS__, 0, 0 },	\
+    },
+#define URL(val)	{				\
+        .type       = SDP_DTYPE_URL,			\
+        .value.str  = val,				\
+    },
+#if 1
+#define LIST(val)	{				\
+        .type       = SDP_DTYPE_SEQ,			\
+        .value.list = (struct sdp_def_data_element_s []) { val LAST }, \
+    },
+#endif
+
+/* Try to keep each single attribute below MAX_PDU_OUT_SIZE bytes
+ * in resulting SDP data representation size.  */
+
+SERVICE(hid,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL))
+        LIST(UUID128(HIDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID"))
+    ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+
+    /* Profile specific */
+    ATTRIBUTE(DEVICE_RELEASE_NUMBER,	UINT16(0x0091)) /* Deprecated, remove */
+    ATTRIBUTE(PARSER_VERSION,		UINT16(0x0111))
+    /* TODO: extract from l2cap_device->device.class[0] */
+    ATTRIBUTE(DEVICE_SUBCLASS,		UINT8(0x40))
+    ATTRIBUTE(COUNTRY_CODE,		UINT8(0x15))
+    ATTRIBUTE(VIRTUAL_CABLE,		TRUE)
+    ATTRIBUTE(RECONNECT_INITIATE,	FALSE)
+    /* TODO: extract from hid->usbdev->report_desc */
+    ATTRIBUTE(DESCRIPTOR_LIST,		LIST(
+        LIST(UINT8(0x22) ARRAY(
+            0x05, 0x01,	/* Usage Page (Generic Desktop) */
+            0x09, 0x06,	/* Usage (Keyboard) */
+            0xa1, 0x01,	/* Collection (Application) */
+            0x75, 0x01,	/*   Report Size (1) */
+            0x95, 0x08,	/*   Report Count (8) */
+            0x05, 0x07,	/*   Usage Page (Key Codes) */
+            0x19, 0xe0,	/*   Usage Minimum (224) */
+            0x29, 0xe7,	/*   Usage Maximum (231) */
+            0x15, 0x00,	/*   Logical Minimum (0) */
+            0x25, 0x01,	/*   Logical Maximum (1) */
+            0x81, 0x02,	/*   Input (Data, Variable, Absolute) */
+            0x95, 0x01,	/*   Report Count (1) */
+            0x75, 0x08,	/*   Report Size (8) */
+            0x81, 0x01,	/*   Input (Constant) */
+            0x95, 0x05,	/*   Report Count (5) */
+            0x75, 0x01,	/*   Report Size (1) */
+            0x05, 0x08,	/*   Usage Page (LEDs) */
+            0x19, 0x01,	/*   Usage Minimum (1) */
+            0x29, 0x05,	/*   Usage Maximum (5) */
+            0x91, 0x02,	/*   Output (Data, Variable, Absolute) */
+            0x95, 0x01,	/*   Report Count (1) */
+            0x75, 0x03,	/*   Report Size (3) */
+            0x91, 0x01,	/*   Output (Constant) */
+            0x95, 0x06,	/*   Report Count (6) */
+            0x75, 0x08,	/*   Report Size (8) */
+            0x15, 0x00,	/*   Logical Minimum (0) */
+            0x25, 0xff,	/*   Logical Maximum (255) */
+            0x05, 0x07,	/*   Usage Page (Key Codes) */
+            0x19, 0x00,	/*   Usage Minimum (0) */
+            0x29, 0xff,	/*   Usage Maximum (255) */
+            0x81, 0x00,	/*   Input (Data, Array) */
+            0xc0	/* End Collection */
+    ))))
+    ATTRIBUTE(LANG_ID_BASE_LIST,	LIST(
+        LIST(UINT16(0x0409) UINT16(0x0100))
+    ))
+    ATTRIBUTE(SDP_DISABLE,		FALSE)
+    ATTRIBUTE(BATTERY_POWER,		TRUE)
+    ATTRIBUTE(REMOTE_WAKEUP,		TRUE)
+    ATTRIBUTE(BOOT_DEVICE,		TRUE)	/* XXX: untested */
+    ATTRIBUTE(SUPERVISION_TIMEOUT,	UINT16(0x0c80))
+    ATTRIBUTE(NORMALLY_CONNECTABLE,	TRUE)
+    ATTRIBUTE(PROFILE_VERSION,		UINT16(0x0100))
+)
+
+SERVICE(sdp,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
+        LIST(UUID128(SDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+
+    /* Profile specific */
+    ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100)))
+    ATTRIBUTE(SVCDB_STATE    , UINT32(1))
+)
+
+SERVICE(pnp,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))	/* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
+        LIST(UUID128(SDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+
+    /* Profile specific */
+    ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
+    ATTRIBUTE(VERSION,         UINT16(0x0100))
+    ATTRIBUTE(PRIMARY_RECORD,  TRUE)
+)
+
+static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_l2cap_sdp_state_s *sdp = qemu_mallocz(sizeof(*sdp));
+    struct sdp_def_service_s *services[] = {
+        &sdp_service_sdp_s,
+        &sdp_service_hid_s,
+        &sdp_service_pnp_s,
+        NULL,
+    };
+
+    sdp->channel = params;
+    sdp->channel->opaque = sdp;
+    sdp->channel->close = bt_l2cap_sdp_close_ch;
+    sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in;
+
+    sdp_service_db_build(sdp, services);
+
+    return 0;
+}
+
+void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev)
+{
+    bt_l2cap_psm_register(dev, BT_PSM_SDP,
+                    MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch);
+}
diff --git a/hw/bt.c b/hw/bt.c
new file mode 100644
index 0000000..3f886b4
--- /dev/null
+++ b/hw/bt.c
@@ -0,0 +1,122 @@
+/*
+ * Convenience functions for bluetooth.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "qemu-common.h"
+#include "net.h"
+#include "bt.h"
+
+/* Slave implementations can ignore this */
+static void bt_dummy_lmp_mode_change(struct bt_link_s *link)
+{
+}
+
+/* Slaves should never receive these PDUs */
+static void bt_dummy_lmp_connection_complete(struct bt_link_s *link)
+{
+    if (link->slave->reject_reason)
+        fprintf(stderr, "%s: stray LMP_not_accepted received, fixme\n",
+                        __FUNCTION__);
+    else
+        fprintf(stderr, "%s: stray LMP_accepted received, fixme\n",
+                        __FUNCTION__);
+    exit(-1);
+}
+
+static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link)
+{
+    fprintf(stderr, "%s: stray LMP_detach received, fixme\n", __FUNCTION__);
+    exit(-1);
+}
+
+static void bt_dummy_lmp_acl_resp(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    fprintf(stderr, "%s: stray ACL response PDU, fixme\n", __FUNCTION__);
+    exit(-1);
+}
+
+/* Slaves that don't hold any additional per link state can use these */
+static void bt_dummy_lmp_connection_request(struct bt_link_s *req)
+{
+    struct bt_link_s *link = qemu_mallocz(sizeof(struct bt_link_s));
+
+    link->slave = req->slave;
+    link->host = req->host;
+
+    req->host->reject_reason = 0;
+    req->host->lmp_connection_complete(link);
+}
+
+static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link)
+{
+    qemu_free(link);
+}
+
+static void bt_dummy_destroy(struct bt_device_s *device)
+{
+    bt_device_done(device);
+    qemu_free(device);
+}
+
+static int bt_dev_idx = 0;
+
+void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net)
+{
+    memset(dev, 0, sizeof(*dev));
+    dev->inquiry_scan = 1;
+    dev->page_scan = 1;
+
+    dev->bd_addr.b[0] = bt_dev_idx & 0xff;
+    dev->bd_addr.b[1] = bt_dev_idx >> 8;
+    dev->bd_addr.b[2] = 0xd0;
+    dev->bd_addr.b[3] = 0xba;
+    dev->bd_addr.b[4] = 0xbe;
+    dev->bd_addr.b[5] = 0xba;
+    bt_dev_idx ++;
+
+    /* Simple slave-only devices need to implement only .lmp_acl_data */
+    dev->lmp_connection_complete = bt_dummy_lmp_connection_complete;
+    dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master;
+    dev->lmp_acl_resp = bt_dummy_lmp_acl_resp;
+    dev->lmp_mode_change = bt_dummy_lmp_mode_change;
+    dev->lmp_connection_request = bt_dummy_lmp_connection_request;
+    dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave;
+
+    dev->handle_destroy = bt_dummy_destroy;
+
+    dev->net = net;
+    dev->next = net->slave;
+    net->slave = dev;
+}
+
+void bt_device_done(struct bt_device_s *dev)
+{
+    struct bt_device_s **p = &dev->net->slave;
+
+    while (*p && *p != dev)
+        p = &(*p)->next;
+    if (*p != dev) {
+        fprintf(stderr, "%s: bad bt device \"%s\"\n", __FUNCTION__,
+                        dev->lmp_name ?: "(null)");
+        exit(-1);
+    }
+
+    *p = dev->next;
+}
diff --git a/hw/bt.h b/hw/bt.h
new file mode 100644
index 0000000..726905f
--- /dev/null
+++ b/hw/bt.h
@@ -0,0 +1,2185 @@
+/*
+ * QEMU Bluetooth HCI helpers.
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * Useful definitions taken from BlueZ project's headers.
+ * Copyright (C) 2000-2001  Qualcomm Incorporated
+ * Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2006  Marcel Holtmann <marcel@holtmann.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ */
+
+/* BD Address */
+typedef struct {
+    uint8_t b[6];
+} __attribute__((packed)) bdaddr_t;
+
+#define BDADDR_ANY	(&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
+#define BDADDR_ALL	(&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
+#define BDADDR_LOCAL	(&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+
+/* Copy, swap, convert BD Address */
+static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
+{
+    return memcmp(ba1, ba2, sizeof(bdaddr_t));
+}
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
+{
+    memcpy(dst, src, sizeof(bdaddr_t));
+}
+
+#define BAINIT(orig)	{ .b = {		\
+    (orig)->b[0], (orig)->b[1], (orig)->b[2],	\
+    (orig)->b[3], (orig)->b[4], (orig)->b[5],	\
+}, }
+
+/* The twisted structures of a bluetooth environment */
+struct bt_device_s;
+struct bt_scatternet_s;
+struct bt_piconet_s;
+struct bt_link_s;
+
+struct bt_scatternet_s {
+    struct bt_device_s *slave;
+};
+
+struct bt_link_s {
+    struct bt_device_s *slave, *host;
+    uint16_t handle;		/* Master (host) side handle */
+    uint16_t acl_interval;
+    enum {
+        acl_active,
+        acl_hold,
+        acl_sniff,
+        acl_parked,
+    } acl_mode;
+};
+
+struct bt_device_s {
+    int lt_addr;
+    bdaddr_t bd_addr;
+    int mtu;
+    int setup;
+    struct bt_scatternet_s *net;
+
+    uint8_t key[16];
+    int key_present;
+    uint8_t class[3];
+
+    uint8_t reject_reason;
+
+    uint64_t lmp_caps;
+    const char *lmp_name;
+    void (*lmp_connection_request)(struct bt_link_s *link);
+    void (*lmp_connection_complete)(struct bt_link_s *link);
+    void (*lmp_disconnect_master)(struct bt_link_s *link);
+    void (*lmp_disconnect_slave)(struct bt_link_s *link);
+    void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data,
+                    int start, int len);
+    void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data,
+                    int start, int len);
+    void (*lmp_mode_change)(struct bt_link_s *link);
+
+    void (*handle_destroy)(struct bt_device_s *device);
+    struct bt_device_s *next;	/* Next in the piconet/scatternet */
+
+    int inquiry_scan;
+    int page_scan;
+
+    uint16_t clkoff;	/* Note: Always little-endian */
+};
+
+/* bt.c */
+void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net);
+void bt_device_done(struct bt_device_s *dev);
+
+/* bt-hci.c */
+struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net);
+
+/* bt-vhci.c */
+void bt_vhci_init(struct HCIInfo *info);
+
+/* bt-hci-csr.c */
+enum {
+    csrhci_pin_reset,
+    csrhci_pin_wakeup,
+    __csrhci_pins,
+};
+qemu_irq *csrhci_pins_get(CharDriverState *chr);
+CharDriverState *uart_hci_init(qemu_irq wakeup);
+
+/* bt-l2cap.c */
+struct bt_l2cap_device_s;
+struct bt_l2cap_conn_params_s;
+struct bt_l2cap_psm_s;
+void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
+                struct bt_scatternet_s *net);
+void bt_l2cap_device_done(struct bt_l2cap_device_s *dev);
+void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm,
+                int min_mtu, int (*new_channel)(struct bt_l2cap_device_s *dev,
+                        struct bt_l2cap_conn_params_s *params));
+
+struct bt_l2cap_device_s {
+    struct bt_device_s device;
+    struct bt_l2cap_psm_s *first_psm;
+};
+
+struct bt_l2cap_conn_params_s {
+    /* Input */
+    uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len);
+    void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan);
+    int remote_mtu;
+    /* Output */
+    void *opaque;
+    void (*sdu_in)(void *opaque, const uint8_t *data, int len);
+    void (*close)(void *opaque);
+};
+
+enum bt_l2cap_psm_predef {
+    BT_PSM_SDP		= 0x0001,
+    BT_PSM_RFCOMM	= 0x0003,
+    BT_PSM_TELEPHONY	= 0x0005,
+    BT_PSM_TCS		= 0x0007,
+    BT_PSM_BNEP		= 0x000f,
+    BT_PSM_HID_CTRL	= 0x0011,
+    BT_PSM_HID_INTR	= 0x0013,
+    BT_PSM_UPNP		= 0x0015,
+    BT_PSM_AVCTP	= 0x0017,
+    BT_PSM_AVDTP	= 0x0019,
+};
+
+/* bt-sdp.c */
+void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev);
+
+/* bt-hid.c */
+struct bt_device_s *bt_mouse_init(struct bt_scatternet_s *net);
+struct bt_device_s *bt_tablet_init(struct bt_scatternet_s *net);
+struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net);
+
+/* Link Management Protocol layer defines */
+
+#define LLID_ACLU_CONT		0x1
+#define LLID_ACLU_START		0x2
+#define LLID_ACLC		0x3
+
+enum lmp_pdu_type {
+    LMP_NAME_REQ		= 0x0001,
+    LMP_NAME_RES		= 0x0002,
+    LMP_ACCEPTED		= 0x0003,
+    LMP_NOT_ACCEPTED		= 0x0004,
+    LMP_CLKOFFSET_REQ		= 0x0005,
+    LMP_CLKOFFSET_RES		= 0x0006,
+    LMP_DETACH			= 0x0007,
+    LMP_IN_RAND			= 0x0008,
+    LMP_COMB_KEY		= 0x0009,
+    LMP_UNIT_KEY		= 0x000a,
+    LMP_AU_RAND			= 0x000b,
+    LMP_SRES			= 0x000c,
+    LMP_TEMP_RAND		= 0x000d,
+    LMP_TEMP_KEY		= 0x000e,
+    LMP_CRYPT_MODE_REQ		= 0x000f,
+    LMP_CRYPT_KEY_SIZE_REQ	= 0x0010,
+    LMP_START_ENCRYPT_REQ	= 0x0011,
+    LMP_STOP_ENCRYPT_REQ	= 0x0012,
+    LMP_SWITCH_REQ		= 0x0013,
+    LMP_HOLD			= 0x0014,
+    LMP_HOLD_REQ		= 0x0015,
+    LMP_SNIFF_REQ		= 0x0017,
+    LMP_UNSNIFF_REQ		= 0x0018,
+    LMP_LMP_PARK_REQ		= 0x0019,
+    LMP_SET_BCAST_SCAN_WND	= 0x001b,
+    LMP_MODIFY_BEACON		= 0x001c,
+    LMP_UNPARK_BD_ADDR_REQ	= 0x001d,
+    LMP_UNPARK_PM_ADDR_REQ	= 0x001e,
+    LMP_INCR_POWER_REQ		= 0x001f,
+    LMP_DECR_POWER_REQ		= 0x0020,
+    LMP_MAX_POWER		= 0x0021,
+    LMP_MIN_POWER		= 0x0022,
+    LMP_AUTO_RATE		= 0x0023,
+    LMP_PREFERRED_RATE		= 0x0024,
+    LMP_VERSION_REQ		= 0x0025,
+    LMP_VERSION_RES		= 0x0026,
+    LMP_FEATURES_REQ		= 0x0027,
+    LMP_FEATURES_RES		= 0x0028,
+    LMP_QUALITY_OF_SERVICE	= 0x0029,
+    LMP_QOS_REQ			= 0x002a,
+    LMP_RM_SCO_LINK_REQ		= 0x002b,
+    LMP_SCO_LINK_REQ		= 0x002c,
+    LMP_MAX_SLOT		= 0x002d,
+    LMP_MAX_SLOT_REQ		= 0x002e,
+    LMP_TIMING_ACCURACY_REQ	= 0x002f,
+    LMP_TIMING_ACCURACY_RES	= 0x0030,
+    LMP_SETUP_COMPLETE		= 0x0031,
+    LMP_USE_SEMIPERM_KEY	= 0x0032,
+    LMP_HOST_CONNECTION_REQ	= 0x0033,
+    LMP_SLOT_OFFSET		= 0x0034,
+    LMP_PAGE_MODE_REQ		= 0x0035,
+    LMP_PAGE_SCAN_MODE_REQ	= 0x0036,
+    LMP_SUPERVISION_TIMEOUT	= 0x0037,
+    LMP_TEST_ACTIVATE		= 0x0038,
+    LMP_TEST_CONTROL		= 0x0039,
+    LMP_CRYPT_KEY_MASK_REQ	= 0x003a,
+    LMP_CRYPT_KEY_MASK_RES	= 0x003b,
+    LMP_SET_AFH			= 0x003c,
+    LMP_ACCEPTED_EXT		= 0x7f01,
+    LMP_NOT_ACCEPTED_EXT	= 0x7f02,
+    LMP_FEATURES_REQ_EXT	= 0x7f03,
+    LMP_FEATURES_RES_EXT	= 0x7f04,
+    LMP_PACKET_TYPE_TBL_REQ	= 0x7f0b,
+    LMP_ESCO_LINK_REQ		= 0x7f0c,
+    LMP_RM_ESCO_LINK_REQ	= 0x7f0d,
+    LMP_CHANNEL_CLASS_REQ	= 0x7f10,
+    LMP_CHANNEL_CLASS		= 0x7f11,
+};
+
+/* Host Controller Interface layer defines */
+
+enum hci_packet_type {
+    HCI_COMMAND_PKT		= 0x01,
+    HCI_ACLDATA_PKT		= 0x02,
+    HCI_SCODATA_PKT		= 0x03,
+    HCI_EVENT_PKT		= 0x04,
+    HCI_VENDOR_PKT		= 0xff,
+};
+
+enum bt_packet_type {
+    HCI_2DH1	= 1 << 1,
+    HCI_3DH1	= 1 << 2,
+    HCI_DM1	= 1 << 3,
+    HCI_DH1	= 1 << 4,
+    HCI_2DH3	= 1 << 8,
+    HCI_3DH3	= 1 << 9,
+    HCI_DM3	= 1 << 10,
+    HCI_DH3	= 1 << 11,
+    HCI_2DH5	= 1 << 12,
+    HCI_3DH5	= 1 << 13,
+    HCI_DM5	= 1 << 14,
+    HCI_DH5	= 1 << 15,
+};
+
+enum sco_packet_type {
+    HCI_HV1	= 1 << 5,
+    HCI_HV2	= 1 << 6,
+    HCI_HV3	= 1 << 7,
+};
+
+enum ev_packet_type {
+    HCI_EV3	= 1 << 3,
+    HCI_EV4	= 1 << 4,
+    HCI_EV5	= 1 << 5,
+    HCI_2EV3	= 1 << 6,
+    HCI_3EV3	= 1 << 7,
+    HCI_2EV5	= 1 << 8,
+    HCI_3EV5	= 1 << 9,
+};
+
+enum hci_error_code {
+    HCI_SUCCESS				= 0x00,
+    HCI_UNKNOWN_COMMAND			= 0x01,
+    HCI_NO_CONNECTION			= 0x02,
+    HCI_HARDWARE_FAILURE		= 0x03,
+    HCI_PAGE_TIMEOUT			= 0x04,
+    HCI_AUTHENTICATION_FAILURE		= 0x05,
+    HCI_PIN_OR_KEY_MISSING		= 0x06,
+    HCI_MEMORY_FULL			= 0x07,
+    HCI_CONNECTION_TIMEOUT		= 0x08,
+    HCI_MAX_NUMBER_OF_CONNECTIONS	= 0x09,
+    HCI_MAX_NUMBER_OF_SCO_CONNECTIONS	= 0x0a,
+    HCI_ACL_CONNECTION_EXISTS		= 0x0b,
+    HCI_COMMAND_DISALLOWED		= 0x0c,
+    HCI_REJECTED_LIMITED_RESOURCES	= 0x0d,
+    HCI_REJECTED_SECURITY		= 0x0e,
+    HCI_REJECTED_PERSONAL		= 0x0f,
+    HCI_HOST_TIMEOUT			= 0x10,
+    HCI_UNSUPPORTED_FEATURE		= 0x11,
+    HCI_INVALID_PARAMETERS		= 0x12,
+    HCI_OE_USER_ENDED_CONNECTION	= 0x13,
+    HCI_OE_LOW_RESOURCES		= 0x14,
+    HCI_OE_POWER_OFF			= 0x15,
+    HCI_CONNECTION_TERMINATED		= 0x16,
+    HCI_REPEATED_ATTEMPTS		= 0x17,
+    HCI_PAIRING_NOT_ALLOWED		= 0x18,
+    HCI_UNKNOWN_LMP_PDU			= 0x19,
+    HCI_UNSUPPORTED_REMOTE_FEATURE	= 0x1a,
+    HCI_SCO_OFFSET_REJECTED		= 0x1b,
+    HCI_SCO_INTERVAL_REJECTED		= 0x1c,
+    HCI_AIR_MODE_REJECTED		= 0x1d,
+    HCI_INVALID_LMP_PARAMETERS		= 0x1e,
+    HCI_UNSPECIFIED_ERROR		= 0x1f,
+    HCI_UNSUPPORTED_LMP_PARAMETER_VALUE	= 0x20,
+    HCI_ROLE_CHANGE_NOT_ALLOWED		= 0x21,
+    HCI_LMP_RESPONSE_TIMEOUT		= 0x22,
+    HCI_LMP_ERROR_TRANSACTION_COLLISION	= 0x23,
+    HCI_LMP_PDU_NOT_ALLOWED		= 0x24,
+    HCI_ENCRYPTION_MODE_NOT_ACCEPTED	= 0x25,
+    HCI_UNIT_LINK_KEY_USED		= 0x26,
+    HCI_QOS_NOT_SUPPORTED		= 0x27,
+    HCI_INSTANT_PASSED			= 0x28,
+    HCI_PAIRING_NOT_SUPPORTED		= 0x29,
+    HCI_TRANSACTION_COLLISION		= 0x2a,
+    HCI_QOS_UNACCEPTABLE_PARAMETER	= 0x2c,
+    HCI_QOS_REJECTED			= 0x2d,
+    HCI_CLASSIFICATION_NOT_SUPPORTED	= 0x2e,
+    HCI_INSUFFICIENT_SECURITY		= 0x2f,
+    HCI_PARAMETER_OUT_OF_RANGE		= 0x30,
+    HCI_ROLE_SWITCH_PENDING		= 0x32,
+    HCI_SLOT_VIOLATION			= 0x34,
+    HCI_ROLE_SWITCH_FAILED		= 0x35,
+};
+
+enum acl_flag_bits {
+    ACL_CONT		= 1 << 0,
+    ACL_START		= 1 << 1,
+    ACL_ACTIVE_BCAST	= 1 << 2,
+    ACL_PICO_BCAST	= 1 << 3,
+};
+
+enum baseband_link_type {
+    SCO_LINK		= 0x00,
+    ACL_LINK		= 0x01,
+};
+
+enum lmp_feature_bits0 {
+    LMP_3SLOT		= 1 << 0,
+    LMP_5SLOT		= 1 << 1,
+    LMP_ENCRYPT		= 1 << 2,
+    LMP_SOFFSET		= 1 << 3,
+    LMP_TACCURACY	= 1 << 4,
+    LMP_RSWITCH		= 1 << 5,
+    LMP_HOLD_MODE	= 1 << 6,
+    LMP_SNIFF_MODE	= 1 << 7,
+};
+
+enum lmp_feature_bits1 {
+    LMP_PARK		= 1 << 0,
+    LMP_RSSI		= 1 << 1,
+    LMP_QUALITY		= 1 << 2,
+    LMP_SCO		= 1 << 3,
+    LMP_HV2		= 1 << 4,
+    LMP_HV3		= 1 << 5,
+    LMP_ULAW		= 1 << 6,
+    LMP_ALAW		= 1 << 7,
+};
+
+enum lmp_feature_bits2 {
+    LMP_CVSD		= 1 << 0,
+    LMP_PSCHEME		= 1 << 1,
+    LMP_PCONTROL	= 1 << 2,
+    LMP_TRSP_SCO	= 1 << 3,
+    LMP_BCAST_ENC	= 1 << 7,
+};
+
+enum lmp_feature_bits3 {
+    LMP_EDR_ACL_2M	= 1 << 1,
+    LMP_EDR_ACL_3M	= 1 << 2,
+    LMP_ENH_ISCAN	= 1 << 3,
+    LMP_ILACE_ISCAN	= 1 << 4,
+    LMP_ILACE_PSCAN	= 1 << 5,
+    LMP_RSSI_INQ	= 1 << 6,
+    LMP_ESCO		= 1 << 7,
+};
+
+enum lmp_feature_bits4 {
+    LMP_EV4		= 1 << 0,
+    LMP_EV5		= 1 << 1,
+    LMP_AFH_CAP_SLV	= 1 << 3,
+    LMP_AFH_CLS_SLV	= 1 << 4,
+    LMP_EDR_3SLOT	= 1 << 7,
+};
+
+enum lmp_feature_bits5 {
+    LMP_EDR_5SLOT	= 1 << 0,
+    LMP_SNIFF_SUBR	= 1 << 1,
+    LMP_AFH_CAP_MST	= 1 << 3,
+    LMP_AFH_CLS_MST	= 1 << 4,
+    LMP_EDR_ESCO_2M	= 1 << 5,
+    LMP_EDR_ESCO_3M	= 1 << 6,
+    LMP_EDR_3S_ESCO	= 1 << 7,
+};
+
+enum lmp_feature_bits6 {
+    LMP_EXT_INQ		= 1 << 0,
+};
+
+enum lmp_feature_bits7 {
+    LMP_EXT_FEAT	= 1 << 7,
+};
+
+enum hci_link_policy {
+    HCI_LP_RSWITCH	= 1 << 0,
+    HCI_LP_HOLD		= 1 << 1,
+    HCI_LP_SNIFF	= 1 << 2,
+    HCI_LP_PARK		= 1 << 3,
+};
+
+enum hci_link_mode {
+    HCI_LM_ACCEPT	= 1 << 15,
+    HCI_LM_MASTER	= 1 << 0,
+    HCI_LM_AUTH		= 1 << 1,
+    HCI_LM_ENCRYPT	= 1 << 2,
+    HCI_LM_TRUSTED	= 1 << 3,
+    HCI_LM_RELIABLE	= 1 << 4,
+    HCI_LM_SECURE	= 1 << 5,
+};
+
+/* HCI Commands */
+
+/* Link Control */
+#define OGF_LINK_CTL		0x01
+
+#define OCF_INQUIRY			0x0001
+typedef struct {
+    uint8_t	lap[3];
+    uint8_t	length;		/* 1.28s units */
+    uint8_t	num_rsp;
+} __attribute__ ((packed)) inquiry_cp;
+#define INQUIRY_CP_SIZE 5
+
+typedef struct {
+    uint8_t		status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) status_bdaddr_rp;
+#define STATUS_BDADDR_RP_SIZE 7
+
+#define OCF_INQUIRY_CANCEL		0x0002
+
+#define OCF_PERIODIC_INQUIRY		0x0003
+typedef struct {
+    uint16_t	max_period;	/* 1.28s units */
+    uint16_t	min_period;	/* 1.28s units */
+    uint8_t	lap[3];
+    uint8_t	length;		/* 1.28s units */
+    uint8_t	num_rsp;
+} __attribute__ ((packed)) periodic_inquiry_cp;
+#define PERIODIC_INQUIRY_CP_SIZE 9
+
+#define OCF_EXIT_PERIODIC_INQUIRY	0x0004
+
+#define OCF_CREATE_CONN			0x0005
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint16_t	pkt_type;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_mode;
+    uint16_t	clock_offset;
+    uint8_t	role_switch;
+} __attribute__ ((packed)) create_conn_cp;
+#define CREATE_CONN_CP_SIZE 13
+
+#define OCF_DISCONNECT			0x0006
+typedef struct {
+    uint16_t	handle;
+    uint8_t	reason;
+} __attribute__ ((packed)) disconnect_cp;
+#define DISCONNECT_CP_SIZE 3
+
+#define OCF_ADD_SCO			0x0007
+typedef struct {
+    uint16_t	handle;
+    uint16_t	pkt_type;
+} __attribute__ ((packed)) add_sco_cp;
+#define ADD_SCO_CP_SIZE 4
+
+#define OCF_CREATE_CONN_CANCEL		0x0008
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) create_conn_cancel_cp;
+#define CREATE_CONN_CANCEL_CP_SIZE 6
+
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) create_conn_cancel_rp;
+#define CREATE_CONN_CANCEL_RP_SIZE 7
+
+#define OCF_ACCEPT_CONN_REQ		0x0009
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	role;
+} __attribute__ ((packed)) accept_conn_req_cp;
+#define ACCEPT_CONN_REQ_CP_SIZE	7
+
+#define OCF_REJECT_CONN_REQ		0x000A
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	reason;
+} __attribute__ ((packed)) reject_conn_req_cp;
+#define REJECT_CONN_REQ_CP_SIZE	7
+
+#define OCF_LINK_KEY_REPLY		0x000B
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	link_key[16];
+} __attribute__ ((packed)) link_key_reply_cp;
+#define LINK_KEY_REPLY_CP_SIZE 22
+
+#define OCF_LINK_KEY_NEG_REPLY		0x000C
+
+#define OCF_PIN_CODE_REPLY		0x000D
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	pin_len;
+    uint8_t	pin_code[16];
+} __attribute__ ((packed)) pin_code_reply_cp;
+#define PIN_CODE_REPLY_CP_SIZE 23
+
+#define OCF_PIN_CODE_NEG_REPLY		0x000E
+
+#define OCF_SET_CONN_PTYPE		0x000F
+typedef struct {
+    uint16_t	 handle;
+    uint16_t	 pkt_type;
+} __attribute__ ((packed)) set_conn_ptype_cp;
+#define SET_CONN_PTYPE_CP_SIZE 4
+
+#define OCF_AUTH_REQUESTED		0x0011
+typedef struct {
+    uint16_t	 handle;
+} __attribute__ ((packed)) auth_requested_cp;
+#define AUTH_REQUESTED_CP_SIZE 2
+
+#define OCF_SET_CONN_ENCRYPT		0x0013
+typedef struct {
+    uint16_t	handle;
+    uint8_t	encrypt;
+} __attribute__ ((packed)) set_conn_encrypt_cp;
+#define SET_CONN_ENCRYPT_CP_SIZE 3
+
+#define OCF_CHANGE_CONN_LINK_KEY	0x0015
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) change_conn_link_key_cp;
+#define CHANGE_CONN_LINK_KEY_CP_SIZE 2
+
+#define OCF_MASTER_LINK_KEY		0x0017
+typedef struct {
+    uint8_t	key_flag;
+} __attribute__ ((packed)) master_link_key_cp;
+#define MASTER_LINK_KEY_CP_SIZE 1
+
+#define OCF_REMOTE_NAME_REQ		0x0019
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_mode;
+    uint16_t	clock_offset;
+} __attribute__ ((packed)) remote_name_req_cp;
+#define REMOTE_NAME_REQ_CP_SIZE 10
+
+#define OCF_REMOTE_NAME_REQ_CANCEL	0x001A
+typedef struct {
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) remote_name_req_cancel_cp;
+#define REMOTE_NAME_REQ_CANCEL_CP_SIZE 6
+
+typedef struct {
+    uint8_t		status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) remote_name_req_cancel_rp;
+#define REMOTE_NAME_REQ_CANCEL_RP_SIZE 7
+
+#define OCF_READ_REMOTE_FEATURES	0x001B
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_remote_features_cp;
+#define READ_REMOTE_FEATURES_CP_SIZE 2
+
+#define OCF_READ_REMOTE_EXT_FEATURES	0x001C
+typedef struct {
+    uint16_t	handle;
+    uint8_t	page_num;
+} __attribute__ ((packed)) read_remote_ext_features_cp;
+#define READ_REMOTE_EXT_FEATURES_CP_SIZE 3
+
+#define OCF_READ_REMOTE_VERSION		0x001D
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_remote_version_cp;
+#define READ_REMOTE_VERSION_CP_SIZE 2
+
+#define OCF_READ_CLOCK_OFFSET		0x001F
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_clock_offset_cp;
+#define READ_CLOCK_OFFSET_CP_SIZE 2
+
+#define OCF_READ_LMP_HANDLE		0x0020
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_lmp_handle_cp;
+#define READ_LMP_HANDLE_CP_SIZE 2
+
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	lmp_handle;
+    uint32_t	reserved;
+} __attribute__ ((packed)) read_lmp_handle_rp;
+#define READ_LMP_HANDLE_RP_SIZE 8
+
+#define OCF_SETUP_SYNC_CONN		0x0028
+typedef struct {
+    uint16_t	handle;
+    uint32_t	tx_bandwith;
+    uint32_t	rx_bandwith;
+    uint16_t	max_latency;
+    uint16_t	voice_setting;
+    uint8_t	retrans_effort;
+    uint16_t	pkt_type;
+} __attribute__ ((packed)) setup_sync_conn_cp;
+#define SETUP_SYNC_CONN_CP_SIZE 17
+
+#define OCF_ACCEPT_SYNC_CONN_REQ	0x0029
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint32_t	tx_bandwith;
+    uint32_t	rx_bandwith;
+    uint16_t	max_latency;
+    uint16_t	voice_setting;
+    uint8_t	retrans_effort;
+    uint16_t	pkt_type;
+} __attribute__ ((packed)) accept_sync_conn_req_cp;
+#define ACCEPT_SYNC_CONN_REQ_CP_SIZE 21
+
+#define OCF_REJECT_SYNC_CONN_REQ	0x002A
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	reason;
+} __attribute__ ((packed)) reject_sync_conn_req_cp;
+#define REJECT_SYNC_CONN_REQ_CP_SIZE 7
+
+/* Link Policy */
+#define OGF_LINK_POLICY		0x02
+
+#define OCF_HOLD_MODE			0x0001
+typedef struct {
+    uint16_t	handle;
+    uint16_t	max_interval;
+    uint16_t	min_interval;
+} __attribute__ ((packed)) hold_mode_cp;
+#define HOLD_MODE_CP_SIZE 6
+
+#define OCF_SNIFF_MODE			0x0003
+typedef struct {
+    uint16_t	handle;
+    uint16_t	max_interval;
+    uint16_t	min_interval;
+    uint16_t	attempt;
+    uint16_t	timeout;
+} __attribute__ ((packed)) sniff_mode_cp;
+#define SNIFF_MODE_CP_SIZE 10
+
+#define OCF_EXIT_SNIFF_MODE		0x0004
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) exit_sniff_mode_cp;
+#define EXIT_SNIFF_MODE_CP_SIZE 2
+
+#define OCF_PARK_MODE			0x0005
+typedef struct {
+    uint16_t	handle;
+    uint16_t	max_interval;
+    uint16_t	min_interval;
+} __attribute__ ((packed)) park_mode_cp;
+#define PARK_MODE_CP_SIZE 6
+
+#define OCF_EXIT_PARK_MODE		0x0006
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) exit_park_mode_cp;
+#define EXIT_PARK_MODE_CP_SIZE 2
+
+#define OCF_QOS_SETUP			0x0007
+typedef struct {
+    uint8_t	service_type;		/* 1 = best effort */
+    uint32_t	token_rate;		/* Byte per seconds */
+    uint32_t	peak_bandwidth;		/* Byte per seconds */
+    uint32_t	latency;		/* Microseconds */
+    uint32_t	delay_variation;	/* Microseconds */
+} __attribute__ ((packed)) hci_qos;
+#define HCI_QOS_CP_SIZE 17
+typedef struct {
+    uint16_t 	handle;
+    uint8_t 	flags;			/* Reserved */
+    hci_qos 	qos;
+} __attribute__ ((packed)) qos_setup_cp;
+#define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE)
+
+#define OCF_ROLE_DISCOVERY		0x0009
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) role_discovery_cp;
+#define ROLE_DISCOVERY_CP_SIZE 2
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	role;
+} __attribute__ ((packed)) role_discovery_rp;
+#define ROLE_DISCOVERY_RP_SIZE 4
+
+#define OCF_SWITCH_ROLE			0x000B
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	role;
+} __attribute__ ((packed)) switch_role_cp;
+#define SWITCH_ROLE_CP_SIZE 7
+
+#define OCF_READ_LINK_POLICY		0x000C
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_link_policy_cp;
+#define READ_LINK_POLICY_CP_SIZE 2
+typedef struct {
+    uint8_t 	status;
+    uint16_t	handle;
+    uint16_t	policy;
+} __attribute__ ((packed)) read_link_policy_rp;
+#define READ_LINK_POLICY_RP_SIZE 5
+
+#define OCF_WRITE_LINK_POLICY		0x000D
+typedef struct {
+    uint16_t	handle;
+    uint16_t	policy;
+} __attribute__ ((packed)) write_link_policy_cp;
+#define WRITE_LINK_POLICY_CP_SIZE 4
+typedef struct {
+    uint8_t 	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) write_link_policy_rp;
+#define WRITE_LINK_POLICY_RP_SIZE 3
+
+#define OCF_READ_DEFAULT_LINK_POLICY	0x000E
+
+#define OCF_WRITE_DEFAULT_LINK_POLICY	0x000F
+
+#define OCF_FLOW_SPECIFICATION		0x0010
+
+#define OCF_SNIFF_SUBRATE		0x0011
+typedef struct {
+    uint16_t	handle;
+    uint16_t	max_remote_latency;
+    uint16_t	max_local_latency;
+    uint16_t	min_remote_timeout;
+    uint16_t	min_local_timeout;
+} __attribute__ ((packed)) sniff_subrate_cp;
+#define SNIFF_SUBRATE_CP_SIZE 10
+
+/* Host Controller and Baseband */
+#define OGF_HOST_CTL		0x03
+
+#define OCF_SET_EVENT_MASK		0x0001
+typedef struct {
+    uint8_t	mask[8];
+} __attribute__ ((packed)) set_event_mask_cp;
+#define SET_EVENT_MASK_CP_SIZE 8
+
+#define OCF_RESET			0x0003
+
+#define OCF_SET_EVENT_FLT		0x0005
+typedef struct {
+    uint8_t	flt_type;
+    uint8_t	cond_type;
+    uint8_t	condition[0];
+} __attribute__ ((packed)) set_event_flt_cp;
+#define SET_EVENT_FLT_CP_SIZE 2
+
+enum bt_filter_type {
+    FLT_CLEAR_ALL		= 0x00,
+    FLT_INQ_RESULT		= 0x01,
+    FLT_CONN_SETUP		= 0x02,
+};
+enum inq_result_cond_type {
+    INQ_RESULT_RETURN_ALL	= 0x00,
+    INQ_RESULT_RETURN_CLASS	= 0x01,
+    INQ_RESULT_RETURN_BDADDR	= 0x02,
+};
+enum conn_setup_cond_type {
+    CONN_SETUP_ALLOW_ALL	= 0x00,
+    CONN_SETUP_ALLOW_CLASS	= 0x01,
+    CONN_SETUP_ALLOW_BDADDR	= 0x02,
+};
+enum conn_setup_cond {
+    CONN_SETUP_AUTO_OFF		= 0x01,
+    CONN_SETUP_AUTO_ON		= 0x02,
+};
+
+#define OCF_FLUSH			0x0008
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) flush_cp;
+#define FLUSH_CP_SIZE 2
+
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) flush_rp;
+#define FLUSH_RP_SIZE 3
+
+#define OCF_READ_PIN_TYPE		0x0009
+typedef struct {
+    uint8_t	status;
+    uint8_t	pin_type;
+} __attribute__ ((packed)) read_pin_type_rp;
+#define READ_PIN_TYPE_RP_SIZE 2
+
+#define OCF_WRITE_PIN_TYPE		0x000A
+typedef struct {
+    uint8_t	pin_type;
+} __attribute__ ((packed)) write_pin_type_cp;
+#define WRITE_PIN_TYPE_CP_SIZE 1
+
+#define OCF_CREATE_NEW_UNIT_KEY		0x000B
+
+#define OCF_READ_STORED_LINK_KEY	0x000D
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	read_all;
+} __attribute__ ((packed)) read_stored_link_key_cp;
+#define READ_STORED_LINK_KEY_CP_SIZE 7
+typedef struct {
+    uint8_t	status;
+    uint16_t	max_keys;
+    uint16_t	num_keys;
+} __attribute__ ((packed)) read_stored_link_key_rp;
+#define READ_STORED_LINK_KEY_RP_SIZE 5
+
+#define OCF_WRITE_STORED_LINK_KEY	0x0011
+typedef struct {
+    uint8_t	num_keys;
+    /* variable length part */
+} __attribute__ ((packed)) write_stored_link_key_cp;
+#define WRITE_STORED_LINK_KEY_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+    uint8_t	num_keys;
+} __attribute__ ((packed)) write_stored_link_key_rp;
+#define READ_WRITE_LINK_KEY_RP_SIZE 2
+
+#define OCF_DELETE_STORED_LINK_KEY	0x0012
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	delete_all;
+} __attribute__ ((packed)) delete_stored_link_key_cp;
+#define DELETE_STORED_LINK_KEY_CP_SIZE 7
+typedef struct {
+    uint8_t	status;
+    uint16_t	num_keys;
+} __attribute__ ((packed)) delete_stored_link_key_rp;
+#define DELETE_STORED_LINK_KEY_RP_SIZE 3
+
+#define OCF_CHANGE_LOCAL_NAME		0x0013
+typedef struct {
+    char	name[248];
+} __attribute__ ((packed)) change_local_name_cp;
+#define CHANGE_LOCAL_NAME_CP_SIZE 248 
+
+#define OCF_READ_LOCAL_NAME		0x0014
+typedef struct {
+    uint8_t	status;
+    char	name[248];
+} __attribute__ ((packed)) read_local_name_rp;
+#define READ_LOCAL_NAME_RP_SIZE 249 
+
+#define OCF_READ_CONN_ACCEPT_TIMEOUT	0x0015
+typedef struct {
+    uint8_t	status;
+    uint16_t	timeout;
+} __attribute__ ((packed)) read_conn_accept_timeout_rp;
+#define READ_CONN_ACCEPT_TIMEOUT_RP_SIZE 3
+
+#define OCF_WRITE_CONN_ACCEPT_TIMEOUT	0x0016
+typedef struct {
+    uint16_t	timeout;
+} __attribute__ ((packed)) write_conn_accept_timeout_cp;
+#define WRITE_CONN_ACCEPT_TIMEOUT_CP_SIZE 2
+
+#define OCF_READ_PAGE_TIMEOUT		0x0017
+typedef struct {
+    uint8_t	status;
+    uint16_t	timeout;
+} __attribute__ ((packed)) read_page_timeout_rp;
+#define READ_PAGE_TIMEOUT_RP_SIZE 3
+
+#define OCF_WRITE_PAGE_TIMEOUT		0x0018
+typedef struct {
+    uint16_t	timeout;
+} __attribute__ ((packed)) write_page_timeout_cp;
+#define WRITE_PAGE_TIMEOUT_CP_SIZE 2
+
+#define OCF_READ_SCAN_ENABLE		0x0019
+typedef struct {
+    uint8_t	status;
+    uint8_t	enable;
+} __attribute__ ((packed)) read_scan_enable_rp;
+#define READ_SCAN_ENABLE_RP_SIZE 2
+
+#define OCF_WRITE_SCAN_ENABLE		0x001A
+typedef struct {
+    uint8_t	scan_enable;
+} __attribute__ ((packed)) write_scan_enable_cp;
+#define WRITE_SCAN_ENABLE_CP_SIZE 1
+
+enum scan_enable_bits {
+    SCAN_DISABLED		= 0,
+    SCAN_INQUIRY		= 1 << 0,
+    SCAN_PAGE			= 1 << 1,
+};
+
+#define OCF_READ_PAGE_ACTIVITY		0x001B
+typedef struct {
+    uint8_t	status;
+    uint16_t	interval;
+    uint16_t	window;
+} __attribute__ ((packed)) read_page_activity_rp;
+#define READ_PAGE_ACTIVITY_RP_SIZE 5
+
+#define OCF_WRITE_PAGE_ACTIVITY		0x001C
+typedef struct {
+    uint16_t	interval;
+    uint16_t	window;
+} __attribute__ ((packed)) write_page_activity_cp;
+#define WRITE_PAGE_ACTIVITY_CP_SIZE 4
+
+#define OCF_READ_INQ_ACTIVITY		0x001D
+typedef struct {
+    uint8_t	status;
+    uint16_t	interval;
+    uint16_t	window;
+} __attribute__ ((packed)) read_inq_activity_rp;
+#define READ_INQ_ACTIVITY_RP_SIZE 5
+
+#define OCF_WRITE_INQ_ACTIVITY		0x001E
+typedef struct {
+    uint16_t	interval;
+    uint16_t	window;
+} __attribute__ ((packed)) write_inq_activity_cp;
+#define WRITE_INQ_ACTIVITY_CP_SIZE 4
+
+#define OCF_READ_AUTH_ENABLE		0x001F
+
+#define OCF_WRITE_AUTH_ENABLE		0x0020
+
+#define AUTH_DISABLED		0x00
+#define AUTH_ENABLED		0x01
+
+#define OCF_READ_ENCRYPT_MODE		0x0021
+
+#define OCF_WRITE_ENCRYPT_MODE		0x0022
+
+#define ENCRYPT_DISABLED	0x00
+#define ENCRYPT_P2P		0x01
+#define ENCRYPT_BOTH		0x02
+
+#define OCF_READ_CLASS_OF_DEV		0x0023
+typedef struct {
+    uint8_t	status;
+    uint8_t	dev_class[3];
+} __attribute__ ((packed)) read_class_of_dev_rp;
+#define READ_CLASS_OF_DEV_RP_SIZE 4 
+
+#define OCF_WRITE_CLASS_OF_DEV		0x0024
+typedef struct {
+    uint8_t	dev_class[3];
+} __attribute__ ((packed)) write_class_of_dev_cp;
+#define WRITE_CLASS_OF_DEV_CP_SIZE 3
+
+#define OCF_READ_VOICE_SETTING		0x0025
+typedef struct {
+    uint8_t	status;
+    uint16_t	voice_setting;
+} __attribute__ ((packed)) read_voice_setting_rp;
+#define READ_VOICE_SETTING_RP_SIZE 3
+
+#define OCF_WRITE_VOICE_SETTING		0x0026
+typedef struct {
+    uint16_t	voice_setting;
+} __attribute__ ((packed)) write_voice_setting_cp;
+#define WRITE_VOICE_SETTING_CP_SIZE 2
+
+#define OCF_READ_AUTOMATIC_FLUSH_TIMEOUT	0x0027
+
+#define OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT	0x0028
+
+#define OCF_READ_NUM_BROADCAST_RETRANS	0x0029
+
+#define OCF_WRITE_NUM_BROADCAST_RETRANS	0x002A
+
+#define OCF_READ_HOLD_MODE_ACTIVITY	0x002B
+
+#define OCF_WRITE_HOLD_MODE_ACTIVITY	0x002C
+
+#define OCF_READ_TRANSMIT_POWER_LEVEL	0x002D
+typedef struct {
+    uint16_t	handle;
+    uint8_t	type;
+} __attribute__ ((packed)) read_transmit_power_level_cp;
+#define READ_TRANSMIT_POWER_LEVEL_CP_SIZE 3
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    int8_t	level;
+} __attribute__ ((packed)) read_transmit_power_level_rp;
+#define READ_TRANSMIT_POWER_LEVEL_RP_SIZE 4
+
+#define OCF_HOST_BUFFER_SIZE		0x0033
+typedef struct {
+    uint16_t	acl_mtu;
+    uint8_t	sco_mtu;
+    uint16_t	acl_max_pkt;
+    uint16_t	sco_max_pkt;
+} __attribute__ ((packed)) host_buffer_size_cp;
+#define HOST_BUFFER_SIZE_CP_SIZE 7
+
+#define OCF_HOST_NUMBER_OF_COMPLETED_PACKETS	0x0035
+
+#define OCF_READ_LINK_SUPERVISION_TIMEOUT	0x0036
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint16_t	link_sup_to;
+} __attribute__ ((packed)) read_link_supervision_timeout_rp;
+#define READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE 5
+
+#define OCF_WRITE_LINK_SUPERVISION_TIMEOUT	0x0037
+typedef struct {
+    uint16_t	handle;
+    uint16_t	link_sup_to;
+} __attribute__ ((packed)) write_link_supervision_timeout_cp;
+#define WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE 4
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) write_link_supervision_timeout_rp;
+#define WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE 3
+
+#define OCF_READ_NUM_SUPPORTED_IAC	0x0038
+
+#define MAX_IAC_LAP 0x40
+#define OCF_READ_CURRENT_IAC_LAP	0x0039
+typedef struct {
+    uint8_t	status;
+    uint8_t	num_current_iac;
+    uint8_t	lap[MAX_IAC_LAP][3];
+} __attribute__ ((packed)) read_current_iac_lap_rp;
+#define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP
+
+#define OCF_WRITE_CURRENT_IAC_LAP	0x003A
+typedef struct {
+    uint8_t	num_current_iac;
+    uint8_t	lap[MAX_IAC_LAP][3];
+} __attribute__ ((packed)) write_current_iac_lap_cp;
+#define WRITE_CURRENT_IAC_LAP_CP_SIZE 1+3*MAX_IAC_LAP
+
+#define OCF_READ_PAGE_SCAN_PERIOD_MODE	0x003B
+
+#define OCF_WRITE_PAGE_SCAN_PERIOD_MODE	0x003C
+
+#define OCF_READ_PAGE_SCAN_MODE		0x003D
+
+#define OCF_WRITE_PAGE_SCAN_MODE	0x003E
+
+#define OCF_SET_AFH_CLASSIFICATION	0x003F
+typedef struct {
+    uint8_t	map[10];
+} __attribute__ ((packed)) set_afh_classification_cp;
+#define SET_AFH_CLASSIFICATION_CP_SIZE 10
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) set_afh_classification_rp;
+#define SET_AFH_CLASSIFICATION_RP_SIZE 1
+
+#define OCF_READ_INQUIRY_SCAN_TYPE	0x0042
+typedef struct {
+    uint8_t	status;
+    uint8_t	type;
+} __attribute__ ((packed)) read_inquiry_scan_type_rp;
+#define READ_INQUIRY_SCAN_TYPE_RP_SIZE 2
+
+#define OCF_WRITE_INQUIRY_SCAN_TYPE	0x0043
+typedef struct {
+    uint8_t	type;
+} __attribute__ ((packed)) write_inquiry_scan_type_cp;
+#define WRITE_INQUIRY_SCAN_TYPE_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) write_inquiry_scan_type_rp;
+#define WRITE_INQUIRY_SCAN_TYPE_RP_SIZE 1
+
+#define OCF_READ_INQUIRY_MODE		0x0044
+typedef struct {
+    uint8_t	status;
+    uint8_t	mode;
+} __attribute__ ((packed)) read_inquiry_mode_rp;
+#define READ_INQUIRY_MODE_RP_SIZE 2
+
+#define OCF_WRITE_INQUIRY_MODE		0x0045
+typedef struct {
+    uint8_t	mode;
+} __attribute__ ((packed)) write_inquiry_mode_cp;
+#define WRITE_INQUIRY_MODE_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) write_inquiry_mode_rp;
+#define WRITE_INQUIRY_MODE_RP_SIZE 1
+
+#define OCF_READ_PAGE_SCAN_TYPE		0x0046
+
+#define OCF_WRITE_PAGE_SCAN_TYPE	0x0047
+
+#define OCF_READ_AFH_MODE		0x0048
+typedef struct {
+    uint8_t	status;
+    uint8_t	mode;
+} __attribute__ ((packed)) read_afh_mode_rp;
+#define READ_AFH_MODE_RP_SIZE 2
+
+#define OCF_WRITE_AFH_MODE		0x0049
+typedef struct {
+    uint8_t	mode;
+} __attribute__ ((packed)) write_afh_mode_cp;
+#define WRITE_AFH_MODE_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) write_afh_mode_rp;
+#define WRITE_AFH_MODE_RP_SIZE 1
+
+#define OCF_READ_EXT_INQUIRY_RESPONSE	0x0051
+typedef struct {
+    uint8_t	status;
+    uint8_t	fec;
+    uint8_t	data[240];
+} __attribute__ ((packed)) read_ext_inquiry_response_rp;
+#define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242
+
+#define OCF_WRITE_EXT_INQUIRY_RESPONSE	0x0052
+typedef struct {
+    uint8_t	fec;
+    uint8_t	data[240];
+} __attribute__ ((packed)) write_ext_inquiry_response_cp;
+#define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241
+typedef struct {
+    uint8_t	status;
+} __attribute__ ((packed)) write_ext_inquiry_response_rp;
+#define WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE 1
+
+/* Informational Parameters */
+#define OGF_INFO_PARAM		0x04
+
+#define OCF_READ_LOCAL_VERSION		0x0001
+typedef struct {
+    uint8_t	status;
+    uint8_t	hci_ver;
+    uint16_t	hci_rev;
+    uint8_t	lmp_ver;
+    uint16_t	manufacturer;
+    uint16_t	lmp_subver;
+} __attribute__ ((packed)) read_local_version_rp;
+#define READ_LOCAL_VERSION_RP_SIZE 9
+
+#define OCF_READ_LOCAL_COMMANDS		0x0002
+typedef struct {
+    uint8_t	status;
+    uint8_t	commands[64];
+} __attribute__ ((packed)) read_local_commands_rp;
+#define READ_LOCAL_COMMANDS_RP_SIZE 65
+
+#define OCF_READ_LOCAL_FEATURES		0x0003
+typedef struct {
+    uint8_t	status;
+    uint8_t	features[8];
+} __attribute__ ((packed)) read_local_features_rp;
+#define READ_LOCAL_FEATURES_RP_SIZE 9
+
+#define OCF_READ_LOCAL_EXT_FEATURES	0x0004
+typedef struct {
+    uint8_t	page_num;
+} __attribute__ ((packed)) read_local_ext_features_cp;
+#define READ_LOCAL_EXT_FEATURES_CP_SIZE 1
+typedef struct {
+    uint8_t	status;
+    uint8_t	page_num;
+    uint8_t	max_page_num;
+    uint8_t	features[8];
+} __attribute__ ((packed)) read_local_ext_features_rp;
+#define READ_LOCAL_EXT_FEATURES_RP_SIZE 11
+
+#define OCF_READ_BUFFER_SIZE		0x0005
+typedef struct {
+    uint8_t	status;
+    uint16_t	acl_mtu;
+    uint8_t	sco_mtu;
+    uint16_t	acl_max_pkt;
+    uint16_t	sco_max_pkt;
+} __attribute__ ((packed)) read_buffer_size_rp;
+#define READ_BUFFER_SIZE_RP_SIZE 8
+
+#define OCF_READ_COUNTRY_CODE		0x0007
+typedef struct {
+    uint8_t	status;
+    uint8_t	country_code;
+} __attribute__ ((packed)) read_country_code_rp;
+#define READ_COUNTRY_CODE_RP_SIZE 2
+
+#define OCF_READ_BD_ADDR		0x0009
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) read_bd_addr_rp;
+#define READ_BD_ADDR_RP_SIZE 7
+
+/* Status params */
+#define OGF_STATUS_PARAM	0x05
+
+#define OCF_READ_FAILED_CONTACT_COUNTER		0x0001
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	counter;
+} __attribute__ ((packed)) read_failed_contact_counter_rp;
+#define READ_FAILED_CONTACT_COUNTER_RP_SIZE 4
+
+#define OCF_RESET_FAILED_CONTACT_COUNTER	0x0002
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) reset_failed_contact_counter_rp;
+#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 4
+
+#define OCF_READ_LINK_QUALITY		0x0003
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) read_link_quality_cp;
+#define READ_LINK_QUALITY_CP_SIZE 4
+
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	link_quality;
+} __attribute__ ((packed)) read_link_quality_rp;
+#define READ_LINK_QUALITY_RP_SIZE 4
+
+#define OCF_READ_RSSI			0x0005
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    int8_t	rssi;
+} __attribute__ ((packed)) read_rssi_rp;
+#define READ_RSSI_RP_SIZE 4
+
+#define OCF_READ_AFH_MAP		0x0006
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	mode;
+    uint8_t	map[10];
+} __attribute__ ((packed)) read_afh_map_rp;
+#define READ_AFH_MAP_RP_SIZE 14
+
+#define OCF_READ_CLOCK			0x0007
+typedef struct {
+    uint16_t	handle;
+    uint8_t	which_clock;
+} __attribute__ ((packed)) read_clock_cp;
+#define READ_CLOCK_CP_SIZE 3
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint32_t	clock;
+    uint16_t	accuracy;
+} __attribute__ ((packed)) read_clock_rp;
+#define READ_CLOCK_RP_SIZE 9
+
+/* Testing commands */
+#define OGF_TESTING_CMD		0x3e
+
+/* Vendor specific commands */
+#define OGF_VENDOR_CMD		0x3f
+
+/* HCI Events */
+
+#define EVT_INQUIRY_COMPLETE		0x01
+
+#define EVT_INQUIRY_RESULT		0x02
+typedef struct {
+    uint8_t	num_responses;
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_period_mode;
+    uint8_t	pscan_mode;
+    uint8_t	dev_class[3];
+    uint16_t	clock_offset;
+} __attribute__ ((packed)) inquiry_info;
+#define INQUIRY_INFO_SIZE 14
+
+#define EVT_CONN_COMPLETE		0x03
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    bdaddr_t	bdaddr;
+    uint8_t	link_type;
+    uint8_t	encr_mode;
+} __attribute__ ((packed)) evt_conn_complete;
+#define EVT_CONN_COMPLETE_SIZE 11
+
+#define EVT_CONN_REQUEST		0x04
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	dev_class[3];
+    uint8_t	link_type;
+} __attribute__ ((packed)) evt_conn_request;
+#define EVT_CONN_REQUEST_SIZE 10
+
+#define EVT_DISCONN_COMPLETE		0x05
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	reason;
+} __attribute__ ((packed)) evt_disconn_complete;
+#define EVT_DISCONN_COMPLETE_SIZE 4
+
+#define EVT_AUTH_COMPLETE		0x06
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+} __attribute__ ((packed)) evt_auth_complete;
+#define EVT_AUTH_COMPLETE_SIZE 3
+
+#define EVT_REMOTE_NAME_REQ_COMPLETE	0x07
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+    char	name[248];
+} __attribute__ ((packed)) evt_remote_name_req_complete;
+#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
+
+#define EVT_ENCRYPT_CHANGE		0x08
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	encrypt;
+} __attribute__ ((packed)) evt_encrypt_change;
+#define EVT_ENCRYPT_CHANGE_SIZE 5
+
+#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE	0x09
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+}  __attribute__ ((packed)) evt_change_conn_link_key_complete;
+#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE 3
+
+#define EVT_MASTER_LINK_KEY_COMPLETE		0x0A
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	key_flag;
+} __attribute__ ((packed)) evt_master_link_key_complete;
+#define EVT_MASTER_LINK_KEY_COMPLETE_SIZE 4
+
+#define EVT_READ_REMOTE_FEATURES_COMPLETE	0x0B
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	features[8];
+} __attribute__ ((packed)) evt_read_remote_features_complete;
+#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
+
+#define EVT_READ_REMOTE_VERSION_COMPLETE	0x0C
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	lmp_ver;
+    uint16_t	manufacturer;
+    uint16_t	lmp_subver;
+} __attribute__ ((packed)) evt_read_remote_version_complete;
+#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
+
+#define EVT_QOS_SETUP_COMPLETE		0x0D
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	flags;			/* Reserved */
+    hci_qos	qos;
+} __attribute__ ((packed)) evt_qos_setup_complete;
+#define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE)
+
+#define EVT_CMD_COMPLETE 		0x0E
+typedef struct {
+    uint8_t	ncmd;
+    uint16_t	opcode;
+} __attribute__ ((packed)) evt_cmd_complete;
+#define EVT_CMD_COMPLETE_SIZE 3
+
+#define EVT_CMD_STATUS 			0x0F
+typedef struct {
+    uint8_t	status;
+    uint8_t	ncmd;
+    uint16_t	opcode;
+} __attribute__ ((packed)) evt_cmd_status;
+#define EVT_CMD_STATUS_SIZE 4
+
+#define EVT_HARDWARE_ERROR		0x10
+typedef struct {
+    uint8_t	code;
+} __attribute__ ((packed)) evt_hardware_error;
+#define EVT_HARDWARE_ERROR_SIZE 1
+
+#define EVT_FLUSH_OCCURRED		0x11
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) evt_flush_occured;
+#define EVT_FLUSH_OCCURRED_SIZE 2
+
+#define EVT_ROLE_CHANGE			0x12
+typedef struct {
+    uint8_t	status;
+    bdaddr_t	bdaddr;
+    uint8_t	role;
+} __attribute__ ((packed)) evt_role_change;
+#define EVT_ROLE_CHANGE_SIZE 8
+
+#define EVT_NUM_COMP_PKTS		0x13
+typedef struct {
+    uint8_t	num_hndl;
+    struct {
+        uint16_t handle;
+        uint16_t num_packets;
+    } connection[0];
+} __attribute__ ((packed)) evt_num_comp_pkts;
+#define EVT_NUM_COMP_PKTS_SIZE(num_hndl) (1 + 4 * (num_hndl))
+
+#define EVT_MODE_CHANGE			0x14
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	mode;
+    uint16_t	interval;
+} __attribute__ ((packed)) evt_mode_change;
+#define EVT_MODE_CHANGE_SIZE 6
+
+#define EVT_RETURN_LINK_KEYS		0x15
+typedef struct {
+    uint8_t	num_keys;
+    /* variable length part */
+} __attribute__ ((packed)) evt_return_link_keys;
+#define EVT_RETURN_LINK_KEYS_SIZE 1
+
+#define EVT_PIN_CODE_REQ		0x16
+typedef struct {
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) evt_pin_code_req;
+#define EVT_PIN_CODE_REQ_SIZE 6
+
+#define EVT_LINK_KEY_REQ		0x17
+typedef struct {
+    bdaddr_t	bdaddr;
+} __attribute__ ((packed)) evt_link_key_req;
+#define EVT_LINK_KEY_REQ_SIZE 6
+
+#define EVT_LINK_KEY_NOTIFY		0x18
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	link_key[16];
+    uint8_t	key_type;
+} __attribute__ ((packed)) evt_link_key_notify;
+#define EVT_LINK_KEY_NOTIFY_SIZE 23
+
+#define EVT_LOOPBACK_COMMAND		0x19
+
+#define EVT_DATA_BUFFER_OVERFLOW	0x1A
+typedef struct {
+    uint8_t	link_type;
+} __attribute__ ((packed)) evt_data_buffer_overflow;
+#define EVT_DATA_BUFFER_OVERFLOW_SIZE 1
+
+#define EVT_MAX_SLOTS_CHANGE		0x1B
+typedef struct {
+    uint16_t	handle;
+    uint8_t	max_slots;
+} __attribute__ ((packed)) evt_max_slots_change;
+#define EVT_MAX_SLOTS_CHANGE_SIZE 3
+
+#define EVT_READ_CLOCK_OFFSET_COMPLETE	0x1C
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint16_t	clock_offset;
+} __attribute__ ((packed)) evt_read_clock_offset_complete;
+#define EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE 5
+
+#define EVT_CONN_PTYPE_CHANGED		0x1D
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint16_t	ptype;
+} __attribute__ ((packed)) evt_conn_ptype_changed;
+#define EVT_CONN_PTYPE_CHANGED_SIZE 5
+
+#define EVT_QOS_VIOLATION		0x1E
+typedef struct {
+    uint16_t	handle;
+} __attribute__ ((packed)) evt_qos_violation;
+#define EVT_QOS_VIOLATION_SIZE 2
+
+#define EVT_PSCAN_REP_MODE_CHANGE	0x20
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+} __attribute__ ((packed)) evt_pscan_rep_mode_change;
+#define EVT_PSCAN_REP_MODE_CHANGE_SIZE 7
+
+#define EVT_FLOW_SPEC_COMPLETE		0x21
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	flags;
+    uint8_t	direction;
+    hci_qos	qos;
+} __attribute__ ((packed)) evt_flow_spec_complete;
+#define EVT_FLOW_SPEC_COMPLETE_SIZE (5 + HCI_QOS_CP_SIZE)
+
+#define EVT_INQUIRY_RESULT_WITH_RSSI	0x22
+typedef struct {
+    uint8_t	num_responses;
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_period_mode;
+    uint8_t	dev_class[3];
+    uint16_t	clock_offset;
+    int8_t	rssi;
+} __attribute__ ((packed)) inquiry_info_with_rssi;
+#define INQUIRY_INFO_WITH_RSSI_SIZE 15
+typedef struct {
+    uint8_t	num_responses;
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_period_mode;
+    uint8_t	pscan_mode;
+    uint8_t	dev_class[3];
+    uint16_t	clock_offset;
+    int8_t	rssi;
+} __attribute__ ((packed)) inquiry_info_with_rssi_and_pscan_mode;
+#define INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE 16
+
+#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE	0x23
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	page_num;
+    uint8_t	max_page_num;
+    uint8_t	features[8];
+} __attribute__ ((packed)) evt_read_remote_ext_features_complete;
+#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE 13
+
+#define EVT_SYNC_CONN_COMPLETE		0x2C
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    bdaddr_t	bdaddr;
+    uint8_t	link_type;
+    uint8_t	trans_interval;
+    uint8_t	retrans_window;
+    uint16_t	rx_pkt_len;
+    uint16_t	tx_pkt_len;
+    uint8_t	air_mode;
+} __attribute__ ((packed)) evt_sync_conn_complete;
+#define EVT_SYNC_CONN_COMPLETE_SIZE 17
+
+#define EVT_SYNC_CONN_CHANGED		0x2D
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint8_t	trans_interval;
+    uint8_t	retrans_window;
+    uint16_t	rx_pkt_len;
+    uint16_t	tx_pkt_len;
+} __attribute__ ((packed)) evt_sync_conn_changed;
+#define EVT_SYNC_CONN_CHANGED_SIZE 9
+
+#define EVT_SNIFF_SUBRATE		0x2E
+typedef struct {
+    uint8_t	status;
+    uint16_t	handle;
+    uint16_t	max_remote_latency;
+    uint16_t	max_local_latency;
+    uint16_t	min_remote_timeout;
+    uint16_t	min_local_timeout;
+} __attribute__ ((packed)) evt_sniff_subrate;
+#define EVT_SNIFF_SUBRATE_SIZE 11
+
+#define EVT_EXTENDED_INQUIRY_RESULT	0x2F
+typedef struct {
+    bdaddr_t	bdaddr;
+    uint8_t	pscan_rep_mode;
+    uint8_t	pscan_period_mode;
+    uint8_t	dev_class[3];
+    uint16_t	clock_offset;
+    int8_t	rssi;
+    uint8_t	data[240];
+} __attribute__ ((packed)) extended_inquiry_info;
+#define EXTENDED_INQUIRY_INFO_SIZE 254
+
+#define EVT_TESTING			0xFE
+
+#define EVT_VENDOR			0xFF
+
+/* Command opcode pack/unpack */
+#define cmd_opcode_pack(ogf, ocf)	(uint16_t)((ocf & 0x03ff)|(ogf << 10))
+#define cmd_opcode_ogf(op)		(op >> 10)
+#define cmd_opcode_ocf(op)		(op & 0x03ff)
+
+/* ACL handle and flags pack/unpack */
+#define acl_handle_pack(h, f)	(uint16_t)(((h) & 0x0fff)|((f) << 12))
+#define acl_handle(h)		((h) & 0x0fff)
+#define acl_flags(h)		((h) >> 12)
+
+/* HCI Packet structures */
+#define HCI_COMMAND_HDR_SIZE	3
+#define HCI_EVENT_HDR_SIZE	2
+#define HCI_ACL_HDR_SIZE	4
+#define HCI_SCO_HDR_SIZE	3
+
+struct hci_command_hdr {
+    uint16_t 	opcode;		/* OCF & OGF */
+    uint8_t	plen;
+} __attribute__ ((packed));
+
+struct hci_event_hdr {
+    uint8_t	evt;
+    uint8_t	plen;
+} __attribute__ ((packed));
+
+struct hci_acl_hdr {
+    uint16_t	handle;		/* Handle & Flags(PB, BC) */
+    uint16_t	dlen;
+} __attribute__ ((packed));
+
+struct hci_sco_hdr {
+    uint16_t	handle;
+    uint8_t	dlen;
+} __attribute__ ((packed));
+
+/* L2CAP layer defines */
+
+enum bt_l2cap_lm_bits {
+    L2CAP_LM_MASTER	= 1 << 0,
+    L2CAP_LM_AUTH	= 1 << 1,
+    L2CAP_LM_ENCRYPT	= 1 << 2,
+    L2CAP_LM_TRUSTED	= 1 << 3,
+    L2CAP_LM_RELIABLE	= 1 << 4,
+    L2CAP_LM_SECURE	= 1 << 5,
+};
+
+enum bt_l2cap_cid_predef {
+    L2CAP_CID_INVALID	= 0x0000,
+    L2CAP_CID_SIGNALLING= 0x0001,
+    L2CAP_CID_GROUP	= 0x0002,
+    L2CAP_CID_ALLOC	= 0x0040,
+};
+
+/* L2CAP command codes */
+enum bt_l2cap_cmd {
+    L2CAP_COMMAND_REJ	= 1,
+    L2CAP_CONN_REQ,
+    L2CAP_CONN_RSP,
+    L2CAP_CONF_REQ,
+    L2CAP_CONF_RSP,
+    L2CAP_DISCONN_REQ,
+    L2CAP_DISCONN_RSP,
+    L2CAP_ECHO_REQ,
+    L2CAP_ECHO_RSP,
+    L2CAP_INFO_REQ,
+    L2CAP_INFO_RSP,
+};
+
+enum bt_l2cap_sar_bits {
+    L2CAP_SAR_NO_SEG	= 0,
+    L2CAP_SAR_START,
+    L2CAP_SAR_END,
+    L2CAP_SAR_CONT,
+};
+
+/* L2CAP structures */
+typedef struct {
+    uint16_t	len;
+    uint16_t	cid;
+    uint8_t	data[0];
+} __attribute__ ((packed)) l2cap_hdr;
+#define L2CAP_HDR_SIZE 4
+
+typedef struct {
+    uint8_t	code;
+    uint8_t	ident;
+    uint16_t	len;
+} __attribute__ ((packed)) l2cap_cmd_hdr;
+#define L2CAP_CMD_HDR_SIZE 4
+
+typedef struct {
+    uint16_t	reason;
+} __attribute__ ((packed)) l2cap_cmd_rej;
+#define L2CAP_CMD_REJ_SIZE 2
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	scid;
+} __attribute__ ((packed)) l2cap_cmd_rej_cid;
+#define L2CAP_CMD_REJ_CID_SIZE 4
+
+/* reject reason */
+enum bt_l2cap_rej_reason {
+    L2CAP_REJ_CMD_NOT_UNDERSTOOD = 0,
+    L2CAP_REJ_SIG_TOOBIG,
+    L2CAP_REJ_CID_INVAL,
+};
+
+typedef struct {
+    uint16_t	psm;
+    uint16_t	scid;
+} __attribute__ ((packed)) l2cap_conn_req;
+#define L2CAP_CONN_REQ_SIZE 4
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	scid;
+    uint16_t	result;
+    uint16_t	status;
+} __attribute__ ((packed)) l2cap_conn_rsp;
+#define L2CAP_CONN_RSP_SIZE 8
+
+/* connect result */
+enum bt_l2cap_conn_res {
+    L2CAP_CR_SUCCESS	= 0,
+    L2CAP_CR_PEND,
+    L2CAP_CR_BAD_PSM,
+    L2CAP_CR_SEC_BLOCK,
+    L2CAP_CR_NO_MEM,
+};
+
+/* connect status */
+enum bt_l2cap_conn_stat {
+    L2CAP_CS_NO_INFO	= 0,
+    L2CAP_CS_AUTHEN_PEND,
+    L2CAP_CS_AUTHOR_PEND,
+};
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	flags;
+    uint8_t	data[0];
+} __attribute__ ((packed)) l2cap_conf_req;
+#define L2CAP_CONF_REQ_SIZE(datalen) (4 + (datalen))
+
+typedef struct {
+    uint16_t	scid;
+    uint16_t	flags;
+    uint16_t	result;
+    uint8_t	data[0];
+} __attribute__ ((packed)) l2cap_conf_rsp;
+#define L2CAP_CONF_RSP_SIZE(datalen) (6 + datalen)
+
+enum bt_l2cap_conf_res {
+    L2CAP_CONF_SUCCESS	= 0,
+    L2CAP_CONF_UNACCEPT,
+    L2CAP_CONF_REJECT,
+    L2CAP_CONF_UNKNOWN,
+};
+
+typedef struct {
+    uint8_t	type;
+    uint8_t	len;
+    uint8_t	val[0];
+} __attribute__ ((packed)) l2cap_conf_opt;
+#define L2CAP_CONF_OPT_SIZE 2
+
+enum bt_l2cap_conf_val {
+    L2CAP_CONF_MTU	= 1,
+    L2CAP_CONF_FLUSH_TO,
+    L2CAP_CONF_QOS,
+    L2CAP_CONF_RFC,
+    L2CAP_CONF_RFC_MODE	= L2CAP_CONF_RFC,
+};
+
+typedef struct {
+    uint8_t	flags;
+    uint8_t	service_type;
+    uint32_t	token_rate;
+    uint32_t	token_bucket_size;
+    uint32_t	peak_bandwidth;
+    uint32_t	latency;
+    uint32_t	delay_variation;
+} __attribute__ ((packed)) l2cap_conf_opt_qos;
+#define L2CAP_CONF_OPT_QOS_SIZE 22
+
+enum bt_l2cap_conf_opt_qos_st {
+    L2CAP_CONF_QOS_NO_TRAFFIC = 0x00,
+    L2CAP_CONF_QOS_BEST_EFFORT,
+    L2CAP_CONF_QOS_GUARANTEED,
+};
+
+#define L2CAP_CONF_QOS_WILDCARD	0xffffffff
+
+enum bt_l2cap_mode {
+    L2CAP_MODE_BASIC	= 0,
+    L2CAP_MODE_RETRANS	= 1,
+    L2CAP_MODE_FLOWCTL	= 2,
+};
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	scid;
+} __attribute__ ((packed)) l2cap_disconn_req;
+#define L2CAP_DISCONN_REQ_SIZE 4
+
+typedef struct {
+    uint16_t	dcid;
+    uint16_t	scid;
+} __attribute__ ((packed)) l2cap_disconn_rsp;
+#define L2CAP_DISCONN_RSP_SIZE 4
+
+typedef struct {
+    uint16_t	type;
+} __attribute__ ((packed)) l2cap_info_req;
+#define L2CAP_INFO_REQ_SIZE 2
+
+typedef struct {
+    uint16_t	type;
+    uint16_t	result;
+    uint8_t	data[0];
+} __attribute__ ((packed)) l2cap_info_rsp;
+#define L2CAP_INFO_RSP_SIZE 4
+
+/* info type */
+enum bt_l2cap_info_type {
+    L2CAP_IT_CL_MTU	= 1,
+    L2CAP_IT_FEAT_MASK,
+};
+
+/* info result */
+enum bt_l2cap_info_result {
+    L2CAP_IR_SUCCESS	= 0,
+    L2CAP_IR_NOTSUPP,
+};
+
+/* Service Discovery Protocol defines */
+/* Note that all multibyte values in lower layer protocols (above in this file)
+ * are little-endian while SDP is big-endian.  */
+
+/* Protocol UUIDs */
+enum sdp_proto_uuid {
+    SDP_UUID		= 0x0001,
+    UDP_UUID		= 0x0002,
+    RFCOMM_UUID		= 0x0003,
+    TCP_UUID		= 0x0004,
+    TCS_BIN_UUID	= 0x0005,
+    TCS_AT_UUID		= 0x0006,
+    OBEX_UUID		= 0x0008,
+    IP_UUID		= 0x0009,
+    FTP_UUID		= 0x000a,
+    HTTP_UUID		= 0x000c,
+    WSP_UUID		= 0x000e,
+    BNEP_UUID		= 0x000f,
+    UPNP_UUID		= 0x0010,
+    HIDP_UUID		= 0x0011,
+    HCRP_CTRL_UUID	= 0x0012,
+    HCRP_DATA_UUID	= 0x0014,
+    HCRP_NOTE_UUID	= 0x0016,
+    AVCTP_UUID		= 0x0017,
+    AVDTP_UUID		= 0x0019,
+    CMTP_UUID		= 0x001b,
+    UDI_UUID		= 0x001d,
+    MCAP_CTRL_UUID	= 0x001e,
+    MCAP_DATA_UUID	= 0x001f,
+    L2CAP_UUID		= 0x0100,
+};
+
+/*
+ * Service class identifiers of standard services and service groups
+ */
+enum service_class_id {
+    SDP_SERVER_SVCLASS_ID		= 0x1000,
+    BROWSE_GRP_DESC_SVCLASS_ID		= 0x1001,
+    PUBLIC_BROWSE_GROUP			= 0x1002,
+    SERIAL_PORT_SVCLASS_ID		= 0x1101,
+    LAN_ACCESS_SVCLASS_ID		= 0x1102,
+    DIALUP_NET_SVCLASS_ID		= 0x1103,
+    IRMC_SYNC_SVCLASS_ID		= 0x1104,
+    OBEX_OBJPUSH_SVCLASS_ID		= 0x1105,
+    OBEX_FILETRANS_SVCLASS_ID		= 0x1106,
+    IRMC_SYNC_CMD_SVCLASS_ID		= 0x1107,
+    HEADSET_SVCLASS_ID			= 0x1108,
+    CORDLESS_TELEPHONY_SVCLASS_ID	= 0x1109,
+    AUDIO_SOURCE_SVCLASS_ID		= 0x110a,
+    AUDIO_SINK_SVCLASS_ID		= 0x110b,
+    AV_REMOTE_TARGET_SVCLASS_ID		= 0x110c,
+    ADVANCED_AUDIO_SVCLASS_ID		= 0x110d,
+    AV_REMOTE_SVCLASS_ID		= 0x110e,
+    VIDEO_CONF_SVCLASS_ID		= 0x110f,
+    INTERCOM_SVCLASS_ID			= 0x1110,
+    FAX_SVCLASS_ID			= 0x1111,
+    HEADSET_AGW_SVCLASS_ID		= 0x1112,
+    WAP_SVCLASS_ID			= 0x1113,
+    WAP_CLIENT_SVCLASS_ID		= 0x1114,
+    PANU_SVCLASS_ID			= 0x1115,
+    NAP_SVCLASS_ID			= 0x1116,
+    GN_SVCLASS_ID			= 0x1117,
+    DIRECT_PRINTING_SVCLASS_ID		= 0x1118,
+    REFERENCE_PRINTING_SVCLASS_ID	= 0x1119,
+    IMAGING_SVCLASS_ID			= 0x111a,
+    IMAGING_RESPONDER_SVCLASS_ID	= 0x111b,
+    IMAGING_ARCHIVE_SVCLASS_ID		= 0x111c,
+    IMAGING_REFOBJS_SVCLASS_ID		= 0x111d,
+    HANDSFREE_SVCLASS_ID		= 0x111e,
+    HANDSFREE_AGW_SVCLASS_ID		= 0x111f,
+    DIRECT_PRT_REFOBJS_SVCLASS_ID	= 0x1120,
+    REFLECTED_UI_SVCLASS_ID		= 0x1121,
+    BASIC_PRINTING_SVCLASS_ID		= 0x1122,
+    PRINTING_STATUS_SVCLASS_ID		= 0x1123,
+    HID_SVCLASS_ID			= 0x1124,
+    HCR_SVCLASS_ID			= 0x1125,
+    HCR_PRINT_SVCLASS_ID		= 0x1126,
+    HCR_SCAN_SVCLASS_ID			= 0x1127,
+    CIP_SVCLASS_ID			= 0x1128,
+    VIDEO_CONF_GW_SVCLASS_ID		= 0x1129,
+    UDI_MT_SVCLASS_ID			= 0x112a,
+    UDI_TA_SVCLASS_ID			= 0x112b,
+    AV_SVCLASS_ID			= 0x112c,
+    SAP_SVCLASS_ID			= 0x112d,
+    PBAP_PCE_SVCLASS_ID			= 0x112e,
+    PBAP_PSE_SVCLASS_ID			= 0x112f,
+    PBAP_SVCLASS_ID			= 0x1130,
+    PNP_INFO_SVCLASS_ID			= 0x1200,
+    GENERIC_NETWORKING_SVCLASS_ID	= 0x1201,
+    GENERIC_FILETRANS_SVCLASS_ID	= 0x1202,
+    GENERIC_AUDIO_SVCLASS_ID		= 0x1203,
+    GENERIC_TELEPHONY_SVCLASS_ID	= 0x1204,
+    UPNP_SVCLASS_ID			= 0x1205,
+    UPNP_IP_SVCLASS_ID			= 0x1206,
+    UPNP_PAN_SVCLASS_ID			= 0x1300,
+    UPNP_LAP_SVCLASS_ID			= 0x1301,
+    UPNP_L2CAP_SVCLASS_ID		= 0x1302,
+    VIDEO_SOURCE_SVCLASS_ID		= 0x1303,
+    VIDEO_SINK_SVCLASS_ID		= 0x1304,
+    VIDEO_DISTRIBUTION_SVCLASS_ID	= 0x1305,
+    MDP_SVCLASS_ID			= 0x1400,
+    MDP_SOURCE_SVCLASS_ID		= 0x1401,
+    MDP_SINK_SVCLASS_ID			= 0x1402,
+    APPLE_AGENT_SVCLASS_ID		= 0x2112,
+};
+
+/*
+ * Standard profile descriptor identifiers; note these
+ * may be identical to some of the service classes defined above
+ */
+#define SDP_SERVER_PROFILE_ID		SDP_SERVER_SVCLASS_ID
+#define BROWSE_GRP_DESC_PROFILE_ID	BROWSE_GRP_DESC_SVCLASS_ID
+#define SERIAL_PORT_PROFILE_ID		SERIAL_PORT_SVCLASS_ID
+#define LAN_ACCESS_PROFILE_ID		LAN_ACCESS_SVCLASS_ID
+#define DIALUP_NET_PROFILE_ID		DIALUP_NET_SVCLASS_ID
+#define IRMC_SYNC_PROFILE_ID		IRMC_SYNC_SVCLASS_ID
+#define OBEX_OBJPUSH_PROFILE_ID		OBEX_OBJPUSH_SVCLASS_ID
+#define OBEX_FILETRANS_PROFILE_ID	OBEX_FILETRANS_SVCLASS_ID
+#define IRMC_SYNC_CMD_PROFILE_ID	IRMC_SYNC_CMD_SVCLASS_ID
+#define HEADSET_PROFILE_ID		HEADSET_SVCLASS_ID
+#define CORDLESS_TELEPHONY_PROFILE_ID	CORDLESS_TELEPHONY_SVCLASS_ID
+#define AUDIO_SOURCE_PROFILE_ID		AUDIO_SOURCE_SVCLASS_ID
+#define AUDIO_SINK_PROFILE_ID		AUDIO_SINK_SVCLASS_ID
+#define AV_REMOTE_TARGET_PROFILE_ID	AV_REMOTE_TARGET_SVCLASS_ID
+#define ADVANCED_AUDIO_PROFILE_ID	ADVANCED_AUDIO_SVCLASS_ID
+#define AV_REMOTE_PROFILE_ID		AV_REMOTE_SVCLASS_ID
+#define VIDEO_CONF_PROFILE_ID		VIDEO_CONF_SVCLASS_ID
+#define INTERCOM_PROFILE_ID		INTERCOM_SVCLASS_ID
+#define FAX_PROFILE_ID			FAX_SVCLASS_ID
+#define HEADSET_AGW_PROFILE_ID		HEADSET_AGW_SVCLASS_ID
+#define WAP_PROFILE_ID			WAP_SVCLASS_ID
+#define WAP_CLIENT_PROFILE_ID		WAP_CLIENT_SVCLASS_ID
+#define PANU_PROFILE_ID			PANU_SVCLASS_ID
+#define NAP_PROFILE_ID			NAP_SVCLASS_ID
+#define GN_PROFILE_ID			GN_SVCLASS_ID
+#define DIRECT_PRINTING_PROFILE_ID	DIRECT_PRINTING_SVCLASS_ID
+#define REFERENCE_PRINTING_PROFILE_ID	REFERENCE_PRINTING_SVCLASS_ID
+#define IMAGING_PROFILE_ID		IMAGING_SVCLASS_ID
+#define IMAGING_RESPONDER_PROFILE_ID	IMAGING_RESPONDER_SVCLASS_ID
+#define IMAGING_ARCHIVE_PROFILE_ID	IMAGING_ARCHIVE_SVCLASS_ID
+#define IMAGING_REFOBJS_PROFILE_ID	IMAGING_REFOBJS_SVCLASS_ID
+#define HANDSFREE_PROFILE_ID		HANDSFREE_SVCLASS_ID
+#define HANDSFREE_AGW_PROFILE_ID	HANDSFREE_AGW_SVCLASS_ID
+#define DIRECT_PRT_REFOBJS_PROFILE_ID	DIRECT_PRT_REFOBJS_SVCLASS_ID
+#define REFLECTED_UI_PROFILE_ID		REFLECTED_UI_SVCLASS_ID
+#define BASIC_PRINTING_PROFILE_ID	BASIC_PRINTING_SVCLASS_ID
+#define PRINTING_STATUS_PROFILE_ID	PRINTING_STATUS_SVCLASS_ID
+#define HID_PROFILE_ID			HID_SVCLASS_ID
+#define HCR_PROFILE_ID			HCR_SCAN_SVCLASS_ID
+#define HCR_PRINT_PROFILE_ID		HCR_PRINT_SVCLASS_ID
+#define HCR_SCAN_PROFILE_ID		HCR_SCAN_SVCLASS_ID
+#define CIP_PROFILE_ID			CIP_SVCLASS_ID
+#define VIDEO_CONF_GW_PROFILE_ID	VIDEO_CONF_GW_SVCLASS_ID
+#define UDI_MT_PROFILE_ID		UDI_MT_SVCLASS_ID
+#define UDI_TA_PROFILE_ID		UDI_TA_SVCLASS_ID
+#define AV_PROFILE_ID			AV_SVCLASS_ID
+#define SAP_PROFILE_ID			SAP_SVCLASS_ID
+#define PBAP_PCE_PROFILE_ID		PBAP_PCE_SVCLASS_ID
+#define PBAP_PSE_PROFILE_ID		PBAP_PSE_SVCLASS_ID
+#define PBAP_PROFILE_ID			PBAP_SVCLASS_ID
+#define PNP_INFO_PROFILE_ID		PNP_INFO_SVCLASS_ID
+#define GENERIC_NETWORKING_PROFILE_ID	GENERIC_NETWORKING_SVCLASS_ID
+#define GENERIC_FILETRANS_PROFILE_ID	GENERIC_FILETRANS_SVCLASS_ID
+#define GENERIC_AUDIO_PROFILE_ID	GENERIC_AUDIO_SVCLASS_ID
+#define GENERIC_TELEPHONY_PROFILE_ID	GENERIC_TELEPHONY_SVCLASS_ID
+#define UPNP_PROFILE_ID			UPNP_SVCLASS_ID
+#define UPNP_IP_PROFILE_ID		UPNP_IP_SVCLASS_ID
+#define UPNP_PAN_PROFILE_ID		UPNP_PAN_SVCLASS_ID
+#define UPNP_LAP_PROFILE_ID		UPNP_LAP_SVCLASS_ID
+#define UPNP_L2CAP_PROFILE_ID		UPNP_L2CAP_SVCLASS_ID
+#define VIDEO_SOURCE_PROFILE_ID		VIDEO_SOURCE_SVCLASS_ID
+#define VIDEO_SINK_PROFILE_ID		VIDEO_SINK_SVCLASS_ID
+#define VIDEO_DISTRIBUTION_PROFILE_ID	VIDEO_DISTRIBUTION_SVCLASS_ID
+#define MDP_PROFILE_ID			MDP_SVCLASS_ID
+#define MDP_SOURCE_PROFILE_ID		MDP_SROUCE_SVCLASS_ID
+#define MDP_SINK_PROFILE_ID		MDP_SINK_SVCLASS_ID
+#define APPLE_AGENT_PROFILE_ID		APPLE_AGENT_SVCLASS_ID
+
+/* Data Representation */
+enum bt_sdp_data_type {
+    SDP_DTYPE_NIL	= 0 << 3,
+    SDP_DTYPE_UINT	= 1 << 3,
+    SDP_DTYPE_SINT	= 2 << 3,
+    SDP_DTYPE_UUID	= 3 << 3,
+    SDP_DTYPE_STRING	= 4 << 3,
+    SDP_DTYPE_BOOL	= 5 << 3,
+    SDP_DTYPE_SEQ	= 6 << 3,
+    SDP_DTYPE_ALT	= 7 << 3,
+    SDP_DTYPE_URL	= 8 << 3,
+};
+
+enum bt_sdp_data_size {
+    SDP_DSIZE_1		= 0,
+    SDP_DSIZE_2,
+    SDP_DSIZE_4,
+    SDP_DSIZE_8,
+    SDP_DSIZE_16,
+    SDP_DSIZE_NEXT1,
+    SDP_DSIZE_NEXT2,
+    SDP_DSIZE_NEXT4,
+    SDP_DSIZE_MASK = SDP_DSIZE_NEXT4,
+};
+
+enum bt_sdp_cmd {
+    SDP_ERROR_RSP		= 0x01,
+    SDP_SVC_SEARCH_REQ		= 0x02,
+    SDP_SVC_SEARCH_RSP		= 0x03,
+    SDP_SVC_ATTR_REQ		= 0x04,
+    SDP_SVC_ATTR_RSP		= 0x05,
+    SDP_SVC_SEARCH_ATTR_REQ	= 0x06,
+    SDP_SVC_SEARCH_ATTR_RSP	= 0x07,
+};
+
+enum bt_sdp_errorcode {
+    SDP_INVALID_VERSION		= 0x0001,
+    SDP_INVALID_RECORD_HANDLE	= 0x0002,
+    SDP_INVALID_SYNTAX		= 0x0003,
+    SDP_INVALID_PDU_SIZE	= 0x0004,
+    SDP_INVALID_CSTATE		= 0x0005,
+};
+
+/*
+ * String identifiers are based on the SDP spec stating that
+ * "base attribute id of the primary (universal) language must be 0x0100"
+ *
+ * Other languages should have their own offset; e.g.:
+ * #define XXXLangBase yyyy
+ * #define AttrServiceName_XXX	0x0000+XXXLangBase
+ */
+#define SDP_PRIMARY_LANG_BASE 		0x0100
+
+enum bt_sdp_attribute_id {
+    SDP_ATTR_RECORD_HANDLE			= 0x0000,
+    SDP_ATTR_SVCLASS_ID_LIST			= 0x0001,
+    SDP_ATTR_RECORD_STATE			= 0x0002,
+    SDP_ATTR_SERVICE_ID				= 0x0003,
+    SDP_ATTR_PROTO_DESC_LIST			= 0x0004,
+    SDP_ATTR_BROWSE_GRP_LIST			= 0x0005,
+    SDP_ATTR_LANG_BASE_ATTR_ID_LIST		= 0x0006,
+    SDP_ATTR_SVCINFO_TTL			= 0x0007,
+    SDP_ATTR_SERVICE_AVAILABILITY		= 0x0008,
+    SDP_ATTR_PFILE_DESC_LIST			= 0x0009,
+    SDP_ATTR_DOC_URL				= 0x000a,
+    SDP_ATTR_CLNT_EXEC_URL			= 0x000b,
+    SDP_ATTR_ICON_URL				= 0x000c,
+    SDP_ATTR_ADD_PROTO_DESC_LIST		= 0x000d,
+
+    SDP_ATTR_SVCNAME_PRIMARY			= SDP_PRIMARY_LANG_BASE + 0,
+    SDP_ATTR_SVCDESC_PRIMARY			= SDP_PRIMARY_LANG_BASE + 1,
+    SDP_ATTR_SVCPROV_PRIMARY			= SDP_PRIMARY_LANG_BASE + 2,
+
+    SDP_ATTR_GROUP_ID				= 0x0200,
+    SDP_ATTR_IP_SUBNET				= 0x0200,
+
+    /* SDP */
+    SDP_ATTR_VERSION_NUM_LIST			= 0x0200,
+    SDP_ATTR_SVCDB_STATE			= 0x0201,
+
+    SDP_ATTR_SERVICE_VERSION			= 0x0300,
+    SDP_ATTR_EXTERNAL_NETWORK			= 0x0301,
+    SDP_ATTR_SUPPORTED_DATA_STORES_LIST		= 0x0301,
+    SDP_ATTR_FAX_CLASS1_SUPPORT			= 0x0302,
+    SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL	= 0x0302,
+    SDP_ATTR_FAX_CLASS20_SUPPORT		= 0x0303,
+    SDP_ATTR_SUPPORTED_FORMATS_LIST		= 0x0303,
+    SDP_ATTR_FAX_CLASS2_SUPPORT			= 0x0304,
+    SDP_ATTR_AUDIO_FEEDBACK_SUPPORT		= 0x0305,
+    SDP_ATTR_NETWORK_ADDRESS			= 0x0306,
+    SDP_ATTR_WAP_GATEWAY			= 0x0307,
+    SDP_ATTR_HOMEPAGE_URL			= 0x0308,
+    SDP_ATTR_WAP_STACK_TYPE			= 0x0309,
+    SDP_ATTR_SECURITY_DESC			= 0x030a,
+    SDP_ATTR_NET_ACCESS_TYPE			= 0x030b,
+    SDP_ATTR_MAX_NET_ACCESSRATE			= 0x030c,
+    SDP_ATTR_IP4_SUBNET				= 0x030d,
+    SDP_ATTR_IP6_SUBNET				= 0x030e,
+    SDP_ATTR_SUPPORTED_CAPABILITIES		= 0x0310,
+    SDP_ATTR_SUPPORTED_FEATURES			= 0x0311,
+    SDP_ATTR_SUPPORTED_FUNCTIONS		= 0x0312,
+    SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY	= 0x0313,
+    SDP_ATTR_SUPPORTED_REPOSITORIES		= 0x0314,
+
+    /* PnP Information */
+    SDP_ATTR_SPECIFICATION_ID			= 0x0200,
+    SDP_ATTR_VENDOR_ID				= 0x0201,
+    SDP_ATTR_PRODUCT_ID				= 0x0202,
+    SDP_ATTR_VERSION				= 0x0203,
+    SDP_ATTR_PRIMARY_RECORD			= 0x0204,
+    SDP_ATTR_VENDOR_ID_SOURCE			= 0x0205,
+
+    /* BT HID */
+    SDP_ATTR_DEVICE_RELEASE_NUMBER		= 0x0200,
+    SDP_ATTR_PARSER_VERSION			= 0x0201,
+    SDP_ATTR_DEVICE_SUBCLASS			= 0x0202,
+    SDP_ATTR_COUNTRY_CODE			= 0x0203,
+    SDP_ATTR_VIRTUAL_CABLE			= 0x0204,
+    SDP_ATTR_RECONNECT_INITIATE			= 0x0205,
+    SDP_ATTR_DESCRIPTOR_LIST			= 0x0206,
+    SDP_ATTR_LANG_ID_BASE_LIST			= 0x0207,
+    SDP_ATTR_SDP_DISABLE			= 0x0208,
+    SDP_ATTR_BATTERY_POWER			= 0x0209,
+    SDP_ATTR_REMOTE_WAKEUP			= 0x020a,
+    SDP_ATTR_PROFILE_VERSION			= 0x020b,
+    SDP_ATTR_SUPERVISION_TIMEOUT		= 0x020c,
+    SDP_ATTR_NORMALLY_CONNECTABLE		= 0x020d,
+    SDP_ATTR_BOOT_DEVICE			= 0x020e,
+};
diff --git a/hw/cdrom.c b/hw/cdrom.c
index 2aa4d3b..87427a5 100644
--- a/hw/cdrom.c
+++ b/hw/cdrom.c
@@ -153,5 +153,3 @@
     cpu_to_be16wu((uint16_t *)buf, len - 2);
     return len;
 }
-
-
diff --git a/hw/devices.h b/hw/devices.h
index 45fead9..156bde2 100644
--- a/hw/devices.h
+++ b/hw/devices.h
@@ -6,51 +6,38 @@
 /* smc91c111.c */
 void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
 
-/* ssd0323.c */
-int ssd0323_xfer_ssi(void *opaque, int data);
-void *ssd0323_init(DisplayState *ds, qemu_irq *cmd_p);
-
-/* ads7846.c */
-struct ads7846_state_s;
-uint32_t ads7846_read(void *opaque);
-void ads7846_write(void *opaque, uint32_t value);
-struct ads7846_state_s *ads7846_init(qemu_irq penirq);
-
 /* tsc210x.c */
-struct uwire_slave_s;
-struct mouse_transform_info_s;
-struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio);
-struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq,
-                qemu_irq dav, AudioState *audio);
-struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip);
+uWireSlave *tsc2102_init(qemu_irq pint);
+uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
+I2SCodec *tsc210x_codec(uWireSlave *chip);
 uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
-void tsc210x_set_transform(struct uwire_slave_s *chip,
-                struct mouse_transform_info_s *info);
-void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down);
+void tsc210x_set_transform(uWireSlave *chip,
+                MouseTransformInfo *info);
+void tsc210x_key_event(uWireSlave *chip, int key, int down);
 
 /* tsc2005.c */
 void *tsc2005_init(qemu_irq pintdav);
 uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
-void tsc2005_set_transform(void *opaque, struct mouse_transform_info_s *info);
+void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
 
 /* stellaris_input.c */
 void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
 
 /* blizzard.c */
-void *s1d13745_init(qemu_irq gpio_int, DisplayState *ds);
+void *s1d13745_init(qemu_irq gpio_int);
 void s1d13745_write(void *opaque, int dc, uint16_t value);
 void s1d13745_write_block(void *opaque, int dc,
                 void *buf, size_t len, int pitch);
 uint16_t s1d13745_read(void *opaque, int dc);
 
 /* cbus.c */
-struct cbus_s {
+typedef struct {
     qemu_irq clk;
     qemu_irq dat;
     qemu_irq sel;
-};
-struct cbus_s *cbus_init(qemu_irq dat_out);
-void cbus_attach(struct cbus_s *bus, void *slave_opaque);
+} CBus;
+CBus *cbus_init(qemu_irq dat_out);
+void cbus_attach(CBus *bus, void *slave_opaque);
 
 void *retu_init(qemu_irq irq, int vilma);
 void *tahvo_init(qemu_irq irq, int betty);
@@ -58,17 +45,26 @@
 void retu_key_event(void *retu, int state);
 
 /* tusb6010.c */
-struct tusb_s;
-struct tusb_s *tusb6010_init(qemu_irq intr);
-int tusb6010_sync_io(struct tusb_s *s);
-int tusb6010_async_io(struct tusb_s *s);
-void tusb6010_power(struct tusb_s *s, int on);
+typedef struct TUSBState TUSBState;
+TUSBState *tusb6010_init(qemu_irq intr);
+int tusb6010_sync_io(TUSBState *s);
+int tusb6010_async_io(TUSBState *s);
+void tusb6010_power(TUSBState *s, int on);
 
 /* tc6393xb.c */
-struct tc6393xb_s;
-struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq);
-void tc6393xb_gpio_out_set(struct tc6393xb_s *s, int line,
+typedef struct TC6393xbState TC6393xbState;
+#define TC6393XB_RAM	0x110000 /* amount of ram for Video and USB */
+TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq);
+void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
                     qemu_irq handler);
-qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s);
+qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s);
+qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
 
+/* sm501.c */
+void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
+                CharDriverState *chr);
+
+/* usb-ohci.c */
+void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
+                         int num_ports, int devfn, qemu_irq irq);
 #endif
diff --git a/hw/dma.c b/hw/dma.c
index 00c6332..c8ed6b0 100644
--- a/hw/dma.c
+++ b/hw/dma.c
@@ -28,17 +28,13 @@
 
 #define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
 #ifdef DEBUG_DMA
-#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
 #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
 #define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
 #else
-#define lwarn(...)
 #define linfo(...)
 #define ldebug(...)
 #endif
 
-#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
-
 struct dma_regs {
     int now[2];
     uint16_t base[2];
@@ -78,6 +74,8 @@
 
 };
 
+static void DMA_run (void);
+
 static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
 
 static void write_page (void *opaque, uint32_t nport, uint32_t data)
@@ -214,6 +212,7 @@
             d->status &= ~(1 << (ichan + 4));
         }
         d->status &= ~(1 << ichan);
+        DMA_run();
         break;
 
     case 0x0a:                  /* single mask */
@@ -221,6 +220,7 @@
             d->mask |= 1 << (data & 3);
         else
             d->mask &= ~(1 << (data & 3));
+        DMA_run();
         break;
 
     case 0x0b:                  /* mode */
@@ -255,10 +255,12 @@
 
     case 0x0e:                  /* clear mask for all channels */
         d->mask = 0;
+        DMA_run();
         break;
 
     case 0x0f:                  /* write mask for all channels */
         d->mask = data;
+        DMA_run();
         break;
 
     default:
@@ -310,6 +312,7 @@
     ichan = nchan & 3;
     linfo ("held cont=%d chan=%d\n", ncont, ichan);
     dma_controllers[ncont].status |= 1 << (ichan + 4);
+    DMA_run();
 }
 
 void DMA_release_DREQ (int nchan)
@@ -320,6 +323,7 @@
     ichan = nchan & 3;
     linfo ("released cont=%d chan=%d\n", ncont, ichan);
     dma_controllers[ncont].status &= ~(1 << (ichan + 4));
+    DMA_run();
 }
 
 static void channel_run (int ncont, int ichan)
@@ -347,10 +351,13 @@
     ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
 }
 
-void DMA_run (void)
+static QEMUBH *dma_bh;
+
+static void DMA_run (void)
 {
     struct dma_cont *d;
     int icont, ichan;
+    int rearm = 0;
 
     d = dma_controllers;
 
@@ -360,10 +367,20 @@
 
             mask = 1 << ichan;
 
-            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
+            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
                 channel_run (icont, ichan);
+                rearm = 1;
+            }
         }
     }
+
+    if (rearm)
+        qemu_bh_schedule_idle(dma_bh);
+}
+
+static void DMA_run_bh(void *unused)
+{
+    DMA_run();
 }
 
 void DMA_register_channel (int nchan,
@@ -430,7 +447,7 @@
 {
     CPUState *env = cpu_single_env;
     if (env)
-        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+        cpu_exit(env);
 }
 
 static void dma_reset(void *opaque)
@@ -458,7 +475,7 @@
         register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
         register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
     }
-    for (i = 0; i < LENOFA (page_port_list); i++) {
+    for (i = 0; i < ARRAY_SIZE (page_port_list); i++) {
         register_ioport_write (page_base + page_port_list[i], 1, 1,
                                write_page, d);
         register_ioport_read (page_base + page_port_list[i], 1, 1,
@@ -476,9 +493,9 @@
         register_ioport_read (base + ((i + 8) << dshift), 1, 1,
                               read_cont, d);
     }
-    qemu_register_reset(dma_reset, d);
+    qemu_register_reset(dma_reset, 0, d);
     dma_reset(d);
-    for (i = 0; i < LENOFA (d->regs); ++i) {
+    for (i = 0; i < ARRAY_SIZE (d->regs); ++i) {
         d->regs[i].transfer_handler = dma_phony_handler;
     }
 }
@@ -534,6 +551,9 @@
         qemu_get_8s (f, &r->dack);
         qemu_get_8s (f, &r->eop);
     }
+
+    DMA_run();
+
     return 0;
 }
 
@@ -545,4 +565,6 @@
               high_page_enable ? 0x488 : -1);
     register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
     register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
+
+    dma_bh = qemu_bh_new(DMA_run_bh, NULL);
 }
diff --git a/hw/goldfish_audio.c b/hw/goldfish_audio.c
index d0a44b5..c8a6712 100644
--- a/hw/goldfish_audio.c
+++ b/hw/goldfish_audio.c
@@ -62,21 +62,25 @@
 	AUDIO_INT_READ_BUFFER_FULL      = 1U << 2,
 };
 
+struct goldfish_audio_buff {
+    uint32_t  address;
+    uint32_t  length;
+    uint8*    data;
+    uint32_t  capacity;
+    uint32_t  offset;
+};
+
 
 struct goldfish_audio_state {
     struct goldfish_device dev;
-    // pointers to our two write buffers
-    uint32_t buffer_1, buffer_2;
-    uint32_t read_buffer;
     // buffer flags
     uint32_t int_status;
     // irq enable mask for int_status
     uint32_t int_enable;
 
-#if USE_QEMU_AUDIO_IN
-    uint32_t  read_pos;
-    uint32_t  read_size;
-#else
+#ifndef USE_QEMU_AUDIO_IN
+    // address of the read buffer
+    uint32_t read_buffer;
     // path to file or device to use for input
     const char* input_source;
     // true if input is a wav file
@@ -94,11 +98,9 @@
     int current_buffer;
 
     // current data to write
-    uint8* data_1;
-    uint32_t data_1_length;
-    uint8* data_2;
-    uint32_t data_2_length;
-
+    struct goldfish_audio_buff  out_buff1[1];
+    struct goldfish_audio_buff  out_buff2[1];
+    struct goldfish_audio_buff  in_buff[1];
 
     // for QEMU sound output
     QEMUSoundCard card;
@@ -108,24 +110,132 @@
 #endif
 };
 
+static void
+goldfish_audio_buff_init( struct goldfish_audio_buff*  b )
+{
+    b->address  = 0;
+    b->length   = 0;
+    b->data     = NULL;
+    b->capacity = 0;
+    b->offset   = 0;
+}
+
+static void
+goldfish_audio_buff_reset( struct goldfish_audio_buff*  b )
+{
+    b->offset = 0;
+    b->length = 0;
+}
+
+static uint32_t
+goldfish_audio_buff_length( struct goldfish_audio_buff*  b )
+{
+    return b->length;
+}
+
+static void
+goldfish_audio_buff_ensure( struct goldfish_audio_buff*  b, uint32_t  size )
+{
+    if (b->capacity < size) {
+        b->data     = qemu_realloc(b->data, size);
+        b->capacity = size;
+    }
+}
+
+static void
+goldfish_audio_buff_set_address( struct goldfish_audio_buff*  b, uint32_t  addr )
+{
+    b->address = addr;
+}
+
+static void
+goldfish_audio_buff_set_length( struct goldfish_audio_buff*  b, uint32_t  len )
+{
+    b->length = len;
+    b->offset = 0;
+    goldfish_audio_buff_ensure(b, len);
+}
+
+static void
+goldfish_audio_buff_read( struct goldfish_audio_buff*  b )
+{
+    cpu_physical_memory_read(b->address, b->data, b->length);
+}
+
+static void
+goldfish_audio_buff_write( struct goldfish_audio_buff*  b )
+{
+    cpu_physical_memory_write(b->address, b->data, b->length);
+}
+
+static int
+goldfish_audio_buff_send( struct goldfish_audio_buff*  b, int  free, struct goldfish_audio_state*  s )
+{
+    int  ret, write = b->length;
+
+    if (write > free)
+        write = free;
+
+    ret = AUD_write(s->voice, b->data + b->offset, write);
+    b->offset += ret;
+    b->length -= ret;
+    return ret;
+}
+
+static int
+goldfish_audio_buff_available( struct goldfish_audio_buff*  b )
+{
+    return b->length - b->offset;
+}
+
+static int
+goldfish_audio_buff_recv( struct goldfish_audio_buff*  b, int  avail, struct goldfish_audio_state*  s )
+{
+    int     missing = b->length - b->offset;
+    int     avail2 = (avail > missing) ? missing : avail;
+    int     read;
+
+    read = AUD_read(s->voicein, b->data + b->offset, avail2 );
+    if (read == 0)
+        return 0;
+
+    if (avail2 > 0)
+        D("%s: AUD_read(%d) returned %d", __FUNCTION__, avail2, read);
+
+    cpu_physical_memory_write( b->address + b->offset, b->data, read );
+    b->offset += read;
+
+    return read;
+}
+
+static void
+goldfish_audio_buff_put( struct goldfish_audio_buff*  b, QEMUFile*  f )
+{
+    qemu_put_be32(f, b->address );
+    qemu_put_be32(f, b->length );
+    qemu_put_be32(f, b->offset );
+    qemu_put_buffer(f, b->data, b->length );
+}
+
+static int
+goldfish_audio_buff_get( struct goldfish_audio_buff*  b, QEMUFile*  f )
+{
+    b->address = qemu_get_be32(f);
+    b->length  = qemu_get_be32(f);
+    b->offset  = qemu_get_be32(f);
+    goldfish_audio_buff_ensure(b, b->length);
+    qemu_get_buffer(f, b->data, b->length);
+}
+
 /* update this whenever you change the goldfish_audio_state structure */
-#define  AUDIO_STATE_SAVE_VERSION  1
+#define  AUDIO_STATE_SAVE_VERSION  2
 
 #define  QFIELD_STRUCT   struct goldfish_audio_state
 QFIELD_BEGIN(audio_state_fields)
-    QFIELD_INT32(buffer_1),
-    QFIELD_INT32(buffer_2),
-    QFIELD_INT32(read_buffer),
     QFIELD_INT32(int_status),
     QFIELD_INT32(int_enable),
-#if USE_QEMU_AUDIO_IN
-    QFIELD_INT32(read_pos),
-    QFIELD_INT32(read_size),
-#endif
     QFIELD_INT32(read_buffer_available),
     QFIELD_INT32(current_buffer),
-    QFIELD_INT32(data_1_length),
-    QFIELD_INT32(data_2_length),
 QFIELD_END
 
 static void  audio_state_save( QEMUFile*  f, void* opaque )
@@ -134,9 +244,9 @@
 
     qemu_put_struct(f, audio_state_fields, s);
 
-    /* we can't write data_1 and data_2 directly */
-    qemu_put_be32( f, s->data_1 - phys_ram_base );
-    qemu_put_be32( f, s->data_2 - phys_ram_base );
+    goldfish_audio_buff_put (s->out_buff1, f);
+    goldfish_audio_buff_put (s->out_buff2, f);
+    goldfish_audio_buff_put (s->in_buff, f);
 }
 
 static int   audio_state_load( QEMUFile*  f, void*  opaque, int  version_id )
@@ -149,8 +259,9 @@
 
     ret = qemu_get_struct(f, audio_state_fields, s);
     if (!ret) {
-        s->data_1 = qemu_get_be32(f) + phys_ram_base;
-        s->data_2 = qemu_get_be32(f) + phys_ram_base;
+        goldfish_audio_buff_get( s->out_buff1, f );
+        goldfish_audio_buff_get( s->out_buff2, f );
+        goldfish_audio_buff_get (s->in_buff, f);
     }
     return -1;
 }
@@ -158,25 +269,25 @@
 static void enable_audio(struct goldfish_audio_state *s, int enable)
 {
     // enable or disable the output voice
-    if (s->voice != NULL)
+    if (s->voice != NULL) {
         AUD_set_active_out(s->voice,   (enable & (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY)) != 0);
+        goldfish_audio_buff_reset( s->out_buff1 );
+        goldfish_audio_buff_reset( s->out_buff2 );
+    }
 
-    if (s->voicein)
+    if (s->voicein) {
         AUD_set_active_in (s->voicein, (enable & AUDIO_INT_READ_BUFFER_FULL) != 0);
-    // reset buffer information
-    s->data_1_length = 0;
-    s->data_2_length = 0;
+        goldfish_audio_buff_reset( s->in_buff );
+    }
     s->current_buffer = 0;
-    s->read_pos = 0;
 }
 
 #if USE_QEMU_AUDIO_IN
 static void start_read(struct goldfish_audio_state *s, uint32_t count)
 {
     //printf( "... goldfish audio start_read, count=%d\n", count );
-    s->read_size = count;
-    s->read_buffer_available = 0;
-    s->read_pos  = 0;
+    goldfish_audio_buff_set_length( s->in_buff, count );
+    s->read_buffer_available = count;
 }
 #else
 static void start_read(struct goldfish_audio_state *s, uint32_t count)
@@ -255,7 +366,6 @@
 {
     uint32_t ret;
     struct goldfish_audio_state *s = opaque;
-    offset -= s->dev.base;
     switch(offset) {
         case AUDIO_INT_STATUS:
             // return current buffer status flags
@@ -277,6 +387,7 @@
 	case AUDIO_READ_BUFFER_AVAILABLE:
             D("%s: AUDIO_READ_BUFFER_AVAILABLE returns %d", __FUNCTION__,
                s->read_buffer_available);
+            goldfish_audio_buff_write( s->in_buff );
 	    return s->read_buffer_available;
 
         default:
@@ -288,7 +399,6 @@
 static void goldfish_audio_write(void *opaque, target_phys_addr_t offset, uint32_t val)
 {
     struct goldfish_audio_state *s = opaque;
-    offset -= s->dev.base;
 
     switch(offset) {
         case AUDIO_INT_ENABLE:
@@ -301,30 +411,34 @@
             break;
         case AUDIO_SET_WRITE_BUFFER_1:
             /* save pointer to buffer 1 */
-            s->buffer_1 = val;
+            D( "%s: AUDIO_SET_WRITE_BUFFER_1 %08x", __FUNCTION__, val);
+            goldfish_audio_buff_set_address( s->out_buff1, val );
             break;
         case AUDIO_SET_WRITE_BUFFER_2:
             /* save pointer to buffer 2 */
-            s->buffer_2 = val;
+            D( "%s: AUDIO_SET_WRITE_BUFFER_2 %08x", __FUNCTION__, val);
+            goldfish_audio_buff_set_address( s->out_buff2, val );
             break;
         case AUDIO_WRITE_BUFFER_1:
             /* record that data in buffer 1 is ready to write */
+            //D( "%s: AUDIO_WRITE_BUFFER_1 %08x", __FUNCTION__, val);
             if (s->current_buffer == 0) s->current_buffer = 1;
-            s->data_1 = phys_ram_base + s->buffer_1;
-            s->data_1_length = val;
+            goldfish_audio_buff_set_length( s->out_buff1, val );
+            goldfish_audio_buff_read( s->out_buff1 );
             s->int_status &= ~AUDIO_INT_WRITE_BUFFER_1_EMPTY;
             break;
         case AUDIO_WRITE_BUFFER_2:
             /* record that data in buffer 2 is ready to write */
+            //D( "%s: AUDIO_WRITE_BUFFER_2 %08x", __FUNCTION__, val);
             if (s->current_buffer == 0) s->current_buffer = 2;
-            s->data_2 = phys_ram_base + s->buffer_2;
-            s->data_2_length = val;
+            goldfish_audio_buff_set_length( s->out_buff2, val );
+            goldfish_audio_buff_read( s->out_buff2 );
             s->int_status &= ~AUDIO_INT_WRITE_BUFFER_2_EMPTY;
             break;
 
-	case AUDIO_SET_READ_BUFFER:
+        case AUDIO_SET_READ_BUFFER:
             /* save pointer to the read buffer */
-            s->read_buffer = val;
+            goldfish_audio_buff_set_address( s->in_buff, val );
             D( "%s: AUDIO_SET_READ_BUFFER %p", __FUNCTION__, (void*)val );
             break;
 
@@ -350,19 +464,14 @@
 
         /* write data in buffer 1 */
         while (free && s->current_buffer == 1) {
-            int write = s->data_1_length;
-            if (write > free) write = free;
-
-            int written = AUD_write(s->voice, s->data_1, write);
+            int  written = goldfish_audio_buff_send( s->out_buff1, free, s );
             if (written) {
-                D("%s: sent %d bytes to audio output", __FUNCTION__, write);
-                s->data_1 += written;
-                s->data_1_length -= written;
+                D("%s: sent %5d bytes to audio output (buffer 1)", __FUNCTION__, written);
                 free -= written;
 
-                if (s->data_1_length == 0) {
+                if (goldfish_audio_buff_length( s->out_buff1 ) == 0) {
                     new_status |= AUDIO_INT_WRITE_BUFFER_1_EMPTY;
-                    s->current_buffer = (s->data_2_length ? 2 : 0);
+                    s->current_buffer = (goldfish_audio_buff_length( s->out_buff2 ) ? 2 : 0);
                 }
             } else {
                 break;
@@ -371,19 +480,14 @@
 
         /* write data in buffer 2 */
         while (free && s->current_buffer == 2) {
-            int write = s->data_2_length;
-            if (write > free) write = free;
-
-            int written = AUD_write(s->voice, s->data_2, write);
+            int  written = goldfish_audio_buff_send( s->out_buff2, free, s );
             if (written) {
-                D("%s: sent %d bytes to audio output", __FUNCTION__, write);
-                s->data_2 += written;
-                s->data_2_length -= written;
+                D("%s: sent %5d bytes to audio output (buffer 2)", __FUNCTION__, written);
                 free -= written;
 
-                if (s->data_2_length == 0) {
+                if (goldfish_audio_buff_length( s->out_buff2 ) == 0) {
                     new_status |= AUDIO_INT_WRITE_BUFFER_2_EMPTY;
-                    s->current_buffer = (s->data_1_length ? 1 : 0);
+                    s->current_buffer = (goldfish_audio_buff_length( s->out_buff1 ) ? 1 : 0);
                 }
             } else {
                 break;
@@ -404,36 +508,22 @@
     struct goldfish_audio_state *s = opaque;
     int new_status = 0;
 
-    if (s->read_pos >= s->read_size)
+    if (goldfish_audio_buff_available( s->in_buff ) == 0 )
         return;
 
-    if (0 && s->read_size > 0)
-        D("%s: in %d (pos=%d size=%d)", __FUNCTION__,
-           avail, s->read_pos, s->read_size );
-
     while (avail > 0) {
-        int     pos     = s->read_pos;
-        int     missing = s->read_size - pos;
-        uint8*  buffer  = (uint8*)phys_ram_base + s->read_buffer + pos;
-        int     read;
-        int     avail2 = (avail > missing) ? missing : avail;
-
-        read = AUD_read(s->voicein, buffer, avail2);
+        int  read = goldfish_audio_buff_recv( s->in_buff, avail, s );
         if (read == 0)
             break;
 
-        if (avail2 > 0)
-            D("%s: AUD_read(%d) returned %d", __FUNCTION__, avail2, read);
-
-        s->read_buffer_available += read;
-
         avail -= read;
-        pos   += read;
-        if (pos == s->read_size) {
+
+        if (goldfish_audio_buff_available( s->in_buff) == 0) {
             new_status |= AUDIO_INT_READ_BUFFER_FULL;
-            D("%s: AUDIO_INT_READ_BUFFER_FULL available=%d", __FUNCTION__, s->read_buffer_available);
+            D("%s: AUDIO_INT_READ_BUFFER_FULL available=%d",
+              __FUNCTION__, goldfish_audio_buff_length( s->in_buff ));
+            break;
         }
-        s->read_pos = pos;
     }
 
     if (new_status && new_status != s->int_status) {
@@ -458,7 +548,7 @@
 void goldfish_audio_init(uint32_t base, int id, const char* input_source)
 {
     struct goldfish_audio_state *s;
-    audsettings_t as;
+    struct audsettings as;
 
     /* nothing to do if no audio input and output */
     if (!android_hw->hw_audioOutput && !android_hw->hw_audioInput)
@@ -482,7 +572,7 @@
      }
 #endif
 
-    AUD_register_card( &glob_audio_state, "goldfish_audio", &s->card);
+    AUD_register_card( "goldfish_audio", &s->card);
 
     as.freq = 44100;
     as.nchannels = 2;
@@ -525,6 +615,10 @@
     }
 #endif
 
+    goldfish_audio_buff_init( s->out_buff1 );
+    goldfish_audio_buff_init( s->out_buff2 );
+    goldfish_audio_buff_init( s->in_buff );
+
     goldfish_device_add(&s->dev, goldfish_audio_readfn, goldfish_audio_writefn, s);
 
     register_savevm( "audio_state", 0, AUDIO_STATE_SAVE_VERSION,
diff --git a/hw/goldfish_battery.c b/hw/goldfish_battery.c
index d9ef785..c5eef9c 100644
--- a/hw/goldfish_battery.c
+++ b/hw/goldfish_battery.c
@@ -83,7 +83,7 @@
 {
     uint32_t ret;
     struct goldfish_battery_state *s = opaque;
-    offset -= s->dev.base;
+
     switch(offset) {
         case BATTERY_INT_STATUS:
             // return current buffer status flags
@@ -116,7 +116,6 @@
 static void goldfish_battery_write(void *opaque, target_phys_addr_t offset, uint32_t val)
 {
     struct goldfish_battery_state *s = opaque;
-    offset -= s->dev.base;
 
     switch(offset) {
         case BATTERY_INT_ENABLE:
diff --git a/hw/goldfish_device.c b/hw/goldfish_device.c
index 2c9dd6e..3ced4ce 100644
--- a/hw/goldfish_device.c
+++ b/hw/goldfish_device.c
@@ -77,8 +77,7 @@
 {
     int iomemtype;
     goldfish_add_device_no_io(dev);
-    iomemtype = cpu_register_io_memory(0, mem_read,
-                                       mem_write, opaque);
+    iomemtype = cpu_register_io_memory(mem_read, mem_write, opaque);
     cpu_register_physical_memory(dev->base, dev->size, iomemtype);
     return 0;
 }
@@ -86,7 +85,6 @@
 static uint32_t goldfish_bus_read(void *opaque, target_phys_addr_t offset)
 {
     struct bus_state *s = (struct bus_state *)opaque;
-    offset -= s->dev.base;
 
     switch (offset) {
         case PDEV_BUS_OP:
@@ -138,7 +136,6 @@
 static void goldfish_bus_write(void *opaque, target_phys_addr_t offset, uint32_t value)
 {
     struct bus_state *s = (struct bus_state *)opaque;
-    offset -= s->dev.base;
 
     switch(offset) {
         case PDEV_BUS_OP:
@@ -152,7 +149,7 @@
             break;
         case PDEV_BUS_GET_NAME:
             if(s->current)
-                pmemcpy(value, s->current->name, strlen(s->current->name));
+                cpu_memory_rw_debug(cpu_single_env, value, (void*)s->current->name, strlen(s->current->name), 1);
             break;
         default:
             cpu_abort (cpu_single_env, "goldfish_bus_write: Bad offset %x\n", offset);
diff --git a/hw/goldfish_events_device.c b/hw/goldfish_events_device.c
index 6f7e41b..d8e265c 100644
--- a/hw/goldfish_events_device.c
+++ b/hw/goldfish_events_device.c
@@ -164,7 +164,7 @@
 static uint32_t events_read(void *x, target_phys_addr_t off)
 {
     events_state *s = (events_state *) x;
-    int offset = off - s->base;
+    int offset = off; // - s->base;
     if (offset == REG_READ)
         return dequeue_event(s);
     else if (offset == REG_LEN)
@@ -177,7 +177,7 @@
 static void events_write(void *x, target_phys_addr_t off, uint32_t val)
 {
     events_state *s = (events_state *) x;
-    int offset = off - s->base;
+    int offset = off; // - s->base;
     if (offset == REG_SET_PAGE)
         s->page = val;
 }
@@ -379,12 +379,12 @@
         events_set_bit(s, EV_SW, 0);
     }
 
-    iomemtype = cpu_register_io_memory(0, events_readfn, events_writefn, s);
+    iomemtype = cpu_register_io_memory(events_readfn, events_writefn, s);
 
     cpu_register_physical_memory(base, 0xfff, iomemtype);
 
     qemu_add_kbd_event_handler(events_put_keycode, s);
-    qemu_add_mouse_event_handler(events_put_mouse, s, 1);
+    qemu_add_mouse_event_handler(events_put_mouse, s, 1, "goldfish-events");
     qemu_add_generic_event_handler(events_put_generic, s);
 
     s->base = base;
diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c
index 71cede2..4a0e335 100644
--- a/hw/goldfish_fb.c
+++ b/hw/goldfish_fb.c
@@ -155,7 +155,7 @@
         s->need_update = 0;
     }
 
-    src_line = phys_ram_base + base;
+    src_line  = qemu_get_ram_ptr( base );
     dst_line  = s->qfbuff->pixels;
     pitch     = s->qfbuff->pitch;
     width     = s->qfbuff->width;
@@ -292,7 +292,7 @@
 {
     uint32_t ret;
     struct goldfish_fb_state *s = opaque;
-    offset -= s->dev.base;
+
     switch(offset) {
         case FB_GET_WIDTH:
             ret = s->qfbuff->width;
@@ -332,7 +332,7 @@
                         uint32_t val)
 {
     struct goldfish_fb_state *s = opaque;
-    offset -= s->dev.base;
+
     switch(offset) {
         case FB_INT_ENABLE:
             s->int_enable = val;
diff --git a/hw/goldfish_interrupt.c b/hw/goldfish_interrupt.c
index 2cba649..c620664 100644
--- a/hw/goldfish_interrupt.c
+++ b/hw/goldfish_interrupt.c
@@ -95,7 +95,6 @@
 static uint32_t goldfish_int_read(void *opaque, target_phys_addr_t offset)
 {
     struct goldfish_int_state *s = (struct goldfish_int_state *)opaque;
-    offset -= s->dev.base;
 
     switch (offset) {
     case INTERRUPT_STATUS: /* IRQ_STATUS */
@@ -119,7 +118,6 @@
 {
     struct goldfish_int_state *s = (struct goldfish_int_state *)opaque;
     uint32_t mask = (1U << value);
-    offset -= s->dev.base;
 
     switch (offset) {
         case INTERRUPT_DISABLE_ALL:
diff --git a/hw/goldfish_memlog.c b/hw/goldfish_memlog.c
index 98fcffc..f4be28a 100644
--- a/hw/goldfish_memlog.c
+++ b/hw/goldfish_memlog.c
@@ -24,7 +24,6 @@
 static uint32_t memlog_read(void *opaque, target_phys_addr_t offset)
 {
     struct goldfish_device *dev = opaque;
-    offset -= dev->base;
 
     return 0;
 }
@@ -35,7 +34,6 @@
 {
     char buf[128];
     struct goldfish_device *dev = opaque;
-    offset -= dev->base;
 
     info[offset / 4] = val;
 
diff --git a/hw/goldfish_mmc.c b/hw/goldfish_mmc.c
index 272f403..2295d2d 100644
--- a/hw/goldfish_mmc.c
+++ b/hw/goldfish_mmc.c
@@ -63,7 +63,7 @@
     struct goldfish_device dev;
     BlockDriverState *bs;
     // pointer to our buffer
-    uint8_t* buffer;
+    uint32_t buffer_address;
     // offsets for read and write operations
     uint32_t read_offset, write_offset;
     // buffer status flags
@@ -78,11 +78,14 @@
     uint32_t block_length;
     uint32_t block_count;
     int is_SDHC;
+
+    uint8_t* buf;
 };
 
-#define  GOLDFISH_MMC_SAVE_VERSION  1
+#define  GOLDFISH_MMC_SAVE_VERSION  2
 #define  QFIELD_STRUCT  struct goldfish_mmc_state
 QFIELD_BEGIN(goldfish_mmc_fields)
+    QFIELD_INT32(buffer_address),
     QFIELD_INT32(read_offset),
     QFIELD_INT32(write_offset),
     QFIELD_INT32(int_status),
@@ -101,7 +104,6 @@
 {
     struct goldfish_mmc_state*  s = opaque;
 
-    qemu_put_be32(f, s->buffer - phys_ram_base);
     qemu_put_struct(f, goldfish_mmc_fields, s);
 }
 
@@ -112,7 +114,6 @@
     if (version_id != GOLDFISH_MMC_SAVE_VERSION)
         return -1;
 
-    s->buffer = qemu_get_be32(f) + phys_ram_base;
     return qemu_get_struct(f, goldfish_mmc_fields, s);
 }
 
@@ -169,6 +170,48 @@
 }
 #endif
 
+static int  goldfish_mmc_bdrv_read(struct goldfish_mmc_state *s,
+                                   int64_t                    sector_number,
+                                   target_phys_addr_t         dst_address,
+                                   int                        num_sectors)
+{
+    int  ret;
+
+    while (num_sectors > 0) {
+        ret = bdrv_read(s->bs, sector_number, s->buf, 1);
+        if (ret < 0)
+            return ret;
+
+        cpu_physical_memory_write(dst_address, s->buf, 512);
+        dst_address   += 512;
+        num_sectors   -= 1;
+        sector_number += 1;
+    }
+    return 0;
+}
+
+static int  goldfish_mmc_bdrv_write(struct goldfish_mmc_state *s,
+                                    int64_t                    sector_number,
+                                    target_phys_addr_t         dst_address,
+                                    int                        num_sectors)
+{
+    int  ret;
+
+    while (num_sectors > 0) {
+        cpu_physical_memory_read(dst_address, s->buf, 512);
+
+        ret = bdrv_write(s->bs, sector_number, s->buf, 1);
+        if (ret < 0)
+            return ret;
+
+        dst_address   += 512;
+        num_sectors   -= 1;
+        sector_number += 1;
+    }
+    return 0;
+}
+
+
 static void goldfish_mmc_do_command(struct goldfish_mmc_state *s, uint32_t cmd, uint32_t arg)
 {
     int result;
@@ -269,9 +312,15 @@
 
         case SD_APP_SEND_SCR:
         {
-            uint32_t* scr = (uint32_t*)s->buffer;
+#if 1 /* this code is actually endian-safe */
+            const uint8_t  scr[8] = "\x02\x25\x00\x00\x00\x00\x00\x00";
+#else /* this original code wasn't */
+            uint32_t scr[2];
             scr[0] = 0x00002502;
             scr[1] = 0x00000000;
+#endif
+            cpu_physical_memory_write(s->buffer_address, (uint8_t*)scr, 8);
+
             s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336
             new_status |= MMC_STAT_END_OF_DATA;
             break;
@@ -293,9 +342,10 @@
 
          case MMC_SWITCH:
             if (arg == 0x00FFFFF1 || arg == 0x80FFFFF1) {
-                uint8_t* switchbuf = s->buffer;
-                memset(switchbuf, 0, 64);
-                switchbuf[13] = 2;
+                uint8_t  buff0[64];
+                memset(buff0, 0, sizeof buff0);
+                buff0[13] = 2;
+                cpu_physical_memory_write(s->buffer_address, buff0, sizeof buff0);
                 new_status |= MMC_STAT_END_OF_DATA;
             }
             s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336
@@ -317,7 +367,7 @@
                 if (arg & 511) fprintf(stderr, "offset %d is not multiple of 512 when reading\n", arg);
                 arg /= s->block_length;
             }
-            result = bdrv_read(s->bs, arg, s->buffer, s->block_count);
+            result = goldfish_mmc_bdrv_read(s, arg, s->buffer_address, s->block_count);
             new_status |= MMC_STAT_END_OF_DATA;
             s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
             break;
@@ -335,7 +385,7 @@
                 arg /= s->block_length;
             }
             // arg is byte offset
-            result = bdrv_write(s->bs, arg, s->buffer, s->block_count);
+            result = goldfish_mmc_bdrv_write(s, arg, s->buffer_address, s->block_count);
 //            bdrv_flush(s->bs);
             new_status |= MMC_STAT_END_OF_DATA;
             s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
@@ -363,7 +413,6 @@
     uint32_t ret;
     struct goldfish_mmc_state *s = opaque;
 
-    offset -= s->dev.base;
     switch(offset) {
         case MMC_INT_STATUS:
             // return current buffer status flags
@@ -394,8 +443,6 @@
     struct goldfish_mmc_state *s = opaque;
     int status, old_status;
 
-    offset -= s->dev.base;
-
     switch(offset) {
 
         case MMC_INT_STATUS:
@@ -416,7 +463,7 @@
             break;
         case MMC_SET_BUFFER:
             /* save pointer to buffer 1 */
-            s->buffer = phys_ram_base + val;
+            s->buffer_address = val;
             break;
         case MMC_CMD:
             goldfish_mmc_do_command(s, val, s->arg);
@@ -459,6 +506,7 @@
     s->dev.size = 0x1000;
     s->dev.irq_count = 1;
     s->bs = bs;
+    s->buf = qemu_memalign(512,512);
 
     goldfish_device_add(&s->dev, goldfish_mmc_readfn, goldfish_mmc_writefn, s);
 
diff --git a/hw/goldfish_nand.c b/hw/goldfish_nand.c
index 61b075e..2d23baa 100644
--- a/hw/goldfish_nand.c
+++ b/hw/goldfish_nand.c
@@ -18,8 +18,8 @@
 
 #define  DEBUG  1
 #if DEBUG
-#  define  D(...)    VERBOSE_PRINT(nand,__VA_ARGS__)
-#  define  D_ACTIVE  VERBOSE_CHECK(nand)
+#  define  D(...)    VERBOSE_PRINT(init,__VA_ARGS__)
+#  define  D_ACTIVE  VERBOSE_CHECK(init)
 #  define  T(...)    VERBOSE_PRINT(nand_limits,__VA_ARGS__)
 #  define  T_ACTIVE  VERBOSE_CHECK(nand_limits)
 #else
@@ -193,7 +193,7 @@
         if(!eof) {
             read_len = do_read(dev->fd, dev->data, read_len);
         }
-        pmemcpy(data, dev->data, read_len);
+        cpu_memory_rw_debug(cpu_single_env, data, dev->data, read_len, 1);
         data += read_len;
         len -= read_len;
     }
@@ -212,7 +212,7 @@
     while(len > 0) {
         if(len < write_len)
             write_len = len;
-        vmemcpy(data, dev->data, write_len);
+        cpu_memory_rw_debug(cpu_single_env, data, dev->data, write_len, 0);
         ret = do_write(dev->fd, dev->data, write_len);
         if(ret < write_len) {
             XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno));
@@ -274,7 +274,7 @@
     case NAND_CMD_GET_DEV_NAME:
         if(size > dev->devname_len)
             size = dev->devname_len;
-        pmemcpy(s->data, dev->devname, size);
+        cpu_memory_rw_debug(cpu_single_env, s->data, dev->devname, size, 1);
         return size;
     case NAND_CMD_READ:
         if(addr >= dev->size)
@@ -283,7 +283,7 @@
             size = dev->size - addr;
         if(dev->fd >= 0)
             return nand_dev_read_file(dev, s->data, addr, size);
-        pmemcpy(s->data, &dev->data[addr], size);
+        cpu_memory_rw_debug(cpu_single_env,s->data, &dev->data[addr], size, 1);
         return size;
     case NAND_CMD_WRITE:
         if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
@@ -294,7 +294,7 @@
             size = dev->size - addr;
         if(dev->fd >= 0)
             return nand_dev_write_file(dev, s->data, addr, size);
-        vmemcpy(s->data, &dev->data[addr], size);
+        cpu_memory_rw_debug(cpu_single_env,s->data, &dev->data[addr], size, 0);
         return size;
     case NAND_CMD_ERASE:
         if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
@@ -324,7 +324,6 @@
 {
     nand_dev_state *s = (nand_dev_state *)opaque;
 
-    offset -= s->base;
     switch (offset) {
     case NAND_DEV:
         s->dev = value;
@@ -359,7 +358,6 @@
     nand_dev_state *s = (nand_dev_state *)opaque;
     nand_dev *dev;
 
-    offset -= s->base;
     switch (offset) {
     case NAND_VERSION:
         return NAND_VERSION_CURRENT;
@@ -422,7 +420,7 @@
     nand_dev_state *s;
 
     s = (nand_dev_state *)qemu_mallocz(sizeof(nand_dev_state));
-    iomemtype = cpu_register_io_memory(0, nand_dev_readfn, nand_dev_writefn, s);
+    iomemtype = cpu_register_io_memory(nand_dev_readfn, nand_dev_writefn, s);
     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
     s->base = base;
 
@@ -595,7 +593,7 @@
     pad = dev_size % dev->erase_size;
     if (pad != 0) {
         dev_size += (dev->erase_size - pad);
-        XLOG("rounding devsize up to a full eraseunit, now %llx\n", dev_size);
+        D("rounding devsize up to a full eraseunit, now %llx\n", dev_size);
     }
     dev->devname = devname;
     dev->devname_len = devname_len;
diff --git a/hw/goldfish_switch.c b/hw/goldfish_switch.c
index 8a12d66..99a9379 100644
--- a/hw/goldfish_switch.c
+++ b/hw/goldfish_switch.c
@@ -62,7 +62,6 @@
 static uint32_t goldfish_switch_read(void *opaque, target_phys_addr_t offset)
 {
     struct switch_state *s = (struct switch_state *)opaque;
-    offset -= s->dev.base;
 
     //printf("goldfish_switch_read %x %x\n", offset, size);
 
@@ -89,13 +88,12 @@
 static void goldfish_switch_write(void *opaque, target_phys_addr_t offset, uint32_t value)
 {
     struct switch_state *s = (struct switch_state *)opaque;
-    offset -= s->dev.base;
 
     //printf("goldfish_switch_read %x %x %x\n", offset, value, size);
 
     switch(offset) {
         case SW_NAME_PTR:
-            pmemcpy(value, s->name, strlen(s->name));
+            cpu_memory_rw_debug(cpu_single_env, value, (void*)s->name, strlen(s->name), 1);
             break;
 
         case SW_STATE:
diff --git a/hw/goldfish_timer.c b/hw/goldfish_timer.c
index 73f1455..8a84895 100644
--- a/hw/goldfish_timer.c
+++ b/hw/goldfish_timer.c
@@ -74,7 +74,6 @@
 static uint32_t goldfish_timer_read(void *opaque, target_phys_addr_t offset)
 {
     struct timer_state *s = (struct timer_state *)opaque;
-    offset -= s->dev.base;
     switch(offset) {
         case TIMER_TIME_LOW:
             s->now = muldiv64(qemu_get_clock(vm_clock), 1000000000, ticks_per_sec);
@@ -91,7 +90,6 @@
 {
     struct timer_state *s = (struct timer_state *)opaque;
     int64_t alarm, now;
-    offset -= s->dev.base;
     switch(offset) {
         case TIMER_ALARM_LOW:
             s->alarm_low = value;
@@ -161,7 +159,6 @@
 static uint32_t goldfish_rtc_read(void *opaque, target_phys_addr_t offset)
 {
     struct rtc_state *s = (struct rtc_state *)opaque;
-    offset -= s->dev.base;
     switch(offset) {
         case 0x0:
             s->now = (int64_t)time(NULL) * 1000000000;
@@ -178,7 +175,6 @@
 {
     struct rtc_state *s = (struct rtc_state *)opaque;
     int64_t alarm;
-    offset -= s->dev.base;
     switch(offset) {
         case 0x8:
             s->alarm_low = value;
diff --git a/hw/goldfish_trace.c b/hw/goldfish_trace.c
index f49b704..c4f2f92 100644
--- a/hw/goldfish_trace.c
+++ b/hw/goldfish_trace.c
@@ -42,7 +42,6 @@
 {
     trace_dev_state *s = (trace_dev_state *)opaque;
 
-    offset -= s->dev.base;
     switch (offset >> 2) {
     case TRACE_DEV_REG_SWITCH:  // context switch, switch to pid
         trace_switch(value);
@@ -89,7 +88,7 @@
         cmdlen = value;
         break;
     case TRACE_DEV_REG_CMDLINE:         // execve, process cmdline
-        vmemcpy(value, arg, cmdlen);
+        cpu_memory_rw_debug(cpu_single_env, value, arg, cmdlen, 0);
         trace_execve(arg, cmdlen);
 #ifdef DEBUG
         {
@@ -227,7 +226,6 @@
 {
     trace_dev_state *s = (trace_dev_state *)opaque;
 
-    offset -= s->dev.base;
     switch (offset >> 2) {
     case TRACE_DEV_REG_ENABLE:          // tracing enable
         return tracing;
diff --git a/hw/goldfish_trace.h b/hw/goldfish_trace.h
index 11ed906..76b61a8 100644
--- a/hw/goldfish_trace.h
+++ b/hw/goldfish_trace.h
@@ -59,9 +59,6 @@
  * interfaces for copy from virtual space
  * from target-arm/op_helper.c
  */
-extern target_phys_addr_t v2p(target_ulong ptr, int is_user);
-extern void vmemcpy(target_ulong ptr, char *buf, int size);
-extern void pmemcpy(target_ulong ptr, const char* buf, int size);
 extern void vstrcpy(target_ulong ptr, char *buf, int max);
 
 /*
diff --git a/hw/goldfish_tty.c b/hw/goldfish_tty.c
index aa62d75..dd50efc 100644
--- a/hw/goldfish_tty.c
+++ b/hw/goldfish_tty.c
@@ -69,7 +69,6 @@
 static uint32_t goldfish_tty_read(void *opaque, target_phys_addr_t offset)
 {
     struct tty_state *s = (struct tty_state *)opaque;
-    offset -= s->dev.base;
 
     //printf("goldfish_tty_read %x %x\n", offset, size);
 
@@ -85,7 +84,6 @@
 static void goldfish_tty_write(void *opaque, target_phys_addr_t offset, uint32_t value)
 {
     struct tty_state *s = (struct tty_state *)opaque;
-    offset -= s->dev.base;
 
     //printf("goldfish_tty_read %x %x %x\n", offset, value, size);
 
@@ -117,18 +115,19 @@
                 case TTY_CMD_WRITE_BUFFER:
                     if(s->cs) {
                         int len;
-                        target_ulong buf;
+                        target_phys_addr_t  buf;
 
                         buf = s->ptr;
                         len = s->ptr_len;
 
-                        while(len) {
-                            int page_remain = TARGET_PAGE_SIZE - (buf & ~TARGET_PAGE_MASK);
-                            int to_write = len;
-                            uint8_t *phys = (uint8_t *)v2p(buf, 0);
-                            if(to_write > page_remain)
-                                to_write = page_remain;
-                            qemu_chr_write(s->cs, phys, to_write);
+                        while (len) {
+                            char   temp[64];
+                            int    to_write = sizeof(temp);
+                            if (to_write > len)
+                                to_write = len;
+
+                            cpu_memory_rw_debug(cpu_single_env, buf, temp, to_write, 0);
+                            qemu_chr_write(s->cs, temp, to_write);
                             buf += to_write;
                             len -= to_write;
                         }
@@ -139,7 +138,7 @@
                 case TTY_CMD_READ_BUFFER:
                     if(s->ptr_len > s->data_count)
                         cpu_abort (cpu_single_env, "goldfish_tty_write: reading more data than available %d %d\n", s->ptr_len, s->data_count);
-                    pmemcpy(s->ptr, s->data, s->ptr_len);
+                    cpu_memory_rw_debug(cpu_single_env,s->ptr, s->data, s->ptr_len,1);
                     //printf("goldfish_tty_write: read %d bytes to %x\n", s->ptr_len, s->ptr);
                     if(s->data_count > s->ptr_len)
                         memmove(s->data, s->data + s->ptr_len, s->data_count - s->ptr_len);
diff --git a/hw/hw.h b/hw/hw.h
index 06e24cb..89c0ef0 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -8,19 +8,81 @@
 
 /* VM Load/Save */
 
+/* This function writes a chunk of data to a file at the given position.
+ * The pos argument can be ignored if the file is only being used for
+ * streaming.  The handler should try to write all of the data it can.
+ */
+typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
+                                    int64_t pos, int size);
+
+/* Read a chunk of data from a file at the given position.  The pos argument
+ * can be ignored if the file is only be used for streaming.  The number of
+ * bytes actually read should be returned.
+ */
+typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
+                                    int64_t pos, int size);
+
+/* Close a file and return an error code */
+typedef int (QEMUFileCloseFunc)(void *opaque);
+
+/* Called to determine if the file has exceeded it's bandwidth allocation.  The
+ * bandwidth capping is a soft limit, not a hard limit.
+ */
+typedef int (QEMUFileRateLimit)(void *opaque);
+
+/* Called to change the current bandwidth allocation. This function must return
+ * the new actual bandwidth. It should be new_rate if everything goes ok, and
+ * the old rate otherwise
+ */
+typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate);
+
+QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
+                         QEMUFileGetBufferFunc *get_buffer,
+                         QEMUFileCloseFunc *close,
+                         QEMUFileRateLimit *rate_limit,
+                         QEMUFileSetRateLimit *set_rate_limit);
 QEMUFile *qemu_fopen(const char *filename, const char *mode);
+QEMUFile *qemu_fopen_socket(int fd);
+QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
+QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+int qemu_popen_fd(QEMUFile *f);
 void qemu_fflush(QEMUFile *f);
-void qemu_fclose(QEMUFile *f);
+int qemu_fclose(QEMUFile *f);
 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
 void qemu_put_byte(QEMUFile *f, int v);
+
+static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)
+{
+    qemu_put_byte(f, (int)v);
+}
+
+#define qemu_put_sbyte qemu_put_byte
+
 void qemu_put_be16(QEMUFile *f, unsigned int v);
 void qemu_put_be32(QEMUFile *f, unsigned int v);
 void qemu_put_be64(QEMUFile *f, uint64_t v);
 int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
 int qemu_get_byte(QEMUFile *f);
+
+static inline unsigned int qemu_get_ubyte(QEMUFile *f)
+{
+    return (unsigned int)qemu_get_byte(f);
+}
+
+#define qemu_get_sbyte qemu_get_byte
+
 unsigned int qemu_get_be16(QEMUFile *f);
 unsigned int qemu_get_be32(QEMUFile *f);
 uint64_t qemu_get_be64(QEMUFile *f);
+int qemu_file_rate_limit(QEMUFile *f);
+size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate);
+int qemu_file_has_error(QEMUFile *f);
+void qemu_file_set_error(QEMUFile *f);
+
+/* Try to send any outstanding data.  This function is useful when output is
+ * halted due to rate limiting or EAGAIN errors occur as it can be used to
+ * resume output. */
+void qemu_file_put_notify(QEMUFile *f);
 
 static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
 {
@@ -62,17 +124,106 @@
     *pv = qemu_get_byte(f);
 }
 
+// Signed versions for type safety
+static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, int size)
+{
+    qemu_put_buffer(f, (const uint8_t *)buf, size);
+}
+
+static inline void qemu_put_sbe16(QEMUFile *f, int v)
+{
+    qemu_put_be16(f, (unsigned int)v);
+}
+
+static inline void qemu_put_sbe32(QEMUFile *f, int v)
+{
+    qemu_put_be32(f, (unsigned int)v);
+}
+
+static inline void qemu_put_sbe64(QEMUFile *f, int64_t v)
+{
+    qemu_put_be64(f, (uint64_t)v);
+}
+
+static inline size_t qemu_get_sbuffer(QEMUFile *f, int8_t *buf, int size)
+{
+    return qemu_get_buffer(f, (uint8_t *)buf, size);
+}
+
+static inline int qemu_get_sbe16(QEMUFile *f)
+{
+    return (int)qemu_get_be16(f);
+}
+
+static inline int qemu_get_sbe32(QEMUFile *f)
+{
+    return (int)qemu_get_be32(f);
+}
+
+static inline int64_t qemu_get_sbe64(QEMUFile *f)
+{
+    return (int64_t)qemu_get_be64(f);
+}
+
+static inline void qemu_put_s8s(QEMUFile *f, const int8_t *pv)
+{
+    qemu_put_8s(f, (const uint8_t *)pv);
+}
+
+static inline void qemu_put_sbe16s(QEMUFile *f, const int16_t *pv)
+{
+    qemu_put_be16s(f, (const uint16_t *)pv);
+}
+
+static inline void qemu_put_sbe32s(QEMUFile *f, const int32_t *pv)
+{
+    qemu_put_be32s(f, (const uint32_t *)pv);
+}
+
+static inline void qemu_put_sbe64s(QEMUFile *f, const int64_t *pv)
+{
+    qemu_put_be64s(f, (const uint64_t *)pv);
+}
+
+static inline void qemu_get_s8s(QEMUFile *f, int8_t *pv)
+{
+    qemu_get_8s(f, (uint8_t *)pv);
+}
+
+static inline void qemu_get_sbe16s(QEMUFile *f, int16_t *pv)
+{
+    qemu_get_be16s(f, (uint16_t *)pv);
+}
+
+static inline void qemu_get_sbe32s(QEMUFile *f, int32_t *pv)
+{
+    qemu_get_be32s(f, (uint32_t *)pv);
+}
+
+static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv)
+{
+    qemu_get_be64s(f, (uint64_t *)pv);
+}
+
 #ifdef NEED_CPU_H
 #if TARGET_LONG_BITS == 64
 #define qemu_put_betl qemu_put_be64
 #define qemu_get_betl qemu_get_be64
 #define qemu_put_betls qemu_put_be64s
 #define qemu_get_betls qemu_get_be64s
+#define qemu_put_sbetl qemu_put_sbe64
+#define qemu_get_sbetl qemu_get_sbe64
+#define qemu_put_sbetls qemu_put_sbe64s
+#define qemu_get_sbetls qemu_get_sbe64s
 #else
 #define qemu_put_betl qemu_put_be32
 #define qemu_get_betl qemu_get_be32
 #define qemu_put_betls qemu_put_be32s
 #define qemu_get_betls qemu_get_be32s
+#define qemu_put_sbetl qemu_put_sbe32
+#define qemu_get_sbetl qemu_get_sbe32
+#define qemu_put_sbetls qemu_put_sbe32s
+#define qemu_get_sbetls qemu_get_sbe32s
 #endif
 #endif
 
@@ -80,6 +231,7 @@
 int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence);
 
 typedef void SaveStateHandler(QEMUFile *f, void *opaque);
+typedef int SaveLiveStateHandler(QEMUFile *f, int stage, void *opaque);
 typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
 
 int register_savevm(const char *idstr,
@@ -89,22 +241,27 @@
                     LoadStateHandler *load_state,
                     void *opaque);
 
+int register_savevm_live(const char *idstr,
+                         int instance_id,
+                         int version_id,
+                         SaveLiveStateHandler *save_live_state,
+                         SaveStateHandler *save_state,
+                         LoadStateHandler *load_state,
+                         void *opaque);
+
+void unregister_savevm(const char *idstr, void *opaque);
+
 typedef void QEMUResetHandler(void *opaque);
 
-void qemu_register_reset(QEMUResetHandler *func, void *opaque);
+void qemu_register_reset(QEMUResetHandler *func, int order, void *opaque);
 
 /* handler to set the boot_device for a specific type of QEMUMachine */
 /* return 0 if success */
-typedef int QEMUBootSetHandler(const char *boot_device);
-extern QEMUBootSetHandler *qemu_boot_set_handler;
-void qemu_register_boot_set(QEMUBootSetHandler *func);
+typedef int QEMUBootSetHandler(void *opaque, const char *boot_device);
+void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque);
 
 /* These should really be in isa.h, but are here to make pc.h happy.  */
 typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
 typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
 
-
-/* ANDROID: copy memory from the QEMU buffer to simulated virtual space */
-extern void pmemcpy(target_ulong ptr, const char *buf, int size);
-
 #endif
diff --git a/hw/irq.c b/hw/irq.c
index eca707d..7703f62 100644
--- a/hw/irq.c
+++ b/hw/irq.c
@@ -56,6 +56,12 @@
     return s;
 }
 
+void qemu_free_irqs(qemu_irq *s)
+{
+    qemu_free(s[0]);
+    qemu_free(s);
+}
+
 static void qemu_notirq(void *opaque, int line, int level)
 {
     struct IRQState *irq = opaque;
diff --git a/hw/irq.h b/hw/irq.h
index 0880ad2..5daae44 100644
--- a/hw/irq.h
+++ b/hw/irq.h
@@ -27,6 +27,7 @@
 
 /* Returns an array of N IRQs.  */
 qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+void qemu_free_irqs(qemu_irq *s);
 
 /* Returns a new IRQ with opposite polarity.  */
 qemu_irq qemu_irq_invert(qemu_irq irq);
diff --git a/hw/isa.h b/hw/isa.h
index 222e4f3..a8c1a56 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -19,7 +19,6 @@
 void DMA_hold_DREQ (int nchan);
 void DMA_release_DREQ (int nchan);
 void DMA_schedule(int nchan);
-void DMA_run (void);
 void DMA_init (int high_page_enable);
 void DMA_register_channel (int nchan,
                            DMA_transfer_handler transfer_handler,
diff --git a/hw/msmouse.c b/hw/msmouse.c
new file mode 100644
index 0000000..69356a5
--- /dev/null
+++ b/hw/msmouse.c
@@ -0,0 +1,78 @@
+/*
+ * QEMU Microsoft serial mouse emulation
+ *
+ * Copyright (c) 2008 Lubomir Rintel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <stdlib.h>
+#include "../qemu-common.h"
+#include "../qemu-char.h"
+#include "../console.h"
+#include "msmouse.h"
+
+#define MSMOUSE_LO6(n) ((n) & 0x3f)
+#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
+
+static void msmouse_event(void *opaque,
+                          int dx, int dy, int dz, int buttons_state)
+{
+    CharDriverState *chr = (CharDriverState *)opaque;
+
+    unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 };
+
+    /* Movement deltas */
+    bytes[0] |= (MSMOUSE_HI2(dy) << 2) | MSMOUSE_HI2(dx);
+    bytes[1] |= MSMOUSE_LO6(dx);
+    bytes[2] |= MSMOUSE_LO6(dy);
+
+    /* Buttons */
+    bytes[0] |= (buttons_state & 0x01 ? 0x20 : 0x00);
+    bytes[0] |= (buttons_state & 0x02 ? 0x10 : 0x00);
+    bytes[3] |= (buttons_state & 0x04 ? 0x20 : 0x00);
+
+    /* We always send the packet of, so that we do not have to keep track
+       of previous state of the middle button. This can potentially confuse
+       some very old drivers for two button mice though. */
+    qemu_chr_read(chr, bytes, 4);
+}
+
+static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
+{
+    /* Ignore writes to mouse port */
+    return len;
+}
+
+static void msmouse_chr_close (struct CharDriverState *chr)
+{
+    qemu_free (chr);
+}
+
+CharDriverState *qemu_chr_open_msmouse(void)
+{
+    CharDriverState *chr;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->chr_write = msmouse_chr_write;
+    chr->chr_close = msmouse_chr_close;
+
+    qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse");
+
+    return chr;
+}
diff --git a/hw/msmouse.h b/hw/msmouse.h
new file mode 100644
index 0000000..947afd9
--- /dev/null
+++ b/hw/msmouse.h
@@ -0,0 +1,2 @@
+/* msmouse.c */
+CharDriverState *qemu_chr_open_msmouse(void);
diff --git a/hw/pc.h b/hw/pc.h
index 2862849..0afffa2 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -1,5 +1,8 @@
 #ifndef HW_PC_H
 #define HW_PC_H
+
+#include "qemu-common.h"
+
 /* PC-style peripherals (also used by other machines).  */
 
 /* serial.c */
@@ -34,18 +37,23 @@
 int pic_read_irq(PicState2 *s);
 void pic_update_irq(PicState2 *s);
 uint32_t pic_intack_read(PicState2 *s);
-void pic_info(void);
-void irq_info(void);
+void pic_info(Monitor *mon);
+void irq_info(Monitor *mon);
 
 /* APIC */
 typedef struct IOAPICState IOAPICState;
-
+void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
+                             uint8_t delivery_mode,
+                             uint8_t vector_num, uint8_t polarity,
+                             uint8_t trigger_mode);
 int apic_init(CPUState *env);
 int apic_accept_pic_intr(CPUState *env);
 void apic_deliver_pic_intr(CPUState *env, int level);
 int apic_get_interrupt(CPUState *env);
 IOAPICState *ioapic_init(void);
 void ioapic_set_irq(void *opaque, int vector, int level);
+void apic_reset_irq_delivered(void);
+int apic_get_irq_delivered(void);
 
 /* i8254.c */
 
@@ -60,6 +68,9 @@
 int pit_get_mode(PITState *pit, int channel);
 int pit_get_out(PITState *pit, int channel, int64_t current_time);
 
+void hpet_pit_disable(void);
+void hpet_pit_enable(void);
+
 /* vmport.c */
 void vmport_init(void);
 void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque);
@@ -71,16 +82,20 @@
 
 void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base);
 void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
-                   target_phys_addr_t base, int it_shift);
+                   target_phys_addr_t base, ram_addr_t size,
+                   target_phys_addr_t mask);
 
 /* mc146818rtc.c */
 
 typedef struct RTCState RTCState;
 
-RTCState *rtc_init(int base, qemu_irq irq);
-RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq);
+RTCState *rtc_init(int base, qemu_irq irq, int base_year);
+RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year);
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
+                      int base_year);
 void rtc_set_memory(RTCState *s, int addr, int val);
 void rtc_set_date(RTCState *s, const struct tm *tm);
+void cmos_set_s3_resume(void);
 
 /* pc.c */
 extern int fd_bootchk;
@@ -90,14 +105,21 @@
 
 /* acpi.c */
 extern int acpi_enabled;
+extern char *acpi_tables;
+extern size_t acpi_tables_len;
+
 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                        qemu_irq sci_irq);
 void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 void acpi_bios_init(void);
+int acpi_table_add(const char *table_desc);
+
+/* hpet.c */
+extern int no_hpet;
 
 /* pcspk.c */
 void pcspk_init(PITState *);
-int pcspk_audio_init(AudioState *, qemu_irq *pic);
+int pcspk_audio_init(qemu_irq *pic);
 
 /* piix_pci.c */
 PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic);
@@ -105,31 +127,26 @@
 int piix3_init(PCIBus *bus, int devfn);
 void i440fx_init_memory_mappings(PCIDevice *d);
 
+extern PCIDevice *piix4_dev;
 int piix4_init(PCIBus *bus, int devfn);
 
 /* vga.c */
+enum vga_retrace_method {
+    VGA_RETRACE_DUMB,
+    VGA_RETRACE_PRECISE
+};
 
-#ifndef TARGET_SPARC
-#define VGA_RAM_SIZE (8192 * 1024)
-#else
-#define VGA_RAM_SIZE (9 * 1024 * 1024)
-#endif
+extern enum vga_retrace_method vga_retrace_method;
 
-int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
-                 unsigned long vga_ram_offset, int vga_ram_size);
-int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
-                 unsigned long vga_ram_offset, int vga_ram_size,
+int isa_vga_init(void);
+int pci_vga_init(PCIBus *bus,
                  unsigned long vga_bios_offset, int vga_bios_size);
-int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
-                    unsigned long vga_ram_offset, int vga_ram_size,
-                    target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
-                    int it_shift);
+int isa_vga_mm_init(target_phys_addr_t vram_base,
+                    target_phys_addr_t ctrl_base, int it_shift);
 
 /* cirrus_vga.c */
-void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
-                         unsigned long vga_ram_offset, int vga_ram_size);
-void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
-                         unsigned long vga_ram_offset, int vga_ram_size);
+void pci_cirrus_vga_init(PCIBus *bus);
+void isa_cirrus_vga_init(void);
 
 /* ide.c */
 void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
@@ -145,4 +162,5 @@
 
 void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd);
 
+int cpu_is_bsp(CPUState *env);
 #endif
diff --git a/hw/pci.c b/hw/pci.c
index 5f7004a..0a738db 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -23,12 +23,14 @@
  */
 #include "hw.h"
 #include "pci.h"
-#include "console.h"
+#include "monitor.h"
 #include "net.h"
+#include "sysemu.h"
 
 //#define DEBUG_PCI
 
 struct PCIBus {
+    BusState qbus;
     int bus_num;
     int devfn_min;
     pci_set_irq_fn set_irq;
@@ -50,7 +52,8 @@
 static void pci_set_irq(void *opaque, int irq_num, int level);
 
 target_phys_addr_t pci_mem_base;
-static int pci_irq_index;
+static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
+static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
 static PCIBus *first_bus;
 
 static void pcibus_save(QEMUFile *f, void *opaque)
@@ -84,18 +87,22 @@
     return 0;
 }
 
-PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+PCIBus *pci_register_bus(DeviceState *parent, const char *name,
+                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          qemu_irq *pic, int devfn_min, int nirq)
 {
     PCIBus *bus;
     static int nbus = 0;
 
-    bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
+    bus = FROM_QBUS(PCIBus, qbus_create(BUS_TYPE_PCI,
+                                        sizeof(PCIBus) + (nirq * sizeof(int)),
+                                        parent, name));
     bus->set_irq = set_irq;
     bus->map_irq = map_irq;
     bus->irq_opaque = pic;
     bus->devfn_min = devfn_min;
     bus->nirq = nirq;
+    bus->next = first_bus;
     first_bus = bus;
     register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus);
     return bus;
@@ -145,17 +152,98 @@
     return 0;
 }
 
-/* -1 for devfn means auto assign */
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
-                               int instance_size, int devfn,
-                               PCIConfigReadFunc *config_read,
-                               PCIConfigWriteFunc *config_write)
+static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
 {
-    PCIDevice *pci_dev;
+    uint16_t *id;
 
-    if (pci_irq_index >= PCI_DEVICES_MAX)
-        return NULL;
+    id = (void*)(&pci_dev->config[PCI_SUBVENDOR_ID]);
+    id[0] = cpu_to_le16(pci_default_sub_vendor_id);
+    id[1] = cpu_to_le16(pci_default_sub_device_id);
+    return 0;
+}
 
+/*
+ * Parse [[<domain>:]<bus>:]<slot>, return -1 on error
+ */
+static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
+{
+    const char *p;
+    char *e;
+    unsigned long val;
+    unsigned long dom = 0, bus = 0;
+    unsigned slot = 0;
+
+    p = addr;
+    val = strtoul(p, &e, 16);
+    if (e == p)
+	return -1;
+    if (*e == ':') {
+	bus = val;
+	p = e + 1;
+	val = strtoul(p, &e, 16);
+	if (e == p)
+	    return -1;
+	if (*e == ':') {
+	    dom = bus;
+	    bus = val;
+	    p = e + 1;
+	    val = strtoul(p, &e, 16);
+	    if (e == p)
+		return -1;
+	}
+    }
+
+    if (dom > 0xffff || bus > 0xff || val > 0x1f)
+	return -1;
+
+    slot = val;
+
+    if (*e)
+	return -1;
+
+    /* Note: QEMU doesn't implement domains other than 0 */
+    if (dom != 0 || pci_find_bus(bus) == NULL)
+	return -1;
+
+    *domp = dom;
+    *busp = bus;
+    *slotp = slot;
+    return 0;
+}
+
+int pci_read_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
+{
+    char devaddr[32];
+
+    if (!get_param_value(devaddr, sizeof(devaddr), "pci_addr", addr))
+        return -1;
+
+    return pci_parse_devaddr(devaddr, domp, busp, slotp);
+}
+
+int pci_assign_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
+{
+    char devaddr[32];
+
+    if (!get_param_value(devaddr, sizeof(devaddr), "pci_addr", addr))
+	return -1;
+
+    if (!strcmp(devaddr, "auto")) {
+        *domp = *busp = 0;
+        *slotp = -1;
+        /* want to support dom/bus auto-assign at some point */
+        return 0;
+    }
+
+    return pci_parse_devaddr(devaddr, domp, busp, slotp);
+}
+
+/* -1 for devfn means auto assign */
+static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
+                                         const char *name, int devfn,
+                                         PCIConfigReadFunc *config_read,
+                                         PCIConfigWriteFunc *config_write)
+{
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) {
             if (!bus->devices[devfn])
@@ -164,13 +252,11 @@
         return NULL;
     found: ;
     }
-    pci_dev = qemu_mallocz(instance_size);
-    if (!pci_dev)
-        return NULL;
     pci_dev->bus = bus;
     pci_dev->devfn = devfn;
     pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
     memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
+    pci_set_default_subsystem_id(pci_dev);
 
     if (!config_read)
         config_read = pci_default_read_config;
@@ -178,13 +264,65 @@
         config_write = pci_default_write_config;
     pci_dev->config_read = config_read;
     pci_dev->config_write = config_write;
-    pci_dev->irq_index = pci_irq_index++;
     bus->devices[devfn] = pci_dev;
     pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4);
     return pci_dev;
 }
 
-void pci_register_io_region(PCIDevice *pci_dev, int region_num,
+PCIDevice *pci_register_device(PCIBus *bus, const char *name,
+                               int instance_size, int devfn,
+                               PCIConfigReadFunc *config_read,
+                               PCIConfigWriteFunc *config_write)
+{
+    PCIDevice *pci_dev;
+
+    pci_dev = qemu_mallocz(instance_size);
+    pci_dev = do_pci_register_device(pci_dev, bus, name, devfn,
+                                     config_read, config_write);
+    return pci_dev;
+}
+static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
+{
+    return addr + pci_mem_base;
+}
+
+static void pci_unregister_io_regions(PCIDevice *pci_dev)
+{
+    PCIIORegion *r;
+    int i;
+
+    for(i = 0; i < PCI_NUM_REGIONS; i++) {
+        r = &pci_dev->io_regions[i];
+        if (!r->size || r->addr == -1)
+            continue;
+        if (r->type == PCI_ADDRESS_SPACE_IO) {
+            isa_unassign_ioport(r->addr, r->size);
+        } else {
+            cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
+                                                     r->size,
+                                                     IO_MEM_UNASSIGNED);
+        }
+    }
+}
+
+int pci_unregister_device(PCIDevice *pci_dev)
+{
+    int ret = 0;
+
+    if (pci_dev->unregister)
+        ret = pci_dev->unregister(pci_dev);
+    if (ret)
+        return ret;
+
+    pci_unregister_io_regions(pci_dev);
+
+    qemu_free_irqs(pci_dev->irq);
+    pci_dev->bus->devices[pci_dev->devfn] = NULL;
+    qdev_free(&pci_dev->qdev);
+    return 0;
+}
+
+void pci_register_bar(PCIDevice *pci_dev, int region_num,
                             uint32_t size, int type,
                             PCIMapIORegionFunc *map_func)
 {
@@ -193,6 +331,13 @@
 
     if ((unsigned int)region_num >= PCI_NUM_REGIONS)
         return;
+
+    if (size & (size-1)) {
+        fprintf(stderr, "ERROR: PCI region size must be pow2 "
+                    "type=0x%x, size=0x%x\n", type, size);
+        exit(1);
+    }
+
     r = &pci_dev->io_regions[region_num];
     r->addr = -1;
     r->size = size;
@@ -206,11 +351,6 @@
     *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type);
 }
 
-static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
-{
-    return addr + pci_mem_base;
-}
-
 static void pci_update_mappings(PCIDevice *d)
 {
     PCIIORegion *r;
@@ -279,6 +419,7 @@
                         cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
                                                      r->size,
                                                      IO_MEM_UNASSIGNED);
+                        qemu_unregister_coalesced_mmio(r->addr, r->size);
                     }
                 }
                 r->addr = new_addr;
@@ -360,12 +501,15 @@
             case 0x01:
             case 0x02:
             case 0x03:
+            case 0x06:
+            case 0x07:
             case 0x08:
             case 0x09:
             case 0x0a:
             case 0x0b:
             case 0x0e:
             case 0x10 ... 0x27: /* base */
+            case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
             case 0x30 ... 0x33: /* rom */
             case 0x3d:
                 can_write = 0;
@@ -382,11 +526,14 @@
             case 0x01:
             case 0x02:
             case 0x03:
+            case 0x06:
+            case 0x07:
             case 0x08:
             case 0x09:
             case 0x0a:
             case 0x0b:
             case 0x0e:
+            case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
             case 0x38 ... 0x3b: /* rom */
             case 0x3d:
                 can_write = 0;
@@ -398,6 +545,18 @@
             break;
         }
         if (can_write) {
+            /* Mask out writes to reserved bits in registers */
+            switch (addr) {
+	    case 0x05:
+                val &= ~PCI_COMMAND_RESERVED_MASK_HI;
+                break;
+            case 0x06:
+                val &= ~PCI_STATUS_RESERVED_MASK_LO;
+                break;
+            case 0x07:
+                val &= ~PCI_STATUS_RESERVED_MASK_HI;
+                break;
+            }
             d->config[addr] = val;
         }
         if (++addr > 0xff)
@@ -515,7 +674,7 @@
     const char *desc;
 } pci_class_desc;
 
-static pci_class_desc pci_class_descriptions[] =
+static const pci_class_desc pci_class_descriptions[] =
 {
     { 0x0100, "SCSI controller"},
     { 0x0101, "IDE controller"},
@@ -557,42 +716,44 @@
 
 static void pci_info_device(PCIDevice *d)
 {
+    Monitor *mon = cur_mon;
     int i, class;
     PCIIORegion *r;
-    pci_class_desc *desc;
+    const pci_class_desc *desc;
 
-    term_printf("  Bus %2d, device %3d, function %d:\n",
-           d->bus->bus_num, d->devfn >> 3, d->devfn & 7);
+    monitor_printf(mon, "  Bus %2d, device %3d, function %d:\n",
+                   d->bus->bus_num, d->devfn >> 3, d->devfn & 7);
     class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE)));
-    term_printf("    ");
+    monitor_printf(mon, "    ");
     desc = pci_class_descriptions;
     while (desc->desc && class != desc->class)
         desc++;
     if (desc->desc) {
-        term_printf("%s", desc->desc);
+        monitor_printf(mon, "%s", desc->desc);
     } else {
-        term_printf("Class %04x", class);
+        monitor_printf(mon, "Class %04x", class);
     }
-    term_printf(": PCI device %04x:%04x\n",
+    monitor_printf(mon, ": PCI device %04x:%04x\n",
            le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))),
            le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID))));
 
     if (d->config[PCI_INTERRUPT_PIN] != 0) {
-        term_printf("      IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]);
+        monitor_printf(mon, "      IRQ %d.\n",
+                       d->config[PCI_INTERRUPT_LINE]);
     }
     if (class == 0x0604) {
-        term_printf("      BUS %d.\n", d->config[0x19]);
+        monitor_printf(mon, "      BUS %d.\n", d->config[0x19]);
     }
     for(i = 0;i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
         if (r->size != 0) {
-            term_printf("      BAR%d: ", i);
+            monitor_printf(mon, "      BAR%d: ", i);
             if (r->type & PCI_ADDRESS_SPACE_IO) {
-                term_printf("I/O at 0x%04x [0x%04x].\n",
-                       r->addr, r->addr + r->size - 1);
+                monitor_printf(mon, "I/O at 0x%04x [0x%04x].\n",
+                               r->addr, r->addr + r->size - 1);
             } else {
-                term_printf("32 bit memory at 0x%08x [0x%08x].\n",
-                       r->addr, r->addr + r->size - 1);
+                monitor_printf(mon, "32 bit memory at 0x%08x [0x%08x].\n",
+                               r->addr, r->addr + r->size - 1);
             }
         }
     }
@@ -618,38 +779,56 @@
     }
 }
 
-void pci_info(void)
+void pci_info(Monitor *mon)
 {
     pci_for_each_device(0, pci_info_device);
 }
 
+static const char * const pci_nic_models[] = {
+    "ne2k_pci",
+    "i82551",
+    "i82557b",
+    "i82559er",
+    "rtl8139",
+    "e1000",
+    "pcnet",
+    "virtio",
+    NULL
+};
+
+static const char * const pci_nic_names[] = {
+    "ne2k_pci",
+    "i82551",
+    "i82557b",
+    "i82559er",
+    "rtl8139",
+    "e1000",
+    "pcnet",
+    "virtio-net-pci",
+    NULL
+};
+
 /* Initialize a PCI NIC.  */
-void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn)
+PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
+                  const char *default_model)
 {
-#if 0
-    if (strcmp(nd->model, "ne2k_pci") == 0) {
-        pci_ne2000_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82551") == 0) {
-        pci_i82551_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82557b") == 0) {
-        pci_i82557b_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "i82559er") == 0) {
-        pci_i82559er_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "rtl8139") == 0) {
-        pci_rtl8139_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "e1000") == 0) {
-        pci_e1000_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "pcnet") == 0) {
-        pci_pcnet_init(bus, nd, devfn);
-    } else if (strcmp(nd->model, "?") == 0) {
-        fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
-                        " ne2k_pci pcnet rtl8139 e1000\n");
-        exit (1);
-    } else {
-        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
-        exit (1);
+    DeviceState *dev;
+    int i;
+
+    qemu_check_nic_model_list(nd, pci_nic_models, default_model);
+
+    for (i = 0; pci_nic_models[i]; i++) {
+        if (strcmp(nd->model, pci_nic_models[i]) == 0) {
+            dev = qdev_create(&bus->qbus, pci_nic_names[i]);
+            qdev_set_prop_int(dev, "devfn", devfn);
+            qdev_set_netdev(dev, nd);
+            qdev_init(dev);
+            nd->private = dev;
+            return (PCIDevice *)dev;
+        }
     }
-#endif
+
+    return NULL;
 }
 
 typedef struct {
@@ -674,28 +853,93 @@
     pci_default_write_config(d, address, val, len);
 }
 
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
+PCIBus *pci_find_bus(int bus_num)
+{
+    PCIBus *bus = first_bus;
+
+    while (bus && bus->bus_num != bus_num)
+        bus = bus->next;
+
+    return bus;
+}
+
+PCIDevice *pci_find_device(int bus_num, int slot, int function)
+{
+    PCIBus *bus = pci_find_bus(bus_num);
+
+    if (!bus)
+        return NULL;
+
+    return bus->devices[PCI_DEVFN(slot, function)];
+}
+
+PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
                         pci_map_irq_fn map_irq, const char *name)
 {
     PCIBridge *s;
     s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
                                          devfn, NULL, pci_bridge_write_config);
-    s->dev.config[0x00] = id >> 16;
-    s->dev.config[0x01] = id >> 24;
-    s->dev.config[0x02] = id; // device_id
-    s->dev.config[0x03] = id >> 8;
+
+    pci_config_set_vendor_id(s->dev.config, vid);
+    pci_config_set_device_id(s->dev.config, did);
+
     s->dev.config[0x04] = 0x06; // command = bus master, pci mem
     s->dev.config[0x05] = 0x00;
     s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
     s->dev.config[0x07] = 0x00; // status = fast devsel
     s->dev.config[0x08] = 0x00; // revision
     s->dev.config[0x09] = 0x00; // programming i/f
-    s->dev.config[0x0A] = 0x04; // class_sub = PCI to PCI bridge
-    s->dev.config[0x0B] = 0x06; // class_base = PCI_bridge
+    pci_config_set_class(s->dev.config, PCI_CLASS_BRIDGE_PCI);
     s->dev.config[0x0D] = 0x10; // latency_timer
-    s->dev.config[0x0E] = 0x81; // header_type
+    s->dev.config[PCI_HEADER_TYPE] =
+        PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE; // header_type
     s->dev.config[0x1E] = 0xa0; // secondary status
 
     s->bus = pci_register_secondary_bus(&s->dev, map_irq);
     return s->bus;
 }
+
+typedef struct {
+    DeviceInfo qdev;
+    pci_qdev_initfn init;
+} PCIDeviceInfo;
+
+static void pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
+{
+    PCIDevice *pci_dev = (PCIDevice *)qdev;
+    PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
+    PCIBus *bus;
+    int devfn;
+
+    bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
+    devfn = qdev_get_prop_int(qdev, "devfn", -1);
+    pci_dev = do_pci_register_device(pci_dev, bus, "FIXME", devfn,
+                                     NULL, NULL);//FIXME:config_read, config_write);
+    assert(pci_dev);
+    info->init(pci_dev);
+}
+
+void pci_qdev_register(const char *name, int size, pci_qdev_initfn init)
+{
+    PCIDeviceInfo *info;
+
+    info = qemu_mallocz(sizeof(*info));
+    info->qdev.name = qemu_strdup(name);
+    info->qdev.size = size;
+    info->init = init;
+    info->qdev.init = pci_qdev_init;
+    info->qdev.bus_type = BUS_TYPE_PCI;
+
+    qdev_register(&info->qdev);
+}
+
+PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->qbus, name);
+    qdev_set_prop_int(dev, "devfn", devfn);
+    qdev_init(dev);
+
+    return (PCIDevice *)dev;
+}
diff --git a/hw/pci.h b/hw/pci.h
index e870987..fcca526 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -1,6 +1,10 @@
 #ifndef QEMU_PCI_H
 #define QEMU_PCI_H
 
+#include "qemu-common.h"
+
+#include "qdev.h"
+
 /* PCI includes legacy ISA access.  */
 #include "isa.h"
 
@@ -8,12 +12,71 @@
 
 extern target_phys_addr_t pci_mem_base;
 
+#define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn)         ((devfn) & 0x07)
+
+/* Class, Vendor and Device IDs from Linux's pci_ids.h */
+#include "pci_ids.h"
+
+/* QEMU-specific Vendor and Device ID definitions */
+
+/* IBM (0x1014) */
+#define PCI_DEVICE_ID_IBM_440GX          0x027f
+#define PCI_DEVICE_ID_IBM_OPENPIC2       0xffff
+
+/* Hitachi (0x1054) */
+#define PCI_VENDOR_ID_HITACHI            0x1054
+#define PCI_DEVICE_ID_HITACHI_SH7751R    0x350e
+
+/* Apple (0x106b) */
+#define PCI_DEVICE_ID_APPLE_343S1201     0x0010
+#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI  0x001e
+#define PCI_DEVICE_ID_APPLE_UNI_N_PCI    0x001f
+#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL   0x0022
+#define PCI_DEVICE_ID_APPLE_IPID_USB     0x003f
+
+/* Realtek (0x10ec) */
+#define PCI_DEVICE_ID_REALTEK_8029       0x8029
+
+/* Xilinx (0x10ee) */
+#define PCI_DEVICE_ID_XILINX_XC2VP30     0x0300
+
+/* Marvell (0x11ab) */
+#define PCI_DEVICE_ID_MARVELL_GT6412X    0x4620
+
+/* QEMU/Bochs VGA (0x1234) */
+#define PCI_VENDOR_ID_QEMU               0x1234
+#define PCI_DEVICE_ID_QEMU_VGA           0x1111
+
+/* VMWare (0x15ad) */
+#define PCI_VENDOR_ID_VMWARE             0x15ad
+#define PCI_DEVICE_ID_VMWARE_SVGA2       0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA        0x0710
+#define PCI_DEVICE_ID_VMWARE_NET         0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI        0x0730
+#define PCI_DEVICE_ID_VMWARE_IDE         0x1729
+
+/* Intel (0x8086) */
+#define PCI_DEVICE_ID_INTEL_82551IT      0x1209
+
+/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
+#define PCI_VENDOR_ID_REDHAT_QUMRANET    0x1af4
+#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_SUBDEVICE_ID_QEMU            0x1100
+
+#define PCI_DEVICE_ID_VIRTIO_NET         0x1000
+#define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
+#define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
+#define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
+
 typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
                                 uint32_t address, uint32_t data, int len);
 typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
                                    uint32_t address, int len);
 typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
                                 uint32_t addr, uint32_t size, int type);
+typedef int PCIUnregisterFunc(PCIDevice *pci_dev);
 
 #define PCI_ADDRESS_SPACE_MEM		0x00
 #define PCI_ADDRESS_SPACE_IO		0x01
@@ -29,20 +92,53 @@
 #define PCI_ROM_SLOT 6
 #define PCI_NUM_REGIONS 7
 
-#define PCI_DEVICES_MAX 64
-
+/* Declarations from linux/pci_regs.h */
 #define PCI_VENDOR_ID		0x00	/* 16 bits */
 #define PCI_DEVICE_ID		0x02	/* 16 bits */
 #define PCI_COMMAND		0x04	/* 16 bits */
 #define  PCI_COMMAND_IO		0x1	/* Enable response in I/O space */
 #define  PCI_COMMAND_MEMORY	0x2	/* Enable response in Memory space */
+#define PCI_STATUS              0x06    /* 16 bits */
+#define PCI_REVISION_ID         0x08    /* 8 bits  */
 #define PCI_CLASS_DEVICE        0x0a    /* Device class */
+#define PCI_HEADER_TYPE         0x0e    /* 8 bits */
+#define  PCI_HEADER_TYPE_NORMAL		0
+#define  PCI_HEADER_TYPE_BRIDGE		1
+#define  PCI_HEADER_TYPE_CARDBUS	2
+#define  PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2c    /* 16 bits */
+#define PCI_SUBSYSTEM_ID        0x2e    /* 16 bits */
 #define PCI_INTERRUPT_LINE	0x3c	/* 8 bits */
 #define PCI_INTERRUPT_PIN	0x3d	/* 8 bits */
 #define PCI_MIN_GNT		0x3e	/* 8 bits */
 #define PCI_MAX_LAT		0x3f	/* 8 bits */
 
+#define PCI_REVISION            0x08    /* obsolete, use PCI_REVISION_ID */
+#define PCI_SUBVENDOR_ID        0x2c    /* obsolete, use PCI_SUBSYSTEM_VENDOR_ID */
+#define PCI_SUBDEVICE_ID        0x2e    /* obsolete, use PCI_SUBSYSTEM_ID */
+
+/* Bits in the PCI Status Register (PCI 2.3 spec) */
+#define PCI_STATUS_RESERVED1	0x007
+#define PCI_STATUS_INT_STATUS	0x008
+#define PCI_STATUS_CAPABILITIES	0x010
+#define PCI_STATUS_66MHZ	0x020
+#define PCI_STATUS_RESERVED2	0x040
+#define PCI_STATUS_FAST_BACK	0x080
+#define PCI_STATUS_DEVSEL	0x600
+
+#define PCI_STATUS_RESERVED_MASK_LO (PCI_STATUS_RESERVED1 | \
+                PCI_STATUS_INT_STATUS | PCI_STATUS_CAPABILITIES | \
+                PCI_STATUS_66MHZ | PCI_STATUS_RESERVED2 | PCI_STATUS_FAST_BACK)
+
+#define PCI_STATUS_RESERVED_MASK_HI (PCI_STATUS_DEVSEL >> 8)
+
+/* Bits in the PCI Command Register (PCI 2.3 spec) */
+#define PCI_COMMAND_RESERVED	0xf800
+
+#define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8)
+
 struct PCIDevice {
+    DeviceState qdev;
     /* PCI config space */
     uint8_t config[256];
 
@@ -55,8 +151,7 @@
     /* do not access the following fields */
     PCIConfigReadFunc *config_read;
     PCIConfigWriteFunc *config_write;
-    /* ??? This is a PC-specific hack, and should be removed.  */
-    int irq_index;
+    PCIUnregisterFunc *unregister;
 
     /* IRQ objects for the INTA-INTD pins.  */
     qemu_irq *irq;
@@ -69,8 +164,9 @@
                                int instance_size, int devfn,
                                PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write);
+int pci_unregister_device(PCIDevice *pci_dev);
 
-void pci_register_io_region(PCIDevice *pci_dev, int region_num,
+void pci_register_bar(PCIDevice *pci_dev, int region_num,
                             uint32_t size, int type,
                             PCIMapIORegionFunc *map_func);
 
@@ -83,27 +179,55 @@
 
 typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
-PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+PCIBus *pci_register_bus(DeviceState *parent, const char *name,
+                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          qemu_irq *pic, int devfn_min, int nirq);
 
-void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn);
+PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
+                  const char *default_model);
 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
 uint32_t pci_data_read(void *opaque, uint32_t addr, int len);
 int pci_bus_num(PCIBus *s);
 void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d));
+PCIBus *pci_find_bus(int bus_num);
+PCIDevice *pci_find_device(int bus_num, int slot, int function);
 
-void pci_info(void);
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
+int pci_read_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp);
+int pci_assign_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp);
+
+void pci_info(Monitor *mon);
+PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
                         pci_map_irq_fn map_irq, const char *name);
 
+static inline void
+pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
+{
+    cpu_to_le16wu((uint16_t *)&pci_config[PCI_VENDOR_ID], val);
+}
+
+static inline void
+pci_config_set_device_id(uint8_t *pci_config, uint16_t val)
+{
+    cpu_to_le16wu((uint16_t *)&pci_config[PCI_DEVICE_ID], val);
+}
+
+static inline void
+pci_config_set_class(uint8_t *pci_config, uint16_t val)
+{
+    cpu_to_le16wu((uint16_t *)&pci_config[PCI_CLASS_DEVICE], val);
+}
+
+typedef void (*pci_qdev_initfn)(PCIDevice *dev);
+void pci_qdev_register(const char *name, int size, pci_qdev_initfn init);
+
+PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
+
 /* lsi53c895a.c */
 #define LSI_MAX_DEVS 7
-void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id);
-void *lsi_scsi_init(PCIBus *bus, int devfn);
+void lsi_scsi_attach(DeviceState *host, BlockDriverState *bd, int id);
 
 /* vmware_vga.c */
-void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
-                     unsigned long vga_ram_offset, int vga_ram_size);
+void pci_vmsvga_init(PCIBus *bus);
 
 /* usb-uhci.c */
 void usb_uhci_piix3_init(PCIBus *bus, int devfn);
@@ -112,31 +236,16 @@
 /* usb-ohci.c */
 void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn);
 
-/* eepro100.c */
-
-void pci_i82551_init(PCIBus *bus, NICInfo *nd, int devfn);
-void pci_i82557b_init(PCIBus *bus, NICInfo *nd, int devfn);
-void pci_i82559er_init(PCIBus *bus, NICInfo *nd, int devfn);
-
-/* ne2000.c */
-
-void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn);
-
-/* rtl8139.c */
-
-void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn);
-
-/* e1000.c */
-void pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn);
-
-/* pcnet.c */
-void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn);
-
 /* prep_pci.c */
 PCIBus *pci_prep_init(qemu_irq *pic);
 
 /* apb_pci.c */
-PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base,
-                     qemu_irq *pic);
+PCIBus *pci_apb_init(target_phys_addr_t special_base,
+                     target_phys_addr_t mem_base,
+                     qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
+
+/* sh_pci.c */
+PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                            qemu_irq *pic, int devfn_min, int nirq);
 
 #endif
diff --git a/hw/pci_host.h b/hw/pci_host.h
index 49a0c59..757b0e2 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -25,6 +25,16 @@
 /* Worker routines for a PCI host controller that uses an {address,data}
    register pair to access PCI configuration space.  */
 
+/* debug PCI */
+//#define DEBUG_PCI
+
+#ifdef DEBUG_PCI
+#define PCI_DPRINTF(fmt, ...) \
+do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define PCI_DPRINTF(fmt, ...)
+#endif
+
 typedef struct {
     uint32_t config_reg;
     PCIBus *bus;
@@ -33,6 +43,9 @@
 static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val)
 {
     PCIHostState *s = opaque;
+
+    PCI_DPRINTF("writeb addr " TARGET_FMT_plx " val %x\n",
+                (target_phys_addr_t)addr, val);
     if (s->config_reg & (1u << 31))
         pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
 }
@@ -43,6 +56,8 @@
 #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap16(val);
 #endif
+    PCI_DPRINTF("writew addr " TARGET_FMT_plx " val %x\n",
+                (target_phys_addr_t)addr, val);
     if (s->config_reg & (1u << 31))
         pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
 }
@@ -53,6 +68,8 @@
 #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap32(val);
 #endif
+    PCI_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n",
+                (target_phys_addr_t)addr, val);
     if (s->config_reg & (1u << 31))
         pci_data_write(s->bus, s->config_reg, val, 4);
 }
@@ -60,9 +77,14 @@
 static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr)
 {
     PCIHostState *s = opaque;
+    uint32_t val;
+
     if (!(s->config_reg & (1 << 31)))
         return 0xff;
-    return pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
+    val = pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
+    PCI_DPRINTF("readb addr " TARGET_FMT_plx " val %x\n",
+                (target_phys_addr_t)addr, val);
+    return val;
 }
 
 static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr)
@@ -72,6 +94,8 @@
     if (!(s->config_reg & (1 << 31)))
         return 0xffff;
     val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
+    PCI_DPRINTF("readw addr " TARGET_FMT_plx " val %x\n",
+                (target_phys_addr_t)addr, val);
 #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap16(val);
 #endif
@@ -85,9 +109,10 @@
     if (!(s->config_reg & (1 << 31)))
         return 0xffffffff;
     val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
+    PCI_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n",
+                (target_phys_addr_t)addr, val);
 #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap32(val);
 #endif
     return val;
 }
-
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
new file mode 100644
index 0000000..3afe674
--- /dev/null
+++ b/hw/pci_ids.h
@@ -0,0 +1,97 @@
+/*
+ *      PCI Class, Vendor and Device IDs
+ *
+ *      Please keep sorted.
+ *
+ *      Abbreviated version of linux/pci_ids.h
+ *
+ *      QEMU-specific definitions belong in pci.h
+ */
+
+/* Device classes and subclasses */
+
+#define PCI_BASE_CLASS_STORAGE           0x01
+#define PCI_BASE_CLASS_NETWORK           0x02
+
+#define PCI_CLASS_STORAGE_SCSI           0x0100
+#define PCI_CLASS_STORAGE_IDE            0x0101
+#define PCI_CLASS_STORAGE_OTHER          0x0180
+
+#define PCI_CLASS_NETWORK_ETHERNET       0x0200
+
+#define PCI_CLASS_DISPLAY_VGA            0x0300
+#define PCI_CLASS_DISPLAY_OTHER          0x0380
+
+#define PCI_CLASS_MULTIMEDIA_AUDIO       0x0401
+
+#define PCI_CLASS_MEMORY_RAM             0x0500
+
+#define PCI_CLASS_SYSTEM_OTHER           0x0880
+
+#define PCI_CLASS_SERIAL_USB             0x0c03
+
+#define PCI_CLASS_BRIDGE_HOST            0x0600
+#define PCI_CLASS_BRIDGE_ISA             0x0601
+#define PCI_CLASS_BRIDGE_PCI             0x0604
+#define PCI_CLASS_BRIDGE_OTHER           0x0680
+
+#define PCI_CLASS_COMMUNICATION_OTHER    0x0780
+
+#define PCI_CLASS_PROCESSOR_CO           0x0b40
+#define PCI_CLASS_PROCESSOR_POWERPC      0x0b20
+
+#define PCI_CLASS_OTHERS                 0xff
+
+/* Vendors and devices.  Sort key: vendor first, device next. */
+
+#define PCI_VENDOR_ID_LSI_LOGIC          0x1000
+#define PCI_DEVICE_ID_LSI_53C895A        0x0012
+
+#define PCI_VENDOR_ID_DEC                0x1011
+#define PCI_DEVICE_ID_DEC_21154          0x0026
+
+#define PCI_VENDOR_ID_CIRRUS             0x1013
+
+#define PCI_VENDOR_ID_IBM                0x1014
+
+#define PCI_VENDOR_ID_AMD                0x1022
+#define PCI_DEVICE_ID_AMD_LANCE          0x2000
+
+#define PCI_VENDOR_ID_MOTOROLA           0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC106    0x0002
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN     0x4801
+
+#define PCI_VENDOR_ID_APPLE              0x106b
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
+
+#define PCI_VENDOR_ID_SUN                0x108e
+#define PCI_DEVICE_ID_SUN_EBUS           0x1000
+#define PCI_DEVICE_ID_SUN_SIMBA          0x5000
+#define PCI_DEVICE_ID_SUN_SABRE          0xa000
+
+#define PCI_VENDOR_ID_CMD                0x1095
+#define PCI_DEVICE_ID_CMD_646            0x0646
+
+#define PCI_VENDOR_ID_REALTEK            0x10ec
+#define PCI_DEVICE_ID_REALTEK_8139       0x8139
+
+#define PCI_VENDOR_ID_XILINX             0x10ee
+
+#define PCI_VENDOR_ID_MARVELL            0x11ab
+
+#define PCI_VENDOR_ID_ENSONIQ            0x1274
+#define PCI_DEVICE_ID_ENSONIQ_ES1370     0x5000
+
+#define PCI_VENDOR_ID_FREESCALE          0x1957
+#define PCI_DEVICE_ID_MPC8533E           0x0030
+
+#define PCI_VENDOR_ID_INTEL              0x8086
+#define PCI_DEVICE_ID_INTEL_82441        0x1237
+#define PCI_DEVICE_ID_INTEL_82801AA_5    0x2415
+#define PCI_DEVICE_ID_INTEL_82371SB_0    0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1    0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2    0x7020
+#define PCI_DEVICE_ID_INTEL_82371AB_0    0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB      0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
diff --git a/hw/pcmcia.h b/hw/pcmcia.h
index bfa23ba..cd9e61c 100644
--- a/hw/pcmcia.h
+++ b/hw/pcmcia.h
@@ -1,19 +1,24 @@
 /* PCMCIA/Cardbus */
 
-struct pcmcia_socket_s {
+#ifndef _HW_PCMCIA_H
+#define _HW_PCMCIA_H
+
+#include "qemu-common.h"
+
+typedef struct {
     qemu_irq irq;
     int attached;
     const char *slot_string;
     const char *card_string;
-};
+} PCMCIASocket;
 
-void pcmcia_socket_register(struct pcmcia_socket_s *socket);
-void pcmcia_socket_unregister(struct pcmcia_socket_s *socket);
-void pcmcia_info(void);
+void pcmcia_socket_register(PCMCIASocket *socket);
+void pcmcia_socket_unregister(PCMCIASocket *socket);
+void pcmcia_info(Monitor *mon);
 
-struct pcmcia_card_s {
+struct PCMCIACardState {
     void *state;
-    struct pcmcia_socket_s *slot;
+    PCMCIASocket *slot;
     int (*attach)(void *state);
     int (*detach)(void *state);
     const uint8_t *cis;
@@ -46,5 +51,6 @@
 #define CISTPL_ENDMARK		0xff
 
 /* dscm1xxxx.c */
-struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv);
+PCMCIACardState *dscm1xxxx_init(BlockDriverState *bdrv);
 
+#endif /* _HW_PCMCIA_H */
diff --git a/hw/pxa.h b/hw/pxa.h
index 16a68d9..2ca36c2 100644
--- a/hw/pxa.h
+++ b/hw/pxa.h
@@ -70,40 +70,40 @@
 void pxa27x_timer_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq irq4);
 
 /* pxa2xx_gpio.c */
-struct pxa2xx_gpio_info_s;
-struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
+typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo;
+PXA2xxGPIOInfo *pxa2xx_gpio_init(target_phys_addr_t base,
                 CPUState *env, qemu_irq *pic, int lines);
-qemu_irq *pxa2xx_gpio_in_get(struct pxa2xx_gpio_info_s *s);
-void pxa2xx_gpio_out_set(struct pxa2xx_gpio_info_s *s,
+qemu_irq *pxa2xx_gpio_in_get(PXA2xxGPIOInfo *s);
+void pxa2xx_gpio_out_set(PXA2xxGPIOInfo *s,
                 int line, qemu_irq handler);
-void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s, qemu_irq handler);
+void pxa2xx_gpio_read_notifier(PXA2xxGPIOInfo *s, qemu_irq handler);
 
 /* pxa2xx_dma.c */
-struct pxa2xx_dma_state_s;
-struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
+typedef struct PXA2xxDMAState PXA2xxDMAState;
+PXA2xxDMAState *pxa255_dma_init(target_phys_addr_t base,
                 qemu_irq irq);
-struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
+PXA2xxDMAState *pxa27x_dma_init(target_phys_addr_t base,
                 qemu_irq irq);
-void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on);
+void pxa2xx_dma_request(PXA2xxDMAState *s, int req_num, int on);
 
 /* pxa2xx_lcd.c */
-struct pxa2xx_lcdc_s;
-struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base,
-                qemu_irq irq, DisplayState *ds);
-void pxa2xx_lcd_vsync_notifier(struct pxa2xx_lcdc_s *s, qemu_irq handler);
+typedef struct PXA2xxLCDState PXA2xxLCDState;
+PXA2xxLCDState *pxa2xx_lcdc_init(target_phys_addr_t base,
+                qemu_irq irq);
+void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler);
 void pxa2xx_lcdc_oritentation(void *opaque, int angle);
 
 /* pxa2xx_mmci.c */
-struct pxa2xx_mmci_s;
-struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base,
+typedef struct PXA2xxMMCIState PXA2xxMMCIState;
+PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base,
                 BlockDriverState *bd, qemu_irq irq, void *dma);
-void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, qemu_irq readonly,
+void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
                 qemu_irq coverswitch);
 
 /* pxa2xx_pcmcia.c */
-struct pxa2xx_pcmcia_s;
-struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base);
-int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card);
+typedef struct PXA2xxPCMCIAState PXA2xxPCMCIAState;
+PXA2xxPCMCIAState *pxa2xx_pcmcia_init(target_phys_addr_t base);
+int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card);
 int pxa2xx_pcmcia_dettach(void *opaque);
 void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq);
 
@@ -112,40 +112,35 @@
     int column;
     int row;
 };
-struct pxa2xx_keypad_s;
-struct pxa2xx_keypad_s *pxa27x_keypad_init(target_phys_addr_t base,
+typedef struct PXA2xxKeyPadState PXA2xxKeyPadState;
+PXA2xxKeyPadState *pxa27x_keypad_init(target_phys_addr_t base,
                 qemu_irq irq);
-void pxa27x_register_keypad(struct pxa2xx_keypad_s *kp, struct keymap *map,
+void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
                 int size);
 
 /* pxa2xx.c */
-struct pxa2xx_ssp_s;
-void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
-                uint32_t (*readfn)(void *opaque),
-                void (*writefn)(void *opaque, uint32_t value), void *opaque);
-
-struct pxa2xx_i2c_s;
-struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base,
+typedef struct PXA2xxI2CState PXA2xxI2CState;
+PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
                 qemu_irq irq, uint32_t page_size);
-i2c_bus *pxa2xx_i2c_bus(struct pxa2xx_i2c_s *s);
+i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s);
 
-struct pxa2xx_i2s_s;
-struct pxa2xx_fir_s;
+typedef struct PXA2xxI2SState PXA2xxI2SState;
+typedef struct PXA2xxFIrState PXA2xxFIrState;
 
-struct pxa2xx_state_s {
+typedef struct {
     CPUState *env;
     qemu_irq *pic;
     qemu_irq reset;
-    struct pxa2xx_dma_state_s *dma;
-    struct pxa2xx_gpio_info_s *gpio;
-    struct pxa2xx_lcdc_s *lcd;
-    struct pxa2xx_ssp_s **ssp;
-    struct pxa2xx_i2c_s *i2c[2];
-    struct pxa2xx_mmci_s *mmc;
-    struct pxa2xx_pcmcia_s *pcmcia[2];
-    struct pxa2xx_i2s_s *i2s;
-    struct pxa2xx_fir_s *fir;
-    struct pxa2xx_keypad_s *kp;
+    PXA2xxDMAState *dma;
+    PXA2xxGPIOInfo *gpio;
+    PXA2xxLCDState *lcd;
+    SSIBus **ssp;
+    PXA2xxI2CState *i2c[2];
+    PXA2xxMMCIState *mmc;
+    PXA2xxPCMCIAState *pcmcia[2];
+    PXA2xxI2SState *i2s;
+    PXA2xxFIrState *fir;
+    PXA2xxKeyPadState *kp;
 
     /* Power management */
     target_phys_addr_t pm_base;
@@ -189,12 +184,11 @@
     QEMUTimer *rtc_swal1;
     QEMUTimer *rtc_swal2;
     QEMUTimer *rtc_pi;
-};
+} PXA2xxState;
 
-struct pxa2xx_i2s_s {
-    target_phys_addr_t base;
+struct PXA2xxI2SState {
     qemu_irq irq;
-    struct pxa2xx_dma_state_s *dma;
+    PXA2xxDMAState *dma;
     void (*data_req)(void *, int, int);
 
     uint32_t control[2];
@@ -216,9 +210,8 @@
 # define PA_FMT			"0x%08lx"
 # define REG_FMT		"0x" TARGET_FMT_plx
 
-struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, DisplayState *ds,
-                const char *revision);
-struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, DisplayState *ds);
+PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision);
+PXA2xxState *pxa255_init(unsigned int sdram_size);
 
 /* usb-ohci.c */
 void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
diff --git a/hw/qdev.c b/hw/qdev.c
new file mode 100644
index 0000000..385e709
--- /dev/null
+++ b/hw/qdev.c
@@ -0,0 +1,409 @@
+/*
+ *  Dynamic device configuration and creation.
+ *
+ *  Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ */
+
+/* The theory here is that it should be possible to create a machine without
+   knowledge of specific devices.  Historically board init routines have
+   passed a bunch of arguments to each device, requiring the board know
+   exactly which device it is dealing with.  This file provides an abstract
+   API for device configuration and initialization.  Devices will generally
+   inherit from a particular bus (e.g. PCI or I2C) rather than
+   this API directly.  */
+
+#include "net.h"
+#include "qdev.h"
+#include "sysemu.h"
+#include "monitor.h"
+
+struct DeviceProperty {
+    const char *name;
+    DevicePropType type;
+    union {
+        uint64_t i;
+        void *ptr;
+    } value;
+    DeviceProperty *next;
+};
+
+struct DeviceType {
+    DeviceInfo *info;
+    DeviceType *next;
+};
+
+/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
+static BusState *main_system_bus;
+
+static DeviceType *device_type_list;
+
+/* Register a new device type.  */
+void qdev_register(DeviceInfo *info)
+{
+    DeviceType *t;
+
+    assert(info->size >= sizeof(DeviceState));
+
+    t = qemu_mallocz(sizeof(DeviceType));
+    t->next = device_type_list;
+    device_type_list = t;
+    t->info = info;
+}
+
+/* Create a new device.  This only initializes the device state structure
+   and allows properties to be set.  qdev_init should be called to
+   initialize the actual device emulation.  */
+DeviceState *qdev_create(BusState *bus, const char *name)
+{
+    DeviceType *t;
+    DeviceState *dev;
+
+    for (t = device_type_list; t; t = t->next) {
+        if (strcmp(t->info->name, name) == 0) {
+            break;
+        }
+    }
+    if (!t) {
+        hw_error("Unknown device '%s'\n", name);
+    }
+
+    dev = qemu_mallocz(t->info->size);
+    dev->type = t;
+
+    if (!bus) {
+        /* ???: This assumes system busses have no additional state.  */
+        if (!main_system_bus) {
+            main_system_bus = qbus_create(BUS_TYPE_SYSTEM, sizeof(BusState),
+                                          NULL, "main-system-bus");
+        }
+        bus = main_system_bus;
+    }
+    if (t->info->bus_type != bus->type) {
+        /* TODO: Print bus type names.  */
+        hw_error("Device '%s' on wrong bus type (%d/%d)", name,
+                 t->info->bus_type, bus->type);
+    }
+    dev->parent_bus = bus;
+    LIST_INSERT_HEAD(&bus->children, dev, sibling);
+    return dev;
+}
+
+/* Initialize a device.  Device properties should be set before calling
+   this function.  IRQs and MMIO regions should be connected/mapped after
+   calling this function.  */
+void qdev_init(DeviceState *dev)
+{
+    dev->type->info->init(dev, dev->type->info);
+}
+
+/* Unlink device from bus and free the structure.  */
+void qdev_free(DeviceState *dev)
+{
+    LIST_REMOVE(dev, sibling);
+    free(dev);
+}
+
+static DeviceProperty *create_prop(DeviceState *dev, const char *name,
+                                   DevicePropType type)
+{
+    DeviceProperty *prop;
+
+    /* TODO: Check for duplicate properties.  */
+    prop = qemu_mallocz(sizeof(*prop));
+    prop->name = qemu_strdup(name);
+    prop->type = type;
+    prop->next = dev->props;
+    dev->props = prop;
+
+    return prop;
+}
+
+void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value)
+{
+    DeviceProperty *prop;
+
+    prop = create_prop(dev, name, PROP_TYPE_INT);
+    prop->value.i = value;
+}
+
+void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value)
+{
+    DeviceProperty *prop;
+
+    prop = create_prop(dev, name, PROP_TYPE_DEV);
+    prop->value.ptr = value;
+}
+
+void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value)
+{
+    DeviceProperty *prop;
+
+    prop = create_prop(dev, name, PROP_TYPE_PTR);
+    prop->value.ptr = value;
+}
+
+void qdev_set_netdev(DeviceState *dev, NICInfo *nd)
+{
+    assert(!dev->nd);
+    dev->nd = nd;
+}
+
+
+/* Get a character (serial) device interface.  */
+CharDriverState *qdev_init_chardev(DeviceState *dev)
+{
+    static int next_serial;
+    static int next_virtconsole;
+    /* FIXME: This is a nasty hack that needs to go away.  */
+    if (strncmp(dev->type->info->name, "virtio", 6) == 0) {
+        return virtcon_hds[next_virtconsole++];
+    } else {
+        return serial_hds[next_serial++];
+    }
+}
+
+BusState *qdev_get_parent_bus(DeviceState *dev)
+{
+    return dev->parent_bus;
+}
+
+static DeviceProperty *find_prop(DeviceState *dev, const char *name,
+                                 DevicePropType type)
+{
+    DeviceProperty *prop;
+
+    for (prop = dev->props; prop; prop = prop->next) {
+        if (strcmp(prop->name, name) == 0) {
+            assert (prop->type == type);
+            return prop;
+        }
+    }
+    return NULL;
+}
+
+uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def)
+{
+    DeviceProperty *prop;
+
+    prop = find_prop(dev, name, PROP_TYPE_INT);
+    if (!prop) {
+        return def;
+    }
+
+    return prop->value.i;
+}
+
+void *qdev_get_prop_ptr(DeviceState *dev, const char *name)
+{
+    DeviceProperty *prop;
+
+    prop = find_prop(dev, name, PROP_TYPE_PTR);
+    assert(prop);
+    return prop->value.ptr;
+}
+
+DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name)
+{
+    DeviceProperty *prop;
+
+    prop = find_prop(dev, name, PROP_TYPE_DEV);
+    if (!prop) {
+        return NULL;
+    }
+    return prop->value.ptr;
+}
+
+void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
+{
+    assert(dev->num_gpio_in == 0);
+    dev->num_gpio_in = n;
+    dev->gpio_in = qemu_allocate_irqs(handler, dev, n);
+}
+
+void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
+{
+    assert(dev->num_gpio_out == 0);
+    dev->num_gpio_out = n;
+    dev->gpio_out = pins;
+}
+
+qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
+{
+    assert(n >= 0 && n < dev->num_gpio_in);
+    return dev->gpio_in[n];
+}
+
+void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
+{
+    assert(n >= 0 && n < dev->num_gpio_out);
+    dev->gpio_out[n] = pin;
+}
+
+VLANClientState *qdev_get_vlan_client(DeviceState *dev,
+                                      NetCanReceive *can_receive,
+                                      NetReceive *receive,
+                                      NetReceiveIOV *receive_iov,
+                                      NetCleanup *cleanup,
+                                      void *opaque)
+{
+    NICInfo *nd = dev->nd;
+    assert(nd);
+    return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
+                                receive, receive_iov, cleanup, opaque);
+}
+
+
+void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr)
+{
+    memcpy(macaddr, dev->nd->macaddr, 6);
+}
+
+static int next_block_unit[IF_COUNT];
+
+/* Get a block device.  This should only be used for single-drive devices
+   (e.g. SD/Floppy/MTD).  Multi-disk devices (scsi/ide) should use the
+   appropriate bus.  */
+BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
+{
+    int unit = next_block_unit[type]++;
+    int index;
+
+    index = drive_get_index(type, 0, unit);
+    if (index == -1) {
+        return NULL;
+    }
+    return drives_table[index].bdrv;
+}
+
+BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
+{
+    BusState *bus;
+
+    LIST_FOREACH(bus, &dev->child_bus, sibling) {
+        if (strcmp(name, bus->name) == 0) {
+            return bus;
+        }
+    }
+    return NULL;
+}
+
+static int next_scsi_bus;
+
+/* Create a scsi bus, and attach devices to it.  */
+/* TODO: Actually create a scsi bus for hotplug to use.  */
+void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
+{
+   int bus = next_scsi_bus++;
+   int unit;
+   int index;
+
+   for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
+       index = drive_get_index(IF_SCSI, bus, unit);
+       if (index == -1) {
+           continue;
+       }
+       attach(host, drives_table[index].bdrv, unit);
+   }
+}
+
+BusState *qbus_create(BusType type, size_t size,
+                      DeviceState *parent, const char *name)
+{
+    BusState *bus;
+
+    bus = qemu_mallocz(size);
+    bus->type = type;
+    bus->parent = parent;
+    bus->name = qemu_strdup(name);
+    LIST_INIT(&bus->children);
+    if (parent) {
+        LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
+    }
+    return bus;
+}
+
+static const char *bus_type_names[] = {
+    [ BUS_TYPE_SYSTEM ] = "System",
+    [ BUS_TYPE_PCI ]    = "PCI",
+    [ BUS_TYPE_SCSI ]   = "SCSI",
+    [ BUS_TYPE_I2C ]    = "I2C",
+    [ BUS_TYPE_SSI ]    = "SSI",
+};
+
+#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
+static void qbus_print(Monitor *mon, BusState *bus, int indent);
+
+static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    DeviceProperty *prop;
+    BusState *child;
+    qdev_printf("dev: %s\n", dev->type->info->name);
+    indent += 2;
+    if (dev->num_gpio_in) {
+        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
+    }
+    if (dev->num_gpio_out) {
+        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
+    }
+    for (prop = dev->props; prop; prop = prop->next) {
+        switch (prop->type) {
+        case PROP_TYPE_INT:
+            qdev_printf("prop-int %s 0x%" PRIx64 "\n", prop->name,
+                        prop->value.i);
+            break;
+        case PROP_TYPE_PTR:
+            qdev_printf("prop-ptr %s\n", prop->name);
+            break;
+        case PROP_TYPE_DEV:
+            qdev_printf("prop-dev %s %s\n", prop->name,
+                        ((DeviceState *)prop->value.ptr)->type->info->name);
+            break;
+        default:
+            qdev_printf("prop-unknown%d %s\n", prop->type, prop->name);
+            break;
+        }
+    }
+    switch (dev->parent_bus->type) {
+    case BUS_TYPE_SYSTEM:
+        sysbus_dev_print(mon, dev, indent);
+        break;
+    default:
+        break;
+    }
+    LIST_FOREACH(child, &dev->child_bus, sibling) {
+        qbus_print(mon, child, indent);
+    }
+}
+
+static void qbus_print(Monitor *mon, BusState *bus, int indent)
+{
+    struct DeviceState *dev;
+
+    qdev_printf("bus: %s\n", bus->name);
+    indent += 2;
+    qdev_printf("type %s\n", bus_type_names[bus->type]);
+    LIST_FOREACH(dev, &bus->children, sibling) {
+        qdev_print(mon, dev, indent);
+    }
+}
+#undef qdev_printf
+
+void do_info_qtree(Monitor *mon)
+{
+    if (main_system_bus)
+        qbus_print(mon, main_system_bus, 0);
+}
diff --git a/hw/qdev.h b/hw/qdev.h
new file mode 100644
index 0000000..ad10499
--- /dev/null
+++ b/hw/qdev.h
@@ -0,0 +1,129 @@
+#ifndef QDEV_H
+#define QDEV_H
+
+#include "hw.h"
+#include "sys-queue.h"
+
+typedef struct DeviceType DeviceType;
+
+typedef struct DeviceProperty DeviceProperty;
+
+typedef struct BusState BusState;
+
+/* This structure should not be accessed directly.  We declare it here
+   so that it can be embedded in individual device state structures.  */
+struct DeviceState {
+    DeviceType *type;
+    BusState *parent_bus;
+    DeviceProperty *props;
+    int num_gpio_out;
+    qemu_irq *gpio_out;
+    int num_gpio_in;
+    qemu_irq *gpio_in;
+    LIST_HEAD(, BusState) child_bus;
+    NICInfo *nd;
+    LIST_ENTRY(DeviceState) sibling;
+};
+
+typedef enum {
+    BUS_TYPE_SYSTEM,
+    BUS_TYPE_PCI,
+    BUS_TYPE_SCSI,
+    BUS_TYPE_I2C,
+    BUS_TYPE_SSI
+} BusType;
+
+struct BusState {
+    DeviceState *parent;
+    const char *name;
+    BusType type;
+    LIST_HEAD(, DeviceState) children;
+    LIST_ENTRY(BusState) sibling;
+};
+
+/*** Board API.  This should go away once we have a machine config file.  ***/
+
+DeviceState *qdev_create(BusState *bus, const char *name);
+void qdev_init(DeviceState *dev);
+void qdev_free(DeviceState *dev);
+
+/* Set properties between creation and init.  */
+void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value);
+void qdev_set_prop_dev(DeviceState *dev, const char *name, DeviceState *value);
+void qdev_set_prop_ptr(DeviceState *dev, const char *name, void *value);
+void qdev_set_netdev(DeviceState *dev, NICInfo *nd);
+
+qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
+void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
+
+BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
+
+/*** Device API.  ***/
+
+typedef enum {
+    PROP_TYPE_INT,
+    PROP_TYPE_PTR,
+    PROP_TYPE_DEV
+} DevicePropType;
+
+typedef struct {
+    const char *name;
+    DevicePropType type;
+} DevicePropList;
+
+typedef struct DeviceInfo DeviceInfo;
+
+typedef void (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
+typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv,
+              int unit);
+
+struct DeviceInfo {
+    const char *name;
+    size_t size;
+    DevicePropList *props;
+
+    /* Private to qdev / bus.  */
+    qdev_initfn init;
+    BusType bus_type;
+};
+
+void qdev_register(DeviceInfo *info);
+
+/* Register device properties.  */
+/* GPIO inputs also double as IRQ sinks.  */
+void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
+void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
+
+void scsi_bus_new(DeviceState *host, SCSIAttachFn attach);
+
+CharDriverState *qdev_init_chardev(DeviceState *dev);
+
+BusState *qdev_get_parent_bus(DeviceState *dev);
+uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def);
+DeviceState *qdev_get_prop_dev(DeviceState *dev, const char *name);
+/* FIXME: Remove opaque pointer properties.  */
+void *qdev_get_prop_ptr(DeviceState *dev, const char *name);
+
+/* Convery from a base type to a parent type, with compile time checking.  */
+#ifdef __GNUC__
+#define DO_UPCAST(type, field, dev) ( __extension__ ( { \
+    char __attribute__((unused)) offset_must_be_zero[ \
+        -offsetof(type, field)]; \
+    container_of(dev, type, field);}))
+#else
+#define DO_UPCAST(type, field, dev) container_of(dev, type, field)
+#endif
+
+/*** BUS API. ***/
+
+BusState *qbus_create(BusType type, size_t size,
+                      DeviceState *parent, const char *name);
+
+#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
+
+/*** monitor commands ***/
+
+void do_info_qtree(Monitor *mon);
+void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+
+#endif
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 16b3215..a0485db 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -13,17 +13,19 @@
  * the host adapter emulator.
  */
 
+#include <qemu-common.h>
+#include <sysemu.h>
 //#define DEBUG_SCSI
 
 #ifdef DEBUG_SCSI
-#define DPRINTF(fmt, args...) \
-do { printf("scsi-disk: " fmt , ##args); } while (0)
+#define DPRINTF(fmt, ...) \
+do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #else
-#define DPRINTF(fmt, args...) do {} while(0)
+#define DPRINTF(fmt, ...) do {} while(0)
 #endif
 
-#define BADF(fmt, args...) \
-do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 
 #include "qemu-common.h"
 #include "block.h"
@@ -34,21 +36,27 @@
 #define SENSE_HARDWARE_ERROR  4
 #define SENSE_ILLEGAL_REQUEST 5
 
-#define SCSI_DMA_BUF_SIZE    65536
+#define STATUS_GOOD            0
+#define STATUS_CHECK_CONDITION 2
+
+#define SCSI_DMA_BUF_SIZE    131072
+#define SCSI_MAX_INQUIRY_LEN 256
+
+#define SCSI_REQ_STATUS_RETRY 0x01
 
 typedef struct SCSIRequest {
     SCSIDeviceState *dev;
     uint32_t tag;
-    /* ??? We should probably keep track of whether the data trasfer is
+    /* ??? We should probably keep track of whether the data transfer is
        a read or a write.  Currently we rely on the host getting it right.  */
     /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
-    int sector;
-    int sector_count;
-    /* The amounnt of data in the buffer.  */
-    int buf_len;
-    uint8_t *dma_buf;
+    uint64_t sector;
+    uint32_t sector_count;
+    struct iovec iov;
+    QEMUIOVector qiov;
     BlockDriverAIOCB *aiocb;
     struct SCSIRequest *next;
+    uint32_t status;
 } SCSIRequest;
 
 struct SCSIDeviceState
@@ -58,12 +66,14 @@
     /* The qemu block layer uses a fixed 512 byte sector size.
        This is the number of 512 byte blocks in a single scsi sector.  */
     int cluster_size;
+    uint64_t max_lba;
     int sense;
     int tcq;
     /* Completion functions may be called from either scsi_{read,write}_data
        or from the AIO completion routines.  */
     scsi_completionfn completion;
     void *opaque;
+    char drive_serial_str[21];
 };
 
 /* Global pool of SCSIRequest structures.  */
@@ -78,13 +88,14 @@
         free_requests = r->next;
     } else {
         r = qemu_malloc(sizeof(SCSIRequest));
-        r->dma_buf = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
+        r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
     }
     r->dev = s;
     r->tag = tag;
     r->sector_count = 0;
-    r->buf_len = 0;
+    r->iov.iov_len = 0;
     r->aiocb = NULL;
+    r->status = 0;
 
     r->next = s->requests;
     s->requests = r;
@@ -124,15 +135,15 @@
 }
 
 /* Helper function for command completion.  */
-static void scsi_command_complete(SCSIRequest *r, int sense)
+static void scsi_command_complete(SCSIRequest *r, int status, int sense)
 {
     SCSIDeviceState *s = r->dev;
     uint32_t tag;
-    DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense);
+    DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", r->tag, status, sense);
     s->sense = sense;
     tag = r->tag;
     scsi_remove_request(r);
-    s->completion(s->opaque, SCSI_REASON_DONE, tag, sense);
+    s->completion(s->opaque, SCSI_REASON_DONE, tag, status);
 }
 
 /* Cancel a pending data transfer.  */
@@ -157,12 +168,13 @@
 
     if (ret) {
         DPRINTF("IO error\n");
-        scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+        s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 0);
+        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE);
         return;
     }
-    DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->buf_len);
+    DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->iov.iov_len);
 
-    s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len);
+    s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
 }
 
 /* Read more data from scsi device into buffer.  */
@@ -176,18 +188,18 @@
     if (!r) {
         BADF("Bad read tag 0x%x\n", tag);
         /* ??? This is the wrong error.  */
-        scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
         return;
     }
     if (r->sector_count == (uint32_t)-1) {
-        DPRINTF("Read buf_len=%d\n", r->buf_len);
+        DPRINTF("Read buf_len=%d\n", r->iov.iov_len);
         r->sector_count = 0;
-        s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len);
+        s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len);
         return;
     }
     DPRINTF("Read sector_count=%d\n", r->sector_count);
     if (r->sector_count == 0) {
-        scsi_command_complete(r, SENSE_NO_SENSE);
+        scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
         return;
     }
 
@@ -195,73 +207,123 @@
     if (n > SCSI_DMA_BUF_SIZE / 512)
         n = SCSI_DMA_BUF_SIZE / 512;
 
-    r->buf_len = n * 512;
-    r->aiocb = bdrv_aio_read(s->bdrv, r->sector, r->dma_buf, n,
-                             scsi_read_complete, r);
+    r->iov.iov_len = n * 512;
+    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+    r->aiocb = bdrv_aio_readv(s->bdrv, r->sector, &r->qiov, n,
+                              scsi_read_complete, r);
     if (r->aiocb == NULL)
-        scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
     r->sector += n;
     r->sector_count -= n;
 }
 
+static int scsi_handle_write_error(SCSIRequest *r, int error)
+{
+    BlockInterfaceErrorAction action = drive_get_onerror(r->dev->bdrv);
+
+    if (action == BLOCK_ERR_IGNORE)
+        return 0;
+
+    if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
+            || action == BLOCK_ERR_STOP_ANY) {
+        r->status |= SCSI_REQ_STATUS_RETRY;
+        vm_stop(0);
+    } else {
+        scsi_command_complete(r, STATUS_CHECK_CONDITION,
+                SENSE_HARDWARE_ERROR);
+    }
+
+    return 1;
+}
+
 static void scsi_write_complete(void * opaque, int ret)
 {
     SCSIRequest *r = (SCSIRequest *)opaque;
     SCSIDeviceState *s = r->dev;
     uint32_t len;
-
-    if (ret) {
-        fprintf(stderr, "scsi-disc: IO write error\n");
-        exit(1);
-    }
+    uint32_t n;
 
     r->aiocb = NULL;
+
+    if (ret) {
+        if (scsi_handle_write_error(r, -ret))
+            return;
+    }
+
+    n = r->iov.iov_len / 512;
+    r->sector += n;
+    r->sector_count -= n;
     if (r->sector_count == 0) {
-        scsi_command_complete(r, SENSE_NO_SENSE);
+        scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
     } else {
         len = r->sector_count * 512;
         if (len > SCSI_DMA_BUF_SIZE) {
             len = SCSI_DMA_BUF_SIZE;
         }
-        r->buf_len = len;
+        r->iov.iov_len = len;
         DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len);
         s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
     }
 }
 
+static void scsi_write_request(SCSIRequest *r)
+{
+    SCSIDeviceState *s = r->dev;
+    uint32_t n;
+
+    n = r->iov.iov_len / 512;
+    if (n) {
+        qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+        r->aiocb = bdrv_aio_writev(s->bdrv, r->sector, &r->qiov, n,
+                                   scsi_write_complete, r);
+        if (r->aiocb == NULL)
+            scsi_command_complete(r, STATUS_CHECK_CONDITION,
+                                  SENSE_HARDWARE_ERROR);
+    } else {
+        /* Invoke completion routine to fetch data from host.  */
+        scsi_write_complete(r, 0);
+    }
+}
+
 /* Write data to a scsi device.  Returns nonzero on failure.
    The transfer may complete asynchronously.  */
 static int scsi_write_data(SCSIDevice *d, uint32_t tag)
 {
     SCSIDeviceState *s = d->state;
     SCSIRequest *r;
-    uint32_t n;
 
     DPRINTF("Write data tag=0x%x\n", tag);
     r = scsi_find_request(s, tag);
     if (!r) {
         BADF("Bad write tag 0x%x\n", tag);
-        scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
         return 1;
     }
+
     if (r->aiocb)
         BADF("Data transfer already in progress\n");
-    n = r->buf_len / 512;
-    if (n) {
-        r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n,
-                                  scsi_write_complete, r);
-        if (r->aiocb == NULL)
-            scsi_command_complete(r, SENSE_HARDWARE_ERROR);
-        r->sector += n;
-        r->sector_count -= n;
-    } else {
-        /* Invoke completion routine to fetch data from host.  */
-        scsi_write_complete(r, 0);
-    }
+
+    scsi_write_request(r);
 
     return 0;
 }
 
+static void scsi_dma_restart_cb(void *opaque, int running, int reason)
+{
+    SCSIDeviceState *s = opaque;
+    SCSIRequest *r = s->requests;
+    if (!running)
+        return;
+
+    while (r) {
+        if (r->status & SCSI_REQ_STATUS_RETRY) {
+            r->status &= ~SCSI_REQ_STATUS_RETRY;
+            scsi_write_request(r); 
+        }
+        r = r->next;
+    }
+}
+
 /* Return a pointer to the data buffer.  */
 static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
 {
@@ -273,7 +335,7 @@
         BADF("Bad buffer tag 0x%x\n", tag);
         return NULL;
     }
-    return r->dma_buf;
+    return (uint8_t *)r->iov.iov_base;
 }
 
 /* Execute a scsi command.  Returns the length of the data expected by the
@@ -286,7 +348,7 @@
 {
     SCSIDeviceState *s = d->state;
     uint64_t nb_sectors;
-    uint32_t lba;
+    uint64_t lba;
     uint32_t len;
     int cmdlen;
     int is_write;
@@ -303,28 +365,34 @@
     /* ??? Tags are not unique for different luns.  We only implement a
        single lun, so this should not matter.  */
     r = scsi_new_request(s, tag);
-    outbuf = r->dma_buf;
+    outbuf = (uint8_t *)r->iov.iov_base;
     is_write = 0;
     DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
     switch (command >> 5) {
     case 0:
-        lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
+        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
+              (((uint64_t) buf[1] & 0x1f) << 16);
         len = buf[4];
         cmdlen = 6;
         break;
     case 1:
     case 2:
-        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
+              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
         len = buf[8] | (buf[7] << 8);
         cmdlen = 10;
         break;
     case 4:
-        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
+              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
+              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
+              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
         len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
         cmdlen = 16;
         break;
     case 5:
-        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
+              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
         len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
         cmdlen = 12;
         break;
@@ -344,21 +412,32 @@
     if (lun || buf[1] >> 5) {
         /* Only LUN 0 supported.  */
         DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
-        goto fail;
+        if (command != 0x03 && command != 0x12) /* REQUEST SENSE and INQUIRY */
+            goto fail;
     }
     switch (command) {
     case 0x0:
 	DPRINTF("Test Unit Ready\n");
+        if (!bdrv_is_inserted(s->bdrv))
+            goto notready;
 	break;
     case 0x03:
         DPRINTF("Request Sense (len %d)\n", len);
         if (len < 4)
             goto fail;
         memset(outbuf, 0, 4);
+        r->iov.iov_len = 4;
+        if (s->sense == SENSE_NOT_READY && len >= 18) {
+            memset(outbuf, 0, 18);
+            r->iov.iov_len = 18;
+            outbuf[7] = 10;
+            /* asc 0x3a, ascq 0: Medium not present */
+            outbuf[12] = 0x3a;
+            outbuf[13] = 0;
+        }
         outbuf[0] = 0xf0;
         outbuf[1] = 0;
         outbuf[2] = s->sense;
-        r->buf_len = 4;
         break;
     case 0x12:
         DPRINTF("Inquiry (len %d)\n", len);
@@ -383,24 +462,26 @@
                         DPRINTF("Inquiry EVPD[Supported pages] "
                                 "buffer size %d\n", len);
 
-                        r->buf_len = 0;
+                        r->iov.iov_len = 0;
 
                         if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
-                            outbuf[r->buf_len++] = 5;
+                            outbuf[r->iov.iov_len++] = 5;
                         } else {
-                            outbuf[r->buf_len++] = 0;
+                            outbuf[r->iov.iov_len++] = 0;
                         }
 
-                        outbuf[r->buf_len++] = 0x00; // this page
-                        outbuf[r->buf_len++] = 0x00;
-                        outbuf[r->buf_len++] = 3;    // number of pages
-                        outbuf[r->buf_len++] = 0x00; // list of supported pages (this page)
-                        outbuf[r->buf_len++] = 0x80; // unit serial number
-                        outbuf[r->buf_len++] = 0x83; // device identification
+                        outbuf[r->iov.iov_len++] = 0x00; // this page
+                        outbuf[r->iov.iov_len++] = 0x00;
+                        outbuf[r->iov.iov_len++] = 3;    // number of pages
+                        outbuf[r->iov.iov_len++] = 0x00; // list of supported pages (this page)
+                        outbuf[r->iov.iov_len++] = 0x80; // unit serial number
+                        outbuf[r->iov.iov_len++] = 0x83; // device identification
                     }
                     break;
                 case 0x80:
                     {
+                        int l;
+
                         /* Device serial number, optional */
                         if (len < 4) {
                             BADF("Error: EVPD[Serial number] Inquiry buffer "
@@ -409,21 +490,22 @@
                         }
 
                         DPRINTF("Inquiry EVPD[Serial number] buffer size %d\n", len);
+                        l = MIN(len, strlen(s->drive_serial_str));
 
-                        r->buf_len = 0;
+                        r->iov.iov_len = 0;
 
                         /* Supported page codes */
                         if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
-                            outbuf[r->buf_len++] = 5;
+                            outbuf[r->iov.iov_len++] = 5;
                         } else {
-                            outbuf[r->buf_len++] = 0;
+                            outbuf[r->iov.iov_len++] = 0;
                         }
 
-                        outbuf[r->buf_len++] = 0x80; // this page
-                        outbuf[r->buf_len++] = 0x00;
-                        outbuf[r->buf_len++] = 0x01; // 1 byte data follow
-
-                        outbuf[r->buf_len++] = '0';  // 1 byte data follow 
+                        outbuf[r->iov.iov_len++] = 0x80; // this page
+                        outbuf[r->iov.iov_len++] = 0x00;
+                        outbuf[r->iov.iov_len++] = l;
+                        memcpy(&outbuf[r->iov.iov_len], s->drive_serial_str, l);
+                        r->iov.iov_len += l;
                     }
 
                     break;
@@ -437,25 +519,25 @@
 
                         DPRINTF("Inquiry EVPD[Device identification] "
                                 "buffer size %d\n", len);
-                        r->buf_len = 0;
+                        r->iov.iov_len = 0;
                         if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
-                            outbuf[r->buf_len++] = 5;
+                            outbuf[r->iov.iov_len++] = 5;
                         } else {
-                            outbuf[r->buf_len++] = 0;
+                            outbuf[r->iov.iov_len++] = 0;
                         }
 
-                        outbuf[r->buf_len++] = 0x83; // this page
-                        outbuf[r->buf_len++] = 0x00;
-                        outbuf[r->buf_len++] = 3 + id_len;
+                        outbuf[r->iov.iov_len++] = 0x83; // this page
+                        outbuf[r->iov.iov_len++] = 0x00;
+                        outbuf[r->iov.iov_len++] = 3 + id_len;
 
-                        outbuf[r->buf_len++] = 0x2; // ASCII
-                        outbuf[r->buf_len++] = 0;   // not officially assigned
-                        outbuf[r->buf_len++] = 0;   // reserved
-                        outbuf[r->buf_len++] = id_len; // length of data following
+                        outbuf[r->iov.iov_len++] = 0x2; // ASCII
+                        outbuf[r->iov.iov_len++] = 0;   // not officially assigned
+                        outbuf[r->iov.iov_len++] = 0;   // reserved
+                        outbuf[r->iov.iov_len++] = id_len; // length of data following
 
-                        memcpy(&outbuf[r->buf_len],
+                        memcpy(&outbuf[r->iov.iov_len],
                                bdrv_get_device_name(s->bdrv), id_len);
-                        r->buf_len += id_len;
+                        r->iov.iov_len += id_len;
                     }
                     break;
                 default:
@@ -486,8 +568,15 @@
                      "is less than 36 (TODO: only 5 required)\n", len);
             }
         }
-	memset(outbuf, 0, 36);
-	if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
+
+        if(len > SCSI_MAX_INQUIRY_LEN)
+            len = SCSI_MAX_INQUIRY_LEN;
+
+        memset(outbuf, 0, len);
+
+        if (lun || buf[1] >> 5) {
+            outbuf[0] = 0x7f;	/* LUN not supported */
+	} else if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
 	    outbuf[0] = 5;
             outbuf[1] = 0x80;
 	    memcpy(&outbuf[16], "QEMU CD-ROM    ", 16);
@@ -501,10 +590,10 @@
            Some later commands are also implemented. */
 	outbuf[2] = 3;
 	outbuf[3] = 2; /* Format 2 */
-	outbuf[4] = 31;
+	outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */
         /* Sync data transfer and TCQ.  */
         outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0);
-	r->buf_len = 36;
+	r->iov.iov_len = len;
 	break;
     case 0x16:
         DPRINTF("Reserve(6)\n");
@@ -639,14 +728,18 @@
                 p[21] = (16 * 176) & 0xff;
                 p += 22;
             }
-            r->buf_len = p - outbuf;
-            outbuf[0] = r->buf_len - 4;
-            if (r->buf_len > len)
-                r->buf_len = len;
+            r->iov.iov_len = p - outbuf;
+            outbuf[0] = r->iov.iov_len - 4;
+            if (r->iov.iov_len > len)
+                r->iov.iov_len = len;
         }
         break;
     case 0x1b:
         DPRINTF("Start Stop Unit\n");
+        if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM &&
+            (buf[4] & 2))
+            /* load/eject medium */
+            bdrv_eject(s->bdrv, !(buf[4] & 1));
 	break;
     case 0x1e:
         DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3);
@@ -657,9 +750,15 @@
         /* The normal LEN field for this command is zero.  */
 	memset(outbuf, 0, 8);
 	bdrv_get_geometry(s->bdrv, &nb_sectors);
+        nb_sectors /= s->cluster_size;
         /* Returned value is the address of the last sector.  */
         if (nb_sectors) {
             nb_sectors--;
+            /* Remember the new size for read/write sanity checking. */
+            s->max_lba = nb_sectors;
+            /* Clip to 2TB, instead of returning capacity modulo 2TB. */
+            if (nb_sectors > UINT32_MAX)
+                nb_sectors = UINT32_MAX;
             outbuf[0] = (nb_sectors >> 24) & 0xff;
             outbuf[1] = (nb_sectors >> 16) & 0xff;
             outbuf[2] = (nb_sectors >> 8) & 0xff;
@@ -668,21 +767,28 @@
             outbuf[5] = 0;
             outbuf[6] = s->cluster_size * 2;
             outbuf[7] = 0;
-            r->buf_len = 8;
+            r->iov.iov_len = 8;
         } else {
-            scsi_command_complete(r, SENSE_NOT_READY);
+        notready:
+            scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
             return 0;
         }
 	break;
     case 0x08:
     case 0x28:
-        DPRINTF("Read (sector %d, count %d)\n", lba, len);
+    case 0x88:
+        DPRINTF("Read (sector %lld, count %d)\n", lba, len);
+        if (lba > s->max_lba)
+            goto illegal_lba;
         r->sector = lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         break;
     case 0x0a:
     case 0x2a:
-        DPRINTF("Write (sector %d, count %d)\n", lba, len);
+    case 0x8a:
+        DPRINTF("Write (sector %lld, count %d)\n", lba, len);
+        if (lba > s->max_lba)
+            goto illegal_lba;
         r->sector = lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         is_write = 1;
@@ -700,6 +806,7 @@
             start_track = buf[6];
             bdrv_get_geometry(s->bdrv, &nb_sectors);
             DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
+            nb_sectors /= s->cluster_size;
             switch(format) {
             case 0:
                 toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
@@ -721,7 +828,7 @@
             if (toclen > 0) {
                 if (len > toclen)
                   len = toclen;
-                r->buf_len = len;
+                r->iov.iov_len = len;
                 break;
             }
         error_cmd:
@@ -734,7 +841,7 @@
         /* ??? This should probably return much more information.  For now
            just return the basic header indicating the CD-ROM profile.  */
         outbuf[7] = 8; // CD-ROM
-        r->buf_len = 8;
+        r->iov.iov_len = 8;
         break;
     case 0x56:
         DPRINTF("Reserve(10)\n");
@@ -746,24 +853,64 @@
         if (buf[1] & 3)
             goto fail;
         break;
+    case 0x9e:
+        /* Service Action In subcommands. */
+        if ((buf[1] & 31) == 0x10) {
+            DPRINTF("SAI READ CAPACITY(16)\n");
+            memset(outbuf, 0, len);
+            bdrv_get_geometry(s->bdrv, &nb_sectors);
+            nb_sectors /= s->cluster_size;
+            /* Returned value is the address of the last sector.  */
+            if (nb_sectors) {
+                nb_sectors--;
+                /* Remember the new size for read/write sanity checking. */
+                s->max_lba = nb_sectors;
+                outbuf[0] = (nb_sectors >> 56) & 0xff;
+                outbuf[1] = (nb_sectors >> 48) & 0xff;
+                outbuf[2] = (nb_sectors >> 40) & 0xff;
+                outbuf[3] = (nb_sectors >> 32) & 0xff;
+                outbuf[4] = (nb_sectors >> 24) & 0xff;
+                outbuf[5] = (nb_sectors >> 16) & 0xff;
+                outbuf[6] = (nb_sectors >> 8) & 0xff;
+                outbuf[7] = nb_sectors & 0xff;
+                outbuf[8] = 0;
+                outbuf[9] = 0;
+                outbuf[10] = s->cluster_size * 2;
+                outbuf[11] = 0;
+                /* Protection, exponent and lowest lba field left blank. */
+                r->iov.iov_len = len;
+            } else {
+                scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
+                return 0;
+            }
+            break;
+        }
+        DPRINTF("Unsupported Service Action In\n");
+        goto fail;
     case 0xa0:
         DPRINTF("Report LUNs (len %d)\n", len);
         if (len < 16)
             goto fail;
         memset(outbuf, 0, 16);
         outbuf[3] = 8;
-        r->buf_len = 16;
+        r->iov.iov_len = 16;
+        break;
+    case 0x2f:
+        DPRINTF("Verify (sector %d, count %d)\n", lba, len);
         break;
     default:
 	DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
     fail:
-        scsi_command_complete(r, SENSE_ILLEGAL_REQUEST);
+        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST);
 	return 0;
+    illegal_lba:
+        scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
+        return 0;
     }
-    if (r->sector_count == 0 && r->buf_len == 0) {
-        scsi_command_complete(r, SENSE_NO_SENSE);
+    if (r->sector_count == 0 && r->iov.iov_len == 0) {
+        scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
     }
-    len = r->sector_count * 512 + r->buf_len;
+    len = r->sector_count * 512 + r->iov.iov_len;
     if (is_write) {
         return -len;
     } else {
@@ -784,6 +931,7 @@
 {
     SCSIDevice *d;
     SCSIDeviceState *s;
+    uint64_t nb_sectors;
 
     s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
     s->bdrv = bdrv;
@@ -795,7 +943,16 @@
     } else {
         s->cluster_size = 1;
     }
-
+    bdrv_get_geometry(s->bdrv, &nb_sectors);
+    nb_sectors /= s->cluster_size;
+    if (nb_sectors)
+        nb_sectors--;
+    s->max_lba = nb_sectors;
+    strncpy(s->drive_serial_str, drive_get_serial(s->bdrv),
+            sizeof(s->drive_serial_str));
+    if (strlen(s->drive_serial_str) == 0)
+        pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0");
+    qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
     d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
     d->state = s;
     d->destroy = scsi_destroy;
diff --git a/hw/smbios.h b/hw/smbios.h
new file mode 100644
index 0000000..3a5169d
--- /dev/null
+++ b/hw/smbios.h
@@ -0,0 +1,162 @@
+#ifndef QEMU_SMBIOS_H
+#define QEMU_SMBIOS_H
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson@hp.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+int smbios_entry_add(const char *t);
+void smbios_add_field(int type, int offset, int len, void *data);
+uint8_t *smbios_get_table(size_t *length);
+
+/*
+ * SMBIOS spec defined tables
+ */
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+    uint8_t type;
+    uint8_t length;
+    uint16_t handle;
+} __attribute__((__packed__));
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+    struct smbios_structure_header header;
+    uint8_t vendor_str;
+    uint8_t bios_version_str;
+    uint16_t bios_starting_address_segment;
+    uint8_t bios_release_date_str;
+    uint8_t bios_rom_size;
+    uint8_t bios_characteristics[8];
+    uint8_t bios_characteristics_extension_bytes[2];
+    uint8_t system_bios_major_release;
+    uint8_t system_bios_minor_release;
+    uint8_t embedded_controller_major_release;
+    uint8_t embedded_controller_minor_release;
+} __attribute__((__packed__));
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t product_name_str;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    uint8_t uuid[16];
+    uint8_t wake_up_type;
+    uint8_t sku_number_str;
+    uint8_t family_str;
+} __attribute__((__packed__));
+
+/* SMBIOS type 3 - System Enclosure (v2.3) */
+struct smbios_type_3 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t type;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    uint8_t asset_tag_number_str;
+    uint8_t boot_up_state;
+    uint8_t power_supply_state;
+    uint8_t thermal_state;
+    uint8_t security_status;
+    uint32_t oem_defined;
+    uint8_t height;
+    uint8_t number_of_power_cords;
+    uint8_t contained_element_count;
+    // contained elements follow
+} __attribute__((__packed__));
+
+/* SMBIOS type 4 - Processor Information (v2.0) */
+struct smbios_type_4 {
+    struct smbios_structure_header header;
+    uint8_t socket_designation_str;
+    uint8_t processor_type;
+    uint8_t processor_family;
+    uint8_t processor_manufacturer_str;
+    uint32_t processor_id[2];
+    uint8_t processor_version_str;
+    uint8_t voltage;
+    uint16_t external_clock;
+    uint16_t max_speed;
+    uint16_t current_speed;
+    uint8_t status;
+    uint8_t processor_upgrade;
+    uint16_t l1_cache_handle;
+    uint16_t l2_cache_handle;
+    uint16_t l3_cache_handle;
+} __attribute__((__packed__));
+
+/* SMBIOS type 16 - Physical Memory Array
+ *   Associated with one type 17 (Memory Device).
+ */
+struct smbios_type_16 {
+    struct smbios_structure_header header;
+    uint8_t location;
+    uint8_t use;
+    uint8_t error_correction;
+    uint32_t maximum_capacity;
+    uint16_t memory_error_information_handle;
+    uint16_t number_of_memory_devices;
+} __attribute__((__packed__));
+/* SMBIOS type 17 - Memory Device
+ *   Associated with one type 19
+ */
+struct smbios_type_17 {
+    struct smbios_structure_header header;
+    uint16_t physical_memory_array_handle;
+    uint16_t memory_error_information_handle;
+    uint16_t total_width;
+    uint16_t data_width;
+    uint16_t size;
+    uint8_t form_factor;
+    uint8_t device_set;
+    uint8_t device_locator_str;
+    uint8_t bank_locator_str;
+    uint8_t memory_type;
+    uint16_t type_detail;
+} __attribute__((__packed__));
+
+/* SMBIOS type 19 - Memory Array Mapped Address */
+struct smbios_type_19 {
+    struct smbios_structure_header header;
+    uint32_t starting_address;
+    uint32_t ending_address;
+    uint16_t memory_array_handle;
+    uint8_t partition_width;
+} __attribute__((__packed__));
+
+/* SMBIOS type 20 - Memory Device Mapped Address */
+struct smbios_type_20 {
+    struct smbios_structure_header header;
+    uint32_t starting_address;
+    uint32_t ending_address;
+    uint16_t memory_device_handle;
+    uint16_t memory_array_mapped_address_handle;
+    uint8_t partition_row_position;
+    uint8_t interleave_position;
+    uint8_t interleaved_data_depth;
+} __attribute__((__packed__));
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+    struct smbios_structure_header header;
+    uint8_t reserved[6];
+    uint8_t boot_status;
+} __attribute__((__packed__));
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+    struct smbios_structure_header header;
+} __attribute__((__packed__));
+
+#endif /*QEMU_SMBIOS_H */
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 410051d3..cf8d864 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -7,7 +7,7 @@
  * This code is licenced under the GPL
  */
 
-#include "hw.h"
+#include "sysbus.h"
 #include "net.h"
 #include "devices.h"
 /* For crc32 */
@@ -17,7 +17,7 @@
 #define NUM_PACKETS 4
 
 typedef struct {
-    uint32_t base;
+    SysBusDevice busdev;
     VLANClientState *vc;
     uint16_t tcr;
     uint16_t rcr;
@@ -43,6 +43,7 @@
     uint8_t int_level;
     uint8_t int_mask;
     uint8_t macaddr[6];
+    int mmio_index;
 } smc91c111_state;
 
 #define RCR_SOFT_RST  0x8000
@@ -249,7 +250,6 @@
 {
     smc91c111_state *s = (smc91c111_state *)opaque;
 
-    offset -= s->base;
     if (offset == 14) {
         s->bank = value;
         return;
@@ -414,15 +414,13 @@
         }
         break;
     }
-    cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n",
-               s->bank, (int)offset);
+    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
 }
 
 static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
 {
     smc91c111_state *s = (smc91c111_state *)opaque;
 
-    offset -= s->base;
     if (offset == 14) {
         return s->bank;
     }
@@ -556,8 +554,7 @@
         }
         break;
     }
-    cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n",
-               s->bank, (int)offset);
+    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
     return 0;
 }
 
@@ -571,10 +568,9 @@
 static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
                              uint32_t value)
 {
-    smc91c111_state *s = (smc91c111_state *)opaque;
     /* 32-bit writes to offset 0xc only actually write to the bank select
        register (offset 0xe)  */
-    if (offset != s->base + 0xc)
+    if (offset != 0xc)
         smc91c111_writew(opaque, offset, value & 0xffff);
     smc91c111_writew(opaque, offset + 2, value >> 16);
 }
@@ -595,9 +591,9 @@
     return val;
 }
 
-static int smc91c111_can_receive(void *opaque)
+static int smc91c111_can_receive(VLANClientState *vc)
 {
-    smc91c111_state *s = (smc91c111_state *)opaque;
+    smc91c111_state *s = vc->opaque;
 
     if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
         return 1;
@@ -606,9 +602,9 @@
     return 1;
 }
 
-static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
+static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
 {
-    smc91c111_state *s = (smc91c111_state *)opaque;
+    smc91c111_state *s = vc->opaque;
     int status;
     int packetsize;
     uint32_t crc;
@@ -616,7 +612,7 @@
     uint8_t *p;
 
     if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
-        return;
+        return -1;
     /* Short packets are padded with zeros.  Receiving a packet
        < 64 bytes long is considered an error condition.  */
     if (size < 64)
@@ -629,10 +625,10 @@
         packetsize += 4;
     /* TODO: Flag overrun and receive errors.  */
     if (packetsize > 2048)
-        return;
+        return -1;
     packetnum = smc91c111_allocate_packet(s);
     if (packetnum == 0x80)
-        return;
+        return -1;
     s->rx_fifo[s->rx_fifo_len++] = packetnum;
 
     p = &s->data[packetnum][0];
@@ -680,6 +676,8 @@
     /* TODO: Raise early RX interrupt?  */
     s->int_level |= INT_RCV;
     smc91c111_update(s);
+
+    return size;
 }
 
 static CPUReadMemoryFunc *smc91c111_readfn[] = {
@@ -694,22 +692,52 @@
     smc91c111_writel
 };
 
-void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+static void smc91c111_cleanup(VLANClientState *vc)
 {
-    smc91c111_state *s;
-    int iomemtype;
+    smc91c111_state *s = vc->opaque;
 
-    s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
-    iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
-                                       smc91c111_writefn, s);
-    cpu_register_physical_memory(base, 16, iomemtype);
-    s->base = base;
-    s->irq = irq;
-    memcpy(s->macaddr, nd->macaddr, 6);
+    cpu_unregister_io_memory(s->mmio_index);
+    qemu_free(s);
+}
+
+static void smc91c111_init1(SysBusDevice *dev)
+{
+    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
+
+    s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
+                                           smc91c111_writefn, s);
+    sysbus_init_mmio(dev, 16, s->mmio_index);
+    sysbus_init_irq(dev, &s->irq);
+    qdev_get_macaddr(&dev->qdev, s->macaddr);
 
     smc91c111_reset(s);
 
-    s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive,
-                                 smc91c111_can_receive, s);
+    s->vc = qdev_get_vlan_client(&dev->qdev,
+                                 smc91c111_can_receive, smc91c111_receive, NULL,
+                                 smc91c111_cleanup, s);
+    qemu_format_nic_info_str(s->vc, s->macaddr);
     /* ??? Save/restore.  */
 }
+
+static void smc91c111_register_devices(void)
+{
+    sysbus_register_dev("smc91c111", sizeof(smc91c111_state), smc91c111_init1);
+}
+
+/* Legacy helper function.  Should go away when machine config files are
+   implemented.  */
+void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    qemu_check_nic_model(nd, "smc91c111");
+    dev = qdev_create(NULL, "smc91c111");
+    qdev_set_netdev(dev, nd);
+    qdev_init(dev);
+    s = sysbus_from_qdev(dev);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+device_init(smc91c111_register_devices)
diff --git a/hw/sysbus.c b/hw/sysbus.c
new file mode 100644
index 0000000..ef3a701
--- /dev/null
+++ b/hw/sysbus.c
@@ -0,0 +1,165 @@
+/*
+ *  System (CPU) Bus device support code
+ *
+ *  Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ */
+
+#include "sysbus.h"
+#include "sysemu.h"
+#include "monitor.h"
+
+void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
+{
+    assert(n >= 0 && n < dev->num_irq);
+    dev->irqs[n] = 0;
+    if (dev->irqp[n]) {
+        *dev->irqp[n] = irq;
+    }
+}
+
+void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
+{
+    assert(n >= 0 && n < dev->num_mmio);
+
+    if (dev->mmio[n].addr == addr) {
+        /* ??? region already mapped here.  */
+        return;
+    }
+    if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
+        /* Unregister previous mapping.  */
+        cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
+                                     IO_MEM_UNASSIGNED);
+    }
+    dev->mmio[n].addr = addr;
+    if (dev->mmio[n].cb) {
+        dev->mmio[n].cb(dev, addr);
+    } else {
+        cpu_register_physical_memory(addr, dev->mmio[n].size,
+                                     dev->mmio[n].iofunc);
+    }
+}
+
+
+/* Request an IRQ source.  The actual IRQ object may be populated later.  */
+void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
+{
+    int n;
+
+    assert(dev->num_irq < QDEV_MAX_IRQ);
+    n = dev->num_irq++;
+    dev->irqp[n] = p;
+}
+
+/* Pass IRQs from a target device.  */
+void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
+{
+    int i;
+    assert(dev->num_irq == 0);
+    dev->num_irq = target->num_irq;
+    for (i = 0; i < dev->num_irq; i++) {
+        dev->irqp[i] = target->irqp[i];
+    }
+}
+
+void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc)
+{
+    int n;
+
+    assert(dev->num_mmio < QDEV_MAX_MMIO);
+    n = dev->num_mmio++;
+    dev->mmio[n].addr = -1;
+    dev->mmio[n].size = size;
+    dev->mmio[n].iofunc = iofunc;
+}
+
+void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
+                         mmio_mapfunc cb)
+{
+    int n;
+
+    assert(dev->num_mmio < QDEV_MAX_MMIO);
+    n = dev->num_mmio++;
+    dev->mmio[n].addr = -1;
+    dev->mmio[n].size = size;
+    dev->mmio[n].cb = cb;
+}
+
+static void sysbus_device_init(DeviceState *dev, DeviceInfo *base)
+{
+    SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
+
+    info->init(sysbus_from_qdev(dev));
+}
+
+void sysbus_register_withprop(SysBusDeviceInfo *info)
+{
+    info->qdev.init = sysbus_device_init;
+    info->qdev.bus_type = BUS_TYPE_SYSTEM;
+
+    assert(info->qdev.size >= sizeof(SysBusDevice));
+    qdev_register(&info->qdev);
+}
+
+void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
+{
+    SysBusDeviceInfo *info;
+
+    info = qemu_mallocz(sizeof(*info));
+    info->qdev.name = qemu_strdup(name);
+    info->qdev.size = size;
+    info->init = init;
+    sysbus_register_withprop(info);
+}
+
+DeviceState *sysbus_create_varargs(const char *name,
+                                   target_phys_addr_t addr, ...)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    va_list va;
+    qemu_irq irq;
+    int n;
+
+    dev = qdev_create(NULL, name);
+    s = sysbus_from_qdev(dev);
+    qdev_init(dev);
+    if (addr != (target_phys_addr_t)-1) {
+        sysbus_mmio_map(s, 0, addr);
+    }
+    va_start(va, addr);
+    n = 0;
+    while (1) {
+        irq = va_arg(va, qemu_irq);
+        if (!irq) {
+            break;
+        }
+        sysbus_connect_irq(s, n, irq);
+        n++;
+    }
+    return dev;
+}
+
+void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    SysBusDevice *s = sysbus_from_qdev(dev);
+    int i;
+
+    for (i = 0; i < s->num_mmio; i++) {
+        monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
+                       indent, "", s->mmio[i].addr, s->mmio[i].size);
+    }
+}
diff --git a/hw/sysbus.h b/hw/sysbus.h
new file mode 100644
index 0000000..7c20808
--- /dev/null
+++ b/hw/sysbus.h
@@ -0,0 +1,62 @@
+#ifndef HW_SYSBUS_H
+#define HW_SYSBUS_H 1
+
+/* Devices attached directly to the main system bus.  */
+
+#include "qdev.h"
+
+#define QDEV_MAX_MMIO 5
+#define QDEV_MAX_IRQ 32
+
+typedef struct SysBusDevice SysBusDevice;
+typedef void (*mmio_mapfunc)(SysBusDevice *dev, target_phys_addr_t addr);
+
+struct SysBusDevice {
+    DeviceState qdev;
+    int num_irq;
+    qemu_irq irqs[QDEV_MAX_IRQ];
+    qemu_irq *irqp[QDEV_MAX_IRQ];
+    int num_mmio;
+    struct {
+        target_phys_addr_t addr;
+        target_phys_addr_t size;
+        mmio_mapfunc cb;
+        int iofunc;
+    } mmio[QDEV_MAX_MMIO];
+};
+
+typedef void (*sysbus_initfn)(SysBusDevice *dev);
+
+/* Macros to compensate for lack of type inheritance in C.  */
+#define sysbus_from_qdev(dev) ((SysBusDevice *)(dev))
+#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
+
+typedef struct {
+    DeviceInfo qdev;
+    sysbus_initfn init;
+} SysBusDeviceInfo;
+
+void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
+void sysbus_register_withprop(SysBusDeviceInfo *info);
+void *sysbus_new(void);
+void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc);
+void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
+                            mmio_mapfunc cb);
+void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
+void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
+
+
+void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
+void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr);
+
+/* Legacy helper function for creating devices.  */
+DeviceState *sysbus_create_varargs(const char *name,
+                                 target_phys_addr_t addr, ...);
+static inline DeviceState *sysbus_create_simple(const char *name,
+                                              target_phys_addr_t addr,
+                                              qemu_irq irq)
+{
+    return sysbus_create_varargs(name, addr, irq, NULL);
+}
+
+#endif /* !HW_SYSBUS_H */
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 406c9ab..c850a91 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -65,8 +65,10 @@
     };
     int kind;
     int protocol;
-    int idle;
+    uint8_t idle;
     int changed;
+    void *datain_opaque;
+    void (*datain)(void *);
 } USBHIDState;
 
 /* mostly the same values as the Bochs USB Mouse device */
@@ -402,6 +404,14 @@
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
+static void usb_hid_changed(USBHIDState *hs)
+{
+    hs->changed = 1;
+
+    if (hs->datain)
+        hs->datain(hs->datain_opaque);
+}
+
 static void usb_mouse_event(void *opaque,
                             int dx1, int dy1, int dz1, int buttons_state)
 {
@@ -412,7 +422,8 @@
     s->dy += dy1;
     s->dz += dz1;
     s->buttons_state = buttons_state;
-    hs->changed = 1;
+
+    usb_hid_changed(hs);
 }
 
 static void usb_tablet_event(void *opaque,
@@ -425,7 +436,8 @@
     s->y = y;
     s->dz += dz;
     s->buttons_state = buttons_state;
-    hs->changed = 1;
+
+    usb_hid_changed(hs);
 }
 
 static void usb_keyboard_event(void *opaque, int keycode)
@@ -439,8 +451,6 @@
     hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
     s->modifiers &= ~(1 << 8);
 
-    hs->changed = 1;
-
     switch (hid_code) {
     case 0x00:
         return;
@@ -465,15 +475,23 @@
             if (s->key[i] == hid_code) {
                 s->key[i] = s->key[-- s->keys];
                 s->key[s->keys] = 0x00;
-                return;
+                usb_hid_changed(hs);
+                break;
             }
+        if (i < 0)
+            return;
     } else {
         for (i = s->keys - 1; i >= 0; i --)
             if (s->key[i] == hid_code)
-                return;
-        if (s->keys < sizeof(s->key))
-            s->key[s->keys ++] = hid_code;
+                break;
+        if (i < 0) {
+            if (s->keys < sizeof(s->key))
+                s->key[s->keys ++] = hid_code;
+        } else
+            return;
     }
+
+    usb_hid_changed(hs);
 }
 
 static inline int int_clamp(int val, int vmin, int vmax)
@@ -776,7 +794,7 @@
         data[0] = s->idle;
         break;
     case SET_IDLE:
-        s->idle = value;
+        s->idle = (uint8_t) (value >> 8);
         ret = 0;
         break;
     default:
@@ -833,8 +851,6 @@
     USBHIDState *s;
 
     s = qemu_mallocz(sizeof(USBHIDState));
-    if (!s)
-        return NULL;
     s->dev.speed = USB_SPEED_FULL;
     s->dev.handle_packet = usb_generic_handle_packet;
 
@@ -856,8 +872,6 @@
     USBHIDState *s;
 
     s = qemu_mallocz(sizeof(USBHIDState));
-    if (!s)
-        return NULL;
     s->dev.speed = USB_SPEED_FULL;
     s->dev.handle_packet = usb_generic_handle_packet;
 
@@ -879,8 +893,6 @@
     USBHIDState *s;
 
     s = qemu_mallocz(sizeof(USBHIDState));
-    if (!s)
-        return NULL;
     s->dev.speed = USB_SPEED_FULL;
     s->dev.handle_packet = usb_generic_handle_packet;
 
@@ -894,3 +906,11 @@
 
     return (USBDevice *) s;
 }
+
+void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
+{
+    USBHIDState *s = (USBHIDState *)dev;
+
+    s->datain_opaque = opaque;
+    s->datain = datain;
+}
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 97c3d05..9f26bbe 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -530,8 +530,6 @@
     if (nb_ports > MAX_PORTS)
         return NULL;
     s = qemu_mallocz(sizeof(USBHubState));
-    if (!s)
-        return NULL;
     s->dev.speed = USB_SPEED_FULL;
     s->dev.handle_packet = usb_hub_handle_packet;
 
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index f7ad25e..3a3eb4a 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -11,14 +11,15 @@
 #include "usb.h"
 #include "block.h"
 #include "scsi-disk.h"
+#include "console.h"
 
 //#define DEBUG_MSD
 
 #ifdef DEBUG_MSD
-#define DPRINTF(fmt, args...) \
-do { printf("usb-msd: " fmt , ##args); } while (0)
+#define DPRINTF(fmt, ...) \
+do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
 #else
-#define DPRINTF(fmt, args...) do {} while(0)
+#define DPRINTF(fmt, ...) do {} while(0)
 #endif
 
 /* USB requests.  */
@@ -548,14 +549,10 @@
     }
 
     s = qemu_mallocz(sizeof(MSDState));
-    if (!s)
-        return NULL;
 
     bdrv = bdrv_new("usb");
     if (bdrv_open2(bdrv, filename, 0, drv) < 0)
         goto fail;
-    if (qemu_key_check(bdrv, filename))
-        goto fail;
     s->bs = bdrv;
 
     s->dev.speed = USB_SPEED_FULL;
@@ -576,3 +573,10 @@
     qemu_free(s);
     return NULL;
 }
+
+BlockDriverState *usb_msd_get_bdrv(USBDevice *dev)
+{
+    MSDState *s = (MSDState *)dev;
+
+    return s->bs;
+}
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 55cb77b..c575480 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  *
  * TODO:
  *  o Isochronous transfers
@@ -32,6 +32,7 @@
 #include "usb.h"
 #include "pci.h"
 #include "pxa.h"
+#include "devices.h"
 
 //#define DEBUG_OHCI
 /* Dump packet contents.  */
@@ -60,13 +61,13 @@
 
 enum ohci_type {
     OHCI_TYPE_PCI,
-    OHCI_TYPE_PXA
+    OHCI_TYPE_PXA,
+    OHCI_TYPE_SM501,
 };
 
 typedef struct {
     qemu_irq irq;
     enum ohci_type type;
-    target_phys_addr_t mem_base;
     int mem;
     int num_ports;
     const char *name;
@@ -109,6 +110,9 @@
     uint32_t hreset;
     uint32_t htest;
 
+    /* SM501 local memory offset */
+    target_phys_addr_t localmem_base;
+
     /* Active packets.  */
     uint32_t old_ctl;
     USBPacket usb_packet;
@@ -426,10 +430,13 @@
 }
 
 /* Get an array of dwords from main memory */
-static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
+static inline int get_dwords(OHCIState *ohci,
+                             uint32_t addr, uint32_t *buf, int num)
 {
     int i;
 
+    addr += ohci->localmem_base;
+
     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
         cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
         *buf = le32_to_cpu(*buf);
@@ -439,10 +446,13 @@
 }
 
 /* Put an array of dwords in to main memory */
-static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
+static inline int put_dwords(OHCIState *ohci,
+                             uint32_t addr, uint32_t *buf, int num)
 {
     int i;
 
+    addr += ohci->localmem_base;
+
     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
         uint32_t tmp = cpu_to_le32(*buf);
         cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
@@ -452,10 +462,13 @@
 }
 
 /* Get an array of words from main memory */
-static inline int get_words(uint32_t addr, uint16_t *buf, int num)
+static inline int get_words(OHCIState *ohci,
+                            uint32_t addr, uint16_t *buf, int num)
 {
     int i;
 
+    addr += ohci->localmem_base;
+
     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
         cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
         *buf = le16_to_cpu(*buf);
@@ -465,10 +478,13 @@
 }
 
 /* Put an array of words in to main memory */
-static inline int put_words(uint32_t addr, uint16_t *buf, int num)
+static inline int put_words(OHCIState *ohci,
+                            uint32_t addr, uint16_t *buf, int num)
 {
     int i;
 
+    addr += ohci->localmem_base;
+
     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
         uint16_t tmp = cpu_to_le16(*buf);
         cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
@@ -477,40 +493,63 @@
     return 1;
 }
 
-static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed)
+static inline int ohci_read_ed(OHCIState *ohci,
+                               uint32_t addr, struct ohci_ed *ed)
 {
-    return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+    return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
 }
 
-static inline int ohci_read_td(uint32_t addr, struct ohci_td *td)
+static inline int ohci_read_td(OHCIState *ohci,
+                               uint32_t addr, struct ohci_td *td)
 {
-    return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
+    return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
 }
 
-static inline int ohci_read_iso_td(uint32_t addr, struct ohci_iso_td *td)
+static inline int ohci_read_iso_td(OHCIState *ohci,
+                                   uint32_t addr, struct ohci_iso_td *td)
 {
-    return (get_dwords(addr, (uint32_t *)td, 4) &&
-            get_words(addr + 16, td->offset, 8));
+    return (get_dwords(ohci, addr, (uint32_t *)td, 4) &&
+            get_words(ohci, addr + 16, td->offset, 8));
 }
 
-static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed)
+static inline int ohci_read_hcca(OHCIState *ohci,
+                                 uint32_t addr, struct ohci_hcca *hcca)
 {
-    return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+    cpu_physical_memory_rw(addr + ohci->localmem_base,
+                           (uint8_t *)hcca, sizeof(*hcca), 0);
+    return 1;
 }
 
-static inline int ohci_put_td(uint32_t addr, struct ohci_td *td)
+static inline int ohci_put_ed(OHCIState *ohci,
+                              uint32_t addr, struct ohci_ed *ed)
 {
-    return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
+    return put_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
 }
 
-static inline int ohci_put_iso_td(uint32_t addr, struct ohci_iso_td *td)
+static inline int ohci_put_td(OHCIState *ohci,
+                              uint32_t addr, struct ohci_td *td)
 {
-    return (put_dwords(addr, (uint32_t *)td, 4) &&
-            put_words(addr + 16, td->offset, 8));
+    return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
+}
+
+static inline int ohci_put_iso_td(OHCIState *ohci,
+                                  uint32_t addr, struct ohci_iso_td *td)
+{
+    return (put_dwords(ohci, addr, (uint32_t *)td, 4) &&
+            put_words(ohci, addr + 16, td->offset, 8));
+}
+
+static inline int ohci_put_hcca(OHCIState *ohci,
+                                uint32_t addr, struct ohci_hcca *hcca)
+{
+    cpu_physical_memory_rw(addr + ohci->localmem_base,
+                           (uint8_t *)hcca, sizeof(*hcca), 1);
+    return 1;
 }
 
 /* Read/Write the contents of a TD from/to main memory.  */
-static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write)
+static void ohci_copy_td(OHCIState *ohci, struct ohci_td *td,
+                         uint8_t *buf, int len, int write)
 {
     uint32_t ptr;
     uint32_t n;
@@ -519,16 +558,17 @@
     n = 0x1000 - (ptr & 0xfff);
     if (n > len)
         n = len;
-    cpu_physical_memory_rw(ptr, buf, n, write);
+    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
     if (n == len)
         return;
     ptr = td->be & ~0xfffu;
     buf += n;
-    cpu_physical_memory_rw(ptr, buf, len - n, write);
+    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
 }
 
 /* Read/Write the contents of an ISO TD from/to main memory.  */
-static void ohci_copy_iso_td(uint32_t start_addr, uint32_t end_addr,
+static void ohci_copy_iso_td(OHCIState *ohci,
+                             uint32_t start_addr, uint32_t end_addr,
                              uint8_t *buf, int len, int write)
 {
     uint32_t ptr;
@@ -538,12 +578,12 @@
     n = 0x1000 - (ptr & 0xfff);
     if (n > len)
         n = len;
-    cpu_physical_memory_rw(ptr, buf, n, write);
+    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
     if (n == len)
         return;
     ptr = end_addr & ~0xfffu;
     buf += n;
-    cpu_physical_memory_rw(ptr, buf, len - n, write);
+    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
 }
 
 static void ohci_process_lists(OHCIState *ohci, int completion);
@@ -580,7 +620,7 @@
 
     addr = ed->head & OHCI_DPTR_MASK;
 
-    if (!ohci_read_iso_td(addr, &iso_td)) {
+    if (!ohci_read_iso_td(ohci, addr, &iso_td)) {
         printf("usb-ohci: ISO_TD read error at %x\n", addr);
         return 0;
     }
@@ -622,7 +662,7 @@
         i = OHCI_BM(iso_td.flags, TD_DI);
         if (i < ohci->done_count)
             ohci->done_count = i;
-        ohci_put_iso_td(addr, &iso_td);        
+        ohci_put_iso_td(ohci, addr, &iso_td);
         return 0;
     }
 
@@ -697,7 +737,7 @@
     }
 
     if (len && dir != OHCI_TD_DIR_IN) {
-        ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, len, 0);
+        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 0);
     }
 
     if (completion) {
@@ -733,7 +773,7 @@
     /* Writeback */
     if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
         /* IN transfer succeeded */
-        ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, ret, 1);
+        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 1);
         OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
                     OHCI_CC_NOERROR);
         OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
@@ -789,7 +829,7 @@
         if (i < ohci->done_count)
             ohci->done_count = i;
     }
-    ohci_put_iso_td(addr, &iso_td);
+    ohci_put_iso_td(ohci, addr, &iso_td);
     return 1;
 }
 
@@ -819,7 +859,7 @@
 #endif
         return 1;
     }
-    if (!ohci_read_td(addr, &td)) {
+    if (!ohci_read_td(ohci, addr, &td)) {
         fprintf(stderr, "usb-ohci: TD read error at %x\n", addr);
         return 0;
     }
@@ -860,7 +900,7 @@
         }
 
         if (len && dir != OHCI_TD_DIR_IN && !completion) {
-            ohci_copy_td(&td, ohci->usb_buf, len, 0);
+            ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0);
         }
     }
 
@@ -919,7 +959,7 @@
     }
     if (ret >= 0) {
         if (dir == OHCI_TD_DIR_IN) {
-            ohci_copy_td(&td, ohci->usb_buf, ret, 1);
+            ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1);
 #ifdef DEBUG_PACKET
             dprintf("  data:");
             for (i = 0; i < ret; i++)
@@ -988,7 +1028,7 @@
     i = OHCI_BM(td.flags, TD_DI);
     if (i < ohci->done_count)
         ohci->done_count = i;
-    ohci_put_td(addr, &td);
+    ohci_put_td(ohci, addr, &td);
     return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
 }
 
@@ -1006,7 +1046,7 @@
         return 0;
 
     for (cur = head; cur; cur = next_ed) {
-        if (!ohci_read_ed(cur, &ed)) {
+        if (!ohci_read_ed(ohci, cur, &ed)) {
             fprintf(stderr, "usb-ohci: ED read error at %x\n", cur);
             return 0;
         }
@@ -1047,7 +1087,7 @@
             }
         }
 
-        ohci_put_ed(cur, &ed);
+        ohci_put_ed(ohci, cur, &ed);
     }
 
     return active;
@@ -1088,7 +1128,7 @@
     OHCIState *ohci = opaque;
     struct ohci_hcca hcca;
 
-    cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 0);
+    ohci_read_hcca(ohci, ohci->hcca, &hcca);
 
     /* Process all the lists at the end of the frame */
     if (ohci->ctl & OHCI_CTL_PLE) {
@@ -1132,7 +1172,7 @@
     ohci_sof(ohci);
 
     /* Writeback HCCA */
-    cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 1);
+    ohci_put_hcca(ohci, ohci->hcca, &hcca);
 }
 
 /* Start sending SOF tokens across the USB bus, lists are processed in
@@ -1361,106 +1401,134 @@
 static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
 {
     OHCIState *ohci = ptr;
-
-    addr -= ohci->mem_base;
+    uint32_t retval;
 
     /* Only aligned reads are allowed on OHCI */
     if (addr & 3) {
         fprintf(stderr, "usb-ohci: Mis-aligned read\n");
         return 0xffffffff;
-    }
-
-    if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
+    } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
         /* HcRhPortStatus */
-        return ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
+        retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
+    } else {
+        switch (addr >> 2) {
+        case 0: /* HcRevision */
+            retval = 0x10;
+            break;
+
+        case 1: /* HcControl */
+            retval = ohci->ctl;
+            break;
+
+        case 2: /* HcCommandStatus */
+            retval = ohci->status;
+            break;
+
+        case 3: /* HcInterruptStatus */
+            retval = ohci->intr_status;
+            break;
+
+        case 4: /* HcInterruptEnable */
+        case 5: /* HcInterruptDisable */
+            retval = ohci->intr;
+            break;
+
+        case 6: /* HcHCCA */
+            retval = ohci->hcca;
+            break;
+
+        case 7: /* HcPeriodCurrentED */
+            retval = ohci->per_cur;
+            break;
+
+        case 8: /* HcControlHeadED */
+            retval = ohci->ctrl_head;
+            break;
+
+        case 9: /* HcControlCurrentED */
+            retval = ohci->ctrl_cur;
+            break;
+
+        case 10: /* HcBulkHeadED */
+            retval = ohci->bulk_head;
+            break;
+
+        case 11: /* HcBulkCurrentED */
+            retval = ohci->bulk_cur;
+            break;
+
+        case 12: /* HcDoneHead */
+            retval = ohci->done;
+            break;
+
+        case 13: /* HcFmInterretval */
+            retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi);
+            break;
+
+        case 14: /* HcFmRemaining */
+            retval = ohci_get_frame_remaining(ohci);
+            break;
+
+        case 15: /* HcFmNumber */
+            retval = ohci->frame_number;
+            break;
+
+        case 16: /* HcPeriodicStart */
+            retval = ohci->pstart;
+            break;
+
+        case 17: /* HcLSThreshold */
+            retval = ohci->lst;
+            break;
+
+        case 18: /* HcRhDescriptorA */
+            retval = ohci->rhdesc_a;
+            break;
+
+        case 19: /* HcRhDescriptorB */
+            retval = ohci->rhdesc_b;
+            break;
+
+        case 20: /* HcRhStatus */
+            retval = ohci->rhstatus;
+            break;
+
+        /* PXA27x specific registers */
+        case 24: /* HcStatus */
+            retval = ohci->hstatus & ohci->hmask;
+            break;
+
+        case 25: /* HcHReset */
+            retval = ohci->hreset;
+            break;
+
+        case 26: /* HcHInterruptEnable */
+            retval = ohci->hmask;
+            break;
+
+        case 27: /* HcHInterruptTest */
+            retval = ohci->htest;
+            break;
+
+        default:
+            fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr);
+            retval = 0xffffffff;
+        }
     }
 
-    switch (addr >> 2) {
-    case 0: /* HcRevision */
-        return 0x10;
-
-    case 1: /* HcControl */
-        return ohci->ctl;
-
-    case 2: /* HcCommandStatus */
-        return ohci->status;
-
-    case 3: /* HcInterruptStatus */
-        return ohci->intr_status;
-
-    case 4: /* HcInterruptEnable */
-    case 5: /* HcInterruptDisable */
-        return ohci->intr;
-
-    case 6: /* HcHCCA */
-        return ohci->hcca;
-
-    case 7: /* HcPeriodCurrentED */
-        return ohci->per_cur;
-
-    case 8: /* HcControlHeadED */
-        return ohci->ctrl_head;
-
-    case 9: /* HcControlCurrentED */
-        return ohci->ctrl_cur;
-
-    case 10: /* HcBulkHeadED */
-        return ohci->bulk_head;
-
-    case 11: /* HcBulkCurrentED */
-        return ohci->bulk_cur;
-
-    case 12: /* HcDoneHead */
-        return ohci->done;
-
-    case 13: /* HcFmInterval */
-        return (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi);
-
-    case 14: /* HcFmRemaining */
-        return ohci_get_frame_remaining(ohci);
-
-    case 15: /* HcFmNumber */
-        return ohci->frame_number;
-
-    case 16: /* HcPeriodicStart */
-        return ohci->pstart;
-
-    case 17: /* HcLSThreshold */
-        return ohci->lst;
-
-    case 18: /* HcRhDescriptorA */
-        return ohci->rhdesc_a;
-
-    case 19: /* HcRhDescriptorB */
-        return ohci->rhdesc_b;
-
-    case 20: /* HcRhStatus */
-        return ohci->rhstatus;
-
-    /* PXA27x specific registers */
-    case 24: /* HcStatus */
-        return ohci->hstatus & ohci->hmask;
-
-    case 25: /* HcHReset */
-        return ohci->hreset;
-
-    case 26: /* HcHInterruptEnable */
-        return ohci->hmask;
-
-    case 27: /* HcHInterruptTest */
-        return ohci->htest;
-
-    default:
-        fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr);
-        return 0xffffffff;
-    }
+#ifdef TARGET_WORDS_BIGENDIAN
+    retval = bswap32(retval);
+#endif
+    return retval;
 }
 
 static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
 {
     OHCIState *ohci = ptr;
 
-    addr -= ohci->mem_base;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
 
     /* Only aligned reads are allowed on OHCI */
     if (addr & 3) {
@@ -1593,7 +1661,8 @@
 };
 
 static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
-            qemu_irq irq, enum ohci_type type, const char *name)
+                          qemu_irq irq, enum ohci_type type,
+                          const char *name, uint32_t localmem_base)
 {
     int i;
 
@@ -1613,7 +1682,8 @@
                 usb_frame_time, usb_bit_time);
     }
 
-    ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
+    ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci);
+    ohci->localmem_base = localmem_base;
     ohci->name = name;
 
     ohci->irq = irq;
@@ -1625,7 +1695,7 @@
     }
 
     ohci->async_td = 0;
-    qemu_register_reset(ohci_reset, ohci);
+    qemu_register_reset(ohci_reset, 0, ohci);
     ohci_reset(ohci);
 }
 
@@ -1638,15 +1708,12 @@
             uint32_t addr, uint32_t size, int type)
 {
     OHCIPCIState *ohci = (OHCIPCIState *)pci_dev;
-    ohci->state.mem_base = addr;
     cpu_register_physical_memory(addr, size, ohci->state.mem);
 }
 
 void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
 {
     OHCIPCIState *ohci;
-    int vid = 0x106b;
-    int did = 0x003f;
 
     ohci = (OHCIPCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci),
                                                devfn, NULL, NULL);
@@ -1655,19 +1722,17 @@
         return;
     }
 
-    ohci->pci_dev.config[0x00] = vid & 0xff;
-    ohci->pci_dev.config[0x01] = (vid >> 8) & 0xff;
-    ohci->pci_dev.config[0x02] = did & 0xff;
-    ohci->pci_dev.config[0x03] = (did >> 8) & 0xff;
+    pci_config_set_vendor_id(ohci->pci_dev.config, PCI_VENDOR_ID_APPLE);
+    pci_config_set_device_id(ohci->pci_dev.config,
+                             PCI_DEVICE_ID_APPLE_IPID_USB);
     ohci->pci_dev.config[0x09] = 0x10; /* OHCI */
-    ohci->pci_dev.config[0x0a] = 0x3;
-    ohci->pci_dev.config[0x0b] = 0xc;
+    pci_config_set_class(ohci->pci_dev.config, PCI_CLASS_SERIAL_USB);
     ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
 
     usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
-                  OHCI_TYPE_PCI, ohci->pci_dev.name);
+                  OHCI_TYPE_PCI, ohci->pci_dev.name, 0);
 
-    pci_register_io_region((struct PCIDevice *)ohci, 0, 256,
+    pci_register_bar((struct PCIDevice *)ohci, 0, 256,
                            PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
 }
 
@@ -1677,8 +1742,19 @@
     OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
 
     usb_ohci_init(ohci, num_ports, devfn, irq,
-                  OHCI_TYPE_PXA, "OHCI USB");
-    ohci->mem_base = base;
+                  OHCI_TYPE_PXA, "OHCI USB", 0);
 
-    cpu_register_physical_memory(ohci->mem_base, 0x1000, ohci->mem);
+    cpu_register_physical_memory(base, 0x1000, ohci->mem);
 }
+
+void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
+                         int num_ports, int devfn, qemu_irq irq)
+{
+    OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
+
+    usb_ohci_init(ohci, num_ports, devfn, irq,
+                  OHCI_TYPE_SM501, "OHCI USB", localmem_base);
+
+    cpu_register_physical_memory(mmio_base, 0x1000, ohci->mem);
+}
+
diff --git a/hw/usb.h b/hw/usb.h
index 1a353bb..8381795 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -21,6 +21,12 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+
+#ifndef _HW_USB_H
+#define _HW_USB_H
+
+#include "block.h"
+
 #define USB_TOKEN_SETUP 0x2d
 #define USB_TOKEN_IN    0x69 /* device -> host */
 #define USB_TOKEN_OUT   0xe1 /* host -> device */
@@ -241,19 +247,24 @@
 /* usb-linux.c */
 USBDevice *usb_host_device_open(const char *devname);
 int usb_host_device_close(const char *devname);
-void usb_host_info(void);
+void usb_host_info(Monitor *mon);
 
 /* usb-hid.c */
 USBDevice *usb_mouse_init(void);
 USBDevice *usb_tablet_init(void);
 USBDevice *usb_keyboard_init(void);
+void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
 
 /* usb-msd.c */
 USBDevice *usb_msd_init(const char *filename);
+BlockDriverState *usb_msd_get_bdrv(USBDevice *dev);
 
 /* usb-net.c */
 USBDevice *usb_net_init(NICInfo *nd);
 
+/* usb-bt.c */
+USBDevice *usb_bt_init(HCIInfo *hci);
+
 /* usb-wacom.c */
 USBDevice *usb_wacom_init(void);
 
@@ -284,8 +295,10 @@
     __musb_irq_max,
 };
 
-struct musb_s;
-struct musb_s *musb_init(qemu_irq *irqs);
-uint32_t musb_core_intr_get(struct musb_s *s);
-void musb_core_intr_clear(struct musb_s *s, uint32_t mask);
-void musb_set_size(struct musb_s *s, int epnum, int size, int is_tx);
+typedef struct MUSBState MUSBState;
+MUSBState *musb_init(qemu_irq *irqs);
+uint32_t musb_core_intr_get(MUSBState *s);
+void musb_core_intr_clear(MUSBState *s, uint32_t mask);
+void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
+
+#endif /* _HW_USB_H */
diff --git a/hw/watchdog.c b/hw/watchdog.c
new file mode 100644
index 0000000..9a28621
--- /dev/null
+++ b/hw/watchdog.c
@@ -0,0 +1,138 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "sys-queue.h"
+#include "sysemu.h"
+#include "hw/watchdog.h"
+
+static LIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
+
+void watchdog_add_model(WatchdogTimerModel *model)
+{
+    LIST_INSERT_HEAD(&watchdog_list, model, entry);
+}
+
+/* Returns:
+ *   0 = continue
+ *   1 = exit program with error
+ *   2 = exit program without error
+ */
+int select_watchdog(const char *p)
+{
+    WatchdogTimerModel *model;
+
+    if (watchdog) {
+        fprintf(stderr,
+                 "qemu: only one watchdog option may be given\n");
+        return 1;
+    }
+
+    /* -watchdog ? lists available devices and exits cleanly. */
+    if (strcmp(p, "?") == 0) {
+        LIST_FOREACH(model, &watchdog_list, entry) {
+            fprintf(stderr, "\t%s\t%s\n",
+                     model->wdt_name, model->wdt_description);
+        }
+        return 2;
+    }
+
+    LIST_FOREACH(model, &watchdog_list, entry) {
+        if (strcasecmp(model->wdt_name, p) == 0) {
+            watchdog = model;
+            return 0;
+        }
+    }
+
+    fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
+    LIST_FOREACH(model, &watchdog_list, entry) {
+        fprintf(stderr, "\t%s\t%s\n",
+                 model->wdt_name, model->wdt_description);
+    }
+    return 1;
+}
+
+int select_watchdog_action(const char *p)
+{
+    if (strcasecmp(p, "reset") == 0)
+        watchdog_action = WDT_RESET;
+    else if (strcasecmp(p, "shutdown") == 0)
+        watchdog_action = WDT_SHUTDOWN;
+    else if (strcasecmp(p, "poweroff") == 0)
+        watchdog_action = WDT_POWEROFF;
+    else if (strcasecmp(p, "pause") == 0)
+        watchdog_action = WDT_PAUSE;
+    else if (strcasecmp(p, "debug") == 0)
+        watchdog_action = WDT_DEBUG;
+    else if (strcasecmp(p, "none") == 0)
+        watchdog_action = WDT_NONE;
+    else
+        return -1;
+
+    return 0;
+}
+
+/* This actually performs the "action" once a watchdog has expired,
+ * ie. reboot, shutdown, exit, etc.
+ */
+void watchdog_perform_action(void)
+{
+    switch(watchdog_action) {
+    case WDT_RESET:             /* same as 'system_reset' in monitor */
+        qemu_system_reset_request();
+        break;
+
+    case WDT_SHUTDOWN:          /* same as 'system_powerdown' in monitor */
+        qemu_system_powerdown_request();
+        break;
+
+    case WDT_POWEROFF:          /* same as 'quit' command in monitor */
+        exit(0);
+        break;
+
+    case WDT_PAUSE:             /* same as 'stop' command in monitor */
+        vm_stop(0);
+        break;
+
+    case WDT_DEBUG:
+        fprintf(stderr, "watchdog: timer fired\n");
+        break;
+
+    case WDT_NONE:
+        break;
+    }
+}
+
+void watchdog_pc_init(PCIBus *pci_bus)
+{
+    if (watchdog)
+        watchdog->wdt_pc_init(pci_bus);
+}
+
+void register_watchdogs(void)
+{
+#if 0
+    wdt_ib700_init();
+    wdt_i6300esb_init();
+#endif
+}
diff --git a/hw/watchdog.h b/hw/watchdog.h
new file mode 100644
index 0000000..c2b2b36
--- /dev/null
+++ b/hw/watchdog.h
@@ -0,0 +1,65 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#ifndef QEMU_WATCHDOG_H
+#define QEMU_WATCHDOG_H
+
+extern void wdt_i6300esb_init(void);
+extern void wdt_ib700_init(void);
+
+/* Possible values for action parameter. */
+#define WDT_RESET        1	/* Hard reset. */
+#define WDT_SHUTDOWN     2	/* Shutdown. */
+#define WDT_POWEROFF     3	/* Quit. */
+#define WDT_PAUSE        4	/* Pause. */
+#define WDT_DEBUG        5	/* Prints a message and continues running. */
+#define WDT_NONE         6	/* Do nothing. */
+
+struct WatchdogTimerModel {
+    LIST_ENTRY(WatchdogTimerModel) entry;
+
+    /* Short name of the device - used to select it on the command line. */
+    const char *wdt_name;
+    /* Longer description (eg. manufacturer and full model number). */
+    const char *wdt_description;
+
+    /* This callback should create/register the device.  It is called
+     * indirectly from hw/pc.c when the virtual PC is being set up.
+     */
+    void (*wdt_pc_init)(PCIBus *pci_bus);
+};
+typedef struct WatchdogTimerModel WatchdogTimerModel;
+
+/* in vl.c */
+extern WatchdogTimerModel *watchdog;
+extern int watchdog_action;
+
+/* in hw/watchdog.c */
+extern int select_watchdog(const char *p);
+extern int select_watchdog_action(const char *action);
+extern void watchdog_add_model(WatchdogTimerModel *model);
+extern void watchdog_perform_action(void);
+extern void watchdog_pc_init(PCIBus *pci_bus);
+extern void register_watchdogs(void);
+
+#endif /* QEMU_WATCHDOG_H */
diff --git a/hw/xen.h b/hw/xen.h
new file mode 100644
index 0000000..780dcf7
--- /dev/null
+++ b/hw/xen.h
@@ -0,0 +1,21 @@
+#ifndef QEMU_HW_XEN_H
+#define QEMU_HW_XEN_H 1
+/*
+ * public xen header
+ *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ *   must not depend on any xen headers being present in
+ *   /usr/include/xen, so it can be included unconditionally.
+ */
+#include <inttypes.h>
+
+/* xen-machine.c */
+enum xen_mode {
+    XEN_EMULATE = 0,  // xen emulation, using xenner (default)
+    XEN_CREATE,       // create xen domain
+    XEN_ATTACH        // attach to xen domain created by xend
+};
+
+extern uint32_t xen_domid;
+extern enum xen_mode xen_mode;
+
+#endif /* QEMU_HW_XEN_H */
diff --git a/hxtool b/hxtool
new file mode 100755
index 0000000..885abe2
--- /dev/null
+++ b/hxtool
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+hxtoh()
+{
+    flag=1
+    while read -r str; do
+        case $str in
+            HXCOMM*)
+            ;;
+            STEXI*|ETEXI*) flag=$(($flag^1))
+            ;;
+            *)
+            test $flag -eq 1 && printf "%s\n" "$str"
+            ;;
+        esac
+    done
+}
+
+hxtotexi()
+{
+    flag=0
+    while read -r str; do
+        case "$str" in
+            HXCOMM*)
+            ;;
+            STEXI*|ETEXI*) flag=$(($flag^1))
+            ;;
+            DEFHEADING*)
+            echo $(expr "$str" : "DEFHEADING(\(.*\))")
+            ;;
+            *)
+            test $flag -eq 1 && echo $str
+            ;;
+        esac
+    done
+}
+
+case "$1" in
+"-h") hxtoh ;;
+"-t") hxtotexi ;;
+*) exit 1 ;;
+esac
+
+exit 0
diff --git a/i386-dis.c b/i386-dis.c
index 7b44179..87c8b9d 100644
--- a/i386-dis.c
+++ b/i386-dis.c
@@ -1,117 +1,243 @@
+/* opcodes/i386-dis.c r1.126 */
 /* Print i386 instructions for GDB, the GNU debugger.
    Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2001
-   Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
-This file is part of GDB.
+   This file is part of GDB.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-/*
- * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
- * July 1988
- *  modified by John Hassey (hassey@dg-rtp.dg.com)
- *  x86-64 support added by Jan Hubicka (jh@suse.cz)
- */
+/* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
+   July 1988
+    modified by John Hassey (hassey@dg-rtp.dg.com)
+    x86-64 support added by Jan Hubicka (jh@suse.cz)
+    VIA PadLock support by Michal Ludvig (mludvig@suse.cz).  */
 
-/*
- * The main tables describing the instructions is essentially a copy
- * of the "Opcode Map" chapter (Appendix A) of the Intel 80386
- * Programmers Manual.  Usually, there is a capital letter, followed
- * by a small letter.  The capital letter tell the addressing mode,
- * and the small letter tells about the operand size.  Refer to
- * the Intel manual for details.
- */
+/* The main tables describing the instructions is essentially a copy
+   of the "Opcode Map" chapter (Appendix A) of the Intel 80386
+   Programmers Manual.  Usually, there is a capital letter, followed
+   by a small letter.  The capital letter tell the addressing mode,
+   and the small letter tells about the operand size.  Refer to
+   the Intel manual for details.  */
 
 #include <stdlib.h>
 #include "dis-asm.h"
-#include "qemu-common.h"
+/* include/opcode/i386.h r1.78 */
 
-#define MAXLEN 20
+/* opcode/i386.h -- Intel 80386 opcode macros
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
+
+   This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* The SystemV/386 SVR3.2 assembler, and probably all AT&T derived
+   ix86 Unix assemblers, generate floating point instructions with
+   reversed source and destination registers in certain cases.
+   Unfortunately, gcc and possibly many other programs use this
+   reversed syntax, so we're stuck with it.
+
+   eg. `fsub %st(3),%st' results in st = st - st(3) as expected, but
+   `fsub %st,%st(3)' results in st(3) = st - st(3), rather than
+   the expected st(3) = st(3) - st
+
+   This happens with all the non-commutative arithmetic floating point
+   operations with two register operands, where the source register is
+   %st, and destination register is %st(i).
+
+   The affected opcode map is dceX, dcfX, deeX, defX.  */
+
+#ifndef SYSV386_COMPAT
+/* Set non-zero for broken, compatible instructions.  Set to zero for
+   non-broken opcodes at your peril.  gcc generates SystemV/386
+   compatible instructions.  */
+#define SYSV386_COMPAT 1
+#endif
+#ifndef OLDGCC_COMPAT
+/* Set non-zero to cater for old (<= 2.8.1) versions of gcc that could
+   generate nonsense fsubp, fsubrp, fdivp and fdivrp with operands
+   reversed.  */
+#define OLDGCC_COMPAT SYSV386_COMPAT
+#endif
+
+#define MOV_AX_DISP32 0xa0
+#define POP_SEG_SHORT 0x07
+#define JUMP_PC_RELATIVE 0xeb
+#define INT_OPCODE  0xcd
+#define INT3_OPCODE 0xcc
+/* The opcode for the fwait instruction, which disassembler treats as a
+   prefix when it can.  */
+#define FWAIT_OPCODE 0x9b
+#define ADDR_PREFIX_OPCODE 0x67
+#define DATA_PREFIX_OPCODE 0x66
+#define LOCK_PREFIX_OPCODE 0xf0
+#define CS_PREFIX_OPCODE 0x2e
+#define DS_PREFIX_OPCODE 0x3e
+#define ES_PREFIX_OPCODE 0x26
+#define FS_PREFIX_OPCODE 0x64
+#define GS_PREFIX_OPCODE 0x65
+#define SS_PREFIX_OPCODE 0x36
+#define REPNE_PREFIX_OPCODE 0xf2
+#define REPE_PREFIX_OPCODE  0xf3
+
+#define TWO_BYTE_OPCODE_ESCAPE 0x0f
+#define NOP_OPCODE (char) 0x90
+
+/* register numbers */
+#define EBP_REG_NUM 5
+#define ESP_REG_NUM 4
+
+/* modrm_byte.regmem for twobyte escape */
+#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM
+/* index_base_byte.index for no index register addressing */
+#define NO_INDEX_REGISTER ESP_REG_NUM
+/* index_base_byte.base for no base register addressing */
+#define NO_BASE_REGISTER EBP_REG_NUM
+#define NO_BASE_REGISTER_16 6
+
+/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */
+#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */
+#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG)
+
+/* x86-64 extension prefix.  */
+#define REX_OPCODE	0x40
+
+/* Indicates 64 bit operand size.  */
+#define REX_W	8
+/* High extension to reg field of modrm byte.  */
+#define REX_R	4
+/* High extension to SIB index field.  */
+#define REX_X	2
+/* High extension to base field of modrm or SIB, or reg field of opcode.  */
+#define REX_B	1
+
+/* max operands per insn */
+#define MAX_OPERANDS 4
+
+/* max immediates per insn (lcall, ljmp, insertq, extrq) */
+#define MAX_IMMEDIATE_OPERANDS 2
+
+/* max memory refs per insn (string ops) */
+#define MAX_MEMORY_OPERANDS 2
+
+/* max size of insn mnemonics.  */
+#define MAX_MNEM_SIZE 16
+
+/* max size of register name in insn mnemonics.  */
+#define MAX_REG_NAME_SIZE 8
+
+/* opcodes/i386-dis.c r1.126 */
+#include "qemu-common.h"
 
 #include <setjmp.h>
 
-#ifndef UNIXWARE_COMPAT
-/* Set non-zero for broken, compatible instructions.  Set to zero for
-   non-broken opcodes.  */
-#define UNIXWARE_COMPAT 1
-#endif
-
-static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
-static void ckprefix PARAMS ((void));
-static const char *prefix_name PARAMS ((int, int));
-static int print_insn PARAMS ((bfd_vma, disassemble_info *));
-static void dofloat PARAMS ((int));
-static void OP_ST PARAMS ((int, int));
-static void OP_STi  PARAMS ((int, int));
-static int putop PARAMS ((const char *, int));
-static void oappend PARAMS ((const char *));
-static void append_seg PARAMS ((void));
-static void OP_indirE PARAMS ((int, int));
-static void print_operand_value (char *buf, size_t bufsize, int hex,
-                                 bfd_vma disp);
-static void OP_E PARAMS ((int, int));
-static void OP_G PARAMS ((int, int));
-static bfd_vma get64 PARAMS ((void));
-static bfd_signed_vma get32 PARAMS ((void));
-static bfd_signed_vma get32s PARAMS ((void));
-static int get16 PARAMS ((void));
-static void set_op PARAMS ((bfd_vma, int));
-static void OP_REG PARAMS ((int, int));
-static void OP_IMREG PARAMS ((int, int));
-static void OP_I PARAMS ((int, int));
-static void OP_I64 PARAMS ((int, int));
-static void OP_sI PARAMS ((int, int));
-static void OP_J PARAMS ((int, int));
-static void OP_SEG PARAMS ((int, int));
-static void OP_DIR PARAMS ((int, int));
-static void OP_OFF PARAMS ((int, int));
-static void OP_OFF64 PARAMS ((int, int));
-static void ptr_reg PARAMS ((int, int));
-static void OP_ESreg PARAMS ((int, int));
-static void OP_DSreg PARAMS ((int, int));
-static void OP_C PARAMS ((int, int));
-static void OP_D PARAMS ((int, int));
-static void OP_T PARAMS ((int, int));
-static void OP_Rd PARAMS ((int, int));
-static void OP_MMX PARAMS ((int, int));
-static void OP_XMM PARAMS ((int, int));
-static void OP_EM PARAMS ((int, int));
-static void OP_EX PARAMS ((int, int));
-static void OP_MS PARAMS ((int, int));
-static void OP_XS PARAMS ((int, int));
-static void OP_3DNowSuffix PARAMS ((int, int));
-static void OP_SIMD_Suffix PARAMS ((int, int));
-static void SIMD_Fixup PARAMS ((int, int));
-static void BadOp PARAMS ((void));
+static int fetch_data (struct disassemble_info *, bfd_byte *);
+static void ckprefix (void);
+static const char *prefix_name (int, int);
+static int print_insn (bfd_vma, disassemble_info *);
+static void dofloat (int);
+static void OP_ST (int, int);
+static void OP_STi (int, int);
+static int putop (const char *, int);
+static void oappend (const char *);
+static void append_seg (void);
+static void OP_indirE (int, int);
+static void print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp);
+static void print_displacement (char *, bfd_vma);
+static void OP_E (int, int);
+static void OP_G (int, int);
+static bfd_vma get64 (void);
+static bfd_signed_vma get32 (void);
+static bfd_signed_vma get32s (void);
+static int get16 (void);
+static void set_op (bfd_vma, int);
+static void OP_REG (int, int);
+static void OP_IMREG (int, int);
+static void OP_I (int, int);
+static void OP_I64 (int, int);
+static void OP_sI (int, int);
+static void OP_J (int, int);
+static void OP_SEG (int, int);
+static void OP_DIR (int, int);
+static void OP_OFF (int, int);
+static void OP_OFF64 (int, int);
+static void ptr_reg (int, int);
+static void OP_ESreg (int, int);
+static void OP_DSreg (int, int);
+static void OP_C (int, int);
+static void OP_D (int, int);
+static void OP_T (int, int);
+static void OP_R (int, int);
+static void OP_MMX (int, int);
+static void OP_XMM (int, int);
+static void OP_EM (int, int);
+static void OP_EX (int, int);
+static void OP_EMC (int,int);
+static void OP_MXC (int,int);
+static void OP_MS (int, int);
+static void OP_XS (int, int);
+static void OP_M (int, int);
+static void OP_VMX (int, int);
+static void OP_0fae (int, int);
+static void OP_0f07 (int, int);
+static void NOP_Fixup1 (int, int);
+static void NOP_Fixup2 (int, int);
+static void OP_3DNowSuffix (int, int);
+static void OP_SIMD_Suffix (int, int);
+static void SIMD_Fixup (int, int);
+static void PNI_Fixup (int, int);
+static void SVME_Fixup (int, int);
+static void INVLPG_Fixup (int, int);
+static void BadOp (void);
+static void VMX_Fixup (int, int);
+static void REP_Fixup (int, int);
+static void CMPXCHG8B_Fixup (int, int);
+static void XMM_Fixup (int, int);
+static void CRC32_Fixup (int, int);
 
 struct dis_private {
   /* Points to first byte not fetched.  */
   bfd_byte *max_fetched;
-  bfd_byte the_buffer[MAXLEN];
+  bfd_byte the_buffer[MAX_MNEM_SIZE];
   bfd_vma insn_start;
   int orig_sizeflag;
   jmp_buf bailout;
 };
 
-/* The opcode for the fwait instruction, which we treat as a prefix
-   when we can.  */
-#define FWAIT_OPCODE (0x9b)
+enum address_mode
+{
+  mode_16bit,
+  mode_32bit,
+  mode_64bit
+};
 
-/* Set to 1 for 64bit mode disassembly.  */
-static int mode_64bit;
+static enum address_mode address_mode;
 
 /* Flags for the prefixes for the current instruction.  See below.  */
 static int prefixes;
@@ -120,10 +246,6 @@
 static int rex;
 /* Bits of REX we've already used.  */
 static int rex_used;
-#define REX_MODE64	8
-#define REX_EXTX	4
-#define REX_EXTY	2
-#define REX_EXTZ	1
 /* Mark parts used in the REX prefix.  When we are testing for
    empty prefix (for 8bit register REX extension), just mask it
    out.  Otherwise test for REX bit is excuse for existence of REX
@@ -131,9 +253,12 @@
 #define USED_REX(value)					\
   {							\
     if (value)						\
-      rex_used |= (rex & value) ? (value) | 0x40 : 0;	\
+      {							\
+	if ((rex & value))				\
+	  rex_used |= (value) | REX_OPCODE;		\
+      }							\
     else						\
-      rex_used |= 0x40;					\
+      rex_used |= REX_OPCODE;				\
   }
 
 /* Flags for prefixes which we somehow handled when printing the
@@ -162,24 +287,25 @@
    ? 1 : fetch_data ((info), (addr)))
 
 static int
-fetch_data (info, addr)
-     struct disassemble_info *info;
-     bfd_byte *addr;
+fetch_data (struct disassemble_info *info, bfd_byte *addr)
 {
   int status;
   struct dis_private *priv = (struct dis_private *) info->private_data;
   bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
 
-  status = (*info->read_memory_func) (start,
-				      priv->max_fetched,
-				      addr - priv->max_fetched,
-				      info);
+  if (addr <= priv->the_buffer + MAX_MNEM_SIZE)
+    status = (*info->read_memory_func) (start,
+					priv->max_fetched,
+					addr - priv->max_fetched,
+					info);
+  else
+    status = -1;
   if (status != 0)
     {
       /* If we did manage to read at least one byte, then
-         print_insn_i386 will do something sensible.  Otherwise, print
-         an error.  We do that here because this is where we know
-         STATUS.  */
+	 print_insn_i386 will do something sensible.  Otherwise, print
+	 an error.  We do that here because this is where we know
+	 STATUS.  */
       if (priv->max_fetched == priv->the_buffer)
 	(*info->memory_error_func) (status, start, info);
       longjmp (priv->bailout, 1);
@@ -189,115 +315,142 @@
   return 1;
 }
 
-#define XX NULL, 0
+#define XX { NULL, 0 }
 
-#define Eb OP_E, b_mode
-#define Ev OP_E, v_mode
-#define Ed OP_E, d_mode
-#define indirEb OP_indirE, b_mode
-#define indirEv OP_indirE, v_mode
-#define Ew OP_E, w_mode
-#define Ma OP_E, v_mode
-#define M OP_E, 0		/* lea, lgdt, etc. */
-#define Mp OP_E, 0		/* 32 or 48 bit memory operand for LDS, LES etc */
-#define Gb OP_G, b_mode
-#define Gv OP_G, v_mode
-#define Gd OP_G, d_mode
-#define Gw OP_G, w_mode
-#define Rd OP_Rd, d_mode
-#define Rm OP_Rd, m_mode
-#define Ib OP_I, b_mode
-#define sIb OP_sI, b_mode	/* sign extened byte */
-#define Iv OP_I, v_mode
-#define Iq OP_I, q_mode
-#define Iv64 OP_I64, v_mode
-#define Iw OP_I, w_mode
-#define Jb OP_J, b_mode
-#define Jv OP_J, v_mode
-#define Cm OP_C, m_mode
-#define Dm OP_D, m_mode
-#define Td OP_T, d_mode
+#define Eb { OP_E, b_mode }
+#define Ev { OP_E, v_mode }
+#define Ed { OP_E, d_mode }
+#define Edq { OP_E, dq_mode }
+#define Edqw { OP_E, dqw_mode }
+#define Edqb { OP_E, dqb_mode }
+#define Edqd { OP_E, dqd_mode }
+#define indirEv { OP_indirE, stack_v_mode }
+#define indirEp { OP_indirE, f_mode }
+#define stackEv { OP_E, stack_v_mode }
+#define Em { OP_E, m_mode }
+#define Ew { OP_E, w_mode }
+#define M { OP_M, 0 }		/* lea, lgdt, etc. */
+#define Ma { OP_M, v_mode }
+#define Mp { OP_M, f_mode }		/* 32 or 48 bit memory operand for LDS, LES etc */
+#define Mq { OP_M, q_mode }
+#define Gb { OP_G, b_mode }
+#define Gv { OP_G, v_mode }
+#define Gd { OP_G, d_mode }
+#define Gdq { OP_G, dq_mode }
+#define Gm { OP_G, m_mode }
+#define Gw { OP_G, w_mode }
+#define Rd { OP_R, d_mode }
+#define Rm { OP_R, m_mode }
+#define Ib { OP_I, b_mode }
+#define sIb { OP_sI, b_mode }	/* sign extened byte */
+#define Iv { OP_I, v_mode }
+#define Iq { OP_I, q_mode }
+#define Iv64 { OP_I64, v_mode }
+#define Iw { OP_I, w_mode }
+#define I1 { OP_I, const_1_mode }
+#define Jb { OP_J, b_mode }
+#define Jv { OP_J, v_mode }
+#define Cm { OP_C, m_mode }
+#define Dm { OP_D, m_mode }
+#define Td { OP_T, d_mode }
 
-#define RMeAX OP_REG, eAX_reg
-#define RMeBX OP_REG, eBX_reg
-#define RMeCX OP_REG, eCX_reg
-#define RMeDX OP_REG, eDX_reg
-#define RMeSP OP_REG, eSP_reg
-#define RMeBP OP_REG, eBP_reg
-#define RMeSI OP_REG, eSI_reg
-#define RMeDI OP_REG, eDI_reg
-#define RMrAX OP_REG, rAX_reg
-#define RMrBX OP_REG, rBX_reg
-#define RMrCX OP_REG, rCX_reg
-#define RMrDX OP_REG, rDX_reg
-#define RMrSP OP_REG, rSP_reg
-#define RMrBP OP_REG, rBP_reg
-#define RMrSI OP_REG, rSI_reg
-#define RMrDI OP_REG, rDI_reg
-#define RMAL OP_REG, al_reg
-#define RMAL OP_REG, al_reg
-#define RMCL OP_REG, cl_reg
-#define RMDL OP_REG, dl_reg
-#define RMBL OP_REG, bl_reg
-#define RMAH OP_REG, ah_reg
-#define RMCH OP_REG, ch_reg
-#define RMDH OP_REG, dh_reg
-#define RMBH OP_REG, bh_reg
-#define RMAX OP_REG, ax_reg
-#define RMDX OP_REG, dx_reg
+#define RMeAX { OP_REG, eAX_reg }
+#define RMeBX { OP_REG, eBX_reg }
+#define RMeCX { OP_REG, eCX_reg }
+#define RMeDX { OP_REG, eDX_reg }
+#define RMeSP { OP_REG, eSP_reg }
+#define RMeBP { OP_REG, eBP_reg }
+#define RMeSI { OP_REG, eSI_reg }
+#define RMeDI { OP_REG, eDI_reg }
+#define RMrAX { OP_REG, rAX_reg }
+#define RMrBX { OP_REG, rBX_reg }
+#define RMrCX { OP_REG, rCX_reg }
+#define RMrDX { OP_REG, rDX_reg }
+#define RMrSP { OP_REG, rSP_reg }
+#define RMrBP { OP_REG, rBP_reg }
+#define RMrSI { OP_REG, rSI_reg }
+#define RMrDI { OP_REG, rDI_reg }
+#define RMAL { OP_REG, al_reg }
+#define RMAL { OP_REG, al_reg }
+#define RMCL { OP_REG, cl_reg }
+#define RMDL { OP_REG, dl_reg }
+#define RMBL { OP_REG, bl_reg }
+#define RMAH { OP_REG, ah_reg }
+#define RMCH { OP_REG, ch_reg }
+#define RMDH { OP_REG, dh_reg }
+#define RMBH { OP_REG, bh_reg }
+#define RMAX { OP_REG, ax_reg }
+#define RMDX { OP_REG, dx_reg }
 
-#define eAX OP_IMREG, eAX_reg
-#define eBX OP_IMREG, eBX_reg
-#define eCX OP_IMREG, eCX_reg
-#define eDX OP_IMREG, eDX_reg
-#define eSP OP_IMREG, eSP_reg
-#define eBP OP_IMREG, eBP_reg
-#define eSI OP_IMREG, eSI_reg
-#define eDI OP_IMREG, eDI_reg
-#define AL OP_IMREG, al_reg
-#define AL OP_IMREG, al_reg
-#define CL OP_IMREG, cl_reg
-#define DL OP_IMREG, dl_reg
-#define BL OP_IMREG, bl_reg
-#define AH OP_IMREG, ah_reg
-#define CH OP_IMREG, ch_reg
-#define DH OP_IMREG, dh_reg
-#define BH OP_IMREG, bh_reg
-#define AX OP_IMREG, ax_reg
-#define DX OP_IMREG, dx_reg
-#define indirDX OP_IMREG, indir_dx_reg
+#define eAX { OP_IMREG, eAX_reg }
+#define eBX { OP_IMREG, eBX_reg }
+#define eCX { OP_IMREG, eCX_reg }
+#define eDX { OP_IMREG, eDX_reg }
+#define eSP { OP_IMREG, eSP_reg }
+#define eBP { OP_IMREG, eBP_reg }
+#define eSI { OP_IMREG, eSI_reg }
+#define eDI { OP_IMREG, eDI_reg }
+#define AL { OP_IMREG, al_reg }
+#define CL { OP_IMREG, cl_reg }
+#define DL { OP_IMREG, dl_reg }
+#define BL { OP_IMREG, bl_reg }
+#define AH { OP_IMREG, ah_reg }
+#define CH { OP_IMREG, ch_reg }
+#define DH { OP_IMREG, dh_reg }
+#define BH { OP_IMREG, bh_reg }
+#define AX { OP_IMREG, ax_reg }
+#define DX { OP_IMREG, dx_reg }
+#define zAX { OP_IMREG, z_mode_ax_reg }
+#define indirDX { OP_IMREG, indir_dx_reg }
 
-#define Sw OP_SEG, w_mode
-#define Ap OP_DIR, 0
-#define Ob OP_OFF, b_mode
-#define Ob64 OP_OFF64, b_mode
-#define Ov OP_OFF, v_mode
-#define Ov64 OP_OFF64, v_mode
-#define Xb OP_DSreg, eSI_reg
-#define Xv OP_DSreg, eSI_reg
-#define Yb OP_ESreg, eDI_reg
-#define Yv OP_ESreg, eDI_reg
-#define DSBX OP_DSreg, eBX_reg
+#define Sw { OP_SEG, w_mode }
+#define Sv { OP_SEG, v_mode }
+#define Ap { OP_DIR, 0 }
+#define Ob { OP_OFF64, b_mode }
+#define Ov { OP_OFF64, v_mode }
+#define Xb { OP_DSreg, eSI_reg }
+#define Xv { OP_DSreg, eSI_reg }
+#define Xz { OP_DSreg, eSI_reg }
+#define Yb { OP_ESreg, eDI_reg }
+#define Yv { OP_ESreg, eDI_reg }
+#define DSBX { OP_DSreg, eBX_reg }
 
-#define es OP_REG, es_reg
-#define ss OP_REG, ss_reg
-#define cs OP_REG, cs_reg
-#define ds OP_REG, ds_reg
-#define fs OP_REG, fs_reg
-#define gs OP_REG, gs_reg
+#define es { OP_REG, es_reg }
+#define ss { OP_REG, ss_reg }
+#define cs { OP_REG, cs_reg }
+#define ds { OP_REG, ds_reg }
+#define fs { OP_REG, fs_reg }
+#define gs { OP_REG, gs_reg }
 
-#define MX OP_MMX, 0
-#define XM OP_XMM, 0
-#define EM OP_EM, v_mode
-#define EX OP_EX, v_mode
-#define MS OP_MS, v_mode
-#define XS OP_XS, v_mode
-#define None OP_E, 0
-#define OPSUF OP_3DNowSuffix, 0
-#define OPSIMD OP_SIMD_Suffix, 0
+#define MX { OP_MMX, 0 }
+#define XM { OP_XMM, 0 }
+#define EM { OP_EM, v_mode }
+#define EMd { OP_EM, d_mode }
+#define EMq { OP_EM, q_mode }
+#define EXd { OP_EX, d_mode }
+#define EXq { OP_EX, q_mode }
+#define EXx { OP_EX, x_mode }
+#define MS { OP_MS, v_mode }
+#define XS { OP_XS, v_mode }
+#define EMC { OP_EMC, v_mode }
+#define MXC { OP_MXC, 0 }
+#define VM { OP_VMX, q_mode }
+#define OPSUF { OP_3DNowSuffix, 0 }
+#define OPSIMD { OP_SIMD_Suffix, 0 }
+#define XMM0 { XMM_Fixup, 0 }
 
-#define cond_jump_flag NULL, cond_jump_mode
-#define loop_jcxz_flag NULL, loop_jcxz_mode
+/* Used handle "rep" prefix for string instructions.  */
+#define Xbr { REP_Fixup, eSI_reg }
+#define Xvr { REP_Fixup, eSI_reg }
+#define Ybr { REP_Fixup, eDI_reg }
+#define Yvr { REP_Fixup, eDI_reg }
+#define Yzr { REP_Fixup, eDI_reg }
+#define indirDXr { REP_Fixup, indir_dx_reg }
+#define ALr { REP_Fixup, al_reg }
+#define eAXr { REP_Fixup, eAX_reg }
+
+#define cond_jump_flag { NULL, cond_jump_mode }
+#define loop_jcxz_flag { NULL, loop_jcxz_mode }
 
 /* bits in sizeflag */
 #define SUFFIX_ALWAYS 4
@@ -309,10 +462,20 @@
 #define w_mode 3  /* word operand */
 #define d_mode 4  /* double word operand  */
 #define q_mode 5  /* quad word operand */
-#define x_mode 6
-#define m_mode 7  /* d_mode in 32bit, q_mode in 64bit mode.  */
-#define cond_jump_mode 8
-#define loop_jcxz_mode 9
+#define t_mode 6  /* ten-byte operand */
+#define x_mode 7  /* 16-byte XMM operand */
+#define m_mode 8  /* d_mode in 32bit, q_mode in 64bit mode.  */
+#define cond_jump_mode 9
+#define loop_jcxz_mode 10
+#define dq_mode 11 /* operand size depends on REX prefixes.  */
+#define dqw_mode 12 /* registers like dq_mode, memory like w_mode.  */
+#define f_mode 13 /* 4- or 6-byte pointer operand */
+#define const_1_mode 14
+#define stack_v_mode 15 /* v_mode for stack-related opcodes.  */
+#define z_mode 16 /* non-quad operand size depends on prefixes */
+#define o_mode 17  /* 16-byte operand */
+#define dqb_mode 18 /* registers like dq_mode, memory like b_mode.  */
+#define dqd_mode 19 /* registers like dq_mode, memory like d_mode.  */
 
 #define es_reg 100
 #define cs_reg 101
@@ -357,101 +520,196 @@
 #define rSI_reg 138
 #define rDI_reg 139
 
+#define z_mode_ax_reg 149
 #define indir_dx_reg 150
 
 #define FLOATCODE 1
 #define USE_GROUPS 2
 #define USE_PREFIX_USER_TABLE 3
 #define X86_64_SPECIAL 4
+#define IS_3BYTE_OPCODE 5
 
-#define FLOAT	  NULL, NULL, FLOATCODE, NULL, 0, NULL, 0
+#define FLOAT	  NULL, { { NULL, FLOATCODE } }
 
-#define GRP1b	  NULL, NULL, USE_GROUPS, NULL,  0, NULL, 0
-#define GRP1S	  NULL, NULL, USE_GROUPS, NULL,  1, NULL, 0
-#define GRP1Ss	  NULL, NULL, USE_GROUPS, NULL,  2, NULL, 0
-#define GRP2b	  NULL, NULL, USE_GROUPS, NULL,  3, NULL, 0
-#define GRP2S	  NULL, NULL, USE_GROUPS, NULL,  4, NULL, 0
-#define GRP2b_one NULL, NULL, USE_GROUPS, NULL,  5, NULL, 0
-#define GRP2S_one NULL, NULL, USE_GROUPS, NULL,  6, NULL, 0
-#define GRP2b_cl  NULL, NULL, USE_GROUPS, NULL,  7, NULL, 0
-#define GRP2S_cl  NULL, NULL, USE_GROUPS, NULL,  8, NULL, 0
-#define GRP3b	  NULL, NULL, USE_GROUPS, NULL,  9, NULL, 0
-#define GRP3S	  NULL, NULL, USE_GROUPS, NULL, 10, NULL, 0
-#define GRP4	  NULL, NULL, USE_GROUPS, NULL, 11, NULL, 0
-#define GRP5	  NULL, NULL, USE_GROUPS, NULL, 12, NULL, 0
-#define GRP6	  NULL, NULL, USE_GROUPS, NULL, 13, NULL, 0
-#define GRP7	  NULL, NULL, USE_GROUPS, NULL, 14, NULL, 0
-#define GRP8	  NULL, NULL, USE_GROUPS, NULL, 15, NULL, 0
-#define GRP9	  NULL, NULL, USE_GROUPS, NULL, 16, NULL, 0
-#define GRP10	  NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0
-#define GRP11	  NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0
-#define GRP12	  NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0
-#define GRP13	  NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0
-#define GRP14	  NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0
-#define GRPAMD	  NULL, NULL, USE_GROUPS, NULL, 22, NULL, 0
+#define GRP1a	  NULL, { { NULL, USE_GROUPS }, { NULL,  0 } }
+#define GRP1b	  NULL, { { NULL, USE_GROUPS }, { NULL,  1 } }
+#define GRP1S	  NULL, { { NULL, USE_GROUPS }, { NULL,  2 } }
+#define GRP1Ss	  NULL, { { NULL, USE_GROUPS }, { NULL,  3 } }
+#define GRP2b	  NULL, { { NULL, USE_GROUPS }, { NULL,  4 } }
+#define GRP2S	  NULL, { { NULL, USE_GROUPS }, { NULL,  5 } }
+#define GRP2b_one NULL, { { NULL, USE_GROUPS }, { NULL,  6 } }
+#define GRP2S_one NULL, { { NULL, USE_GROUPS }, { NULL,  7 } }
+#define GRP2b_cl  NULL, { { NULL, USE_GROUPS }, { NULL,  8 } }
+#define GRP2S_cl  NULL, { { NULL, USE_GROUPS }, { NULL,  9 } }
+#define GRP3b	  NULL, { { NULL, USE_GROUPS }, { NULL, 10 } }
+#define GRP3S	  NULL, { { NULL, USE_GROUPS }, { NULL, 11 } }
+#define GRP4	  NULL, { { NULL, USE_GROUPS }, { NULL, 12 } }
+#define GRP5	  NULL, { { NULL, USE_GROUPS }, { NULL, 13 } }
+#define GRP6	  NULL, { { NULL, USE_GROUPS }, { NULL, 14 } }
+#define GRP7	  NULL, { { NULL, USE_GROUPS }, { NULL, 15 } }
+#define GRP8	  NULL, { { NULL, USE_GROUPS }, { NULL, 16 } }
+#define GRP9	  NULL, { { NULL, USE_GROUPS }, { NULL, 17 } }
+#define GRP11_C6  NULL, { { NULL, USE_GROUPS }, { NULL, 18 } }
+#define GRP11_C7  NULL, { { NULL, USE_GROUPS }, { NULL, 19 } }
+#define GRP12	  NULL, { { NULL, USE_GROUPS }, { NULL, 20 } }
+#define GRP13	  NULL, { { NULL, USE_GROUPS }, { NULL, 21 } }
+#define GRP14	  NULL, { { NULL, USE_GROUPS }, { NULL, 22 } }
+#define GRP15	  NULL, { { NULL, USE_GROUPS }, { NULL, 23 } }
+#define GRP16	  NULL, { { NULL, USE_GROUPS }, { NULL, 24 } }
+#define GRPAMD	  NULL, { { NULL, USE_GROUPS }, { NULL, 25 } }
+#define GRPPADLCK1 NULL, { { NULL, USE_GROUPS }, { NULL, 26 } }
+#define GRPPADLCK2 NULL, { { NULL, USE_GROUPS }, { NULL, 27 } }
 
-#define PREGRP0   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  0, NULL, 0
-#define PREGRP1   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  1, NULL, 0
-#define PREGRP2   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  2, NULL, 0
-#define PREGRP3   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  3, NULL, 0
-#define PREGRP4   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  4, NULL, 0
-#define PREGRP5   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  5, NULL, 0
-#define PREGRP6   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  6, NULL, 0
-#define PREGRP7   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  7, NULL, 0
-#define PREGRP8   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  8, NULL, 0
-#define PREGRP9   NULL, NULL, USE_PREFIX_USER_TABLE, NULL,  9, NULL, 0
-#define PREGRP10  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 10, NULL, 0
-#define PREGRP11  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 11, NULL, 0
-#define PREGRP12  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 12, NULL, 0
-#define PREGRP13  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 13, NULL, 0
-#define PREGRP14  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 14, NULL, 0
-#define PREGRP15  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 15, NULL, 0
-#define PREGRP16  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 16, NULL, 0
-#define PREGRP17  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 17, NULL, 0
-#define PREGRP18  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 18, NULL, 0
-#define PREGRP19  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 19, NULL, 0
-#define PREGRP20  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 20, NULL, 0
-#define PREGRP21  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 21, NULL, 0
-#define PREGRP22  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 22, NULL, 0
-#define PREGRP23  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 23, NULL, 0
-#define PREGRP24  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 24, NULL, 0
-#define PREGRP25  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 25, NULL, 0
-#define PREGRP26  NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 26, NULL, 0
+#define PREGRP0   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  0 } }
+#define PREGRP1   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  1 } }
+#define PREGRP2   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  2 } }
+#define PREGRP3   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  3 } }
+#define PREGRP4   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  4 } }
+#define PREGRP5   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  5 } }
+#define PREGRP6   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  6 } }
+#define PREGRP7   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  7 } }
+#define PREGRP8   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  8 } }
+#define PREGRP9   NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL,  9 } }
+#define PREGRP10  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 10 } }
+#define PREGRP11  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 11 } }
+#define PREGRP12  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 12 } }
+#define PREGRP13  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 13 } }
+#define PREGRP14  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 14 } }
+#define PREGRP15  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 15 } }
+#define PREGRP16  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 16 } }
+#define PREGRP17  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 17 } }
+#define PREGRP18  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 18 } }
+#define PREGRP19  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 19 } }
+#define PREGRP20  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 20 } }
+#define PREGRP21  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 21 } }
+#define PREGRP22  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 22 } }
+#define PREGRP23  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 23 } }
+#define PREGRP24  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 24 } }
+#define PREGRP25  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 25 } }
+#define PREGRP26  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 26 } }
+#define PREGRP27  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 27 } }
+#define PREGRP28  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 28 } }
+#define PREGRP29  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 29 } }
+#define PREGRP30  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 30 } }
+#define PREGRP31  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 31 } }
+#define PREGRP32  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 32 } }
+#define PREGRP33  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 33 } }
+#define PREGRP34  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 34 } }
+#define PREGRP35  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 35 } }
+#define PREGRP36  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 36 } }
+#define PREGRP37  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 37 } }
+#define PREGRP38  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 38 } }
+#define PREGRP39  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 39 } }
+#define PREGRP40  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 40 } }
+#define PREGRP41  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 41 } }
+#define PREGRP42  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 42 } }
+#define PREGRP43  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 43 } }
+#define PREGRP44  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 44 } }
+#define PREGRP45  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 45 } }
+#define PREGRP46  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 46 } }
+#define PREGRP47  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 47 } }
+#define PREGRP48  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 48 } }
+#define PREGRP49  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 49 } }
+#define PREGRP50  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 50 } }
+#define PREGRP51  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 51 } }
+#define PREGRP52  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 52 } }
+#define PREGRP53  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 53 } }
+#define PREGRP54  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 54 } }
+#define PREGRP55  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 55 } }
+#define PREGRP56  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 56 } }
+#define PREGRP57  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 57 } }
+#define PREGRP58  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 58 } }
+#define PREGRP59  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 59 } }
+#define PREGRP60  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 60 } }
+#define PREGRP61  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 61 } }
+#define PREGRP62  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 62 } }
+#define PREGRP63  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 63 } }
+#define PREGRP64  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 64 } }
+#define PREGRP65  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 65 } }
+#define PREGRP66  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 66 } }
+#define PREGRP67  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 67 } }
+#define PREGRP68  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 68 } }
+#define PREGRP69  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 69 } }
+#define PREGRP70  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 70 } }
+#define PREGRP71  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 71 } }
+#define PREGRP72  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 72 } }
+#define PREGRP73  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 73 } }
+#define PREGRP74  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 74 } }
+#define PREGRP75  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 75 } }
+#define PREGRP76  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 76 } }
+#define PREGRP77  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 77 } }
+#define PREGRP78  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 78 } }
+#define PREGRP79  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 79 } }
+#define PREGRP80  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 80 } }
+#define PREGRP81  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 81 } }
+#define PREGRP82  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 82 } }
+#define PREGRP83  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 83 } }
+#define PREGRP84  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 84 } }
+#define PREGRP85  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 85 } }
+#define PREGRP86  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 86 } }
+#define PREGRP87  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 87 } }
+#define PREGRP88  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 88 } }
+#define PREGRP89  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 89 } }
+#define PREGRP90  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 90 } }
+#define PREGRP91  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 91 } }
+#define PREGRP92  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 92 } }
+#define PREGRP93  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 93 } }
+#define PREGRP94  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 94 } }
+#define PREGRP95  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 95 } }
+#define PREGRP96  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 96 } }
+#define PREGRP97  NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 97 } }
 
-#define X86_64_0  NULL, NULL, X86_64_SPECIAL, NULL,  0, NULL, 0
 
-typedef void (*op_rtn) PARAMS ((int bytemode, int sizeflag));
+#define X86_64_0  NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } }
+#define X86_64_1  NULL, { { NULL, X86_64_SPECIAL }, { NULL, 1 } }
+#define X86_64_2  NULL, { { NULL, X86_64_SPECIAL }, { NULL, 2 } }
+#define X86_64_3  NULL, { { NULL, X86_64_SPECIAL }, { NULL, 3 } }
+
+#define THREE_BYTE_0 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 0 } }
+#define THREE_BYTE_1 NULL, { { NULL, IS_3BYTE_OPCODE }, { NULL, 1 } }
+
+typedef void (*op_rtn) (int bytemode, int sizeflag);
 
 struct dis386 {
   const char *name;
-  op_rtn op1;
-  int bytemode1;
-  op_rtn op2;
-  int bytemode2;
-  op_rtn op3;
-  int bytemode3;
+  struct
+    {
+      op_rtn rtn;
+      int bytemode;
+    } op[MAX_OPERANDS];
 };
 
 /* Upper case letters in the instruction names here are macros.
    'A' => print 'b' if no register operands or suffix_always is true
    'B' => print 'b' if suffix_always is true
+   'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand
+   .      size prefix
+   'D' => print 'w' if no register operands or 'w', 'l' or 'q', if
+   .      suffix_always is true
    'E' => print 'e' if 32-bit form of jcxz
    'F' => print 'w' or 'l' depending on address size prefix (loop insns)
+   'G' => print 'w' or 'l' depending on operand size prefix (i/o insns)
    'H' => print ",pt" or ",pn" branch hint
+   'I' => honor following macro letter even in Intel mode (implemented only
+   .      for some of the macro letters)
+   'J' => print 'l'
+   'K' => print 'd' or 'q' if rex prefix is present.
    'L' => print 'l' if suffix_always is true
    'N' => print 'n' if instruction has no wait "prefix"
-   'O' => print 'd', or 'o'
+   'O' => print 'd' or 'o' (or 'q' in Intel mode)
    'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix,
    .      or suffix_always is true.  print 'q' if rex prefix is present.
    'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always
    .      is true
-   'R' => print 'w', 'l' or 'q' ("wd" or "dq" in intel mode)
+   'R' => print 'w', 'l' or 'q' ('d' for 'l' and 'e' in Intel mode)
    'S' => print 'w', 'l' or 'q' if suffix_always is true
    'T' => print 'q' in 64bit mode and behave as 'P' otherwise
    'U' => print 'q' in 64bit mode and behave as 'Q' otherwise
+   'V' => print 'q' in 64bit mode and behave as 'S' otherwise
+   'W' => print 'b', 'w' or 'l' ('d' in Intel mode)
    'X' => print 's', 'd' depending on data16 prefix (for XMM)
-   'W' => print 'b' or 'w' ("w" or "de" in intel mode)
    'Y' => 'q' if instruction has an REX 64bit overwrite prefix
+   'Z' => print 'q' in 64bit mode and behave as 'L' otherwise
 
    Many of the above letters print nothing in Intel mode.  See "putop"
    for the details.
@@ -464,249 +722,248 @@
 
 static const struct dis386 dis386[] = {
   /* 00 */
-  { "addB",		Eb, Gb, XX },
-  { "addS",		Ev, Gv, XX },
-  { "addB",		Gb, Eb, XX },
-  { "addS",		Gv, Ev, XX },
-  { "addB",		AL, Ib, XX },
-  { "addS",		eAX, Iv, XX },
-  { "push{T|}",		es, XX, XX },
-  { "pop{T|}",		es, XX, XX },
+  { "addB",		{ Eb, Gb } },
+  { "addS",		{ Ev, Gv } },
+  { "addB",		{ Gb, Eb } },
+  { "addS",		{ Gv, Ev } },
+  { "addB",		{ AL, Ib } },
+  { "addS",		{ eAX, Iv } },
+  { "push{T|}",		{ es } },
+  { "pop{T|}",		{ es } },
   /* 08 */
-  { "orB",		Eb, Gb, XX },
-  { "orS",		Ev, Gv, XX },
-  { "orB",		Gb, Eb, XX },
-  { "orS",		Gv, Ev, XX },
-  { "orB",		AL, Ib, XX },
-  { "orS",		eAX, Iv, XX },
-  { "push{T|}",		cs, XX, XX },
-  { "(bad)",		XX, XX, XX },	/* 0x0f extended opcode escape */
+  { "orB",		{ Eb, Gb } },
+  { "orS",		{ Ev, Gv } },
+  { "orB",		{ Gb, Eb } },
+  { "orS",		{ Gv, Ev } },
+  { "orB",		{ AL, Ib } },
+  { "orS",		{ eAX, Iv } },
+  { "push{T|}",		{ cs } },
+  { "(bad)",		{ XX } },	/* 0x0f extended opcode escape */
   /* 10 */
-  { "adcB",		Eb, Gb, XX },
-  { "adcS",		Ev, Gv, XX },
-  { "adcB",		Gb, Eb, XX },
-  { "adcS",		Gv, Ev, XX },
-  { "adcB",		AL, Ib, XX },
-  { "adcS",		eAX, Iv, XX },
-  { "push{T|}",		ss, XX, XX },
-  { "popT|}",		ss, XX, XX },
+  { "adcB",		{ Eb, Gb } },
+  { "adcS",		{ Ev, Gv } },
+  { "adcB",		{ Gb, Eb } },
+  { "adcS",		{ Gv, Ev } },
+  { "adcB",		{ AL, Ib } },
+  { "adcS",		{ eAX, Iv } },
+  { "push{T|}",		{ ss } },
+  { "pop{T|}",		{ ss } },
   /* 18 */
-  { "sbbB",		Eb, Gb, XX },
-  { "sbbS",		Ev, Gv, XX },
-  { "sbbB",		Gb, Eb, XX },
-  { "sbbS",		Gv, Ev, XX },
-  { "sbbB",		AL, Ib, XX },
-  { "sbbS",		eAX, Iv, XX },
-  { "push{T|}",		ds, XX, XX },
-  { "pop{T|}",		ds, XX, XX },
+  { "sbbB",		{ Eb, Gb } },
+  { "sbbS",		{ Ev, Gv } },
+  { "sbbB",		{ Gb, Eb } },
+  { "sbbS",		{ Gv, Ev } },
+  { "sbbB",		{ AL, Ib } },
+  { "sbbS",		{ eAX, Iv } },
+  { "push{T|}",		{ ds } },
+  { "pop{T|}",		{ ds } },
   /* 20 */
-  { "andB",		Eb, Gb, XX },
-  { "andS",		Ev, Gv, XX },
-  { "andB",		Gb, Eb, XX },
-  { "andS",		Gv, Ev, XX },
-  { "andB",		AL, Ib, XX },
-  { "andS",		eAX, Iv, XX },
-  { "(bad)",		XX, XX, XX },	/* SEG ES prefix */
-  { "daa{|}",		XX, XX, XX },
+  { "andB",		{ Eb, Gb } },
+  { "andS",		{ Ev, Gv } },
+  { "andB",		{ Gb, Eb } },
+  { "andS",		{ Gv, Ev } },
+  { "andB",		{ AL, Ib } },
+  { "andS",		{ eAX, Iv } },
+  { "(bad)",		{ XX } },	/* SEG ES prefix */
+  { "daa{|}",		{ XX } },
   /* 28 */
-  { "subB",		Eb, Gb, XX },
-  { "subS",		Ev, Gv, XX },
-  { "subB",		Gb, Eb, XX },
-  { "subS",		Gv, Ev, XX },
-  { "subB",		AL, Ib, XX },
-  { "subS",		eAX, Iv, XX },
-  { "(bad)",		XX, XX, XX },	/* SEG CS prefix */
-  { "das{|}",		XX, XX, XX },
+  { "subB",		{ Eb, Gb } },
+  { "subS",		{ Ev, Gv } },
+  { "subB",		{ Gb, Eb } },
+  { "subS",		{ Gv, Ev } },
+  { "subB",		{ AL, Ib } },
+  { "subS",		{ eAX, Iv } },
+  { "(bad)",		{ XX } },	/* SEG CS prefix */
+  { "das{|}",		{ XX } },
   /* 30 */
-  { "xorB",		Eb, Gb, XX },
-  { "xorS",		Ev, Gv, XX },
-  { "xorB",		Gb, Eb, XX },
-  { "xorS",		Gv, Ev, XX },
-  { "xorB",		AL, Ib, XX },
-  { "xorS",		eAX, Iv, XX },
-  { "(bad)",		XX, XX, XX },	/* SEG SS prefix */
-  { "aaa{|}",		XX, XX, XX },
+  { "xorB",		{ Eb, Gb } },
+  { "xorS",		{ Ev, Gv } },
+  { "xorB",		{ Gb, Eb } },
+  { "xorS",		{ Gv, Ev } },
+  { "xorB",		{ AL, Ib } },
+  { "xorS",		{ eAX, Iv } },
+  { "(bad)",		{ XX } },	/* SEG SS prefix */
+  { "aaa{|}",		{ XX } },
   /* 38 */
-  { "cmpB",		Eb, Gb, XX },
-  { "cmpS",		Ev, Gv, XX },
-  { "cmpB",		Gb, Eb, XX },
-  { "cmpS",		Gv, Ev, XX },
-  { "cmpB",		AL, Ib, XX },
-  { "cmpS",		eAX, Iv, XX },
-  { "(bad)",		XX, XX, XX },	/* SEG DS prefix */
-  { "aas{|}",		XX, XX, XX },
+  { "cmpB",		{ Eb, Gb } },
+  { "cmpS",		{ Ev, Gv } },
+  { "cmpB",		{ Gb, Eb } },
+  { "cmpS",		{ Gv, Ev } },
+  { "cmpB",		{ AL, Ib } },
+  { "cmpS",		{ eAX, Iv } },
+  { "(bad)",		{ XX } },	/* SEG DS prefix */
+  { "aas{|}",		{ XX } },
   /* 40 */
-  { "inc{S|}",		RMeAX, XX, XX },
-  { "inc{S|}",		RMeCX, XX, XX },
-  { "inc{S|}",		RMeDX, XX, XX },
-  { "inc{S|}",		RMeBX, XX, XX },
-  { "inc{S|}",		RMeSP, XX, XX },
-  { "inc{S|}",		RMeBP, XX, XX },
-  { "inc{S|}",		RMeSI, XX, XX },
-  { "inc{S|}",		RMeDI, XX, XX },
+  { "inc{S|}",		{ RMeAX } },
+  { "inc{S|}",		{ RMeCX } },
+  { "inc{S|}",		{ RMeDX } },
+  { "inc{S|}",		{ RMeBX } },
+  { "inc{S|}",		{ RMeSP } },
+  { "inc{S|}",		{ RMeBP } },
+  { "inc{S|}",		{ RMeSI } },
+  { "inc{S|}",		{ RMeDI } },
   /* 48 */
-  { "dec{S|}",		RMeAX, XX, XX },
-  { "dec{S|}",		RMeCX, XX, XX },
-  { "dec{S|}",		RMeDX, XX, XX },
-  { "dec{S|}",		RMeBX, XX, XX },
-  { "dec{S|}",		RMeSP, XX, XX },
-  { "dec{S|}",		RMeBP, XX, XX },
-  { "dec{S|}",		RMeSI, XX, XX },
-  { "dec{S|}",		RMeDI, XX, XX },
+  { "dec{S|}",		{ RMeAX } },
+  { "dec{S|}",		{ RMeCX } },
+  { "dec{S|}",		{ RMeDX } },
+  { "dec{S|}",		{ RMeBX } },
+  { "dec{S|}",		{ RMeSP } },
+  { "dec{S|}",		{ RMeBP } },
+  { "dec{S|}",		{ RMeSI } },
+  { "dec{S|}",		{ RMeDI } },
   /* 50 */
-  { "pushS",		RMrAX, XX, XX },
-  { "pushS",		RMrCX, XX, XX },
-  { "pushS",		RMrDX, XX, XX },
-  { "pushS",		RMrBX, XX, XX },
-  { "pushS",		RMrSP, XX, XX },
-  { "pushS",		RMrBP, XX, XX },
-  { "pushS",		RMrSI, XX, XX },
-  { "pushS",		RMrDI, XX, XX },
+  { "pushV",		{ RMrAX } },
+  { "pushV",		{ RMrCX } },
+  { "pushV",		{ RMrDX } },
+  { "pushV",		{ RMrBX } },
+  { "pushV",		{ RMrSP } },
+  { "pushV",		{ RMrBP } },
+  { "pushV",		{ RMrSI } },
+  { "pushV",		{ RMrDI } },
   /* 58 */
-  { "popS",		RMrAX, XX, XX },
-  { "popS",		RMrCX, XX, XX },
-  { "popS",		RMrDX, XX, XX },
-  { "popS",		RMrBX, XX, XX },
-  { "popS",		RMrSP, XX, XX },
-  { "popS",		RMrBP, XX, XX },
-  { "popS",		RMrSI, XX, XX },
-  { "popS",		RMrDI, XX, XX },
+  { "popV",		{ RMrAX } },
+  { "popV",		{ RMrCX } },
+  { "popV",		{ RMrDX } },
+  { "popV",		{ RMrBX } },
+  { "popV",		{ RMrSP } },
+  { "popV",		{ RMrBP } },
+  { "popV",		{ RMrSI } },
+  { "popV",		{ RMrDI } },
   /* 60 */
-  { "pusha{P|}",	XX, XX, XX },
-  { "popa{P|}",		XX, XX, XX },
-  { "bound{S|}",	Gv, Ma, XX },
   { X86_64_0 },
-  { "(bad)",		XX, XX, XX },	/* seg fs */
-  { "(bad)",		XX, XX, XX },	/* seg gs */
-  { "(bad)",		XX, XX, XX },	/* op size prefix */
-  { "(bad)",		XX, XX, XX },	/* adr size prefix */
+  { X86_64_1 },
+  { X86_64_2 },
+  { X86_64_3 },
+  { "(bad)",		{ XX } },	/* seg fs */
+  { "(bad)",		{ XX } },	/* seg gs */
+  { "(bad)",		{ XX } },	/* op size prefix */
+  { "(bad)",		{ XX } },	/* adr size prefix */
   /* 68 */
-  { "pushT",		Iq, XX, XX },
-  { "imulS",		Gv, Ev, Iv },
-  { "pushT",		sIb, XX, XX },
-  { "imulS",		Gv, Ev, sIb },
-  { "ins{b||b|}",	Yb, indirDX, XX },
-  { "ins{R||R|}",	Yv, indirDX, XX },
-  { "outs{b||b|}",	indirDX, Xb, XX },
-  { "outs{R||R|}",	indirDX, Xv, XX },
+  { "pushT",		{ Iq } },
+  { "imulS",		{ Gv, Ev, Iv } },
+  { "pushT",		{ sIb } },
+  { "imulS",		{ Gv, Ev, sIb } },
+  { "ins{b||b|}",	{ Ybr, indirDX } },
+  { "ins{R||G|}",	{ Yzr, indirDX } },
+  { "outs{b||b|}",	{ indirDXr, Xb } },
+  { "outs{R||G|}",	{ indirDXr, Xz } },
   /* 70 */
-  { "joH",		Jb, XX, cond_jump_flag },
-  { "jnoH",		Jb, XX, cond_jump_flag },
-  { "jbH",		Jb, XX, cond_jump_flag },
-  { "jaeH",		Jb, XX, cond_jump_flag },
-  { "jeH",		Jb, XX, cond_jump_flag },
-  { "jneH",		Jb, XX, cond_jump_flag },
-  { "jbeH",		Jb, XX, cond_jump_flag },
-  { "jaH",		Jb, XX, cond_jump_flag },
+  { "joH",		{ Jb, XX, cond_jump_flag } },
+  { "jnoH",		{ Jb, XX, cond_jump_flag } },
+  { "jbH",		{ Jb, XX, cond_jump_flag } },
+  { "jaeH",		{ Jb, XX, cond_jump_flag } },
+  { "jeH",		{ Jb, XX, cond_jump_flag } },
+  { "jneH",		{ Jb, XX, cond_jump_flag } },
+  { "jbeH",		{ Jb, XX, cond_jump_flag } },
+  { "jaH",		{ Jb, XX, cond_jump_flag } },
   /* 78 */
-  { "jsH",		Jb, XX, cond_jump_flag },
-  { "jnsH",		Jb, XX, cond_jump_flag },
-  { "jpH",		Jb, XX, cond_jump_flag },
-  { "jnpH",		Jb, XX, cond_jump_flag },
-  { "jlH",		Jb, XX, cond_jump_flag },
-  { "jgeH",		Jb, XX, cond_jump_flag },
-  { "jleH",		Jb, XX, cond_jump_flag },
-  { "jgH",		Jb, XX, cond_jump_flag },
+  { "jsH",		{ Jb, XX, cond_jump_flag } },
+  { "jnsH",		{ Jb, XX, cond_jump_flag } },
+  { "jpH",		{ Jb, XX, cond_jump_flag } },
+  { "jnpH",		{ Jb, XX, cond_jump_flag } },
+  { "jlH",		{ Jb, XX, cond_jump_flag } },
+  { "jgeH",		{ Jb, XX, cond_jump_flag } },
+  { "jleH",		{ Jb, XX, cond_jump_flag } },
+  { "jgH",		{ Jb, XX, cond_jump_flag } },
   /* 80 */
   { GRP1b },
   { GRP1S },
-  { "(bad)",		XX, XX, XX },
+  { "(bad)",		{ XX } },
   { GRP1Ss },
-  { "testB",		Eb, Gb, XX },
-  { "testS",		Ev, Gv, XX },
-  { "xchgB",		Eb, Gb, XX },
-  { "xchgS",		Ev, Gv, XX },
+  { "testB",		{ Eb, Gb } },
+  { "testS",		{ Ev, Gv } },
+  { "xchgB",		{ Eb, Gb } },
+  { "xchgS",		{ Ev, Gv } },
   /* 88 */
-  { "movB",		Eb, Gb, XX },
-  { "movS",		Ev, Gv, XX },
-  { "movB",		Gb, Eb, XX },
-  { "movS",		Gv, Ev, XX },
-  { "movQ",		Ev, Sw, XX },
-  { "leaS",		Gv, M, XX },
-  { "movQ",		Sw, Ev, XX },
-  { "popU",		Ev, XX, XX },
+  { "movB",		{ Eb, Gb } },
+  { "movS",		{ Ev, Gv } },
+  { "movB",		{ Gb, Eb } },
+  { "movS",		{ Gv, Ev } },
+  { "movD",		{ Sv, Sw } },
+  { "leaS",		{ Gv, M } },
+  { "movD",		{ Sw, Sv } },
+  { GRP1a },
   /* 90 */
-  { "nop",		XX, XX, XX },
-  /* FIXME: NOP with REPz prefix is called PAUSE.  */
-  { "xchgS",		RMeCX, eAX, XX },
-  { "xchgS",		RMeDX, eAX, XX },
-  { "xchgS",		RMeBX, eAX, XX },
-  { "xchgS",		RMeSP, eAX, XX },
-  { "xchgS",		RMeBP, eAX, XX },
-  { "xchgS",		RMeSI, eAX, XX },
-  { "xchgS",		RMeDI, eAX, XX },
+  { PREGRP38 },
+  { "xchgS",		{ RMeCX, eAX } },
+  { "xchgS",		{ RMeDX, eAX } },
+  { "xchgS",		{ RMeBX, eAX } },
+  { "xchgS",		{ RMeSP, eAX } },
+  { "xchgS",		{ RMeBP, eAX } },
+  { "xchgS",		{ RMeSI, eAX } },
+  { "xchgS",		{ RMeDI, eAX } },
   /* 98 */
-  { "cW{tR||tR|}",	XX, XX, XX },
-  { "cR{tO||tO|}",	XX, XX, XX },
-  { "lcall{T|}",	Ap, XX, XX },
-  { "(bad)",		XX, XX, XX },	/* fwait */
-  { "pushfT",		XX, XX, XX },
-  { "popfT",		XX, XX, XX },
-  { "sahf{|}",		XX, XX, XX },
-  { "lahf{|}",		XX, XX, XX },
+  { "cW{t||t|}R",	{ XX } },
+  { "cR{t||t|}O",	{ XX } },
+  { "Jcall{T|}",	{ Ap } },
+  { "(bad)",		{ XX } },	/* fwait */
+  { "pushfT",		{ XX } },
+  { "popfT",		{ XX } },
+  { "sahf{|}",		{ XX } },
+  { "lahf{|}",		{ XX } },
   /* a0 */
-  { "movB",		AL, Ob64, XX },
-  { "movS",		eAX, Ov64, XX },
-  { "movB",		Ob64, AL, XX },
-  { "movS",		Ov64, eAX, XX },
-  { "movs{b||b|}",	Yb, Xb, XX },
-  { "movs{R||R|}",	Yv, Xv, XX },
-  { "cmps{b||b|}",	Xb, Yb, XX },
-  { "cmps{R||R|}",	Xv, Yv, XX },
+  { "movB",		{ AL, Ob } },
+  { "movS",		{ eAX, Ov } },
+  { "movB",		{ Ob, AL } },
+  { "movS",		{ Ov, eAX } },
+  { "movs{b||b|}",	{ Ybr, Xb } },
+  { "movs{R||R|}",	{ Yvr, Xv } },
+  { "cmps{b||b|}",	{ Xb, Yb } },
+  { "cmps{R||R|}",	{ Xv, Yv } },
   /* a8 */
-  { "testB",		AL, Ib, XX },
-  { "testS",		eAX, Iv, XX },
-  { "stosB",		Yb, AL, XX },
-  { "stosS",		Yv, eAX, XX },
-  { "lodsB",		AL, Xb, XX },
-  { "lodsS",		eAX, Xv, XX },
-  { "scasB",		AL, Yb, XX },
-  { "scasS",		eAX, Yv, XX },
+  { "testB",		{ AL, Ib } },
+  { "testS",		{ eAX, Iv } },
+  { "stosB",		{ Ybr, AL } },
+  { "stosS",		{ Yvr, eAX } },
+  { "lodsB",		{ ALr, Xb } },
+  { "lodsS",		{ eAXr, Xv } },
+  { "scasB",		{ AL, Yb } },
+  { "scasS",		{ eAX, Yv } },
   /* b0 */
-  { "movB",		RMAL, Ib, XX },
-  { "movB",		RMCL, Ib, XX },
-  { "movB",		RMDL, Ib, XX },
-  { "movB",		RMBL, Ib, XX },
-  { "movB",		RMAH, Ib, XX },
-  { "movB",		RMCH, Ib, XX },
-  { "movB",		RMDH, Ib, XX },
-  { "movB",		RMBH, Ib, XX },
+  { "movB",		{ RMAL, Ib } },
+  { "movB",		{ RMCL, Ib } },
+  { "movB",		{ RMDL, Ib } },
+  { "movB",		{ RMBL, Ib } },
+  { "movB",		{ RMAH, Ib } },
+  { "movB",		{ RMCH, Ib } },
+  { "movB",		{ RMDH, Ib } },
+  { "movB",		{ RMBH, Ib } },
   /* b8 */
-  { "movS",		RMeAX, Iv64, XX },
-  { "movS",		RMeCX, Iv64, XX },
-  { "movS",		RMeDX, Iv64, XX },
-  { "movS",		RMeBX, Iv64, XX },
-  { "movS",		RMeSP, Iv64, XX },
-  { "movS",		RMeBP, Iv64, XX },
-  { "movS",		RMeSI, Iv64, XX },
-  { "movS",		RMeDI, Iv64, XX },
+  { "movS",		{ RMeAX, Iv64 } },
+  { "movS",		{ RMeCX, Iv64 } },
+  { "movS",		{ RMeDX, Iv64 } },
+  { "movS",		{ RMeBX, Iv64 } },
+  { "movS",		{ RMeSP, Iv64 } },
+  { "movS",		{ RMeBP, Iv64 } },
+  { "movS",		{ RMeSI, Iv64 } },
+  { "movS",		{ RMeDI, Iv64 } },
   /* c0 */
   { GRP2b },
   { GRP2S },
-  { "retT",		Iw, XX, XX },
-  { "retT",		XX, XX, XX },
-  { "les{S|}",		Gv, Mp, XX },
-  { "ldsS",		Gv, Mp, XX },
-  { "movA",		Eb, Ib, XX },
-  { "movQ",		Ev, Iv, XX },
+  { "retT",		{ Iw } },
+  { "retT",		{ XX } },
+  { "les{S|}",		{ Gv, Mp } },
+  { "ldsS",		{ Gv, Mp } },
+  { GRP11_C6 },
+  { GRP11_C7 },
   /* c8 */
-  { "enterT",		Iw, Ib, XX },
-  { "leaveT",		XX, XX, XX },
-  { "lretP",		Iw, XX, XX },
-  { "lretP",		XX, XX, XX },
-  { "int3",		XX, XX, XX },
-  { "int",		Ib, XX, XX },
-  { "into{|}",		XX, XX, XX },
-  { "iretP",		XX, XX, XX },
+  { "enterT",		{ Iw, Ib } },
+  { "leaveT",		{ XX } },
+  { "lretP",		{ Iw } },
+  { "lretP",		{ XX } },
+  { "int3",		{ XX } },
+  { "int",		{ Ib } },
+  { "into{|}",		{ XX } },
+  { "iretP",		{ XX } },
   /* d0 */
   { GRP2b_one },
   { GRP2S_one },
   { GRP2b_cl },
   { GRP2S_cl },
-  { "aam{|}",		sIb, XX, XX },
-  { "aad{|}",		sIb, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "xlat",		DSBX, XX, XX },
+  { "aam{|}",		{ sIb } },
+  { "aad{|}",		{ sIb } },
+  { "(bad)",		{ XX } },
+  { "xlat",		{ DSBX } },
   /* d8 */
   { FLOAT },
   { FLOAT },
@@ -717,39 +974,39 @@
   { FLOAT },
   { FLOAT },
   /* e0 */
-  { "loopneFH",		Jb, XX, loop_jcxz_flag },
-  { "loopeFH",		Jb, XX, loop_jcxz_flag },
-  { "loopFH",		Jb, XX, loop_jcxz_flag },
-  { "jEcxzH",		Jb, XX, loop_jcxz_flag },
-  { "inB",		AL, Ib, XX },
-  { "inS",		eAX, Ib, XX },
-  { "outB",		Ib, AL, XX },
-  { "outS",		Ib, eAX, XX },
+  { "loopneFH",		{ Jb, XX, loop_jcxz_flag } },
+  { "loopeFH",		{ Jb, XX, loop_jcxz_flag } },
+  { "loopFH",		{ Jb, XX, loop_jcxz_flag } },
+  { "jEcxzH",		{ Jb, XX, loop_jcxz_flag } },
+  { "inB",		{ AL, Ib } },
+  { "inG",		{ zAX, Ib } },
+  { "outB",		{ Ib, AL } },
+  { "outG",		{ Ib, zAX } },
   /* e8 */
-  { "callT",		Jv, XX, XX },
-  { "jmpT",		Jv, XX, XX },
-  { "ljmp{T|}",		Ap, XX, XX },
-  { "jmp",		Jb, XX, XX },
-  { "inB",		AL, indirDX, XX },
-  { "inS",		eAX, indirDX, XX },
-  { "outB",		indirDX, AL, XX },
-  { "outS",		indirDX, eAX, XX },
+  { "callT",		{ Jv } },
+  { "jmpT",		{ Jv } },
+  { "Jjmp{T|}",		{ Ap } },
+  { "jmp",		{ Jb } },
+  { "inB",		{ AL, indirDX } },
+  { "inG",		{ zAX, indirDX } },
+  { "outB",		{ indirDX, AL } },
+  { "outG",		{ indirDX, zAX } },
   /* f0 */
-  { "(bad)",		XX, XX, XX },	/* lock prefix */
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },	/* repne */
-  { "(bad)",		XX, XX, XX },	/* repz */
-  { "hlt",		XX, XX, XX },
-  { "cmc",		XX, XX, XX },
+  { "(bad)",		{ XX } },	/* lock prefix */
+  { "icebp",		{ XX } },
+  { "(bad)",		{ XX } },	/* repne */
+  { "(bad)",		{ XX } },	/* repz */
+  { "hlt",		{ XX } },
+  { "cmc",		{ XX } },
   { GRP3b },
   { GRP3S },
   /* f8 */
-  { "clc",		XX, XX, XX },
-  { "stc",		XX, XX, XX },
-  { "cli",		XX, XX, XX },
-  { "sti",		XX, XX, XX },
-  { "cld",		XX, XX, XX },
-  { "std",		XX, XX, XX },
+  { "clc",		{ XX } },
+  { "stc",		{ XX } },
+  { "cli",		{ XX } },
+  { "sti",		{ XX } },
+  { "cld",		{ XX } },
+  { "std",		{ XX } },
   { GRP4 },
   { GRP5 },
 };
@@ -758,102 +1015,102 @@
   /* 00 */
   { GRP6 },
   { GRP7 },
-  { "larS",		Gv, Ew, XX },
-  { "lslS",		Gv, Ew, XX },
-  { "(bad)",		XX, XX, XX },
-  { "syscall",		XX, XX, XX },
-  { "clts",		XX, XX, XX },
-  { "sysretP",		XX, XX, XX },
+  { "larS",		{ Gv, Ew } },
+  { "lslS",		{ Gv, Ew } },
+  { "(bad)",		{ XX } },
+  { "syscall",		{ XX } },
+  { "clts",		{ XX } },
+  { "sysretP",		{ XX } },
   /* 08 */
-  { "invd",		XX, XX, XX },
-  { "wbinvd",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "ud2a",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
+  { "invd",		{ XX } },
+  { "wbinvd",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "ud2a",		{ XX } },
+  { "(bad)",		{ XX } },
   { GRPAMD },
-  { "femms",		XX, XX, XX },
-  { "",			MX, EM, OPSUF }, /* See OP_3DNowSuffix.  */
+  { "femms",		{ XX } },
+  { "",			{ MX, EM, OPSUF } }, /* See OP_3DNowSuffix.  */
   /* 10 */
   { PREGRP8 },
   { PREGRP9 },
-  { "movlpX",		XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */
-  { "movlpX",		EX, XM, SIMD_Fixup, 'h' },
-  { "unpcklpX",		XM, EX, XX },
-  { "unpckhpX",		XM, EX, XX },
-  { "movhpX",		XM, EX, SIMD_Fixup, 'l' },
-  { "movhpX",		EX, XM, SIMD_Fixup, 'l' },
+  { PREGRP30 },
+  { "movlpX",		{ EXq, XM, { SIMD_Fixup, 'h' } } },
+  { "unpcklpX",		{ XM, EXq } },
+  { "unpckhpX",		{ XM, EXq } },
+  { PREGRP31 },
+  { "movhpX",		{ EXq, XM, { SIMD_Fixup, 'l' } } },
   /* 18 */
-  { GRP14 },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
+  { GRP16 },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "nopQ",		{ Ev } },
   /* 20 */
-  { "movL",		Rm, Cm, XX },
-  { "movL",		Rm, Dm, XX },
-  { "movL",		Cm, Rm, XX },
-  { "movL",		Dm, Rm, XX },
-  { "movL",		Rd, Td, XX },
-  { "(bad)",		XX, XX, XX },
-  { "movL",		Td, Rd, XX },
-  { "(bad)",		XX, XX, XX },
+  { "movZ",		{ Rm, Cm } },
+  { "movZ",		{ Rm, Dm } },
+  { "movZ",		{ Cm, Rm } },
+  { "movZ",		{ Dm, Rm } },
+  { "movL",		{ Rd, Td } },
+  { "(bad)",		{ XX } },
+  { "movL",		{ Td, Rd } },
+  { "(bad)",		{ XX } },
   /* 28 */
-  { "movapX",		XM, EX, XX },
-  { "movapX",		EX, XM, XX },
+  { "movapX",		{ XM, EXx } },
+  { "movapX",		{ EXx,  XM } },
   { PREGRP2 },
-  { "movntpX",		Ev, XM, XX },
+  { PREGRP33 },
   { PREGRP4 },
   { PREGRP3 },
-  { "ucomisX",		XM,EX, XX },
-  { "comisX",		XM,EX, XX },
+  { PREGRP93 },
+  { PREGRP94 },
   /* 30 */
-  { "wrmsr",		XX, XX, XX },
-  { "rdtsc",		XX, XX, XX },
-  { "rdmsr",		XX, XX, XX },
-  { "rdpmc",		XX, XX, XX },
-  { "sysenter",		XX, XX, XX },
-  { "sysexit",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
+  { "wrmsr",		{ XX } },
+  { "rdtsc",		{ XX } },
+  { "rdmsr",		{ XX } },
+  { "rdpmc",		{ XX } },
+  { "sysenter",		{ XX } },
+  { "sysexit",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
   /* 38 */
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
+  { THREE_BYTE_0 },
+  { "(bad)",		{ XX } },
+  { THREE_BYTE_1 },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
   /* 40 */
-  { "cmovo",		Gv, Ev, XX },
-  { "cmovno",		Gv, Ev, XX },
-  { "cmovb",		Gv, Ev, XX },
-  { "cmovae",		Gv, Ev, XX },
-  { "cmove",		Gv, Ev, XX },
-  { "cmovne",		Gv, Ev, XX },
-  { "cmovbe",		Gv, Ev, XX },
-  { "cmova",		Gv, Ev, XX },
+  { "cmovo",		{ Gv, Ev } },
+  { "cmovno",		{ Gv, Ev } },
+  { "cmovb",		{ Gv, Ev } },
+  { "cmovae",		{ Gv, Ev } },
+  { "cmove",		{ Gv, Ev } },
+  { "cmovne",		{ Gv, Ev } },
+  { "cmovbe",		{ Gv, Ev } },
+  { "cmova",		{ Gv, Ev } },
   /* 48 */
-  { "cmovs",		Gv, Ev, XX },
-  { "cmovns",		Gv, Ev, XX },
-  { "cmovp",		Gv, Ev, XX },
-  { "cmovnp",		Gv, Ev, XX },
-  { "cmovl",		Gv, Ev, XX },
-  { "cmovge",		Gv, Ev, XX },
-  { "cmovle",		Gv, Ev, XX },
-  { "cmovg",		Gv, Ev, XX },
+  { "cmovs",		{ Gv, Ev } },
+  { "cmovns",		{ Gv, Ev } },
+  { "cmovp",		{ Gv, Ev } },
+  { "cmovnp",		{ Gv, Ev } },
+  { "cmovl",		{ Gv, Ev } },
+  { "cmovge",		{ Gv, Ev } },
+  { "cmovle",		{ Gv, Ev } },
+  { "cmovg",		{ Gv, Ev } },
   /* 50 */
-  { "movmskpX",		Gd, XS, XX },
+  { "movmskpX",		{ Gdq, XS } },
   { PREGRP13 },
   { PREGRP12 },
   { PREGRP11 },
-  { "andpX",		XM, EX, XX },
-  { "andnpX",		XM, EX, XX },
-  { "orpX",		XM, EX, XX },
-  { "xorpX",		XM, EX, XX },
+  { "andpX",		{ XM, EXx } },
+  { "andnpX",		{ XM, EXx } },
+  { "orpX",		{ XM, EXx } },
+  { "xorpX",		{ XM, EXx } },
   /* 58 */
   { PREGRP0 },
   { PREGRP10 },
@@ -864,185 +1121,185 @@
   { PREGRP5 },
   { PREGRP6 },
   /* 60 */
-  { "punpcklbw",	MX, EM, XX },
-  { "punpcklwd",	MX, EM, XX },
-  { "punpckldq",	MX, EM, XX },
-  { "packsswb",		MX, EM, XX },
-  { "pcmpgtb",		MX, EM, XX },
-  { "pcmpgtw",		MX, EM, XX },
-  { "pcmpgtd",		MX, EM, XX },
-  { "packuswb",		MX, EM, XX },
+  { PREGRP95 },
+  { PREGRP96 },
+  { PREGRP97 },
+  { "packsswb",		{ MX, EM } },
+  { "pcmpgtb",		{ MX, EM } },
+  { "pcmpgtw",		{ MX, EM } },
+  { "pcmpgtd",		{ MX, EM } },
+  { "packuswb",		{ MX, EM } },
   /* 68 */
-  { "punpckhbw",	MX, EM, XX },
-  { "punpckhwd",	MX, EM, XX },
-  { "punpckhdq",	MX, EM, XX },
-  { "packssdw",		MX, EM, XX },
+  { "punpckhbw",	{ MX, EM } },
+  { "punpckhwd",	{ MX, EM } },
+  { "punpckhdq",	{ MX, EM } },
+  { "packssdw",		{ MX, EM } },
   { PREGRP26 },
   { PREGRP24 },
-  { "movd",		MX, Ed, XX },
+  { "movd",		{ MX, Edq } },
   { PREGRP19 },
   /* 70 */
   { PREGRP22 },
-  { GRP10 },
-  { GRP11 },
   { GRP12 },
-  { "pcmpeqb",		MX, EM, XX },
-  { "pcmpeqw",		MX, EM, XX },
-  { "pcmpeqd",		MX, EM, XX },
-  { "emms",		XX, XX, XX },
+  { GRP13 },
+  { GRP14 },
+  { "pcmpeqb",		{ MX, EM } },
+  { "pcmpeqw",		{ MX, EM } },
+  { "pcmpeqd",		{ MX, EM } },
+  { "emms",		{ XX } },
   /* 78 */
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
+  { PREGRP34 },
+  { PREGRP35 },
+  { "(bad)",		{ XX } },
+  { "(bad)",		{ XX } },
+  { PREGRP28 },
+  { PREGRP29 },
   { PREGRP23 },
   { PREGRP20 },
   /* 80 */
-  { "joH",		Jv, XX, cond_jump_flag },
-  { "jnoH",		Jv, XX, cond_jump_flag },
-  { "jbH",		Jv, XX, cond_jump_flag },
-  { "jaeH",		Jv, XX, cond_jump_flag },
-  { "jeH",		Jv, XX, cond_jump_flag },
-  { "jneH",		Jv, XX, cond_jump_flag },
-  { "jbeH",		Jv, XX, cond_jump_flag },
-  { "jaH",		Jv, XX, cond_jump_flag },
+  { "joH",		{ Jv, XX, cond_jump_flag } },
+  { "jnoH",		{ Jv, XX, cond_jump_flag } },
+  { "jbH",		{ Jv, XX, cond_jump_flag } },
+  { "jaeH",		{ Jv, XX, cond_jump_flag } },
+  { "jeH",		{ Jv, XX, cond_jump_flag } },
+  { "jneH",		{ Jv, XX, cond_jump_flag } },
+  { "jbeH",		{ Jv, XX, cond_jump_flag } },
+  { "jaH",		{ Jv, XX, cond_jump_flag } },
   /* 88 */
-  { "jsH",		Jv, XX, cond_jump_flag },
-  { "jnsH",		Jv, XX, cond_jump_flag },
-  { "jpH",		Jv, XX, cond_jump_flag },
-  { "jnpH",		Jv, XX, cond_jump_flag },
-  { "jlH",		Jv, XX, cond_jump_flag },
-  { "jgeH",		Jv, XX, cond_jump_flag },
-  { "jleH",		Jv, XX, cond_jump_flag },
-  { "jgH",		Jv, XX, cond_jump_flag },
+  { "jsH",		{ Jv, XX, cond_jump_flag } },
+  { "jnsH",		{ Jv, XX, cond_jump_flag } },
+  { "jpH",		{ Jv, XX, cond_jump_flag } },
+  { "jnpH",		{ Jv, XX, cond_jump_flag } },
+  { "jlH",		{ Jv, XX, cond_jump_flag } },
+  { "jgeH",		{ Jv, XX, cond_jump_flag } },
+  { "jleH",		{ Jv, XX, cond_jump_flag } },
+  { "jgH",		{ Jv, XX, cond_jump_flag } },
   /* 90 */
-  { "seto",		Eb, XX, XX },
-  { "setno",		Eb, XX, XX },
-  { "setb",		Eb, XX, XX },
-  { "setae",		Eb, XX, XX },
-  { "sete",		Eb, XX, XX },
-  { "setne",		Eb, XX, XX },
-  { "setbe",		Eb, XX, XX },
-  { "seta",		Eb, XX, XX },
+  { "seto",		{ Eb } },
+  { "setno",		{ Eb } },
+  { "setb",		{ Eb } },
+  { "setae",		{ Eb } },
+  { "sete",		{ Eb } },
+  { "setne",		{ Eb } },
+  { "setbe",		{ Eb } },
+  { "seta",		{ Eb } },
   /* 98 */
-  { "sets",		Eb, XX, XX },
-  { "setns",		Eb, XX, XX },
-  { "setp",		Eb, XX, XX },
-  { "setnp",		Eb, XX, XX },
-  { "setl",		Eb, XX, XX },
-  { "setge",		Eb, XX, XX },
-  { "setle",		Eb, XX, XX },
-  { "setg",		Eb, XX, XX },
+  { "sets",		{ Eb } },
+  { "setns",		{ Eb } },
+  { "setp",		{ Eb } },
+  { "setnp",		{ Eb } },
+  { "setl",		{ Eb } },
+  { "setge",		{ Eb } },
+  { "setle",		{ Eb } },
+  { "setg",		{ Eb } },
   /* a0 */
-  { "pushT",		fs, XX, XX },
-  { "popT",		fs, XX, XX },
-  { "cpuid",		XX, XX, XX },
-  { "btS",		Ev, Gv, XX },
-  { "shldS",		Ev, Gv, Ib },
-  { "shldS",		Ev, Gv, CL },
-  { "(bad)",		XX, XX, XX },
-  { "(bad)",		XX, XX, XX },
+  { "pushT",		{ fs } },
+  { "popT",		{ fs } },
+  { "cpuid",		{ XX } },
+  { "btS",		{ Ev, Gv } },
+  { "shldS",		{ Ev, Gv, Ib } },
+  { "shldS",		{ Ev, Gv, CL } },
+  { GRPPADLCK2 },
+  { GRPPADLCK1 },
   /* a8 */
-  { "pushT",		gs, XX, XX },
-  { "popT",		gs, XX, XX },
-  { "rsm",		XX, XX, XX },
-  { "btsS",		Ev, Gv, XX },
-  { "shrdS",		Ev, Gv, Ib },
-  { "shrdS",		Ev, Gv, CL },
-  { GRP13 },
-  { "imulS",		Gv, Ev, XX },
+  { "pushT",		{ gs } },
+  { "popT",		{ gs } },
+  { "rsm",		{ XX } },
+  { "btsS",		{ Ev, Gv } },
+  { "shrdS",		{ Ev, Gv, Ib } },
+  { "shrdS",		{ Ev, Gv, CL } },
+  { GRP15 },
+  { "imulS",		{ Gv, Ev } },
   /* b0 */
-  { "cmpxchgB",		Eb, Gb, XX },
-  { "cmpxchgS",		Ev, Gv, XX },
-  { "lssS",		Gv, Mp, XX },
-  { "btrS",		Ev, Gv, XX },
-  { "lfsS",		Gv, Mp, XX },
-  { "lgsS",		Gv, Mp, XX },
-  { "movz{bR|x|bR|x}",	Gv, Eb, XX },
-  { "movz{wR|x|wR|x}",	Gv, Ew, XX }, /* yes, there really is movzww ! */
+  { "cmpxchgB",		{ Eb, Gb } },
+  { "cmpxchgS",		{ Ev, Gv } },
+  { "lssS",		{ Gv, Mp } },
+  { "btrS",		{ Ev, Gv } },
+  { "lfsS",		{ Gv, Mp } },
+  { "lgsS",		{ Gv, Mp } },
+  { "movz{bR|x|bR|x}",	{ Gv, Eb } },
+  { "movz{wR|x|wR|x}",	{ Gv, Ew } }, /* yes, there really is movzww ! */
   /* b8 */
-  { "(bad)",		XX, XX, XX },
-  { "ud2b",		XX, XX, XX },
+  { PREGRP37 },
+  { "ud2b",		{ XX } },
   { GRP8 },
-  { "btcS",		Ev, Gv, XX },
-  { "bsfS",		Gv, Ev, XX },
-  { "bsrS",		Gv, Ev, XX },
-  { "movs{bR|x|bR|x}",	Gv, Eb, XX },
-  { "movs{wR|x|wR|x}",	Gv, Ew, XX }, /* yes, there really is movsww ! */
+  { "btcS",		{ Ev, Gv } },
+  { "bsfS",		{ Gv, Ev } },
+  { PREGRP36 },
+  { "movs{bR|x|bR|x}",	{ Gv, Eb } },
+  { "movs{wR|x|wR|x}",	{ Gv, Ew } }, /* yes, there really is movsww ! */
   /* c0 */
-  { "xaddB",		Eb, Gb, XX },
-  { "xaddS",		Ev, Gv, XX },
+  { "xaddB",		{ Eb, Gb } },
+  { "xaddS",		{ Ev, Gv } },
   { PREGRP1 },
-  { "movntiS",		Ev, Gv, XX },
-  { "pinsrw",		MX, Ed, Ib },
-  { "pextrw",		Gd, MS, Ib },
-  { "shufpX",		XM, EX, Ib },
+  { "movntiS",		{ Ev, Gv } },
+  { "pinsrw",		{ MX, Edqw, Ib } },
+  { "pextrw",		{ Gdq, MS, Ib } },
+  { "shufpX",		{ XM, EXx, Ib } },
   { GRP9 },
   /* c8 */
-  { "bswap",		RMeAX, XX, XX },
-  { "bswap",		RMeCX, XX, XX },
-  { "bswap",		RMeDX, XX, XX },
-  { "bswap",		RMeBX, XX, XX },
-  { "bswap",		RMeSP, XX, XX },
-  { "bswap",		RMeBP, XX, XX },
-  { "bswap",		RMeSI, XX, XX },
-  { "bswap",		RMeDI, XX, XX },
+  { "bswap",		{ RMeAX } },
+  { "bswap",		{ RMeCX } },
+  { "bswap",		{ RMeDX } },
+  { "bswap",		{ RMeBX } },
+  { "bswap",		{ RMeSP } },
+  { "bswap",		{ RMeBP } },
+  { "bswap",		{ RMeSI } },
+  { "bswap",		{ RMeDI } },
   /* d0 */
-  { "(bad)",		XX, XX, XX },
-  { "psrlw",		MX, EM, XX },
-  { "psrld",		MX, EM, XX },
-  { "psrlq",		MX, EM, XX },
-  { "paddq",		MX, EM, XX },
-  { "pmullw",		MX, EM, XX },
+  { PREGRP27 },
+  { "psrlw",		{ MX, EM } },
+  { "psrld",		{ MX, EM } },
+  { "psrlq",		{ MX, EM } },
+  { "paddq",		{ MX, EM } },
+  { "pmullw",		{ MX, EM } },
   { PREGRP21 },
-  { "pmovmskb",		Gd, MS, XX },
+  { "pmovmskb",		{ Gdq, MS } },
   /* d8 */
-  { "psubusb",		MX, EM, XX },
-  { "psubusw",		MX, EM, XX },
-  { "pminub",		MX, EM, XX },
-  { "pand",		MX, EM, XX },
-  { "paddusb",		MX, EM, XX },
-  { "paddusw",		MX, EM, XX },
-  { "pmaxub",		MX, EM, XX },
-  { "pandn",		MX, EM, XX },
+  { "psubusb",		{ MX, EM } },
+  { "psubusw",		{ MX, EM } },
+  { "pminub",		{ MX, EM } },
+  { "pand",		{ MX, EM } },
+  { "paddusb",		{ MX, EM } },
+  { "paddusw",		{ MX, EM } },
+  { "pmaxub",		{ MX, EM } },
+  { "pandn",		{ MX, EM } },
   /* e0 */
-  { "pavgb",		MX, EM, XX },
-  { "psraw",		MX, EM, XX },
-  { "psrad",		MX, EM, XX },
-  { "pavgw",		MX, EM, XX },
-  { "pmulhuw",		MX, EM, XX },
-  { "pmulhw",		MX, EM, XX },
+  { "pavgb",		{ MX, EM } },
+  { "psraw",		{ MX, EM } },
+  { "psrad",		{ MX, EM } },
+  { "pavgw",		{ MX, EM } },
+  { "pmulhuw",		{ MX, EM } },
+  { "pmulhw",		{ MX, EM } },
   { PREGRP15 },
   { PREGRP25 },
   /* e8 */
-  { "psubsb",		MX, EM, XX },
-  { "psubsw",		MX, EM, XX },
-  { "pminsw",		MX, EM, XX },
-  { "por",		MX, EM, XX },
-  { "paddsb",		MX, EM, XX },
-  { "paddsw",		MX, EM, XX },
-  { "pmaxsw",		MX, EM, XX },
-  { "pxor",		MX, EM, XX },
+  { "psubsb",		{ MX, EM } },
+  { "psubsw",		{ MX, EM } },
+  { "pminsw",		{ MX, EM } },
+  { "por",		{ MX, EM } },
+  { "paddsb",		{ MX, EM } },
+  { "paddsw",		{ MX, EM } },
+  { "pmaxsw",		{ MX, EM } },
+  { "pxor",		{ MX, EM } },
   /* f0 */
-  { "(bad)",		XX, XX, XX },
-  { "psllw",		MX, EM, XX },
-  { "pslld",		MX, EM, XX },
-  { "psllq",		MX, EM, XX },
-  { "pmuludq",		MX, EM, XX },
-  { "pmaddwd",		MX, EM, XX },
-  { "psadbw",		MX, EM, XX },
+  { PREGRP32 },
+  { "psllw",		{ MX, EM } },
+  { "pslld",		{ MX, EM } },
+  { "psllq",		{ MX, EM } },
+  { "pmuludq",		{ MX, EM } },
+  { "pmaddwd",		{ MX, EM } },
+  { "psadbw",		{ MX, EM } },
   { PREGRP18 },
   /* f8 */
-  { "psubb",		MX, EM, XX },
-  { "psubw",		MX, EM, XX },
-  { "psubd",		MX, EM, XX },
-  { "psubq",		MX, EM, XX },
-  { "paddb",		MX, EM, XX },
-  { "paddw",		MX, EM, XX },
-  { "paddd",		MX, EM, XX },
-  { "(bad)",		XX, XX, XX }
+  { "psubb",		{ MX, EM } },
+  { "psubw",		{ MX, EM } },
+  { "psubd",		{ MX, EM } },
+  { "psubq",		{ MX, EM } },
+  { "paddb",		{ MX, EM } },
+  { "paddw",		{ MX, EM } },
+  { "paddd",		{ MX, EM } },
+  { "(bad)",		{ XX } },
 };
 
 static const unsigned char onebyte_has_modrm[256] = {
@@ -1072,44 +1329,234 @@
   /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
   /*       -------------------------------        */
   /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */
-  /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */
+  /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1, /* 1f */
   /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */
-  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */
   /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */
   /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */
   /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */
-  /* 70 */ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */
+  /* 70 */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 7f */
   /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
   /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */
-  /* a0 */ 0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1, /* af */
-  /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */
+  /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */
+  /* b0 */ 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1, /* bf */
   /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */
-  /* d0 */ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */
+  /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */
   /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */
-  /* f0 */ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0  /* ff */
+  /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0  /* ff */
   /*       -------------------------------        */
   /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
 };
 
-static const unsigned char twobyte_uses_SSE_prefix[256] = {
+static const unsigned char twobyte_uses_DATA_prefix[256] = {
   /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
   /*       -------------------------------        */
   /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
-  /* 10 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
-  /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */
-  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */
   /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
   /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */
   /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */
-  /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */
+  /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1, /* 7f */
   /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
   /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
   /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
   /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
   /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0  /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+static const unsigned char twobyte_uses_REPNZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,1,0,0,0,0,0,0,1,1,1,0,1,1,1,1, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+static const unsigned char twobyte_uses_REPZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6f */
+  /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, /* bf */
+  /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
   /* d0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */
   /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */
-  /* f0 */ 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0  /* ff */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 38 XX uses DATA prefix.  */
+static const unsigned char threebyte_0x38_uses_DATA_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 0f */
+  /* 10 */ 1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0, /* 1f */
+  /* 20 */ 1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0, /* 2f */
+  /* 30 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* 3f */
+  /* 40 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 38 XX uses REPNZ prefix.  */
+static const unsigned char threebyte_0x38_uses_REPNZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 38 XX uses REPZ prefix.  */
+static const unsigned char threebyte_0x38_uses_REPZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 3a XX uses DATA prefix.  */
+static const unsigned char threebyte_0x3a_uses_DATA_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1, /* 0f */
+  /* 10 */ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 3a XX uses REPNZ prefix.  */
+static const unsigned char threebyte_0x3a_uses_REPNZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
+  /*       -------------------------------        */
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+};
+
+/* This is used to determine if opcode 0f 3a XX uses REPZ prefix.  */
+static const unsigned char threebyte_0x3a_uses_REPZ_prefix[256] = {
+  /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
+  /*       -------------------------------        */
+  /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+  /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */
+  /* 20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */
+  /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+  /* c0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */
+  /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ff */
   /*       -------------------------------        */
   /*       0 1 2 3 4 5 6 7 8 9 a b c d e f        */
 };
@@ -1121,9 +1568,13 @@
 static unsigned char *insn_codep;
 static unsigned char *codep;
 static disassemble_info *the_info;
-static int mod;
-static int rm;
-static int reg;
+static struct
+  {
+    int mod;
+    int reg;
+    int rm;
+  }
+modrm;
 static unsigned char need_modrm;
 
 /* If we are accessing mod/rm/reg without need_modrm set, then the
@@ -1131,526 +1582,1738 @@
    need to update onebyte_has_modrm or twobyte_has_modrm.  */
 #define MODRM_CHECK  if (!need_modrm) abort ()
 
-static const char **names64;
-static const char **names32;
-static const char **names16;
-static const char **names8;
-static const char **names8rex;
-static const char **names_seg;
-static const char **index16;
+static const char * const *names64;
+static const char * const *names32;
+static const char * const *names16;
+static const char * const *names8;
+static const char * const *names8rex;
+static const char * const *names_seg;
+static const char * const *index16;
 
-static const char *intel_names64[] = {
+static const char * const intel_names64[] = {
   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
 };
-static const char *intel_names32[] = {
+static const char * const intel_names32[] = {
   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
   "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
 };
-static const char *intel_names16[] = {
+static const char * const intel_names16[] = {
   "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
   "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
 };
-static const char *intel_names8[] = {
+static const char * const intel_names8[] = {
   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
 };
-static const char *intel_names8rex[] = {
+static const char * const intel_names8rex[] = {
   "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
   "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"
 };
-static const char *intel_names_seg[] = {
+static const char * const intel_names_seg[] = {
   "es", "cs", "ss", "ds", "fs", "gs", "?", "?",
 };
-static const char *intel_index16[] = {
+static const char * const intel_index16[] = {
   "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"
 };
 
-static const char *att_names64[] = {
+static const char * const att_names64[] = {
   "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
   "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"
 };
-static const char *att_names32[] = {
+static const char * const att_names32[] = {
   "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
   "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d"
 };
-static const char *att_names16[] = {
+static const char * const att_names16[] = {
   "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
   "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w"
 };
-static const char *att_names8[] = {
+static const char * const att_names8[] = {
   "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh",
 };
-static const char *att_names8rex[] = {
+static const char * const att_names8rex[] = {
   "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil",
   "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b"
 };
-static const char *att_names_seg[] = {
+static const char * const att_names_seg[] = {
   "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?",
 };
-static const char *att_index16[] = {
+static const char * const att_index16[] = {
   "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx"
 };
 
 static const struct dis386 grps[][8] = {
+  /* GRP1a */
+  {
+    { "popU",	{ stackEv } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+  },
   /* GRP1b */
   {
-    { "addA",	Eb, Ib, XX },
-    { "orA",	Eb, Ib, XX },
-    { "adcA",	Eb, Ib, XX },
-    { "sbbA",	Eb, Ib, XX },
-    { "andA",	Eb, Ib, XX },
-    { "subA",	Eb, Ib, XX },
-    { "xorA",	Eb, Ib, XX },
-    { "cmpA",	Eb, Ib, XX }
+    { "addA",	{ Eb, Ib } },
+    { "orA",	{ Eb, Ib } },
+    { "adcA",	{ Eb, Ib } },
+    { "sbbA",	{ Eb, Ib } },
+    { "andA",	{ Eb, Ib } },
+    { "subA",	{ Eb, Ib } },
+    { "xorA",	{ Eb, Ib } },
+    { "cmpA",	{ Eb, Ib } },
   },
   /* GRP1S */
   {
-    { "addQ",	Ev, Iv, XX },
-    { "orQ",	Ev, Iv, XX },
-    { "adcQ",	Ev, Iv, XX },
-    { "sbbQ",	Ev, Iv, XX },
-    { "andQ",	Ev, Iv, XX },
-    { "subQ",	Ev, Iv, XX },
-    { "xorQ",	Ev, Iv, XX },
-    { "cmpQ",	Ev, Iv, XX }
+    { "addQ",	{ Ev, Iv } },
+    { "orQ",	{ Ev, Iv } },
+    { "adcQ",	{ Ev, Iv } },
+    { "sbbQ",	{ Ev, Iv } },
+    { "andQ",	{ Ev, Iv } },
+    { "subQ",	{ Ev, Iv } },
+    { "xorQ",	{ Ev, Iv } },
+    { "cmpQ",	{ Ev, Iv } },
   },
   /* GRP1Ss */
   {
-    { "addQ",	Ev, sIb, XX },
-    { "orQ",	Ev, sIb, XX },
-    { "adcQ",	Ev, sIb, XX },
-    { "sbbQ",	Ev, sIb, XX },
-    { "andQ",	Ev, sIb, XX },
-    { "subQ",	Ev, sIb, XX },
-    { "xorQ",	Ev, sIb, XX },
-    { "cmpQ",	Ev, sIb, XX }
+    { "addQ",	{ Ev, sIb } },
+    { "orQ",	{ Ev, sIb } },
+    { "adcQ",	{ Ev, sIb } },
+    { "sbbQ",	{ Ev, sIb } },
+    { "andQ",	{ Ev, sIb } },
+    { "subQ",	{ Ev, sIb } },
+    { "xorQ",	{ Ev, sIb } },
+    { "cmpQ",	{ Ev, sIb } },
   },
   /* GRP2b */
   {
-    { "rolA",	Eb, Ib, XX },
-    { "rorA",	Eb, Ib, XX },
-    { "rclA",	Eb, Ib, XX },
-    { "rcrA",	Eb, Ib, XX },
-    { "shlA",	Eb, Ib, XX },
-    { "shrA",	Eb, Ib, XX },
-    { "(bad)",	XX, XX, XX },
-    { "sarA",	Eb, Ib, XX },
+    { "rolA",	{ Eb, Ib } },
+    { "rorA",	{ Eb, Ib } },
+    { "rclA",	{ Eb, Ib } },
+    { "rcrA",	{ Eb, Ib } },
+    { "shlA",	{ Eb, Ib } },
+    { "shrA",	{ Eb, Ib } },
+    { "(bad)",	{ XX } },
+    { "sarA",	{ Eb, Ib } },
   },
   /* GRP2S */
   {
-    { "rolQ",	Ev, Ib, XX },
-    { "rorQ",	Ev, Ib, XX },
-    { "rclQ",	Ev, Ib, XX },
-    { "rcrQ",	Ev, Ib, XX },
-    { "shlQ",	Ev, Ib, XX },
-    { "shrQ",	Ev, Ib, XX },
-    { "(bad)",	XX, XX, XX },
-    { "sarQ",	Ev, Ib, XX },
+    { "rolQ",	{ Ev, Ib } },
+    { "rorQ",	{ Ev, Ib } },
+    { "rclQ",	{ Ev, Ib } },
+    { "rcrQ",	{ Ev, Ib } },
+    { "shlQ",	{ Ev, Ib } },
+    { "shrQ",	{ Ev, Ib } },
+    { "(bad)",	{ XX } },
+    { "sarQ",	{ Ev, Ib } },
   },
   /* GRP2b_one */
   {
-    { "rolA",	Eb, XX, XX },
-    { "rorA",	Eb, XX, XX },
-    { "rclA",	Eb, XX, XX },
-    { "rcrA",	Eb, XX, XX },
-    { "shlA",	Eb, XX, XX },
-    { "shrA",	Eb, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "sarA",	Eb, XX, XX },
+    { "rolA",	{ Eb, I1 } },
+    { "rorA",	{ Eb, I1 } },
+    { "rclA",	{ Eb, I1 } },
+    { "rcrA",	{ Eb, I1 } },
+    { "shlA",	{ Eb, I1 } },
+    { "shrA",	{ Eb, I1 } },
+    { "(bad)",	{ XX } },
+    { "sarA",	{ Eb, I1 } },
   },
   /* GRP2S_one */
   {
-    { "rolQ",	Ev, XX, XX },
-    { "rorQ",	Ev, XX, XX },
-    { "rclQ",	Ev, XX, XX },
-    { "rcrQ",	Ev, XX, XX },
-    { "shlQ",	Ev, XX, XX },
-    { "shrQ",	Ev, XX, XX },
-    { "(bad)",	XX, XX, XX},
-    { "sarQ",	Ev, XX, XX },
+    { "rolQ",	{ Ev, I1 } },
+    { "rorQ",	{ Ev, I1 } },
+    { "rclQ",	{ Ev, I1 } },
+    { "rcrQ",	{ Ev, I1 } },
+    { "shlQ",	{ Ev, I1 } },
+    { "shrQ",	{ Ev, I1 } },
+    { "(bad)",	{ XX } },
+    { "sarQ",	{ Ev, I1 } },
   },
   /* GRP2b_cl */
   {
-    { "rolA",	Eb, CL, XX },
-    { "rorA",	Eb, CL, XX },
-    { "rclA",	Eb, CL, XX },
-    { "rcrA",	Eb, CL, XX },
-    { "shlA",	Eb, CL, XX },
-    { "shrA",	Eb, CL, XX },
-    { "(bad)",	XX, XX, XX },
-    { "sarA",	Eb, CL, XX },
+    { "rolA",	{ Eb, CL } },
+    { "rorA",	{ Eb, CL } },
+    { "rclA",	{ Eb, CL } },
+    { "rcrA",	{ Eb, CL } },
+    { "shlA",	{ Eb, CL } },
+    { "shrA",	{ Eb, CL } },
+    { "(bad)",	{ XX } },
+    { "sarA",	{ Eb, CL } },
   },
   /* GRP2S_cl */
   {
-    { "rolQ",	Ev, CL, XX },
-    { "rorQ",	Ev, CL, XX },
-    { "rclQ",	Ev, CL, XX },
-    { "rcrQ",	Ev, CL, XX },
-    { "shlQ",	Ev, CL, XX },
-    { "shrQ",	Ev, CL, XX },
-    { "(bad)",	XX, XX, XX },
-    { "sarQ",	Ev, CL, XX }
+    { "rolQ",	{ Ev, CL } },
+    { "rorQ",	{ Ev, CL } },
+    { "rclQ",	{ Ev, CL } },
+    { "rcrQ",	{ Ev, CL } },
+    { "shlQ",	{ Ev, CL } },
+    { "shrQ",	{ Ev, CL } },
+    { "(bad)",	{ XX } },
+    { "sarQ",	{ Ev, CL } },
   },
   /* GRP3b */
   {
-    { "testA",	Eb, Ib, XX },
-    { "(bad)",	Eb, XX, XX },
-    { "notA",	Eb, XX, XX },
-    { "negA",	Eb, XX, XX },
-    { "mulA",	Eb, XX, XX },	/* Don't print the implicit %al register,  */
-    { "imulA",	Eb, XX, XX },	/* to distinguish these opcodes from other */
-    { "divA",	Eb, XX, XX },	/* mul/imul opcodes.  Do the same for div  */
-    { "idivA",	Eb, XX, XX }	/* and idiv for consistency.		   */
+    { "testA",	{ Eb, Ib } },
+    { "(bad)",	{ Eb } },
+    { "notA",	{ Eb } },
+    { "negA",	{ Eb } },
+    { "mulA",	{ Eb } },	/* Don't print the implicit %al register,  */
+    { "imulA",	{ Eb } },	/* to distinguish these opcodes from other */
+    { "divA",	{ Eb } },	/* mul/imul opcodes.  Do the same for div  */
+    { "idivA",	{ Eb } },	/* and idiv for consistency.		   */
   },
   /* GRP3S */
   {
-    { "testQ",	Ev, Iv, XX },
-    { "(bad)",	XX, XX, XX },
-    { "notQ",	Ev, XX, XX },
-    { "negQ",	Ev, XX, XX },
-    { "mulQ",	Ev, XX, XX },	/* Don't print the implicit register.  */
-    { "imulQ",	Ev, XX, XX },
-    { "divQ",	Ev, XX, XX },
-    { "idivQ",	Ev, XX, XX },
+    { "testQ",	{ Ev, Iv } },
+    { "(bad)",	{ XX } },
+    { "notQ",	{ Ev } },
+    { "negQ",	{ Ev } },
+    { "mulQ",	{ Ev } },	/* Don't print the implicit register.  */
+    { "imulQ",	{ Ev } },
+    { "divQ",	{ Ev } },
+    { "idivQ",	{ Ev } },
   },
   /* GRP4 */
   {
-    { "incA",	Eb, XX, XX },
-    { "decA",	Eb, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
+    { "incA",	{ Eb } },
+    { "decA",	{ Eb } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
   },
   /* GRP5 */
   {
-    { "incQ",	Ev, XX, XX },
-    { "decQ",	Ev, XX, XX },
-    { "callT",	indirEv, XX, XX },
-    { "lcallT",	indirEv, XX, XX },
-    { "jmpT",	indirEv, XX, XX },
-    { "ljmpT",	indirEv, XX, XX },
-    { "pushU",	Ev, XX, XX },
-    { "(bad)",	XX, XX, XX },
+    { "incQ",	{ Ev } },
+    { "decQ",	{ Ev } },
+    { "callT",	{ indirEv } },
+    { "JcallT",	{ indirEp } },
+    { "jmpT",	{ indirEv } },
+    { "JjmpT",	{ indirEp } },
+    { "pushU",	{ stackEv } },
+    { "(bad)",	{ XX } },
   },
   /* GRP6 */
   {
-    { "sldtQ",	Ev, XX, XX },
-    { "strQ",	Ev, XX, XX },
-    { "lldt",	Ew, XX, XX },
-    { "ltr",	Ew, XX, XX },
-    { "verr",	Ew, XX, XX },
-    { "verw",	Ew, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX }
+    { "sldtD",	{ Sv } },
+    { "strD",	{ Sv } },
+    { "lldt",	{ Ew } },
+    { "ltr",	{ Ew } },
+    { "verr",	{ Ew } },
+    { "verw",	{ Ew } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
   },
   /* GRP7 */
   {
-    { "sgdtQ",	 M, XX, XX },
-    { "sidtQ",	 M, XX, XX },
-    { "lgdtQ",	 M, XX, XX },
-    { "lidtQ",	 M, XX, XX },
-    { "smswQ",	Ev, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "lmsw",	Ew, XX, XX },
-    { "invlpg",	Ew, XX, XX },
+    { "sgdt{Q|IQ||}", { { VMX_Fixup, 0 } } },
+    { "sidt{Q|IQ||}", { { PNI_Fixup, 0 } } },
+    { "lgdt{Q|Q||}",	 { M } },
+    { "lidt{Q|Q||}",	 { { SVME_Fixup, 0 } } },
+    { "smswD",	{ Sv } },
+    { "(bad)",	{ XX } },
+    { "lmsw",	{ Ew } },
+    { "invlpg",	{ { INVLPG_Fixup, w_mode } } },
   },
   /* GRP8 */
   {
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "btQ",	Ev, Ib, XX },
-    { "btsQ",	Ev, Ib, XX },
-    { "btrQ",	Ev, Ib, XX },
-    { "btcQ",	Ev, Ib, XX },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "btQ",	{ Ev, Ib } },
+    { "btsQ",	{ Ev, Ib } },
+    { "btrQ",	{ Ev, Ib } },
+    { "btcQ",	{ Ev, Ib } },
   },
   /* GRP9 */
   {
-    { "(bad)",	XX, XX, XX },
-    { "cmpxchg8b", Ev, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
+    { "(bad)",	{ XX } },
+    { "cmpxchg8b", { { CMPXCHG8B_Fixup, q_mode } } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "",	{ VM } },		/* See OP_VMX.  */
+    { "vmptrst", { Mq } },
   },
-  /* GRP10 */
+  /* GRP11_C6 */
   {
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "psrlw",	MS, Ib, XX },
-    { "(bad)",	XX, XX, XX },
-    { "psraw",	MS, Ib, XX },
-    { "(bad)",	XX, XX, XX },
-    { "psllw",	MS, Ib, XX },
-    { "(bad)",	XX, XX, XX },
+    { "movA",	{ Eb, Ib } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
   },
-  /* GRP11 */
+  /* GRP11_C7 */
   {
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "psrld",	MS, Ib, XX },
-    { "(bad)",	XX, XX, XX },
-    { "psrad",	MS, Ib, XX },
-    { "(bad)",	XX, XX, XX },
-    { "pslld",	MS, Ib, XX },
-    { "(bad)",	XX, XX, XX },
+    { "movQ",	{ Ev, Iv } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",  { XX } },
   },
   /* GRP12 */
   {
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "psrlq",	MS, Ib, XX },
-    { "psrldq",	MS, Ib, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "psllq",	MS, Ib, XX },
-    { "pslldq",	MS, Ib, XX },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "psrlw",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "psraw",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "psllw",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
   },
   /* GRP13 */
   {
-    { "fxsave", Ev, XX, XX },
-    { "fxrstor", Ev, XX, XX },
-    { "ldmxcsr", Ev, XX, XX },
-    { "stmxcsr", Ev, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "lfence", None, XX, XX },
-    { "mfence", None, XX, XX },
-    { "sfence", None, XX, XX },
-    /* FIXME: the sfence with memory operand is clflush!  */
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "psrld",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "psrad",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "pslld",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
   },
   /* GRP14 */
   {
-    { "prefetchnta", Ev, XX, XX },
-    { "prefetcht0", Ev, XX, XX },
-    { "prefetcht1", Ev, XX, XX },
-    { "prefetcht2", Ev, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "psrlq",	{ MS, Ib } },
+    { "psrldq",	{ MS, Ib } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "psllq",	{ MS, Ib } },
+    { "pslldq",	{ MS, Ib } },
+  },
+  /* GRP15 */
+  {
+    { "fxsave",		{ Ev } },
+    { "fxrstor",	{ Ev } },
+    { "ldmxcsr",	{ Ev } },
+    { "stmxcsr",	{ Ev } },
+    { "(bad)",		{ XX } },
+    { "lfence",		{ { OP_0fae, 0 } } },
+    { "mfence",		{ { OP_0fae, 0 } } },
+    { "clflush",	{ { OP_0fae, 0 } } },
+  },
+  /* GRP16 */
+  {
+    { "prefetchnta",	{ Ev } },
+    { "prefetcht0",	{ Ev } },
+    { "prefetcht1",	{ Ev } },
+    { "prefetcht2",	{ Ev } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
   },
   /* GRPAMD */
   {
-    { "prefetch", Eb, XX, XX },
-    { "prefetchw", Eb, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
+    { "prefetch",	{ Eb } },
+    { "prefetchw",	{ Eb } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+    { "(bad)",		{ XX } },
+  },
+  /* GRPPADLCK1 */
+  {
+    { "xstore-rng",	{ { OP_0f07, 0 } } },
+    { "xcrypt-ecb",	{ { OP_0f07, 0 } } },
+    { "xcrypt-cbc",	{ { OP_0f07, 0 } } },
+    { "xcrypt-ctr",	{ { OP_0f07, 0 } } },
+    { "xcrypt-cfb",	{ { OP_0f07, 0 } } },
+    { "xcrypt-ofb",	{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+  },
+  /* GRPPADLCK2 */
+  {
+    { "montmul",	{ { OP_0f07, 0 } } },
+    { "xsha1",		{ { OP_0f07, 0 } } },
+    { "xsha256",	{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
+    { "(bad)",		{ { OP_0f07, 0 } } },
   }
 };
 
 static const struct dis386 prefix_user_table[][4] = {
   /* PREGRP0 */
   {
-    { "addps", XM, EX, XX },
-    { "addss", XM, EX, XX },
-    { "addpd", XM, EX, XX },
-    { "addsd", XM, EX, XX },
+    { "addps", { XM, EXx } },
+    { "addss", { XM, EXd } },
+    { "addpd", { XM, EXx } },
+    { "addsd", { XM, EXq } },
   },
   /* PREGRP1 */
   {
-    { "", XM, EX, OPSIMD },	/* See OP_SIMD_SUFFIX.  */
-    { "", XM, EX, OPSIMD },
-    { "", XM, EX, OPSIMD },
-    { "", XM, EX, OPSIMD },
+    { "", { XM, EXx, OPSIMD } },	/* See OP_SIMD_SUFFIX.  */
+    { "", { XM, EXx, OPSIMD } },
+    { "", { XM, EXx, OPSIMD } },
+    { "", { XM, EXx, OPSIMD } },
   },
   /* PREGRP2 */
   {
-    { "cvtpi2ps", XM, EM, XX },
-    { "cvtsi2ssY", XM, Ev, XX },
-    { "cvtpi2pd", XM, EM, XX },
-    { "cvtsi2sdY", XM, Ev, XX },
+    { "cvtpi2ps", { XM, EMC } },
+    { "cvtsi2ssY", { XM, Ev } },
+    { "cvtpi2pd", { XM, EMC } },
+    { "cvtsi2sdY", { XM, Ev } },
   },
   /* PREGRP3 */
   {
-    { "cvtps2pi", MX, EX, XX },
-    { "cvtss2siY", Gv, EX, XX },
-    { "cvtpd2pi", MX, EX, XX },
-    { "cvtsd2siY", Gv, EX, XX },
+    { "cvtps2pi", { MXC, EXx } },
+    { "cvtss2siY", { Gv, EXx } },
+    { "cvtpd2pi", { MXC, EXx } },
+    { "cvtsd2siY", { Gv, EXx } },
   },
   /* PREGRP4 */
   {
-    { "cvttps2pi", MX, EX, XX },
-    { "cvttss2siY", Gv, EX, XX },
-    { "cvttpd2pi", MX, EX, XX },
-    { "cvttsd2siY", Gv, EX, XX },
+    { "cvttps2pi", { MXC, EXx } },
+    { "cvttss2siY", { Gv, EXx } },
+    { "cvttpd2pi", { MXC, EXx } },
+    { "cvttsd2siY", { Gv, EXx } },
   },
   /* PREGRP5 */
   {
-    { "divps", XM, EX, XX },
-    { "divss", XM, EX, XX },
-    { "divpd", XM, EX, XX },
-    { "divsd", XM, EX, XX },
+    { "divps",	{ XM, EXx } },
+    { "divss",	{ XM, EXx } },
+    { "divpd",	{ XM, EXx } },
+    { "divsd",	{ XM, EXx } },
   },
   /* PREGRP6 */
   {
-    { "maxps", XM, EX, XX },
-    { "maxss", XM, EX, XX },
-    { "maxpd", XM, EX, XX },
-    { "maxsd", XM, EX, XX },
+    { "maxps",	{ XM, EXx } },
+    { "maxss",	{ XM, EXx } },
+    { "maxpd",	{ XM, EXx } },
+    { "maxsd",	{ XM, EXx } },
   },
   /* PREGRP7 */
   {
-    { "minps", XM, EX, XX },
-    { "minss", XM, EX, XX },
-    { "minpd", XM, EX, XX },
-    { "minsd", XM, EX, XX },
+    { "minps",	{ XM, EXx } },
+    { "minss",	{ XM, EXx } },
+    { "minpd",	{ XM, EXx } },
+    { "minsd",	{ XM, EXx } },
   },
   /* PREGRP8 */
   {
-    { "movups", XM, EX, XX },
-    { "movss", XM, EX, XX },
-    { "movupd", XM, EX, XX },
-    { "movsd", XM, EX, XX },
+    { "movups",	{ XM, EXx } },
+    { "movss",	{ XM, EXx } },
+    { "movupd",	{ XM, EXx } },
+    { "movsd",	{ XM, EXx } },
   },
   /* PREGRP9 */
   {
-    { "movups", EX, XM, XX },
-    { "movss", EX, XM, XX },
-    { "movupd", EX, XM, XX },
-    { "movsd", EX, XM, XX },
+    { "movups",	{ EXx,  XM } },
+    { "movss",	{ EXx,  XM } },
+    { "movupd",	{ EXx,  XM } },
+    { "movsd",	{ EXx,  XM } },
   },
   /* PREGRP10 */
   {
-    { "mulps", XM, EX, XX },
-    { "mulss", XM, EX, XX },
-    { "mulpd", XM, EX, XX },
-    { "mulsd", XM, EX, XX },
+    { "mulps",	{ XM, EXx } },
+    { "mulss",	{ XM, EXx } },
+    { "mulpd",	{ XM, EXx } },
+    { "mulsd",	{ XM, EXx } },
   },
   /* PREGRP11 */
   {
-    { "rcpps", XM, EX, XX },
-    { "rcpss", XM, EX, XX },
-    { "(bad)", XM, EX, XX },
-    { "(bad)", XM, EX, XX },
+    { "rcpps",	{ XM, EXx } },
+    { "rcpss",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
   },
   /* PREGRP12 */
   {
-    { "rsqrtps", XM, EX, XX },
-    { "rsqrtss", XM, EX, XX },
-    { "(bad)", XM, EX, XX },
-    { "(bad)", XM, EX, XX },
+    { "rsqrtps",{ XM, EXx } },
+    { "rsqrtss",{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
   },
   /* PREGRP13 */
   {
-    { "sqrtps", XM, EX, XX },
-    { "sqrtss", XM, EX, XX },
-    { "sqrtpd", XM, EX, XX },
-    { "sqrtsd", XM, EX, XX },
+    { "sqrtps", { XM, EXx } },
+    { "sqrtss", { XM, EXx } },
+    { "sqrtpd", { XM, EXx } },
+    { "sqrtsd",	{ XM, EXx } },
   },
   /* PREGRP14 */
   {
-    { "subps", XM, EX, XX },
-    { "subss", XM, EX, XX },
-    { "subpd", XM, EX, XX },
-    { "subsd", XM, EX, XX },
+    { "subps",	{ XM, EXx } },
+    { "subss",	{ XM, EXx } },
+    { "subpd",	{ XM, EXx } },
+    { "subsd",	{ XM, EXx } },
   },
   /* PREGRP15 */
   {
-    { "(bad)", XM, EX, XX },
-    { "cvtdq2pd", XM, EX, XX },
-    { "cvttpd2dq", XM, EX, XX },
-    { "cvtpd2dq", XM, EX, XX },
+    { "(bad)",	{ XM, EXx } },
+    { "cvtdq2pd", { XM, EXq } },
+    { "cvttpd2dq", { XM, EXx } },
+    { "cvtpd2dq", { XM, EXx } },
   },
   /* PREGRP16 */
   {
-    { "cvtdq2ps", XM, EX, XX },
-    { "cvttps2dq",XM, EX, XX },
-    { "cvtps2dq",XM, EX, XX },
-    { "(bad)", XM, EX, XX },
+    { "cvtdq2ps", { XM, EXx } },
+    { "cvttps2dq", { XM, EXx } },
+    { "cvtps2dq", { XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
   },
   /* PREGRP17 */
   {
-    { "cvtps2pd", XM, EX, XX },
-    { "cvtss2sd", XM, EX, XX },
-    { "cvtpd2ps", XM, EX, XX },
-    { "cvtsd2ss", XM, EX, XX },
+    { "cvtps2pd", { XM, EXq } },
+    { "cvtss2sd", { XM, EXx } },
+    { "cvtpd2ps", { XM, EXx } },
+    { "cvtsd2ss", { XM, EXx } },
   },
   /* PREGRP18 */
   {
-    { "maskmovq", MX, MS, XX },
-    { "(bad)", XM, EX, XX },
-    { "maskmovdqu", XM, EX, XX },
-    { "(bad)", XM, EX, XX },
+    { "maskmovq", { MX, MS } },
+    { "(bad)",	{ XM, EXx } },
+    { "maskmovdqu", { XM, XS } },
+    { "(bad)",	{ XM, EXx } },
   },
   /* PREGRP19 */
   {
-    { "movq", MX, EM, XX },
-    { "movdqu", XM, EX, XX },
-    { "movdqa", XM, EX, XX },
-    { "(bad)", XM, EX, XX },
+    { "movq",	{ MX, EM } },
+    { "movdqu",	{ XM, EXx } },
+    { "movdqa",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
   },
   /* PREGRP20 */
   {
-    { "movq", EM, MX, XX },
-    { "movdqu", EX, XM, XX },
-    { "movdqa", EX, XM, XX },
-    { "(bad)", EX, XM, XX },
+    { "movq",	{ EM, MX } },
+    { "movdqu",	{ EXx,  XM } },
+    { "movdqa",	{ EXx,  XM } },
+    { "(bad)",	{ EXx,  XM } },
   },
   /* PREGRP21 */
   {
-    { "(bad)", EX, XM, XX },
-    { "movq2dq", XM, MS, XX },
-    { "movq", EX, XM, XX },
-    { "movdq2q", MX, XS, XX },
+    { "(bad)",	{ EXx,  XM } },
+    { "movq2dq",{ XM, MS } },
+    { "movq",	{ EXx,  XM } },
+    { "movdq2q",{ MX, XS } },
   },
   /* PREGRP22 */
   {
-    { "pshufw", MX, EM, Ib },
-    { "pshufhw", XM, EX, Ib },
-    { "pshufd", XM, EX, Ib },
-    { "pshuflw", XM, EX, Ib },
+    { "pshufw",	{ MX, EM, Ib } },
+    { "pshufhw",{ XM, EXx, Ib } },
+    { "pshufd",	{ XM, EXx, Ib } },
+    { "pshuflw",{ XM, EXx, Ib } },
   },
   /* PREGRP23 */
   {
-    { "movd", Ed, MX, XX },
-    { "movq", XM, EX, XX },
-    { "movd", Ed, XM, XX },
-    { "(bad)", Ed, XM, XX },
+    { "movd",	{ Edq, MX } },
+    { "movq",	{ XM, EXx } },
+    { "movd",	{ Edq, XM } },
+    { "(bad)",	{ Ed, XM } },
   },
   /* PREGRP24 */
   {
-    { "(bad)", MX, EX, XX },
-    { "(bad)", XM, EX, XX },
-    { "punpckhqdq", XM, EX, XX },
-    { "(bad)", XM, EX, XX },
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "punpckhqdq", { XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
   },
   /* PREGRP25 */
   {
-  { "movntq", Ev, MX, XX },
-  { "(bad)", Ev, XM, XX },
-  { "movntdq", Ev, XM, XX },
-  { "(bad)", Ev, XM, XX },
+    { "movntq",	{ EM, MX } },
+    { "(bad)",	{ EM, XM } },
+    { "movntdq",{ EM, XM } },
+    { "(bad)",	{ EM, XM } },
   },
   /* PREGRP26 */
   {
-    { "(bad)", MX, EX, XX },
-    { "(bad)", XM, EX, XX },
-    { "punpcklqdq", XM, EX, XX },
-    { "(bad)", XM, EX, XX },
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "punpcklqdq", { XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+  },
+  /* PREGRP27 */
+  {
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "addsubpd", { XM, EXx } },
+    { "addsubps", { XM, EXx } },
+  },
+  /* PREGRP28 */
+  {
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "haddpd",	{ XM, EXx } },
+    { "haddps",	{ XM, EXx } },
+  },
+  /* PREGRP29 */
+  {
+    { "(bad)",	{ MX, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "hsubpd",	{ XM, EXx } },
+    { "hsubps",	{ XM, EXx } },
+  },
+  /* PREGRP30 */
+  {
+    { "movlpX",	{ XM, EXq, { SIMD_Fixup, 'h' } } }, /* really only 2 operands */
+    { "movsldup", { XM, EXx } },
+    { "movlpd",	{ XM, EXq } },
+    { "movddup", { XM, EXq } },
+  },
+  /* PREGRP31 */
+  {
+    { "movhpX",	{ XM, EXq, { SIMD_Fixup, 'l' } } },
+    { "movshdup", { XM, EXx } },
+    { "movhpd",	{ XM, EXq } },
+    { "(bad)",	{ XM, EXq } },
+  },
+  /* PREGRP32 */
+  {
+    { "(bad)",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "(bad)",	{ XM, EXx } },
+    { "lddqu",	{ XM, M } },
+  },
+  /* PREGRP33 */
+  {
+    {"movntps", { Ev, XM } },
+    {"movntss", { Ev, XM } },
+    {"movntpd", { Ev, XM } },
+    {"movntsd", { Ev, XM } },
+  },
+
+  /* PREGRP34 */
+  {
+    {"vmread",	{ Em, Gm } },
+    {"(bad)",	{ XX } },
+    {"extrq",	{ XS, Ib, Ib } },
+    {"insertq",	{ XM, XS, Ib, Ib } },
+  },
+
+ /* PREGRP35 */
+  {
+    {"vmwrite",	{ Gm, Em } },
+    {"(bad)",	{ XX } },
+    {"extrq",	{ XM, XS } },
+    {"insertq",	{ XM, XS } },
+  },
+
+  /* PREGRP36 */
+  {
+    { "bsrS",	{ Gv, Ev } },
+    { "lzcntS",	{ Gv, Ev } },
+    { "bsrS",	{ Gv, Ev } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP37 */
+  {
+    { "(bad)", { XX } },
+    { "popcntS", { Gv, Ev } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+  },
+
+  /* PREGRP38 */
+  {
+    { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } },
+    { "pause", { XX } },
+    { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } },
+    { "(bad)", { XX } },
+  },
+
+  /* PREGRP39 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pblendvb", {XM, EXx, XMM0 } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP40 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "blendvps", {XM, EXx, XMM0 } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP41 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "blendvpd", { XM, EXx, XMM0 } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP42 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "ptest",  { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP43 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxbw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP44 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxbd", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP45 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxbq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP46 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxwd", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP47 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxwq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP48 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovsxdq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP49 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmuldq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP50 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpeqq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP51 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "movntdqa", { XM, EM } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP52 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "packusdw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP53 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxbw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP54 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxbd", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP55 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxbq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP56 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxwd", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP57 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxwq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP58 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmovzxdq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP59 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pminsb",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP60 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pminsd",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP61 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pminuw",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP62 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pminud",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP63 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmaxsb",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP64 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmaxsd",	{ XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP65 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmaxuw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP66 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmaxud", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP67 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pmulld", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP68 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "phminposuw", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP69 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "roundps", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP70 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "roundpd", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP71 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "roundss", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP72 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "roundsd", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP73 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "blendps", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP74 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "blendpd", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP75 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pblendw", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP76 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pextrb",	{ Edqb, XM, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP77 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pextrw",	{ Edqw, XM, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP78 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pextrK",	{ Edq, XM, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP79 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "extractps", { Edqd, XM, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP80 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pinsrb",	{ XM, Edqb, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP81 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "insertps", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP82 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pinsrK",	{ XM, Edq, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP83 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "dpps",	{ XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP84 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "dppd",	{ XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP85 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "mpsadbw", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP86 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpgtq", { XM, EXx } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP87 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "crc32",	{ Gdq, { CRC32_Fixup, b_mode } } },
+  },
+
+  /* PREGRP88 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "crc32",	{ Gdq, { CRC32_Fixup, v_mode } } },
+  },
+
+  /* PREGRP89 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpestrm", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP90 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpestri", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP91 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpistrm", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP92 */
+  {
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "pcmpistri", { XM, EXx, Ib } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP93 */
+  {
+    { "ucomiss",{ XM, EXd } },
+    { "(bad)",	{ XX } },
+    { "ucomisd",{ XM, EXq } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP94 */
+  {
+    { "comiss",	{ XM, EXd } },
+    { "(bad)",	{ XX } },
+    { "comisd",	{ XM, EXq } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP95 */
+  {
+    { "punpcklbw",{ MX, EMd } },
+    { "(bad)",	{ XX } },
+    { "punpcklbw",{ MX, EMq } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP96 */
+  {
+    { "punpcklwd",{ MX, EMd } },
+    { "(bad)",	{ XX } },
+    { "punpcklwd",{ MX, EMq } },
+    { "(bad)",	{ XX } },
+  },
+
+  /* PREGRP97 */
+  {
+    { "punpckldq",{ MX, EMd } },
+    { "(bad)",	{ XX } },
+    { "punpckldq",{ MX, EMq } },
+    { "(bad)",	{ XX } },
   },
 };
 
 static const struct dis386 x86_64_table[][2] = {
   {
-    { "arpl", Ew, Gw, XX },
-    { "movs{||lq|xd}", Gv, Ed, XX },
+    { "pusha{P|}", { XX } },
+    { "(bad)", { XX } },
   },
+  {
+    { "popa{P|}", { XX } },
+    { "(bad)", { XX } },
+  },
+  {
+    { "bound{S|}", { Gv, Ma } },
+    { "(bad)", { XX } },
+  },
+  {
+    { "arpl", { Ew, Gw } },
+    { "movs{||lq|xd}", { Gv, Ed } },
+  },
+};
+
+static const struct dis386 three_byte_table[][256] = {
+  /* THREE_BYTE_0 */
+  {
+    /* 00 */
+    { "pshufb", { MX, EM } },
+    { "phaddw", { MX, EM } },
+    { "phaddd",	{ MX, EM } },
+    { "phaddsw", { MX, EM } },
+    { "pmaddubsw", { MX, EM } },
+    { "phsubw", { MX, EM } },
+    { "phsubd", { MX, EM } },
+    { "phsubsw", { MX, EM } },
+    /* 08 */
+    { "psignb", { MX, EM } },
+    { "psignw", { MX, EM } },
+    { "psignd", { MX, EM } },
+    { "pmulhrsw", { MX, EM } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 10 */
+    { PREGRP39 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { PREGRP40 },
+    { PREGRP41 },
+    { "(bad)", { XX } },
+    { PREGRP42 },
+    /* 18 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "pabsb", { MX, EM } },
+    { "pabsw", { MX, EM } },
+    { "pabsd", { MX, EM } },
+    { "(bad)", { XX } },
+    /* 20 */
+    { PREGRP43 },
+    { PREGRP44 },
+    { PREGRP45 },
+    { PREGRP46 },
+    { PREGRP47 },
+    { PREGRP48 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 28 */
+    { PREGRP49 },
+    { PREGRP50 },
+    { PREGRP51 },
+    { PREGRP52 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 30 */
+    { PREGRP53 },
+    { PREGRP54 },
+    { PREGRP55 },
+    { PREGRP56 },
+    { PREGRP57 },
+    { PREGRP58 },
+    { "(bad)", { XX } },
+    { PREGRP86 },
+    /* 38 */
+    { PREGRP59 },
+    { PREGRP60 },
+    { PREGRP61 },
+    { PREGRP62 },
+    { PREGRP63 },
+    { PREGRP64 },
+    { PREGRP65 },
+    { PREGRP66 },
+    /* 40 */
+    { PREGRP67 },
+    { PREGRP68 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 48 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 50 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 58 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 60 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 68 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 70 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 78 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 80 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 88 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 90 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 98 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* a0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* a8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* b0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* b8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* c0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* c8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* d0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* d8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* e0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* e8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* f0 */
+    { PREGRP87 },
+    { PREGRP88 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* f8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+  },
+  /* THREE_BYTE_1 */
+  {
+    /* 00 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 08 */
+    { PREGRP69 },
+    { PREGRP70 },
+    { PREGRP71 },
+    { PREGRP72 },
+    { PREGRP73 },
+    { PREGRP74 },
+    { PREGRP75 },
+    { "palignr", { MX, EM, Ib } },
+    /* 10 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { PREGRP76 },
+    { PREGRP77 },
+    { PREGRP78 },
+    { PREGRP79 },
+    /* 18 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 20 */
+    { PREGRP80 },
+    { PREGRP81 },
+    { PREGRP82 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 28 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 30 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 38 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 40 */
+    { PREGRP83 },
+    { PREGRP84 },
+    { PREGRP85 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 48 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 50 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 58 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 60 */
+    { PREGRP89 },
+    { PREGRP90 },
+    { PREGRP91 },
+    { PREGRP92 },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 68 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 70 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 78 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 80 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 88 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 90 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* 98 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* a0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* a8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* b0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* b8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* c0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* c8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* d0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* d8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* e0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* e8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* f0 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    /* f8 */
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+    { "(bad)", { XX } },
+  }
 };
 
 #define INTERNAL_DISASSEMBLER_ERROR _("<internal disassembler error>")
 
 static void
-ckprefix ()
+ckprefix (void)
 {
   int newrex;
   rex = 0;
@@ -1680,7 +3343,7 @@
 	case 0x4d:
 	case 0x4e:
 	case 0x4f:
-	    if (mode_64bit)
+	    if (address_mode == mode_64bit)
 	      newrex = *codep;
 	    else
 	      return;
@@ -1722,7 +3385,7 @@
 	  /* fwait is really an instruction.  If there are prefixes
 	     before the fwait, they belong to the fwait, *not* to the
 	     following instruction.  */
-	  if (prefixes)
+	  if (prefixes || rex)
 	    {
 	      prefixes |= PREFIX_FWAIT;
 	      codep++;
@@ -1736,8 +3399,8 @@
       /* Rex is ignored when followed by another prefix.  */
       if (rex)
 	{
-	  oappend (prefix_name (rex, 0));
-	  oappend (" ");
+	  rex_used = rex;
+	  return;
 	}
       rex = newrex;
       codep++;
@@ -1748,45 +3411,48 @@
    prefix byte.  */
 
 static const char *
-prefix_name (pref, sizeflag)
-     int pref;
-     int sizeflag;
+prefix_name (int pref, int sizeflag)
 {
+  static const char * const rexes [16] =
+    {
+      "rex",		/* 0x40 */
+      "rex.B",		/* 0x41 */
+      "rex.X",		/* 0x42 */
+      "rex.XB",		/* 0x43 */
+      "rex.R",		/* 0x44 */
+      "rex.RB",		/* 0x45 */
+      "rex.RX",		/* 0x46 */
+      "rex.RXB",	/* 0x47 */
+      "rex.W",		/* 0x48 */
+      "rex.WB",		/* 0x49 */
+      "rex.WX",		/* 0x4a */
+      "rex.WXB",	/* 0x4b */
+      "rex.WR",		/* 0x4c */
+      "rex.WRB",	/* 0x4d */
+      "rex.WRX",	/* 0x4e */
+      "rex.WRXB",	/* 0x4f */
+    };
+
   switch (pref)
     {
     /* REX prefixes family.  */
     case 0x40:
-      return "rex";
     case 0x41:
-      return "rexZ";
     case 0x42:
-      return "rexY";
     case 0x43:
-      return "rexYZ";
     case 0x44:
-      return "rexX";
     case 0x45:
-      return "rexXZ";
     case 0x46:
-      return "rexXY";
     case 0x47:
-      return "rexXYZ";
     case 0x48:
-      return "rex64";
     case 0x49:
-      return "rex64Z";
     case 0x4a:
-      return "rex64Y";
     case 0x4b:
-      return "rex64YZ";
     case 0x4c:
-      return "rex64X";
     case 0x4d:
-      return "rex64XZ";
     case 0x4e:
-      return "rex64XY";
     case 0x4f:
-      return "rex64XYZ";
+      return rexes [pref - 0x40];
     case 0xf3:
       return "repz";
     case 0xf2:
@@ -1808,10 +3474,10 @@
     case 0x66:
       return (sizeflag & DFLAG) ? "data16" : "data32";
     case 0x67:
-      if (mode_64bit)
-        return (sizeflag & AFLAG) ? "addr32" : "addr64";
+      if (address_mode == mode_64bit)
+	return (sizeflag & AFLAG) ? "addr32" : "addr64";
       else
-        return ((sizeflag & AFLAG) && !mode_64bit) ? "addr16" : "addr32";
+	return (sizeflag & AFLAG) ? "addr16" : "addr32";
     case FWAIT_OPCODE:
       return "fwait";
     default:
@@ -1819,12 +3485,13 @@
     }
 }
 
-static char op1out[100], op2out[100], op3out[100];
-static int op_ad, op_index[3];
-static bfd_vma op_address[3];
-static bfd_vma op_riprel[3];
+static char op_out[MAX_OPERANDS][100];
+static int op_ad, op_index[MAX_OPERANDS];
+static int two_source_ops;
+static bfd_vma op_address[MAX_OPERANDS];
+static bfd_vma op_riprel[MAX_OPERANDS];
 static bfd_vma start_pc;
-
+
 /*
  *   On the 386's of 1988, the maximum length of an instruction is 15 bytes.
  *   (see topic "Redundant prefixes" in the "Differences from 8086"
@@ -1834,16 +3501,14 @@
  * The function returns the length of this instruction in bytes.
  */
 
-static int8_t intel_syntax;
+static char intel_syntax;
 static char open_char;
 static char close_char;
 static char separator_char;
 static char scale_char;
 
 int
-print_insn_i386 (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
+print_insn_i386 (bfd_vma pc, disassemble_info *info)
 {
   intel_syntax = -1;
 
@@ -1851,24 +3516,26 @@
 }
 
 static int
-print_insn (pc, info)
-     bfd_vma pc;
-     disassemble_info *info;
+print_insn (bfd_vma pc, disassemble_info *info)
 {
   const struct dis386 *dp;
   int i;
-  int two_source_ops;
-  char *first, *second, *third;
+  char *op_txt[MAX_OPERANDS];
   int needcomma;
-  unsigned char uses_SSE_prefix;
+  unsigned char uses_DATA_prefix, uses_LOCK_prefix;
+  unsigned char uses_REPNZ_prefix, uses_REPZ_prefix;
   int sizeflag;
   const char *p;
   struct dis_private priv;
+  unsigned char op;
 
-  mode_64bit = (info->mach == bfd_mach_x86_64_intel_syntax
-		|| info->mach == bfd_mach_x86_64);
+  if (info->mach == bfd_mach_x86_64_intel_syntax
+      || info->mach == bfd_mach_x86_64)
+    address_mode = mode_64bit;
+  else
+    address_mode = mode_32bit;
 
-  if (intel_syntax == -1)
+  if (intel_syntax == (char) -1)
     intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax
 		    || info->mach == bfd_mach_x86_64_intel_syntax);
 
@@ -1886,17 +3553,17 @@
     {
       if (strncmp (p, "x86-64", 6) == 0)
 	{
-	  mode_64bit = 1;
+	  address_mode = mode_64bit;
 	  priv.orig_sizeflag = AFLAG | DFLAG;
 	}
       else if (strncmp (p, "i386", 4) == 0)
 	{
-	  mode_64bit = 0;
+	  address_mode = mode_32bit;
 	  priv.orig_sizeflag = AFLAG | DFLAG;
 	}
       else if (strncmp (p, "i8086", 5) == 0)
 	{
-	  mode_64bit = 0;
+	  address_mode = mode_16bit;
 	  priv.orig_sizeflag = 0;
 	}
       else if (strncmp (p, "intel", 5) == 0)
@@ -1909,10 +3576,20 @@
 	}
       else if (strncmp (p, "addr", 4) == 0)
 	{
-	  if (p[4] == '1' && p[5] == '6')
-	    priv.orig_sizeflag &= ~AFLAG;
-	  else if (p[4] == '3' && p[5] == '2')
-	    priv.orig_sizeflag |= AFLAG;
+	  if (address_mode == mode_64bit)
+	    {
+	      if (p[4] == '3' && p[5] == '2')
+		priv.orig_sizeflag &= ~AFLAG;
+	      else if (p[4] == '6' && p[5] == '4')
+		priv.orig_sizeflag |= AFLAG;
+	    }
+	  else
+	    {
+	      if (p[4] == '1' && p[5] == '6')
+		priv.orig_sizeflag &= ~AFLAG;
+	      else if (p[4] == '3' && p[5] == '2')
+		priv.orig_sizeflag |= AFLAG;
+	    }
 	}
       else if (strncmp (p, "data", 4) == 0)
 	{
@@ -1962,16 +3639,16 @@
      puts most long word instructions on a single line.  */
   info->bytes_per_line = 7;
 
-  info->private_data = (PTR) &priv;
+  info->private_data = &priv;
   priv.max_fetched = priv.the_buffer;
   priv.insn_start = pc;
 
   obuf[0] = 0;
-  op1out[0] = 0;
-  op2out[0] = 0;
-  op3out[0] = 0;
-
-  op_index[0] = op_index[1] = op_index[2] = -1;
+  for (i = 0; i < MAX_OPERANDS; ++i)
+    {
+      op_out[i][0] = 0;
+      op_index[i] = -1;
+    }
 
   the_info = info;
   start_pc = pc;
@@ -2012,13 +3689,14 @@
   FETCH_DATA (info, codep + 1);
   two_source_ops = (*codep == 0x62) || (*codep == 0xc8);
 
-  if ((prefixes & PREFIX_FWAIT)
-      && ((*codep < 0xd8) || (*codep > 0xdf)))
+  if (((prefixes & PREFIX_FWAIT)
+       && ((*codep < 0xd8) || (*codep > 0xdf)))
+      || (rex && rex_used))
     {
       const char *name;
 
-      /* fwait not followed by floating point instruction.  Print the
-         first prefix, which is probably fwait itself.  */
+      /* fwait not followed by floating point instruction, or rex followed
+	 by other prefixes.  Print the first prefix.  */
       name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag);
       if (name == NULL)
 	name = INTERNAL_DISASSEMBLER_ERROR;
@@ -2026,32 +3704,64 @@
       return 1;
     }
 
+  op = 0;
   if (*codep == 0x0f)
     {
+      unsigned char threebyte;
       FETCH_DATA (info, codep + 2);
-      dp = &dis386_twobyte[*++codep];
+      threebyte = *++codep;
+      dp = &dis386_twobyte[threebyte];
       need_modrm = twobyte_has_modrm[*codep];
-      uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep];
+      uses_DATA_prefix = twobyte_uses_DATA_prefix[*codep];
+      uses_REPNZ_prefix = twobyte_uses_REPNZ_prefix[*codep];
+      uses_REPZ_prefix = twobyte_uses_REPZ_prefix[*codep];
+      uses_LOCK_prefix = (*codep & ~0x02) == 0x20;
+      codep++;
+      if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE)
+	{
+	  FETCH_DATA (info, codep + 2);
+	  op = *codep++;
+	  switch (threebyte)
+	    {
+	    case 0x38:
+	      uses_DATA_prefix = threebyte_0x38_uses_DATA_prefix[op];
+	      uses_REPNZ_prefix = threebyte_0x38_uses_REPNZ_prefix[op];
+	      uses_REPZ_prefix = threebyte_0x38_uses_REPZ_prefix[op];
+	      break;
+	    case 0x3a:
+	      uses_DATA_prefix = threebyte_0x3a_uses_DATA_prefix[op];
+	      uses_REPNZ_prefix = threebyte_0x3a_uses_REPNZ_prefix[op];
+	      uses_REPZ_prefix = threebyte_0x3a_uses_REPZ_prefix[op];
+	      break;
+	    default:
+	      break;
+	    }
+	}
     }
   else
     {
       dp = &dis386[*codep];
       need_modrm = onebyte_has_modrm[*codep];
-      uses_SSE_prefix = 0;
+      uses_DATA_prefix = 0;
+      uses_REPNZ_prefix = 0;
+      /* pause is 0xf3 0x90.  */
+      uses_REPZ_prefix = *codep == 0x90;
+      uses_LOCK_prefix = 0;
+      codep++;
     }
-  codep++;
 
-  if (!uses_SSE_prefix && (prefixes & PREFIX_REPZ))
+  if (!uses_REPZ_prefix && (prefixes & PREFIX_REPZ))
     {
       oappend ("repz ");
       used_prefixes |= PREFIX_REPZ;
     }
-  if (!uses_SSE_prefix && (prefixes & PREFIX_REPNZ))
+  if (!uses_REPNZ_prefix && (prefixes & PREFIX_REPNZ))
     {
       oappend ("repnz ");
       used_prefixes |= PREFIX_REPNZ;
     }
-  if (prefixes & PREFIX_LOCK)
+
+  if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK))
     {
       oappend ("lock ");
       used_prefixes |= PREFIX_LOCK;
@@ -2060,9 +3770,9 @@
   if (prefixes & PREFIX_ADDR)
     {
       sizeflag ^= AFLAG;
-      if (dp->bytemode3 != loop_jcxz_mode || intel_syntax)
+      if (dp->op[2].bytemode != loop_jcxz_mode || intel_syntax)
 	{
-	  if ((sizeflag & AFLAG) || mode_64bit)
+	  if ((sizeflag & AFLAG) || address_mode == mode_64bit)
 	    oappend ("addr32 ");
 	  else
 	    oappend ("addr16 ");
@@ -2070,11 +3780,11 @@
 	}
     }
 
-  if (!uses_SSE_prefix && (prefixes & PREFIX_DATA))
+  if (!uses_DATA_prefix && (prefixes & PREFIX_DATA))
     {
       sizeflag ^= DFLAG;
-      if (dp->bytemode3 == cond_jump_mode
-	  && dp->bytemode1 == v_mode
+      if (dp->op[2].bytemode == cond_jump_mode
+	  && dp->op[0].bytemode == v_mode
 	  && !intel_syntax)
 	{
 	  if (sizeflag & DFLAG)
@@ -2085,15 +3795,22 @@
 	}
     }
 
-  if (need_modrm)
+  if (dp->name == NULL && dp->op[0].bytemode == IS_3BYTE_OPCODE)
+    {
+      dp = &three_byte_table[dp->op[1].bytemode][op];
+      modrm.mod = (*codep >> 6) & 3;
+      modrm.reg = (*codep >> 3) & 7;
+      modrm.rm = *codep & 7;
+    }
+  else if (need_modrm)
     {
       FETCH_DATA (info, codep + 1);
-      mod = (*codep >> 6) & 3;
-      reg = (*codep >> 3) & 7;
-      rm = *codep & 7;
+      modrm.mod = (*codep >> 6) & 3;
+      modrm.reg = (*codep >> 3) & 7;
+      modrm.rm = *codep & 7;
     }
 
-  if (dp->name == NULL && dp->bytemode1 == FLOATCODE)
+  if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE)
     {
       dofloat (sizeflag);
     }
@@ -2102,10 +3819,10 @@
       int index;
       if (dp->name == NULL)
 	{
-	  switch (dp->bytemode1)
+	  switch (dp->op[0].bytemode)
 	    {
 	    case USE_GROUPS:
-	      dp = &grps[dp->bytemode2][reg];
+	      dp = &grps[dp->op[1].bytemode][modrm.reg];
 	      break;
 
 	    case USE_PREFIX_USER_TABLE:
@@ -2115,21 +3832,24 @@
 		index = 1;
 	      else
 		{
-		  used_prefixes |= (prefixes & PREFIX_DATA);
-		  if (prefixes & PREFIX_DATA)
-		    index = 2;
+		  /* We should check PREFIX_REPNZ and PREFIX_REPZ
+		     before PREFIX_DATA.  */
+		  used_prefixes |= (prefixes & PREFIX_REPNZ);
+		  if (prefixes & PREFIX_REPNZ)
+		    index = 3;
 		  else
 		    {
-		      used_prefixes |= (prefixes & PREFIX_REPNZ);
-		      if (prefixes & PREFIX_REPNZ)
-			index = 3;
+		      used_prefixes |= (prefixes & PREFIX_DATA);
+		      if (prefixes & PREFIX_DATA)
+			index = 2;
 		    }
 		}
-	      dp = &prefix_user_table[dp->bytemode2][index];
+	      dp = &prefix_user_table[dp->op[1].bytemode][index];
 	      break;
 
 	    case X86_64_SPECIAL:
-	      dp = &x86_64_table[dp->bytemode2][mode_64bit];
+	      index = address_mode == mode_64bit ? 1 : 0;
+	      dp = &x86_64_table[dp->op[1].bytemode][index];
 	      break;
 
 	    default:
@@ -2139,21 +3859,14 @@
 	}
 
       if (putop (dp->name, sizeflag) == 0)
-	{
-	  obufp = op1out;
-	  op_ad = 2;
-	  if (dp->op1)
-	    (*dp->op1) (dp->bytemode1, sizeflag);
-
-	  obufp = op2out;
-	  op_ad = 1;
-	  if (dp->op2)
-	    (*dp->op2) (dp->bytemode2, sizeflag);
-
-	  obufp = op3out;
-	  op_ad = 0;
-	  if (dp->op3)
-	    (*dp->op3) (dp->bytemode3, sizeflag);
+        {
+	  for (i = 0; i < MAX_OPERANDS; ++i)
+	    {
+	      obufp = op_out[i];
+	      op_ad = MAX_OPERANDS - 1 - i;
+	      if (dp->op[i].rtn)
+		(*dp->op[i].rtn) (dp->op[i].bytemode, sizeflag);
+	    }
 	}
     }
 
@@ -2190,53 +3903,47 @@
      order as the intel book; everything else is printed in reverse order.  */
   if (intel_syntax || two_source_ops)
     {
-      first = op1out;
-      second = op2out;
-      third = op3out;
-      op_ad = op_index[0];
-      op_index[0] = op_index[2];
-      op_index[2] = op_ad;
+      bfd_vma riprel;
+
+      for (i = 0; i < MAX_OPERANDS; ++i)
+        op_txt[i] = op_out[i];
+
+      for (i = 0; i < (MAX_OPERANDS >> 1); ++i)
+	{
+          op_ad = op_index[i];
+          op_index[i] = op_index[MAX_OPERANDS - 1 - i];
+          op_index[MAX_OPERANDS - 1 - i] = op_ad;
+	  riprel = op_riprel[i];
+	  op_riprel[i] = op_riprel [MAX_OPERANDS - 1 - i];
+	  op_riprel[MAX_OPERANDS - 1 - i] = riprel;
+	}
     }
   else
     {
-      first = op3out;
-      second = op2out;
-      third = op1out;
+      for (i = 0; i < MAX_OPERANDS; ++i)
+        op_txt[MAX_OPERANDS - 1 - i] = op_out[i];
     }
+
   needcomma = 0;
-  if (*first)
-    {
-      if (op_index[0] != -1 && !op_riprel[0])
-	(*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info);
-      else
-	(*info->fprintf_func) (info->stream, "%s", first);
-      needcomma = 1;
-    }
-  if (*second)
-    {
-      if (needcomma)
-	(*info->fprintf_func) (info->stream, ",");
-      if (op_index[1] != -1 && !op_riprel[1])
-	(*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info);
-      else
-	(*info->fprintf_func) (info->stream, "%s", second);
-      needcomma = 1;
-    }
-  if (*third)
-    {
-      if (needcomma)
-	(*info->fprintf_func) (info->stream, ",");
-      if (op_index[2] != -1 && !op_riprel[2])
-	(*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info);
-      else
-	(*info->fprintf_func) (info->stream, "%s", third);
-    }
-  for (i = 0; i < 3; i++)
+  for (i = 0; i < MAX_OPERANDS; ++i)
+    if (*op_txt[i])
+      {
+	if (needcomma)
+	  (*info->fprintf_func) (info->stream, ",");
+	if (op_index[i] != -1 && !op_riprel[i])
+	  (*info->print_address_func) ((bfd_vma) op_address[op_index[i]], info);
+	else
+	  (*info->fprintf_func) (info->stream, "%s", op_txt[i]);
+	needcomma = 1;
+      }
+
+  for (i = 0; i < MAX_OPERANDS; i++)
     if (op_index[i] != -1 && op_riprel[i])
       {
 	(*info->fprintf_func) (info->stream, "        # ");
 	(*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep
 						+ op_address[op_index[i]]), info);
+	break;
       }
   return codep - priv.the_buffer;
 }
@@ -2251,14 +3958,14 @@
   "fsubr{s||s|}",
   "fdiv{s||s|}",
   "fdivr{s||s|}",
-  /*  d9 */
+  /* d9 */
   "fld{s||s|}",
   "(bad)",
   "fst{s||s|}",
   "fstp{s||s|}",
-  "fldenv",
+  "fldenvIC",
   "fldcw",
-  "fNstenv",
+  "fNstenvIC",
   "fNstcw",
   /* da */
   "fiadd{l||l|}",
@@ -2271,7 +3978,7 @@
   "fidivr{l||l|}",
   /* db */
   "fild{l||l|}",
-  "(bad)",
+  "fisttp{l||l|}",
   "fist{l||l|}",
   "fistp{l||l|}",
   "(bad)",
@@ -2289,12 +3996,12 @@
   "fdivr{l||l|}",
   /* dd */
   "fld{l||l|}",
-  "(bad)",
+  "fisttp{ll||ll|}",
   "fst{l||l|}",
   "fstp{l||l|}",
-  "frstor",
+  "frstorIC",
   "(bad)",
-  "fNsave",
+  "fNsaveIC",
   "fNstsw",
   /* de */
   "fiadd",
@@ -2307,46 +4014,121 @@
   "fidivr",
   /* df */
   "fild",
-  "(bad)",
+  "fisttp",
   "fist",
   "fistp",
   "fbld",
   "fild{ll||ll|}",
   "fbstp",
-  "fistpll",
+  "fistp{ll||ll|}",
 };
 
-#define ST OP_ST, 0
-#define STi OP_STi, 0
+static const unsigned char float_mem_mode[] = {
+  /* d8 */
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  /* d9 */
+  d_mode,
+  0,
+  d_mode,
+  d_mode,
+  0,
+  w_mode,
+  0,
+  w_mode,
+  /* da */
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  /* db */
+  d_mode,
+  d_mode,
+  d_mode,
+  d_mode,
+  0,
+  t_mode,
+  0,
+  t_mode,
+  /* dc */
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  /* dd */
+  q_mode,
+  q_mode,
+  q_mode,
+  q_mode,
+  0,
+  0,
+  0,
+  w_mode,
+  /* de */
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  /* df */
+  w_mode,
+  w_mode,
+  w_mode,
+  w_mode,
+  t_mode,
+  q_mode,
+  t_mode,
+  q_mode
+};
 
-#define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0
-#define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0
-#define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0
-#define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0
-#define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0
-#define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0
-#define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0
-#define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0
-#define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0
+#define ST { OP_ST, 0 }
+#define STi { OP_STi, 0 }
+
+#define FGRPd9_2 NULL, { { NULL, 0 } }
+#define FGRPd9_4 NULL, { { NULL, 1 } }
+#define FGRPd9_5 NULL, { { NULL, 2 } }
+#define FGRPd9_6 NULL, { { NULL, 3 } }
+#define FGRPd9_7 NULL, { { NULL, 4 } }
+#define FGRPda_5 NULL, { { NULL, 5 } }
+#define FGRPdb_4 NULL, { { NULL, 6 } }
+#define FGRPde_3 NULL, { { NULL, 7 } }
+#define FGRPdf_4 NULL, { { NULL, 8 } }
 
 static const struct dis386 float_reg[][8] = {
   /* d8 */
   {
-    { "fadd",	ST, STi, XX },
-    { "fmul",	ST, STi, XX },
-    { "fcom",	STi, XX, XX },
-    { "fcomp",	STi, XX, XX },
-    { "fsub",	ST, STi, XX },
-    { "fsubr",	ST, STi, XX },
-    { "fdiv",	ST, STi, XX },
-    { "fdivr",	ST, STi, XX },
+    { "fadd",	{ ST, STi } },
+    { "fmul",	{ ST, STi } },
+    { "fcom",	{ STi } },
+    { "fcomp",	{ STi } },
+    { "fsub",	{ ST, STi } },
+    { "fsubr",	{ ST, STi } },
+    { "fdiv",	{ ST, STi } },
+    { "fdivr",	{ ST, STi } },
   },
   /* d9 */
   {
-    { "fld",	STi, XX, XX },
-    { "fxch",	STi, XX, XX },
+    { "fld",	{ STi } },
+    { "fxch",	{ STi } },
     { FGRPd9_2 },
-    { "(bad)",	XX, XX, XX },
+    { "(bad)",	{ XX } },
     { FGRPd9_4 },
     { FGRPd9_5 },
     { FGRPd9_6 },
@@ -2354,83 +4136,83 @@
   },
   /* da */
   {
-    { "fcmovb",	ST, STi, XX },
-    { "fcmove",	ST, STi, XX },
-    { "fcmovbe",ST, STi, XX },
-    { "fcmovu",	ST, STi, XX },
-    { "(bad)",	XX, XX, XX },
+    { "fcmovb",	{ ST, STi } },
+    { "fcmove",	{ ST, STi } },
+    { "fcmovbe",{ ST, STi } },
+    { "fcmovu",	{ ST, STi } },
+    { "(bad)",	{ XX } },
     { FGRPda_5 },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
   },
   /* db */
   {
-    { "fcmovnb",ST, STi, XX },
-    { "fcmovne",ST, STi, XX },
-    { "fcmovnbe",ST, STi, XX },
-    { "fcmovnu",ST, STi, XX },
+    { "fcmovnb",{ ST, STi } },
+    { "fcmovne",{ ST, STi } },
+    { "fcmovnbe",{ ST, STi } },
+    { "fcmovnu",{ ST, STi } },
     { FGRPdb_4 },
-    { "fucomi",	ST, STi, XX },
-    { "fcomi",	ST, STi, XX },
-    { "(bad)",	XX, XX, XX },
+    { "fucomi",	{ ST, STi } },
+    { "fcomi",	{ ST, STi } },
+    { "(bad)",	{ XX } },
   },
   /* dc */
   {
-    { "fadd",	STi, ST, XX },
-    { "fmul",	STi, ST, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-#if UNIXWARE_COMPAT
-    { "fsub",	STi, ST, XX },
-    { "fsubr",	STi, ST, XX },
-    { "fdiv",	STi, ST, XX },
-    { "fdivr",	STi, ST, XX },
+    { "fadd",	{ STi, ST } },
+    { "fmul",	{ STi, ST } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+#if SYSV386_COMPAT
+    { "fsub",	{ STi, ST } },
+    { "fsubr",	{ STi, ST } },
+    { "fdiv",	{ STi, ST } },
+    { "fdivr",	{ STi, ST } },
 #else
-    { "fsubr",	STi, ST, XX },
-    { "fsub",	STi, ST, XX },
-    { "fdivr",	STi, ST, XX },
-    { "fdiv",	STi, ST, XX },
+    { "fsubr",	{ STi, ST } },
+    { "fsub",	{ STi, ST } },
+    { "fdivr",	{ STi, ST } },
+    { "fdiv",	{ STi, ST } },
 #endif
   },
   /* dd */
   {
-    { "ffree",	STi, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "fst",	STi, XX, XX },
-    { "fstp",	STi, XX, XX },
-    { "fucom",	STi, XX, XX },
-    { "fucomp",	STi, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
+    { "ffree",	{ STi } },
+    { "(bad)",	{ XX } },
+    { "fst",	{ STi } },
+    { "fstp",	{ STi } },
+    { "fucom",	{ STi } },
+    { "fucomp",	{ STi } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
   },
   /* de */
   {
-    { "faddp",	STi, ST, XX },
-    { "fmulp",	STi, ST, XX },
-    { "(bad)",	XX, XX, XX },
+    { "faddp",	{ STi, ST } },
+    { "fmulp",	{ STi, ST } },
+    { "(bad)",	{ XX } },
     { FGRPde_3 },
-#if UNIXWARE_COMPAT
-    { "fsubp",	STi, ST, XX },
-    { "fsubrp",	STi, ST, XX },
-    { "fdivp",	STi, ST, XX },
-    { "fdivrp",	STi, ST, XX },
+#if SYSV386_COMPAT
+    { "fsubp",	{ STi, ST } },
+    { "fsubrp",	{ STi, ST } },
+    { "fdivp",	{ STi, ST } },
+    { "fdivrp",	{ STi, ST } },
 #else
-    { "fsubrp",	STi, ST, XX },
-    { "fsubp",	STi, ST, XX },
-    { "fdivrp",	STi, ST, XX },
-    { "fdivp",	STi, ST, XX },
+    { "fsubrp",	{ STi, ST } },
+    { "fsubp",	{ STi, ST } },
+    { "fdivrp",	{ STi, ST } },
+    { "fdivp",	{ STi, ST } },
 #endif
   },
   /* df */
   {
-    { "ffreep",	STi, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
-    { "(bad)",	XX, XX, XX },
+    { "ffreep",	{ STi } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
+    { "(bad)",	{ XX } },
     { FGRPdf_4 },
-    { "fucomip",ST, STi, XX },
-    { "fcomip", ST, STi, XX },
-    { "(bad)",	XX, XX, XX },
+    { "fucomip", { ST, STi } },
+    { "fcomip", { ST, STi } },
+    { "(bad)",	{ XX } },
   },
 };
 
@@ -2483,77 +4265,71 @@
 };
 
 static void
-dofloat (sizeflag)
-     int sizeflag;
+dofloat (int sizeflag)
 {
   const struct dis386 *dp;
   unsigned char floatop;
 
   floatop = codep[-1];
 
-  if (mod != 3)
+  if (modrm.mod != 3)
     {
-      putop (float_mem[(floatop - 0xd8) * 8 + reg], sizeflag);
-      obufp = op1out;
-      if (floatop == 0xdb)
-        OP_E (x_mode, sizeflag);
-      else if (floatop == 0xdd)
-        OP_E (d_mode, sizeflag);
-      else
-        OP_E (v_mode, sizeflag);
+      int fp_indx = (floatop - 0xd8) * 8 + modrm.reg;
+
+      putop (float_mem[fp_indx], sizeflag);
+      obufp = op_out[0];
+      op_ad = 2;
+      OP_E (float_mem_mode[fp_indx], sizeflag);
       return;
     }
   /* Skip mod/rm byte.  */
   MODRM_CHECK;
   codep++;
 
-  dp = &float_reg[floatop - 0xd8][reg];
+  dp = &float_reg[floatop - 0xd8][modrm.reg];
   if (dp->name == NULL)
     {
-      putop (fgrps[dp->bytemode1][rm], sizeflag);
+      putop (fgrps[dp->op[0].bytemode][modrm.rm], sizeflag);
 
       /* Instruction fnstsw is only one with strange arg.  */
       if (floatop == 0xdf && codep[-1] == 0xe0)
-        pstrcpy (op1out, sizeof(op1out), names16[0]);
+        pstrcpy (op_out[0], sizeof(op_out[0]), names16[0]);
     }
   else
     {
       putop (dp->name, sizeflag);
 
-      obufp = op1out;
-      if (dp->op1)
-	(*dp->op1) (dp->bytemode1, sizeflag);
-      obufp = op2out;
-      if (dp->op2)
-	(*dp->op2) (dp->bytemode2, sizeflag);
+      obufp = op_out[0];
+      op_ad = 2;
+      if (dp->op[0].rtn)
+	(*dp->op[0].rtn) (dp->op[0].bytemode, sizeflag);
+
+      obufp = op_out[1];
+      op_ad = 1;
+      if (dp->op[1].rtn)
+	(*dp->op[1].rtn) (dp->op[1].bytemode, sizeflag);
     }
 }
 
 static void
-OP_ST (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
-  oappend ("%st");
+  oappend ("%st" + intel_syntax);
 }
 
 static void
-OP_STi (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
-  snprintf (scratchbuf, sizeof(scratchbuf), "%%st(%d)", rm);
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%st(%d)", modrm.rm);
   oappend (scratchbuf + intel_syntax);
 }
 
 /* Capital letters in template are macros.  */
 static int
-putop (template, sizeflag)
-     const char *template;
-     int sizeflag;
+putop (const char *template, int sizeflag)
 {
   const char *p;
-  int alt;
+  int alt = 0;
 
   for (p = template; *p; p++)
     {
@@ -2566,7 +4342,7 @@
 	  alt = 0;
 	  if (intel_syntax)
 	    alt += 1;
-	  if (mode_64bit)
+	  if (address_mode == mode_64bit)
 	    alt += 2;
 	  while (alt != 0)
 	    {
@@ -2584,7 +4360,10 @@
 		}
 	      alt--;
 	    }
-	  break;
+	  /* Fall through.  */
+	case 'I':
+	  alt = 1;
+	  continue;
 	case '|':
 	  while (*++p != '}')
 	    {
@@ -2595,19 +4374,48 @@
 	case '}':
 	  break;
 	case 'A':
-          if (intel_syntax)
-            break;
-	  if (mod != 3 || (sizeflag & SUFFIX_ALWAYS))
+	  if (intel_syntax)
+	    break;
+	  if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS))
 	    *obufp++ = 'b';
 	  break;
 	case 'B':
-          if (intel_syntax)
-            break;
+	  if (intel_syntax)
+	    break;
 	  if (sizeflag & SUFFIX_ALWAYS)
 	    *obufp++ = 'b';
 	  break;
+	case 'C':
+	  if (intel_syntax && !alt)
+	    break;
+	  if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS))
+	    {
+	      if (sizeflag & DFLAG)
+		*obufp++ = intel_syntax ? 'd' : 'l';
+	      else
+		*obufp++ = intel_syntax ? 'w' : 's';
+	      used_prefixes |= (prefixes & PREFIX_DATA);
+	    }
+	  break;
+	case 'D':
+	  if (intel_syntax || !(sizeflag & SUFFIX_ALWAYS))
+	    break;
+	  USED_REX (REX_W);
+	  if (modrm.mod == 3)
+	    {
+	      if (rex & REX_W)
+		*obufp++ = 'q';
+	      else if (sizeflag & DFLAG)
+		*obufp++ = intel_syntax ? 'd' : 'l';
+	      else
+		*obufp++ = 'w';
+	      used_prefixes |= (prefixes & PREFIX_DATA);
+	    }
+	  else
+	    *obufp++ = 'w';
+	  break;
 	case 'E':		/* For jcxz/jecxz */
-	  if (mode_64bit)
+	  if (address_mode == mode_64bit)
 	    {
 	      if (sizeflag & AFLAG)
 		*obufp++ = 'r';
@@ -2620,20 +4428,30 @@
 	  used_prefixes |= (prefixes & PREFIX_ADDR);
 	  break;
 	case 'F':
-          if (intel_syntax)
-            break;
+	  if (intel_syntax)
+	    break;
 	  if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS))
 	    {
 	      if (sizeflag & AFLAG)
-		*obufp++ = mode_64bit ? 'q' : 'l';
+		*obufp++ = address_mode == mode_64bit ? 'q' : 'l';
 	      else
-		*obufp++ = mode_64bit ? 'l' : 'w';
+		*obufp++ = address_mode == mode_64bit ? 'l' : 'w';
 	      used_prefixes |= (prefixes & PREFIX_ADDR);
 	    }
 	  break;
+	case 'G':
+	  if (intel_syntax || (obufp[-1] != 's' && !(sizeflag & SUFFIX_ALWAYS)))
+	    break;
+	  if ((rex & REX_W) || (sizeflag & DFLAG))
+	    *obufp++ = 'l';
+	  else
+	    *obufp++ = 'w';
+	  if (!(rex & REX_W))
+	    used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
 	case 'H':
-          if (intel_syntax)
-            break;
+	  if (intel_syntax)
+	    break;
 	  if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS
 	      || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS)
 	    {
@@ -2646,9 +4464,30 @@
 		*obufp++ = 'n';
 	    }
 	  break;
+	case 'J':
+	  if (intel_syntax)
+	    break;
+	  *obufp++ = 'l';
+	  break;
+	case 'K':
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    *obufp++ = 'q';
+	  else
+	    *obufp++ = 'd';
+	  break;
+	case 'Z':
+	  if (intel_syntax)
+	    break;
+	  if (address_mode == mode_64bit && (sizeflag & SUFFIX_ALWAYS))
+	    {
+	      *obufp++ = 'q';
+	      break;
+	    }
+	  /* Fall through.  */
 	case 'L':
-          if (intel_syntax)
-            break;
+	  if (intel_syntax)
+	    break;
 	  if (sizeflag & SUFFIX_ALWAYS)
 	    *obufp++ = 'l';
 	  break;
@@ -2659,30 +4498,34 @@
 	    used_prefixes |= PREFIX_FWAIT;
 	  break;
 	case 'O':
-	  USED_REX (REX_MODE64);
-	  if (rex & REX_MODE64)
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
 	    *obufp++ = 'o';
+	  else if (intel_syntax && (sizeflag & DFLAG))
+	    *obufp++ = 'q';
 	  else
 	    *obufp++ = 'd';
+	  if (!(rex & REX_W))
+	    used_prefixes |= (prefixes & PREFIX_DATA);
 	  break;
 	case 'T':
-          if (intel_syntax)
-            break;
-	  if (mode_64bit)
+	  if (intel_syntax)
+	    break;
+	  if (address_mode == mode_64bit && (sizeflag & DFLAG))
 	    {
 	      *obufp++ = 'q';
 	      break;
 	    }
 	  /* Fall through.  */
 	case 'P':
-          if (intel_syntax)
-            break;
+	  if (intel_syntax)
+	    break;
 	  if ((prefixes & PREFIX_DATA)
-	      || (rex & REX_MODE64)
+	      || (rex & REX_W)
 	      || (sizeflag & SUFFIX_ALWAYS))
 	    {
-	      USED_REX (REX_MODE64);
-	      if (rex & REX_MODE64)
+	      USED_REX (REX_W);
+	      if (rex & REX_W)
 		*obufp++ = 'q';
 	      else
 		{
@@ -2690,75 +4533,73 @@
 		      *obufp++ = 'l';
 		   else
 		     *obufp++ = 'w';
-		   used_prefixes |= (prefixes & PREFIX_DATA);
 		}
+	      used_prefixes |= (prefixes & PREFIX_DATA);
 	    }
 	  break;
 	case 'U':
-          if (intel_syntax)
-            break;
-	  if (mode_64bit)
+	  if (intel_syntax)
+	    break;
+	  if (address_mode == mode_64bit && (sizeflag & DFLAG))
 	    {
-	      *obufp++ = 'q';
+	      if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS))
+		*obufp++ = 'q';
 	      break;
 	    }
 	  /* Fall through.  */
 	case 'Q':
-          if (intel_syntax)
-            break;
-	  USED_REX (REX_MODE64);
-	  if (mod != 3 || (sizeflag & SUFFIX_ALWAYS))
+	  if (intel_syntax && !alt)
+	    break;
+	  USED_REX (REX_W);
+	  if (modrm.mod != 3 || (sizeflag & SUFFIX_ALWAYS))
 	    {
-	      if (rex & REX_MODE64)
+	      if (rex & REX_W)
 		*obufp++ = 'q';
 	      else
 		{
 		  if (sizeflag & DFLAG)
-		    *obufp++ = 'l';
+		    *obufp++ = intel_syntax ? 'd' : 'l';
 		  else
 		    *obufp++ = 'w';
-		  used_prefixes |= (prefixes & PREFIX_DATA);
 		}
+	      used_prefixes |= (prefixes & PREFIX_DATA);
 	    }
 	  break;
 	case 'R':
-	  USED_REX (REX_MODE64);
-          if (intel_syntax)
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    *obufp++ = 'q';
+	  else if (sizeflag & DFLAG)
 	    {
-	      if (rex & REX_MODE64)
-		{
-		  *obufp++ = 'q';
-		  *obufp++ = 't';
-		}
-	      else if (sizeflag & DFLAG)
-		{
+	      if (intel_syntax)
 		  *obufp++ = 'd';
-		  *obufp++ = 'q';
-		}
 	      else
-		{
-		  *obufp++ = 'w';
-		  *obufp++ = 'd';
-		}
+		  *obufp++ = 'l';
 	    }
 	  else
-	    {
-	      if (rex & REX_MODE64)
-		*obufp++ = 'q';
-	      else if (sizeflag & DFLAG)
-		*obufp++ = 'l';
-	      else
-		*obufp++ = 'w';
-	    }
-	  if (!(rex & REX_MODE64))
+	    *obufp++ = 'w';
+	  if (intel_syntax && !p[1]
+	      && ((rex & REX_W) || (sizeflag & DFLAG)))
+	    *obufp++ = 'e';
+	  if (!(rex & REX_W))
 	    used_prefixes |= (prefixes & PREFIX_DATA);
 	  break;
+	case 'V':
+	  if (intel_syntax)
+	    break;
+	  if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	    {
+	      if (sizeflag & SUFFIX_ALWAYS)
+		*obufp++ = 'q';
+	      break;
+	    }
+	  /* Fall through.  */
 	case 'S':
-          if (intel_syntax)
-            break;
+	  if (intel_syntax)
+	    break;
 	  if (sizeflag & SUFFIX_ALWAYS)
 	    {
-	      if (rex & REX_MODE64)
+	      if (rex & REX_W)
 		*obufp++ = 'q';
 	      else
 		{
@@ -2775,63 +4616,51 @@
 	    *obufp++ = 'd';
 	  else
 	    *obufp++ = 's';
-          used_prefixes |= (prefixes & PREFIX_DATA);
+	  used_prefixes |= (prefixes & PREFIX_DATA);
 	  break;
 	case 'Y':
-          if (intel_syntax)
-            break;
-	  if (rex & REX_MODE64)
+	  if (intel_syntax)
+	    break;
+	  if (rex & REX_W)
 	    {
-	      USED_REX (REX_MODE64);
+	      USED_REX (REX_W);
 	      *obufp++ = 'q';
 	    }
 	  break;
 	  /* implicit operand size 'l' for i386 or 'q' for x86-64 */
 	case 'W':
 	  /* operand size flag for cwtl, cbtw */
-	  USED_REX (0);
-	  if (rex)
-	    *obufp++ = 'l';
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    {
+	      if (intel_syntax)
+		*obufp++ = 'd';
+	      else
+		*obufp++ = 'l';
+	    }
 	  else if (sizeflag & DFLAG)
 	    *obufp++ = 'w';
 	  else
 	    *obufp++ = 'b';
-          if (intel_syntax)
-	    {
-	      if (rex)
-		{
-		  *obufp++ = 'q';
-		  *obufp++ = 'e';
-		}
-	      if (sizeflag & DFLAG)
-		{
-		  *obufp++ = 'd';
-		  *obufp++ = 'e';
-		}
-	      else
-		{
-		  *obufp++ = 'w';
-		}
-	    }
-	  if (!rex)
+	  if (!(rex & REX_W))
 	    used_prefixes |= (prefixes & PREFIX_DATA);
 	  break;
 	}
+      alt = 0;
     }
   *obufp = 0;
   return 0;
 }
 
 static void
-oappend (s)
-     const char *s;
+oappend (const char *s)
 {
   strcpy (obufp, s);
   obufp += strlen (s);
 }
 
 static void
-append_seg ()
+append_seg (void)
 {
   if (prefixes & PREFIX_CS)
     {
@@ -2866,9 +4695,7 @@
 }
 
 static void
-OP_indirE (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_indirE (int bytemode, int sizeflag)
 {
   if (!intel_syntax)
     oappend ("*");
@@ -2878,7 +4705,7 @@
 static void
 print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp)
 {
-  if (mode_64bit)
+  if (address_mode == mode_64bit)
     {
       if (hex)
 	{
@@ -2932,63 +4759,187 @@
     }
 }
 
+/* Put DISP in BUF as signed hex number.  */
+
 static void
-OP_E (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+print_displacement (char *buf, bfd_vma disp)
+{
+  bfd_signed_vma val = disp;
+  char tmp[30];
+  int i, j = 0;
+
+  if (val < 0)
+    {
+      buf[j++] = '-';
+      val = -disp;
+
+      /* Check for possible overflow.  */
+      if (val < 0)
+	{
+	  switch (address_mode)
+	    {
+	    case mode_64bit:
+	      strcpy (buf + j, "0x8000000000000000");
+	      break;
+	    case mode_32bit:
+	      strcpy (buf + j, "0x80000000");
+	      break;
+	    case mode_16bit:
+	      strcpy (buf + j, "0x8000");
+	      break;
+	    }
+	  return;
+	}
+    }
+
+  buf[j++] = '0';
+  buf[j++] = 'x';
+
+  snprintf_vma (tmp, sizeof(tmp), val);
+  for (i = 0; tmp[i] == '0'; i++)
+    continue;
+  if (tmp[i] == '\0')
+    i--;
+  strcpy (buf + j, tmp + i);
+}
+
+static void
+intel_operand_size (int bytemode, int sizeflag)
+{
+  switch (bytemode)
+    {
+    case b_mode:
+    case dqb_mode:
+      oappend ("BYTE PTR ");
+      break;
+    case w_mode:
+    case dqw_mode:
+      oappend ("WORD PTR ");
+      break;
+    case stack_v_mode:
+      if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	{
+	  oappend ("QWORD PTR ");
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+	  break;
+	}
+      /* FALLTHRU */
+    case v_mode:
+    case dq_mode:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	oappend ("QWORD PTR ");
+      else if ((sizeflag & DFLAG) || bytemode == dq_mode)
+	oappend ("DWORD PTR ");
+      else
+	oappend ("WORD PTR ");
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case z_mode:
+      if ((rex & REX_W) || (sizeflag & DFLAG))
+	*obufp++ = 'D';
+      oappend ("WORD PTR ");
+      if (!(rex & REX_W))
+	used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case d_mode:
+    case dqd_mode:
+      oappend ("DWORD PTR ");
+      break;
+    case q_mode:
+      oappend ("QWORD PTR ");
+      break;
+    case m_mode:
+      if (address_mode == mode_64bit)
+	oappend ("QWORD PTR ");
+      else
+	oappend ("DWORD PTR ");
+      break;
+    case f_mode:
+      if (sizeflag & DFLAG)
+	oappend ("FWORD PTR ");
+      else
+	oappend ("DWORD PTR ");
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    case t_mode:
+      oappend ("TBYTE PTR ");
+      break;
+    case x_mode:
+      oappend ("XMMWORD PTR ");
+      break;
+    case o_mode:
+      oappend ("OWORD PTR ");
+      break;
+    default:
+      break;
+    }
+}
+
+static void
+OP_E (int bytemode, int sizeflag)
 {
   bfd_vma disp;
   int add = 0;
   int riprel = 0;
-  USED_REX (REX_EXTZ);
-  if (rex & REX_EXTZ)
+  USED_REX (REX_B);
+  if (rex & REX_B)
     add += 8;
 
   /* Skip mod/rm byte.  */
   MODRM_CHECK;
   codep++;
 
-  if (mod == 3)
+  if (modrm.mod == 3)
     {
       switch (bytemode)
 	{
 	case b_mode:
 	  USED_REX (0);
 	  if (rex)
-	    oappend (names8rex[rm + add]);
+	    oappend (names8rex[modrm.rm + add]);
 	  else
-	    oappend (names8[rm + add]);
+	    oappend (names8[modrm.rm + add]);
 	  break;
 	case w_mode:
-	  oappend (names16[rm + add]);
+	  oappend (names16[modrm.rm + add]);
 	  break;
 	case d_mode:
-	  oappend (names32[rm + add]);
+	  oappend (names32[modrm.rm + add]);
 	  break;
 	case q_mode:
-	  oappend (names64[rm + add]);
+	  oappend (names64[modrm.rm + add]);
 	  break;
 	case m_mode:
-	  if (mode_64bit)
-	    oappend (names64[rm + add]);
+	  if (address_mode == mode_64bit)
+	    oappend (names64[modrm.rm + add]);
 	  else
-	    oappend (names32[rm + add]);
+	    oappend (names32[modrm.rm + add]);
 	  break;
+	case stack_v_mode:
+	  if (address_mode == mode_64bit && (sizeflag & DFLAG))
+	    {
+	      oappend (names64[modrm.rm + add]);
+	      used_prefixes |= (prefixes & PREFIX_DATA);
+	      break;
+	    }
+	  bytemode = v_mode;
+	  /* FALLTHRU */
 	case v_mode:
-	  USED_REX (REX_MODE64);
-	  if (rex & REX_MODE64)
-	    oappend (names64[rm + add]);
-	  else if (sizeflag & DFLAG)
-	    oappend (names32[rm + add]);
+	case dq_mode:
+	case dqb_mode:
+	case dqd_mode:
+	case dqw_mode:
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    oappend (names64[modrm.rm + add]);
+	  else if ((sizeflag & DFLAG) || bytemode != v_mode)
+	    oappend (names32[modrm.rm + add]);
 	  else
-	    oappend (names16[rm + add]);
+	    oappend (names16[modrm.rm + add]);
 	  used_prefixes |= (prefixes & PREFIX_DATA);
 	  break;
 	case 0:
-	  if (!(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */)
-	      && !(codep[-2] == 0xAE && codep[-1] == 0xF0 /* mfence */)
-	      && !(codep[-2] == 0xAE && codep[-1] == 0xe8 /* lfence */))
-	    BadOp ();	/* bad sfence,lea,lds,les,lfs,lgs,lss modrm */
 	  break;
 	default:
 	  oappend (INTERNAL_DISASSEMBLER_ERROR);
@@ -2998,10 +4949,14 @@
     }
 
   disp = 0;
+  if (intel_syntax)
+    intel_operand_size (bytemode, sizeflag);
   append_seg ();
 
-  if ((sizeflag & AFLAG) || mode_64bit) /* 32 bit address mode */
+  if ((sizeflag & AFLAG) || address_mode == mode_64bit)
     {
+      /* 32/64 bit address mode */
+      int havedisp;
       int havesib;
       int havebase;
       int base;
@@ -3010,31 +4965,31 @@
 
       havesib = 0;
       havebase = 1;
-      base = rm;
+      base = modrm.rm;
 
       if (base == 4)
 	{
 	  havesib = 1;
 	  FETCH_DATA (the_info, codep + 1);
-	  scale = (*codep >> 6) & 3;
 	  index = (*codep >> 3) & 7;
+	  if (address_mode == mode_64bit || index != 0x4)
+	    /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored.  */
+	    scale = (*codep >> 6) & 3;
 	  base = *codep & 7;
-	  USED_REX (REX_EXTY);
-	  USED_REX (REX_EXTZ);
-	  if (rex & REX_EXTY)
+	  USED_REX (REX_X);
+	  if (rex & REX_X)
 	    index += 8;
-	  if (rex & REX_EXTZ)
-	    base += 8;
 	  codep++;
 	}
+      base += add;
 
-      switch (mod)
+      switch (modrm.mod)
 	{
 	case 0:
 	  if ((base & 7) == 5)
 	    {
 	      havebase = 0;
-	      if (mode_64bit && !havesib && (sizeflag & AFLAG))
+	      if (address_mode == mode_64bit && !havesib)
 		riprel = 1;
 	      disp = get32s ();
 	    }
@@ -3050,117 +5005,81 @@
 	  break;
 	}
 
+      havedisp = havebase || (havesib && (index != 4 || scale != 0));
+
       if (!intel_syntax)
-        if (mod != 0 || (base & 7) == 5)
-          {
-            print_operand_value (scratchbuf, sizeof(scratchbuf), !riprel, disp);
-            oappend (scratchbuf);
+	if (modrm.mod != 0 || (base & 7) == 5)
+	  {
+	    if (havedisp || riprel)
+	      print_displacement (scratchbuf, disp);
+	    else
+              print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp);
+	    oappend (scratchbuf);
 	    if (riprel)
 	      {
 		set_op (disp, 1);
 		oappend ("(%rip)");
 	      }
-          }
+	  }
 
-      if (havebase || (havesib && (index != 4 || scale != 0)))
+      if (havedisp || (intel_syntax && riprel))
 	{
-          if (intel_syntax)
-            {
-              switch (bytemode)
-                {
-                case b_mode:
-                  oappend ("BYTE PTR ");
-                  break;
-                case w_mode:
-                  oappend ("WORD PTR ");
-                  break;
-                case v_mode:
-                  oappend ("DWORD PTR ");
-                  break;
-                case d_mode:
-                  oappend ("QWORD PTR ");
-                  break;
-                case m_mode:
-		  if (mode_64bit)
-		    oappend ("DWORD PTR ");
-		  else
-		    oappend ("QWORD PTR ");
-		  break;
-                case x_mode:
-                  oappend ("XWORD PTR ");
-                  break;
-                default:
-                  break;
-                }
-             }
 	  *obufp++ = open_char;
 	  if (intel_syntax && riprel)
-	    oappend ("rip + ");
-          *obufp = '\0';
-	  USED_REX (REX_EXTZ);
-	  if (!havesib && (rex & REX_EXTZ))
-	    base += 8;
+	    {
+	      set_op (disp, 1);
+	      oappend ("rip");
+	    }
+	  *obufp = '\0';
 	  if (havebase)
-	    oappend (mode_64bit && (sizeflag & AFLAG)
+	    oappend (address_mode == mode_64bit && (sizeflag & AFLAG)
 		     ? names64[base] : names32[base]);
 	  if (havesib)
 	    {
 	      if (index != 4)
 		{
-                  if (intel_syntax)
-                    {
-                      if (havebase)
-                        {
-                          *obufp++ = separator_char;
-                          *obufp = '\0';
-                        }
-                      snprintf (scratchbuf, sizeof(scratchbuf), "%s",
-                                mode_64bit && (sizeflag & AFLAG)
-                                ? names64[index] : names32[index]);
-                    }
-                  else
-                      snprintf (scratchbuf, sizeof(scratchbuf), ",%s",
-                                mode_64bit && (sizeflag & AFLAG)
-                                ? names64[index] : names32[index]);
+		  if (!intel_syntax || havebase)
+		    {
+		      *obufp++ = separator_char;
+		      *obufp = '\0';
+		    }
+		  oappend (address_mode == mode_64bit && (sizeflag & AFLAG)
+			   ? names64[index] : names32[index]);
+		}
+	      if (scale != 0 || (!intel_syntax && index != 4))
+		{
+		  *obufp++ = scale_char;
+		  *obufp = '\0';
+		  snprintf (scratchbuf, sizeof(scratchbuf), "%d", 1 << scale);
 		  oappend (scratchbuf);
 		}
-              if (!intel_syntax
-                  || (intel_syntax
-                      && bytemode != b_mode
-                      && bytemode != w_mode
-                      && bytemode != v_mode))
-                {
-                  *obufp++ = scale_char;
-                  *obufp = '\0';
-                  snprintf (scratchbuf, sizeof(scratchbuf), "%d", 1 << scale);
-	          oappend (scratchbuf);
-                }
 	    }
-          if (intel_syntax)
-            if (mod != 0 || (base & 7) == 5)
-              {
-		/* Don't print zero displacements.  */
-                if (disp != 0)
-                  {
-		    if ((bfd_signed_vma) disp > 0)
-		      {
-			*obufp++ = '+';
-			*obufp = '\0';
-		      }
+	  if (intel_syntax
+	      && (disp || modrm.mod != 0 || (base & 7) == 5))
+	    {
+	      if ((bfd_signed_vma) disp >= 0)
+		{
+		  *obufp++ = '+';
+		  *obufp = '\0';
+		}
+	      else if (modrm.mod != 1)
+		{
+		  *obufp++ = '-';
+		  *obufp = '\0';
+		  disp = - (bfd_signed_vma) disp;
+		}
 
-                    print_operand_value (scratchbuf, sizeof(scratchbuf), 0,
-                                         disp);
-                    oappend (scratchbuf);
-                  }
-              }
+	      print_displacement (scratchbuf, disp);
+	      oappend (scratchbuf);
+	    }
 
 	  *obufp++ = close_char;
-          *obufp = '\0';
+	  *obufp = '\0';
 	}
       else if (intel_syntax)
-        {
-          if (mod != 0 || (base & 7) == 5)
-            {
+	{
+	  if (modrm.mod != 0 || (base & 7) == 5)
+	    {
 	      if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
 			      | PREFIX_ES | PREFIX_FS | PREFIX_GS))
 		;
@@ -3169,17 +5088,17 @@
 		  oappend (names_seg[ds_reg - es_reg]);
 		  oappend (":");
 		}
-              print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp);
-              oappend (scratchbuf);
-            }
-        }
+	      print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp);
+	      oappend (scratchbuf);
+	    }
+	}
     }
   else
     { /* 16 bit address mode */
-      switch (mod)
+      switch (modrm.mod)
 	{
 	case 0:
-	  if ((rm & 7) == 6)
+	  if (modrm.rm == 6)
 	    {
 	      disp = get16 ();
 	      if ((disp & 0x8000) != 0)
@@ -3200,60 +5119,101 @@
 	}
 
       if (!intel_syntax)
-        if (mod != 0 || (rm & 7) == 6)
-          {
-            print_operand_value (scratchbuf, sizeof(scratchbuf), 0, disp);
-            oappend (scratchbuf);
-          }
+	if (modrm.mod != 0 || modrm.rm == 6)
+	  {
+	    print_displacement (scratchbuf, disp);
+	    oappend (scratchbuf);
+	  }
 
-      if (mod != 0 || (rm & 7) != 6)
+      if (modrm.mod != 0 || modrm.rm != 6)
 	{
 	  *obufp++ = open_char;
-          *obufp = '\0';
-	  oappend (index16[rm + add]);
-          *obufp++ = close_char;
-          *obufp = '\0';
+	  *obufp = '\0';
+	  oappend (index16[modrm.rm]);
+	  if (intel_syntax
+	      && (disp || modrm.mod != 0 || modrm.rm == 6))
+	    {
+	      if ((bfd_signed_vma) disp >= 0)
+		{
+		  *obufp++ = '+';
+		  *obufp = '\0';
+		}
+	      else if (modrm.mod != 1)
+		{
+		  *obufp++ = '-';
+		  *obufp = '\0';
+		  disp = - (bfd_signed_vma) disp;
+		}
+
+	      print_displacement (scratchbuf, disp);
+	      oappend (scratchbuf);
+	    }
+
+	  *obufp++ = close_char;
+	  *obufp = '\0';
+	}
+      else if (intel_syntax)
+	{
+	  if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
+			  | PREFIX_ES | PREFIX_FS | PREFIX_GS))
+	    ;
+	  else
+	    {
+	      oappend (names_seg[ds_reg - es_reg]);
+	      oappend (":");
+	    }
+	  print_operand_value (scratchbuf, sizeof(scratchbuf), 1,
+                               disp & 0xffff);
+	  oappend (scratchbuf);
 	}
     }
 }
 
 static void
-OP_G (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_G (int bytemode, int sizeflag)
 {
   int add = 0;
-  USED_REX (REX_EXTX);
-  if (rex & REX_EXTX)
+  USED_REX (REX_R);
+  if (rex & REX_R)
     add += 8;
   switch (bytemode)
     {
     case b_mode:
       USED_REX (0);
       if (rex)
-	oappend (names8rex[reg + add]);
+	oappend (names8rex[modrm.reg + add]);
       else
-	oappend (names8[reg + add]);
+	oappend (names8[modrm.reg + add]);
       break;
     case w_mode:
-      oappend (names16[reg + add]);
+      oappend (names16[modrm.reg + add]);
       break;
     case d_mode:
-      oappend (names32[reg + add]);
+      oappend (names32[modrm.reg + add]);
       break;
     case q_mode:
-      oappend (names64[reg + add]);
+      oappend (names64[modrm.reg + add]);
       break;
     case v_mode:
-      USED_REX (REX_MODE64);
-      if (rex & REX_MODE64)
-	oappend (names64[reg + add]);
-      else if (sizeflag & DFLAG)
-	oappend (names32[reg + add]);
+    case dq_mode:
+    case dqb_mode:
+    case dqd_mode:
+    case dqw_mode:
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	oappend (names64[modrm.reg + add]);
+      else if ((sizeflag & DFLAG) || bytemode != v_mode)
+	oappend (names32[modrm.reg + add]);
       else
-	oappend (names16[reg + add]);
+	oappend (names16[modrm.reg + add]);
       used_prefixes |= (prefixes & PREFIX_DATA);
       break;
+    case m_mode:
+      if (address_mode == mode_64bit)
+	oappend (names64[modrm.reg + add]);
+      else
+	oappend (names32[modrm.reg + add]);
+      break;
     default:
       oappend (INTERNAL_DISASSEMBLER_ERROR);
       break;
@@ -3261,7 +5221,7 @@
 }
 
 static bfd_vma
-get64 ()
+get64 (void)
 {
   bfd_vma x;
 #ifdef BFD64
@@ -3286,7 +5246,7 @@
 }
 
 static bfd_signed_vma
-get32 ()
+get32 (void)
 {
   bfd_signed_vma x = 0;
 
@@ -3299,7 +5259,7 @@
 }
 
 static bfd_signed_vma
-get32s ()
+get32s (void)
 {
   bfd_signed_vma x = 0;
 
@@ -3315,7 +5275,7 @@
 }
 
 static int
-get16 ()
+get16 (void)
 {
   int x = 0;
 
@@ -3326,12 +5286,10 @@
 }
 
 static void
-set_op (op, riprel)
-     bfd_vma op;
-     int riprel;
+set_op (bfd_vma op, int riprel)
 {
   op_index[op_ad] = op_ad;
-  if (mode_64bit)
+  if (address_mode == mode_64bit)
     {
       op_address[op_ad] = op;
       op_riprel[op_ad] = riprel;
@@ -3345,24 +5303,16 @@
 }
 
 static void
-OP_REG (code, sizeflag)
-     int code;
-     int sizeflag;
+OP_REG (int code, int sizeflag)
 {
   const char *s;
   int add = 0;
-  USED_REX (REX_EXTZ);
-  if (rex & REX_EXTZ)
+  USED_REX (REX_B);
+  if (rex & REX_B)
     add = 8;
 
   switch (code)
     {
-    case indir_dx_reg:
-      if (intel_syntax)
-        s = "[dx]";
-      else
-        s = "(%dx)";
-      break;
     case ax_reg: case cx_reg: case dx_reg: case bx_reg:
     case sp_reg: case bp_reg: case si_reg: case di_reg:
       s = names16[code - ax_reg + add];
@@ -3381,7 +5331,7 @@
       break;
     case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg:
     case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg:
-      if (mode_64bit)
+      if (address_mode == mode_64bit && (sizeflag & DFLAG))
 	{
 	  s = names64[code - rAX_reg + add];
 	  break;
@@ -3390,8 +5340,8 @@
       /* Fall through.  */
     case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
     case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
-      USED_REX (REX_MODE64);
-      if (rex & REX_MODE64)
+      USED_REX (REX_W);
+      if (rex & REX_W)
 	s = names64[code - eAX_reg + add];
       else if (sizeflag & DFLAG)
 	s = names32[code - eAX_reg + add];
@@ -3407,9 +5357,7 @@
 }
 
 static void
-OP_IMREG (code, sizeflag)
-     int code;
-     int sizeflag;
+OP_IMREG (int code, int sizeflag)
 {
   const char *s;
 
@@ -3417,9 +5365,9 @@
     {
     case indir_dx_reg:
       if (intel_syntax)
-        s = "[dx]";
+	s = "dx";
       else
-        s = "(%dx)";
+	s = "(%dx)";
       break;
     case ax_reg: case cx_reg: case dx_reg: case bx_reg:
     case sp_reg: case bp_reg: case si_reg: case di_reg:
@@ -3439,8 +5387,8 @@
       break;
     case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
     case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
-      USED_REX (REX_MODE64);
-      if (rex & REX_MODE64)
+      USED_REX (REX_W);
+      if (rex & REX_W)
 	s = names64[code - eAX_reg];
       else if (sizeflag & DFLAG)
 	s = names32[code - eAX_reg];
@@ -3448,6 +5396,14 @@
 	s = names16[code - eAX_reg];
       used_prefixes |= (prefixes & PREFIX_DATA);
       break;
+    case z_mode_ax_reg:
+      if ((rex & REX_W) || (sizeflag & DFLAG))
+	s = *names32;
+      else
+	s = *names16;
+      if (!(rex & REX_W))
+	used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
     default:
       s = INTERNAL_DISASSEMBLER_ERROR;
       break;
@@ -3456,9 +5412,7 @@
 }
 
 static void
-OP_I (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_I (int bytemode, int sizeflag)
 {
   bfd_signed_vma op;
   bfd_signed_vma mask = -1;
@@ -3471,15 +5425,15 @@
       mask = 0xff;
       break;
     case q_mode:
-      if (mode_64bit)
+      if (address_mode == mode_64bit)
 	{
 	  op = get32s ();
 	  break;
 	}
       /* Fall through.  */
     case v_mode:
-      USED_REX (REX_MODE64);
-      if (rex & REX_MODE64)
+      USED_REX (REX_W);
+      if (rex & REX_W)
 	op = get32s ();
       else if (sizeflag & DFLAG)
 	{
@@ -3497,6 +5451,10 @@
       mask = 0xfffff;
       op = get16 ();
       break;
+    case const_1_mode:
+      if (intel_syntax)
+        oappend ("1");
+      return;
     default:
       oappend (INTERNAL_DISASSEMBLER_ERROR);
       return;
@@ -3510,14 +5468,12 @@
 }
 
 static void
-OP_I64 (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_I64 (int bytemode, int sizeflag)
 {
   bfd_signed_vma op;
   bfd_signed_vma mask = -1;
 
-  if (!mode_64bit)
+  if (address_mode != mode_64bit)
     {
       OP_I (bytemode, sizeflag);
       return;
@@ -3531,8 +5487,8 @@
       mask = 0xff;
       break;
     case v_mode:
-      USED_REX (REX_MODE64);
-      if (rex & REX_MODE64)
+      USED_REX (REX_W);
+      if (rex & REX_W)
 	op = get64 ();
       else if (sizeflag & DFLAG)
 	{
@@ -3563,9 +5519,7 @@
 }
 
 static void
-OP_sI (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_sI (int bytemode, int sizeflag)
 {
   bfd_signed_vma op;
   bfd_signed_vma mask = -1;
@@ -3580,8 +5534,8 @@
       mask = 0xffffffff;
       break;
     case v_mode:
-      USED_REX (REX_MODE64);
-      if (rex & REX_MODE64)
+      USED_REX (REX_W);
+      if (rex & REX_W)
 	op = get32s ();
       else if (sizeflag & DFLAG)
 	{
@@ -3614,12 +5568,11 @@
 }
 
 static void
-OP_J (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_J (int bytemode, int sizeflag)
 {
   bfd_vma disp;
   bfd_vma mask = -1;
+  bfd_vma segment = 0;
 
   switch (bytemode)
     {
@@ -3630,39 +5583,45 @@
 	disp -= 0x100;
       break;
     case v_mode:
-      if (sizeflag & DFLAG)
+      if ((sizeflag & DFLAG) || (rex & REX_W))
 	disp = get32s ();
       else
 	{
 	  disp = get16 ();
-	  /* For some reason, a data16 prefix on a jump instruction
-	     means that the pc is masked to 16 bits after the
-	     displacement is added!  */
+	  if ((disp & 0x8000) != 0)
+	    disp -= 0x10000;
+	  /* In 16bit mode, address is wrapped around at 64k within
+	     the same segment.  Otherwise, a data16 prefix on a jump
+	     instruction means that the pc is masked to 16 bits after
+	     the displacement is added!  */
 	  mask = 0xffff;
+	  if ((prefixes & PREFIX_DATA) == 0)
+	    segment = ((start_pc + codep - start_codep)
+		       & ~((bfd_vma) 0xffff));
 	}
+      used_prefixes |= (prefixes & PREFIX_DATA);
       break;
     default:
       oappend (INTERNAL_DISASSEMBLER_ERROR);
       return;
     }
-  disp = (start_pc + codep - start_codep + disp) & mask;
+  disp = ((start_pc + codep - start_codep + disp) & mask) | segment;
   set_op (disp, 0);
   print_operand_value (scratchbuf, sizeof(scratchbuf), 1, disp);
   oappend (scratchbuf);
 }
 
 static void
-OP_SEG (dummy, sizeflag)
-     int dummy;
-     int sizeflag;
+OP_SEG (int bytemode, int sizeflag)
 {
-  oappend (names_seg[reg]);
+  if (bytemode == w_mode)
+    oappend (names_seg[modrm.reg]);
+  else
+    OP_E (modrm.mod == 3 ? bytemode : w_mode, sizeflag);
 }
 
 static void
-OP_DIR (dummy, sizeflag)
-     int dummy;
-     int sizeflag;
+OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag)
 {
   int seg, offset;
 
@@ -3678,22 +5637,22 @@
     }
   used_prefixes |= (prefixes & PREFIX_DATA);
   if (intel_syntax)
-    snprintf (scratchbuf, sizeof(scratchbuf), "0x%x,0x%x", seg, offset);
+    snprintf (scratchbuf, sizeof(scratchbuf), "0x%x:0x%x", seg, offset);
   else
     snprintf (scratchbuf, sizeof(scratchbuf), "$0x%x,$0x%x", seg, offset);
   oappend (scratchbuf);
 }
 
 static void
-OP_OFF (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_OFF (int bytemode, int sizeflag)
 {
   bfd_vma off;
 
+  if (intel_syntax && (sizeflag & SUFFIX_ALWAYS))
+    intel_operand_size (bytemode, sizeflag);
   append_seg ();
 
-  if ((sizeflag & AFLAG) || mode_64bit)
+  if ((sizeflag & AFLAG) || address_mode == mode_64bit)
     off = get32 ();
   else
     off = get16 ();
@@ -3701,7 +5660,7 @@
   if (intel_syntax)
     {
       if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
-		        | PREFIX_ES | PREFIX_FS | PREFIX_GS)))
+			| PREFIX_ES | PREFIX_FS | PREFIX_GS)))
 	{
 	  oappend (names_seg[ds_reg - es_reg]);
 	  oappend (":");
@@ -3712,18 +5671,19 @@
 }
 
 static void
-OP_OFF64 (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_OFF64 (int bytemode, int sizeflag)
 {
   bfd_vma off;
 
-  if (!mode_64bit)
+  if (address_mode != mode_64bit
+      || (prefixes & PREFIX_ADDR))
     {
       OP_OFF (bytemode, sizeflag);
       return;
     }
 
+  if (intel_syntax && (sizeflag & SUFFIX_ALWAYS))
+    intel_operand_size (bytemode, sizeflag);
   append_seg ();
 
   off = get64 ();
@@ -3731,7 +5691,7 @@
   if (intel_syntax)
     {
       if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
-		        | PREFIX_ES | PREFIX_FS | PREFIX_GS)))
+			| PREFIX_ES | PREFIX_FS | PREFIX_GS)))
 	{
 	  oappend (names_seg[ds_reg - es_reg]);
 	  oappend (":");
@@ -3742,49 +5702,71 @@
 }
 
 static void
-ptr_reg (code, sizeflag)
-     int code;
-     int sizeflag;
+ptr_reg (int code, int sizeflag)
 {
   const char *s;
-  if (intel_syntax)
-    oappend ("[");
-  else
-    oappend ("(");
 
-  USED_REX (REX_MODE64);
-  if (rex & REX_MODE64)
+  *obufp++ = open_char;
+  used_prefixes |= (prefixes & PREFIX_ADDR);
+  if (address_mode == mode_64bit)
     {
       if (!(sizeflag & AFLAG))
-        s = names32[code - eAX_reg];
+	s = names32[code - eAX_reg];
       else
-        s = names64[code - eAX_reg];
+	s = names64[code - eAX_reg];
     }
   else if (sizeflag & AFLAG)
     s = names32[code - eAX_reg];
   else
     s = names16[code - eAX_reg];
   oappend (s);
-  if (intel_syntax)
-    oappend ("]");
-  else
-    oappend (")");
+  *obufp++ = close_char;
+  *obufp = 0;
 }
 
 static void
-OP_ESreg (code, sizeflag)
-     int code;
-     int sizeflag;
+OP_ESreg (int code, int sizeflag)
 {
+  if (intel_syntax)
+    {
+      switch (codep[-1])
+	{
+	case 0x6d:	/* insw/insl */
+	  intel_operand_size (z_mode, sizeflag);
+	  break;
+	case 0xa5:	/* movsw/movsl/movsq */
+	case 0xa7:	/* cmpsw/cmpsl/cmpsq */
+	case 0xab:	/* stosw/stosl */
+	case 0xaf:	/* scasw/scasl */
+	  intel_operand_size (v_mode, sizeflag);
+	  break;
+	default:
+	  intel_operand_size (b_mode, sizeflag);
+	}
+    }
   oappend ("%es:" + intel_syntax);
   ptr_reg (code, sizeflag);
 }
 
 static void
-OP_DSreg (code, sizeflag)
-     int code;
-     int sizeflag;
+OP_DSreg (int code, int sizeflag)
 {
+  if (intel_syntax)
+    {
+      switch (codep[-1])
+	{
+	case 0x6f:	/* outsw/outsl */
+	  intel_operand_size (z_mode, sizeflag);
+	  break;
+	case 0xa5:	/* movsw/movsl/movsq */
+	case 0xa7:	/* cmpsw/cmpsl/cmpsq */
+	case 0xad:	/* lodsw/lodsl/lodsq */
+	  intel_operand_size (v_mode, sizeflag);
+	  break;
+	default:
+	  intel_operand_size (b_mode, sizeflag);
+	}
+    }
   if ((prefixes
        & (PREFIX_CS
 	  | PREFIX_DS
@@ -3798,154 +5780,253 @@
 }
 
 static void
-OP_C (dummy, sizeflag)
-     int dummy;
-     int sizeflag;
+OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
   int add = 0;
-  USED_REX (REX_EXTX);
-  if (rex & REX_EXTX)
-    add = 8;
-  snprintf (scratchbuf, sizeof(scratchbuf), "%%cr%d", reg + add);
+  if (rex & REX_R)
+    {
+      USED_REX (REX_R);
+      add = 8;
+    }
+  else if (address_mode != mode_64bit && (prefixes & PREFIX_LOCK))
+    {
+      used_prefixes |= PREFIX_LOCK;
+      add = 8;
+    }
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%cr%d", modrm.reg + add);
   oappend (scratchbuf + intel_syntax);
 }
 
 static void
-OP_D (dummy, sizeflag)
-     int dummy;
-     int sizeflag;
+OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
   int add = 0;
-  USED_REX (REX_EXTX);
-  if (rex & REX_EXTX)
+  USED_REX (REX_R);
+  if (rex & REX_R)
     add = 8;
   if (intel_syntax)
-    snprintf (scratchbuf, sizeof(scratchbuf), "db%d", reg + add);
+    snprintf (scratchbuf, sizeof(scratchbuf), "db%d", modrm.reg + add);
   else
-    snprintf (scratchbuf, sizeof(scratchbuf), "%%db%d", reg + add);
+    snprintf (scratchbuf, sizeof(scratchbuf), "%%db%d", modrm.reg + add);
   oappend (scratchbuf);
 }
 
 static void
-OP_T (dummy, sizeflag)
-     int dummy;
-     int sizeflag;
+OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
-  snprintf (scratchbuf, sizeof(scratchbuf), "%%tr%d", reg);
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%tr%d", modrm.reg);
   oappend (scratchbuf + intel_syntax);
 }
 
 static void
-OP_Rd (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_R (int bytemode, int sizeflag)
 {
-  if (mod == 3)
+  if (modrm.mod == 3)
     OP_E (bytemode, sizeflag);
   else
     BadOp ();
 }
 
 static void
-OP_MMX (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
-  int add = 0;
-  USED_REX (REX_EXTX);
-  if (rex & REX_EXTX)
-    add = 8;
   used_prefixes |= (prefixes & PREFIX_DATA);
   if (prefixes & PREFIX_DATA)
-    snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg + add);
-  else
-    snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", reg + add);
-  oappend (scratchbuf + intel_syntax);
-}
-
-static void
-OP_XMM (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
-{
-  int add = 0;
-  USED_REX (REX_EXTX);
-  if (rex & REX_EXTX)
-    add = 8;
-  snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg + add);
-  oappend (scratchbuf + intel_syntax);
-}
-
-static void
-OP_EM (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
-{
-  int add = 0;
-  if (mod != 3)
     {
+      int add = 0;
+      USED_REX (REX_R);
+      if (rex & REX_R)
+	add = 8;
+      snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add);
+    }
+  else
+    snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  int add = 0;
+  USED_REX (REX_R);
+  if (rex & REX_R)
+    add = 8;
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.reg + add);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_EM (int bytemode, int sizeflag)
+{
+  if (modrm.mod != 3)
+    {
+      if (intel_syntax && bytemode == v_mode)
+	{
+	  bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode;
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+ 	}
       OP_E (bytemode, sizeflag);
       return;
     }
-  USED_REX (REX_EXTZ);
-  if (rex & REX_EXTZ)
-    add = 8;
 
   /* Skip mod/rm byte.  */
   MODRM_CHECK;
   codep++;
   used_prefixes |= (prefixes & PREFIX_DATA);
   if (prefixes & PREFIX_DATA)
-    snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", rm + add);
+    {
+      int add = 0;
+
+      USED_REX (REX_B);
+      if (rex & REX_B)
+	add = 8;
+      snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add);
+    }
   else
-    snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", rm + add);
+    snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm);
+  oappend (scratchbuf + intel_syntax);
+}
+
+/* cvt* are the only instructions in sse2 which have
+   both SSE and MMX operands and also have 0x66 prefix
+   in their opcode. 0x66 was originally used to differentiate
+   between SSE and MMX instruction(operands). So we have to handle the
+   cvt* separately using OP_EMC and OP_MXC */
+static void
+OP_EMC (int bytemode, int sizeflag)
+{
+  if (modrm.mod != 3)
+    {
+      if (intel_syntax && bytemode == v_mode)
+	{
+	  bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode;
+	  used_prefixes |= (prefixes & PREFIX_DATA);
+ 	}
+      OP_E (bytemode, sizeflag);
+      return;
+    }
+
+  /* Skip mod/rm byte.  */
+  MODRM_CHECK;
+  codep++;
+  used_prefixes |= (prefixes & PREFIX_DATA);
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.rm);
   oappend (scratchbuf + intel_syntax);
 }
 
 static void
-OP_EX (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_MXC (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
+{
+  used_prefixes |= (prefixes & PREFIX_DATA);
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%mm%d", modrm.reg);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+OP_EX (int bytemode, int sizeflag)
 {
   int add = 0;
-  if (mod != 3)
+  if (modrm.mod != 3)
     {
       OP_E (bytemode, sizeflag);
       return;
     }
-  USED_REX (REX_EXTZ);
-  if (rex & REX_EXTZ)
+  USED_REX (REX_B);
+  if (rex & REX_B)
     add = 8;
 
   /* Skip mod/rm byte.  */
   MODRM_CHECK;
   codep++;
-  snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", rm + add);
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", modrm.rm + add);
   oappend (scratchbuf + intel_syntax);
 }
 
 static void
-OP_MS (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_MS (int bytemode, int sizeflag)
 {
-  if (mod == 3)
+  if (modrm.mod == 3)
     OP_EM (bytemode, sizeflag);
   else
     BadOp ();
 }
 
 static void
-OP_XS (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_XS (int bytemode, int sizeflag)
 {
-  if (mod == 3)
+  if (modrm.mod == 3)
     OP_EX (bytemode, sizeflag);
   else
     BadOp ();
 }
 
+static void
+OP_M (int bytemode, int sizeflag)
+{
+  if (modrm.mod == 3)
+    /* bad bound,lea,lds,les,lfs,lgs,lss,cmpxchg8b,vmptrst modrm */
+    BadOp ();
+  else
+    OP_E (bytemode, sizeflag);
+}
+
+static void
+OP_0f07 (int bytemode, int sizeflag)
+{
+  if (modrm.mod != 3 || modrm.rm != 0)
+    BadOp ();
+  else
+    OP_E (bytemode, sizeflag);
+}
+
+static void
+OP_0fae (int bytemode, int sizeflag)
+{
+  if (modrm.mod == 3)
+    {
+      if (modrm.reg == 7)
+	strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence");
+
+      if (modrm.reg < 5 || modrm.rm != 0)
+	{
+	  BadOp ();	/* bad sfence, mfence, or lfence */
+	  return;
+	}
+    }
+  else if (modrm.reg != 7)
+    {
+      BadOp ();		/* bad clflush */
+      return;
+    }
+
+  OP_E (bytemode, sizeflag);
+}
+
+/* NOP is an alias of "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in
+   32bit mode and "xchg %rax,%rax" in 64bit mode.  */
+
+static void
+NOP_Fixup1 (int bytemode, int sizeflag)
+{
+  if ((prefixes & PREFIX_DATA) != 0
+      || (rex != 0
+	  && rex != 0x48
+	  && address_mode == mode_64bit))
+    OP_REG (bytemode, sizeflag);
+  else
+    strcpy (obuf, "nop");
+}
+
+static void
+NOP_Fixup2 (int bytemode, int sizeflag)
+{
+  if ((prefixes & PREFIX_DATA) != 0
+      || (rex != 0
+	  && rex != 0x48
+	  && address_mode == mode_64bit))
+    OP_IMREG (bytemode, sizeflag);
+}
+
 static const char *Suffix3DNow[] = {
 /* 00 */	NULL,		NULL,		NULL,		NULL,
 /* 04 */	NULL,		NULL,		NULL,		NULL,
@@ -3992,7 +6073,7 @@
 /* A8 */	NULL,		NULL,		"pfsubr",	NULL,
 /* AC */	NULL,		NULL,		"pfacc",	NULL,
 /* B0 */	"pfcmpeq",	NULL,		NULL,		NULL,
-/* B4 */	"pfmul",	NULL,		"pfrcpit2",	"pfmulhrw",
+/* B4 */	"pfmul",	NULL,		"pfrcpit2",	"pmulhrw",
 /* B8 */	NULL,		NULL,		NULL,		"pswapd",
 /* BC */	NULL,		NULL,		NULL,		"pavgusb",
 /* C0 */	NULL,		NULL,		NULL,		NULL,
@@ -4014,9 +6095,7 @@
 };
 
 static void
-OP_3DNowSuffix (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
   const char *mnemonic;
 
@@ -4034,8 +6113,8 @@
 	 of the opcode (0x0f0f) and the opcode suffix, we need to do
 	 all the modrm processing first, and don't know until now that
 	 we have a bad opcode.  This necessitates some cleaning up.  */
-      op1out[0] = '\0';
-      op2out[0] = '\0';
+      op_out[0][0] = '\0';
+      op_out[1][0] = '\0';
       BadOp ();
     }
 }
@@ -4052,9 +6131,7 @@
 };
 
 static void
-OP_SIMD_Suffix (bytemode, sizeflag)
-     int bytemode;
-     int sizeflag;
+OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
   unsigned int cmp_type;
 
@@ -4087,20 +6164,18 @@
   else
     {
       /* We have a bad extension byte.  Clean up.  */
-      op1out[0] = '\0';
-      op2out[0] = '\0';
+      op_out[0][0] = '\0';
+      op_out[1][0] = '\0';
       BadOp ();
     }
 }
 
 static void
-SIMD_Fixup (extrachar, sizeflag)
-     int extrachar;
-     int sizeflag;
+SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED)
 {
   /* Change movlps/movhps to movhlps/movlhps for 2 register operand
      forms of these instructions.  */
-  if (mod == 3)
+  if (modrm.mod == 3)
     {
       char *p = obuf + strlen (obuf);
       *(p + 1) = '\0';
@@ -4112,9 +6187,375 @@
 }
 
 static void
+PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag)
+{
+  if (modrm.mod == 3 && modrm.reg == 1 && modrm.rm <= 1)
+    {
+      /* Override "sidt".  */
+      size_t olen = strlen (obuf);
+      char *p = obuf + olen - 4;
+      const char * const *names = (address_mode == mode_64bit
+			    ? names64 : names32);
+
+      /* We might have a suffix when disassembling with -Msuffix.  */
+      if (*p == 'i')
+	--p;
+
+      /* Remove "addr16/addr32" if we aren't in Intel mode.  */
+      if (!intel_syntax
+	  && (prefixes & PREFIX_ADDR)
+	  && olen >= (4 + 7)
+	  && *(p - 1) == ' '
+	  && strncmp (p - 7, "addr", 4) == 0
+	  && (strncmp (p - 3, "16", 2) == 0
+	      || strncmp (p - 3, "32", 2) == 0))
+	p -= 7;
+
+      if (modrm.rm)
+	{
+	  /* mwait %eax,%ecx  */
+	  strcpy (p, "mwait");
+	  if (!intel_syntax)
+	    strcpy (op_out[0], names[0]);
+	}
+      else
+	{
+	  /* monitor %eax,%ecx,%edx"  */
+	  strcpy (p, "monitor");
+	  if (!intel_syntax)
+	    {
+	      const char * const *op1_names;
+	      if (!(prefixes & PREFIX_ADDR))
+		op1_names = (address_mode == mode_16bit
+			     ? names16 : names);
+	      else
+		{
+		  op1_names = (address_mode != mode_32bit
+			       ? names32 : names16);
+		  used_prefixes |= PREFIX_ADDR;
+		}
+	      strcpy (op_out[0], op1_names[0]);
+	      strcpy (op_out[2], names[2]);
+	    }
+	}
+      if (!intel_syntax)
+	{
+	  strcpy (op_out[1], names[1]);
+	  two_source_ops = 1;
+	}
+
+      codep++;
+    }
+  else
+    OP_M (0, sizeflag);
+}
+
+static void
+SVME_Fixup (int bytemode, int sizeflag)
+{
+  const char *alt;
+  char *p;
+
+  switch (*codep)
+    {
+    case 0xd8:
+      alt = "vmrun";
+      break;
+    case 0xd9:
+      alt = "vmmcall";
+      break;
+    case 0xda:
+      alt = "vmload";
+      break;
+    case 0xdb:
+      alt = "vmsave";
+      break;
+    case 0xdc:
+      alt = "stgi";
+      break;
+    case 0xdd:
+      alt = "clgi";
+      break;
+    case 0xde:
+      alt = "skinit";
+      break;
+    case 0xdf:
+      alt = "invlpga";
+      break;
+    default:
+      OP_M (bytemode, sizeflag);
+      return;
+    }
+  /* Override "lidt".  */
+  p = obuf + strlen (obuf) - 4;
+  /* We might have a suffix.  */
+  if (*p == 'i')
+    --p;
+  strcpy (p, alt);
+  if (!(prefixes & PREFIX_ADDR))
+    {
+      ++codep;
+      return;
+    }
+  used_prefixes |= PREFIX_ADDR;
+  switch (*codep++)
+    {
+    case 0xdf:
+      strcpy (op_out[1], names32[1]);
+      two_source_ops = 1;
+	  /* Fall through.  */
+    case 0xd8:
+    case 0xda:
+    case 0xdb:
+      *obufp++ = open_char;
+      if (address_mode == mode_64bit || (sizeflag & AFLAG))
+        alt = names32[0];
+      else
+        alt = names16[0];
+      strcpy (obufp, alt);
+      obufp += strlen (alt);
+      *obufp++ = close_char;
+      *obufp = '\0';
+      break;
+    }
+}
+
+static void
+INVLPG_Fixup (int bytemode, int sizeflag)
+{
+  const char *alt;
+
+  switch (*codep)
+    {
+    case 0xf8:
+      alt = "swapgs";
+      break;
+    case 0xf9:
+      alt = "rdtscp";
+      break;
+    default:
+      OP_M (bytemode, sizeflag);
+      return;
+    }
+  /* Override "invlpg".  */
+  strcpy (obuf + strlen (obuf) - 6, alt);
+  codep++;
+}
+
+static void
 BadOp (void)
 {
   /* Throw away prefixes and 1st. opcode byte.  */
   codep = insn_codep + 1;
   oappend ("(bad)");
 }
+
+static void
+VMX_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag)
+{
+  if (modrm.mod == 3
+      && modrm.reg == 0
+      && modrm.rm >=1
+      && modrm.rm <= 4)
+    {
+      /* Override "sgdt".  */
+      char *p = obuf + strlen (obuf) - 4;
+
+      /* We might have a suffix when disassembling with -Msuffix.  */
+      if (*p == 'g')
+	--p;
+
+      switch (modrm.rm)
+	{
+	case 1:
+	  strcpy (p, "vmcall");
+	  break;
+	case 2:
+	  strcpy (p, "vmlaunch");
+	  break;
+	case 3:
+	  strcpy (p, "vmresume");
+	  break;
+	case 4:
+	  strcpy (p, "vmxoff");
+	  break;
+	}
+
+      codep++;
+    }
+  else
+    OP_E (0, sizeflag);
+}
+
+static void
+OP_VMX (int bytemode, int sizeflag)
+{
+  used_prefixes |= (prefixes & (PREFIX_DATA | PREFIX_REPZ));
+  if (prefixes & PREFIX_DATA)
+    strcpy (obuf, "vmclear");
+  else if (prefixes & PREFIX_REPZ)
+    strcpy (obuf, "vmxon");
+  else
+    strcpy (obuf, "vmptrld");
+  OP_E (bytemode, sizeflag);
+}
+
+static void
+REP_Fixup (int bytemode, int sizeflag)
+{
+  /* The 0xf3 prefix should be displayed as "rep" for ins, outs, movs,
+     lods and stos.  */
+  size_t ilen = 0;
+
+  if (prefixes & PREFIX_REPZ)
+    switch (*insn_codep)
+      {
+      case 0x6e:	/* outsb */
+      case 0x6f:	/* outsw/outsl */
+      case 0xa4:	/* movsb */
+      case 0xa5:	/* movsw/movsl/movsq */
+	if (!intel_syntax)
+	  ilen = 5;
+	else
+	  ilen = 4;
+	break;
+      case 0xaa:	/* stosb */
+      case 0xab:	/* stosw/stosl/stosq */
+      case 0xac:	/* lodsb */
+      case 0xad:	/* lodsw/lodsl/lodsq */
+	if (!intel_syntax && (sizeflag & SUFFIX_ALWAYS))
+	  ilen = 5;
+	else
+	  ilen = 4;
+	break;
+      case 0x6c:	/* insb */
+      case 0x6d:	/* insl/insw */
+	if (!intel_syntax)
+	  ilen = 4;
+	else
+	  ilen = 3;
+	break;
+      default:
+	abort ();
+	break;
+      }
+
+  if (ilen != 0)
+    {
+      size_t olen;
+      char *p;
+
+      olen = strlen (obuf);
+      p = obuf + olen - ilen - 1 - 4;
+      /* Handle "repz [addr16|addr32]".  */
+      if ((prefixes & PREFIX_ADDR))
+	p -= 1 + 6;
+
+      memmove (p + 3, p + 4, olen - (p + 3 - obuf));
+    }
+
+  switch (bytemode)
+    {
+    case al_reg:
+    case eAX_reg:
+    case indir_dx_reg:
+      OP_IMREG (bytemode, sizeflag);
+      break;
+    case eDI_reg:
+      OP_ESreg (bytemode, sizeflag);
+      break;
+    case eSI_reg:
+      OP_DSreg (bytemode, sizeflag);
+      break;
+    default:
+      abort ();
+      break;
+    }
+}
+
+static void
+CMPXCHG8B_Fixup (int bytemode, int sizeflag)
+{
+  USED_REX (REX_W);
+  if (rex & REX_W)
+    {
+      /* Change cmpxchg8b to cmpxchg16b.  */
+      char *p = obuf + strlen (obuf) - 2;
+      strcpy (p, "16b");
+      bytemode = o_mode;
+    }
+  OP_M (bytemode, sizeflag);
+}
+
+static void
+XMM_Fixup (int reg, int sizeflag ATTRIBUTE_UNUSED)
+{
+  snprintf (scratchbuf, sizeof(scratchbuf), "%%xmm%d", reg);
+  oappend (scratchbuf + intel_syntax);
+}
+
+static void
+CRC32_Fixup (int bytemode, int sizeflag)
+{
+  /* Add proper suffix to "crc32".  */
+  char *p = obuf + strlen (obuf);
+
+  switch (bytemode)
+    {
+    case b_mode:
+      if (intel_syntax)
+	break;
+
+      *p++ = 'b';
+      break;
+    case v_mode:
+      if (intel_syntax)
+	break;
+
+      USED_REX (REX_W);
+      if (rex & REX_W)
+	*p++ = 'q';
+      else if (sizeflag & DFLAG)
+	*p++ = 'l';
+      else
+	*p++ = 'w';
+      used_prefixes |= (prefixes & PREFIX_DATA);
+      break;
+    default:
+      oappend (INTERNAL_DISASSEMBLER_ERROR);
+      break;
+    }
+  *p = '\0';
+
+  if (modrm.mod == 3)
+    {
+      int add;
+
+      /* Skip mod/rm byte.  */
+      MODRM_CHECK;
+      codep++;
+
+      USED_REX (REX_B);
+      add = (rex & REX_B) ? 8 : 0;
+      if (bytemode == b_mode)
+	{
+	  USED_REX (0);
+	  if (rex)
+	    oappend (names8rex[modrm.rm + add]);
+	  else
+	    oappend (names8[modrm.rm + add]);
+	}
+      else
+	{
+	  USED_REX (REX_W);
+	  if (rex & REX_W)
+	    oappend (names64[modrm.rm + add]);
+	  else if ((prefixes & PREFIX_DATA))
+	    oappend (names16[modrm.rm + add]);
+	  else
+	    oappend (names32[modrm.rm + add]);
+	}
+    }
+  else
+    OP_E (bytemode, sizeflag);
+}
diff --git a/iolooper-select.c b/iolooper-select.c
new file mode 100644
index 0000000..74a5a3a
--- /dev/null
+++ b/iolooper-select.c
@@ -0,0 +1,176 @@
+#include "iolooper.h"
+#include "qemu-common.h"
+
+/* An implementation of iolooper.h based on Unix select() */
+#ifdef _WIN32
+#  include <winsock2.h>
+#else
+#  include <sys/types.h>
+#  include <sys/select.h>
+#endif
+
+struct IoLooper {
+    fd_set   reads[1];
+    fd_set   writes[1];
+    fd_set   reads_result[1];
+    fd_set   writes_result[1];
+    int      max_fd;
+    int      max_fd_valid;
+};
+
+IoLooper*
+iolooper_new(void)
+{
+    IoLooper*  iol = qemu_malloc(sizeof(*iol));
+    iolooper_reset(iol);
+    return iol;
+}
+
+void
+iolooper_free( IoLooper*  iol )
+{
+    qemu_free(iol);
+}
+
+void
+iolooper_reset( IoLooper*  iol )
+{
+    FD_ZERO(iol->reads);
+    FD_ZERO(iol->writes);
+    iol->max_fd = -1;
+    iol->max_fd_valid = 1;
+}
+
+static void
+iolooper_add_fd( IoLooper*  iol, int fd )
+{
+    if (iol->max_fd_valid && fd > iol->max_fd) {
+        iol->max_fd = fd;
+    }
+}
+
+static void
+iolooper_del_fd( IoLooper*  iol, int fd )
+{
+    if (iol->max_fd_valid && fd == iol->max_fd)
+        iol->max_fd_valid = 0;
+}
+
+static int
+iolooper_fd_count( IoLooper*  iol )
+{
+    int  max_fd = iol->max_fd;
+    int  fd;
+
+    if (iol->max_fd_valid)
+        return max_fd + 1;
+
+    /* recompute max fd */
+    for (fd = 0; fd < FD_SETSIZE; fd++) {
+        if (!FD_ISSET(fd, iol->reads) && !FD_ISSET(fd, iol->writes))
+            continue;
+
+        max_fd = fd;
+    }
+    iol->max_fd       = max_fd;
+    iol->max_fd_valid = 1;
+
+    return max_fd + 1;
+}
+
+void
+iolooper_add_read( IoLooper*  iol, int  fd )
+{
+    if (fd >= 0) {
+        iolooper_add_fd(iol, fd);
+        FD_SET(fd, iol->reads);
+    }
+}
+
+void
+iolooper_add_write( IoLooper*  iol, int  fd )
+{
+    if (fd >= 0) {
+        iolooper_add_fd(iol, fd);
+        FD_SET(fd, iol->writes);
+    }
+}
+
+void
+iolooper_del_read( IoLooper*  iol, int  fd )
+{
+    if (fd >= 0) {
+        iolooper_del_fd(iol, fd);
+        FD_CLR(fd, iol->reads);
+    }
+}
+
+void
+iolooper_del_write( IoLooper*  iol, int  fd )
+{
+    if (fd >= 0) {
+        iolooper_del_fd(iol, fd);
+        FD_CLR(fd, iol->reads);
+    }
+}
+
+int
+iolooper_poll( IoLooper*  iol )
+{
+    int     count = iolooper_fd_count(iol);
+    int     ret;
+    fd_set  errs;
+
+    if (count == 0)
+        return 0;
+
+    FD_ZERO(&errs);
+
+    do {
+        struct timeval  tv;
+
+        tv.tv_sec = tv.tv_usec = 0;
+
+        iol->reads_result[0]  = iol->reads[0];
+        iol->writes_result[0] = iol->writes[0];
+
+        ret = select( count, iol->reads_result, iol->writes_result, &errs, &tv);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+int
+iolooper_wait( IoLooper*  iol, int64_t  duration )
+{
+    int     count = iolooper_fd_count(iol);
+    int     ret;
+    fd_set  errs;
+
+    if (count == 0)
+        return 0;
+
+    FD_ZERO(&errs);
+
+    do {
+        iol->reads_result[0]  = iol->reads[0];
+        iol->writes_result[0] = iol->writes[0];
+
+        ret = select( count, iol->reads_result, iol->writes_result, &errs, NULL);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+
+int
+iolooper_is_read( IoLooper*  iol, int  fd )
+{
+    return FD_ISSET(fd, iol->reads_result);
+}
+
+int
+iolooper_is_write( IoLooper*  iol, int  fd )
+{
+    return FD_ISSET(fd, iol->writes_result);
+}
diff --git a/iolooper.h b/iolooper.h
new file mode 100644
index 0000000..ead3583
--- /dev/null
+++ b/iolooper.h
@@ -0,0 +1,25 @@
+#ifndef IOLOOPER_H
+#define IOLOOPER_H
+
+#include <stdint.h>
+
+/* An IOLooper is an abstraction for select() */
+
+typedef struct IoLooper  IoLooper;
+
+IoLooper*  iolooper_new(void);
+void       iolooper_free( IoLooper*  iol );
+void       iolooper_reset( IoLooper*  iol );
+
+void       iolooper_add_read( IoLooper*  iol, int  fd );
+void       iolooper_add_write( IoLooper*  iol, int  fd );
+void       iolooper_del_read( IoLooper*  iol, int  fd );
+void       iolooper_del_write( IoLooper*  iol, int  fd );
+
+int        iolooper_poll( IoLooper*  iol );
+int        iolooper_wait( IoLooper*  iol, int64_t  duration );
+
+int        iolooper_is_read( IoLooper*  iol, int  fd );
+int        iolooper_is_write( IoLooper*  iol, int  fd );
+
+#endif /* IOLOOPER_H */
diff --git a/keymaps.c b/keymaps.c
index 15c40fa..23db4a0 100644
--- a/keymaps.c
+++ b/keymaps.c
@@ -22,34 +22,20 @@
  * THE SOFTWARE.
  */
 
-static int get_keysym(const char *name)
+#include "keymaps.h"
+#include "sysemu.h"
+
+static int get_keysym(const name2keysym_t *table,
+		      const char *name)
 {
-    name2keysym_t *p;
-    for(p = name2keysym; p->name != NULL; p++) {
+    const name2keysym_t *p;
+    for(p = table; p->name != NULL; p++) {
         if (!strcmp(p->name, name))
             return p->keysym;
     }
     return 0;
 }
 
-struct key_range {
-    int start;
-    int end;
-    struct key_range *next;
-};
-
-#define MAX_NORMAL_KEYCODE 512
-#define MAX_EXTRA_COUNT 256
-typedef struct {
-    uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
-    struct {
-	int keysym;
-	uint16_t keycode;
-    } keysym2keycode_extra[MAX_EXTRA_COUNT];
-    int extra_count;
-    struct key_range *keypad_range;
-    struct key_range *numlock_range;
-} kbd_layout_t;
 
 static void add_to_key_range(struct key_range **krp, int code) {
     struct key_range *kr;
@@ -67,34 +53,31 @@
     }
     if (kr == NULL) {
 	kr = qemu_mallocz(sizeof(*kr));
-	if (kr) {
-	    kr->start = kr->end = code;
-	    kr->next = *krp;
-	    *krp = kr;
-	}
+        kr->start = kr->end = code;
+        kr->next = *krp;
+        *krp = kr;
     }
 }
 
-static kbd_layout_t *parse_keyboard_layout(const char *language,
+static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
+					   const char *language,
 					   kbd_layout_t * k)
 {
     FILE *f;
-    char file_name[1024];
+    char * filename;
     char line[1024];
     int len;
 
-    snprintf(file_name, sizeof(file_name),
-             "%s/keymaps/%s", bios_dir, language);
+    filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
 
     if (!k)
 	k = qemu_mallocz(sizeof(kbd_layout_t));
-    if (!k)
-        return 0;
-    if (!(f = fopen(file_name, "r"))) {
+    if (!(filename && (f = fopen(filename, "r")))) {
 	fprintf(stderr,
-		"Could not read keymap file: '%s'\n", file_name);
+		"Could not read keymap file: '%s'\n", language);
 	return 0;
     }
+    qemu_free(filename);
     for(;;) {
 	if (fgets(line, 1024, f) == NULL)
             break;
@@ -106,7 +89,7 @@
 	if (!strncmp(line, "map ", 4))
 	    continue;
 	if (!strncmp(line, "include ", 8)) {
-	    parse_keyboard_layout(line + 8, k);
+	    parse_keyboard_layout(table, line + 8, k);
         } else {
 	    char *end_of_keysym = line;
 	    while (*end_of_keysym != 0 && *end_of_keysym != ' ')
@@ -114,7 +97,7 @@
 	    if (*end_of_keysym) {
 		int keysym;
 		*end_of_keysym = 0;
-		keysym = get_keysym(line);
+		keysym = get_keysym(table, line);
 		if (keysym == 0) {
                     //		    fprintf(stderr, "Warning: unknown keysym %s\n", line);
 		} else {
@@ -158,12 +141,14 @@
     return k;
 }
 
-static void *init_keyboard_layout(const char *language)
+
+void *init_keyboard_layout(const name2keysym_t *table, const char *language)
 {
-    return parse_keyboard_layout(language, 0);
+    return parse_keyboard_layout(table, language, 0);
 }
 
-static int keysym2scancode(void *kbd_layout, int keysym)
+
+int keysym2scancode(void *kbd_layout, int keysym)
 {
     kbd_layout_t *k = kbd_layout;
     if (keysym < MAX_NORMAL_KEYCODE) {
@@ -184,7 +169,7 @@
     return 0;
 }
 
-static inline int keycode_is_keypad(void *kbd_layout, int keycode)
+int keycode_is_keypad(void *kbd_layout, int keycode)
 {
     kbd_layout_t *k = kbd_layout;
     struct key_range *kr;
@@ -195,7 +180,7 @@
     return 0;
 }
 
-static inline int keysym_is_numlock(void *kbd_layout, int keysym)
+int keysym_is_numlock(void *kbd_layout, int keysym)
 {
     kbd_layout_t *k = kbd_layout;
     struct key_range *kr;
diff --git a/keymaps.h b/keymaps.h
new file mode 100644
index 0000000..17f6efd
--- /dev/null
+++ b/keymaps.h
@@ -0,0 +1,60 @@
+/*
+ * QEMU keysym to keycode conversion using rdesktop keymaps
+ *
+ * Copyright (c) 2004 Johannes Schindelin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef __QEMU_KEYMAPS_H__
+#define __QEMU_KEYMAPS_H__
+
+#include "qemu-common.h"
+
+typedef struct {
+	const char* name;
+	int keysym;
+} name2keysym_t;
+
+struct key_range {
+    int start;
+    int end;
+    struct key_range *next;
+};
+
+#define MAX_NORMAL_KEYCODE 512
+#define MAX_EXTRA_COUNT 256
+typedef struct {
+    uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
+    struct {
+	int keysym;
+	uint16_t keycode;
+    } keysym2keycode_extra[MAX_EXTRA_COUNT];
+    int extra_count;
+    struct key_range *keypad_range;
+    struct key_range *numlock_range;
+} kbd_layout_t;
+
+
+void *init_keyboard_layout(const name2keysym_t *table, const char *language);
+int keysym2scancode(void *kbd_layout, int keysym);
+int keycode_is_keypad(void *kbd_layout, int keycode);
+int keysym_is_numlock(void *kbd_layout, int keysym);
+
+#endif /* __QEMU_KEYMAPS_H__ */
diff --git a/kqemu.c b/kqemu.c
index 4783aa2..c27c6ae 100644
--- a/kqemu.c
+++ b/kqemu.c
@@ -15,11 +15,10 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include "config.h"
 #ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <winioctl.h>
 #else
@@ -42,11 +41,20 @@
 #include "exec-all.h"
 #include "qemu-common.h"
 
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
 
 #define DEBUG
 //#define PROFILE
 
+
+#ifdef DEBUG
+#  define LOG_INT(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
+#  define LOG_INT_STATE(env) log_cpu_state_mask(CPU_LOG_INT, (env), 0)
+#else
+#  define LOG_INT(...) do { } while (0)
+#  define LOG_INT_STATE(env) do { } while (0)
+#endif
+
 #include <unistd.h>
 #include <fcntl.h>
 #include "kqemu.h"
@@ -83,6 +91,8 @@
 uint8_t *modified_ram_pages_table;
 int qpi_io_memory;
 uint32_t kqemu_comm_base; /* physical address of the QPI communication page */
+ram_addr_t kqemu_phys_ram_size;
+uint8_t *kqemu_phys_ram_base;
 
 #define cpuid(index, eax, ebx, ecx, edx) \
   asm volatile ("cpuid" \
@@ -206,13 +216,14 @@
                                       sizeof(uint64_t));
     if (!modified_ram_pages)
         goto fail;
-    modified_ram_pages_table = qemu_mallocz(phys_ram_size >> TARGET_PAGE_BITS);
+    modified_ram_pages_table =
+        qemu_mallocz(kqemu_phys_ram_size >> TARGET_PAGE_BITS);
     if (!modified_ram_pages_table)
         goto fail;
 
     memset(&kinit, 0, sizeof(kinit)); /* set the paddings to zero */
-    kinit.ram_base = phys_ram_base;
-    kinit.ram_size = phys_ram_size;
+    kinit.ram_base = kqemu_phys_ram_base;
+    kinit.ram_size = kqemu_phys_ram_size;
     kinit.ram_dirty = phys_ram_dirty;
     kinit.pages_to_flush = pages_to_flush;
     kinit.ram_pages_to_update = ram_pages_to_update;
@@ -241,11 +252,7 @@
 
 void kqemu_flush_page(CPUState *env, target_ulong addr)
 {
-#if defined(DEBUG)
-    if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
-    }
-#endif
+    LOG_INT("kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
     if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH)
         nb_pages_to_flush = KQEMU_FLUSH_ALL;
     else
@@ -254,22 +261,14 @@
 
 void kqemu_flush(CPUState *env, int global)
 {
-#ifdef DEBUG
-    if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "kqemu_flush:\n");
-    }
-#endif
+    LOG_INT("kqemu_flush:\n");
     nb_pages_to_flush = KQEMU_FLUSH_ALL;
 }
 
 void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr)
 {
-#ifdef DEBUG
-    if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "kqemu_set_notdirty: addr=%08lx\n", 
+    LOG_INT("kqemu_set_notdirty: addr=%08lx\n", 
                 (unsigned long)ram_addr);
-    }
-#endif
     /* we only track transitions to dirty state */
     if (phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] != 0xff)
         return;
@@ -703,12 +702,8 @@
 #ifdef CONFIG_PROFILER
     ti = profile_getclock();
 #endif
-#ifdef DEBUG
-    if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "kqemu: cpu_exec: enter\n");
-        cpu_dump_state(env, logfile, fprintf, 0);
-    }
-#endif
+    LOG_INT("kqemu: cpu_exec: enter\n");
+    LOG_INT_STATE(env);
     for(i = 0; i < CPU_NB_REGS; i++)
         kenv->regs[i] = env->regs[i];
     kenv->eip = env->eip;
@@ -867,11 +862,7 @@
     else
         env->hflags &= ~HF_OSFXSR_MASK;
 
-#ifdef DEBUG
-    if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
-    }
-#endif
+    LOG_INT("kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
     if (ret == KQEMU_RET_SYSCALL) {
         /* syscall instruction */
         return do_syscall(env, kenv);
@@ -884,13 +875,8 @@
 #ifdef CONFIG_PROFILER
         kqemu_ret_int_count++;
 #endif
-#ifdef DEBUG
-        if (loglevel & CPU_LOG_INT) {
-            fprintf(logfile, "kqemu: interrupt v=%02x:\n",
-                    env->exception_index);
-            cpu_dump_state(env, logfile, fprintf, 0);
-        }
-#endif
+        LOG_INT("kqemu: interrupt v=%02x:\n", env->exception_index);
+        LOG_INT_STATE(env);
         return 1;
     } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
         env->exception_index = ret & 0xff;
@@ -900,23 +886,15 @@
 #ifdef CONFIG_PROFILER
         kqemu_ret_excp_count++;
 #endif
-#ifdef DEBUG
-        if (loglevel & CPU_LOG_INT) {
-            fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
+        LOG_INT("kqemu: exception v=%02x e=%04x:\n",
                     env->exception_index, env->error_code);
-            cpu_dump_state(env, logfile, fprintf, 0);
-        }
-#endif
+        LOG_INT_STATE(env);
         return 1;
     } else if (ret == KQEMU_RET_INTR) {
 #ifdef CONFIG_PROFILER
         kqemu_ret_intr_count++;
 #endif
-#ifdef DEBUG
-        if (loglevel & CPU_LOG_INT) {
-            cpu_dump_state(env, logfile, fprintf, 0);
-        }
-#endif
+        LOG_INT_STATE(env);
         return 0;
     } else if (ret == KQEMU_RET_SOFTMMU) {
 #ifdef CONFIG_PROFILER
@@ -925,11 +903,7 @@
             kqemu_record_pc(pc);
         }
 #endif
-#ifdef DEBUG
-        if (loglevel & CPU_LOG_INT) {
-            cpu_dump_state(env, logfile, fprintf, 0);
-        }
-#endif
+        LOG_INT_STATE(env);
         return 2;
     } else {
         cpu_dump_state(env, stderr, fprintf, 0);
@@ -1016,7 +990,7 @@
 static void qpi_init(void)
 {
     kqemu_comm_base = 0xff000000 | 1;
-    qpi_io_memory = cpu_register_io_memory(0, 
+    qpi_io_memory = cpu_register_io_memory(
                                            qpi_mem_read, 
                                            qpi_mem_write, NULL);
     cpu_register_physical_memory(kqemu_comm_base & ~0xfff, 
diff --git a/kvm.h b/kvm.h
new file mode 100644
index 0000000..560aef3
--- /dev/null
+++ b/kvm.h
@@ -0,0 +1,142 @@
+/*
+ * QEMU KVM support
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_KVM_H
+#define QEMU_KVM_H
+
+#include "config.h"
+#include "sys-queue.h"
+
+#ifdef CONFIG_KVM
+extern int kvm_allowed;
+
+#define kvm_enabled() (kvm_allowed)
+#else
+#define kvm_enabled() (0)
+#endif
+
+struct kvm_run;
+
+/* external API */
+
+int kvm_init(int smp_cpus);
+
+int kvm_init_vcpu(CPUState *env);
+int kvm_sync_vcpus(void);
+
+int kvm_cpu_exec(CPUState *env);
+
+void kvm_set_phys_mem(target_phys_addr_t start_addr,
+                      ram_addr_t size,
+                      ram_addr_t phys_offset);
+
+int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr);
+
+int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size);
+int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size);
+int kvm_set_migration_log(int enable);
+
+int kvm_has_sync_mmu(void);
+
+void kvm_setup_guest_memory(void *start, size_t size);
+
+int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
+int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size);
+
+int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type);
+int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type);
+void kvm_remove_all_breakpoints(CPUState *current_env);
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap);
+
+/* internal API */
+
+struct KVMState;
+typedef struct KVMState KVMState;
+
+int kvm_ioctl(KVMState *s, int type, ...);
+
+int kvm_vm_ioctl(KVMState *s, int type, ...);
+
+int kvm_vcpu_ioctl(CPUState *env, int type, ...);
+
+int kvm_get_mp_state(CPUState *env);
+int kvm_put_mp_state(CPUState *env);
+
+/* Arch specific hooks */
+
+int kvm_arch_post_run(CPUState *env, struct kvm_run *run);
+
+int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
+
+int kvm_arch_pre_run(CPUState *env, struct kvm_run *run);
+
+int kvm_arch_get_registers(CPUState *env);
+
+int kvm_arch_put_registers(CPUState *env);
+
+int kvm_arch_init(KVMState *s, int smp_cpus);
+
+int kvm_arch_init_vcpu(CPUState *env);
+
+struct kvm_guest_debug;
+struct kvm_debug_exit_arch;
+
+struct kvm_sw_breakpoint {
+    target_ulong pc;
+    target_ulong saved_insn;
+    int use_count;
+    TAILQ_ENTRY(kvm_sw_breakpoint) entry;
+};
+
+TAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint);
+
+int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info);
+
+struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
+                                                 target_ulong pc);
+
+int kvm_sw_breakpoints_active(CPUState *env);
+
+int kvm_arch_insert_sw_breakpoint(CPUState *current_env,
+                                  struct kvm_sw_breakpoint *bp);
+int kvm_arch_remove_sw_breakpoint(CPUState *current_env,
+                                  struct kvm_sw_breakpoint *bp);
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type);
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type);
+void kvm_arch_remove_all_hw_breakpoints(void);
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);
+
+int kvm_check_extension(KVMState *s, unsigned int extension);
+
+uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
+                                      int reg);
+
+/* generic hooks - to be moved/refactored once there are more users */
+
+static inline void cpu_synchronize_state(CPUState *env, int modified)
+{
+    if (kvm_enabled()) {
+        if (modified)
+            kvm_arch_put_registers(env);
+        else
+            kvm_arch_get_registers(env);
+    }
+}
+
+#endif
diff --git a/loader.c b/loader.c
index 84ed123..9350c54 100644
--- a/loader.c
+++ b/loader.c
@@ -20,13 +20,36 @@
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
+ *
+ * Gunzip functionality in this file is derived from u-boot:
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
+
 #include "qemu-common.h"
-#include "cpu.h"
 #include "disas.h"
 #include "sysemu.h"
 #include "uboot_image.h"
 
+#include <zlib.h>
+
 /* return the size or -1 if error */
 int get_image_size(const char *filename)
 {
@@ -67,11 +90,12 @@
     while (nbytes) {
 	want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
 	did = fread(buf, 1, want, f);
-	if (did != want) break;
 
 	cpu_physical_memory_write_rom(dst_addr, buf, did);
 	dst_addr += did;
 	nbytes -= did;
+	if (did != want)
+	    break;
     }
     return dst_addr - dst_begin;
 }
@@ -175,7 +199,6 @@
     (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :	\
      (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
 #define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
-#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
 #define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1))
 
 #define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
@@ -243,8 +266,6 @@
     if (lseek(fd, offset, SEEK_SET) < 0)
         return NULL;
     ptr = qemu_malloc(size);
-    if (!ptr)
-        return NULL;
     if (read(fd, ptr, size) != size) {
         qemu_free(ptr);
         return NULL;
@@ -283,7 +304,7 @@
 #include "elf_ops.h"
 
 /* return < 0 if error, otherwise the number of bytes loaded in memory */
-int load_elf(const char *filename, int64_t virt_to_phys_addend,
+int load_elf(const char *filename, int64_t address_offset,
              uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr)
 {
     int fd, data_order, host_data_order, must_swab, ret;
@@ -318,10 +339,10 @@
 
     lseek(fd, 0, SEEK_SET);
     if (e_ident[EI_CLASS] == ELFCLASS64) {
-        ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry,
+        ret = load_elf64(fd, address_offset, must_swab, pentry,
                          lowaddr, highaddr);
     } else {
-        ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry,
+        ret = load_elf32(fd, address_offset, must_swab, pentry,
                          lowaddr, highaddr);
     }
 
@@ -346,15 +367,101 @@
 #endif
 }
 
-/* Load a U-Boot image.  */
-int load_uboot(const char *filename, target_ulong *ep, int *is_linux)
-{
 
+#define ZALLOC_ALIGNMENT	16
+
+static void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p;
+
+    size *= items;
+    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+    p = qemu_malloc(size);
+
+    return (p);
+}
+
+static void zfree(void *x, void *addr)
+{
+    qemu_free(addr);
+}
+
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+#define DEFLATED	8
+
+/* This is the maximum in uboot, so if a uImage overflows this, it would
+ * overflow on real hardware too. */
+#define UBOOT_MAX_GUNZIP_BYTES 0x800000
+
+static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
+                      size_t srclen)
+{
+    z_stream s;
+    ssize_t dstbytes;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+        puts ("Error: Bad gzipped data\n");
+        return -1;
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+        i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+        while (src[i++] != 0)
+            ;
+    if ((flags & COMMENT) != 0)
+        while (src[i++] != 0)
+            ;
+    if ((flags & HEAD_CRC) != 0)
+        i += 2;
+    if (i >= srclen) {
+        puts ("Error: gunzip out of data in header\n");
+        return -1;
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+        printf ("Error: inflateInit2() returned %d\n", r);
+        return (-1);
+    }
+    s.next_in = src + i;
+    s.avail_in = srclen - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+        printf ("Error: inflate() returned %d\n", r);
+        return -1;
+    }
+    dstbytes = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+
+    return dstbytes;
+}
+
+/* Load a U-Boot image.  */
+int load_uimage(const char *filename, target_ulong *ep, target_ulong *loadaddr,
+                int *is_linux)
+{
     int fd;
     int size;
     uboot_image_header_t h;
     uboot_image_header_t *hdr = &h;
     uint8_t *data = NULL;
+    int ret = -1;
 
     fd = open(filename, O_RDONLY | O_BINARY);
     if (fd < 0)
@@ -362,28 +469,33 @@
 
     size = read(fd, hdr, sizeof(uboot_image_header_t));
     if (size < 0)
-        goto fail;
+        goto out;
 
     bswap_uboot_header(hdr);
 
     if (hdr->ih_magic != IH_MAGIC)
-        goto fail;
+        goto out;
 
-    /* TODO: Implement Multi-File images.  */
-    if (hdr->ih_type == IH_TYPE_MULTI) {
-        fprintf(stderr, "Unable to load multi-file u-boot images\n");
-        goto fail;
+    /* TODO: Implement other image types.  */
+    if (hdr->ih_type != IH_TYPE_KERNEL) {
+        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
+        goto out;
     }
 
-    /* TODO: Implement compressed images.  */
-    if (hdr->ih_comp != IH_COMP_NONE) {
-        fprintf(stderr, "Unable to load compressed u-boot images\n");
-        goto fail;
+    switch (hdr->ih_comp) {
+    case IH_COMP_NONE:
+    case IH_COMP_GZIP:
+        break;
+    default:
+        fprintf(stderr,
+                "Unable to load u-boot images with compression type %d\n",
+                hdr->ih_comp);
+        goto out;
     }
 
     /* TODO: Check CPU type.  */
     if (is_linux) {
-        if (hdr->ih_type == IH_TYPE_KERNEL && hdr->ih_os == IH_OS_LINUX)
+        if (hdr->ih_os == IH_OS_LINUX)
             *is_linux = 1;
         else
             *is_linux = 0;
@@ -391,22 +503,40 @@
 
     *ep = hdr->ih_ep;
     data = qemu_malloc(hdr->ih_size);
-    if (!data)
-        goto fail;
 
     if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
         fprintf(stderr, "Error reading file\n");
-        goto fail;
+        goto out;
+    }
+
+    if (hdr->ih_comp == IH_COMP_GZIP) {
+        uint8_t *compressed_data;
+        size_t max_bytes;
+        ssize_t bytes;
+
+        compressed_data = data;
+        max_bytes = UBOOT_MAX_GUNZIP_BYTES;
+        data = qemu_malloc(max_bytes);
+
+        bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
+        qemu_free(compressed_data);
+        if (bytes < 0) {
+            fprintf(stderr, "Unable to decompress gzipped image!\n");
+            goto out;
+        }
+        hdr->ih_size = bytes;
     }
 
     cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size);
 
-    return hdr->ih_size;
+    if (loadaddr)
+        *loadaddr = hdr->ih_load;
 
-fail:
+    ret = hdr->ih_size;
+
+out:
     if (data)
         qemu_free(data);
     close(fd);
-    return -1;
+    return ret;
 }
-
diff --git a/migration-dummy-android.c b/migration-dummy-android.c
new file mode 100755
index 0000000..6c81c82
--- /dev/null
+++ b/migration-dummy-android.c
@@ -0,0 +1,65 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "migration.h"
+#include "monitor.h"
+#include "buffered_file.h"
+#include "sysemu.h"
+#include "block.h"
+#include "qemu_socket.h"
+
+//#define DEBUG_MIGRATION
+
+#ifdef DEBUG_MIGRATION
+#define dprintf(fmt, ...) \
+    do { printf("migration: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+void qemu_start_incoming_migration(const char *uri)
+{
+    fprintf(stderr, "migration not supported !!\n");
+}
+
+void do_migrate(Monitor *mon, int detach, const char *uri)
+{
+	return;
+}
+
+void do_migrate_cancel(Monitor *mon)
+{
+	return;
+}
+
+void do_migrate_set_speed(Monitor *mon, const char *value)
+{
+	return;
+}
+
+uint64_t migrate_max_downtime(void)
+{
+    return 0;
+}
+
+void do_migrate_set_downtime(Monitor *mon, const char *value)
+{
+    return;
+}
+
+void do_info_migrate(Monitor *mon)
+{
+	monitor_printf(mon, "No Migration support\n");
+}
diff --git a/migration-exec.c b/migration-exec.c
new file mode 100644
index 0000000..0dd5aff
--- /dev/null
+++ b/migration-exec.c
@@ -0,0 +1,144 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ * Copyright Dell MessageOne 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Charles Duffy     <charles_duffy@messageone.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "buffered_file.h"
+#include "block.h"
+
+//#define DEBUG_MIGRATION_EXEC
+
+#ifdef DEBUG_MIGRATION_EXEC
+#define dprintf(fmt, ...) \
+    do { printf("migration-exec: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int file_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int file_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return write(s->fd, buf, size);
+}
+
+static int exec_close(FdMigrationState *s)
+{
+    dprintf("exec_close\n");
+    if (s->opaque) {
+        qemu_fclose(s->opaque);
+        s->opaque = NULL;
+        s->fd = -1;
+    }
+    return 0;
+}
+
+MigrationState *exec_start_outgoing_migration(const char *command,
+                                             int64_t bandwidth_limit,
+                                             int detach)
+{
+    FdMigrationState *s;
+    FILE *f;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    f = popen(command, "w");
+    if (f == NULL) {
+        dprintf("Unable to popen exec target\n");
+        goto err_after_alloc;
+    }
+
+    s->fd = fileno(f);
+    if (s->fd == -1) {
+        dprintf("Unable to retrieve file descriptor for popen'd handle\n");
+        goto err_after_open;
+    }
+
+    if (fcntl(s->fd, F_SETFD, O_NONBLOCK) == -1) {
+        dprintf("Unable to set nonblocking mode on file descriptor\n");
+        goto err_after_open;
+    }
+
+    s->opaque = qemu_popen(f, "w");
+
+    s->close = exec_close;
+    s->get_error = file_errno;
+    s->write = file_write;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon_resume = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+
+    if (!detach)
+        migrate_fd_monitor_suspend(s);
+
+    migrate_fd_connect(s);
+    return &s->mig_state;
+
+err_after_open:
+    pclose(f);
+err_after_alloc:
+    qemu_free(s);
+    return NULL;
+}
+
+static void exec_accept_incoming_migration(void *opaque)
+{
+    QEMUFile *f = opaque;
+    int ret;
+
+    vm_stop(0); /* just in case */
+    ret = qemu_loadvm_state(f);
+    if (ret < 0) {
+        fprintf(stderr, "load of migration failed\n");
+        goto err;
+    }
+    qemu_announce_self();
+    dprintf("successfully loaded vm state\n");
+    /* we've successfully migrated, close the fd */
+    qemu_set_fd_handler2(qemu_popen_fd(f), NULL, NULL, NULL, NULL);
+    vm_start();
+
+err:
+    qemu_fclose(f);
+}
+
+int exec_start_incoming_migration(const char *command)
+{
+    QEMUFile *f;
+
+    dprintf("Attempting to start an incoming migration\n");
+    f = qemu_popen_cmd(command, "r");
+    if(f == NULL) {
+        dprintf("Unable to apply qemu wrapper to popen file\n");
+        return -errno;
+    }
+
+    qemu_set_fd_handler2(qemu_popen_fd(f), NULL,
+			 exec_accept_incoming_migration, NULL,
+			 (void *)(unsigned long)f);
+
+    return 0;
+}
diff --git a/migration-tcp-android.c b/migration-tcp-android.c
new file mode 100644
index 0000000..51e1b78
--- /dev/null
+++ b/migration-tcp-android.c
@@ -0,0 +1,197 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "buffered_file.h"
+#include "block.h"
+
+//#define DEBUG_MIGRATION_TCP
+
+#ifdef DEBUG_MIGRATION_TCP
+#define dprintf(fmt, ...) \
+    do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int socket_errno(FdMigrationState *s)
+{
+    return errno;
+}
+
+static int socket_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return socket_send(s->fd, buf, size);
+}
+
+static int tcp_close(FdMigrationState *s)
+{
+    dprintf("tcp_close\n");
+    if (s->fd != -1) {
+        socket_close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+
+static void tcp_wait_for_connect(void *opaque)
+{
+    FdMigrationState *s = opaque;
+    int ret;
+
+    dprintf("connect completed\n");
+    ret = socket_get_error(s->fd);
+    if (ret < 0) {
+        dprintf("error connecting %d\n", val);
+        migrate_fd_error(s);
+        return;
+    }
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+
+    migrate_fd_connect(s);
+}
+
+MigrationState *tcp_start_outgoing_migration(const char *host_port,
+                                             int64_t bandwidth_limit,
+                                             int detach)
+{
+    SockAddress  addr;
+    FdMigrationState *s;
+    int ret;
+
+    if (parse_host_port(&addr, host_port) < 0)
+        return NULL;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->get_error = socket_errno;
+    s->write = socket_write;
+    s->close = tcp_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon_resume = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+    s->fd = socket_create_inet(SOCKET_STREAM);
+    if (s->fd == -1) {
+        qemu_free(s);
+        return NULL;
+    }
+
+    socket_set_nonblock(s->fd);
+
+    if (!detach)
+        migrate_fd_monitor_suspend(s);
+
+    do {
+        ret = socket_connect(s->fd, &addr);
+        if (ret == -1)
+            ret = -(s->get_error(s));
+
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+            qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
+    } while (ret == -EINTR);
+
+    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+        dprintf("connect failed\n");
+        socket_close(s->fd);
+        qemu_free(s);
+        return NULL;
+    } else if (ret >= 0)
+        migrate_fd_connect(s);
+
+    return &s->mig_state;
+}
+
+static void tcp_accept_incoming_migration(void *opaque)
+{
+    SockAddress  addr;
+    int s = (unsigned long)opaque;
+    QEMUFile *f;
+    int c, ret;
+
+    c = socket_accept(s, &addr);
+    dprintf("accepted migration\n");
+
+    if (c == -1) {
+        fprintf(stderr, "could not accept migration connection\n");
+        return;
+    }
+
+    f = qemu_fopen_socket(c);
+    if (f == NULL) {
+        fprintf(stderr, "could not qemu_fopen socket\n");
+        goto out;
+    }
+
+    vm_stop(0); /* just in case */
+    ret = qemu_loadvm_state(f);
+    if (ret < 0) {
+        fprintf(stderr, "load of migration failed\n");
+        goto out_fopen;
+    }
+    qemu_announce_self();
+    dprintf("successfully loaded vm state\n");
+
+    /* we've successfully migrated, close the server socket */
+    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
+    socket_close(s);
+
+    vm_start();
+
+out_fopen:
+    qemu_fclose(f);
+out:
+    socket_close(c);
+}
+
+int tcp_start_incoming_migration(const char *host_port)
+{
+    SockAddress addr;
+    int s;
+
+    if (parse_host_port(&addr, host_port) < 0) {
+        fprintf(stderr, "invalid host/port combination: %s\n", host_port);
+        return -EINVAL;
+    }
+
+    s = socket_create_inet(SOCKET_STREAM);
+    if (s == -1)
+        return -socket_error();
+
+    socket_set_xreuseaddr(s);
+
+    if (socket_bind(s, &addr) == -1)
+        goto err;
+
+    if (socket_listen(s, 1) == -1)
+        goto err;
+
+    qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
+                         (void *)(unsigned long)s);
+
+    return 0;
+
+err:
+    socket_close(s);
+    return -socket_error();
+}
diff --git a/migration-tcp.c b/migration-tcp.c
new file mode 100644
index 0000000..1f4358e
--- /dev/null
+++ b/migration-tcp.c
@@ -0,0 +1,211 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "buffered_file.h"
+#include "block.h"
+
+//#define DEBUG_MIGRATION_TCP
+
+#ifdef DEBUG_MIGRATION_TCP
+#define dprintf(fmt, ...) \
+    do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+static int socket_errno(FdMigrationState *s)
+{
+    return socket_error();
+}
+
+static int socket_write(FdMigrationState *s, const void * buf, size_t size)
+{
+    return send(s->fd, buf, size, 0);
+}
+
+static int tcp_close(FdMigrationState *s)
+{
+    dprintf("tcp_close\n");
+    if (s->fd != -1) {
+        close(s->fd);
+        s->fd = -1;
+    }
+    return 0;
+}
+
+
+static void tcp_wait_for_connect(void *opaque)
+{
+    FdMigrationState *s = opaque;
+    int val, ret;
+    socklen_t valsize = sizeof(val);
+
+    dprintf("connect completed\n");
+    do {
+        ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
+    } while (ret == -1 && (s->get_error(s)) == EINTR);
+
+    if (ret < 0) {
+        migrate_fd_error(s);
+        return;
+    }
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+
+    if (val == 0)
+        migrate_fd_connect(s);
+    else {
+        dprintf("error connecting %d\n", val);
+        migrate_fd_error(s);
+    }
+}
+
+MigrationState *tcp_start_outgoing_migration(const char *host_port,
+                                             int64_t bandwidth_limit,
+                                             int detach)
+{
+    struct sockaddr_in addr;
+    FdMigrationState *s;
+    int ret;
+
+    if (parse_host_port(&addr, host_port) < 0)
+        return NULL;
+
+    s = qemu_mallocz(sizeof(*s));
+
+    s->get_error = socket_errno;
+    s->write = socket_write;
+    s->close = tcp_close;
+    s->mig_state.cancel = migrate_fd_cancel;
+    s->mig_state.get_status = migrate_fd_get_status;
+    s->mig_state.release = migrate_fd_release;
+
+    s->state = MIG_STATE_ACTIVE;
+    s->mon_resume = NULL;
+    s->bandwidth_limit = bandwidth_limit;
+    s->fd = socket(PF_INET, SOCK_STREAM, 0);
+    if (s->fd == -1) {
+        qemu_free(s);
+        return NULL;
+    }
+
+    socket_set_nonblock(s->fd);
+
+    if (!detach)
+        migrate_fd_monitor_suspend(s);
+
+    do {
+        ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
+        if (ret == -1)
+            ret = -(s->get_error(s));
+
+        if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
+            qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
+    } while (ret == -EINTR);
+
+    if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
+        dprintf("connect failed\n");
+        close(s->fd);
+        qemu_free(s);
+        return NULL;
+    } else if (ret >= 0)
+        migrate_fd_connect(s);
+
+    return &s->mig_state;
+}
+
+static void tcp_accept_incoming_migration(void *opaque)
+{
+    struct sockaddr_in addr;
+    socklen_t addrlen = sizeof(addr);
+    int s = (unsigned long)opaque;
+    QEMUFile *f;
+    int c, ret;
+
+    do {
+        c = accept(s, (struct sockaddr *)&addr, &addrlen);
+    } while (c == -1 && socket_error() == EINTR);
+
+    dprintf("accepted migration\n");
+
+    if (c == -1) {
+        fprintf(stderr, "could not accept migration connection\n");
+        return;
+    }
+
+    f = qemu_fopen_socket(c);
+    if (f == NULL) {
+        fprintf(stderr, "could not qemu_fopen socket\n");
+        goto out;
+    }
+
+    vm_stop(0); /* just in case */
+    ret = qemu_loadvm_state(f);
+    if (ret < 0) {
+        fprintf(stderr, "load of migration failed\n");
+        goto out_fopen;
+    }
+    qemu_announce_self();
+    dprintf("successfully loaded vm state\n");
+
+    /* we've successfully migrated, close the server socket */
+    qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
+    close(s);
+
+    vm_start();
+
+out_fopen:
+    qemu_fclose(f);
+out:
+    close(c);
+}
+
+int tcp_start_incoming_migration(const char *host_port)
+{
+    struct sockaddr_in addr;
+    int val;
+    int s;
+
+    if (parse_host_port(&addr, host_port) < 0) {
+        fprintf(stderr, "invalid host/port combination: %s\n", host_port);
+        return -EINVAL;
+    }
+
+    s = socket(PF_INET, SOCK_STREAM, 0);
+    if (s == -1)
+        return -socket_error();
+
+    val = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+        goto err;
+
+    if (listen(s, 1) == -1)
+        goto err;
+
+    qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
+                         (void *)(unsigned long)s);
+
+    return 0;
+
+err:
+    close(s);
+    return -socket_error();
+}
diff --git a/migration.c b/migration.c
new file mode 100644
index 0000000..190b37e
--- /dev/null
+++ b/migration.c
@@ -0,0 +1,337 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "migration.h"
+#include "monitor.h"
+#include "buffered_file.h"
+#include "sysemu.h"
+#include "block.h"
+#include "qemu_socket.h"
+
+//#define DEBUG_MIGRATION
+
+#ifdef DEBUG_MIGRATION
+#define dprintf(fmt, ...) \
+    do { printf("migration: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+/* Migration speed throttling */
+static uint32_t max_throttle = (32 << 20);
+
+static MigrationState *current_migration;
+
+void qemu_start_incoming_migration(const char *uri)
+{
+    const char *p;
+
+    if (strstart(uri, "tcp:", &p))
+        tcp_start_incoming_migration(p);
+#if !defined(WIN32)
+    else if (strstart(uri, "exec:", &p))
+        exec_start_incoming_migration(p);
+#endif
+    else
+        fprintf(stderr, "unknown migration protocol: %s\n", uri);
+}
+
+void do_migrate(Monitor *mon, int detach, const char *uri)
+{
+    MigrationState *s = NULL;
+    const char *p;
+
+    if (strstart(uri, "tcp:", &p))
+        s = tcp_start_outgoing_migration(p, max_throttle, detach);
+#if !defined(WIN32)
+    else if (strstart(uri, "exec:", &p))
+        s = exec_start_outgoing_migration(p, max_throttle, detach);
+#endif
+    else
+        monitor_printf(mon, "unknown migration protocol: %s\n", uri);
+
+    if (s == NULL)
+        monitor_printf(mon, "migration failed\n");
+    else {
+        if (current_migration)
+            current_migration->release(current_migration);
+
+        current_migration = s;
+    }
+}
+
+void do_migrate_cancel(Monitor *mon)
+{
+    MigrationState *s = current_migration;
+
+    if (s)
+        s->cancel(s);
+}
+
+void do_migrate_set_speed(Monitor *mon, const char *value)
+{
+    double d;
+    char *ptr;
+    FdMigrationState *s;
+
+    d = strtod(value, &ptr);
+    switch (*ptr) {
+    case 'G': case 'g':
+        d *= 1024;
+    case 'M': case 'm':
+        d *= 1024;
+    case 'K': case 'k':
+        d *= 1024;
+    default:
+        break;
+    }
+
+    max_throttle = (uint32_t)d;
+    s = migrate_to_fms(current_migration);
+
+    if (s) {
+        qemu_file_set_rate_limit(s->file, max_throttle);
+    }
+    
+}
+
+/* amount of nanoseconds we are willing to wait for migration to be down.
+ * the choice of nanoseconds is because it is the maximum resolution that
+ * get_clock() can achieve. It is an internal measure. All user-visible
+ * units must be in seconds */
+static uint64_t max_downtime = 30000000;
+
+uint64_t migrate_max_downtime(void)
+{
+    return max_downtime;
+}
+
+void do_migrate_set_downtime(Monitor *mon, const char *value)
+{
+    char *ptr;
+    double d;
+
+    d = strtod(value, &ptr);
+    if (!strcmp(ptr,"ms")) {
+        d *= 1000000;
+    } else if (!strcmp(ptr,"us")) {
+        d *= 1000;
+    } else if (!strcmp(ptr,"ns")) {
+    } else {
+        /* all else considered to be seconds */
+        d *= 1000000000;
+    }
+
+    max_downtime = (uint64_t)d;
+}
+
+void do_info_migrate(Monitor *mon)
+{
+    MigrationState *s = current_migration;
+
+    if (s) {
+        monitor_printf(mon, "Migration status: ");
+        switch (s->get_status(s)) {
+        case MIG_STATE_ACTIVE:
+            monitor_printf(mon, "active\n");
+            monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n", ram_bytes_transferred() >> 10);
+            monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n", ram_bytes_remaining() >> 10);
+            monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n", ram_bytes_total() >> 10);
+            break;
+        case MIG_STATE_COMPLETED:
+            monitor_printf(mon, "completed\n");
+            break;
+        case MIG_STATE_ERROR:
+            monitor_printf(mon, "failed\n");
+            break;
+        case MIG_STATE_CANCELLED:
+            monitor_printf(mon, "cancelled\n");
+            break;
+        }
+    }
+}
+
+/* shared migration helpers */
+
+void migrate_fd_monitor_suspend(FdMigrationState *s)
+{
+    s->mon_resume = cur_mon;
+    if (monitor_suspend(cur_mon) == 0)
+        dprintf("suspending monitor\n");
+    else
+        monitor_printf(cur_mon, "terminal does not allow synchronous "
+                       "migration, continuing detached\n");
+}
+
+void migrate_fd_error(FdMigrationState *s)
+{
+    dprintf("setting error state\n");
+    s->state = MIG_STATE_ERROR;
+    migrate_fd_cleanup(s);
+}
+
+void migrate_fd_cleanup(FdMigrationState *s)
+{
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+
+    if (s->file) {
+        dprintf("closing file\n");
+        qemu_fclose(s->file);
+    }
+
+    if (s->fd != -1)
+        close(s->fd);
+
+    /* Don't resume monitor until we've flushed all of the buffers */
+    if (s->mon_resume)
+        monitor_resume(s->mon_resume);
+
+    s->fd = -1;
+}
+
+void migrate_fd_put_notify(void *opaque)
+{
+    FdMigrationState *s = opaque;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    qemu_file_put_notify(s->file);
+}
+
+ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size)
+{
+    FdMigrationState *s = opaque;
+    ssize_t ret;
+
+    do {
+        ret = s->write(s, data, size);
+    } while (ret == -1 && ((s->get_error(s)) == EINTR));
+
+    if (ret == -1)
+        ret = -(s->get_error(s));
+
+    if (ret == -EAGAIN)
+        qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s);
+
+    return ret;
+}
+
+void migrate_fd_connect(FdMigrationState *s)
+{
+    int ret;
+
+    s->file = qemu_fopen_ops_buffered(s,
+                                      s->bandwidth_limit,
+                                      migrate_fd_put_buffer,
+                                      migrate_fd_put_ready,
+                                      migrate_fd_wait_for_unfreeze,
+                                      migrate_fd_close);
+
+    dprintf("beginning savevm\n");
+    ret = qemu_savevm_state_begin(s->file);
+    if (ret < 0) {
+        dprintf("failed, %d\n", ret);
+        migrate_fd_error(s);
+        return;
+    }
+
+    migrate_fd_put_ready(s);
+}
+
+void migrate_fd_put_ready(void *opaque)
+{
+    FdMigrationState *s = opaque;
+
+    if (s->state != MIG_STATE_ACTIVE) {
+        dprintf("put_ready returning because of non-active state\n");
+        return;
+    }
+
+    dprintf("iterate\n");
+    if (qemu_savevm_state_iterate(s->file) == 1) {
+        int state;
+        dprintf("done iterating\n");
+        vm_stop(0);
+
+        bdrv_flush_all();
+        if ((qemu_savevm_state_complete(s->file)) < 0) {
+            vm_start();
+            state = MIG_STATE_ERROR;
+        } else {
+            state = MIG_STATE_COMPLETED;
+        }
+        migrate_fd_cleanup(s);
+        s->state = state;
+    }
+}
+
+int migrate_fd_get_status(MigrationState *mig_state)
+{
+    FdMigrationState *s = migrate_to_fms(mig_state);
+    return s->state;
+}
+
+void migrate_fd_cancel(MigrationState *mig_state)
+{
+    FdMigrationState *s = migrate_to_fms(mig_state);
+
+    if (s->state != MIG_STATE_ACTIVE)
+        return;
+
+    dprintf("cancelling migration\n");
+
+    s->state = MIG_STATE_CANCELLED;
+
+    migrate_fd_cleanup(s);
+}
+
+void migrate_fd_release(MigrationState *mig_state)
+{
+    FdMigrationState *s = migrate_to_fms(mig_state);
+
+    dprintf("releasing state\n");
+   
+    if (s->state == MIG_STATE_ACTIVE) {
+        s->state = MIG_STATE_CANCELLED;
+        migrate_fd_cleanup(s);
+    }
+    free(s);
+}
+
+void migrate_fd_wait_for_unfreeze(void *opaque)
+{
+    FdMigrationState *s = opaque;
+    int ret;
+
+    dprintf("wait for unfreeze\n");
+    if (s->state != MIG_STATE_ACTIVE)
+        return;
+
+    do {
+        fd_set wfds;
+
+        FD_ZERO(&wfds);
+        FD_SET(s->fd, &wfds);
+
+        ret = select(s->fd + 1, NULL, &wfds, NULL, NULL);
+    } while (ret == -1 && (s->get_error(s)) == EINTR);
+}
+
+int migrate_fd_close(void *opaque)
+{
+    FdMigrationState *s = opaque;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    return s->close(s);
+}
diff --git a/migration.h b/migration.h
new file mode 100644
index 0000000..37c7f8e
--- /dev/null
+++ b/migration.h
@@ -0,0 +1,105 @@
+/*
+ * QEMU live migration
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_MIGRATION_H
+#define QEMU_MIGRATION_H
+
+#include "qemu-common.h"
+
+#define MIG_STATE_ERROR		-1
+#define MIG_STATE_COMPLETED	0
+#define MIG_STATE_CANCELLED	1
+#define MIG_STATE_ACTIVE	2
+
+typedef struct MigrationState MigrationState;
+
+struct MigrationState
+{
+    /* FIXME: add more accessors to print migration info */
+    void (*cancel)(MigrationState *s);
+    int (*get_status)(MigrationState *s);
+    void (*release)(MigrationState *s);
+};
+
+typedef struct FdMigrationState FdMigrationState;
+
+struct FdMigrationState
+{
+    MigrationState mig_state;
+    int64_t bandwidth_limit;
+    QEMUFile *file;
+    int fd;
+    Monitor *mon_resume;
+    int state;
+    int (*get_error)(struct FdMigrationState*);
+    int (*close)(struct FdMigrationState*);
+    int (*write)(struct FdMigrationState*, const void *, size_t);
+    void *opaque;
+};
+
+void qemu_start_incoming_migration(const char *uri);
+
+void do_migrate(Monitor *mon, int detach, const char *uri);
+
+void do_migrate_cancel(Monitor *mon);
+
+void do_migrate_set_speed(Monitor *mon, const char *value);
+
+uint64_t migrate_max_downtime(void);
+
+void do_migrate_set_downtime(Monitor *mon, const char *value);
+
+void do_info_migrate(Monitor *mon);
+
+int exec_start_incoming_migration(const char *host_port);
+
+MigrationState *exec_start_outgoing_migration(const char *host_port,
+					     int64_t bandwidth_limit,
+					     int detach);
+
+int tcp_start_incoming_migration(const char *host_port);
+
+MigrationState *tcp_start_outgoing_migration(const char *host_port,
+					     int64_t bandwidth_limit,
+					     int detach);
+
+void migrate_fd_monitor_suspend(FdMigrationState *s);
+
+void migrate_fd_error(FdMigrationState *s);
+
+void migrate_fd_cleanup(FdMigrationState *s);
+
+void migrate_fd_put_notify(void *opaque);
+
+ssize_t migrate_fd_put_buffer(void *opaque, const void *data, size_t size);
+
+void migrate_fd_connect(FdMigrationState *s);
+
+void migrate_fd_put_ready(void *opaque);
+
+int migrate_fd_get_status(MigrationState *mig_state);
+
+void migrate_fd_cancel(MigrationState *mig_state);
+
+void migrate_fd_release(MigrationState *mig_state);
+
+void migrate_fd_wait_for_unfreeze(void *opaque);
+
+int migrate_fd_close(void *opaque);
+
+static inline FdMigrationState *migrate_to_fms(MigrationState *mig_state)
+{
+    return container_of(mig_state, FdMigrationState, mig_state);
+}
+
+#endif
diff --git a/module.c b/module.c
new file mode 100644
index 0000000..3729283
--- /dev/null
+++ b/module.c
@@ -0,0 +1,80 @@
+/*
+ * QEMU Module Infrastructure
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "sys-queue.h"
+#include "module.h"
+
+typedef struct ModuleEntry
+{
+    module_init_type type;
+    void (*init)(void);
+    TAILQ_ENTRY(ModuleEntry) node;
+} ModuleEntry;
+
+typedef TAILQ_HEAD(, ModuleEntry) ModuleTypeList;
+
+static ModuleTypeList init_type_list[MODULE_INIT_MAX];
+
+static void init_types(void)
+{
+    static int inited;
+    int i;
+
+    if (inited) {
+        return;
+    }
+
+    for (i = 0; i < MODULE_INIT_MAX; i++) {
+        TAILQ_INIT(&init_type_list[i]);
+    }
+
+    inited = 1;
+}
+
+
+static ModuleTypeList *find_type(module_init_type type)
+{
+    ModuleTypeList *l;
+
+    init_types();
+
+    l = &init_type_list[type];
+
+    return l;
+}
+
+void register_module_init(void (*fn)(void), module_init_type type)
+{
+    ModuleEntry *e;
+    ModuleTypeList *l;
+
+    e = qemu_mallocz(sizeof(*e));
+    e->init = fn;
+
+    l = find_type(type);
+
+    TAILQ_INSERT_TAIL(l, e, node);
+}
+
+void module_call_init(module_init_type type)
+{
+    ModuleTypeList *l;
+    ModuleEntry *e;
+
+    l = find_type(type);
+
+    TAILQ_FOREACH(e, l, node) {
+        e->init();
+    }
+}
diff --git a/module.h b/module.h
new file mode 100644
index 0000000..9263f1c
--- /dev/null
+++ b/module.h
@@ -0,0 +1,38 @@
+/*
+ * QEMU Module Infrastructure
+ *
+ * Copyright IBM, Corp. 2009
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_MODULE_H
+#define QEMU_MODULE_H
+
+/* This should not be used directly.  Use block_init etc. instead.  */
+#define module_init(function, type)                                         \
+static void __attribute__((constructor)) do_qemu_init_ ## function(void) {  \
+    register_module_init(function, type);                                   \
+}
+
+typedef enum {
+    MODULE_INIT_BLOCK,
+    MODULE_INIT_DEVICE,
+    MODULE_INIT_MACHINE,
+    MODULE_INIT_MAX
+} module_init_type;
+
+#define block_init(function) module_init(function, MODULE_INIT_BLOCK)
+#define device_init(function) module_init(function, MODULE_INIT_DEVICE)
+#define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
+
+void register_module_init(void (*fn)(void), module_init_type type);
+
+void module_call_init(module_init_type type);
+
+#endif
diff --git a/monitor.c b/monitor.c
index f0f38a7..6b45f6c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -21,30 +21,33 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <dirent.h>
 #include "hw/hw.h"
+#include "hw/qdev.h"
 #include "hw/usb.h"
-
+#include "hw/pcmcia.h"
 #include "hw/pc.h"
 #include "hw/pci.h"
+#include "hw/watchdog.h"
 #include "gdbstub.h"
 #include "net.h"
 #include "qemu-char.h"
 #include "sysemu.h"
+#include "monitor.h"
+#include "readline.h"
 #include "console.h"
 #include "block.h"
 #include "audio/audio.h"
 #include "disas.h"
-#include "cpu-defs.h"
-#include <dirent.h>
+#include "balloon.h"
 #include "qemu-timer.h"
+#include "migration.h"
+#include "kvm.h"
+#include "acl.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
 
-#ifndef offsetof
-#define offsetof(type, field) ((size_t) &((type *)0)->field)
-#endif
-
 /*
  * Supported types:
  *
@@ -59,95 +62,125 @@
  *
  */
 
-typedef struct term_cmd_t {
+typedef struct mon_cmd_t {
     const char *name;
     const char *args_type;
     void *handler;
     const char *params;
     const char *help;
-} term_cmd_t;
+} mon_cmd_t;
 
-#define MAX_MON 4
-static CharDriverState *monitor_hd[MAX_MON];
-static int hide_banner;
+struct Monitor {
+    CharDriverState *chr;
+    int flags;
+    int suspend_cnt;
+    uint8_t outbuf[1024];
+    int outbuf_index;
+    ReadLineState *rs;
+    CPUState *mon_cpu;
+    BlockDriverCompletionFunc *password_completion_cb;
+    void *password_opaque;
+    LIST_ENTRY(Monitor) entry;
+};
 
-static term_cmd_t term_cmds[];
-static term_cmd_t info_cmds[];
+static LIST_HEAD(mon_list, Monitor) mon_list;
 
-static uint8_t term_outbuf[1024];
-static int term_outbuf_index;
+static const mon_cmd_t mon_cmds[];
+static const mon_cmd_t info_cmds[];
 
-static void monitor_start_input(void);
+Monitor *cur_mon = NULL;
 
-CPUState *mon_cpu = NULL;
+static void monitor_command_cb(Monitor *mon, const char *cmdline,
+                               void *opaque);
 
-void term_flush(void)
+static void monitor_read_command(Monitor *mon, int show_prompt)
 {
-    int i;
-    if (term_outbuf_index > 0) {
-        for (i = 0; i < MAX_MON; i++)
-            if (monitor_hd[i] && monitor_hd[i]->focus == 0)
-                qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index);
-        term_outbuf_index = 0;
+    readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL);
+    if (show_prompt)
+        readline_show_prompt(mon->rs);
+}
+
+static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+                                 void *opaque)
+{
+    if (mon->rs) {
+        readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
+        /* prompt is printed on return from the command handler */
+        return 0;
+    } else {
+        monitor_printf(mon, "terminal does not support password prompting\n");
+        return -ENOTTY;
+    }
+}
+
+void monitor_flush(Monitor *mon)
+{
+    if (mon && mon->outbuf_index != 0 && mon->chr->focus == 0) {
+        qemu_chr_write(mon->chr, mon->outbuf, mon->outbuf_index);
+        mon->outbuf_index = 0;
     }
 }
 
 /* flush at every end of line or if the buffer is full */
-void term_puts(const char *str)
+static void monitor_puts(Monitor *mon, const char *str)
 {
     char c;
+
+    if (!mon)
+        return;
+
     for(;;) {
         c = *str++;
         if (c == '\0')
             break;
         if (c == '\n')
-            term_outbuf[term_outbuf_index++] = '\r';
-        term_outbuf[term_outbuf_index++] = c;
-        if (term_outbuf_index >= (sizeof(term_outbuf) - 1) ||
-            c == '\n')
-            term_flush();
+            mon->outbuf[mon->outbuf_index++] = '\r';
+        mon->outbuf[mon->outbuf_index++] = c;
+        if (mon->outbuf_index >= (sizeof(mon->outbuf) - 1)
+            || c == '\n')
+            monitor_flush(mon);
     }
 }
 
-void term_vprintf(const char *fmt, va_list ap)
+void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 {
     char buf[4096];
     vsnprintf(buf, sizeof(buf), fmt, ap);
-    term_puts(buf);
+    monitor_puts(mon, buf);
 }
 
-void term_printf(const char *fmt, ...)
+void monitor_printf(Monitor *mon, const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
-    term_vprintf(fmt, ap);
+    monitor_vprintf(mon, fmt, ap);
     va_end(ap);
 }
 
-void term_print_filename(const char *filename)
+void monitor_print_filename(Monitor *mon, const char *filename)
 {
     int i;
 
     for (i = 0; filename[i]; i++) {
-	switch (filename[i]) {
-	case ' ':
-	case '"':
-	case '\\':
-	    term_printf("\\%c", filename[i]);
-	    break;
-	case '\t':
-	    term_printf("\\t");
-	    break;
-	case '\r':
-	    term_printf("\\r");
-	    break;
-	case '\n':
-	    term_printf("\\n");
-	    break;
-	default:
-	    term_printf("%c", filename[i]);
-	    break;
-	}
+        switch (filename[i]) {
+        case ' ':
+        case '"':
+        case '\\':
+            monitor_printf(mon, "\\%c", filename[i]);
+            break;
+        case '\t':
+            monitor_printf(mon, "\\t");
+            break;
+        case '\r':
+            monitor_printf(mon, "\\r");
+            break;
+        case '\n':
+            monitor_printf(mon, "\\n");
+            break;
+        default:
+            monitor_printf(mon, "%c", filename[i]);
+            break;
+        }
     }
 }
 
@@ -155,7 +188,7 @@
 {
     va_list ap;
     va_start(ap, fmt);
-    term_vprintf(fmt, ap);
+    monitor_vprintf((Monitor *)stream, fmt, ap);
     va_end(ap);
     return 0;
 }
@@ -180,39 +213,36 @@
     return 0;
 }
 
-static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name)
+static void help_cmd_dump(Monitor *mon, const mon_cmd_t *cmds,
+                          const char *prefix, const char *name)
 {
-    term_cmd_t *cmd;
+    const mon_cmd_t *cmd;
 
     for(cmd = cmds; cmd->name != NULL; cmd++) {
         if (!name || !strcmp(name, cmd->name))
-            term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help);
+            monitor_printf(mon, "%s%s %s -- %s\n", prefix, cmd->name,
+                           cmd->params, cmd->help);
     }
 }
 
-static void help_cmd(const char *name)
+static void help_cmd(Monitor *mon, const char *name)
 {
     if (name && !strcmp(name, "info")) {
-        help_cmd1(info_cmds, "info ", NULL);
+        help_cmd_dump(mon, info_cmds, "info ", NULL);
     } else {
-        help_cmd1(term_cmds, "", name);
+        help_cmd_dump(mon, mon_cmds, "", name);
         if (name && !strcmp(name, "log")) {
-            CPULogItem *item;
-            term_printf("Log items (comma separated):\n");
-            term_printf("%-10s %s\n", "none", "remove all logs");
+            const CPULogItem *item;
+            monitor_printf(mon, "Log items (comma separated):\n");
+            monitor_printf(mon, "%-10s %s\n", "none", "remove all logs");
             for(item = cpu_log_items; item->mask != 0; item++) {
-                term_printf("%-10s %s\n", item->name, item->help);
+                monitor_printf(mon, "%-10s %s\n", item->name, item->help);
             }
         }
     }
 }
 
-static void do_help(const char *name)
-{
-    help_cmd(name);
-}
-
-static void do_commit(const char *device)
+static void do_commit(Monitor *mon, const char *device)
 {
     int i, all_devices;
 
@@ -224,10 +254,10 @@
     }
 }
 
-static void do_info(const char *item)
+static void do_info(Monitor *mon, const char *item)
 {
-    term_cmd_t *cmd;
-    void (*handler)(void);
+    const mon_cmd_t *cmd;
+    void (*handler)(Monitor *);
 
     if (!item)
         goto help;
@@ -236,32 +266,39 @@
             goto found;
     }
  help:
-    help_cmd("info");
+    help_cmd(mon, "info");
     return;
  found:
     handler = cmd->handler;
-    handler();
+    handler(mon);
 }
 
-static void do_info_version(void)
+static void do_info_version(Monitor *mon)
 {
-  term_printf("%s\n", QEMU_VERSION);
+    monitor_printf(mon, "%s\n", QEMU_VERSION QEMU_PKGVERSION);
 }
 
-static void do_info_name(void)
+static void do_info_name(Monitor *mon)
 {
     if (qemu_name)
-        term_printf("%s\n", qemu_name);
+        monitor_printf(mon, "%s\n", qemu_name);
 }
 
-static void do_info_block(void)
+#if defined(TARGET_I386)
+static void do_info_hpet(Monitor *mon)
 {
-    bdrv_info();
+    monitor_printf(mon, "HPET is %s by QEMU\n",
+                   (no_hpet) ? "disabled" : "enabled");
 }
+#endif
 
-static void do_info_blockstats(void)
+static void do_info_uuid(Monitor *mon)
 {
-    bdrv_info_stats();
+    monitor_printf(mon, UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1],
+                   qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
+                   qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
+                   qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
+                   qemu_uuid[14], qemu_uuid[15]);
 }
 
 /* get the current CPU defined by the user */
@@ -271,7 +308,7 @@
 
     for(env = first_cpu; env != NULL; env = env->next_cpu) {
         if (env->cpu_index == cpu_index) {
-            mon_cpu = env;
+            cur_mon->mon_cpu = env;
             return 0;
         }
     }
@@ -280,28 +317,29 @@
 
 static CPUState *mon_get_cpu(void)
 {
-    if (!mon_cpu) {
+    if (!cur_mon->mon_cpu) {
         mon_set_cpu(0);
     }
-    return mon_cpu;
+    cpu_synchronize_state(cur_mon->mon_cpu, 0);
+    return cur_mon->mon_cpu;
 }
 
-static void do_info_registers(void)
+static void do_info_registers(Monitor *mon)
 {
     CPUState *env;
     env = mon_get_cpu();
     if (!env)
         return;
 #ifdef TARGET_I386
-    cpu_dump_state(env, NULL, monitor_fprintf,
+    cpu_dump_state(env, (FILE *)mon, monitor_fprintf,
                    X86_DUMP_FPU);
 #else
-    cpu_dump_state(env, NULL, monitor_fprintf,
+    cpu_dump_state(env, (FILE *)mon, monitor_fprintf,
                    0);
 #endif
 }
 
-static void do_info_cpus(void)
+static void do_info_cpus(Monitor *mon)
 {
     CPUState *env;
 
@@ -309,76 +347,81 @@
     mon_get_cpu();
 
     for(env = first_cpu; env != NULL; env = env->next_cpu) {
-        term_printf("%c CPU #%d:",
-                    (env == mon_cpu) ? '*' : ' ',
-                    env->cpu_index);
+        cpu_synchronize_state(env, 0);
+        monitor_printf(mon, "%c CPU #%d:",
+                       (env == mon->mon_cpu) ? '*' : ' ',
+                       env->cpu_index);
 #if defined(TARGET_I386)
-        term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base);
+        monitor_printf(mon, " pc=0x" TARGET_FMT_lx,
+                       env->eip + env->segs[R_CS].base);
 #elif defined(TARGET_PPC)
-        term_printf(" nip=0x" TARGET_FMT_lx, env->nip);
+        monitor_printf(mon, " nip=0x" TARGET_FMT_lx, env->nip);
 #elif defined(TARGET_SPARC)
-        term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc);
+        monitor_printf(mon, " pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx,
+                       env->pc, env->npc);
 #elif defined(TARGET_MIPS)
-        term_printf(" PC=0x" TARGET_FMT_lx, env->active_tc.PC);
+        monitor_printf(mon, " PC=0x" TARGET_FMT_lx, env->active_tc.PC);
 #endif
         if (env->halted)
-            term_printf(" (halted)");
-        term_printf("\n");
+            monitor_printf(mon, " (halted)");
+        monitor_printf(mon, "\n");
     }
 }
 
-static void do_cpu_set(int index)
+static void do_cpu_set(Monitor *mon, int index)
 {
     if (mon_set_cpu(index) < 0)
-        term_printf("Invalid CPU index\n");
+        monitor_printf(mon, "Invalid CPU index\n");
 }
 
-static void do_info_jit(void)
+static void do_info_jit(Monitor *mon)
 {
-    dump_exec_info(NULL, monitor_fprintf);
+    dump_exec_info((FILE *)mon, monitor_fprintf);
 }
 
-static void do_info_history (void)
+static void do_info_history(Monitor *mon)
 {
     int i;
     const char *str;
 
+    if (!mon->rs)
+        return;
     i = 0;
     for(;;) {
-        str = readline_get_history(i);
+        str = readline_get_history(mon->rs, i);
         if (!str)
             break;
-	term_printf("%d: '%s'\n", i, str);
+        monitor_printf(mon, "%d: '%s'\n", i, str);
         i++;
     }
 }
 
 #if defined(TARGET_PPC)
 /* XXX: not implemented in other targets */
-static void do_info_cpu_stats (void)
+static void do_info_cpu_stats(Monitor *mon)
 {
     CPUState *env;
 
     env = mon_get_cpu();
-    cpu_dump_statistics(env, NULL, &monitor_fprintf, 0);
+    cpu_dump_statistics(env, (FILE *)mon, &monitor_fprintf, 0);
 }
 #endif
 
-static void do_quit(void)
+static void do_quit(Monitor *mon)
 {
     exit(0);
 }
 
-static int eject_device(BlockDriverState *bs, int force)
+static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
 {
     if (bdrv_is_inserted(bs)) {
         if (!force) {
             if (!bdrv_is_removable(bs)) {
-                term_printf("device is not removable\n");
+                monitor_printf(mon, "device is not removable\n");
                 return -1;
             }
             if (bdrv_is_locked(bs)) {
-                term_printf("device is locked\n");
+                monitor_printf(mon, "device is locked\n");
                 return -1;
             }
         }
@@ -387,76 +430,90 @@
     return 0;
 }
 
-static void do_eject(int force, const char *filename)
+static void do_eject(Monitor *mon, int force, const char *filename)
 {
     BlockDriverState *bs;
 
     bs = bdrv_find(filename);
     if (!bs) {
-        term_printf("device not found\n");
+        monitor_printf(mon, "device not found\n");
         return;
     }
-    eject_device(bs, force);
+    eject_device(mon, bs, force);
 }
 
-static void do_change_block(const char *device, const char *filename, const char *fmt)
+static void do_change_block(Monitor *mon, const char *device,
+                            const char *filename, const char *fmt)
 {
     BlockDriverState *bs;
     BlockDriver *drv = NULL;
 
     bs = bdrv_find(device);
     if (!bs) {
-        term_printf("device not found\n");
+        monitor_printf(mon, "device not found\n");
         return;
     }
     if (fmt) {
         drv = bdrv_find_format(fmt);
         if (!drv) {
-            term_printf("invalid format %s\n", fmt);
+            monitor_printf(mon, "invalid format %s\n", fmt);
             return;
         }
     }
-    if (eject_device(bs, 0) < 0)
+    if (eject_device(mon, bs, 0) < 0)
         return;
     bdrv_open2(bs, filename, 0, drv);
-    qemu_key_check(bs, filename);
+    monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
 }
 
-static void do_change_vnc(const char *target)
+static void change_vnc_password_cb(Monitor *mon, const char *password,
+                                   void *opaque)
+{
+    if (vnc_display_password(NULL, password) < 0)
+        monitor_printf(mon, "could not set VNC server password\n");
+
+    monitor_read_command(mon, 1);
+}
+
+static void do_change_vnc(Monitor *mon, const char *target, const char *arg)
 {
     if (strcmp(target, "passwd") == 0 ||
-	strcmp(target, "password") == 0) {
-	char password[9];
-	monitor_readline("Password: ", 1, password, sizeof(password)-1);
-	password[sizeof(password)-1] = '\0';
-	if (vnc_display_password(NULL, password) < 0)
-	    term_printf("could not set VNC server password\n");
+        strcmp(target, "password") == 0) {
+        if (arg) {
+            char password[9];
+            strncpy(password, arg, sizeof(password));
+            password[sizeof(password) - 1] = '\0';
+            change_vnc_password_cb(mon, password, NULL);
+        } else {
+            monitor_read_password(mon, change_vnc_password_cb, NULL);
+        }
     } else {
-	if (vnc_display_open(NULL, target) < 0)
-	    term_printf("could not start VNC server on %s\n", target);
+        if (vnc_display_open(NULL, target) < 0)
+            monitor_printf(mon, "could not start VNC server on %s\n", target);
     }
 }
 
-static void do_change(const char *device, const char *target, const char *fmt)
+static void do_change(Monitor *mon, const char *device, const char *target,
+                      const char *arg)
 {
     if (strcmp(device, "vnc") == 0) {
-	do_change_vnc(target);
+        do_change_vnc(mon, target, arg);
     } else {
-	do_change_block(device, target, fmt);
+        do_change_block(mon, device, target, arg);
     }
 }
 
-static void do_screen_dump(const char *filename)
+static void do_screen_dump(Monitor *mon, const char *filename)
 {
     vga_hw_screen_dump(filename);
 }
 
-static void do_logfile(const char *filename)
+static void do_logfile(Monitor *mon, const char *filename)
 {
     cpu_set_log_filename(filename);
 }
 
-static void do_log(const char *items)
+static void do_log(Monitor *mon, const char *items)
 {
     int mask;
 
@@ -465,64 +522,116 @@
     } else {
         mask = cpu_str_to_log_mask(items);
         if (!mask) {
-            help_cmd("log");
+            help_cmd(mon, "log");
             return;
         }
     }
     cpu_set_log(mask);
 }
 
-static void do_stop(void)
+static void do_singlestep(Monitor *mon, const char *option)
+{
+    if (!option || !strcmp(option, "on")) {
+        singlestep = 1;
+    } else if (!strcmp(option, "off")) {
+        singlestep = 0;
+    } else {
+        monitor_printf(mon, "unexpected option %s\n", option);
+    }
+}
+
+static void do_stop(Monitor *mon)
 {
     vm_stop(EXCP_INTERRUPT);
 }
 
-static void do_cont(void)
+static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);
+
+struct bdrv_iterate_context {
+    Monitor *mon;
+    int err;
+};
+
+static void do_cont(Monitor *mon)
 {
-    vm_start();
+    struct bdrv_iterate_context context = { mon, 0 };
+
+    bdrv_iterate(encrypted_bdrv_it, &context);
+    /* only resume the vm if all keys are set and valid */
+    if (!context.err)
+        vm_start();
 }
 
-#ifdef CONFIG_GDBSTUB
-static void do_gdbserver(const char *port)
+static void bdrv_key_cb(void *opaque, int err)
 {
-    if (!port)
-        port = DEFAULT_GDBSTUB_PORT;
-    if (gdbserver_start(port) < 0) {
-        qemu_printf("Could not open gdbserver socket on port '%s'\n", port);
-    } else {
-        qemu_printf("Waiting gdb connection on port '%s'\n", port);
+    Monitor *mon = opaque;
+
+    /* another key was set successfully, retry to continue */
+    if (!err)
+        do_cont(mon);
+}
+
+static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
+{
+    struct bdrv_iterate_context *context = opaque;
+
+    if (!context->err && bdrv_key_required(bs)) {
+        context->err = -EBUSY;
+        monitor_read_bdrv_key_start(context->mon, bs, bdrv_key_cb,
+                                    context->mon);
     }
 }
-#endif
 
-static void term_printc(int c)
+static void do_gdbserver(Monitor *mon, const char *device)
 {
-    term_printf("'");
+    if (!device)
+        device = "tcp::" DEFAULT_GDBSTUB_PORT;
+    if (gdbserver_start(device) < 0) {
+        monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
+                       device);
+    } else if (strcmp(device, "none") == 0) {
+        monitor_printf(mon, "Disabled gdbserver\n");
+    } else {
+        monitor_printf(mon, "Waiting for gdb connection on device '%s'\n",
+                       device);
+    }
+}
+
+static void do_watchdog_action(Monitor *mon, const char *action)
+{
+    if (select_watchdog_action(action) == -1) {
+        monitor_printf(mon, "Unknown watchdog action '%s'\n", action);
+    }
+}
+
+static void monitor_printc(Monitor *mon, int c)
+{
+    monitor_printf(mon, "'");
     switch(c) {
     case '\'':
-        term_printf("\\'");
+        monitor_printf(mon, "\\'");
         break;
     case '\\':
-        term_printf("\\\\");
+        monitor_printf(mon, "\\\\");
         break;
     case '\n':
-        term_printf("\\n");
+        monitor_printf(mon, "\\n");
         break;
     case '\r':
-        term_printf("\\r");
+        monitor_printf(mon, "\\r");
         break;
     default:
         if (c >= 32 && c <= 126) {
-            term_printf("%c", c);
+            monitor_printf(mon, "%c", c);
         } else {
-            term_printf("\\x%02x", c);
+            monitor_printf(mon, "\\x%02x", c);
         }
         break;
     }
-    term_printf("'");
+    monitor_printf(mon, "'");
 }
 
-static void memory_dump(int count, int format, int wsize,
+static void memory_dump(Monitor *mon, int count, int format, int wsize,
                         target_phys_addr_t addr, int is_physical)
 {
     CPUState *env;
@@ -556,7 +665,7 @@
             }
         }
 #endif
-        monitor_disas(env, addr, count, is_physical, flags);
+        monitor_disas(mon, env, addr, count, is_physical, flags);
         return;
     }
 
@@ -587,9 +696,9 @@
 
     while (len > 0) {
         if (is_physical)
-            term_printf(TARGET_FMT_plx ":", addr);
+            monitor_printf(mon, TARGET_FMT_plx ":", addr);
         else
-            term_printf(TARGET_FMT_lx ":", (target_ulong)addr);
+            monitor_printf(mon, TARGET_FMT_lx ":", (target_ulong)addr);
         l = len;
         if (l > line_size)
             l = line_size;
@@ -600,7 +709,7 @@
             if (!env)
                 break;
             if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) {
-                term_printf(" Cannot access memory\n");
+                monitor_printf(mon, " Cannot access memory\n");
                 break;
             }
         }
@@ -621,27 +730,27 @@
                 v = ldq_raw(buf + i);
                 break;
             }
-            term_printf(" ");
+            monitor_printf(mon, " ");
             switch(format) {
             case 'o':
-                term_printf("%#*" PRIo64, max_digits, v);
+                monitor_printf(mon, "%#*" PRIo64, max_digits, v);
                 break;
             case 'x':
-                term_printf("0x%0*" PRIx64, max_digits, v);
+                monitor_printf(mon, "0x%0*" PRIx64, max_digits, v);
                 break;
             case 'u':
-                term_printf("%*" PRIu64, max_digits, v);
+                monitor_printf(mon, "%*" PRIu64, max_digits, v);
                 break;
             case 'd':
-                term_printf("%*" PRId64, max_digits, v);
+                monitor_printf(mon, "%*" PRId64, max_digits, v);
                 break;
             case 'c':
-                term_printc(v);
+                monitor_printc(mon, v);
                 break;
             }
             i += wsize;
         }
-        term_printf("\n");
+        monitor_printf(mon, "\n");
         addr += l;
         len -= l;
     }
@@ -653,11 +762,11 @@
 #define GET_TLONG(h, l) (l)
 #endif
 
-static void do_memory_dump(int count, int format, int size,
+static void do_memory_dump(Monitor *mon, int count, int format, int size,
                            uint32_t addrh, uint32_t addrl)
 {
     target_long addr = GET_TLONG(addrh, addrl);
-    memory_dump(count, format, size, addr, 0);
+    memory_dump(mon, count, format, size, addr, 0);
 }
 
 #if TARGET_PHYS_ADDR_BITS > 32
@@ -666,60 +775,61 @@
 #define GET_TPHYSADDR(h, l) (l)
 #endif
 
-static void do_physical_memory_dump(int count, int format, int size,
-                                    uint32_t addrh, uint32_t addrl)
+static void do_physical_memory_dump(Monitor *mon, int count, int format,
+                                    int size, uint32_t addrh, uint32_t addrl)
 
 {
     target_phys_addr_t addr = GET_TPHYSADDR(addrh, addrl);
-    memory_dump(count, format, size, addr, 1);
+    memory_dump(mon, count, format, size, addr, 1);
 }
 
-static void do_print(int count, int format, int size, unsigned int valh, unsigned int vall)
+static void do_print(Monitor *mon, int count, int format, int size,
+                     unsigned int valh, unsigned int vall)
 {
     target_phys_addr_t val = GET_TPHYSADDR(valh, vall);
 #if TARGET_PHYS_ADDR_BITS == 32
     switch(format) {
     case 'o':
-        term_printf("%#o", val);
+        monitor_printf(mon, "%#o", val);
         break;
     case 'x':
-        term_printf("%#x", val);
+        monitor_printf(mon, "%#x", val);
         break;
     case 'u':
-        term_printf("%u", val);
+        monitor_printf(mon, "%u", val);
         break;
     default:
     case 'd':
-        term_printf("%d", val);
+        monitor_printf(mon, "%d", val);
         break;
     case 'c':
-        term_printc(val);
+        monitor_printc(mon, val);
         break;
     }
 #else
     switch(format) {
     case 'o':
-        term_printf("%#" PRIo64, val);
+        monitor_printf(mon, "%#" PRIo64, val);
         break;
     case 'x':
-        term_printf("%#" PRIx64, val);
+        monitor_printf(mon, "%#" PRIx64, val);
         break;
     case 'u':
-        term_printf("%" PRIu64, val);
+        monitor_printf(mon, "%" PRIu64, val);
         break;
     default:
     case 'd':
-        term_printf("%" PRId64, val);
+        monitor_printf(mon, "%" PRId64, val);
         break;
     case 'c':
-        term_printc(val);
+        monitor_printc(mon, val);
         break;
     }
 #endif
-    term_printf("\n");
+    monitor_printf(mon, "\n");
 }
 
-static void do_memory_save(unsigned int valh, unsigned int vall,
+static void do_memory_save(Monitor *mon, unsigned int valh, unsigned int vall,
                            uint32_t size, const char *filename)
 {
     FILE *f;
@@ -734,7 +844,7 @@
 
     f = fopen(filename, "wb");
     if (!f) {
-        term_printf("could not open '%s'\n", filename);
+        monitor_printf(mon, "could not open '%s'\n", filename);
         return;
     }
     while (size != 0) {
@@ -749,8 +859,9 @@
     fclose(f);
 }
 
-static void do_physical_memory_save(unsigned int valh, unsigned int vall,
-                                    uint32_t size, const char *filename)
+static void do_physical_memory_save(Monitor *mon, unsigned int valh,
+                                    unsigned int vall, uint32_t size,
+                                    const char *filename)
 {
     FILE *f;
     uint32_t l;
@@ -759,7 +870,7 @@
 
     f = fopen(filename, "wb");
     if (!f) {
-        term_printf("could not open '%s'\n", filename);
+        monitor_printf(mon, "could not open '%s'\n", filename);
         return;
     }
     while (size != 0) {
@@ -775,7 +886,7 @@
     fclose(f);
 }
 
-static void do_sum(uint32_t start, uint32_t size)
+static void do_sum(Monitor *mon, uint32_t start, uint32_t size)
 {
     uint32_t addr;
     uint8_t buf[1];
@@ -788,7 +899,7 @@
         sum = (sum >> 1) | (sum << 15);
         sum += buf[0];
     }
-    term_printf("%05d\n", sum);
+    monitor_printf(mon, "%05d\n", sum);
 }
 
 typedef struct {
@@ -856,6 +967,9 @@
     { 0x30, "b" },
     { 0x31, "n" },
     { 0x32, "m" },
+    { 0x33, "comma" },
+    { 0x34, "dot" },
+    { 0x35, "slash" },
 
     { 0x37, "asterisk" },
 
@@ -968,7 +1082,8 @@
     }
 }
 
-static void do_sendkey(const char *string, int has_hold_time, int hold_time)
+static void do_sendkey(Monitor *mon, const char *string, int has_hold_time,
+                       int hold_time)
 {
     char keyname_buf[16];
     char *separator;
@@ -987,17 +1102,17 @@
         if (keyname_len > 0) {
             pstrcpy(keyname_buf, sizeof(keyname_buf), string);
             if (keyname_len > sizeof(keyname_buf) - 1) {
-                term_printf("invalid key: '%s...'\n", keyname_buf);
+                monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf);
                 return;
             }
             if (i == MAX_KEYCODES) {
-                term_printf("too many keys\n");
+                monitor_printf(mon, "too many keys\n");
                 return;
             }
             keyname_buf[keyname_len] = 0;
             keycode = get_keycode(keyname_buf);
             if (keycode < 0) {
-                term_printf("unknown key: '%s'\n", keyname_buf);
+                monitor_printf(mon, "unknown key: '%s'\n", keyname_buf);
                 return;
             }
             keycodes[i++] = keycode;
@@ -1021,7 +1136,7 @@
 
 static int mouse_button_state;
 
-static void do_mouse_move(const char *dx_str, const char *dy_str,
+static void do_mouse_move(Monitor *mon, const char *dx_str, const char *dy_str,
                           const char *dz_str)
 {
     int dx, dy, dz;
@@ -1033,13 +1148,14 @@
     kbd_mouse_event(dx, dy, dz, mouse_button_state);
 }
 
-static void do_mouse_button(int button_state)
+static void do_mouse_button(Monitor *mon, int button_state)
 {
     mouse_button_state = button_state;
     kbd_mouse_event(0, 0, 0, mouse_button_state);
 }
 
-static void do_ioport_read(int count, int format, int size, int addr, int has_index, int index)
+static void do_ioport_read(Monitor *mon, int count, int format, int size,
+                           int addr, int has_index, int index)
 {
     uint32_t val;
     int suffix;
@@ -1065,37 +1181,65 @@
         suffix = 'l';
         break;
     }
-    term_printf("port%c[0x%04x] = %#0*x\n",
-                suffix, addr, size * 2, val);
+    monitor_printf(mon, "port%c[0x%04x] = %#0*x\n",
+                   suffix, addr, size * 2, val);
 }
 
-static void do_system_reset(void)
+/* boot_set handler */
+static QEMUBootSetHandler *qemu_boot_set_handler = NULL;
+static void *boot_opaque;
+
+void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
+{
+    qemu_boot_set_handler = func;
+    boot_opaque = opaque;
+}
+
+static void do_boot_set(Monitor *mon, const char *bootdevice)
+{
+    int res;
+
+    if (qemu_boot_set_handler)  {
+        res = qemu_boot_set_handler(boot_opaque, bootdevice);
+        if (res == 0)
+            monitor_printf(mon, "boot device list now set to %s\n",
+                           bootdevice);
+        else
+            monitor_printf(mon, "setting boot device list failed with "
+                           "error %i\n", res);
+    } else {
+        monitor_printf(mon, "no function defined to set boot device list for "
+                       "this architecture\n");
+    }
+}
+
+static void do_system_reset(Monitor *mon)
 {
     qemu_system_reset_request();
 }
 
-static void do_system_powerdown(void)
+static void do_system_powerdown(Monitor *mon)
 {
     qemu_system_powerdown_request();
 }
 
 #if defined(TARGET_I386)
-static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
+static void print_pte(Monitor *mon, uint32_t addr, uint32_t pte, uint32_t mask)
 {
-    term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n",
-                addr,
-                pte & mask,
-                pte & PG_GLOBAL_MASK ? 'G' : '-',
-                pte & PG_PSE_MASK ? 'P' : '-',
-                pte & PG_DIRTY_MASK ? 'D' : '-',
-                pte & PG_ACCESSED_MASK ? 'A' : '-',
-                pte & PG_PCD_MASK ? 'C' : '-',
-                pte & PG_PWT_MASK ? 'T' : '-',
-                pte & PG_USER_MASK ? 'U' : '-',
-                pte & PG_RW_MASK ? 'W' : '-');
+    monitor_printf(mon, "%08x: %08x %c%c%c%c%c%c%c%c\n",
+                   addr,
+                   pte & mask,
+                   pte & PG_GLOBAL_MASK ? 'G' : '-',
+                   pte & PG_PSE_MASK ? 'P' : '-',
+                   pte & PG_DIRTY_MASK ? 'D' : '-',
+                   pte & PG_ACCESSED_MASK ? 'A' : '-',
+                   pte & PG_PCD_MASK ? 'C' : '-',
+                   pte & PG_PWT_MASK ? 'T' : '-',
+                   pte & PG_USER_MASK ? 'U' : '-',
+                   pte & PG_RW_MASK ? 'W' : '-');
 }
 
-static void tlb_info(void)
+static void tlb_info(Monitor *mon)
 {
     CPUState *env;
     int l1, l2;
@@ -1106,7 +1250,7 @@
         return;
 
     if (!(env->cr[0] & CR0_PG_MASK)) {
-        term_printf("PG disabled\n");
+        monitor_printf(mon, "PG disabled\n");
         return;
     }
     pgd = env->cr[3] & ~0xfff;
@@ -1115,14 +1259,14 @@
         pde = le32_to_cpu(pde);
         if (pde & PG_PRESENT_MASK) {
             if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
-                print_pte((l1 << 22), pde, ~((1 << 20) - 1));
+                print_pte(mon, (l1 << 22), pde, ~((1 << 20) - 1));
             } else {
                 for(l2 = 0; l2 < 1024; l2++) {
                     cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
                                              (uint8_t *)&pte, 4);
                     pte = le32_to_cpu(pte);
                     if (pte & PG_PRESENT_MASK) {
-                        print_pte((l1 << 22) + (l2 << 12),
+                        print_pte(mon, (l1 << 22) + (l2 << 12),
                                   pte & ~PG_PSE_MASK,
                                   ~0xfff);
                     }
@@ -1132,18 +1276,18 @@
     }
 }
 
-static void mem_print(uint32_t *pstart, int *plast_prot,
+static void mem_print(Monitor *mon, uint32_t *pstart, int *plast_prot,
                       uint32_t end, int prot)
 {
     int prot1;
     prot1 = *plast_prot;
     if (prot != prot1) {
         if (*pstart != -1) {
-            term_printf("%08x-%08x %08x %c%c%c\n",
-                        *pstart, end, end - *pstart,
-                        prot1 & PG_USER_MASK ? 'u' : '-',
-                        'r',
-                        prot1 & PG_RW_MASK ? 'w' : '-');
+            monitor_printf(mon, "%08x-%08x %08x %c%c%c\n",
+                           *pstart, end, end - *pstart,
+                           prot1 & PG_USER_MASK ? 'u' : '-',
+                           'r',
+                           prot1 & PG_RW_MASK ? 'w' : '-');
         }
         if (prot != 0)
             *pstart = end;
@@ -1153,7 +1297,7 @@
     }
 }
 
-static void mem_info(void)
+static void mem_info(Monitor *mon)
 {
     CPUState *env;
     int l1, l2, prot, last_prot;
@@ -1164,7 +1308,7 @@
         return;
 
     if (!(env->cr[0] & CR0_PG_MASK)) {
-        term_printf("PG disabled\n");
+        monitor_printf(mon, "PG disabled\n");
         return;
     }
     pgd = env->cr[3] & ~0xfff;
@@ -1177,7 +1321,7 @@
         if (pde & PG_PRESENT_MASK) {
             if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
                 prot = pde & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK);
-                mem_print(&start, &last_prot, end, prot);
+                mem_print(mon, &start, &last_prot, end, prot);
             } else {
                 for(l2 = 0; l2 < 1024; l2++) {
                     cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
@@ -1189,47 +1333,108 @@
                     } else {
                         prot = 0;
                     }
-                    mem_print(&start, &last_prot, end, prot);
+                    mem_print(mon, &start, &last_prot, end, prot);
                 }
             }
         } else {
             prot = 0;
-            mem_print(&start, &last_prot, end, prot);
+            mem_print(mon, &start, &last_prot, end, prot);
         }
     }
 }
 #endif
 
-static void do_info_kqemu(void)
+#if defined(TARGET_SH4)
+
+static void print_tlb(Monitor *mon, int idx, tlb_t *tlb)
 {
-#ifdef USE_KQEMU
+    monitor_printf(mon, " tlb%i:\t"
+                   "asid=%hhu vpn=%x\tppn=%x\tsz=%hhu size=%u\t"
+                   "v=%hhu shared=%hhu cached=%hhu prot=%hhu "
+                   "dirty=%hhu writethrough=%hhu\n",
+                   idx,
+                   tlb->asid, tlb->vpn, tlb->ppn, tlb->sz, tlb->size,
+                   tlb->v, tlb->sh, tlb->c, tlb->pr,
+                   tlb->d, tlb->wt);
+}
+
+static void tlb_info(Monitor *mon)
+{
+    CPUState *env = mon_get_cpu();
+    int i;
+
+    monitor_printf (mon, "ITLB:\n");
+    for (i = 0 ; i < ITLB_SIZE ; i++)
+        print_tlb (mon, i, &env->itlb[i]);
+    monitor_printf (mon, "UTLB:\n");
+    for (i = 0 ; i < UTLB_SIZE ; i++)
+        print_tlb (mon, i, &env->utlb[i]);
+}
+
+#endif
+
+static void do_info_kqemu(Monitor *mon)
+{
+#ifdef CONFIG_KQEMU
     CPUState *env;
     int val;
     val = 0;
     env = mon_get_cpu();
     if (!env) {
-        term_printf("No cpu initialized yet");
+        monitor_printf(mon, "No cpu initialized yet");
         return;
     }
     val = env->kqemu_enabled;
-    term_printf("kqemu support: ");
+    monitor_printf(mon, "kqemu support: ");
     switch(val) {
     default:
     case 0:
-        term_printf("disabled\n");
+        monitor_printf(mon, "disabled\n");
         break;
     case 1:
-        term_printf("enabled for user code\n");
+        monitor_printf(mon, "enabled for user code\n");
         break;
     case 2:
-        term_printf("enabled for user and kernel code\n");
+        monitor_printf(mon, "enabled for user and kernel code\n");
         break;
     }
 #else
-    term_printf("kqemu support: not compiled\n");
+    monitor_printf(mon, "kqemu support: not compiled\n");
 #endif
 }
 
+static void do_info_kvm(Monitor *mon)
+{
+#ifdef CONFIG_KVM
+    monitor_printf(mon, "kvm support: ");
+    if (kvm_enabled())
+        monitor_printf(mon, "enabled\n");
+    else
+        monitor_printf(mon, "disabled\n");
+#else
+    monitor_printf(mon, "kvm support: not compiled\n");
+#endif
+}
+
+static void do_info_numa(Monitor *mon)
+{
+    int i;
+    CPUState *env;
+
+    monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
+    for (i = 0; i < nb_numa_nodes; i++) {
+        monitor_printf(mon, "node %d cpus:", i);
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            if (env->numa_node == i) {
+                monitor_printf(mon, " %d", env->cpu_index);
+            }
+        }
+        monitor_printf(mon, "\n");
+        monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i,
+            node_mem[i] >> 20);
+    }
+}
+
 #ifdef CONFIG_PROFILER
 
 int64_t kqemu_time;
@@ -1240,23 +1445,25 @@
 int64_t kqemu_ret_excp_count;
 int64_t kqemu_ret_intr_count;
 
-static void do_info_profile(void)
+static void do_info_profile(Monitor *mon)
 {
     int64_t total;
     total = qemu_time;
     if (total == 0)
         total = 1;
-    term_printf("async time  %" PRId64 " (%0.3f)\n",
-                dev_time, dev_time / (double)ticks_per_sec);
-    term_printf("qemu time   %" PRId64 " (%0.3f)\n",
-                qemu_time, qemu_time / (double)ticks_per_sec);
-    term_printf("kqemu time  %" PRId64 " (%0.3f %0.1f%%) count=%" PRId64 " int=%" PRId64 " excp=%" PRId64 " intr=%" PRId64 "\n",
-                kqemu_time, kqemu_time / (double)ticks_per_sec,
-                kqemu_time / (double)total * 100.0,
-                kqemu_exec_count,
-                kqemu_ret_int_count,
-                kqemu_ret_excp_count,
-                kqemu_ret_intr_count);
+    monitor_printf(mon, "async time  %" PRId64 " (%0.3f)\n",
+                   dev_time, dev_time / (double)ticks_per_sec);
+    monitor_printf(mon, "qemu time   %" PRId64 " (%0.3f)\n",
+                   qemu_time, qemu_time / (double)ticks_per_sec);
+    monitor_printf(mon, "kqemu time  %" PRId64 " (%0.3f %0.1f%%) count=%"
+                        PRId64 " int=%" PRId64 " excp=%" PRId64 " intr=%"
+                        PRId64 "\n",
+                   kqemu_time, kqemu_time / (double)ticks_per_sec,
+                   kqemu_time / (double)total * 100.0,
+                   kqemu_exec_count,
+                   kqemu_ret_int_count,
+                   kqemu_ret_excp_count,
+                   kqemu_ret_intr_count);
     qemu_time = 0;
     kqemu_time = 0;
     kqemu_exec_count = 0;
@@ -1264,32 +1471,33 @@
     kqemu_ret_int_count = 0;
     kqemu_ret_excp_count = 0;
     kqemu_ret_intr_count = 0;
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     kqemu_record_dump();
 #endif
 }
 #else
-static void do_info_profile(void)
+static void do_info_profile(Monitor *mon)
 {
-    term_printf("Internal profiler not compiled\n");
+    monitor_printf(mon, "Internal profiler not compiled\n");
 }
 #endif
 
 /* Capture support */
 static LIST_HEAD (capture_list_head, CaptureState) capture_head;
 
-static void do_info_capture (void)
+static void do_info_capture(Monitor *mon)
 {
     int i;
     CaptureState *s;
 
     for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
-        term_printf ("[%d]: ", i);
+        monitor_printf(mon, "[%d]: ", i);
         s->ops.info (s->opaque);
     }
 }
 
-static void do_stop_capture (int n)
+#ifdef HAS_AUDIO
+static void do_stop_capture(Monitor *mon, int n)
 {
     int i;
     CaptureState *s;
@@ -1304,111 +1512,170 @@
     }
 }
 
-#ifdef HAS_AUDIO
-int wav_start_capture (CaptureState *s, const char *path, int freq,
-                       int bits, int nchannels);
-
-static void do_wav_capture (const char *path,
-                            int has_freq, int freq,
-                            int has_bits, int bits,
-                            int has_channels, int nchannels)
+static void do_wav_capture(Monitor *mon, const char *path,
+                           int has_freq, int freq,
+                           int has_bits, int bits,
+                           int has_channels, int nchannels)
 {
     CaptureState *s;
 
     s = qemu_mallocz (sizeof (*s));
-    if (!s) {
-        term_printf ("Not enough memory to add wave capture\n");
-        return;
-    }
 
     freq = has_freq ? freq : 44100;
     bits = has_bits ? bits : 16;
     nchannels = has_channels ? nchannels : 2;
 
     if (wav_start_capture (s, path, freq, bits, nchannels)) {
-        term_printf ("Faied to add wave capture\n");
+        monitor_printf(mon, "Faied to add wave capture\n");
         qemu_free (s);
-        return;
     }
     LIST_INSERT_HEAD (&capture_head, s, entries);
 }
 #endif
 
-static term_cmd_t term_cmds[] = {
-    { "help|?", "s?", do_help,
-      "[cmd]", "show the help" },
-    { "commit", "s", do_commit,
-      "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" },
-    { "info", "s?", do_info,
-      "subcommand", "show various information about the system state" },
-    { "q|quit", "", do_quit,
-      "", "quit the emulator" },
-    { "eject", "-fB", do_eject,
-      "[-f] device", "eject a removable media (use -f to force it)" },
-    { "change", "BF", do_change,
-      "device filename", "change a removable media" },
-    { "screendump", "F", do_screen_dump,
-      "filename", "save screen into PPM image 'filename'" },
-    { "log", "s", do_log,
-      "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
-#if 0
-    { "savevm", "F", do_savevm,
-      "filename", "save the whole virtual machine state to 'filename'" },
-    { "loadvm", "F", do_loadvm,
-      "filename", "restore the whole virtual machine state from 'filename'" },
-#endif
-    { "stop", "", do_stop,
-      "", "stop emulation", },
-    { "c|cont", "", do_cont,
-      "", "resume emulation", },
-#ifdef CONFIG_GDBSTUB
-    { "gdbserver", "s?", do_gdbserver,
-      "[port]", "start gdbserver session (default port=1234)", },
-#endif
-    { "x", "/l", do_memory_dump,
-      "/fmt addr", "virtual memory dump starting at 'addr'", },
-    { "xp", "/l", do_physical_memory_dump,
-      "/fmt addr", "physical memory dump starting at 'addr'", },
-    { "p|print", "/l", do_print,
-      "/fmt expr", "print expression value (use $reg for CPU register access)", },
-    { "i", "/ii.", do_ioport_read,
-      "/fmt addr", "I/O port read" },
+#if defined(TARGET_I386)
+static void do_inject_nmi(Monitor *mon, int cpu_index)
+{
+    CPUState *env;
 
-    { "sendkey", "si?", do_sendkey,
-      "keys [hold_ms]", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)" },
-    { "system_reset", "", do_system_reset,
-      "", "reset the system" },
-    { "system_powerdown", "", do_system_powerdown,
-      "", "send system power down event" },
-    { "sum", "ii", do_sum,
-      "addr size", "compute the checksum of a memory region" },
-    { "usb_add", "s", do_usb_add,
-      "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" },
-    { "usb_del", "s", do_usb_del,
-      "device", "remove USB device 'bus.addr'" },
-    { "cpu", "i", do_cpu_set,
-      "index", "set the default CPU" },
-    { "mouse_move", "sss?", do_mouse_move,
-      "dx dy [dz]", "send mouse move events" },
-    { "mouse_button", "i", do_mouse_button,
-      "state", "change mouse button state (1=L, 2=M, 4=R)" },
-#ifdef HAS_AUDIO
-    { "wavcapture", "si?i?i?", do_wav_capture,
-      "path [frequency bits channels]",
-      "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" },
+    for (env = first_cpu; env != NULL; env = env->next_cpu)
+        if (env->cpu_index == cpu_index) {
+            cpu_interrupt(env, CPU_INTERRUPT_NMI);
+            break;
+        }
+}
 #endif
-     { "stopcapture", "i", do_stop_capture,
-       "capture index", "stop capture" },
+
+static void do_info_status(Monitor *mon)
+{
+    if (vm_running) {
+        if (singlestep) {
+            monitor_printf(mon, "VM status: running (single step mode)\n");
+        } else {
+            monitor_printf(mon, "VM status: running\n");
+        }
+    } else
+       monitor_printf(mon, "VM status: paused\n");
+}
+
+
+static void do_balloon(Monitor *mon, int value)
+{
+    ram_addr_t target = value;
+    qemu_balloon(target << 20);
+}
+
+static void do_info_balloon(Monitor *mon)
+{
+    ram_addr_t actual;
+
+    actual = qemu_balloon_status();
+    if (kvm_enabled() && !kvm_has_sync_mmu())
+        monitor_printf(mon, "Using KVM without synchronous MMU, "
+                       "ballooning disabled\n");
+    else if (actual == 0)
+        monitor_printf(mon, "Ballooning not activated in VM\n");
+    else
+        monitor_printf(mon, "balloon: actual=%d\n", (int)(actual >> 20));
+}
+
+static void do_acl(Monitor *mon,
+                   const char *command,
+                   const char *aclname,
+                   const char *match,
+                   int has_index,
+                   int index)
+{
+    qemu_acl *acl;
+
+    acl = qemu_acl_find(aclname);
+    if (!acl) {
+        monitor_printf(mon, "acl: unknown list '%s'\n", aclname);
+        return;
+    }
+
+    if (strcmp(command, "show") == 0) {
+        int i = 0;
+        qemu_acl_entry *entry;
+        monitor_printf(mon, "policy: %s\n",
+                       acl->defaultDeny ? "deny" : "allow");
+        TAILQ_FOREACH(entry, &acl->entries, next) {
+            i++;
+            monitor_printf(mon, "%d: %s %s\n", i,
+                           entry->deny ? "deny" : "allow",
+                           entry->match);
+        }
+    } else if (strcmp(command, "reset") == 0) {
+        qemu_acl_reset(acl);
+        monitor_printf(mon, "acl: removed all rules\n");
+    } else if (strcmp(command, "policy") == 0) {
+        if (!match) {
+            monitor_printf(mon, "acl: missing policy parameter\n");
+            return;
+        }
+
+        if (strcmp(match, "allow") == 0) {
+            acl->defaultDeny = 0;
+            monitor_printf(mon, "acl: policy set to 'allow'\n");
+        } else if (strcmp(match, "deny") == 0) {
+            acl->defaultDeny = 1;
+            monitor_printf(mon, "acl: policy set to 'deny'\n");
+        } else {
+            monitor_printf(mon, "acl: unknown policy '%s', expected 'deny' or 'allow'\n", match);
+        }
+    } else if ((strcmp(command, "allow") == 0) ||
+               (strcmp(command, "deny") == 0)) {
+        int deny = strcmp(command, "deny") == 0 ? 1 : 0;
+        int ret;
+
+        if (!match) {
+            monitor_printf(mon, "acl: missing match parameter\n");
+            return;
+        }
+
+        if (has_index)
+            ret = qemu_acl_insert(acl, deny, match, index);
+        else
+            ret = qemu_acl_append(acl, deny, match);
+        if (ret < 0)
+            monitor_printf(mon, "acl: unable to add acl entry\n");
+        else
+            monitor_printf(mon, "acl: added rule at position %d\n", ret);
+    } else if (strcmp(command, "remove") == 0) {
+        int ret;
+
+        if (!match) {
+            monitor_printf(mon, "acl: missing match parameter\n");
+            return;
+        }
+
+        ret = qemu_acl_remove(acl, match);
+        if (ret < 0)
+            monitor_printf(mon, "acl: no matching acl entry\n");
+        else
+            monitor_printf(mon, "acl: removed rule at position %d\n", ret);
+    } else {
+        monitor_printf(mon, "acl: unknown command '%s'\n", command);
+    }
+}
+
+static const mon_cmd_t mon_cmds[] = {
+#include "qemu-monitor.h"
     { NULL, NULL, },
 };
 
-static term_cmd_t info_cmds[] = {
+/* Please update qemu-monitor.hx when adding or changing commands */
+static const mon_cmd_t info_cmds[] = {
     { "version", "", do_info_version,
-      "", "show the version of qemu" },
+      "", "show the version of QEMU" },
     { "network", "", do_info_network,
       "", "show the network state" },
-    { "block", "", do_info_block,
+    { "chardev", "", qemu_chr_info,
+      "", "show the character devices" },
+    { "block", "", bdrv_info,
       "", "show the block devices" },
+    { "blockstats", "", bdrv_info_stats,
+      "", "show block device statistics" },
     { "registers", "", do_info_registers,
       "", "show the cpu registers" },
     { "cpus", "", do_info_cpus,
@@ -1421,16 +1688,24 @@
       "", "show i8259 (PIC) state", },
     { "pci", "", pci_info,
       "", "show PCI info", },
-#if defined(TARGET_I386)
+#if defined(TARGET_I386) || defined(TARGET_SH4)
     { "tlb", "", tlb_info,
       "", "show virtual to physical memory mappings", },
+#endif
+#if defined(TARGET_I386)
     { "mem", "", mem_info,
       "", "show the active virtual memory mappings", },
+    { "hpet", "", do_info_hpet,
+      "", "show state of HPET", },
 #endif
     { "jit", "", do_info_jit,
       "", "show dynamic compiler info", },
     { "kqemu", "", do_info_kqemu,
-      "", "show kqemu information", },
+      "", "show KQEMU information", },
+    { "kvm", "", do_info_kvm,
+      "", "show KVM information", },
+    { "numa", "", do_info_numa,
+      "", "show NUMA information", },
     { "usb", "", usb_info,
       "", "show guest USB devices", },
     { "usbhost", "", usb_host_info,
@@ -1438,7 +1713,34 @@
     { "profile", "", do_info_profile,
       "", "show profiling information", },
     { "capture", "", do_info_capture,
-      "show capture information" },
+      "", "show capture information" },
+    { "snapshots", "", do_info_snapshots,
+      "", "show the currently saved VM snapshots" },
+    { "status", "", do_info_status,
+      "", "show the current VM status (running|paused)" },
+    { "pcmcia", "", pcmcia_info,
+      "", "show guest PCMCIA status" },
+    { "mice", "", do_info_mice,
+      "", "show which guest mouse is receiving events" },
+    { "vnc", "", do_info_vnc,
+      "", "show the vnc server status"},
+    { "name", "", do_info_name,
+      "", "show the current VM name" },
+    { "uuid", "", do_info_uuid,
+      "", "show the current VM UUID" },
+#if defined(TARGET_PPC)
+    { "cpustats", "", do_info_cpu_stats,
+      "", "show CPU statistics", },
+#endif
+#if defined(CONFIG_SLIRP)
+    { "slirp", "", do_info_slirp,
+      "", "show SLIRP statistics", },
+#endif
+    { "migrate", "", do_info_migrate, "", "show migration status" },
+    { "balloon", "", do_info_balloon,
+      "", "show balloon information" },
+    { "qtree", "", do_info_qtree,
+      "", "show device tree" },
     { NULL, NULL, },
 };
 
@@ -1453,12 +1755,12 @@
 typedef struct MonitorDef {
     const char *name;
     int offset;
-    target_long (*get_value)(struct MonitorDef *md, int val);
+    target_long (*get_value)(const struct MonitorDef *md, int val);
     int type;
 } MonitorDef;
 
 #if defined(TARGET_I386)
-static target_long monitor_get_pc (struct MonitorDef *md, int val)
+static target_long monitor_get_pc (const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     if (!env)
@@ -1468,7 +1770,7 @@
 #endif
 
 #if defined(TARGET_PPC)
-static target_long monitor_get_ccr (struct MonitorDef *md, int val)
+static target_long monitor_get_ccr (const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     unsigned int u;
@@ -1479,12 +1781,12 @@
 
     u = 0;
     for (i = 0; i < 8; i++)
-	u |= env->crf[i] << (32 - (4 * i));
+        u |= env->crf[i] << (32 - (4 * i));
 
     return u;
 }
 
-static target_long monitor_get_msr (struct MonitorDef *md, int val)
+static target_long monitor_get_msr (const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     if (!env)
@@ -1492,15 +1794,15 @@
     return env->msr;
 }
 
-static target_long monitor_get_xer (struct MonitorDef *md, int val)
+static target_long monitor_get_xer (const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     if (!env)
         return 0;
-    return ppc_load_xer(env);
+    return env->xer;
 }
 
-static target_long monitor_get_decr (struct MonitorDef *md, int val)
+static target_long monitor_get_decr (const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     if (!env)
@@ -1508,7 +1810,7 @@
     return cpu_ppc_load_decr(env);
 }
 
-static target_long monitor_get_tbu (struct MonitorDef *md, int val)
+static target_long monitor_get_tbu (const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     if (!env)
@@ -1516,7 +1818,7 @@
     return cpu_ppc_load_tbu(env);
 }
 
-static target_long monitor_get_tbl (struct MonitorDef *md, int val)
+static target_long monitor_get_tbl (const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     if (!env)
@@ -1527,7 +1829,7 @@
 
 #if defined(TARGET_SPARC)
 #ifndef TARGET_SPARC64
-static target_long monitor_get_psr (struct MonitorDef *md, int val)
+static target_long monitor_get_psr (const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     if (!env)
@@ -1536,7 +1838,7 @@
 }
 #endif
 
-static target_long monitor_get_reg(struct MonitorDef *md, int val)
+static target_long monitor_get_reg(const struct MonitorDef *md, int val)
 {
     CPUState *env = mon_get_cpu();
     if (!env)
@@ -1545,7 +1847,7 @@
 }
 #endif
 
-static MonitorDef monitor_defs[] = {
+static const MonitorDef monitor_defs[] = {
 #ifdef TARGET_I386
 
 #define SEG(name, seg) \
@@ -1782,42 +2084,20 @@
     { "cleanwin", offsetof(CPUState, cleanwin) },
     { "fprs", offsetof(CPUState, fprs) },
 #endif
-#elif defined(TARGET_ARM)
-    { "r0", offsetof(CPUState, regs[0]) },
-    { "r1", offsetof(CPUState, regs[1]) },
-    { "r2", offsetof(CPUState, regs[2]) },
-    { "r3", offsetof(CPUState, regs[3]) },
-    { "r4", offsetof(CPUState, regs[4]) },
-    { "r5", offsetof(CPUState, regs[5]) },
-    { "r6", offsetof(CPUState, regs[6]) },
-    { "r7", offsetof(CPUState, regs[7]) },
-    { "r8", offsetof(CPUState, regs[8]) },
-    { "r9", offsetof(CPUState, regs[9]) },
-    { "r10", offsetof(CPUState, regs[10]) },
-    { "r11", offsetof(CPUState, regs[11]) },
-    { "r12", offsetof(CPUState, regs[12]) },
-    { "r13", offsetof(CPUState, regs[13]) },
-    { "r14", offsetof(CPUState, regs[14]) },
-    { "r15", offsetof(CPUState, regs[15]) },
-    /* some interesting aliases */
-    { "sp", offsetof(CPUState, regs[13]) },
-    { "lr", offsetof(CPUState, regs[14]) },
-    { "pc", offsetof(CPUState, regs[15]) },
 #endif
     { NULL },
 };
 
-static void expr_error(const char *fmt)
+static void expr_error(Monitor *mon, const char *msg)
 {
-    term_printf(fmt);
-    term_printf("\n");
+    monitor_printf(mon, "%s\n", msg);
     longjmp(expr_env, 1);
 }
 
 /* return 0 if OK, -1 if not found, -2 if no CPU defined */
 static int get_monitor_def(target_long *pval, const char *name)
 {
-    MonitorDef *md;
+    const MonitorDef *md;
     void *ptr;
 
     for(md = monitor_defs; md->name != NULL; md++) {
@@ -1851,14 +2131,14 @@
 {
     if (pch != '\0') {
         pch++;
-        while (isspace(*pch))
+        while (qemu_isspace(*pch))
             pch++;
     }
 }
 
-static int64_t expr_sum(void);
+static int64_t expr_sum(Monitor *mon);
 
-static int64_t expr_unary(void)
+static int64_t expr_unary(Monitor *mon)
 {
     int64_t n;
     char *p;
@@ -1867,32 +2147,32 @@
     switch(*pch) {
     case '+':
         next();
-        n = expr_unary();
+        n = expr_unary(mon);
         break;
     case '-':
         next();
-        n = -expr_unary();
+        n = -expr_unary(mon);
         break;
     case '~':
         next();
-        n = ~expr_unary();
+        n = ~expr_unary(mon);
         break;
     case '(':
         next();
-        n = expr_sum();
+        n = expr_sum(mon);
         if (*pch != ')') {
-            expr_error("')' expected");
+            expr_error(mon, "')' expected");
         }
         next();
         break;
     case '\'':
         pch++;
         if (*pch == '\0')
-            expr_error("character constant expected");
+            expr_error(mon, "character constant expected");
         n = *pch;
         pch++;
         if (*pch != '\'')
-            expr_error("missing terminating \' character");
+            expr_error(mon, "missing terminating \' character");
         next();
         break;
     case '$':
@@ -1910,19 +2190,19 @@
                     *q++ = *pch;
                 pch++;
             }
-            while (isspace(*pch))
+            while (qemu_isspace(*pch))
                 pch++;
             *q = 0;
             ret = get_monitor_def(&reg, buf);
             if (ret == -1)
-                expr_error("unknown register");
+                expr_error(mon, "unknown register");
             else if (ret == -2)
-                expr_error("no cpu defined");
+                expr_error(mon, "no cpu defined");
             n = reg;
         }
         break;
     case '\0':
-        expr_error("unexpected end of expression");
+        expr_error(mon, "unexpected end of expression");
         n = 0;
         break;
     default:
@@ -1932,10 +2212,10 @@
         n = strtoul(pch, &p, 0);
 #endif
         if (pch == p) {
-            expr_error("invalid char in expression");
+            expr_error(mon, "invalid char in expression");
         }
         pch = p;
-        while (isspace(*pch))
+        while (qemu_isspace(*pch))
             pch++;
         break;
     }
@@ -1943,18 +2223,18 @@
 }
 
 
-static int64_t expr_prod(void)
+static int64_t expr_prod(Monitor *mon)
 {
     int64_t val, val2;
     int op;
 
-    val = expr_unary();
+    val = expr_unary(mon);
     for(;;) {
         op = *pch;
         if (op != '*' && op != '/' && op != '%')
             break;
         next();
-        val2 = expr_unary();
+        val2 = expr_unary(mon);
         switch(op) {
         default:
         case '*':
@@ -1963,7 +2243,7 @@
         case '/':
         case '%':
             if (val2 == 0)
-                expr_error("division by zero");
+                expr_error(mon, "division by zero");
             if (op == '/')
                 val /= val2;
             else
@@ -1974,18 +2254,18 @@
     return val;
 }
 
-static int64_t expr_logic(void)
+static int64_t expr_logic(Monitor *mon)
 {
     int64_t val, val2;
     int op;
 
-    val = expr_prod();
+    val = expr_prod(mon);
     for(;;) {
         op = *pch;
         if (op != '&' && op != '|' && op != '^')
             break;
         next();
-        val2 = expr_prod();
+        val2 = expr_prod(mon);
         switch(op) {
         default:
         case '&':
@@ -2002,18 +2282,18 @@
     return val;
 }
 
-static int64_t expr_sum(void)
+static int64_t expr_sum(Monitor *mon)
 {
     int64_t val, val2;
     int op;
 
-    val = expr_logic();
+    val = expr_logic(mon);
     for(;;) {
         op = *pch;
         if (op != '+' && op != '-')
             break;
         next();
-        val2 = expr_logic();
+        val2 = expr_logic(mon);
         if (op == '+')
             val += val2;
         else
@@ -2022,16 +2302,16 @@
     return val;
 }
 
-static int get_expr(int64_t *pval, const char **pp)
+static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
 {
     pch = *pp;
     if (setjmp(expr_env)) {
         *pp = pch;
         return -1;
     }
-    while (isspace(*pch))
+    while (qemu_isspace(*pch))
         pch++;
-    *pval = expr_sum();
+    *pval = expr_sum(mon);
     *pp = pch;
     return 0;
 }
@@ -2044,7 +2324,7 @@
 
     q = buf;
     p = *pp;
-    while (isspace(*p))
+    while (qemu_isspace(*p))
         p++;
     if (*p == '\0') {
     fail:
@@ -2089,7 +2369,7 @@
         }
         p++;
     } else {
-        while (*p != '\0' && !isspace(*p)) {
+        while (*p != '\0' && !qemu_isspace(*p)) {
             if ((q - buf) < buf_size - 1) {
                 *q++ = *p;
             }
@@ -2101,61 +2381,78 @@
     return 0;
 }
 
+/*
+ * Store the command-name in cmdname, and return a pointer to
+ * the remaining of the command string.
+ */
+static const char *get_command_name(const char *cmdline,
+                                    char *cmdname, size_t nlen)
+{
+    size_t len;
+    const char *p, *pstart;
+
+    p = cmdline;
+    while (qemu_isspace(*p))
+        p++;
+    if (*p == '\0')
+        return NULL;
+    pstart = p;
+    while (*p != '\0' && *p != '/' && !qemu_isspace(*p))
+        p++;
+    len = p - pstart;
+    if (len > nlen - 1)
+        len = nlen - 1;
+    memcpy(cmdname, pstart, len);
+    cmdname[len] = '\0';
+    return p;
+}
+
 static int default_fmt_format = 'x';
 static int default_fmt_size = 4;
 
 #define MAX_ARGS 16
 
-static void monitor_handle_command(const char *cmdline)
+static void monitor_handle_command(Monitor *mon, const char *cmdline)
 {
-    const char *p, *pstart, *typestr;
-    char *q;
-    int c, nb_args, len, i, has_arg;
-    term_cmd_t *cmd;
+    const char *p, *typestr;
+    int c, nb_args, i, has_arg;
+    const mon_cmd_t *cmd;
     char cmdname[256];
     char buf[1024];
     void *str_allocated[MAX_ARGS];
     void *args[MAX_ARGS];
-    void (*handler_0)(void);
-    void (*handler_1)(void *arg0);
-    void (*handler_2)(void *arg0, void *arg1);
-    void (*handler_3)(void *arg0, void *arg1, void *arg2);
-    void (*handler_4)(void *arg0, void *arg1, void *arg2, void *arg3);
-    void (*handler_5)(void *arg0, void *arg1, void *arg2, void *arg3,
-                      void *arg4);
-    void (*handler_6)(void *arg0, void *arg1, void *arg2, void *arg3,
-                      void *arg4, void *arg5);
-    void (*handler_7)(void *arg0, void *arg1, void *arg2, void *arg3,
-                      void *arg4, void *arg5, void *arg6);
+    void (*handler_0)(Monitor *mon);
+    void (*handler_1)(Monitor *mon, void *arg0);
+    void (*handler_2)(Monitor *mon, void *arg0, void *arg1);
+    void (*handler_3)(Monitor *mon, void *arg0, void *arg1, void *arg2);
+    void (*handler_4)(Monitor *mon, void *arg0, void *arg1, void *arg2,
+                      void *arg3);
+    void (*handler_5)(Monitor *mon, void *arg0, void *arg1, void *arg2,
+                      void *arg3, void *arg4);
+    void (*handler_6)(Monitor *mon, void *arg0, void *arg1, void *arg2,
+                      void *arg3, void *arg4, void *arg5);
+    void (*handler_7)(Monitor *mon, void *arg0, void *arg1, void *arg2,
+                      void *arg3, void *arg4, void *arg5, void *arg6);
 
 #ifdef DEBUG
-    term_printf("command='%s'\n", cmdline);
+    monitor_printf(mon, "command='%s'\n", cmdline);
 #endif
 
     /* extract the command name */
-    p = cmdline;
-    q = cmdname;
-    while (isspace(*p))
-        p++;
-    if (*p == '\0')
+    p = get_command_name(cmdline, cmdname, sizeof(cmdname));
+    if (!p)
         return;
-    pstart = p;
-    while (*p != '\0' && *p != '/' && !isspace(*p))
-        p++;
-    len = p - pstart;
-    if (len > sizeof(cmdname) - 1)
-        len = sizeof(cmdname) - 1;
-    memcpy(cmdname, pstart, len);
-    cmdname[len] = '\0';
 
     /* find the command */
-    for(cmd = term_cmds; cmd->name != NULL; cmd++) {
+    for(cmd = mon_cmds; cmd->name != NULL; cmd++) {
         if (compare_cmd(cmdname, cmd->name))
-            goto found;
+            break;
     }
-    term_printf("unknown command: '%s'\n", cmdname);
-    return;
- found:
+
+    if (cmd->name == NULL) {
+        monitor_printf(mon, "unknown command: '%s'\n", cmdname);
+        return;
+    }
 
     for(i = 0; i < MAX_ARGS; i++)
         str_allocated[i] = NULL;
@@ -2176,7 +2473,7 @@
                 int ret;
                 char *str;
 
-                while (isspace(*p))
+                while (qemu_isspace(*p))
                     p++;
                 if (*typestr == '?') {
                     typestr++;
@@ -2190,13 +2487,15 @@
                 if (ret < 0) {
                     switch(c) {
                     case 'F':
-                        term_printf("%s: filename expected\n", cmdname);
+                        monitor_printf(mon, "%s: filename expected\n",
+                                       cmdname);
                         break;
                     case 'B':
-                        term_printf("%s: block device name expected\n", cmdname);
+                        monitor_printf(mon, "%s: block device name expected\n",
+                                       cmdname);
                         break;
                     default:
-                        term_printf("%s: string expected\n", cmdname);
+                        monitor_printf(mon, "%s: string expected\n", cmdname);
                         break;
                     }
                     goto fail;
@@ -2207,7 +2506,7 @@
             add_str:
                 if (nb_args >= MAX_ARGS) {
                 error_args:
-                    term_printf("%s: too many arguments\n", cmdname);
+                    monitor_printf(mon, "%s: too many arguments\n", cmdname);
                     goto fail;
                 }
                 args[nb_args++] = str;
@@ -2217,15 +2516,15 @@
             {
                 int count, format, size;
 
-                while (isspace(*p))
+                while (qemu_isspace(*p))
                     p++;
                 if (*p == '/') {
                     /* format found */
                     p++;
                     count = 1;
-                    if (isdigit(*p)) {
+                    if (qemu_isdigit(*p)) {
                         count = 0;
-                        while (isdigit(*p)) {
+                        while (qemu_isdigit(*p)) {
                             count = count * 10 + (*p - '0');
                             p++;
                         }
@@ -2264,8 +2563,9 @@
                         }
                     }
                 next:
-                    if (*p != '\0' && !isspace(*p)) {
-                        term_printf("invalid char in format: '%c'\n", *p);
+                    if (*p != '\0' && !qemu_isspace(*p)) {
+                        monitor_printf(mon, "invalid char in format: '%c'\n",
+                                       *p);
                         goto fail;
                     }
                     if (format < 0)
@@ -2274,8 +2574,8 @@
                         /* for 'i', not specifying a size gives -1 as size */
                         if (size < 0)
                             size = default_fmt_size;
+                        default_fmt_size = size;
                     }
-                    default_fmt_size = size;
                     default_fmt_format = format;
                 } else {
                     count = 1;
@@ -2298,7 +2598,7 @@
             {
                 int64_t val;
 
-                while (isspace(*p))
+                while (qemu_isspace(*p))
                     p++;
                 if (*typestr == '?' || *typestr == '.') {
                     if (*typestr == '?') {
@@ -2309,7 +2609,7 @@
                     } else {
                         if (*p == '.') {
                             p++;
-                            while (isspace(*p))
+                            while (qemu_isspace(*p))
                                 p++;
                             has_arg = 1;
                         } else {
@@ -2327,7 +2627,7 @@
                         goto add_num;
                     }
                 }
-                if (get_expr(&val, &p))
+                if (get_expr(mon, &val, &p))
                     goto fail;
             add_num:
                 if (c == 'i') {
@@ -2354,14 +2654,14 @@
                 c = *typestr++;
                 if (c == '\0')
                     goto bad_type;
-                while (isspace(*p))
+                while (qemu_isspace(*p))
                     p++;
                 has_option = 0;
                 if (*p == '-') {
                     p++;
                     if (*p != c) {
-                        term_printf("%s: unsupported option -%c\n",
-                                    cmdname, *p);
+                        monitor_printf(mon, "%s: unsupported option -%c\n",
+                                       cmdname, *p);
                         goto fail;
                     }
                     p++;
@@ -2374,60 +2674,60 @@
             break;
         default:
         bad_type:
-            term_printf("%s: unknown type '%c'\n", cmdname, c);
+            monitor_printf(mon, "%s: unknown type '%c'\n", cmdname, c);
             goto fail;
         }
     }
     /* check that all arguments were parsed */
-    while (isspace(*p))
+    while (qemu_isspace(*p))
         p++;
     if (*p != '\0') {
-        term_printf("%s: extraneous characters at the end of line\n",
-                    cmdname);
+        monitor_printf(mon, "%s: extraneous characters at the end of line\n",
+                       cmdname);
         goto fail;
     }
 
     switch(nb_args) {
     case 0:
         handler_0 = cmd->handler;
-        handler_0();
+        handler_0(mon);
         break;
     case 1:
         handler_1 = cmd->handler;
-        handler_1(args[0]);
+        handler_1(mon, args[0]);
         break;
     case 2:
         handler_2 = cmd->handler;
-        handler_2(args[0], args[1]);
+        handler_2(mon, args[0], args[1]);
         break;
     case 3:
         handler_3 = cmd->handler;
-        handler_3(args[0], args[1], args[2]);
+        handler_3(mon, args[0], args[1], args[2]);
         break;
     case 4:
         handler_4 = cmd->handler;
-        handler_4(args[0], args[1], args[2], args[3]);
+        handler_4(mon, args[0], args[1], args[2], args[3]);
         break;
     case 5:
         handler_5 = cmd->handler;
-        handler_5(args[0], args[1], args[2], args[3], args[4]);
+        handler_5(mon, args[0], args[1], args[2], args[3], args[4]);
         break;
     case 6:
         handler_6 = cmd->handler;
-        handler_6(args[0], args[1], args[2], args[3], args[4], args[5]);
+        handler_6(mon, args[0], args[1], args[2], args[3], args[4], args[5]);
         break;
     case 7:
         handler_7 = cmd->handler;
-        handler_7(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
+        handler_7(mon, args[0], args[1], args[2], args[3], args[4], args[5],
+                  args[6]);
         break;
     default:
-        term_printf("unsupported number of arguments: %d\n", nb_args);
+        monitor_printf(mon, "unsupported number of arguments: %d\n", nb_args);
         goto fail;
     }
  fail:
     for(i = 0; i < MAX_ARGS; i++)
         qemu_free(str_allocated[i]);
-    return;
 }
 
 static void cmd_completion(const char *name, const char *list)
@@ -2448,7 +2748,7 @@
         memcpy(cmd, pstart, len);
         cmd[len] = '\0';
         if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
-            add_completion(cmd);
+            readline_add_completion(cur_mon->rs, cmd);
         }
         if (*p == '\0')
             break;
@@ -2479,7 +2779,8 @@
         pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
     }
 #ifdef DEBUG_COMPLETION
-    term_printf("input='%s' path='%s' prefix='%s'\n", input, path, file_prefix);
+    monitor_printf(cur_mon, "input='%s' path='%s' prefix='%s'\n",
+                   input, path, file_prefix);
 #endif
     ffs = opendir(path);
     if (!ffs)
@@ -2500,19 +2801,20 @@
             stat(file, &sb);
             if(S_ISDIR(sb.st_mode))
                 pstrcat(file, sizeof(file), "/");
-            add_completion(file);
+            readline_add_completion(cur_mon->rs, file);
         }
     }
     closedir(ffs);
 }
 
-static void block_completion_it(void *opaque, const char *name)
+static void block_completion_it(void *opaque, BlockDriverState *bs)
 {
+    const char *name = bdrv_get_device_name(bs);
     const char *input = opaque;
 
     if (input[0] == '\0' ||
         !strncmp(name, (char *)input, strlen(input))) {
-        add_completion(name);
+        readline_add_completion(cur_mon->rs, name);
     }
 }
 
@@ -2527,7 +2829,7 @@
     p = cmdline;
     nb_args = 0;
     for(;;) {
-        while (isspace(*p))
+        while (qemu_isspace(*p))
             p++;
         if (*p == '\0')
             break;
@@ -2542,26 +2844,26 @@
     *pnb_args = nb_args;
 }
 
-void readline_find_completion(const char *cmdline)
+static void monitor_find_completion(const char *cmdline)
 {
     const char *cmdname;
     char *args[MAX_ARGS];
     int nb_args, i, len;
     const char *ptype, *str;
-    term_cmd_t *cmd;
+    const mon_cmd_t *cmd;
     const KeyDef *key;
 
     parse_cmdline(cmdline, &nb_args, args);
 #ifdef DEBUG_COMPLETION
     for(i = 0; i < nb_args; i++) {
-        term_printf("arg%d = '%s'\n", i, (char *)args[i]);
+        monitor_printf(cur_mon, "arg%d = '%s'\n", i, (char *)args[i]);
     }
 #endif
 
     /* if the line ends with a space, it means we want to complete the
        next arg */
     len = strlen(cmdline);
-    if (len > 0 && isspace(cmdline[len - 1])) {
+    if (len > 0 && qemu_isspace(cmdline[len - 1])) {
         if (nb_args >= MAX_ARGS)
             return;
         args[nb_args++] = qemu_strdup("");
@@ -2572,13 +2874,13 @@
             cmdname = "";
         else
             cmdname = args[0];
-        completion_index = strlen(cmdname);
-        for(cmd = term_cmds; cmd->name != NULL; cmd++) {
+        readline_set_completion_index(cur_mon->rs, strlen(cmdname));
+        for(cmd = mon_cmds; cmd->name != NULL; cmd++) {
             cmd_completion(cmdname, cmd->name);
         }
     } else {
         /* find the command */
-        for(cmd = term_cmds; cmd->name != NULL; cmd++) {
+        for(cmd = mon_cmds; cmd->name != NULL; cmd++) {
             if (compare_cmd(args[0], cmd->name))
                 goto found;
         }
@@ -2596,23 +2898,26 @@
         switch(*ptype) {
         case 'F':
             /* file completion */
-            completion_index = strlen(str);
+            readline_set_completion_index(cur_mon->rs, strlen(str));
             file_completion(str);
             break;
         case 'B':
             /* block device name completion */
-            completion_index = strlen(str);
+            readline_set_completion_index(cur_mon->rs, strlen(str));
             bdrv_iterate(block_completion_it, (void *)str);
             break;
         case 's':
             /* XXX: more generic ? */
             if (!strcmp(cmd->name, "info")) {
-                completion_index = strlen(str);
+                readline_set_completion_index(cur_mon->rs, strlen(str));
                 for(cmd = info_cmds; cmd->name != NULL; cmd++) {
                     cmd_completion(str, cmd->name);
                 }
             } else if (!strcmp(cmd->name, "sendkey")) {
-                completion_index = strlen(str);
+                char *sep = strrchr(str, '-');
+                if (sep)
+                    str = sep + 1;
+                readline_set_completion_index(cur_mon->rs, strlen(str));
                 for(key = key_defs; key->name != NULL; key++) {
                     cmd_completion(str, key->name);
                 }
@@ -2626,111 +2931,156 @@
         qemu_free(args[i]);
 }
 
-static int term_can_read(void *opaque)
+static int monitor_can_read(void *opaque)
 {
-    return 128;
+    Monitor *mon = opaque;
+
+    return (mon->suspend_cnt == 0) ? 128 : 0;
 }
 
-static void term_read(void *opaque, const uint8_t *buf, int size)
+static void monitor_read(void *opaque, const uint8_t *buf, int size)
 {
+    Monitor *old_mon = cur_mon;
     int i;
-    for(i = 0; i < size; i++)
-        readline_handle_byte(buf[i]);
+
+    cur_mon = opaque;
+
+    if (cur_mon->rs) {
+        for (i = 0; i < size; i++)
+            readline_handle_byte(cur_mon->rs, buf[i]);
+    } else {
+        if (size == 0 || buf[size - 1] != 0)
+            monitor_printf(cur_mon, "corrupted command\n");
+        else
+            monitor_handle_command(cur_mon, (char *)buf);
+    }
+
+    cur_mon = old_mon;
 }
 
-static void monitor_start_input(void);
-
-static void monitor_handle_command1(void *opaque, const char *cmdline)
+static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque)
 {
-    monitor_handle_command(cmdline);
-    monitor_start_input();
+    monitor_suspend(mon);
+    monitor_handle_command(mon, cmdline);
+    monitor_resume(mon);
 }
 
-static void monitor_start_input(void)
+int monitor_suspend(Monitor *mon)
 {
-    readline_start("(qemu) ", 0, monitor_handle_command1, NULL);
+    if (!mon->rs)
+        return -ENOTTY;
+    mon->suspend_cnt++;
+    return 0;
 }
 
-static void term_event(void *opaque, int event)
+void monitor_resume(Monitor *mon)
 {
-    if (event != CHR_EVENT_RESET)
-	return;
-
-    if (!hide_banner)
-	    term_printf("QEMU %s monitor - type 'help' for more information\n",
-			QEMU_VERSION);
-    monitor_start_input();
+    if (!mon->rs)
+        return;
+    if (--mon->suspend_cnt == 0)
+        readline_show_prompt(mon->rs);
 }
 
-static int is_first_init = 1;
-
-void monitor_init(CharDriverState *hd, int show_banner)
+static void monitor_event(void *opaque, int event)
 {
-    int i;
+    Monitor *mon = opaque;
+
+    switch (event) {
+    case CHR_EVENT_MUX_IN:
+        readline_restart(mon->rs);
+        monitor_resume(mon);
+        monitor_flush(mon);
+        break;
+
+    case CHR_EVENT_MUX_OUT:
+        if (mon->suspend_cnt == 0)
+            monitor_printf(mon, "\n");
+        monitor_flush(mon);
+        monitor_suspend(mon);
+        break;
+
+    case CHR_EVENT_RESET:
+        monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
+                       "information\n", QEMU_VERSION);
+        if (mon->chr->focus == 0)
+            readline_show_prompt(mon->rs);
+        break;
+    }
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ * End:
+ */
+
+void monitor_init(CharDriverState *chr, int flags)
+{
+    static int is_first_init = 1;
+    Monitor *mon;
 
     if (is_first_init) {
         key_timer = qemu_new_timer(vm_clock, release_keys, NULL);
-        if (!key_timer)
-            return;
-        for (i = 0; i < MAX_MON; i++) {
-            monitor_hd[i] = NULL;
-        }
         is_first_init = 0;
     }
-    for (i = 0; i < MAX_MON; i++) {
-        if (monitor_hd[i] == NULL) {
-            monitor_hd[i] = hd;
-            break;
-        }
+
+    mon = qemu_mallocz(sizeof(*mon));
+
+    mon->chr = chr;
+    mon->flags = flags;
+    if (mon->chr->focus != 0)
+        mon->suspend_cnt = 1; /* mux'ed monitors start suspended */
+    if (flags & MONITOR_USE_READLINE) {
+        mon->rs = readline_init(mon, monitor_find_completion);
+        monitor_read_command(mon, 0);
     }
 
-    hide_banner = !show_banner;
+    qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, monitor_event,
+                          mon);
 
-    qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL);
-
-    readline_start("", 0, monitor_handle_command1, NULL);
+    LIST_INSERT_HEAD(&mon_list, mon, entry);
+    if (!cur_mon || (flags & MONITOR_IS_DEFAULT))
+        cur_mon = mon;
 }
 
-/* XXX: use threads ? */
-/* modal monitor readline */
-static int monitor_readline_started;
-static char *monitor_readline_buf;
-static int monitor_readline_buf_size;
-
-static void monitor_readline_cb(void *opaque, const char *input)
+static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
 {
-    pstrcpy(monitor_readline_buf, monitor_readline_buf_size, input);
-    monitor_readline_started = 0;
+    BlockDriverState *bs = opaque;
+    int ret = 0;
+
+    if (bdrv_set_key(bs, password) != 0) {
+        monitor_printf(mon, "invalid password\n");
+        ret = -EPERM;
+    }
+    if (mon->password_completion_cb)
+        mon->password_completion_cb(mon->password_opaque, ret);
+
+    monitor_read_command(mon, 1);
 }
 
-void monitor_readline(const char *prompt, int is_password,
-                      char *buf, int buf_size)
+void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+                                 BlockDriverCompletionFunc *completion_cb,
+                                 void *opaque)
 {
-    int i;
-    int old_focus[MAX_MON];
+    int err;
 
-    if (is_password) {
-        for (i = 0; i < MAX_MON; i++) {
-            old_focus[i] = 0;
-            if (monitor_hd[i]) {
-                old_focus[i] = monitor_hd[i]->focus;
-                monitor_hd[i]->focus = 0;
-                qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS);
-            }
-        }
+    if (!bdrv_key_required(bs)) {
+        if (completion_cb)
+            completion_cb(opaque, 0);
+        return;
     }
 
-    readline_start(prompt, is_password, monitor_readline_cb, NULL);
-    monitor_readline_buf = buf;
-    monitor_readline_buf_size = buf_size;
-    monitor_readline_started = 1;
-    while (monitor_readline_started) {
-        main_loop_wait(10);
-    }
-    /* restore original focus */
-    if (is_password) {
-        for (i = 0; i < MAX_MON; i++)
-            if (old_focus[i])
-                monitor_hd[i]->focus = old_focus[i];
-    }
+    monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
+                   bdrv_get_encrypted_filename(bs));
+
+    mon->password_completion_cb = completion_cb;
+    mon->password_opaque = opaque;
+
+    err = monitor_read_password(mon, bdrv_password_cb, bs);
+
+    if (err && completion_cb)
+        completion_cb(opaque, err);
 }
diff --git a/monitor.h b/monitor.h
new file mode 100644
index 0000000..13e8cc7
--- /dev/null
+++ b/monitor.h
@@ -0,0 +1,29 @@
+#ifndef MONITOR_H
+#define MONITOR_H
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "block.h"
+
+extern Monitor *cur_mon;
+
+/* flags for monitor_init */
+#define MONITOR_IS_DEFAULT    0x01
+#define MONITOR_USE_READLINE  0x02
+
+void monitor_init(CharDriverState *chr, int flags);
+
+int monitor_suspend(Monitor *mon);
+void monitor_resume(Monitor *mon);
+
+void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+                                 BlockDriverCompletionFunc *completion_cb,
+                                 void *opaque);
+
+void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap);
+void monitor_printf(Monitor *mon, const char *fmt, ...)
+    __attribute__ ((__format__ (__printf__, 2, 3)));
+void monitor_print_filename(Monitor *mon, const char *filename);
+void monitor_flush(Monitor *mon);
+
+#endif /* !MONITOR_H */
diff --git a/net-android.c b/net-android.c
new file mode 100644
index 0000000..da01a61
--- /dev/null
+++ b/net-android.c
@@ -0,0 +1,2596 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+#include "tcpdump.h"
+
+/* Needed early for HOST_BSD etc. */
+#include "config-host.h"
+
+#ifndef _WIN32
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#ifdef __NetBSD__
+#include <net/if_tap.h>
+#endif
+#ifdef __linux__
+#include <linux/if_tun.h>
+#endif
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+#ifdef HOST_BSD
+#include <sys/stat.h>
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <libutil.h>
+#else
+#include <util.h>
+#endif
+#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+#include <freebsd/stdlib.h>
+#else
+#ifdef __linux__
+#include <pty.h>
+#include <malloc.h>
+#include <linux/rtc.h>
+
+/* For the benefit of older linux systems which don't supply it,
+   we use a local copy of hpet.h. */
+/* #include <linux/hpet.h> */
+#include "hpet.h"
+
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+#endif
+#ifdef __sun__
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
+#endif
+#endif
+#endif
+
+#if defined(__OpenBSD__)
+#include <util.h>
+#endif
+
+#if defined(CONFIG_VDE)
+#include <libvdeplug.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <malloc.h>
+#include <sys/timeb.h>
+#include <mmsystem.h>
+#define getopt_long_only getopt_long
+#define memalign(align, size) malloc(size)
+#endif
+
+#include "qemu-common.h"
+#include "net.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "audio/audio.h"
+#include "qemu_socket.h"
+#include "qemu-log.h"
+
+#if defined(CONFIG_SLIRP)
+#include "libslirp.h"
+#endif
+
+#if defined(CONFIG_SHAPER)
+#include "shaper.h"
+#endif
+
+static VLANState *first_vlan;
+
+/***********************************************************/
+/* network device redirectors */
+
+#if defined(DEBUG_NET) || defined(DEBUG_SLIRP)
+static void hex_dump(FILE *f, const uint8_t *buf, int size)
+{
+    int len, i, j, c;
+
+    for(i=0;i<size;i+=16) {
+        len = size - i;
+        if (len > 16)
+            len = 16;
+        fprintf(f, "%08x ", i);
+        for(j=0;j<16;j++) {
+            if (j < len)
+                fprintf(f, " %02x", buf[i+j]);
+            else
+                fprintf(f, "   ");
+        }
+        fprintf(f, " ");
+        for(j=0;j<len;j++) {
+            c = buf[i+j];
+            if (c < ' ' || c > '~')
+                c = '.';
+            fprintf(f, "%c", c);
+        }
+        fprintf(f, "\n");
+    }
+}
+#endif
+
+static int parse_macaddr(uint8_t *macaddr, const char *p)
+{
+    int i;
+    char *last_char;
+    long int offset;
+
+    errno = 0;
+    offset = strtol(p, &last_char, 0);    
+    if (0 == errno && '\0' == *last_char &&
+            offset >= 0 && offset <= 0xFFFFFF) {
+        macaddr[3] = (offset & 0xFF0000) >> 16;
+        macaddr[4] = (offset & 0xFF00) >> 8;
+        macaddr[5] = offset & 0xFF;
+        return 0;
+    } else {
+        for(i = 0; i < 6; i++) {
+            macaddr[i] = strtol(p, (char **)&p, 16);
+            if (i == 5) {
+                if (*p != '\0')
+                    return -1;
+            } else {
+                if (*p != ':' && *p != '-')
+                    return -1;
+                p++;
+            }
+        }
+        return 0;    
+    }
+
+    return -1;
+}
+
+static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
+{
+    const char *p, *p1;
+    int len;
+    p = *pp;
+    p1 = strchr(p, sep);
+    if (!p1)
+        return -1;
+    len = p1 - p;
+    p1++;
+    if (buf_size > 0) {
+        if (len > buf_size - 1)
+            len = buf_size - 1;
+        memcpy(buf, p, len);
+        buf[len] = '\0';
+    }
+    *pp = p1;
+    return 0;
+}
+
+int parse_host_src_port(SockAddress *haddr,
+                        SockAddress *saddr,
+                        const char *input_str)
+{
+    char *str = strdup(input_str);
+    char *host_str = str;
+    char *src_str;
+    const char *src_str2;
+    char *ptr;
+
+    /*
+     * Chop off any extra arguments at the end of the string which
+     * would start with a comma, then fill in the src port information
+     * if it was provided else use the "any address" and "any port".
+     */
+    if ((ptr = strchr(str,',')))
+        *ptr = '\0';
+
+    if ((src_str = strchr(input_str,'@'))) {
+        *src_str = '\0';
+        src_str++;
+    }
+
+    if (parse_host_port(haddr, host_str) < 0)
+        goto fail;
+
+    src_str2 = src_str;
+    if (!src_str || *src_str == '\0')
+        src_str2 = ":0";
+
+    if (parse_host_port(saddr, src_str2) < 0)
+        goto fail;
+
+    free(str);
+    return(0);
+
+fail:
+    free(str);
+    return -1;
+}
+
+int parse_host_port(SockAddress *saddr, const char *str)
+{
+    char buf[512];
+    const char *p, *r;
+    uint32_t ip;
+    int port;
+
+    p = str;
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+        return -1;
+
+    if (buf[0] == '\0') {
+        ip = 0;
+    } else {
+        if (qemu_isdigit(buf[0])) {
+            if (inet_strtoip(buf, &ip) < 0)
+                return -1;
+        } else {
+            if (sock_address_init_resolve(saddr, buf, 0, 0) < 0)
+                return - 1;
+            ip = sock_address_get_ip(saddr);
+        }
+    }
+    port = strtol(p, (char **)&r, 0);
+    if (r == p)
+        return -1;
+    sock_address_init_inet(saddr, ip, port);
+    return 0;
+}
+
+#if !defined(_WIN32) && 0
+static int parse_unix_path(struct sockaddr_un *uaddr, const char *str)
+{
+    const char *p;
+    int len;
+
+    len = MIN(108, strlen(str));
+    p = strchr(str, ',');
+    if (p)
+	len = MIN(len, p - str);
+
+    memset(uaddr, 0, sizeof(*uaddr));
+
+    uaddr->sun_family = AF_UNIX;
+    memcpy(uaddr->sun_path, str, len);
+
+    return 0;
+}
+#endif
+
+void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6])
+{
+    snprintf(vc->info_str, sizeof(vc->info_str),
+             "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+             vc->model,
+             macaddr[0], macaddr[1], macaddr[2],
+             macaddr[3], macaddr[4], macaddr[5]);
+}
+
+static char *assign_name(VLANClientState *vc1, const char *model)
+{
+    VLANState *vlan;
+    char buf[256];
+    int id = 0;
+
+    for (vlan = first_vlan; vlan; vlan = vlan->next) {
+        VLANClientState *vc;
+
+        for (vc = vlan->first_client; vc; vc = vc->next)
+            if (vc != vc1 && strcmp(vc->model, model) == 0)
+                id++;
+    }
+
+    snprintf(buf, sizeof(buf), "%s.%d", model, id);
+
+    return strdup(buf);
+}
+
+VLANClientState *qemu_new_vlan_client(VLANState *vlan,
+                                      const char *model,
+                                      const char *name,
+                                      NetCanReceive *can_receive,
+                                      NetReceive *receive,
+                                      NetReceiveIOV *receive_iov,
+                                      NetCleanup *cleanup,
+                                      void *opaque)
+{
+    VLANClientState *vc, **pvc;
+    vc = qemu_mallocz(sizeof(VLANClientState));
+    vc->model = strdup(model);
+    if (name)
+        vc->name = strdup(name);
+    else
+        vc->name = assign_name(vc, model);
+    vc->can_receive = can_receive;
+    vc->receive = receive;
+    vc->receive_iov = receive_iov;
+    vc->cleanup = cleanup;
+    vc->opaque = opaque;
+    vc->vlan = vlan;
+
+    vc->next = NULL;
+    pvc = &vlan->first_client;
+    while (*pvc != NULL)
+        pvc = &(*pvc)->next;
+    *pvc = vc;
+    return vc;
+}
+
+void qemu_del_vlan_client(VLANClientState *vc)
+{
+    VLANClientState **pvc = &vc->vlan->first_client;
+
+    while (*pvc != NULL)
+        if (*pvc == vc) {
+            *pvc = vc->next;
+            if (vc->cleanup) {
+                vc->cleanup(vc);
+            }
+            free(vc->name);
+            free(vc->model);
+            qemu_free(vc);
+            break;
+        } else
+            pvc = &(*pvc)->next;
+}
+
+VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque)
+{
+    VLANClientState **pvc = &vlan->first_client;
+
+    while (*pvc != NULL)
+        if ((*pvc)->opaque == opaque)
+            return *pvc;
+        else
+            pvc = &(*pvc)->next;
+
+    return NULL;
+}
+
+int qemu_can_send_packet(VLANClientState *sender)
+{
+    VLANState *vlan = sender->vlan;
+    VLANClientState *vc;
+
+    for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
+        if (vc == sender) {
+            continue;
+        }
+
+        /* no can_receive() handler, they can always receive */
+        if (!vc->can_receive || vc->can_receive(vc)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int
+qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size)
+{
+    VLANClientState *vc;
+    int ret = -1;
+
+    sender->vlan->delivering = 1;
+
+    for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) {
+        ssize_t len;
+
+        if (vc == sender) {
+            continue;
+        }
+
+        if (vc->link_down) {
+            ret = size;
+            continue;
+        }
+
+        len = vc->receive(vc, buf, size);
+
+        ret = (ret >= 0) ? ret : len;
+    }
+
+    sender->vlan->delivering = 0;
+
+    return ret;
+}
+
+void qemu_flush_queued_packets(VLANClientState *vc)
+{
+    VLANPacket *packet;
+
+    while ((packet = vc->vlan->send_queue) != NULL) {
+        int ret;
+
+        vc->vlan->send_queue = packet->next;
+
+        ret = qemu_deliver_packet(packet->sender, packet->data, packet->size);
+        if (ret == 0 && packet->sent_cb != NULL) {
+            packet->next = vc->vlan->send_queue;
+            vc->vlan->send_queue = packet;
+            break;
+        }
+
+        if (packet->sent_cb)
+            packet->sent_cb(packet->sender);
+
+        qemu_free(packet);
+    }
+}
+
+static void qemu_enqueue_packet(VLANClientState *sender,
+                                const uint8_t *buf, int size,
+                                NetPacketSent *sent_cb)
+{
+    VLANPacket *packet;
+
+    packet = qemu_malloc(sizeof(VLANPacket) + size);
+    packet->next = sender->vlan->send_queue;
+    packet->sender = sender;
+    packet->size = size;
+    packet->sent_cb = sent_cb;
+    memcpy(packet->data, buf, size);
+    sender->vlan->send_queue = packet;
+}
+
+ssize_t qemu_send_packet_async(VLANClientState *sender,
+                               const uint8_t *buf, int size,
+                               NetPacketSent *sent_cb)
+{
+    int ret;
+
+    if (sender->link_down) {
+        return size;
+    }
+
+#ifdef DEBUG_NET
+    printf("vlan %d send:\n", sender->vlan->id);
+    hex_dump(stdout, buf, size);
+#endif
+
+    if (sender->vlan->delivering) {
+        qemu_enqueue_packet(sender, buf, size, NULL);
+        return size;
+    }
+
+    ret = qemu_deliver_packet(sender, buf, size);
+    if (ret == 0 && sent_cb != NULL) {
+        qemu_enqueue_packet(sender, buf, size, sent_cb);
+        return 0;
+    }
+
+    qemu_flush_queued_packets(sender);
+
+    return ret;
+}
+
+void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
+{
+    qemu_send_packet_async(vc, buf, size, NULL);
+}
+
+static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
+                               int iovcnt)
+{
+    uint8_t buffer[4096];
+    size_t offset = 0;
+    int i;
+
+    for (i = 0; i < iovcnt; i++) {
+        size_t len;
+
+        len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
+        memcpy(buffer + offset, iov[i].iov_base, len);
+        offset += len;
+    }
+
+    return vc->receive(vc, buffer, offset);
+}
+
+static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
+{
+    size_t offset = 0;
+    int i;
+
+    for (i = 0; i < iovcnt; i++)
+        offset += iov[i].iov_len;
+    return offset;
+}
+
+static int qemu_deliver_packet_iov(VLANClientState *sender,
+                                   const struct iovec *iov, int iovcnt)
+{
+    VLANClientState *vc;
+    int ret = -1;
+
+    sender->vlan->delivering = 1;
+
+    for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) {
+        ssize_t len;
+
+        if (vc == sender) {
+            continue;
+        }
+
+        if (vc->link_down) {
+            ret = calc_iov_length(iov, iovcnt);
+            continue;
+        }
+
+        if (vc->receive_iov) {
+            len = vc->receive_iov(vc, iov, iovcnt);
+        } else {
+            len = vc_sendv_compat(vc, iov, iovcnt);
+        }
+
+        ret = (ret >= 0) ? ret : len;
+    }
+
+    sender->vlan->delivering = 0;
+
+    return ret;
+}
+
+static ssize_t qemu_enqueue_packet_iov(VLANClientState *sender,
+                                       const struct iovec *iov, int iovcnt,
+                                       NetPacketSent *sent_cb)
+{
+    VLANPacket *packet;
+    size_t max_len = 0;
+    int i;
+
+    max_len = calc_iov_length(iov, iovcnt);
+
+    packet = qemu_malloc(sizeof(VLANPacket) + max_len);
+    packet->next = sender->vlan->send_queue;
+    packet->sender = sender;
+    packet->sent_cb = sent_cb;
+    packet->size = 0;
+
+    for (i = 0; i < iovcnt; i++) {
+        size_t len = iov[i].iov_len;
+
+        memcpy(packet->data + packet->size, iov[i].iov_base, len);
+        packet->size += len;
+    }
+
+    sender->vlan->send_queue = packet;
+
+    return packet->size;
+}
+
+ssize_t qemu_sendv_packet_async(VLANClientState *sender,
+                                const struct iovec *iov, int iovcnt,
+                                NetPacketSent *sent_cb)
+{
+    int ret;
+
+    if (sender->link_down) {
+        return calc_iov_length(iov, iovcnt);
+    }
+
+    if (sender->vlan->delivering) {
+        return qemu_enqueue_packet_iov(sender, iov, iovcnt, NULL);
+    }
+
+    ret = qemu_deliver_packet_iov(sender, iov, iovcnt);
+    if (ret == 0 && sent_cb != NULL) {
+        qemu_enqueue_packet_iov(sender, iov, iovcnt, sent_cb);
+        return 0;
+    }
+
+    qemu_flush_queued_packets(sender);
+
+    return ret;
+}
+
+ssize_t
+qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt)
+{
+    return qemu_sendv_packet_async(vc, iov, iovcnt, NULL);
+}
+
+static void config_error(Monitor *mon, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    if (mon) {
+        monitor_vprintf(mon, fmt, ap);
+    } else {
+        fprintf(stderr, "qemu: ");
+        vfprintf(stderr, fmt, ap);
+        exit(1);
+    }
+    va_end(ap);
+}
+
+#if defined(CONFIG_SLIRP)
+
+/* slirp network adapter */
+
+struct slirp_config_str {
+    struct slirp_config_str *next;
+    const char *str;
+};
+
+static int slirp_inited;
+static struct slirp_config_str *slirp_redirs;
+#ifndef _WIN32
+static const char *slirp_smb_export;
+#endif
+static VLANClientState *slirp_vc;
+
+#ifndef _WIN32
+static void slirp_smb(const char *exported_dir);
+#endif
+static void slirp_redirection(Monitor *mon, const char *redir_str);
+
+double   qemu_net_upload_speed   = 0.;
+double   qemu_net_download_speed = 0.;
+int      qemu_net_min_latency = 0;
+int      qemu_net_max_latency = 0;
+int      qemu_net_disable = 0;
+
+int
+ip_packet_is_internal( const uint8_t*  data, size_t  size )
+{
+    const uint8_t*  end = data + size;
+
+    /* must have room for Mac + IP header */
+    if (data + 40 > end)
+        return 0;
+
+    if (data[12] != 0x08 || data[13] != 0x00 )
+        return 0;
+
+    /* must have valid IP header */
+    data += 14;
+    if ((data[0] >> 4) != 4 || (data[0] & 15) < 5)
+        return 0;
+
+    /* internal if both source and dest addresses are in 10.x.x.x */
+    return ( data[12] == 10 && data[16] == 10);
+}
+
+#ifdef CONFIG_SHAPER
+
+NetShaper  slirp_shaper_in;
+NetShaper  slirp_shaper_out;
+NetDelay   slirp_delay_in;
+
+static void
+slirp_delay_in_cb( void*   data,
+                   size_t  size,
+                   void*   opaque )
+{
+    slirp_input( (const uint8_t*)data, (int)size );
+    opaque = opaque;
+}
+
+static void
+slirp_shaper_in_cb( void*   data,
+                    size_t  size,
+                    void*   opaque )
+{
+    netdelay_send_aux( slirp_delay_in, data, size, opaque );
+}
+
+static void
+slirp_shaper_out_cb( void*   data,
+                     size_t  size,
+                     void*   opaque )
+{
+    qemu_send_packet( slirp_vc, (const uint8_t*)data, (int)size );
+}
+
+void
+slirp_init_shapers( void )
+{
+    slirp_delay_in   = netdelay_create( slirp_delay_in_cb );
+    slirp_shaper_in  = netshaper_create( 1, slirp_shaper_in_cb );
+    slirp_shaper_out = netshaper_create( 1, slirp_shaper_out_cb );
+
+    netdelay_set_latency( slirp_delay_in, qemu_net_min_latency, qemu_net_max_latency );
+    netshaper_set_rate( slirp_shaper_out, qemu_net_download_speed );
+    netshaper_set_rate( slirp_shaper_in,  qemu_net_upload_speed  );
+}
+
+#endif /* CONFIG_SHAPER */
+
+
+int slirp_can_output(void)
+{
+    return !slirp_vc || qemu_can_send_packet(slirp_vc);
+}
+
+void slirp_output(const uint8_t *pkt, int pkt_len)
+{
+#ifdef DEBUG_SLIRP
+    printf("slirp output:\n");
+    hex_dump(stdout, pkt, pkt_len);
+#endif
+    if (qemu_tcpdump_active)
+        qemu_tcpdump_packet(pkt, pkt_len);
+
+    if (!slirp_vc)
+        return;
+    qemu_send_packet(slirp_vc, pkt, pkt_len);
+}
+
+int slirp_is_inited(void)
+{
+    return slirp_inited;
+}
+
+static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+#ifdef DEBUG_SLIRP
+    printf("slirp input:\n");
+    hex_dump(stdout, buf, size);
+#endif
+    if (qemu_tcpdump_active)
+        qemu_tcpdump_packet(buf, size);
+
+    slirp_input(buf, size);
+    return size;
+}
+
+static int slirp_in_use;
+
+static void net_slirp_cleanup(VLANClientState *vc)
+{
+    slirp_in_use = 0;
+}
+
+static int net_slirp_init(VLANState *vlan, const char *model, const char *name,
+                          int restricted, const char *ip)
+{
+    if (slirp_in_use) {
+        /* slirp only supports a single instance so far */
+        return -1;
+    }
+    if (!slirp_inited) {
+        slirp_inited = 1;
+        slirp_init(restricted, ip);
+
+        while (slirp_redirs) {
+            struct slirp_config_str *config = slirp_redirs;
+
+            slirp_redirection(NULL, config->str);
+            slirp_redirs = config->next;
+            qemu_free(config);
+        }
+#ifndef _WIN32
+        if (slirp_smb_export) {
+            slirp_smb(slirp_smb_export);
+        }
+#endif
+        slirp_init_shapers();
+    }
+
+    slirp_vc = qemu_new_vlan_client(vlan, model, name, NULL, slirp_receive,
+                                    NULL, net_slirp_cleanup, NULL);
+    slirp_vc->info_str[0] = '\0';
+    slirp_in_use = 1;
+    return 0;
+}
+
+static void net_slirp_redir_print(void *opaque, int is_udp,
+                                  const SockAddress *laddr,
+                                  const SockAddress *faddr)
+{
+    Monitor *mon = (Monitor *)opaque;
+    uint32_t h_addr;
+    uint32_t g_addr;
+    char buf[16];
+
+    h_addr = sock_address_get_ip(faddr);
+    g_addr = sock_address_get_ip(laddr);
+
+    monitor_printf(mon, "  %s |", is_udp ? "udp" : "tcp" );
+    snprintf(buf, 15, "%d.%d.%d.%d", (h_addr >> 24) & 0xff,
+                                     (h_addr >> 16) & 0xff,
+                                     (h_addr >> 8) & 0xff,
+                                     (h_addr) & 0xff);
+    monitor_printf(mon, " %15s |", buf);
+    monitor_printf(mon, " %5d |", sock_address_get_port(faddr));
+
+    snprintf(buf, 15, "%d.%d.%d.%d", (g_addr >> 24) & 0xff,
+                                     (g_addr >> 16) & 0xff,
+                                     (g_addr >> 8) & 0xff,
+                                     (g_addr) & 0xff);
+    monitor_printf(mon, " %15s |", buf);
+    monitor_printf(mon, " %5d\n", sock_address_get_port(laddr));
+
+}
+
+static void net_slirp_redir_list(Monitor *mon)
+{
+    if (!mon)
+        return;
+
+    monitor_printf(mon, " Prot |    Host Addr    | HPort |    Guest Addr   | GPort\n");
+    monitor_printf(mon, "      |                 |       |                 |      \n");
+    slirp_redir_loop(net_slirp_redir_print, mon);
+}
+
+static void net_slirp_redir_rm(Monitor *mon, const char *port_str)
+{
+    int host_port;
+    char buf[256] = "";
+    const char *p = port_str;
+    int is_udp = 0;
+    int n;
+
+    if (!mon)
+        return;
+
+    if (!port_str || !port_str[0])
+        goto fail_syntax;
+
+    get_str_sep(buf, sizeof(buf), &p, ':');
+
+    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+        is_udp = 0;
+    } else if (!strcmp(buf, "udp")) {
+        is_udp = 1;
+    } else {
+        goto fail_syntax;
+    }
+
+    host_port = atoi(p);
+
+    n = slirp_redir_rm(is_udp, host_port);
+
+    monitor_printf(mon, "removed %d redirections to %s port %d\n", n,
+                        is_udp ? "udp" : "tcp", host_port);
+    return;
+
+ fail_syntax:
+    monitor_printf(mon, "invalid format\n");
+}
+
+static void slirp_redirection(Monitor *mon, const char *redir_str)
+{
+    uint32_t guest_addr;
+    int host_port, guest_port;
+    const char *p;
+    char buf[256], *r;
+    int is_udp;
+
+    p = redir_str;
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+        is_udp = 0;
+    } else if (!strcmp(buf, "udp")) {
+        is_udp = 1;
+    } else {
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    host_port = strtol(buf, &r, 0);
+    if (r == buf) {
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    if (buf[0] == '\0') {
+        pstrcpy(buf, sizeof(buf), "10.0.2.15");
+    }
+    if (inet_strtoip(buf, &guest_addr) < 0) {
+        goto fail_syntax;
+    }
+
+    guest_port = strtol(p, &r, 0);
+    if (r == p) {
+        goto fail_syntax;
+    }
+
+    if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) {
+        config_error(mon, "could not set up redirection '%s'\n", redir_str);
+    }
+    return;
+
+ fail_syntax:
+    config_error(mon, "invalid redirection format '%s'\n", redir_str);
+}
+
+void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2)
+{
+    struct slirp_config_str *config;
+
+    if (!slirp_inited) {
+        if (mon) {
+            monitor_printf(mon, "user mode network stack not in use\n");
+        } else {
+            config = qemu_malloc(sizeof(*config));
+            config->str = redir_str;
+            config->next = slirp_redirs;
+            slirp_redirs = config;
+        }
+        return;
+    }
+
+    if (!strcmp(redir_str, "remove")) {
+        net_slirp_redir_rm(mon, redir_opt2);
+        return;
+    }
+
+    if (!strcmp(redir_str, "list")) {
+        net_slirp_redir_list(mon);
+        return;
+    }
+
+    slirp_redirection(mon, redir_str);
+}
+
+#ifndef _WIN32
+
+static char smb_dir[1024];
+
+static void erase_dir(char *dir_name)
+{
+    DIR *d;
+    struct dirent *de;
+    char filename[1024];
+
+    /* erase all the files in the directory */
+    if ((d = opendir(dir_name)) != NULL) {
+        for(;;) {
+            de = readdir(d);
+            if (!de)
+                break;
+            if (strcmp(de->d_name, ".") != 0 &&
+                strcmp(de->d_name, "..") != 0) {
+                snprintf(filename, sizeof(filename), "%s/%s",
+                         smb_dir, de->d_name);
+                if (unlink(filename) != 0)  /* is it a directory? */
+                    erase_dir(filename);
+            }
+        }
+        closedir(d);
+        rmdir(dir_name);
+    }
+}
+
+/* automatic user mode samba server configuration */
+static void smb_exit(void)
+{
+    erase_dir(smb_dir);
+}
+
+static void slirp_smb(const char *exported_dir)
+{
+    char smb_conf[1024];
+    char smb_cmdline[1024];
+    FILE *f;
+
+    /* XXX: better tmp dir construction */
+    snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%ld", (long)getpid());
+    if (mkdir(smb_dir, 0700) < 0) {
+        fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir);
+        exit(1);
+    }
+    snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf");
+
+    f = fopen(smb_conf, "w");
+    if (!f) {
+        fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf);
+        exit(1);
+    }
+    fprintf(f,
+            "[global]\n"
+            "private dir=%s\n"
+            "smb ports=0\n"
+            "socket address=127.0.0.1\n"
+            "pid directory=%s\n"
+            "lock directory=%s\n"
+            "log file=%s/log.smbd\n"
+            "smb passwd file=%s/smbpasswd\n"
+            "security = share\n"
+            "[qemu]\n"
+            "path=%s\n"
+            "read only=no\n"
+            "guest ok=yes\n",
+            smb_dir,
+            smb_dir,
+            smb_dir,
+            smb_dir,
+            smb_dir,
+            exported_dir
+            );
+    fclose(f);
+    atexit(smb_exit);
+
+    snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
+             SMBD_COMMAND, smb_conf);
+
+    slirp_add_exec(0, smb_cmdline, 4, 139);
+}
+
+/* automatic user mode samba server configuration */
+void net_slirp_smb(const char *exported_dir)
+{
+    if (slirp_smb_export) {
+        fprintf(stderr, "-smb given twice\n");
+        exit(1);
+    }
+    slirp_smb_export = exported_dir;
+    if (slirp_inited) {
+        slirp_smb(exported_dir);
+    }
+}
+
+#endif /* !defined(_WIN32) */
+
+void do_info_slirp(Monitor *mon)
+{
+    //slirp_stats();
+}
+
+struct VMChannel {
+    CharDriverState *hd;
+    int port;
+};
+
+static int vmchannel_can_read(void *opaque)
+{
+    struct VMChannel *vmc = (struct VMChannel*)opaque;
+    return slirp_socket_can_recv(4, vmc->port);
+}
+
+static void vmchannel_read(void *opaque, const uint8_t *buf, int size)
+{
+    struct VMChannel *vmc = (struct VMChannel*)opaque;
+    slirp_socket_recv(4, vmc->port, buf, size);
+}
+
+#endif /* CONFIG_SLIRP */
+
+#if !defined(_WIN32)
+
+typedef struct TAPState {
+    VLANClientState *vc;
+    int fd;
+    char down_script[1024];
+    char down_script_arg[128];
+    uint8_t buf[4096];
+} TAPState;
+
+static int launch_script(const char *setup_script, const char *ifname, int fd);
+
+static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
+                               int iovcnt)
+{
+    TAPState *s = vc->opaque;
+    ssize_t len;
+
+    do {
+        len = writev(s->fd, iov, iovcnt);
+    } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+
+    return len;
+}
+
+static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    TAPState *s = vc->opaque;
+    ssize_t len;
+
+    do {
+        len = write(s->fd, buf, size);
+    } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+
+    return len;
+}
+
+static int tap_can_send(void *opaque)
+{
+    TAPState *s = opaque;
+
+    return qemu_can_send_packet(s->vc);
+}
+
+#ifdef __sun__
+static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
+{
+    struct strbuf sbuf;
+    int f = 0;
+
+    sbuf.maxlen = maxlen;
+    sbuf.buf = (char *)buf;
+
+    return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
+}
+#else
+static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
+{
+    return read(tapfd, buf, maxlen);
+}
+#endif
+
+static void tap_send(void *opaque);
+
+static void tap_send_completed(VLANClientState *vc)
+{
+    TAPState *s = vc->opaque;
+
+    qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s);
+}
+
+static void tap_send(void *opaque)
+{
+    TAPState *s = opaque;
+    int size;
+
+    do {
+        size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
+        if (size <= 0) {
+            break;
+        }
+
+        size = qemu_send_packet_async(s->vc, s->buf, size, tap_send_completed);
+        if (size == 0) {
+            qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+        }
+    } while (size > 0);
+}
+
+static void tap_cleanup(VLANClientState *vc)
+{
+    TAPState *s = vc->opaque;
+
+    if (s->down_script[0])
+        launch_script(s->down_script, s->down_script_arg, s->fd);
+
+    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+    close(s->fd);
+    qemu_free(s);
+}
+
+/* fd support */
+
+static TAPState *net_tap_fd_init(VLANState *vlan,
+                                 const char *model,
+                                 const char *name,
+                                 int fd)
+{
+    TAPState *s;
+
+    s = qemu_mallocz(sizeof(TAPState));
+    s->fd = fd;
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive,
+                                 tap_receive_iov, tap_cleanup, s);
+    qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd);
+    return s;
+}
+
+#if defined (HOST_BSD) || defined (__FreeBSD_kernel__)
+static int tap_open(char *ifname, int ifname_size)
+{
+    int fd;
+    char *dev;
+    struct stat s;
+
+    TFR(fd = open("/dev/tap", O_RDWR));
+    if (fd < 0) {
+        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+        return -1;
+    }
+
+    fstat(fd, &s);
+    dev = devname(s.st_rdev, S_IFCHR);
+    pstrcpy(ifname, ifname_size, dev);
+
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+#elif defined(__sun__)
+#define TUNNEWPPA       (('T'<<16) | 0x0001)
+/*
+ * Allocate TAP device, returns opened fd.
+ * Stores dev name in the first arg(must be large enough).
+ */
+static int tap_alloc(char *dev, size_t dev_size)
+{
+    int tap_fd, if_fd, ppa = -1;
+    static int ip_fd = 0;
+    char *ptr;
+
+    static int arp_fd = 0;
+    int ip_muxid, arp_muxid;
+    struct strioctl  strioc_if, strioc_ppa;
+    int link_type = I_PLINK;;
+    struct lifreq ifr;
+    char actual_name[32] = "";
+
+    memset(&ifr, 0x0, sizeof(ifr));
+
+    if( *dev ){
+       ptr = dev;
+       while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++;
+       ppa = atoi(ptr);
+    }
+
+    /* Check if IP device was opened */
+    if( ip_fd )
+       close(ip_fd);
+
+    TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
+    if (ip_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
+       return -1;
+    }
+
+    TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
+    if (tap_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/tap");
+       return -1;
+    }
+
+    /* Assign a new PPA and get its unit number. */
+    strioc_ppa.ic_cmd = TUNNEWPPA;
+    strioc_ppa.ic_timout = 0;
+    strioc_ppa.ic_len = sizeof(ppa);
+    strioc_ppa.ic_dp = (char *)&ppa;
+    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
+       syslog (LOG_ERR, "Can't assign new interface");
+
+    TFR(if_fd = open("/dev/tap", O_RDWR, 0));
+    if (if_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/tap (2)");
+       return -1;
+    }
+    if(ioctl(if_fd, I_PUSH, "ip") < 0){
+       syslog(LOG_ERR, "Can't push IP module");
+       return -1;
+    }
+
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+	syslog(LOG_ERR, "Can't get flags\n");
+
+    snprintf (actual_name, 32, "tap%d", ppa);
+    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
+
+    ifr.lifr_ppa = ppa;
+    /* Assign ppa according to the unit number returned by tun device */
+
+    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
+        syslog (LOG_ERR, "Can't set PPA %d", ppa);
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+        syslog (LOG_ERR, "Can't get flags\n");
+    /* Push arp module to if_fd */
+    if (ioctl (if_fd, I_PUSH, "arp") < 0)
+        syslog (LOG_ERR, "Can't push ARP module (2)");
+
+    /* Push arp module to ip_fd */
+    if (ioctl (ip_fd, I_POP, NULL) < 0)
+        syslog (LOG_ERR, "I_POP failed\n");
+    if (ioctl (ip_fd, I_PUSH, "arp") < 0)
+        syslog (LOG_ERR, "Can't push ARP module (3)\n");
+    /* Open arp_fd */
+    TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
+    if (arp_fd < 0)
+       syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
+
+    /* Set ifname to arp */
+    strioc_if.ic_cmd = SIOCSLIFNAME;
+    strioc_if.ic_timout = 0;
+    strioc_if.ic_len = sizeof(ifr);
+    strioc_if.ic_dp = (char *)&ifr;
+    if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
+        syslog (LOG_ERR, "Can't set ifname to arp\n");
+    }
+
+    if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
+       syslog(LOG_ERR, "Can't link TAP device to IP");
+       return -1;
+    }
+
+    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
+        syslog (LOG_ERR, "Can't link TAP device to ARP");
+
+    close (if_fd);
+
+    memset(&ifr, 0x0, sizeof(ifr));
+    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
+    ifr.lifr_ip_muxid  = ip_muxid;
+    ifr.lifr_arp_muxid = arp_muxid;
+
+    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
+    {
+      ioctl (ip_fd, I_PUNLINK , arp_muxid);
+      ioctl (ip_fd, I_PUNLINK, ip_muxid);
+      syslog (LOG_ERR, "Can't set multiplexor id");
+    }
+
+    snprintf(dev, dev_size, "tap%d", ppa);
+    return tap_fd;
+}
+
+static int tap_open(char *ifname, int ifname_size)
+{
+    char  dev[10]="";
+    int fd;
+    if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){
+       fprintf(stderr, "Cannot allocate TAP device\n");
+       return -1;
+    }
+    pstrcpy(ifname, ifname_size, dev);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+#elif defined (_AIX)
+static int tap_open(char *ifname, int ifname_size)
+{
+    fprintf (stderr, "no tap on AIX\n");
+    return -1;
+}
+#else
+static int tap_open(char *ifname, int ifname_size)
+{
+    struct ifreq ifr;
+    int fd, ret;
+
+    TFR(fd = open("/dev/net/tun", O_RDWR));
+    if (fd < 0) {
+        fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
+        return -1;
+    }
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+    if (ifname[0] != '\0')
+        pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
+    else
+        pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
+    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+    if (ret != 0) {
+        fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
+        close(fd);
+        return -1;
+    }
+    pstrcpy(ifname, ifname_size, ifr.ifr_name);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+#endif
+
+static int launch_script(const char *setup_script, const char *ifname, int fd)
+{
+    sigset_t oldmask, mask;
+    int pid, status;
+    char *args[3];
+    char **parg;
+
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGCHLD);
+    sigprocmask(SIG_BLOCK, &mask, &oldmask);
+
+    /* try to launch network script */
+    pid = fork();
+    if (pid == 0) {
+        int open_max = sysconf(_SC_OPEN_MAX), i;
+
+        for (i = 0; i < open_max; i++) {
+            if (i != STDIN_FILENO &&
+                i != STDOUT_FILENO &&
+                i != STDERR_FILENO &&
+                i != fd) {
+                close(i);
+            }
+        }
+        parg = args;
+        *parg++ = (char *)setup_script;
+        *parg++ = (char *)ifname;
+        *parg++ = NULL;
+        execv(setup_script, args);
+        _exit(1);
+    } else if (pid > 0) {
+        while (waitpid(pid, &status, 0) != pid) {
+            /* loop */
+        }
+        sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+            return 0;
+        }
+    }
+    fprintf(stderr, "%s: could not launch network script\n", setup_script);
+    return -1;
+}
+
+static int net_tap_init(VLANState *vlan, const char *model,
+                        const char *name, const char *ifname1,
+                        const char *setup_script, const char *down_script)
+{
+    TAPState *s;
+    int fd;
+    char ifname[128];
+
+    if (ifname1 != NULL)
+        pstrcpy(ifname, sizeof(ifname), ifname1);
+    else
+        ifname[0] = '\0';
+    TFR(fd = tap_open(ifname, sizeof(ifname)));
+    if (fd < 0)
+        return -1;
+
+    if (!setup_script || !strcmp(setup_script, "no"))
+        setup_script = "";
+    if (setup_script[0] != '\0') {
+	if (launch_script(setup_script, ifname, fd))
+	    return -1;
+    }
+    s = net_tap_fd_init(vlan, model, name, fd);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "ifname=%s,script=%s,downscript=%s",
+             ifname, setup_script, down_script);
+    if (down_script && strcmp(down_script, "no")) {
+        snprintf(s->down_script, sizeof(s->down_script), "%s", down_script);
+        snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
+    }
+    return 0;
+}
+
+#endif /* !_WIN32 */
+
+#if defined(CONFIG_VDE)
+typedef struct VDEState {
+    VLANClientState *vc;
+    VDECONN *vde;
+} VDEState;
+
+static void vde_to_qemu(void *opaque)
+{
+    VDEState *s = opaque;
+    uint8_t buf[4096];
+    int size;
+
+    size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0);
+    if (size > 0) {
+        qemu_send_packet(s->vc, buf, size);
+    }
+}
+
+static ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    VDEState *s = vc->opaque;
+    ssize_t ret;
+
+    do {
+      ret = vde_send(s->vde, (const char *)buf, size, 0);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+static void vde_cleanup(VLANClientState *vc)
+{
+    VDEState *s = vc->opaque;
+    qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL);
+    vde_close(s->vde);
+    qemu_free(s);
+}
+
+static int net_vde_init(VLANState *vlan, const char *model,
+                        const char *name, const char *sock,
+                        int port, const char *group, int mode)
+{
+    VDEState *s;
+    char *init_group = strlen(group) ? (char *)group : NULL;
+    char *init_sock = strlen(sock) ? (char *)sock : NULL;
+
+    struct vde_open_args args = {
+        .port = port,
+        .group = init_group,
+        .mode = mode,
+    };
+
+    s = qemu_mallocz(sizeof(VDEState));
+    s->vde = vde_open(init_sock, (char *)"QEMU", &args);
+    if (!s->vde){
+        free(s);
+        return -1;
+    }
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, vde_receive,
+                                 NULL, vde_cleanup, s);
+    qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d",
+             sock, vde_datafd(s->vde));
+    return 0;
+}
+#endif
+
+/* network connection */
+typedef struct NetSocketState {
+    VLANClientState *vc;
+    int fd;
+    int state; /* 0 = getting length, 1 = getting data */
+    unsigned int index;
+    unsigned int packet_len;
+    uint8_t buf[4096];
+    SockAddress  dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
+} NetSocketState;
+
+typedef struct NetSocketListenState {
+    VLANState *vlan;
+    char *model;
+    char *name;
+    int fd;
+} NetSocketListenState;
+
+/* XXX: we consider we can send the whole packet without blocking */
+static ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    NetSocketState *s = vc->opaque;
+    uint32_t len;
+    len = htonl(size);
+
+    socket_send(s->fd, (const uint8_t *)&len, sizeof(len));
+    return socket_send(s->fd, buf, size);
+}
+
+static ssize_t net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    NetSocketState *s = vc->opaque;
+
+    return sendto(s->fd, (const void *)buf, size, 0,
+                  (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
+}
+
+static void net_socket_send(void *opaque)
+{
+    NetSocketState *s = opaque;
+    int size, err;
+    unsigned l;
+    uint8_t buf1[4096];
+    const uint8_t *buf;
+
+    size = recv(s->fd, (void *)buf1, sizeof(buf1), 0);
+    if (size < 0) {
+        err = socket_error();
+        if (err != EWOULDBLOCK)
+            goto eoc;
+    } else if (size == 0) {
+        /* end of connection */
+    eoc:
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+        return;
+    }
+    buf = buf1;
+    while (size > 0) {
+        /* reassemble a packet from the network */
+        switch(s->state) {
+        case 0:
+            l = 4 - s->index;
+            if (l > size)
+                l = size;
+            memcpy(s->buf + s->index, buf, l);
+            buf += l;
+            size -= l;
+            s->index += l;
+            if (s->index == 4) {
+                /* got length */
+                s->packet_len = ntohl(*(uint32_t *)s->buf);
+                s->index = 0;
+                s->state = 1;
+            }
+            break;
+        case 1:
+            l = s->packet_len - s->index;
+            if (l > size)
+                l = size;
+            if (s->index + l <= sizeof(s->buf)) {
+                memcpy(s->buf + s->index, buf, l);
+            } else {
+                fprintf(stderr, "serious error: oversized packet received,"
+                    "connection terminated.\n");
+                s->state = 0;
+                goto eoc;
+            }
+
+            s->index += l;
+            buf += l;
+            size -= l;
+            if (s->index >= s->packet_len) {
+                qemu_send_packet(s->vc, s->buf, s->packet_len);
+                s->index = 0;
+                s->state = 0;
+            }
+            break;
+        }
+    }
+}
+
+static void net_socket_send_dgram(void *opaque)
+{
+    NetSocketState *s = opaque;
+    int size;
+
+    size = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
+    if (size < 0)
+        return;
+    if (size == 0) {
+        /* end of connection */
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        return;
+    }
+    qemu_send_packet(s->vc, s->buf, size);
+}
+
+static int net_socket_mcast_create(SockAddress *mcastaddr)
+{
+    int fd;
+    int ret;
+    if (!IN_MULTICAST(sock_address_get_ip(mcastaddr))) {
+	fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
+		sock_address_to_string(mcastaddr),
+                sock_address_get_ip(mcastaddr));
+	return -1;
+
+    }
+    fd = socket_create_inet(SOCKET_DGRAM);
+    if (fd < 0) {
+        perror("socket(PF_INET, SOCK_DGRAM)");
+        return -1;
+    }
+
+    ret = socket_set_xreuseaddr(fd);
+    if (ret < 0) {
+	perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+	goto fail;
+    }
+
+    ret = socket_bind(fd, mcastaddr);
+    if (ret < 0) {
+        perror("bind");
+        goto fail;
+    }
+
+    /* Add host to multicast group */
+    ret = socket_mcast_inet_add_membership(fd, sock_address_get_ip(mcastaddr));
+    if (ret < 0) {
+	perror("setsockopt(IP_ADD_MEMBERSHIP)");
+	goto fail;
+    }
+
+    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+    ret = socket_mcast_inet_set_loop(fd, 1);
+    if (ret < 0) {
+	perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
+	goto fail;
+    }
+
+    socket_set_nonblock(fd);
+    return fd;
+fail:
+    if (fd >= 0)
+        socket_close(fd);
+    return -1;
+}
+
+static void net_socket_cleanup(VLANClientState *vc)
+{
+    NetSocketState *s = vc->opaque;
+    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+    socket_close(s->fd);
+    qemu_free(s);
+}
+
+static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
+                                                const char *model,
+                                                const char *name,
+                                                int fd, int is_connected)
+{
+    SockAddress  saddr;
+    int newfd;
+    NetSocketState *s;
+
+    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
+     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
+     * by ONLY ONE process: we must "clone" this dgram socket --jjo
+     */
+
+    if (is_connected) {
+	if (socket_get_address(fd, &saddr) == 0) {
+	    /* must be bound */
+	    if (sock_address_get_ip(&saddr) == 0) {
+		fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
+			fd);
+		return NULL;
+	    }
+	    /* clone dgram socket */
+	    newfd = net_socket_mcast_create(&saddr);
+	    if (newfd < 0) {
+		/* error already reported by net_socket_mcast_create() */
+		socket_close(fd);
+		return NULL;
+	    }
+	    /* clone newfd to fd, close newfd */
+	    dup2(newfd, fd);
+	    socket_close(newfd);
+
+	} else {
+	    fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
+		    fd, strerror(errno));
+	    return NULL;
+	}
+    }
+
+    s = qemu_mallocz(sizeof(NetSocketState));
+    s->fd = fd;
+
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive_dgram,
+                                 NULL, net_socket_cleanup, s);
+    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
+
+    /* mcast: save bound address as dst */
+    if (is_connected) s->dgram_dst=saddr;
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+	    "socket: fd=%d (%s mcast=%s)",
+	    fd, is_connected? "cloned" : "",
+	    sock_address_to_string(&saddr));
+    return s;
+}
+
+static void net_socket_connect(void *opaque)
+{
+    NetSocketState *s = opaque;
+    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
+}
+
+static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
+                                                 const char *model,
+                                                 const char *name,
+                                                 int fd, int is_connected)
+{
+    NetSocketState *s;
+    s = qemu_mallocz(sizeof(NetSocketState));
+    s->fd = fd;
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive,
+                                 NULL, net_socket_cleanup, s);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: fd=%d", fd);
+    if (is_connected) {
+        net_socket_connect(s);
+    } else {
+        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
+    }
+    return s;
+}
+
+static NetSocketState *net_socket_fd_init(VLANState *vlan,
+                                          const char *model, const char *name,
+                                          int fd, int is_connected)
+{
+    SocketType  so_type = socket_get_type(fd);
+
+    switch(so_type) {
+    case SOCKET_DGRAM:
+        return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
+    case SOCKET_STREAM:
+        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+    default:
+        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
+        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
+        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+    }
+    return NULL;
+}
+
+static void net_socket_accept(void *opaque)
+{
+    NetSocketListenState *s = opaque;
+    NetSocketState *s1;
+    SockAddress  saddr;
+    int fd;
+
+    for(;;) {
+        fd = socket_accept(s->fd, &saddr);
+        if (fd < 0) {
+            return;
+        } else if (fd >= 0) {
+            break;
+        }
+    }
+    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
+    if (!s1) {
+        socket_close(fd);
+    } else {
+        snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
+                 "socket: connection from %s", sock_address_to_string(&saddr));
+    }
+}
+
+static int net_socket_listen_init(VLANState *vlan,
+                                  const char *model,
+                                  const char *name,
+                                  const char *host_str)
+{
+    NetSocketListenState *s;
+    int fd, ret;
+    SockAddress  saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    s = qemu_mallocz(sizeof(NetSocketListenState));
+
+    fd = socket_create_inet(SOCKET_STREAM);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+    socket_set_nonblock(fd);
+
+    /* allow fast reuse */
+    socket_set_xreuseaddr(fd);
+
+    ret = socket_bind(fd, &saddr);
+    if (ret < 0) {
+        perror("bind");
+        return -1;
+    }
+    ret = socket_listen(fd, 0);
+    if (ret < 0) {
+        perror("listen");
+        return -1;
+    }
+    s->vlan = vlan;
+    s->model = strdup(model);
+    s->name = name ? strdup(name) : NULL;
+    s->fd = fd;
+    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
+    return 0;
+}
+
+static int net_socket_connect_init(VLANState *vlan,
+                                   const char *model,
+                                   const char *name,
+                                   const char *host_str)
+{
+    NetSocketState *s;
+    int fd, connected, ret, err;
+    SockAddress saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    fd = socket_create_inet(SOCKET_STREAM);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+    socket_set_nonblock(fd);
+
+    connected = 0;
+    for(;;) {
+        ret = socket_connect(fd, &saddr);
+        if (ret < 0) {
+            err = socket_error();
+            if (err == EWOULDBLOCK || err == EAGAIN) {
+            } else if (err == EINPROGRESS || err == EALREADY) {
+                break;
+            } else {
+                perror("connect");
+                socket_close(fd);
+                return -1;
+            }
+        } else {
+            connected = 1;
+            break;
+        }
+    }
+    s = net_socket_fd_init(vlan, model, name, fd, connected);
+    if (!s)
+        return -1;
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: connect to %s",
+             sock_address_to_string(&saddr));
+    return 0;
+}
+
+static int net_socket_mcast_init(VLANState *vlan,
+                                 const char *model,
+                                 const char *name,
+                                 const char *host_str)
+{
+    NetSocketState *s;
+    int fd;
+    SockAddress saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+
+    fd = net_socket_mcast_create(&saddr);
+    if (fd < 0)
+	return -1;
+
+    s = net_socket_fd_init(vlan, model, name, fd, 0);
+    if (!s)
+        return -1;
+
+    s->dgram_dst = saddr;
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: mcast=%s",
+             sock_address_to_string(&saddr));
+    return 0;
+
+}
+
+typedef struct DumpState {
+    VLANClientState *pcap_vc;
+    int fd;
+    int pcap_caplen;
+} DumpState;
+
+#define PCAP_MAGIC 0xa1b2c3d4
+
+struct pcap_file_hdr {
+    uint32_t magic;
+    uint16_t version_major;
+    uint16_t version_minor;
+    int32_t thiszone;
+    uint32_t sigfigs;
+    uint32_t snaplen;
+    uint32_t linktype;
+};
+
+struct pcap_sf_pkthdr {
+    struct {
+        int32_t tv_sec;
+        int32_t tv_usec;
+    } ts;
+    uint32_t caplen;
+    uint32_t len;
+};
+
+static ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    DumpState *s = vc->opaque;
+    struct pcap_sf_pkthdr hdr;
+    int64_t ts;
+    int caplen;
+
+    /* Early return in case of previous error. */
+    if (s->fd < 0) {
+        return size;
+    }
+
+    ts = muldiv64(qemu_get_clock(vm_clock), 1000000, ticks_per_sec);
+    caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
+
+    hdr.ts.tv_sec = ts / 1000000;
+    hdr.ts.tv_usec = ts % 1000000;
+    hdr.caplen = caplen;
+    hdr.len = size;
+    if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
+        write(s->fd, buf, caplen) != caplen) {
+        qemu_log("-net dump write error - stop dump\n");
+        close(s->fd);
+        s->fd = -1;
+    }
+
+    return size;
+}
+
+static void net_dump_cleanup(VLANClientState *vc)
+{
+    DumpState *s = vc->opaque;
+
+    close(s->fd);
+    qemu_free(s);
+}
+
+static int net_dump_init(Monitor *mon, VLANState *vlan, const char *device,
+                         const char *name, const char *filename, int len)
+{
+    struct pcap_file_hdr hdr;
+    DumpState *s;
+
+    s = qemu_malloc(sizeof(DumpState));
+
+    s->fd = open(filename, O_CREAT | O_WRONLY, 0644);
+    if (s->fd < 0) {
+        config_error(mon, "-net dump: can't open %s\n", filename);
+        return -1;
+    }
+
+    s->pcap_caplen = len;
+
+    hdr.magic = PCAP_MAGIC;
+    hdr.version_major = 2;
+    hdr.version_minor = 4;
+    hdr.thiszone = 0;
+    hdr.sigfigs = 0;
+    hdr.snaplen = s->pcap_caplen;
+    hdr.linktype = 1;
+
+    if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
+        config_error(mon, "-net dump write error: %s\n", strerror(errno));
+        close(s->fd);
+        qemu_free(s);
+        return -1;
+    }
+
+    s->pcap_vc = qemu_new_vlan_client(vlan, device, name, NULL, dump_receive, NULL,
+                                      net_dump_cleanup, s);
+    snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str),
+             "dump to %s (len=%d)", filename, len);
+    return 0;
+}
+
+/* find or alloc a new VLAN */
+VLANState *qemu_find_vlan(int id)
+{
+    VLANState **pvlan, *vlan;
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->id == id)
+            return vlan;
+    }
+    vlan = qemu_mallocz(sizeof(VLANState));
+    vlan->id = id;
+    vlan->next = NULL;
+    pvlan = &first_vlan;
+    while (*pvlan != NULL)
+        pvlan = &(*pvlan)->next;
+    *pvlan = vlan;
+    return vlan;
+}
+
+static int nic_get_free_idx(void)
+{
+    int index;
+
+    for (index = 0; index < MAX_NICS; index++)
+        if (!nd_table[index].used)
+            return index;
+    return -1;
+}
+
+void qemu_check_nic_model(NICInfo *nd, const char *model)
+{
+    const char *models[2];
+
+    models[0] = model;
+    models[1] = NULL;
+
+    qemu_check_nic_model_list(nd, models, model);
+}
+
+void qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
+                               const char *default_model)
+{
+    int i, exit_status = 0;
+
+    if (!nd->model)
+        nd->model = strdup(default_model);
+
+    if (strcmp(nd->model, "?") != 0) {
+        for (i = 0 ; models[i]; i++)
+            if (strcmp(nd->model, models[i]) == 0)
+                return;
+
+        fprintf(stderr, "qemu: Unsupported NIC model: %s\n", nd->model);
+        exit_status = 1;
+    }
+
+    fprintf(stderr, "qemu: Supported NIC models: ");
+    for (i = 0 ; models[i]; i++)
+        fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n');
+
+    exit(exit_status);
+}
+
+int net_client_init(Monitor *mon, const char *device, const char *p)
+{
+    static const char * const fd_params[] = {
+        "vlan", "name", "fd", NULL
+    };
+    char buf[1024];
+    int vlan_id, ret;
+    VLANState *vlan;
+    char *name = NULL;
+
+    vlan_id = 0;
+    if (get_param_value(buf, sizeof(buf), "vlan", p)) {
+        vlan_id = strtol(buf, NULL, 0);
+    }
+    vlan = qemu_find_vlan(vlan_id);
+
+    if (get_param_value(buf, sizeof(buf), "name", p)) {
+        name = qemu_strdup(buf);
+    }
+    if (!strcmp(device, "nic")) {
+        static const char * const nic_params[] = {
+            "vlan", "name", "macaddr", "model", NULL
+        };
+        NICInfo *nd;
+        uint8_t *macaddr;
+        int idx = nic_get_free_idx();
+
+        if (check_params(buf, sizeof(buf), nic_params, p) < 0) {
+            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
+            ret = -1;
+            goto out;
+        }
+        if (idx == -1 || nb_nics >= MAX_NICS) {
+            config_error(mon, "Too Many NICs\n");
+            ret = -1;
+            goto out;
+        }
+        nd = &nd_table[idx];
+        macaddr = nd->macaddr;
+        macaddr[0] = 0x52;
+        macaddr[1] = 0x54;
+        macaddr[2] = 0x00;
+        macaddr[3] = 0x12;
+        macaddr[4] = 0x34;
+        macaddr[5] = 0x56 + idx;
+
+        if (get_param_value(buf, sizeof(buf), "macaddr", p)) {
+            if (parse_macaddr(macaddr, buf) < 0) {
+                config_error(mon, "invalid syntax for ethernet address\n");
+                ret = -1;
+                goto out;
+            }
+        }
+        if (get_param_value(buf, sizeof(buf), "model", p)) {
+            nd->model = strdup(buf);
+        }
+        nd->vlan = vlan;
+        nd->name = name;
+        nd->used = 1;
+        name = NULL;
+        nb_nics++;
+        vlan->nb_guest_devs++;
+        ret = idx;
+    } else
+    if (!strcmp(device, "none")) {
+        if (*p != '\0') {
+            config_error(mon, "'none' takes no parameters\n");
+            ret = -1;
+            goto out;
+        }
+        /* does nothing. It is needed to signal that no network cards
+           are wanted */
+        ret = 0;
+    } else
+#ifdef CONFIG_SLIRP
+    if (!strcmp(device, "user")) {
+        static const char * const slirp_params[] = {
+            "vlan", "name", "hostname", "restrict", "ip", NULL
+        };
+        int restricted = 0;
+        char *ip = NULL;
+
+        if (check_params(buf, sizeof(buf), slirp_params, p) < 0) {
+            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
+            ret = -1;
+            goto out;
+        }
+        if (get_param_value(buf, sizeof(buf), "hostname", p)) {
+            pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf);
+        }
+        if (get_param_value(buf, sizeof(buf), "restrict", p)) {
+            restricted = (buf[0] == 'y') ? 1 : 0;
+        }
+        if (get_param_value(buf, sizeof(buf), "ip", p)) {
+            ip = qemu_strdup(buf);
+        }
+        vlan->nb_host_devs++;
+        ret = net_slirp_init(vlan, device, name, restricted, ip);
+        qemu_free(ip);
+    } else if (!strcmp(device, "channel")) {
+        long port;
+        char name[20], *devname;
+        struct VMChannel *vmc;
+
+        port = strtol(p, &devname, 10);
+        devname++;
+        if (port < 1 || port > 65535) {
+            config_error(mon, "vmchannel wrong port number\n");
+            ret = -1;
+            goto out;
+        }
+        vmc = malloc(sizeof(struct VMChannel));
+        snprintf(name, 20, "vmchannel%ld", port);
+        vmc->hd = qemu_chr_open(name, devname, NULL);
+        if (!vmc->hd) {
+            config_error(mon, "could not open vmchannel device '%s'\n",
+                         devname);
+            ret = -1;
+            goto out;
+        }
+        vmc->port = port;
+        slirp_add_exec(3, vmc->hd, 4, port);
+        qemu_chr_add_handlers(vmc->hd, vmchannel_can_read, vmchannel_read,
+                NULL, vmc);
+        ret = 0;
+    } else
+#endif
+#ifdef _WIN32
+    if (!strcmp(device, "tap")) {
+        static const char * const tap_params[] = {
+            "vlan", "name", "ifname", NULL
+        };
+        char ifname[64];
+
+        if (check_params(buf, sizeof(buf), tap_params, p) < 0) {
+            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
+            ret = -1;
+            goto out;
+        }
+        if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+            config_error(mon, "tap: no interface name\n");
+            ret = -1;
+            goto out;
+        }
+        vlan->nb_host_devs++;
+        ret = tap_win32_init(vlan, device, name, ifname);
+    } else
+#elif defined (_AIX)
+#else
+    if (!strcmp(device, "tap")) {
+        char ifname[64], chkbuf[64];
+        char setup_script[1024], down_script[1024];
+        int fd;
+        vlan->nb_host_devs++;
+        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
+            if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            fd = strtol(buf, NULL, 0);
+            fcntl(fd, F_SETFL, O_NONBLOCK);
+            net_tap_fd_init(vlan, device, name, fd);
+            ret = 0;
+        } else {
+            static const char * const tap_params[] = {
+                "vlan", "name", "ifname", "script", "downscript", NULL
+            };
+            if (check_params(chkbuf, sizeof(chkbuf), tap_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+                ifname[0] = '\0';
+            }
+            if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
+                pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
+            }
+            if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) {
+                pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT);
+            }
+            ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script);
+        }
+    } else
+#endif
+    if (!strcmp(device, "socket")) {
+        char chkbuf[64];
+        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
+            int fd;
+            if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            fd = strtol(buf, NULL, 0);
+            ret = -1;
+            if (net_socket_fd_init(vlan, device, name, fd, 1))
+                ret = 0;
+        } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) {
+            static const char * const listen_params[] = {
+                "vlan", "name", "listen", NULL
+            };
+            if (check_params(chkbuf, sizeof(chkbuf), listen_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            ret = net_socket_listen_init(vlan, device, name, buf);
+        } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
+            static const char * const connect_params[] = {
+                "vlan", "name", "connect", NULL
+            };
+            if (check_params(chkbuf, sizeof(chkbuf), connect_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            ret = net_socket_connect_init(vlan, device, name, buf);
+        } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
+            static const char * const mcast_params[] = {
+                "vlan", "name", "mcast", NULL
+            };
+            if (check_params(chkbuf, sizeof(chkbuf), mcast_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            ret = net_socket_mcast_init(vlan, device, name, buf);
+        } else {
+            config_error(mon, "Unknown socket options: %s\n", p);
+            ret = -1;
+            goto out;
+        }
+        vlan->nb_host_devs++;
+    } else
+#ifdef CONFIG_VDE
+    if (!strcmp(device, "vde")) {
+        static const char * const vde_params[] = {
+            "vlan", "name", "sock", "port", "group", "mode", NULL
+        };
+        char vde_sock[1024], vde_group[512];
+	int vde_port, vde_mode;
+
+        if (check_params(buf, sizeof(buf), vde_params, p) < 0) {
+            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
+            ret = -1;
+            goto out;
+        }
+        vlan->nb_host_devs++;
+        if (get_param_value(vde_sock, sizeof(vde_sock), "sock", p) <= 0) {
+	    vde_sock[0] = '\0';
+	}
+	if (get_param_value(buf, sizeof(buf), "port", p) > 0) {
+	    vde_port = strtol(buf, NULL, 10);
+	} else {
+	    vde_port = 0;
+	}
+	if (get_param_value(vde_group, sizeof(vde_group), "group", p) <= 0) {
+	    vde_group[0] = '\0';
+	}
+	if (get_param_value(buf, sizeof(buf), "mode", p) > 0) {
+	    vde_mode = strtol(buf, NULL, 8);
+	} else {
+	    vde_mode = 0700;
+	}
+	ret = net_vde_init(vlan, device, name, vde_sock, vde_port, vde_group, vde_mode);
+    } else
+#endif
+    if (!strcmp(device, "dump")) {
+        int len = 65536;
+
+        if (get_param_value(buf, sizeof(buf), "len", p) > 0) {
+            len = strtol(buf, NULL, 0);
+        }
+        if (!get_param_value(buf, sizeof(buf), "file", p)) {
+            snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id);
+        }
+        ret = net_dump_init(mon, vlan, device, name, buf, len);
+    } else {
+        config_error(mon, "Unknown network device: %s\n", device);
+        ret = -1;
+        goto out;
+    }
+    if (ret < 0) {
+        config_error(mon, "Could not initialize device '%s'\n", device);
+    }
+out:
+    qemu_free(name);
+    return ret;
+}
+
+void net_client_uninit(NICInfo *nd)
+{
+    nd->vlan->nb_guest_devs--;
+    nb_nics--;
+    nd->used = 0;
+    free((void *)nd->model);
+}
+
+static int net_host_check_device(const char *device)
+{
+    int i;
+    const char *valid_param_list[] = { "tap", "socket", "dump"
+#ifdef CONFIG_SLIRP
+                                       ,"user"
+#endif
+#ifdef CONFIG_VDE
+                                       ,"vde"
+#endif
+    };
+    for (i = 0; i < sizeof(valid_param_list) / sizeof(char *); i++) {
+        if (!strncmp(valid_param_list[i], device,
+                     strlen(valid_param_list[i])))
+            return 1;
+    }
+
+    return 0;
+}
+
+void net_host_device_add(Monitor *mon, const char *device, const char *opts)
+{
+    if (!net_host_check_device(device)) {
+        monitor_printf(mon, "invalid host network device %s\n", device);
+        return;
+    }
+    if (net_client_init(mon, device, opts ? opts : "") < 0) {
+        monitor_printf(mon, "adding host network device %s failed\n", device);
+    }
+}
+
+void net_host_device_remove(Monitor *mon, int vlan_id, const char *device)
+{
+    VLANState *vlan;
+    VLANClientState *vc;
+
+    vlan = qemu_find_vlan(vlan_id);
+
+    for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
+        if (!strcmp(vc->name, device)) {
+            break;
+        }
+    }
+
+    if (!vc) {
+        monitor_printf(mon, "can't find device %s\n", device);
+        return;
+    }
+    if (!net_host_check_device(vc->model)) {
+        monitor_printf(mon, "invalid host network device %s\n", device);
+        return;
+    }
+    qemu_del_vlan_client(vc);
+}
+
+int net_client_parse(const char *str)
+{
+    const char *p;
+    char *q;
+    char device[64];
+
+    p = str;
+    q = device;
+    while (*p != '\0' && *p != ',') {
+        if ((q - device) < sizeof(device) - 1)
+            *q++ = *p;
+        p++;
+    }
+    *q = '\0';
+    if (*p == ',')
+        p++;
+
+    return net_client_init(NULL, device, p);
+}
+
+void do_info_network(Monitor *mon)
+{
+    VLANState *vlan;
+    VLANClientState *vc;
+
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
+        for(vc = vlan->first_client; vc != NULL; vc = vc->next)
+            monitor_printf(mon, "  %s: %s\n", vc->name, vc->info_str);
+    }
+}
+
+int do_set_link(Monitor *mon, const char *name, const char *up_or_down)
+{
+    VLANState *vlan;
+    VLANClientState *vc = NULL;
+
+    for (vlan = first_vlan; vlan != NULL; vlan = vlan->next)
+        for (vc = vlan->first_client; vc != NULL; vc = vc->next)
+            if (strcmp(vc->name, name) == 0)
+                goto done;
+done:
+
+    if (!vc) {
+        monitor_printf(mon, "could not find network device '%s'", name);
+        return 0;
+    }
+
+    if (strcmp(up_or_down, "up") == 0)
+        vc->link_down = 0;
+    else if (strcmp(up_or_down, "down") == 0)
+        vc->link_down = 1;
+    else
+        monitor_printf(mon, "invalid link status '%s'; only 'up' or 'down' "
+                       "valid\n", up_or_down);
+
+    if (vc->link_status_changed)
+        vc->link_status_changed(vc);
+
+    return 1;
+}
+
+void net_cleanup(void)
+{
+    VLANState *vlan;
+
+    /* close network clients */
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        VLANClientState *vc = vlan->first_client;
+
+        while (vc) {
+            VLANClientState *next = vc->next;
+
+            qemu_del_vlan_client(vc);
+
+            vc = next;
+        }
+    }
+}
+
+void net_client_check(void)
+{
+    VLANState *vlan;
+
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
+            continue;
+        if (vlan->nb_guest_devs == 0)
+            fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
+        if (vlan->nb_host_devs == 0)
+            fprintf(stderr,
+                    "Warning: vlan %d is not connected to host network\n",
+                    vlan->id);
+    }
+}
diff --git a/net-checksum.c b/net-checksum.c
new file mode 100644
index 0000000..fac0651
--- /dev/null
+++ b/net-checksum.c
@@ -0,0 +1,87 @@
+/*
+ *  IP checksumming functions.
+ *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ */
+
+#include "hw/hw.h"
+#include "net.h"
+
+#define PROTO_TCP  6
+#define PROTO_UDP 17
+
+uint32_t net_checksum_add(int len, uint8_t *buf)
+{
+    uint32_t sum = 0;
+    int i;
+
+    for (i = 0; i < len; i++) {
+	if (i & 1)
+	    sum += (uint32_t)buf[i];
+	else
+	    sum += (uint32_t)buf[i] << 8;
+    }
+    return sum;
+}
+
+uint16_t net_checksum_finish(uint32_t sum)
+{
+    while (sum>>16)
+	sum = (sum & 0xFFFF)+(sum >> 16);
+    return ~sum;
+}
+
+uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto,
+                             uint8_t *addrs, uint8_t *buf)
+{
+    uint32_t sum = 0;
+
+    sum += net_checksum_add(length, buf);         // payload
+    sum += net_checksum_add(8, addrs);            // src + dst address
+    sum += proto + length;                        // protocol & length
+    return net_checksum_finish(sum);
+}
+
+void net_checksum_calculate(uint8_t *data, int length)
+{
+    int hlen, plen, proto, csum_offset;
+    uint16_t csum;
+
+    if ((data[14] & 0xf0) != 0x40)
+	return; /* not IPv4 */
+    hlen  = (data[14] & 0x0f) * 4;
+    plen  = (data[16] << 8 | data[17]) - hlen;
+    proto = data[23];
+
+    switch (proto) {
+    case PROTO_TCP:
+	csum_offset = 16;
+	break;
+    case PROTO_UDP:
+	csum_offset = 6;
+	break;
+    default:
+	return;
+    }
+
+    if (plen < csum_offset+2)
+	return;
+
+    data[14+hlen+csum_offset]   = 0;
+    data[14+hlen+csum_offset+1] = 0;
+    csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen);
+    data[14+hlen+csum_offset]   = csum >> 8;
+    data[14+hlen+csum_offset+1] = csum & 0xff;
+}
diff --git a/net.c b/net.c
new file mode 100644
index 0000000..af9de73
--- /dev/null
+++ b/net.c
@@ -0,0 +1,2534 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+/* Needed early for HOST_BSD etc. */
+#include "config-host.h"
+
+#ifndef _WIN32
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#ifdef __NetBSD__
+#include <net/if_tap.h>
+#endif
+#ifdef __linux__
+#include <linux/if_tun.h>
+#endif
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+#ifdef HOST_BSD
+#include <sys/stat.h>
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <libutil.h>
+#else
+#include <util.h>
+#endif
+#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+#include <freebsd/stdlib.h>
+#else
+#ifdef __linux__
+#include <pty.h>
+#include <malloc.h>
+#include <linux/rtc.h>
+
+/* For the benefit of older linux systems which don't supply it,
+   we use a local copy of hpet.h. */
+/* #include <linux/hpet.h> */
+#include "hpet.h"
+
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+#endif
+#ifdef __sun__
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
+#endif
+#endif
+#endif
+
+#if defined(__OpenBSD__)
+#include <util.h>
+#endif
+
+#if defined(CONFIG_VDE)
+#include <libvdeplug.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <malloc.h>
+#include <sys/timeb.h>
+#include <mmsystem.h>
+#define getopt_long_only getopt_long
+#define memalign(align, size) malloc(size)
+#endif
+
+#include "qemu-common.h"
+#include "net.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "audio/audio.h"
+#include "qemu_socket.h"
+#include "qemu-log.h"
+
+#if defined(CONFIG_SLIRP)
+#include "libslirp.h"
+#endif
+
+
+static VLANState *first_vlan;
+
+/***********************************************************/
+/* network device redirectors */
+
+#if defined(DEBUG_NET) || defined(DEBUG_SLIRP)
+static void hex_dump(FILE *f, const uint8_t *buf, int size)
+{
+    int len, i, j, c;
+
+    for(i=0;i<size;i+=16) {
+        len = size - i;
+        if (len > 16)
+            len = 16;
+        fprintf(f, "%08x ", i);
+        for(j=0;j<16;j++) {
+            if (j < len)
+                fprintf(f, " %02x", buf[i+j]);
+            else
+                fprintf(f, "   ");
+        }
+        fprintf(f, " ");
+        for(j=0;j<len;j++) {
+            c = buf[i+j];
+            if (c < ' ' || c > '~')
+                c = '.';
+            fprintf(f, "%c", c);
+        }
+        fprintf(f, "\n");
+    }
+}
+#endif
+
+static int parse_macaddr(uint8_t *macaddr, const char *p)
+{
+    int i;
+    char *last_char;
+    long int offset;
+
+    errno = 0;
+    offset = strtol(p, &last_char, 0);    
+    if (0 == errno && '\0' == *last_char &&
+            offset >= 0 && offset <= 0xFFFFFF) {
+        macaddr[3] = (offset & 0xFF0000) >> 16;
+        macaddr[4] = (offset & 0xFF00) >> 8;
+        macaddr[5] = offset & 0xFF;
+        return 0;
+    } else {
+        for(i = 0; i < 6; i++) {
+            macaddr[i] = strtol(p, (char **)&p, 16);
+            if (i == 5) {
+                if (*p != '\0')
+                    return -1;
+            } else {
+                if (*p != ':' && *p != '-')
+                    return -1;
+                p++;
+            }
+        }
+        return 0;    
+    }
+
+    return -1;
+}
+
+static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
+{
+    const char *p, *p1;
+    int len;
+    p = *pp;
+    p1 = strchr(p, sep);
+    if (!p1)
+        return -1;
+    len = p1 - p;
+    p1++;
+    if (buf_size > 0) {
+        if (len > buf_size - 1)
+            len = buf_size - 1;
+        memcpy(buf, p, len);
+        buf[len] = '\0';
+    }
+    *pp = p1;
+    return 0;
+}
+
+int parse_host_src_port(struct sockaddr_in *haddr,
+                        struct sockaddr_in *saddr,
+                        const char *input_str)
+{
+    char *str = strdup(input_str);
+    char *host_str = str;
+    char *src_str;
+    const char *src_str2;
+    char *ptr;
+
+    /*
+     * Chop off any extra arguments at the end of the string which
+     * would start with a comma, then fill in the src port information
+     * if it was provided else use the "any address" and "any port".
+     */
+    if ((ptr = strchr(str,',')))
+        *ptr = '\0';
+
+    if ((src_str = strchr(input_str,'@'))) {
+        *src_str = '\0';
+        src_str++;
+    }
+
+    if (parse_host_port(haddr, host_str) < 0)
+        goto fail;
+
+    src_str2 = src_str;
+    if (!src_str || *src_str == '\0')
+        src_str2 = ":0";
+
+    if (parse_host_port(saddr, src_str2) < 0)
+        goto fail;
+
+    free(str);
+    return(0);
+
+fail:
+    free(str);
+    return -1;
+}
+
+int parse_host_port(struct sockaddr_in *saddr, const char *str)
+{
+    char buf[512];
+    struct hostent *he;
+    const char *p, *r;
+    int port;
+
+    p = str;
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+        return -1;
+    saddr->sin_family = AF_INET;
+    if (buf[0] == '\0') {
+        saddr->sin_addr.s_addr = 0;
+    } else {
+        if (qemu_isdigit(buf[0])) {
+            if (!inet_aton(buf, &saddr->sin_addr))
+                return -1;
+        } else {
+            if ((he = gethostbyname(buf)) == NULL)
+                return - 1;
+            saddr->sin_addr = *(struct in_addr *)he->h_addr;
+        }
+    }
+    port = strtol(p, (char **)&r, 0);
+    if (r == p)
+        return -1;
+    saddr->sin_port = htons(port);
+    return 0;
+}
+
+#if !defined(_WIN32) && 0
+static int parse_unix_path(struct sockaddr_un *uaddr, const char *str)
+{
+    const char *p;
+    int len;
+
+    len = MIN(108, strlen(str));
+    p = strchr(str, ',');
+    if (p)
+	len = MIN(len, p - str);
+
+    memset(uaddr, 0, sizeof(*uaddr));
+
+    uaddr->sun_family = AF_UNIX;
+    memcpy(uaddr->sun_path, str, len);
+
+    return 0;
+}
+#endif
+
+void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6])
+{
+    snprintf(vc->info_str, sizeof(vc->info_str),
+             "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+             vc->model,
+             macaddr[0], macaddr[1], macaddr[2],
+             macaddr[3], macaddr[4], macaddr[5]);
+}
+
+static char *assign_name(VLANClientState *vc1, const char *model)
+{
+    VLANState *vlan;
+    char buf[256];
+    int id = 0;
+
+    for (vlan = first_vlan; vlan; vlan = vlan->next) {
+        VLANClientState *vc;
+
+        for (vc = vlan->first_client; vc; vc = vc->next)
+            if (vc != vc1 && strcmp(vc->model, model) == 0)
+                id++;
+    }
+
+    snprintf(buf, sizeof(buf), "%s.%d", model, id);
+
+    return strdup(buf);
+}
+
+VLANClientState *qemu_new_vlan_client(VLANState *vlan,
+                                      const char *model,
+                                      const char *name,
+                                      NetCanReceive *can_receive,
+                                      NetReceive *receive,
+                                      NetReceiveIOV *receive_iov,
+                                      NetCleanup *cleanup,
+                                      void *opaque)
+{
+    VLANClientState *vc, **pvc;
+    vc = qemu_mallocz(sizeof(VLANClientState));
+    vc->model = strdup(model);
+    if (name)
+        vc->name = strdup(name);
+    else
+        vc->name = assign_name(vc, model);
+    vc->can_receive = can_receive;
+    vc->receive = receive;
+    vc->receive_iov = receive_iov;
+    vc->cleanup = cleanup;
+    vc->opaque = opaque;
+    vc->vlan = vlan;
+
+    vc->next = NULL;
+    pvc = &vlan->first_client;
+    while (*pvc != NULL)
+        pvc = &(*pvc)->next;
+    *pvc = vc;
+    return vc;
+}
+
+void qemu_del_vlan_client(VLANClientState *vc)
+{
+    VLANClientState **pvc = &vc->vlan->first_client;
+
+    while (*pvc != NULL)
+        if (*pvc == vc) {
+            *pvc = vc->next;
+            if (vc->cleanup) {
+                vc->cleanup(vc);
+            }
+            free(vc->name);
+            free(vc->model);
+            qemu_free(vc);
+            break;
+        } else
+            pvc = &(*pvc)->next;
+}
+
+VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque)
+{
+    VLANClientState **pvc = &vlan->first_client;
+
+    while (*pvc != NULL)
+        if ((*pvc)->opaque == opaque)
+            return *pvc;
+        else
+            pvc = &(*pvc)->next;
+
+    return NULL;
+}
+
+int qemu_can_send_packet(VLANClientState *sender)
+{
+    VLANState *vlan = sender->vlan;
+    VLANClientState *vc;
+
+    for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
+        if (vc == sender) {
+            continue;
+        }
+
+        /* no can_receive() handler, they can always receive */
+        if (!vc->can_receive || vc->can_receive(vc)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int
+qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size)
+{
+    VLANClientState *vc;
+    int ret = -1;
+
+    sender->vlan->delivering = 1;
+
+    for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) {
+        ssize_t len;
+
+        if (vc == sender) {
+            continue;
+        }
+
+        if (vc->link_down) {
+            ret = size;
+            continue;
+        }
+
+        len = vc->receive(vc, buf, size);
+
+        ret = (ret >= 0) ? ret : len;
+    }
+
+    sender->vlan->delivering = 0;
+
+    return ret;
+}
+
+void qemu_flush_queued_packets(VLANClientState *vc)
+{
+    VLANPacket *packet;
+
+    while ((packet = vc->vlan->send_queue) != NULL) {
+        int ret;
+
+        vc->vlan->send_queue = packet->next;
+
+        ret = qemu_deliver_packet(packet->sender, packet->data, packet->size);
+        if (ret == 0 && packet->sent_cb != NULL) {
+            packet->next = vc->vlan->send_queue;
+            vc->vlan->send_queue = packet;
+            break;
+        }
+
+        if (packet->sent_cb)
+            packet->sent_cb(packet->sender);
+
+        qemu_free(packet);
+    }
+}
+
+static void qemu_enqueue_packet(VLANClientState *sender,
+                                const uint8_t *buf, int size,
+                                NetPacketSent *sent_cb)
+{
+    VLANPacket *packet;
+
+    packet = qemu_malloc(sizeof(VLANPacket) + size);
+    packet->next = sender->vlan->send_queue;
+    packet->sender = sender;
+    packet->size = size;
+    packet->sent_cb = sent_cb;
+    memcpy(packet->data, buf, size);
+    sender->vlan->send_queue = packet;
+}
+
+ssize_t qemu_send_packet_async(VLANClientState *sender,
+                               const uint8_t *buf, int size,
+                               NetPacketSent *sent_cb)
+{
+    int ret;
+
+    if (sender->link_down) {
+        return size;
+    }
+
+#ifdef DEBUG_NET
+    printf("vlan %d send:\n", sender->vlan->id);
+    hex_dump(stdout, buf, size);
+#endif
+
+    if (sender->vlan->delivering) {
+        qemu_enqueue_packet(sender, buf, size, NULL);
+        return size;
+    }
+
+    ret = qemu_deliver_packet(sender, buf, size);
+    if (ret == 0 && sent_cb != NULL) {
+        qemu_enqueue_packet(sender, buf, size, sent_cb);
+        return 0;
+    }
+
+    qemu_flush_queued_packets(sender);
+
+    return ret;
+}
+
+void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
+{
+    qemu_send_packet_async(vc, buf, size, NULL);
+}
+
+static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
+                               int iovcnt)
+{
+    uint8_t buffer[4096];
+    size_t offset = 0;
+    int i;
+
+    for (i = 0; i < iovcnt; i++) {
+        size_t len;
+
+        len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
+        memcpy(buffer + offset, iov[i].iov_base, len);
+        offset += len;
+    }
+
+    return vc->receive(vc, buffer, offset);
+}
+
+static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
+{
+    size_t offset = 0;
+    int i;
+
+    for (i = 0; i < iovcnt; i++)
+        offset += iov[i].iov_len;
+    return offset;
+}
+
+static int qemu_deliver_packet_iov(VLANClientState *sender,
+                                   const struct iovec *iov, int iovcnt)
+{
+    VLANClientState *vc;
+    int ret = -1;
+
+    sender->vlan->delivering = 1;
+
+    for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) {
+        ssize_t len;
+
+        if (vc == sender) {
+            continue;
+        }
+
+        if (vc->link_down) {
+            ret = calc_iov_length(iov, iovcnt);
+            continue;
+        }
+
+        if (vc->receive_iov) {
+            len = vc->receive_iov(vc, iov, iovcnt);
+        } else {
+            len = vc_sendv_compat(vc, iov, iovcnt);
+        }
+
+        ret = (ret >= 0) ? ret : len;
+    }
+
+    sender->vlan->delivering = 0;
+
+    return ret;
+}
+
+static ssize_t qemu_enqueue_packet_iov(VLANClientState *sender,
+                                       const struct iovec *iov, int iovcnt,
+                                       NetPacketSent *sent_cb)
+{
+    VLANPacket *packet;
+    size_t max_len = 0;
+    int i;
+
+    max_len = calc_iov_length(iov, iovcnt);
+
+    packet = qemu_malloc(sizeof(VLANPacket) + max_len);
+    packet->next = sender->vlan->send_queue;
+    packet->sender = sender;
+    packet->sent_cb = sent_cb;
+    packet->size = 0;
+
+    for (i = 0; i < iovcnt; i++) {
+        size_t len = iov[i].iov_len;
+
+        memcpy(packet->data + packet->size, iov[i].iov_base, len);
+        packet->size += len;
+    }
+
+    sender->vlan->send_queue = packet;
+
+    return packet->size;
+}
+
+ssize_t qemu_sendv_packet_async(VLANClientState *sender,
+                                const struct iovec *iov, int iovcnt,
+                                NetPacketSent *sent_cb)
+{
+    int ret;
+
+    if (sender->link_down) {
+        return calc_iov_length(iov, iovcnt);
+    }
+
+    if (sender->vlan->delivering) {
+        return qemu_enqueue_packet_iov(sender, iov, iovcnt, NULL);
+    }
+
+    ret = qemu_deliver_packet_iov(sender, iov, iovcnt);
+    if (ret == 0 && sent_cb != NULL) {
+        qemu_enqueue_packet_iov(sender, iov, iovcnt, sent_cb);
+        return 0;
+    }
+
+    qemu_flush_queued_packets(sender);
+
+    return ret;
+}
+
+ssize_t
+qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt)
+{
+    return qemu_sendv_packet_async(vc, iov, iovcnt, NULL);
+}
+
+static void config_error(Monitor *mon, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    if (mon) {
+        monitor_vprintf(mon, fmt, ap);
+    } else {
+        fprintf(stderr, "qemu: ");
+        vfprintf(stderr, fmt, ap);
+        exit(1);
+    }
+    va_end(ap);
+}
+
+#if defined(CONFIG_SLIRP)
+
+/* slirp network adapter */
+
+struct slirp_config_str {
+    struct slirp_config_str *next;
+    const char *str;
+};
+
+static int slirp_inited;
+static struct slirp_config_str *slirp_redirs;
+#ifndef _WIN32
+static const char *slirp_smb_export;
+#endif
+static VLANClientState *slirp_vc;
+
+#ifndef _WIN32
+static void slirp_smb(const char *exported_dir);
+#endif
+static void slirp_redirection(Monitor *mon, const char *redir_str);
+
+int slirp_can_output(void)
+{
+    return !slirp_vc || qemu_can_send_packet(slirp_vc);
+}
+
+void slirp_output(const uint8_t *pkt, int pkt_len)
+{
+#ifdef DEBUG_SLIRP
+    printf("slirp output:\n");
+    hex_dump(stdout, pkt, pkt_len);
+#endif
+    if (!slirp_vc)
+        return;
+    qemu_send_packet(slirp_vc, pkt, pkt_len);
+}
+
+int slirp_is_inited(void)
+{
+    return slirp_inited;
+}
+
+static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+#ifdef DEBUG_SLIRP
+    printf("slirp input:\n");
+    hex_dump(stdout, buf, size);
+#endif
+    slirp_input(buf, size);
+    return size;
+}
+
+static int slirp_in_use;
+
+static void net_slirp_cleanup(VLANClientState *vc)
+{
+    slirp_in_use = 0;
+}
+
+static int net_slirp_init(VLANState *vlan, const char *model, const char *name,
+                          int restricted, const char *ip)
+{
+    if (slirp_in_use) {
+        /* slirp only supports a single instance so far */
+        return -1;
+    }
+    if (!slirp_inited) {
+        slirp_inited = 1;
+        slirp_init(restricted, ip);
+
+        while (slirp_redirs) {
+            struct slirp_config_str *config = slirp_redirs;
+
+            slirp_redirection(NULL, config->str);
+            slirp_redirs = config->next;
+            qemu_free(config);
+        }
+#ifndef _WIN32
+        if (slirp_smb_export) {
+            slirp_smb(slirp_smb_export);
+        }
+#endif
+    }
+
+    slirp_vc = qemu_new_vlan_client(vlan, model, name, NULL, slirp_receive,
+                                    NULL, net_slirp_cleanup, NULL);
+    slirp_vc->info_str[0] = '\0';
+    slirp_in_use = 1;
+    return 0;
+}
+
+static void net_slirp_redir_print(void *opaque, int is_udp,
+                                  struct in_addr *laddr, u_int lport,
+                                  struct in_addr *faddr, u_int fport)
+{
+    Monitor *mon = (Monitor *)opaque;
+    uint32_t h_addr;
+    uint32_t g_addr;
+    char buf[16];
+
+    h_addr = ntohl(faddr->s_addr);
+    g_addr = ntohl(laddr->s_addr);
+
+    monitor_printf(mon, "  %s |", is_udp ? "udp" : "tcp" );
+    snprintf(buf, 15, "%d.%d.%d.%d", (h_addr >> 24) & 0xff,
+                                     (h_addr >> 16) & 0xff,
+                                     (h_addr >> 8) & 0xff,
+                                     (h_addr) & 0xff);
+    monitor_printf(mon, " %15s |", buf);
+    monitor_printf(mon, " %5d |", fport);
+
+    snprintf(buf, 15, "%d.%d.%d.%d", (g_addr >> 24) & 0xff,
+                                     (g_addr >> 16) & 0xff,
+                                     (g_addr >> 8) & 0xff,
+                                     (g_addr) & 0xff);
+    monitor_printf(mon, " %15s |", buf);
+    monitor_printf(mon, " %5d\n", lport);
+
+}
+
+static void net_slirp_redir_list(Monitor *mon)
+{
+    if (!mon)
+        return;
+
+    monitor_printf(mon, " Prot |    Host Addr    | HPort |    Guest Addr   | GPort\n");
+    monitor_printf(mon, "      |                 |       |                 |      \n");
+    slirp_redir_loop(net_slirp_redir_print, mon);
+}
+
+static void net_slirp_redir_rm(Monitor *mon, const char *port_str)
+{
+    int host_port;
+    char buf[256] = "";
+    const char *p = port_str;
+    int is_udp = 0;
+    int n;
+
+    if (!mon)
+        return;
+
+    if (!port_str || !port_str[0])
+        goto fail_syntax;
+
+    get_str_sep(buf, sizeof(buf), &p, ':');
+
+    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+        is_udp = 0;
+    } else if (!strcmp(buf, "udp")) {
+        is_udp = 1;
+    } else {
+        goto fail_syntax;
+    }
+
+    host_port = atoi(p);
+
+    n = slirp_redir_rm(is_udp, host_port);
+
+    monitor_printf(mon, "removed %d redirections to %s port %d\n", n,
+                        is_udp ? "udp" : "tcp", host_port);
+    return;
+
+ fail_syntax:
+    monitor_printf(mon, "invalid format\n");
+}
+
+static void slirp_redirection(Monitor *mon, const char *redir_str)
+{
+    struct in_addr guest_addr;
+    int host_port, guest_port;
+    const char *p;
+    char buf[256], *r;
+    int is_udp;
+
+    p = redir_str;
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+        is_udp = 0;
+    } else if (!strcmp(buf, "udp")) {
+        is_udp = 1;
+    } else {
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    host_port = strtol(buf, &r, 0);
+    if (r == buf) {
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    if (buf[0] == '\0') {
+        pstrcpy(buf, sizeof(buf), "10.0.2.15");
+    }
+    if (!inet_aton(buf, &guest_addr)) {
+        goto fail_syntax;
+    }
+
+    guest_port = strtol(p, &r, 0);
+    if (r == p) {
+        goto fail_syntax;
+    }
+
+    if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) {
+        config_error(mon, "could not set up redirection '%s'\n", redir_str);
+    }
+    return;
+
+ fail_syntax:
+    config_error(mon, "invalid redirection format '%s'\n", redir_str);
+}
+
+void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2)
+{
+    struct slirp_config_str *config;
+
+    if (!slirp_inited) {
+        if (mon) {
+            monitor_printf(mon, "user mode network stack not in use\n");
+        } else {
+            config = qemu_malloc(sizeof(*config));
+            config->str = redir_str;
+            config->next = slirp_redirs;
+            slirp_redirs = config;
+        }
+        return;
+    }
+
+    if (!strcmp(redir_str, "remove")) {
+        net_slirp_redir_rm(mon, redir_opt2);
+        return;
+    }
+
+    if (!strcmp(redir_str, "list")) {
+        net_slirp_redir_list(mon);
+        return;
+    }
+
+    slirp_redirection(mon, redir_str);
+}
+
+#ifndef _WIN32
+
+static char smb_dir[1024];
+
+static void erase_dir(char *dir_name)
+{
+    DIR *d;
+    struct dirent *de;
+    char filename[1024];
+
+    /* erase all the files in the directory */
+    if ((d = opendir(dir_name)) != NULL) {
+        for(;;) {
+            de = readdir(d);
+            if (!de)
+                break;
+            if (strcmp(de->d_name, ".") != 0 &&
+                strcmp(de->d_name, "..") != 0) {
+                snprintf(filename, sizeof(filename), "%s/%s",
+                         smb_dir, de->d_name);
+                if (unlink(filename) != 0)  /* is it a directory? */
+                    erase_dir(filename);
+            }
+        }
+        closedir(d);
+        rmdir(dir_name);
+    }
+}
+
+/* automatic user mode samba server configuration */
+static void smb_exit(void)
+{
+    erase_dir(smb_dir);
+}
+
+static void slirp_smb(const char *exported_dir)
+{
+    char smb_conf[1024];
+    char smb_cmdline[1024];
+    FILE *f;
+
+    /* XXX: better tmp dir construction */
+    snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%ld", (long)getpid());
+    if (mkdir(smb_dir, 0700) < 0) {
+        fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir);
+        exit(1);
+    }
+    snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf");
+
+    f = fopen(smb_conf, "w");
+    if (!f) {
+        fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf);
+        exit(1);
+    }
+    fprintf(f,
+            "[global]\n"
+            "private dir=%s\n"
+            "smb ports=0\n"
+            "socket address=127.0.0.1\n"
+            "pid directory=%s\n"
+            "lock directory=%s\n"
+            "log file=%s/log.smbd\n"
+            "smb passwd file=%s/smbpasswd\n"
+            "security = share\n"
+            "[qemu]\n"
+            "path=%s\n"
+            "read only=no\n"
+            "guest ok=yes\n",
+            smb_dir,
+            smb_dir,
+            smb_dir,
+            smb_dir,
+            smb_dir,
+            exported_dir
+            );
+    fclose(f);
+    atexit(smb_exit);
+
+    snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
+             SMBD_COMMAND, smb_conf);
+
+    slirp_add_exec(0, smb_cmdline, 4, 139);
+}
+
+/* automatic user mode samba server configuration */
+void net_slirp_smb(const char *exported_dir)
+{
+    if (slirp_smb_export) {
+        fprintf(stderr, "-smb given twice\n");
+        exit(1);
+    }
+    slirp_smb_export = exported_dir;
+    if (slirp_inited) {
+        slirp_smb(exported_dir);
+    }
+}
+
+#endif /* !defined(_WIN32) */
+
+void do_info_slirp(Monitor *mon)
+{
+    slirp_stats();
+}
+
+struct VMChannel {
+    CharDriverState *hd;
+    int port;
+};
+
+static int vmchannel_can_read(void *opaque)
+{
+    struct VMChannel *vmc = (struct VMChannel*)opaque;
+    return slirp_socket_can_recv(4, vmc->port);
+}
+
+static void vmchannel_read(void *opaque, const uint8_t *buf, int size)
+{
+    struct VMChannel *vmc = (struct VMChannel*)opaque;
+    slirp_socket_recv(4, vmc->port, buf, size);
+}
+
+#endif /* CONFIG_SLIRP */
+
+#if !defined(_WIN32)
+
+typedef struct TAPState {
+    VLANClientState *vc;
+    int fd;
+    char down_script[1024];
+    char down_script_arg[128];
+    uint8_t buf[4096];
+} TAPState;
+
+static int launch_script(const char *setup_script, const char *ifname, int fd);
+
+static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
+                               int iovcnt)
+{
+    TAPState *s = vc->opaque;
+    ssize_t len;
+
+    do {
+        len = writev(s->fd, iov, iovcnt);
+    } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+
+    return len;
+}
+
+static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    TAPState *s = vc->opaque;
+    ssize_t len;
+
+    do {
+        len = write(s->fd, buf, size);
+    } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+
+    return len;
+}
+
+static int tap_can_send(void *opaque)
+{
+    TAPState *s = opaque;
+
+    return qemu_can_send_packet(s->vc);
+}
+
+#ifdef __sun__
+static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
+{
+    struct strbuf sbuf;
+    int f = 0;
+
+    sbuf.maxlen = maxlen;
+    sbuf.buf = (char *)buf;
+
+    return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
+}
+#else
+static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
+{
+    return read(tapfd, buf, maxlen);
+}
+#endif
+
+static void tap_send(void *opaque);
+
+static void tap_send_completed(VLANClientState *vc)
+{
+    TAPState *s = vc->opaque;
+
+    qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s);
+}
+
+static void tap_send(void *opaque)
+{
+    TAPState *s = opaque;
+    int size;
+
+    do {
+        size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
+        if (size <= 0) {
+            break;
+        }
+
+        size = qemu_send_packet_async(s->vc, s->buf, size, tap_send_completed);
+        if (size == 0) {
+            qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+        }
+    } while (size > 0);
+}
+
+static void tap_cleanup(VLANClientState *vc)
+{
+    TAPState *s = vc->opaque;
+
+    if (s->down_script[0])
+        launch_script(s->down_script, s->down_script_arg, s->fd);
+
+    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+    close(s->fd);
+    qemu_free(s);
+}
+
+/* fd support */
+
+static TAPState *net_tap_fd_init(VLANState *vlan,
+                                 const char *model,
+                                 const char *name,
+                                 int fd)
+{
+    TAPState *s;
+
+    s = qemu_mallocz(sizeof(TAPState));
+    s->fd = fd;
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive,
+                                 tap_receive_iov, tap_cleanup, s);
+    qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd);
+    return s;
+}
+
+#if defined (HOST_BSD) || defined (__FreeBSD_kernel__)
+static int tap_open(char *ifname, int ifname_size)
+{
+    int fd;
+    char *dev;
+    struct stat s;
+
+    TFR(fd = open("/dev/tap", O_RDWR));
+    if (fd < 0) {
+        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+        return -1;
+    }
+
+    fstat(fd, &s);
+    dev = devname(s.st_rdev, S_IFCHR);
+    pstrcpy(ifname, ifname_size, dev);
+
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+#elif defined(__sun__)
+#define TUNNEWPPA       (('T'<<16) | 0x0001)
+/*
+ * Allocate TAP device, returns opened fd.
+ * Stores dev name in the first arg(must be large enough).
+ */
+static int tap_alloc(char *dev, size_t dev_size)
+{
+    int tap_fd, if_fd, ppa = -1;
+    static int ip_fd = 0;
+    char *ptr;
+
+    static int arp_fd = 0;
+    int ip_muxid, arp_muxid;
+    struct strioctl  strioc_if, strioc_ppa;
+    int link_type = I_PLINK;;
+    struct lifreq ifr;
+    char actual_name[32] = "";
+
+    memset(&ifr, 0x0, sizeof(ifr));
+
+    if( *dev ){
+       ptr = dev;
+       while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++;
+       ppa = atoi(ptr);
+    }
+
+    /* Check if IP device was opened */
+    if( ip_fd )
+       close(ip_fd);
+
+    TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
+    if (ip_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
+       return -1;
+    }
+
+    TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
+    if (tap_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/tap");
+       return -1;
+    }
+
+    /* Assign a new PPA and get its unit number. */
+    strioc_ppa.ic_cmd = TUNNEWPPA;
+    strioc_ppa.ic_timout = 0;
+    strioc_ppa.ic_len = sizeof(ppa);
+    strioc_ppa.ic_dp = (char *)&ppa;
+    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
+       syslog (LOG_ERR, "Can't assign new interface");
+
+    TFR(if_fd = open("/dev/tap", O_RDWR, 0));
+    if (if_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/tap (2)");
+       return -1;
+    }
+    if(ioctl(if_fd, I_PUSH, "ip") < 0){
+       syslog(LOG_ERR, "Can't push IP module");
+       return -1;
+    }
+
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+	syslog(LOG_ERR, "Can't get flags\n");
+
+    snprintf (actual_name, 32, "tap%d", ppa);
+    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
+
+    ifr.lifr_ppa = ppa;
+    /* Assign ppa according to the unit number returned by tun device */
+
+    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
+        syslog (LOG_ERR, "Can't set PPA %d", ppa);
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+        syslog (LOG_ERR, "Can't get flags\n");
+    /* Push arp module to if_fd */
+    if (ioctl (if_fd, I_PUSH, "arp") < 0)
+        syslog (LOG_ERR, "Can't push ARP module (2)");
+
+    /* Push arp module to ip_fd */
+    if (ioctl (ip_fd, I_POP, NULL) < 0)
+        syslog (LOG_ERR, "I_POP failed\n");
+    if (ioctl (ip_fd, I_PUSH, "arp") < 0)
+        syslog (LOG_ERR, "Can't push ARP module (3)\n");
+    /* Open arp_fd */
+    TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
+    if (arp_fd < 0)
+       syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
+
+    /* Set ifname to arp */
+    strioc_if.ic_cmd = SIOCSLIFNAME;
+    strioc_if.ic_timout = 0;
+    strioc_if.ic_len = sizeof(ifr);
+    strioc_if.ic_dp = (char *)&ifr;
+    if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
+        syslog (LOG_ERR, "Can't set ifname to arp\n");
+    }
+
+    if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
+       syslog(LOG_ERR, "Can't link TAP device to IP");
+       return -1;
+    }
+
+    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
+        syslog (LOG_ERR, "Can't link TAP device to ARP");
+
+    close (if_fd);
+
+    memset(&ifr, 0x0, sizeof(ifr));
+    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
+    ifr.lifr_ip_muxid  = ip_muxid;
+    ifr.lifr_arp_muxid = arp_muxid;
+
+    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
+    {
+      ioctl (ip_fd, I_PUNLINK , arp_muxid);
+      ioctl (ip_fd, I_PUNLINK, ip_muxid);
+      syslog (LOG_ERR, "Can't set multiplexor id");
+    }
+
+    snprintf(dev, dev_size, "tap%d", ppa);
+    return tap_fd;
+}
+
+static int tap_open(char *ifname, int ifname_size)
+{
+    char  dev[10]="";
+    int fd;
+    if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){
+       fprintf(stderr, "Cannot allocate TAP device\n");
+       return -1;
+    }
+    pstrcpy(ifname, ifname_size, dev);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+#elif defined (_AIX)
+static int tap_open(char *ifname, int ifname_size)
+{
+    fprintf (stderr, "no tap on AIX\n");
+    return -1;
+}
+#else
+static int tap_open(char *ifname, int ifname_size)
+{
+    struct ifreq ifr;
+    int fd, ret;
+
+    TFR(fd = open("/dev/net/tun", O_RDWR));
+    if (fd < 0) {
+        fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
+        return -1;
+    }
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+    if (ifname[0] != '\0')
+        pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
+    else
+        pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
+    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+    if (ret != 0) {
+        fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
+        close(fd);
+        return -1;
+    }
+    pstrcpy(ifname, ifname_size, ifr.ifr_name);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+#endif
+
+static int launch_script(const char *setup_script, const char *ifname, int fd)
+{
+    sigset_t oldmask, mask;
+    int pid, status;
+    char *args[3];
+    char **parg;
+
+    sigemptyset(&mask);
+    sigaddset(&mask, SIGCHLD);
+    sigprocmask(SIG_BLOCK, &mask, &oldmask);
+
+    /* try to launch network script */
+    pid = fork();
+    if (pid == 0) {
+        int open_max = sysconf(_SC_OPEN_MAX), i;
+
+        for (i = 0; i < open_max; i++) {
+            if (i != STDIN_FILENO &&
+                i != STDOUT_FILENO &&
+                i != STDERR_FILENO &&
+                i != fd) {
+                close(i);
+            }
+        }
+        parg = args;
+        *parg++ = (char *)setup_script;
+        *parg++ = (char *)ifname;
+        *parg++ = NULL;
+        execv(setup_script, args);
+        _exit(1);
+    } else if (pid > 0) {
+        while (waitpid(pid, &status, 0) != pid) {
+            /* loop */
+        }
+        sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+            return 0;
+        }
+    }
+    fprintf(stderr, "%s: could not launch network script\n", setup_script);
+    return -1;
+}
+
+static int net_tap_init(VLANState *vlan, const char *model,
+                        const char *name, const char *ifname1,
+                        const char *setup_script, const char *down_script)
+{
+    TAPState *s;
+    int fd;
+    char ifname[128];
+
+    if (ifname1 != NULL)
+        pstrcpy(ifname, sizeof(ifname), ifname1);
+    else
+        ifname[0] = '\0';
+    TFR(fd = tap_open(ifname, sizeof(ifname)));
+    if (fd < 0)
+        return -1;
+
+    if (!setup_script || !strcmp(setup_script, "no"))
+        setup_script = "";
+    if (setup_script[0] != '\0') {
+	if (launch_script(setup_script, ifname, fd))
+	    return -1;
+    }
+    s = net_tap_fd_init(vlan, model, name, fd);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "ifname=%s,script=%s,downscript=%s",
+             ifname, setup_script, down_script);
+    if (down_script && strcmp(down_script, "no")) {
+        snprintf(s->down_script, sizeof(s->down_script), "%s", down_script);
+        snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
+    }
+    return 0;
+}
+
+#endif /* !_WIN32 */
+
+#if defined(CONFIG_VDE)
+typedef struct VDEState {
+    VLANClientState *vc;
+    VDECONN *vde;
+} VDEState;
+
+static void vde_to_qemu(void *opaque)
+{
+    VDEState *s = opaque;
+    uint8_t buf[4096];
+    int size;
+
+    size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0);
+    if (size > 0) {
+        qemu_send_packet(s->vc, buf, size);
+    }
+}
+
+static ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    VDEState *s = vc->opaque;
+    ssize_t ret;
+
+    do {
+      ret = vde_send(s->vde, (const char *)buf, size, 0);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+static void vde_cleanup(VLANClientState *vc)
+{
+    VDEState *s = vc->opaque;
+    qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL);
+    vde_close(s->vde);
+    qemu_free(s);
+}
+
+static int net_vde_init(VLANState *vlan, const char *model,
+                        const char *name, const char *sock,
+                        int port, const char *group, int mode)
+{
+    VDEState *s;
+    char *init_group = strlen(group) ? (char *)group : NULL;
+    char *init_sock = strlen(sock) ? (char *)sock : NULL;
+
+    struct vde_open_args args = {
+        .port = port,
+        .group = init_group,
+        .mode = mode,
+    };
+
+    s = qemu_mallocz(sizeof(VDEState));
+    s->vde = vde_open(init_sock, (char *)"QEMU", &args);
+    if (!s->vde){
+        free(s);
+        return -1;
+    }
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, vde_receive,
+                                 NULL, vde_cleanup, s);
+    qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d",
+             sock, vde_datafd(s->vde));
+    return 0;
+}
+#endif
+
+/* network connection */
+typedef struct NetSocketState {
+    VLANClientState *vc;
+    int fd;
+    int state; /* 0 = getting length, 1 = getting data */
+    unsigned int index;
+    unsigned int packet_len;
+    uint8_t buf[4096];
+    struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
+} NetSocketState;
+
+typedef struct NetSocketListenState {
+    VLANState *vlan;
+    char *model;
+    char *name;
+    int fd;
+} NetSocketListenState;
+
+/* XXX: we consider we can send the whole packet without blocking */
+static ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    NetSocketState *s = vc->opaque;
+    uint32_t len;
+    len = htonl(size);
+
+    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
+    return send_all(s->fd, buf, size);
+}
+
+static ssize_t net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    NetSocketState *s = vc->opaque;
+
+    return sendto(s->fd, (const void *)buf, size, 0,
+                  (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
+}
+
+static void net_socket_send(void *opaque)
+{
+    NetSocketState *s = opaque;
+    int size, err;
+    unsigned l;
+    uint8_t buf1[4096];
+    const uint8_t *buf;
+
+    size = recv(s->fd, (void *)buf1, sizeof(buf1), 0);
+    if (size < 0) {
+        err = socket_error();
+        if (err != EWOULDBLOCK)
+            goto eoc;
+    } else if (size == 0) {
+        /* end of connection */
+    eoc:
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+        return;
+    }
+    buf = buf1;
+    while (size > 0) {
+        /* reassemble a packet from the network */
+        switch(s->state) {
+        case 0:
+            l = 4 - s->index;
+            if (l > size)
+                l = size;
+            memcpy(s->buf + s->index, buf, l);
+            buf += l;
+            size -= l;
+            s->index += l;
+            if (s->index == 4) {
+                /* got length */
+                s->packet_len = ntohl(*(uint32_t *)s->buf);
+                s->index = 0;
+                s->state = 1;
+            }
+            break;
+        case 1:
+            l = s->packet_len - s->index;
+            if (l > size)
+                l = size;
+            if (s->index + l <= sizeof(s->buf)) {
+                memcpy(s->buf + s->index, buf, l);
+            } else {
+                fprintf(stderr, "serious error: oversized packet received,"
+                    "connection terminated.\n");
+                s->state = 0;
+                goto eoc;
+            }
+
+            s->index += l;
+            buf += l;
+            size -= l;
+            if (s->index >= s->packet_len) {
+                qemu_send_packet(s->vc, s->buf, s->packet_len);
+                s->index = 0;
+                s->state = 0;
+            }
+            break;
+        }
+    }
+}
+
+static void net_socket_send_dgram(void *opaque)
+{
+    NetSocketState *s = opaque;
+    int size;
+
+    size = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
+    if (size < 0)
+        return;
+    if (size == 0) {
+        /* end of connection */
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        return;
+    }
+    qemu_send_packet(s->vc, s->buf, size);
+}
+
+static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
+{
+    struct ip_mreq imr;
+    int fd;
+    int val, ret;
+    if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
+	fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
+		inet_ntoa(mcastaddr->sin_addr),
+                (int)ntohl(mcastaddr->sin_addr.s_addr));
+	return -1;
+
+    }
+    fd = socket(PF_INET, SOCK_DGRAM, 0);
+    if (fd < 0) {
+        perror("socket(PF_INET, SOCK_DGRAM)");
+        return -1;
+    }
+
+    val = 1;
+    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+                   (const char *)&val, sizeof(val));
+    if (ret < 0) {
+	perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+	goto fail;
+    }
+
+    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
+    if (ret < 0) {
+        perror("bind");
+        goto fail;
+    }
+
+    /* Add host to multicast group */
+    imr.imr_multiaddr = mcastaddr->sin_addr;
+    imr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                     (const char *)&imr, sizeof(struct ip_mreq));
+    if (ret < 0) {
+	perror("setsockopt(IP_ADD_MEMBERSHIP)");
+	goto fail;
+    }
+
+    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+    val = 1;
+    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+                   (const char *)&val, sizeof(val));
+    if (ret < 0) {
+	perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
+	goto fail;
+    }
+
+    socket_set_nonblock(fd);
+    return fd;
+fail:
+    if (fd >= 0)
+        closesocket(fd);
+    return -1;
+}
+
+static void net_socket_cleanup(VLANClientState *vc)
+{
+    NetSocketState *s = vc->opaque;
+    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+    close(s->fd);
+    qemu_free(s);
+}
+
+static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
+                                                const char *model,
+                                                const char *name,
+                                                int fd, int is_connected)
+{
+    struct sockaddr_in saddr;
+    int newfd;
+    socklen_t saddr_len;
+    NetSocketState *s;
+
+    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
+     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
+     * by ONLY ONE process: we must "clone" this dgram socket --jjo
+     */
+
+    if (is_connected) {
+	if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
+	    /* must be bound */
+	    if (saddr.sin_addr.s_addr==0) {
+		fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
+			fd);
+		return NULL;
+	    }
+	    /* clone dgram socket */
+	    newfd = net_socket_mcast_create(&saddr);
+	    if (newfd < 0) {
+		/* error already reported by net_socket_mcast_create() */
+		close(fd);
+		return NULL;
+	    }
+	    /* clone newfd to fd, close newfd */
+	    dup2(newfd, fd);
+	    close(newfd);
+
+	} else {
+	    fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
+		    fd, strerror(errno));
+	    return NULL;
+	}
+    }
+
+    s = qemu_mallocz(sizeof(NetSocketState));
+    s->fd = fd;
+
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive_dgram,
+                                 NULL, net_socket_cleanup, s);
+    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
+
+    /* mcast: save bound address as dst */
+    if (is_connected) s->dgram_dst=saddr;
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+	    "socket: fd=%d (%s mcast=%s:%d)",
+	    fd, is_connected? "cloned" : "",
+	    inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return s;
+}
+
+static void net_socket_connect(void *opaque)
+{
+    NetSocketState *s = opaque;
+    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
+}
+
+static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
+                                                 const char *model,
+                                                 const char *name,
+                                                 int fd, int is_connected)
+{
+    NetSocketState *s;
+    s = qemu_mallocz(sizeof(NetSocketState));
+    s->fd = fd;
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive,
+                                 NULL, net_socket_cleanup, s);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: fd=%d", fd);
+    if (is_connected) {
+        net_socket_connect(s);
+    } else {
+        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
+    }
+    return s;
+}
+
+static NetSocketState *net_socket_fd_init(VLANState *vlan,
+                                          const char *model, const char *name,
+                                          int fd, int is_connected)
+{
+    int so_type=-1, optlen=sizeof(so_type);
+
+    if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
+        (socklen_t *)&optlen)< 0) {
+	fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
+	return NULL;
+    }
+    switch(so_type) {
+    case SOCK_DGRAM:
+        return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
+    case SOCK_STREAM:
+        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+    default:
+        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
+        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
+        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
+    }
+    return NULL;
+}
+
+static void net_socket_accept(void *opaque)
+{
+    NetSocketListenState *s = opaque;
+    NetSocketState *s1;
+    struct sockaddr_in saddr;
+    socklen_t len;
+    int fd;
+
+    for(;;) {
+        len = sizeof(saddr);
+        fd = accept(s->fd, (struct sockaddr *)&saddr, &len);
+        if (fd < 0 && errno != EINTR) {
+            return;
+        } else if (fd >= 0) {
+            break;
+        }
+    }
+    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
+    if (!s1) {
+        closesocket(fd);
+    } else {
+        snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
+                 "socket: connection from %s:%d",
+                 inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    }
+}
+
+static int net_socket_listen_init(VLANState *vlan,
+                                  const char *model,
+                                  const char *name,
+                                  const char *host_str)
+{
+    NetSocketListenState *s;
+    int fd, val, ret;
+    struct sockaddr_in saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    s = qemu_mallocz(sizeof(NetSocketListenState));
+
+    fd = socket(PF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+    socket_set_nonblock(fd);
+
+    /* allow fast reuse */
+    val = 1;
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+
+    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+    if (ret < 0) {
+        perror("bind");
+        return -1;
+    }
+    ret = listen(fd, 0);
+    if (ret < 0) {
+        perror("listen");
+        return -1;
+    }
+    s->vlan = vlan;
+    s->model = strdup(model);
+    s->name = name ? strdup(name) : NULL;
+    s->fd = fd;
+    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
+    return 0;
+}
+
+static int net_socket_connect_init(VLANState *vlan,
+                                   const char *model,
+                                   const char *name,
+                                   const char *host_str)
+{
+    NetSocketState *s;
+    int fd, connected, ret, err;
+    struct sockaddr_in saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    fd = socket(PF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+    socket_set_nonblock(fd);
+
+    connected = 0;
+    for(;;) {
+        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+        if (ret < 0) {
+            err = socket_error();
+            if (err == EINTR || err == EWOULDBLOCK) {
+            } else if (err == EINPROGRESS) {
+                break;
+#ifdef _WIN32
+            } else if (err == WSAEALREADY) {
+                break;
+#endif
+            } else {
+                perror("connect");
+                closesocket(fd);
+                return -1;
+            }
+        } else {
+            connected = 1;
+            break;
+        }
+    }
+    s = net_socket_fd_init(vlan, model, name, fd, connected);
+    if (!s)
+        return -1;
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: connect to %s:%d",
+             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return 0;
+}
+
+static int net_socket_mcast_init(VLANState *vlan,
+                                 const char *model,
+                                 const char *name,
+                                 const char *host_str)
+{
+    NetSocketState *s;
+    int fd;
+    struct sockaddr_in saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+
+    fd = net_socket_mcast_create(&saddr);
+    if (fd < 0)
+	return -1;
+
+    s = net_socket_fd_init(vlan, model, name, fd, 0);
+    if (!s)
+        return -1;
+
+    s->dgram_dst = saddr;
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: mcast=%s:%d",
+             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return 0;
+
+}
+
+typedef struct DumpState {
+    VLANClientState *pcap_vc;
+    int fd;
+    int pcap_caplen;
+} DumpState;
+
+#define PCAP_MAGIC 0xa1b2c3d4
+
+struct pcap_file_hdr {
+    uint32_t magic;
+    uint16_t version_major;
+    uint16_t version_minor;
+    int32_t thiszone;
+    uint32_t sigfigs;
+    uint32_t snaplen;
+    uint32_t linktype;
+};
+
+struct pcap_sf_pkthdr {
+    struct {
+        int32_t tv_sec;
+        int32_t tv_usec;
+    } ts;
+    uint32_t caplen;
+    uint32_t len;
+};
+
+static ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    DumpState *s = vc->opaque;
+    struct pcap_sf_pkthdr hdr;
+    int64_t ts;
+    int caplen;
+
+    /* Early return in case of previous error. */
+    if (s->fd < 0) {
+        return size;
+    }
+
+    ts = muldiv64(qemu_get_clock(vm_clock), 1000000, ticks_per_sec);
+    caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
+
+    hdr.ts.tv_sec = ts / 1000000;
+    hdr.ts.tv_usec = ts % 1000000;
+    hdr.caplen = caplen;
+    hdr.len = size;
+    if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
+        write(s->fd, buf, caplen) != caplen) {
+        qemu_log("-net dump write error - stop dump\n");
+        close(s->fd);
+        s->fd = -1;
+    }
+
+    return size;
+}
+
+static void net_dump_cleanup(VLANClientState *vc)
+{
+    DumpState *s = vc->opaque;
+
+    close(s->fd);
+    qemu_free(s);
+}
+
+static int net_dump_init(Monitor *mon, VLANState *vlan, const char *device,
+                         const char *name, const char *filename, int len)
+{
+    struct pcap_file_hdr hdr;
+    DumpState *s;
+
+    s = qemu_malloc(sizeof(DumpState));
+
+    s->fd = open(filename, O_CREAT | O_WRONLY, 0644);
+    if (s->fd < 0) {
+        config_error(mon, "-net dump: can't open %s\n", filename);
+        return -1;
+    }
+
+    s->pcap_caplen = len;
+
+    hdr.magic = PCAP_MAGIC;
+    hdr.version_major = 2;
+    hdr.version_minor = 4;
+    hdr.thiszone = 0;
+    hdr.sigfigs = 0;
+    hdr.snaplen = s->pcap_caplen;
+    hdr.linktype = 1;
+
+    if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
+        config_error(mon, "-net dump write error: %s\n", strerror(errno));
+        close(s->fd);
+        qemu_free(s);
+        return -1;
+    }
+
+    s->pcap_vc = qemu_new_vlan_client(vlan, device, name, NULL, dump_receive, NULL,
+                                      net_dump_cleanup, s);
+    snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str),
+             "dump to %s (len=%d)", filename, len);
+    return 0;
+}
+
+/* find or alloc a new VLAN */
+VLANState *qemu_find_vlan(int id)
+{
+    VLANState **pvlan, *vlan;
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->id == id)
+            return vlan;
+    }
+    vlan = qemu_mallocz(sizeof(VLANState));
+    vlan->id = id;
+    vlan->next = NULL;
+    pvlan = &first_vlan;
+    while (*pvlan != NULL)
+        pvlan = &(*pvlan)->next;
+    *pvlan = vlan;
+    return vlan;
+}
+
+static int nic_get_free_idx(void)
+{
+    int index;
+
+    for (index = 0; index < MAX_NICS; index++)
+        if (!nd_table[index].used)
+            return index;
+    return -1;
+}
+
+void qemu_check_nic_model(NICInfo *nd, const char *model)
+{
+    const char *models[2];
+
+    models[0] = model;
+    models[1] = NULL;
+
+    qemu_check_nic_model_list(nd, models, model);
+}
+
+void qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
+                               const char *default_model)
+{
+    int i, exit_status = 0;
+
+    if (!nd->model)
+        nd->model = strdup(default_model);
+
+    if (strcmp(nd->model, "?") != 0) {
+        for (i = 0 ; models[i]; i++)
+            if (strcmp(nd->model, models[i]) == 0)
+                return;
+
+        fprintf(stderr, "qemu: Unsupported NIC model: %s\n", nd->model);
+        exit_status = 1;
+    }
+
+    fprintf(stderr, "qemu: Supported NIC models: ");
+    for (i = 0 ; models[i]; i++)
+        fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n');
+
+    exit(exit_status);
+}
+
+int net_client_init(Monitor *mon, const char *device, const char *p)
+{
+    static const char * const fd_params[] = {
+        "vlan", "name", "fd", NULL
+    };
+    char buf[1024];
+    int vlan_id, ret;
+    VLANState *vlan;
+    char *name = NULL;
+
+    vlan_id = 0;
+    if (get_param_value(buf, sizeof(buf), "vlan", p)) {
+        vlan_id = strtol(buf, NULL, 0);
+    }
+    vlan = qemu_find_vlan(vlan_id);
+
+    if (get_param_value(buf, sizeof(buf), "name", p)) {
+        name = qemu_strdup(buf);
+    }
+    if (!strcmp(device, "nic")) {
+        static const char * const nic_params[] = {
+            "vlan", "name", "macaddr", "model", NULL
+        };
+        NICInfo *nd;
+        uint8_t *macaddr;
+        int idx = nic_get_free_idx();
+
+        if (check_params(buf, sizeof(buf), nic_params, p) < 0) {
+            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
+            ret = -1;
+            goto out;
+        }
+        if (idx == -1 || nb_nics >= MAX_NICS) {
+            config_error(mon, "Too Many NICs\n");
+            ret = -1;
+            goto out;
+        }
+        nd = &nd_table[idx];
+        macaddr = nd->macaddr;
+        macaddr[0] = 0x52;
+        macaddr[1] = 0x54;
+        macaddr[2] = 0x00;
+        macaddr[3] = 0x12;
+        macaddr[4] = 0x34;
+        macaddr[5] = 0x56 + idx;
+
+        if (get_param_value(buf, sizeof(buf), "macaddr", p)) {
+            if (parse_macaddr(macaddr, buf) < 0) {
+                config_error(mon, "invalid syntax for ethernet address\n");
+                ret = -1;
+                goto out;
+            }
+        }
+        if (get_param_value(buf, sizeof(buf), "model", p)) {
+            nd->model = strdup(buf);
+        }
+        nd->vlan = vlan;
+        nd->name = name;
+        nd->used = 1;
+        name = NULL;
+        nb_nics++;
+        vlan->nb_guest_devs++;
+        ret = idx;
+    } else
+    if (!strcmp(device, "none")) {
+        if (*p != '\0') {
+            config_error(mon, "'none' takes no parameters\n");
+            ret = -1;
+            goto out;
+        }
+        /* does nothing. It is needed to signal that no network cards
+           are wanted */
+        ret = 0;
+    } else
+#ifdef CONFIG_SLIRP
+    if (!strcmp(device, "user")) {
+        static const char * const slirp_params[] = {
+            "vlan", "name", "hostname", "restrict", "ip", NULL
+        };
+        int restricted = 0;
+        char *ip = NULL;
+
+        if (check_params(buf, sizeof(buf), slirp_params, p) < 0) {
+            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
+            ret = -1;
+            goto out;
+        }
+        if (get_param_value(buf, sizeof(buf), "hostname", p)) {
+            pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf);
+        }
+        if (get_param_value(buf, sizeof(buf), "restrict", p)) {
+            restricted = (buf[0] == 'y') ? 1 : 0;
+        }
+        if (get_param_value(buf, sizeof(buf), "ip", p)) {
+            ip = qemu_strdup(buf);
+        }
+        vlan->nb_host_devs++;
+        ret = net_slirp_init(vlan, device, name, restricted, ip);
+        qemu_free(ip);
+    } else if (!strcmp(device, "channel")) {
+        long port;
+        char name[20], *devname;
+        struct VMChannel *vmc;
+
+        port = strtol(p, &devname, 10);
+        devname++;
+        if (port < 1 || port > 65535) {
+            config_error(mon, "vmchannel wrong port number\n");
+            ret = -1;
+            goto out;
+        }
+        vmc = malloc(sizeof(struct VMChannel));
+        snprintf(name, 20, "vmchannel%ld", port);
+        vmc->hd = qemu_chr_open(name, devname, NULL);
+        if (!vmc->hd) {
+            config_error(mon, "could not open vmchannel device '%s'\n",
+                         devname);
+            ret = -1;
+            goto out;
+        }
+        vmc->port = port;
+        slirp_add_exec(3, vmc->hd, 4, port);
+        qemu_chr_add_handlers(vmc->hd, vmchannel_can_read, vmchannel_read,
+                NULL, vmc);
+        ret = 0;
+    } else
+#endif
+#ifdef _WIN32
+    if (!strcmp(device, "tap")) {
+        static const char * const tap_params[] = {
+            "vlan", "name", "ifname", NULL
+        };
+        char ifname[64];
+
+        if (check_params(buf, sizeof(buf), tap_params, p) < 0) {
+            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
+            ret = -1;
+            goto out;
+        }
+        if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+            config_error(mon, "tap: no interface name\n");
+            ret = -1;
+            goto out;
+        }
+        vlan->nb_host_devs++;
+        ret = tap_win32_init(vlan, device, name, ifname);
+    } else
+#elif defined (_AIX)
+#else
+    if (!strcmp(device, "tap")) {
+        char ifname[64], chkbuf[64];
+        char setup_script[1024], down_script[1024];
+        int fd;
+        vlan->nb_host_devs++;
+        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
+            if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            fd = strtol(buf, NULL, 0);
+            fcntl(fd, F_SETFL, O_NONBLOCK);
+            net_tap_fd_init(vlan, device, name, fd);
+            ret = 0;
+        } else {
+            static const char * const tap_params[] = {
+                "vlan", "name", "ifname", "script", "downscript", NULL
+            };
+            if (check_params(chkbuf, sizeof(chkbuf), tap_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+                ifname[0] = '\0';
+            }
+            if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
+                pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
+            }
+            if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) {
+                pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT);
+            }
+            ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script);
+        }
+    } else
+#endif
+    if (!strcmp(device, "socket")) {
+        char chkbuf[64];
+        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
+            int fd;
+            if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            fd = strtol(buf, NULL, 0);
+            ret = -1;
+            if (net_socket_fd_init(vlan, device, name, fd, 1))
+                ret = 0;
+        } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) {
+            static const char * const listen_params[] = {
+                "vlan", "name", "listen", NULL
+            };
+            if (check_params(chkbuf, sizeof(chkbuf), listen_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            ret = net_socket_listen_init(vlan, device, name, buf);
+        } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
+            static const char * const connect_params[] = {
+                "vlan", "name", "connect", NULL
+            };
+            if (check_params(chkbuf, sizeof(chkbuf), connect_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            ret = net_socket_connect_init(vlan, device, name, buf);
+        } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
+            static const char * const mcast_params[] = {
+                "vlan", "name", "mcast", NULL
+            };
+            if (check_params(chkbuf, sizeof(chkbuf), mcast_params, p) < 0) {
+                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
+                ret = -1;
+                goto out;
+            }
+            ret = net_socket_mcast_init(vlan, device, name, buf);
+        } else {
+            config_error(mon, "Unknown socket options: %s\n", p);
+            ret = -1;
+            goto out;
+        }
+        vlan->nb_host_devs++;
+    } else
+#ifdef CONFIG_VDE
+    if (!strcmp(device, "vde")) {
+        static const char * const vde_params[] = {
+            "vlan", "name", "sock", "port", "group", "mode", NULL
+        };
+        char vde_sock[1024], vde_group[512];
+	int vde_port, vde_mode;
+
+        if (check_params(buf, sizeof(buf), vde_params, p) < 0) {
+            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
+            ret = -1;
+            goto out;
+        }
+        vlan->nb_host_devs++;
+        if (get_param_value(vde_sock, sizeof(vde_sock), "sock", p) <= 0) {
+	    vde_sock[0] = '\0';
+	}
+	if (get_param_value(buf, sizeof(buf), "port", p) > 0) {
+	    vde_port = strtol(buf, NULL, 10);
+	} else {
+	    vde_port = 0;
+	}
+	if (get_param_value(vde_group, sizeof(vde_group), "group", p) <= 0) {
+	    vde_group[0] = '\0';
+	}
+	if (get_param_value(buf, sizeof(buf), "mode", p) > 0) {
+	    vde_mode = strtol(buf, NULL, 8);
+	} else {
+	    vde_mode = 0700;
+	}
+	ret = net_vde_init(vlan, device, name, vde_sock, vde_port, vde_group, vde_mode);
+    } else
+#endif
+    if (!strcmp(device, "dump")) {
+        int len = 65536;
+
+        if (get_param_value(buf, sizeof(buf), "len", p) > 0) {
+            len = strtol(buf, NULL, 0);
+        }
+        if (!get_param_value(buf, sizeof(buf), "file", p)) {
+            snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id);
+        }
+        ret = net_dump_init(mon, vlan, device, name, buf, len);
+    } else {
+        config_error(mon, "Unknown network device: %s\n", device);
+        ret = -1;
+        goto out;
+    }
+    if (ret < 0) {
+        config_error(mon, "Could not initialize device '%s'\n", device);
+    }
+out:
+    qemu_free(name);
+    return ret;
+}
+
+void net_client_uninit(NICInfo *nd)
+{
+    nd->vlan->nb_guest_devs--;
+    nb_nics--;
+    nd->used = 0;
+    free((void *)nd->model);
+}
+
+static int net_host_check_device(const char *device)
+{
+    int i;
+    const char *valid_param_list[] = { "tap", "socket", "dump"
+#ifdef CONFIG_SLIRP
+                                       ,"user"
+#endif
+#ifdef CONFIG_VDE
+                                       ,"vde"
+#endif
+    };
+    for (i = 0; i < sizeof(valid_param_list) / sizeof(char *); i++) {
+        if (!strncmp(valid_param_list[i], device,
+                     strlen(valid_param_list[i])))
+            return 1;
+    }
+
+    return 0;
+}
+
+void net_host_device_add(Monitor *mon, const char *device, const char *opts)
+{
+    if (!net_host_check_device(device)) {
+        monitor_printf(mon, "invalid host network device %s\n", device);
+        return;
+    }
+    if (net_client_init(mon, device, opts ? opts : "") < 0) {
+        monitor_printf(mon, "adding host network device %s failed\n", device);
+    }
+}
+
+void net_host_device_remove(Monitor *mon, int vlan_id, const char *device)
+{
+    VLANState *vlan;
+    VLANClientState *vc;
+
+    vlan = qemu_find_vlan(vlan_id);
+
+    for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
+        if (!strcmp(vc->name, device)) {
+            break;
+        }
+    }
+
+    if (!vc) {
+        monitor_printf(mon, "can't find device %s\n", device);
+        return;
+    }
+    if (!net_host_check_device(vc->model)) {
+        monitor_printf(mon, "invalid host network device %s\n", device);
+        return;
+    }
+    qemu_del_vlan_client(vc);
+}
+
+int net_client_parse(const char *str)
+{
+    const char *p;
+    char *q;
+    char device[64];
+
+    p = str;
+    q = device;
+    while (*p != '\0' && *p != ',') {
+        if ((q - device) < sizeof(device) - 1)
+            *q++ = *p;
+        p++;
+    }
+    *q = '\0';
+    if (*p == ',')
+        p++;
+
+    return net_client_init(NULL, device, p);
+}
+
+void do_info_network(Monitor *mon)
+{
+    VLANState *vlan;
+    VLANClientState *vc;
+
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
+        for(vc = vlan->first_client; vc != NULL; vc = vc->next)
+            monitor_printf(mon, "  %s: %s\n", vc->name, vc->info_str);
+    }
+}
+
+int do_set_link(Monitor *mon, const char *name, const char *up_or_down)
+{
+    VLANState *vlan;
+    VLANClientState *vc = NULL;
+
+    for (vlan = first_vlan; vlan != NULL; vlan = vlan->next)
+        for (vc = vlan->first_client; vc != NULL; vc = vc->next)
+            if (strcmp(vc->name, name) == 0)
+                goto done;
+done:
+
+    if (!vc) {
+        monitor_printf(mon, "could not find network device '%s'", name);
+        return 0;
+    }
+
+    if (strcmp(up_or_down, "up") == 0)
+        vc->link_down = 0;
+    else if (strcmp(up_or_down, "down") == 0)
+        vc->link_down = 1;
+    else
+        monitor_printf(mon, "invalid link status '%s'; only 'up' or 'down' "
+                       "valid\n", up_or_down);
+
+    if (vc->link_status_changed)
+        vc->link_status_changed(vc);
+
+    return 1;
+}
+
+void net_cleanup(void)
+{
+    VLANState *vlan;
+
+    /* close network clients */
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        VLANClientState *vc = vlan->first_client;
+
+        while (vc) {
+            VLANClientState *next = vc->next;
+
+            qemu_del_vlan_client(vc);
+
+            vc = next;
+        }
+    }
+}
+
+void net_client_check(void)
+{
+    VLANState *vlan;
+
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
+            continue;
+        if (vlan->nb_guest_devs == 0)
+            fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
+        if (vlan->nb_host_devs == 0)
+            fprintf(stderr,
+                    "Warning: vlan %d is not connected to host network\n",
+                    vlan->id);
+    }
+}
diff --git a/net.h b/net.h
index 5212b48..89e7706 100644
--- a/net.h
+++ b/net.h
@@ -1,39 +1,84 @@
 #ifndef QEMU_NET_H
 #define QEMU_NET_H
 
+#include "qemu-common.h"
+
 /* VLANs support */
 
 typedef struct VLANClientState VLANClientState;
 
+typedef int (NetCanReceive)(VLANClientState *);
+typedef ssize_t (NetReceive)(VLANClientState *, const uint8_t *, size_t);
+typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int);
+typedef void (NetCleanup) (VLANClientState *);
+typedef void (LinkStatusChanged)(VLANClientState *);
+
 struct VLANClientState {
-    IOReadHandler *fd_read;
+    NetReceive *receive;
+    NetReceiveIOV *receive_iov;
     /* Packets may still be sent if this returns zero.  It's used to
        rate-limit the slirp code.  */
-    IOCanRWHandler *fd_can_read;
+    NetCanReceive *can_receive;
+    NetCleanup *cleanup;
+    LinkStatusChanged *link_status_changed;
+    int link_down;
     void *opaque;
     struct VLANClientState *next;
     struct VLANState *vlan;
+    char *model;
+    char *name;
     char info_str[256];
 };
 
+typedef struct VLANPacket VLANPacket;
+
+typedef void (NetPacketSent) (VLANClientState *);
+
+struct VLANPacket {
+    struct VLANPacket *next;
+    VLANClientState *sender;
+    int size;
+    NetPacketSent *sent_cb;
+    uint8_t data[0];
+};
+
 struct VLANState {
     int id;
     VLANClientState *first_client;
     struct VLANState *next;
     unsigned int nb_guest_devs, nb_host_devs;
+    VLANPacket *send_queue;
+    int delivering;
 };
 
 VLANState *qemu_find_vlan(int id);
 VLANClientState *qemu_new_vlan_client(VLANState *vlan,
-                                      IOReadHandler *fd_read,
-                                      IOCanRWHandler *fd_can_read,
+                                      const char *model,
+                                      const char *name,
+                                      NetCanReceive *can_receive,
+                                      NetReceive *receive,
+                                      NetReceiveIOV *receive_iov,
+                                      NetCleanup *cleanup,
                                       void *opaque);
 void qemu_del_vlan_client(VLANClientState *vc);
+VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque);
 int qemu_can_send_packet(VLANClientState *vc);
+ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
+                          int iovcnt);
+ssize_t qemu_sendv_packet_async(VLANClientState *vc, const struct iovec *iov,
+                                int iovcnt, NetPacketSent *sent_cb);
 void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+ssize_t qemu_send_packet_async(VLANClientState *vc, const uint8_t *buf,
+                               int size, NetPacketSent *sent_cb);
+void qemu_flush_queued_packets(VLANClientState *vc);
+void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]);
+void qemu_check_nic_model(NICInfo *nd, const char *model);
+void qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
+                               const char *default_model);
 void qemu_handler_true(void *opaque);
 
-void do_info_network(void);
+void do_info_network(Monitor *mon);
+int do_set_link(Monitor *mon, const char *name, const char *up_or_down);
 
 /* NIC info */
 
@@ -42,12 +87,29 @@
 struct NICInfo {
     uint8_t macaddr[6];
     const char *model;
+    const char *name;
     VLANState *vlan;
+    void *private;
+    int used;
 };
 
 extern int nb_nics;
 extern NICInfo nd_table[MAX_NICS];
 
+/* BT HCI info */
+
+struct HCIInfo {
+    int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr);
+    void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void (*acl_send)(struct HCIInfo *hci, const uint8_t *data, int len);
+    void *opaque;
+    void (*evt_recv)(void *opaque, const uint8_t *data, int len);
+    void (*acl_recv)(void *opaque, const uint8_t *data, int len);
+};
+
+struct HCIInfo *qemu_next_hci(void);
+
 /* checksumming functions (net-checksum.c) */
 uint32_t net_checksum_add(int len, uint8_t *buf);
 uint16_t net_checksum_finish(uint32_t sum);
@@ -55,4 +117,32 @@
                              uint8_t *addrs, uint8_t *buf);
 void net_checksum_calculate(uint8_t *data, int length);
 
+/* from net.c */
+int net_client_init(Monitor *mon, const char *device, const char *p);
+void net_client_uninit(NICInfo *nd);
+int net_client_parse(const char *str);
+void net_slirp_smb(const char *exported_dir);
+void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2);
+void net_cleanup(void);
+int slirp_is_inited(void);
+void net_client_check(void);
+void net_host_device_add(Monitor *mon, const char *device, const char *opts);
+void net_host_device_remove(Monitor *mon, int vlan_id, const char *device);
+
+#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
+#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
+#ifdef __sun__
+#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
+#else
+#define SMBD_COMMAND "/usr/sbin/smbd"
+#endif
+
+void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr);
+VLANClientState *qdev_get_vlan_client(DeviceState *dev,
+                                      NetCanReceive *can_receive,
+                                      NetReceive *receive,
+                                      NetReceiveIOV *receive_iov,
+                                      NetCleanup *cleanup,
+                                      void *opaque);
+
 #endif
diff --git a/osdep.c b/osdep.c
index 49193e9..5065079 100644
--- a/osdep.c
+++ b/osdep.c
@@ -67,15 +67,17 @@
 
 #else
 
-#if defined(USE_KQEMU)
+#if defined(CONFIG_KQEMU)
 
 #ifdef __OpenBSD__
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/mount.h>
 #else
+#ifndef __FreeBSD__
 #include <sys/vfs.h>
 #endif
+#endif
 
 #include <sys/mman.h>
 #include <fcntl.h>
@@ -86,7 +88,8 @@
     static int phys_ram_size = 0;
     void *ptr;
 
-#ifdef __OpenBSD__ /* no need (?) for a dummy file on OpenBSD */
+/* no need (?) for a dummy file on OpenBSD/FreeBSD */
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
     int map_anon = MAP_ANON;
 #else
     int map_anon = 0;
@@ -153,7 +156,7 @@
     }
     size = (size + 4095) & ~4095;
     ftruncate(phys_ram_fd, phys_ram_size + size);
-#endif /* !__OpenBSD__ */
+#endif /* !(__OpenBSD__ || __FreeBSD__ || __DragonFly__) */
     ptr = mmap(NULL,
                size,
                PROT_WRITE | PROT_READ, map_anon | MAP_SHARED,
@@ -182,7 +185,7 @@
     if (ret != 0)
         return NULL;
     return ptr;
-#elif defined(_BSD)
+#elif defined(HOST_BSD)
     return valloc(size);
 #else
     return memalign(alignment, size);
@@ -192,20 +195,16 @@
 /* alloc shared memory pages */
 void *qemu_vmalloc(size_t size)
 {
-#if defined(USE_KQEMU)
+#if defined(CONFIG_KQEMU)
     if (kqemu_allowed)
         return kqemu_vmalloc(size);
 #endif
-#ifdef _BSD
-    return valloc(size);
-#else
-    return memalign(4096, size);
-#endif
+    return qemu_memalign(getpagesize(), size);
 }
 
 void qemu_vfree(void *ptr)
 {
-#if defined(USE_KQEMU)
+#if defined(CONFIG_KQEMU)
     if (kqemu_allowed)
         kqemu_vfree(ptr);
 #endif
@@ -283,6 +282,18 @@
      Do not set errno on error.  */
   return 0;
 }
+
+int  ffs(int  val)
+{
+	int  nn;
+	
+	for (nn = 0; nn < sizeof(int)*8; nn++)
+		if (val & (1 << nn))
+			return nn+1;
+
+	return 0;
+}
+
 #endif /* _WIN32 */
 
 
diff --git a/osdep.h b/osdep.h
index 626cea1..ffbf221 100644
--- a/osdep.h
+++ b/osdep.h
@@ -7,6 +7,10 @@
 #include <sys/signal.h>
 #endif
 
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
 #ifndef glue
 #define xglue(x, y) x ## y
 #define glue(x, y) xglue(x, y)
@@ -14,12 +18,6 @@
 #define tostring(s)	#s
 #endif
 
-#ifndef container_of
-#define container_of(ptr, type, member) ({                      \
-        const typeof(((type *) 0)->member) *__mptr = (ptr);     \
-        (type *) ((char *) __mptr - offsetof(type, member));})
-#endif
-
 #ifndef likely
 #if __GNUC__ < 3
 #define __builtin_expect(x, n) (x)
@@ -54,8 +52,10 @@
 #define always_inline inline
 #else
 #define always_inline __attribute__ (( always_inline )) __inline__
+#ifdef __OPTIMIZE__
 #define inline always_inline
 #endif
+#endif
 #else
 #define inline always_inline
 #endif
@@ -68,6 +68,13 @@
 
 #define qemu_printf printf
 
+#if defined (__GNUC__) && defined (__GNUC_MINOR__)
+# define QEMU_GNUC_PREREQ(maj, min) \
+         ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define QEMU_GNUC_PREREQ(maj, min) 0
+#endif
+
 void *qemu_memalign(size_t alignment, size_t size);
 void *qemu_vmalloc(size_t size);
 void qemu_vfree(void *ptr);
diff --git a/ppc-dis.c b/ppc-dis.c
index f9ae53e..e3bc170 100644
--- a/ppc-dis.c
+++ b/ppc-dis.c
@@ -1,5 +1,6 @@
 /* ppc-dis.c -- Disassemble PowerPC instructions
-   Copyright 1994 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
 
 This file is part of GDB, GAS, and the GNU binutils.
@@ -16,11 +17,13 @@
 
 You should have received a copy of the GNU General Public License
 along with this file; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 #include "dis-asm.h"
+#define BFD_DEFAULT_TARGET_SIZE 64
 
 /* ppc.h -- Header file for PowerPC opcode table
-   Copyright 1994 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+   2007 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
 
 This file is part of GDB, GAS, and the GNU binutils.
@@ -37,7 +40,7 @@
 
 You should have received a copy of the GNU General Public License
 along with this file; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 /* The opcode table is an array of struct powerpc_opcode.  */
 
@@ -48,18 +51,18 @@
 
   /* The opcode itself.  Those bits which will be filled in with
      operands are zeroes.  */
-  uint32_t opcode;
+  unsigned long opcode;
 
   /* The opcode mask.  This is used by the disassembler.  This is a
      mask containing ones indicating those bits which must match the
      opcode field, and zeroes indicating those bits which need not
      match (and are presumably filled in by operands).  */
-  uint32_t mask;
+  unsigned long mask;
 
   /* One bit flags for the opcode.  These are used to indicate which
      specific processors support the instructions.  The defined values
      are listed below.  */
-  uint32_t flags;
+  unsigned long flags;
 
   /* An array of operand codes.  Each code is an index into the
      operand table.  They appear in the order which the operands must
@@ -76,24 +79,92 @@
 /* Values defined for the flags field of a struct powerpc_opcode.  */
 
 /* Opcode is defined for the PowerPC architecture.  */
-#define PPC_OPCODE_PPC (01)
+#define PPC_OPCODE_PPC			 1
 
 /* Opcode is defined for the POWER (RS/6000) architecture.  */
-#define PPC_OPCODE_POWER (02)
+#define PPC_OPCODE_POWER		 2
 
 /* Opcode is defined for the POWER2 (Rios 2) architecture.  */
-#define PPC_OPCODE_POWER2 (04)
+#define PPC_OPCODE_POWER2		 4
 
 /* Opcode is only defined on 32 bit architectures.  */
-#define PPC_OPCODE_32 (010)
+#define PPC_OPCODE_32			 8
 
 /* Opcode is only defined on 64 bit architectures.  */
-#define PPC_OPCODE_64 (020)
+#define PPC_OPCODE_64		      0x10
 
 /* Opcode is supported by the Motorola PowerPC 601 processor.  The 601
    is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions,
    but it also supports many additional POWER instructions.  */
-#define PPC_OPCODE_601 (040)
+#define PPC_OPCODE_601		      0x20
+
+/* Opcode is supported in both the Power and PowerPC architectures
+   (ie, compiler's -mcpu=common or assembler's -mcom).  */
+#define PPC_OPCODE_COMMON	      0x40
+
+/* Opcode is supported for any Power or PowerPC platform (this is
+   for the assembler's -many option, and it eliminates duplicates).  */
+#define PPC_OPCODE_ANY		      0x80
+
+/* Opcode is supported as part of the 64-bit bridge.  */
+#define PPC_OPCODE_64_BRIDGE	     0x100
+
+/* Opcode is supported by Altivec Vector Unit */
+#define PPC_OPCODE_ALTIVEC	     0x200
+
+/* Opcode is supported by PowerPC 403 processor.  */
+#define PPC_OPCODE_403		     0x400
+
+/* Opcode is supported by PowerPC BookE processor.  */
+#define PPC_OPCODE_BOOKE	     0x800
+
+/* Opcode is only supported by 64-bit PowerPC BookE processor.  */
+#define PPC_OPCODE_BOOKE64	    0x1000
+
+/* Opcode is supported by PowerPC 440 processor.  */
+#define PPC_OPCODE_440		    0x2000
+
+/* Opcode is only supported by Power4 architecture.  */
+#define PPC_OPCODE_POWER4	    0x4000
+
+/* Opcode isn't supported by Power4 architecture.  */
+#define PPC_OPCODE_NOPOWER4	    0x8000
+
+/* Opcode is only supported by POWERPC Classic architecture.  */
+#define PPC_OPCODE_CLASSIC	   0x10000
+
+/* Opcode is only supported by e500x2 Core.  */
+#define PPC_OPCODE_SPE		   0x20000
+
+/* Opcode is supported by e500x2 Integer select APU.  */
+#define PPC_OPCODE_ISEL		   0x40000
+
+/* Opcode is an e500 SPE floating point instruction.  */
+#define PPC_OPCODE_EFS		   0x80000
+
+/* Opcode is supported by branch locking APU.  */
+#define PPC_OPCODE_BRLOCK	  0x100000
+
+/* Opcode is supported by performance monitor APU.  */
+#define PPC_OPCODE_PMR		  0x200000
+
+/* Opcode is supported by cache locking APU.  */
+#define PPC_OPCODE_CACHELCK	  0x400000
+
+/* Opcode is supported by machine check APU.  */
+#define PPC_OPCODE_RFMCI	  0x800000
+
+/* Opcode is only supported by Power5 architecture.  */
+#define PPC_OPCODE_POWER5	 0x1000000
+
+/* Opcode is supported by PowerPC e300 family.  */
+#define PPC_OPCODE_E300          0x2000000
+
+/* Opcode is only supported by Power6 architecture.  */
+#define PPC_OPCODE_POWER6	 0x4000000
+
+/* Opcode is only supported by PowerPC Cell family.  */
+#define PPC_OPCODE_CELL		 0x8000000
 
 /* A macro to extract the major opcode from an instruction.  */
 #define PPC_OP(i) (((i) >> 26) & 0x3f)
@@ -102,20 +173,21 @@
 
 struct powerpc_operand
 {
-  /* The number of bits in the operand.  */
-  int bits;
+  /* A bitmask of bits in the operand.  */
+  unsigned int bitm;
 
-  /* How far the operand is left shifted in the instruction.  */
+  /* How far the operand is left shifted in the instruction.
+     -1 to indicate that BITM and SHIFT cannot be used to determine
+     where the operand goes in the insn.  */
   int shift;
 
   /* Insertion function.  This is used by the assembler.  To insert an
      operand value into an instruction, check this field.
 
      If it is NULL, execute
-         i |= (op & ((1 << o->bits) - 1)) << o->shift;
+	 i |= (op & o->bitm) << o->shift;
      (i is the instruction which we are filling in, o is a pointer to
-     this structure, and op is the opcode value; this assumes twos
-     complement arithmetic).
+     this structure, and op is the operand value).
 
      If this field is not NULL, then simply call it with the
      instruction and the operand value.  It will return the new value
@@ -124,19 +196,18 @@
      string (the operand will be inserted in any case).  If the
      operand value is legal, *ERRMSG will be unchanged (most operands
      can accept any value).  */
-  unsigned long (*insert)(uint32_t instruction, int32_t op,
-				   const char **errmsg);
+  unsigned long (*insert)
+    (unsigned long instruction, long op, int dialect, const char **errmsg);
 
   /* Extraction function.  This is used by the disassembler.  To
      extract this operand type from an instruction, check this field.
 
      If it is NULL, compute
-         op = ((i) >> o->shift) & ((1 << o->bits) - 1);
-	 if ((o->flags & PPC_OPERAND_SIGNED) != 0
-	     && (op & (1 << (o->bits - 1))) != 0)
-	   op -= 1 << o->bits;
+	 op = (i >> o->shift) & o->bitm;
+	 if ((o->flags & PPC_OPERAND_SIGNED) != 0)
+	   sign_extend (op);
      (i is the instruction, o is a pointer to this structure, and op
-     is the result; this assumes twos complement arithmetic).
+     is the result).
 
      If this field is not NULL, then simply call it with the
      instruction value.  It will return the value of the operand.  If
@@ -144,27 +215,28 @@
      non-zero if this operand type can not actually be extracted from
      this operand (i.e., the instruction does not match).  If the
      operand is valid, *INVALID will not be changed.  */
-  long (*extract) (uint32_t instruction, int *invalid);
+  long (*extract) (unsigned long instruction, int dialect, int *invalid);
 
   /* One bit syntax flags.  */
-  uint32_t flags;
+  unsigned long flags;
 };
 
 /* Elements in the table are retrieved by indexing with values from
    the operands field of the powerpc_opcodes table.  */
 
 extern const struct powerpc_operand powerpc_operands[];
+extern const unsigned int num_powerpc_operands;
 
 /* Values defined for the flags field of a struct powerpc_operand.  */
 
 /* This operand takes signed values.  */
-#define PPC_OPERAND_SIGNED (01)
+#define PPC_OPERAND_SIGNED (0x1)
 
 /* This operand takes signed values, but also accepts a full positive
    range of values when running in 32 bit mode.  That is, if bits is
    16, it takes any value from -0x8000 to 0xffff.  In 64 bit mode,
    this flag is ignored.  */
-#define PPC_OPERAND_SIGNOPT (02)
+#define PPC_OPERAND_SIGNOPT (0x2)
 
 /* This operand does not actually exist in the assembler input.  This
    is used to support extended mnemonics such as mr, for which two
@@ -172,14 +244,14 @@
    insert function with any op value.  The disassembler should call
    the extract function, ignore the return value, and check the value
    placed in the valid argument.  */
-#define PPC_OPERAND_FAKE (04)
+#define PPC_OPERAND_FAKE (0x4)
 
 /* The next operand should be wrapped in parentheses rather than
    separated from this one by a comma.  This is used for the load and
    store instructions which want their operands to look like
        reg,displacement(reg)
    */
-#define PPC_OPERAND_PARENS (010)
+#define PPC_OPERAND_PARENS (0x8)
 
 /* This operand may use the symbolic names for the CR fields, which
    are
@@ -188,31 +260,34 @@
        cr4 4	cr5 5	cr6 6	cr7 7
    These may be combined arithmetically, as in cr2*4+gt.  These are
    only supported on the PowerPC, not the POWER.  */
-#define PPC_OPERAND_CR (020)
+#define PPC_OPERAND_CR (0x10)
 
 /* This operand names a register.  The disassembler uses this to print
    register names with a leading 'r'.  */
-#define PPC_OPERAND_GPR (040)
+#define PPC_OPERAND_GPR (0x20)
+
+/* Like PPC_OPERAND_GPR, but don't print a leading 'r' for r0.  */
+#define PPC_OPERAND_GPR_0 (0x40)
 
 /* This operand names a floating point register.  The disassembler
    prints these with a leading 'f'.  */
-#define PPC_OPERAND_FPR (0100)
+#define PPC_OPERAND_FPR (0x80)
 
 /* This operand is a relative branch displacement.  The disassembler
    prints these symbolically if possible.  */
-#define PPC_OPERAND_RELATIVE (0200)
+#define PPC_OPERAND_RELATIVE (0x100)
 
 /* This operand is an absolute branch address.  The disassembler
    prints these symbolically if possible.  */
-#define PPC_OPERAND_ABSOLUTE (0400)
+#define PPC_OPERAND_ABSOLUTE (0x200)
 
 /* This operand is optional, and is zero if omitted.  This is used for
-   the optional BF and L fields in the comparison instructions.  The
+   example, in the optional BF field in the comparison instructions.  The
    assembler must count the number of operands remaining on the line,
    and the number of operands remaining for the opcode, and decide
    whether this operand is present or not.  The disassembler should
    print this operand out only if it is not zero.  */
-#define PPC_OPERAND_OPTIONAL (01000)
+#define PPC_OPERAND_OPTIONAL (0x400)
 
 /* This flag is only used with PPC_OPERAND_OPTIONAL.  If this operand
    is omitted, then for the next operand use this operand value plus
@@ -220,14 +295,27 @@
    hack is needed because the Power rotate instructions can take
    either 4 or 5 operands.  The disassembler should print this operand
    out regardless of the PPC_OPERAND_OPTIONAL field.  */
-#define PPC_OPERAND_NEXT (02000)
+#define PPC_OPERAND_NEXT (0x800)
 
 /* This operand should be regarded as a negative number for the
    purposes of overflow checking (i.e., the normal most negative
    number is disallowed and one more than the normal most positive
    number is allowed).  This flag will only be set for a signed
    operand.  */
-#define PPC_OPERAND_NEGATIVE (04000)
+#define PPC_OPERAND_NEGATIVE (0x1000)
+
+/* This operand names a vector unit register.  The disassembler
+   prints these with a leading 'v'.  */
+#define PPC_OPERAND_VR (0x2000)
+
+/* This operand is for the DS field in a DS form instruction.  */
+#define PPC_OPERAND_DS (0x4000)
+
+/* This operand is for the DQ field in a DQ form instruction.  */
+#define PPC_OPERAND_DQ (0x8000)
+
+/* Valid range of operand is 0..n rather than 0..n-1.  */
+#define PPC_OPERAND_PLUS1 (0x10000)
 
 /* The POWER and PowerPC assemblers use a few macros.  We keep them
    with the operands table for simplicity.  The macro table is an
@@ -244,7 +332,7 @@
   /* One bit flags for the opcode.  These are used to indicate which
      specific processors support the instructions.  The values are the
      same as those for the struct powerpc_opcode flags field.  */
-  uint32_t flags;
+  unsigned long flags;
 
   /* A format string to turn the macro into a normal instruction.
      Each %N in the string is replaced with operand number N (zero
@@ -256,24 +344,26 @@
 extern const int powerpc_num_macros;
 
 /* ppc-opc.c -- PowerPC opcode list
-   Copyright 1994 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
 
-This file is part of GDB, GAS, and the GNU binutils.
+   This file is part of GDB, GAS, and the GNU binutils.
 
-GDB, GAS, and the GNU binutils are free software; you can redistribute
-them and/or modify them under the terms of the GNU General Public
-License as published by the Free Software Foundation; either version
-2, or (at your option) any later version.
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   2, or (at your option) any later version.
 
-GDB, GAS, and the GNU binutils are distributed in the hope that they
-will be useful, but WITHOUT ANY WARRANTY; without even the implied
-warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
-the GNU General Public License for more details.
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   will be useful, but WITHOUT ANY WARRANTY; without even the implied
+   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+   the GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this file; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, write to the Free
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 /* This file holds the PowerPC opcode table.  The opcode table
    includes almost all of the extended instruction mnemonics.  This
@@ -288,355 +378,523 @@
 
 /* Local insertion and extraction functions.  */
 
-static unsigned long insert_bat (uint32_t, int32_t, const char **);
-static long extract_bat(uint32_t, int *);
-static unsigned long insert_bba(uint32_t, int32_t, const char **);
-static long extract_bba(uint32_t, int *);
-static unsigned long insert_bd(uint32_t, int32_t, const char **);
-static long extract_bd(uint32_t, int *);
-static unsigned long insert_bdm(uint32_t, int32_t, const char **);
-static long extract_bdm(uint32_t, int *);
-static unsigned long insert_bdp(uint32_t, int32_t, const char **);
-static long extract_bdp(uint32_t, int *);
-static unsigned long insert_bo(uint32_t, int32_t, const char **);
-static long extract_bo(uint32_t, int *);
-static unsigned long insert_boe(uint32_t, int32_t, const char **);
-static long extract_boe(uint32_t, int *);
-static unsigned long insert_ds(uint32_t, int32_t, const char **);
-static long extract_ds(uint32_t, int *);
-static unsigned long insert_li(uint32_t, int32_t, const char **);
-static long extract_li(uint32_t, int *);
-static unsigned long insert_mbe(uint32_t, int32_t, const char **);
-static long extract_mbe(uint32_t, int *);
-static unsigned long insert_mb6(uint32_t, int32_t, const char **);
-static long extract_mb6(uint32_t, int *);
-static unsigned long insert_nb(uint32_t, int32_t, const char **);
-static long extract_nb(uint32_t, int *);
-static unsigned long insert_nsi(uint32_t, int32_t, const char **);
-static long extract_nsi(uint32_t, int *);
-static unsigned long insert_ral(uint32_t, int32_t, const char **);
-static unsigned long insert_ram(uint32_t, int32_t, const char **);
-static unsigned long insert_ras(uint32_t, int32_t, const char **);
-static unsigned long insert_rbs(uint32_t, int32_t, const char **);
-static long extract_rbs(uint32_t, int *);
-static unsigned long insert_sh6(uint32_t, int32_t, const char **);
-static long extract_sh6(uint32_t, int *);
-static unsigned long insert_spr(uint32_t, int32_t, const char **);
-static long extract_spr(uint32_t, int *);
-static unsigned long insert_tbr(uint32_t, int32_t, const char **);
-static long extract_tbr(uint32_t, int *);
+static unsigned long insert_bat (unsigned long, long, int, const char **);
+static long extract_bat (unsigned long, int, int *);
+static unsigned long insert_bba (unsigned long, long, int, const char **);
+static long extract_bba (unsigned long, int, int *);
+static unsigned long insert_bdm (unsigned long, long, int, const char **);
+static long extract_bdm (unsigned long, int, int *);
+static unsigned long insert_bdp (unsigned long, long, int, const char **);
+static long extract_bdp (unsigned long, int, int *);
+static unsigned long insert_bo (unsigned long, long, int, const char **);
+static long extract_bo (unsigned long, int, int *);
+static unsigned long insert_boe (unsigned long, long, int, const char **);
+static long extract_boe (unsigned long, int, int *);
+static unsigned long insert_fxm (unsigned long, long, int, const char **);
+static long extract_fxm (unsigned long, int, int *);
+static unsigned long insert_mbe (unsigned long, long, int, const char **);
+static long extract_mbe (unsigned long, int, int *);
+static unsigned long insert_mb6 (unsigned long, long, int, const char **);
+static long extract_mb6 (unsigned long, int, int *);
+static long extract_nb (unsigned long, int, int *);
+static unsigned long insert_nsi (unsigned long, long, int, const char **);
+static long extract_nsi (unsigned long, int, int *);
+static unsigned long insert_ral (unsigned long, long, int, const char **);
+static unsigned long insert_ram (unsigned long, long, int, const char **);
+static unsigned long insert_raq (unsigned long, long, int, const char **);
+static unsigned long insert_ras (unsigned long, long, int, const char **);
+static unsigned long insert_rbs (unsigned long, long, int, const char **);
+static long extract_rbs (unsigned long, int, int *);
+static unsigned long insert_sh6 (unsigned long, long, int, const char **);
+static long extract_sh6 (unsigned long, int, int *);
+static unsigned long insert_spr (unsigned long, long, int, const char **);
+static long extract_spr (unsigned long, int, int *);
+static unsigned long insert_sprg (unsigned long, long, int, const char **);
+static long extract_sprg (unsigned long, int, int *);
+static unsigned long insert_tbr (unsigned long, long, int, const char **);
+static long extract_tbr (unsigned long, int, int *);
 
 /* The operands table.
 
-   The fields are bits, shift, signed, insert, extract, flags.  */
+   The fields are bitm, shift, insert, extract, flags.
+
+   We used to put parens around the various additions, like the one
+   for BA just below.  However, that caused trouble with feeble
+   compilers with a limit on depth of a parenthesized expression, like
+   (reportedly) the compiler in Microsoft Developer Studio 5.  So we
+   omit the parens, since the macros are never used in a context where
+   the addition will be ambiguous.  */
 
 const struct powerpc_operand powerpc_operands[] =
 {
   /* The zero index is used to indicate the end of the list of
      operands.  */
-#define UNUSED (0)
-  { 0, 0, 0, 0, 0 },
+#define UNUSED 0
+  { 0, 0, NULL, NULL, 0 },
 
   /* The BA field in an XL form instruction.  */
-#define BA (1)
-#define BA_MASK (0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_CR },
+#define BA UNUSED + 1
+  /* The BI field in a B form or XL form instruction.  */
+#define BI BA
+#define BI_MASK (0x1f << 16)
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_CR },
 
   /* The BA field in an XL form instruction when it must be the same
      as the BT field in the same instruction.  */
-#define BAT (2)
-  { 5, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE },
+#define BAT BA + 1
+  { 0x1f, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE },
 
   /* The BB field in an XL form instruction.  */
-#define BB (3)
+#define BB BAT + 1
 #define BB_MASK (0x1f << 11)
-  { 5, 11, 0, 0, PPC_OPERAND_CR },
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_CR },
 
   /* The BB field in an XL form instruction when it must be the same
      as the BA field in the same instruction.  */
-#define BBA (4)
-  { 5, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE },
+#define BBA BB + 1
+  { 0x1f, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE },
 
   /* The BD field in a B form instruction.  The lower two bits are
      forced to zero.  */
-#define BD (5)
-  { 16, 0, insert_bd, extract_bd, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+#define BD BBA + 1
+  { 0xfffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
 
   /* The BD field in a B form instruction when absolute addressing is
      used.  */
-#define BDA (6)
-  { 16, 0, insert_bd, extract_bd, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+#define BDA BD + 1
+  { 0xfffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
 
   /* The BD field in a B form instruction when the - modifier is used.
      This sets the y bit of the BO field appropriately.  */
-#define BDM (7)
-  { 16, 0, insert_bdm, extract_bdm,
+#define BDM BDA + 1
+  { 0xfffc, 0, insert_bdm, extract_bdm,
       PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
 
   /* The BD field in a B form instruction when the - modifier is used
      and absolute address is used.  */
-#define BDMA (8)
-  { 16, 0, insert_bdm, extract_bdm,
+#define BDMA BDM + 1
+  { 0xfffc, 0, insert_bdm, extract_bdm,
       PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
 
   /* The BD field in a B form instruction when the + modifier is used.
      This sets the y bit of the BO field appropriately.  */
-#define BDP (9)
-  { 16, 0, insert_bdp, extract_bdp,
+#define BDP BDMA + 1
+  { 0xfffc, 0, insert_bdp, extract_bdp,
       PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
 
   /* The BD field in a B form instruction when the + modifier is used
      and absolute addressing is used.  */
-#define BDPA (10)
-  { 16, 0, insert_bdp, extract_bdp,
+#define BDPA BDP + 1
+  { 0xfffc, 0, insert_bdp, extract_bdp,
       PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
 
   /* The BF field in an X or XL form instruction.  */
-#define BF (11)
-  { 3, 23, 0, 0, PPC_OPERAND_CR },
+#define BF BDPA + 1
+  /* The CRFD field in an X form instruction.  */
+#define CRFD BF
+  { 0x7, 23, NULL, NULL, PPC_OPERAND_CR },
+
+  /* The BF field in an X or XL form instruction.  */
+#define BFF BF + 1
+  { 0x7, 23, NULL, NULL, 0 },
 
   /* An optional BF field.  This is used for comparison instructions,
      in which an omitted BF field is taken as zero.  */
-#define OBF (12)
-  { 3, 23, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+#define OBF BFF + 1
+  { 0x7, 23, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
 
   /* The BFA field in an X or XL form instruction.  */
-#define BFA (13)
-  { 3, 18, 0, 0, PPC_OPERAND_CR },
-
-  /* The BI field in a B form or XL form instruction.  */
-#define BI (14)
-#define BI_MASK (0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_CR },
+#define BFA OBF + 1
+  { 0x7, 18, NULL, NULL, PPC_OPERAND_CR },
 
   /* The BO field in a B form instruction.  Certain values are
      illegal.  */
-#define BO (15)
+#define BO BFA + 1
 #define BO_MASK (0x1f << 21)
-  { 5, 21, insert_bo, extract_bo, 0 },
+  { 0x1f, 21, insert_bo, extract_bo, 0 },
 
   /* The BO field in a B form instruction when the + or - modifier is
      used.  This is like the BO field, but it must be even.  */
-#define BOE (16)
-  { 5, 21, insert_boe, extract_boe, 0 },
+#define BOE BO + 1
+  { 0x1e, 21, insert_boe, extract_boe, 0 },
+
+#define BH BOE + 1
+  { 0x3, 11, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
   /* The BT field in an X or XL form instruction.  */
-#define BT (17)
-  { 5, 21, 0, 0, PPC_OPERAND_CR },
+#define BT BH + 1
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_CR },
 
   /* The condition register number portion of the BI field in a B form
      or XL form instruction.  This is used for the extended
      conditional branch mnemonics, which set the lower two bits of the
      BI field.  This field is optional.  */
-#define CR (18)
-  { 3, 18, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+#define CR BT + 1
+  { 0x7, 18, NULL, NULL, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The CRB field in an X form instruction.  */
+#define CRB CR + 1
+  /* The MB field in an M form instruction.  */
+#define MB CRB
+#define MB_MASK (0x1f << 6)
+  { 0x1f, 6, NULL, NULL, 0 },
+
+  /* The CRFS field in an X form instruction.  */
+#define CRFS CRB + 1
+  { 0x7, 0, NULL, NULL, PPC_OPERAND_CR },
+
+  /* The CT field in an X form instruction.  */
+#define CT CRFS + 1
+  /* The MO field in an mbar instruction.  */
+#define MO CT
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
   /* The D field in a D form instruction.  This is a displacement off
      a register, and implies that the next operand is a register in
      parentheses.  */
-#define D (19)
-  { 16, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+#define D CT + 1
+  { 0xffff, 0, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DE field in a DE form instruction.  This is like D, but is 12
+     bits only.  */
+#define DE D + 1
+  { 0xfff, 4, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DES field in a DES form instruction.  This is like DS, but is 14
+     bits only (12 stored.)  */
+#define DES DE + 1
+  { 0x3ffc, 2, NULL, NULL, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DQ field in a DQ form instruction.  This is like D, but the
+     lower four bits are forced to zero. */
+#define DQ DES + 1
+  { 0xfff0, 0, NULL, NULL,
+    PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DQ },
 
   /* The DS field in a DS form instruction.  This is like D, but the
      lower two bits are forced to zero.  */
-#define DS (20)
-  { 16, 0, insert_ds, extract_ds, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+#define DS DQ + 1
+  { 0xfffc, 0, NULL, NULL,
+    PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED | PPC_OPERAND_DS },
+
+  /* The E field in a wrteei instruction.  */
+#define E DS + 1
+  { 0x1, 15, NULL, NULL, 0 },
 
   /* The FL1 field in a POWER SC form instruction.  */
-#define FL1 (21)
-  { 4, 12, 0, 0, 0 },
+#define FL1 E + 1
+  /* The U field in an X form instruction.  */
+#define U FL1
+  { 0xf, 12, NULL, NULL, 0 },
 
   /* The FL2 field in a POWER SC form instruction.  */
-#define FL2 (22)
-  { 3, 2, 0, 0, 0 },
+#define FL2 FL1 + 1
+  { 0x7, 2, NULL, NULL, 0 },
 
   /* The FLM field in an XFL form instruction.  */
-#define FLM (23)
-  { 8, 17, 0, 0, 0 },
+#define FLM FL2 + 1
+  { 0xff, 17, NULL, NULL, 0 },
 
   /* The FRA field in an X or A form instruction.  */
-#define FRA (24)
+#define FRA FLM + 1
 #define FRA_MASK (0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_FPR },
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_FPR },
 
   /* The FRB field in an X or A form instruction.  */
-#define FRB (25)
+#define FRB FRA + 1
 #define FRB_MASK (0x1f << 11)
-  { 5, 11, 0, 0, PPC_OPERAND_FPR },
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_FPR },
 
   /* The FRC field in an A form instruction.  */
-#define FRC (26)
+#define FRC FRB + 1
 #define FRC_MASK (0x1f << 6)
-  { 5, 6, 0, 0, PPC_OPERAND_FPR },
+  { 0x1f, 6, NULL, NULL, PPC_OPERAND_FPR },
 
   /* The FRS field in an X form instruction or the FRT field in a D, X
      or A form instruction.  */
-#define FRS (27)
-#define FRT (FRS)
-  { 5, 21, 0, 0, PPC_OPERAND_FPR },
+#define FRS FRC + 1
+#define FRT FRS
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_FPR },
 
   /* The FXM field in an XFX instruction.  */
-#define FXM (28)
-#define FXM_MASK (0xff << 12)
-  { 8, 12, 0, 0, 0 },
+#define FXM FRS + 1
+  { 0xff, 12, insert_fxm, extract_fxm, 0 },
+
+  /* Power4 version for mfcr.  */
+#define FXM4 FXM + 1
+  { 0xff, 12, insert_fxm, extract_fxm, PPC_OPERAND_OPTIONAL },
 
   /* The L field in a D or X form instruction.  */
-#define L (29)
-  { 1, 21, 0, 0, PPC_OPERAND_OPTIONAL },
+#define L FXM4 + 1
+  { 0x1, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
-  /* The LEV field in a POWER SC form instruction.  */
-#define LEV (30)
-  { 7, 5, 0, 0, 0 },
+  /* The LEV field in a POWER SVC form instruction.  */
+#define SVC_LEV L + 1
+  { 0x7f, 5, NULL, NULL, 0 },
+
+  /* The LEV field in an SC form instruction.  */
+#define LEV SVC_LEV + 1
+  { 0x7f, 5, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
   /* The LI field in an I form instruction.  The lower two bits are
      forced to zero.  */
-#define LI (31)
-  { 26, 0, insert_li, extract_li, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+#define LI LEV + 1
+  { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
 
   /* The LI field in an I form instruction when used as an absolute
      address.  */
-#define LIA (32)
-  { 26, 0, insert_li, extract_li, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+#define LIA LI + 1
+  { 0x3fffffc, 0, NULL, NULL, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
 
-  /* The MB field in an M form instruction.  */
-#define MB (33)
-#define MB_MASK (0x1f << 6)
-  { 5, 6, 0, 0, 0 },
+  /* The LS field in an X (sync) form instruction.  */
+#define LS LIA + 1
+  { 0x3, 21, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
   /* The ME field in an M form instruction.  */
-#define ME (34)
+#define ME LS + 1
 #define ME_MASK (0x1f << 1)
-  { 5, 1, 0, 0, 0 },
+  { 0x1f, 1, NULL, NULL, 0 },
 
   /* The MB and ME fields in an M form instruction expressed a single
      operand which is a bitmask indicating which bits to select.  This
      is a two operand form using PPC_OPERAND_NEXT.  See the
      description in opcode/ppc.h for what this means.  */
-#define MBE (35)
-  { 5, 6, 0, 0, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
-  { 32, 0, insert_mbe, extract_mbe, 0 },
+#define MBE ME + 1
+  { 0x1f, 6, NULL, NULL, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
+  { -1, 0, insert_mbe, extract_mbe, 0 },
 
   /* The MB or ME field in an MD or MDS form instruction.  The high
      bit is wrapped to the low end.  */
-#define MB6 (37)
-#define ME6 (MB6)
+#define MB6 MBE + 2
+#define ME6 MB6
 #define MB6_MASK (0x3f << 5)
-  { 6, 5, insert_mb6, extract_mb6, 0 },
+  { 0x3f, 5, insert_mb6, extract_mb6, 0 },
 
   /* The NB field in an X form instruction.  The value 32 is stored as
      0.  */
-#define NB (38)
-  { 6, 11, insert_nb, extract_nb, 0 },
+#define NB MB6 + 1
+  { 0x1f, 11, NULL, extract_nb, PPC_OPERAND_PLUS1 },
 
   /* The NSI field in a D form instruction.  This is the same as the
      SI field, only negated.  */
-#define NSI (39)
-  { 16, 0, insert_nsi, extract_nsi,
+#define NSI NB + 1
+  { 0xffff, 0, insert_nsi, extract_nsi,
       PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED },
 
-  /* The RA field in an D, DS, X, XO, M, or MDS form instruction.  */
-#define RA (40)
+  /* The RA field in an D, DS, DQ, X, XO, M, or MDS form instruction.  */
+#define RA NSI + 1
 #define RA_MASK (0x1f << 16)
-  { 5, 16, 0, 0, PPC_OPERAND_GPR },
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR },
+
+  /* As above, but 0 in the RA field means zero, not r0.  */
+#define RA0 RA + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RA field in the DQ form lq instruction, which has special
+     value restrictions.  */
+#define RAQ RA0 + 1
+  { 0x1f, 16, insert_raq, NULL, PPC_OPERAND_GPR_0 },
 
   /* The RA field in a D or X form instruction which is an updating
      load, which means that the RA field may not be zero and may not
      equal the RT field.  */
-#define RAL (41)
-  { 5, 16, insert_ral, 0, PPC_OPERAND_GPR },
+#define RAL RAQ + 1
+  { 0x1f, 16, insert_ral, NULL, PPC_OPERAND_GPR_0 },
 
   /* The RA field in an lmw instruction, which has special value
      restrictions.  */
-#define RAM (42)
-  { 5, 16, insert_ram, 0, PPC_OPERAND_GPR },
+#define RAM RAL + 1
+  { 0x1f, 16, insert_ram, NULL, PPC_OPERAND_GPR_0 },
 
   /* The RA field in a D or X form instruction which is an updating
      store or an updating floating point load, which means that the RA
      field may not be zero.  */
-#define RAS (43)
-  { 5, 16, insert_ras, 0, PPC_OPERAND_GPR },
+#define RAS RAM + 1
+  { 0x1f, 16, insert_ras, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RA field of the tlbwe instruction, which is optional.  */
+#define RAOPT RAS + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL },
 
   /* The RB field in an X, XO, M, or MDS form instruction.  */
-#define RB (44)
+#define RB RAOPT + 1
 #define RB_MASK (0x1f << 11)
-  { 5, 11, 0, 0, PPC_OPERAND_GPR },
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_GPR },
 
   /* The RB field in an X form instruction when it must be the same as
      the RS field in the instruction.  This is used for extended
      mnemonics like mr.  */
-#define RBS (45)
-  { 5, 1, insert_rbs, extract_rbs, PPC_OPERAND_FAKE },
+#define RBS RB + 1
+  { 0x1f, 11, insert_rbs, extract_rbs, PPC_OPERAND_FAKE },
 
   /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form
      instruction or the RT field in a D, DS, X, XFX or XO form
      instruction.  */
-#define RS (46)
-#define RT (RS)
+#define RS RBS + 1
+#define RT RS
 #define RT_MASK (0x1f << 21)
-  { 5, 21, 0, 0, PPC_OPERAND_GPR },
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR },
+
+  /* The RS and RT fields of the DS form stq instruction, which have
+     special value restrictions.  */
+#define RSQ RS + 1
+#define RTQ RSQ
+  { 0x1e, 21, NULL, NULL, PPC_OPERAND_GPR_0 },
+
+  /* The RS field of the tlbwe instruction, which is optional.  */
+#define RSO RSQ + 1
+#define RTO RSO
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_GPR | PPC_OPERAND_OPTIONAL },
 
   /* The SH field in an X or M form instruction.  */
-#define SH (47)
+#define SH RSO + 1
 #define SH_MASK (0x1f << 11)
-  { 5, 11, 0, 0, 0 },
+  /* The other UIMM field in a EVX form instruction.  */
+#define EVUIMM SH
+  { 0x1f, 11, NULL, NULL, 0 },
 
   /* The SH field in an MD form instruction.  This is split.  */
-#define SH6 (48)
+#define SH6 SH + 1
 #define SH6_MASK ((0x1f << 11) | (1 << 1))
-  { 6, 1, insert_sh6, extract_sh6, 0 },
+  { 0x3f, -1, insert_sh6, extract_sh6, 0 },
+
+  /* The SH field of the tlbwe instruction, which is optional.  */
+#define SHO SH6 + 1
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_OPTIONAL },
 
   /* The SI field in a D form instruction.  */
-#define SI (49)
-  { 16, 0, 0, 0, PPC_OPERAND_SIGNED },
+#define SI SHO + 1
+  { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED },
 
   /* The SI field in a D form instruction when we accept a wide range
      of positive values.  */
-#define SISIGNOPT (50)
-  { 16, 0, 0, 0, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT },
+#define SISIGNOPT SI + 1
+  { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT },
 
   /* The SPR field in an XFX form instruction.  This is flipped--the
      lower 5 bits are stored in the upper 5 and vice- versa.  */
-#define SPR (51)
+#define SPR SISIGNOPT + 1
+#define PMR SPR
 #define SPR_MASK (0x3ff << 11)
-  { 10, 11, insert_spr, extract_spr, 0 },
+  { 0x3ff, 11, insert_spr, extract_spr, 0 },
 
   /* The BAT index number in an XFX form m[ft]ibat[lu] instruction.  */
-#define SPRBAT (52)
+#define SPRBAT SPR + 1
 #define SPRBAT_MASK (0x3 << 17)
-  { 2, 17, 0, 0, 0 },
+  { 0x3, 17, NULL, NULL, 0 },
 
   /* The SPRG register number in an XFX form m[ft]sprg instruction.  */
-#define SPRG (53)
-#define SPRG_MASK (0x3 << 16)
-  { 2, 16, 0, 0, 0 },
+#define SPRG SPRBAT + 1
+  { 0x1f, 16, insert_sprg, extract_sprg, 0 },
 
   /* The SR field in an X form instruction.  */
-#define SR (54)
-  { 4, 16, 0, 0, 0 },
+#define SR SPRG + 1
+  { 0xf, 16, NULL, NULL, 0 },
+
+  /* The STRM field in an X AltiVec form instruction.  */
+#define STRM SR + 1
+  { 0x3, 21, NULL, NULL, 0 },
 
   /* The SV field in a POWER SC form instruction.  */
-#define SV (55)
-  { 14, 2, 0, 0, 0 },
+#define SV STRM + 1
+  { 0x3fff, 2, NULL, NULL, 0 },
 
   /* The TBR field in an XFX form instruction.  This is like the SPR
      field, but it is optional.  */
-#define TBR (56)
-  { 10, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL },
+#define TBR SV + 1
+  { 0x3ff, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL },
 
   /* The TO field in a D or X form instruction.  */
-#define TO (57)
+#define TO TBR + 1
 #define TO_MASK (0x1f << 21)
-  { 5, 21, 0, 0, 0 },
-
-  /* The U field in an X form instruction.  */
-#define U (58)
-  { 4, 12, 0, 0, 0 },
+  { 0x1f, 21, NULL, NULL, 0 },
 
   /* The UI field in a D form instruction.  */
-#define UI (59)
-  { 16, 0, 0, 0, 0 },
+#define UI TO + 1
+  { 0xffff, 0, NULL, NULL, 0 },
+
+  /* The VA field in a VA, VX or VXR form instruction.  */
+#define VA UI + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_VR },
+
+  /* The VB field in a VA, VX or VXR form instruction.  */
+#define VB VA + 1
+  { 0x1f, 11, NULL, NULL, PPC_OPERAND_VR },
+
+  /* The VC field in a VA form instruction.  */
+#define VC VB + 1
+  { 0x1f, 6, NULL, NULL, PPC_OPERAND_VR },
+
+  /* The VD or VS field in a VA, VX, VXR or X form instruction.  */
+#define VD VC + 1
+#define VS VD
+  { 0x1f, 21, NULL, NULL, PPC_OPERAND_VR },
+
+  /* The SIMM field in a VX form instruction.  */
+#define SIMM VD + 1
+  { 0x1f, 16, NULL, NULL, PPC_OPERAND_SIGNED},
+
+  /* The UIMM field in a VX form instruction, and TE in Z form.  */
+#define UIMM SIMM + 1
+#define TE UIMM
+  { 0x1f, 16, NULL, NULL, 0 },
+
+  /* The SHB field in a VA form instruction.  */
+#define SHB UIMM + 1
+  { 0xf, 6, NULL, NULL, 0 },
+
+  /* The other UIMM field in a half word EVX form instruction.  */
+#define EVUIMM_2 SHB + 1
+  { 0x3e, 10, NULL, NULL, PPC_OPERAND_PARENS },
+
+  /* The other UIMM field in a word EVX form instruction.  */
+#define EVUIMM_4 EVUIMM_2 + 1
+  { 0x7c, 9, NULL, NULL, PPC_OPERAND_PARENS },
+
+  /* The other UIMM field in a double EVX form instruction.  */
+#define EVUIMM_8 EVUIMM_4 + 1
+  { 0xf8, 8, NULL, NULL, PPC_OPERAND_PARENS },
+
+  /* The WS field.  */
+#define WS EVUIMM_8 + 1
+  { 0x7, 11, NULL, NULL, 0 },
+
+  /* The L field in an mtmsrd or A form instruction or W in an X form.  */
+#define A_L WS + 1
+#define W A_L
+  { 0x1, 16, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+#define RMC A_L + 1
+  { 0x3, 9, NULL, NULL, 0 },
+
+#define R RMC + 1
+  { 0x1, 16, NULL, NULL, 0 },
+
+#define SP R + 1
+  { 0x3, 19, NULL, NULL, 0 },
+
+#define S SP + 1
+  { 0x1, 20, NULL, NULL, 0 },
+
+  /* SH field starting at bit position 16.  */
+#define SH16 S + 1
+  /* The DCM and DGM fields in a Z form instruction.  */
+#define DCM SH16
+#define DGM DCM
+  { 0x3f, 10, NULL, NULL, 0 },
+
+  /* The EH field in larx instruction.  */
+#define EH SH16 + 1
+  { 0x1, 0, NULL, NULL, PPC_OPERAND_OPTIONAL },
+
+  /* The L field in an mtfsf or XFL form instruction.  */
+#define XFL_L EH + 1
+  { 0x1, 25, NULL, NULL, PPC_OPERAND_OPTIONAL},
 };
 
+const unsigned int num_powerpc_operands = (sizeof (powerpc_operands)
+					   / sizeof (powerpc_operands[0]));
+
 /* The functions used to insert and extract complicated operands.  */
 
 /* The BA field in an XL form instruction when it must be the same as
@@ -645,23 +903,21 @@
    and the extraction function just checks that the fields are the
    same.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_bat (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_bat (unsigned long insn,
+	    long value ATTRIBUTE_UNUSED,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
   return insn | (((insn >> 21) & 0x1f) << 16);
 }
 
 static long
-extract_bat (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_bat (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
 {
-  if (invalid != (int *) NULL
-      && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
+  if (((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
     *invalid = 1;
   return 0;
 }
@@ -672,169 +928,210 @@
    and the extraction function just checks that the fields are the
    same.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_bba (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_bba (unsigned long insn,
+	    long value ATTRIBUTE_UNUSED,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
   return insn | (((insn >> 16) & 0x1f) << 11);
 }
 
 static long
-extract_bba (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_bba (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
 {
-  if (invalid != (int *) NULL
-      && ((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f))
+  if (((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f))
     *invalid = 1;
   return 0;
 }
 
-/* The BD field in a B form instruction.  The lower two bits are
-   forced to zero.  */
-
-/*ARGSUSED*/
-static unsigned long
-insert_bd (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
-{
-  return insn | (value & 0xfffc);
-}
-
-/*ARGSUSED*/
-static long
-extract_bd (insn, invalid)
-     uint32_t insn;
-     int *invalid;
-{
-  if ((insn & 0x8000) != 0)
-    return (insn & 0xfffc) - 0x10000;
-  else
-    return insn & 0xfffc;
-}
-
 /* The BD field in a B form instruction when the - modifier is used.
    This modifier means that the branch is not expected to be taken.
-   We must set the y bit of the BO field to 1 if the offset is
-   negative.  When extracting, we require that the y bit be 1 and that
-   the offset be positive, since if the y bit is 0 we just want to
-   print the normal form of the instruction.  */
+   For chips built to versions of the architecture prior to version 2
+   (ie. not Power4 compatible), we set the y bit of the BO field to 1
+   if the offset is negative.  When extracting, we require that the y
+   bit be 1 and that the offset be positive, since if the y bit is 0
+   we just want to print the normal form of the instruction.
+   Power4 compatible targets use two bits, "a", and "t", instead of
+   the "y" bit.  "at" == 00 => no hint, "at" == 01 => unpredictable,
+   "at" == 10 => not taken, "at" == 11 => taken.  The "t" bit is 00001
+   in BO field, the "a" bit is 00010 for branch on CR(BI) and 01000
+   for branch on CTR.  We only handle the taken/not-taken hint here.
+   Note that we don't relax the conditions tested here when
+   disassembling with -Many because insns using extract_bdm and
+   extract_bdp always occur in pairs.  One or the other will always
+   be valid.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_bdm (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_bdm (unsigned long insn,
+	    long value,
+	    int dialect,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
-  if ((value & 0x8000) != 0)
-    insn |= 1 << 21;
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      if ((value & 0x8000) != 0)
+	insn |= 1 << 21;
+    }
+  else
+    {
+      if ((insn & (0x14 << 21)) == (0x04 << 21))
+	insn |= 0x02 << 21;
+      else if ((insn & (0x14 << 21)) == (0x10 << 21))
+	insn |= 0x08 << 21;
+    }
   return insn | (value & 0xfffc);
 }
 
 static long
-extract_bdm (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_bdm (unsigned long insn,
+	     int dialect,
+	     int *invalid)
 {
-  if (invalid != (int *) NULL
-      && ((insn & (1 << 21)) == 0
-	  || (insn & (1 << 15)) == 0))
-    *invalid = 1;
-  if ((insn & 0x8000) != 0)
-    return (insn & 0xfffc) - 0x10000;
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      if (((insn & (1 << 21)) == 0) != ((insn & (1 << 15)) == 0))
+	*invalid = 1;
+    }
   else
-    return insn & 0xfffc;
+    {
+      if ((insn & (0x17 << 21)) != (0x06 << 21)
+	  && (insn & (0x1d << 21)) != (0x18 << 21))
+	*invalid = 1;
+    }
+
+  return ((insn & 0xfffc) ^ 0x8000) - 0x8000;
 }
 
 /* The BD field in a B form instruction when the + modifier is used.
    This is like BDM, above, except that the branch is expected to be
    taken.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_bdp (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_bdp (unsigned long insn,
+	    long value,
+	    int dialect,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
-  if ((value & 0x8000) == 0)
-    insn |= 1 << 21;
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      if ((value & 0x8000) == 0)
+	insn |= 1 << 21;
+    }
+  else
+    {
+      if ((insn & (0x14 << 21)) == (0x04 << 21))
+	insn |= 0x03 << 21;
+      else if ((insn & (0x14 << 21)) == (0x10 << 21))
+	insn |= 0x09 << 21;
+    }
   return insn | (value & 0xfffc);
 }
 
 static long
-extract_bdp (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_bdp (unsigned long insn,
+	     int dialect,
+	     int *invalid)
 {
-  if (invalid != (int *) NULL
-      && ((insn & (1 << 21)) == 0
-	  || (insn & (1 << 15)) != 0))
-    *invalid = 1;
-  if ((insn & 0x8000) != 0)
-    return (insn & 0xfffc) - 0x10000;
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
+    {
+      if (((insn & (1 << 21)) == 0) == ((insn & (1 << 15)) == 0))
+	*invalid = 1;
+    }
   else
-    return insn & 0xfffc;
+    {
+      if ((insn & (0x17 << 21)) != (0x07 << 21)
+	  && (insn & (0x1d << 21)) != (0x19 << 21))
+	*invalid = 1;
+    }
+
+  return ((insn & 0xfffc) ^ 0x8000) - 0x8000;
 }
 
 /* Check for legal values of a BO field.  */
 
 static int
-valid_bo (int32_t value)
+valid_bo (long value, int dialect, int extract)
 {
-  /* Certain encodings have bits that are required to be zero.  These
-     are (z must be zero, y may be anything):
-         001zy
-	 011zy
-	 1z00y
-	 1z01y
-	 1z1zz
-     */
-  switch (value & 0x14)
+  if ((dialect & PPC_OPCODE_POWER4) == 0)
     {
-    default:
-    case 0:
-      return 1;
-    case 0x4:
-      return (value & 0x2) == 0;
-    case 0x10:
-      return (value & 0x8) == 0;
-    case 0x14:
-      return value == 0x14;
+      int valid;
+      /* Certain encodings have bits that are required to be zero.
+	 These are (z must be zero, y may be anything):
+	     001zy
+	     011zy
+	     1z00y
+	     1z01y
+	     1z1zz
+      */
+      switch (value & 0x14)
+	{
+	default:
+	case 0:
+	  valid = 1;
+	  break;
+	case 0x4:
+	  valid = (value & 0x2) == 0;
+	  break;
+	case 0x10:
+	  valid = (value & 0x8) == 0;
+	  break;
+	case 0x14:
+	  valid = value == 0x14;
+	  break;
+	}
+      /* When disassembling with -Many, accept power4 encodings too.  */
+      if (valid
+	  || (dialect & PPC_OPCODE_ANY) == 0
+	  || !extract)
+	return valid;
     }
+
+  /* Certain encodings have bits that are required to be zero.
+     These are (z must be zero, a & t may be anything):
+	 0000z
+	 0001z
+	 0100z
+	 0101z
+	 001at
+	 011at
+	 1a00t
+	 1a01t
+	 1z1zz
+  */
+  if ((value & 0x14) == 0)
+    return (value & 0x1) == 0;
+  else if ((value & 0x14) == 0x14)
+    return value == 0x14;
+  else
+    return 1;
 }
 
 /* The BO field in a B form instruction.  Warn about attempts to set
    the field to an illegal value.  */
 
 static unsigned long
-insert_bo (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_bo (unsigned long insn,
+	   long value,
+	   int dialect,
+	   const char **errmsg)
 {
-  if (errmsg != (const char **) NULL
-      && ! valid_bo (value))
-    *errmsg = "invalid conditional option";
+  if (!valid_bo (value, dialect, 0))
+    *errmsg = _("invalid conditional option");
   return insn | ((value & 0x1f) << 21);
 }
 
 static long
-extract_bo (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_bo (unsigned long insn,
+	    int dialect,
+	    int *invalid)
 {
-  int32_t value;
+  long value;
 
   value = (insn >> 21) & 0x1f;
-  if (invalid != (int *) NULL
-      && ! valid_bo (value))
+  if (!valid_bo (value, dialect, 1))
     *invalid = 1;
   return value;
 }
@@ -844,83 +1141,102 @@
    extracting it, we force it to be even.  */
 
 static unsigned long
-insert_boe (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_boe (unsigned long insn,
+	    long value,
+	    int dialect,
+	    const char **errmsg)
 {
-  if (errmsg != (const char **) NULL)
-    {
-      if (! valid_bo (value))
-	*errmsg = "invalid conditional option";
-      else if ((value & 1) != 0)
-	*errmsg = "attempt to set y bit when using + or - modifier";
-    }
+  if (!valid_bo (value, dialect, 0))
+    *errmsg = _("invalid conditional option");
+  else if ((value & 1) != 0)
+    *errmsg = _("attempt to set y bit when using + or - modifier");
+
   return insn | ((value & 0x1f) << 21);
 }
 
 static long
-extract_boe (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_boe (unsigned long insn,
+	     int dialect,
+	     int *invalid)
 {
-  int32_t value;
+  long value;
 
   value = (insn >> 21) & 0x1f;
-  if (invalid != (int *) NULL
-      && ! valid_bo (value))
+  if (!valid_bo (value, dialect, 1))
     *invalid = 1;
   return value & 0x1e;
 }
 
-/* The DS field in a DS form instruction.  This is like D, but the
-   lower two bits are forced to zero.  */
+/* FXM mask in mfcr and mtcrf instructions.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_ds (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_fxm (unsigned long insn,
+	    long value,
+	    int dialect,
+	    const char **errmsg)
 {
-  return insn | (value & 0xfffc);
+  /* If we're handling the mfocrf and mtocrf insns ensure that exactly
+     one bit of the mask field is set.  */
+  if ((insn & (1 << 20)) != 0)
+    {
+      if (value == 0 || (value & -value) != value)
+	{
+	  *errmsg = _("invalid mask field");
+	  value = 0;
+	}
+    }
+
+  /* If the optional field on mfcr is missing that means we want to use
+     the old form of the instruction that moves the whole cr.  In that
+     case we'll have VALUE zero.  There doesn't seem to be a way to
+     distinguish this from the case where someone writes mfcr %r3,0.  */
+  else if (value == 0)
+    ;
+
+  /* If only one bit of the FXM field is set, we can use the new form
+     of the instruction, which is faster.  Unlike the Power4 branch hint
+     encoding, this is not backward compatible.  Do not generate the
+     new form unless -mpower4 has been given, or -many and the two
+     operand form of mfcr was used.  */
+  else if ((value & -value) == value
+	   && ((dialect & PPC_OPCODE_POWER4) != 0
+	       || ((dialect & PPC_OPCODE_ANY) != 0
+		   && (insn & (0x3ff << 1)) == 19 << 1)))
+    insn |= 1 << 20;
+
+  /* Any other value on mfcr is an error.  */
+  else if ((insn & (0x3ff << 1)) == 19 << 1)
+    {
+      *errmsg = _("ignoring invalid mfcr mask");
+      value = 0;
+    }
+
+  return insn | ((value & 0xff) << 12);
 }
 
-/*ARGSUSED*/
 static long
-extract_ds (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_fxm (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
 {
-  if ((insn & 0x8000) != 0)
-    return (insn & 0xfffc) - 0x10000;
-  else
-    return insn & 0xfffc;
-}
+  long mask = (insn >> 12) & 0xff;
 
-/* The LI field in an I form instruction.  The lower two bits are
-   forced to zero.  */
+  /* Is this a Power4 insn?  */
+  if ((insn & (1 << 20)) != 0)
+    {
+      /* Exactly one bit of MASK should be set.  */
+      if (mask == 0 || (mask & -mask) != mask)
+	*invalid = 1;
+    }
 
-/*ARGSUSED*/
-static unsigned long
-insert_li (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
-{
-  return insn | (value & 0x3fffffc);
-}
+  /* Check that non-power4 form of mfcr has a zero MASK.  */
+  else if ((insn & (0x3ff << 1)) == 19 << 1)
+    {
+      if (mask != 0)
+	*invalid = 1;
+    }
 
-/*ARGSUSED*/
-static long
-extract_li (insn, invalid)
-     uint32_t insn;
-     int *invalid;
-{
-  if ((insn & 0x2000000) != 0)
-    return (insn & 0x3fffffc) - 0x4000000;
-  else
-    return insn & 0x3fffffc;
+  return mask;
 }
 
 /* The MB and ME fields in an M form instruction expressed as a single
@@ -929,85 +1245,104 @@
    instruction which uses a field of this type.  */
 
 static unsigned long
-insert_mbe (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_mbe (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
 {
-  uint32_t uval;
-  int mb, me;
+  unsigned long uval, mask;
+  int mb, me, mx, count, last;
 
   uval = value;
 
   if (uval == 0)
     {
-      if (errmsg != (const char **) NULL)
-	*errmsg = "illegal bitmask";
+      *errmsg = _("illegal bitmask");
       return insn;
     }
 
-  me = 31;
-  while ((uval & 1) == 0)
-    {
-      uval >>= 1;
-      --me;
-    }
+  mb = 0;
+  me = 32;
+  if ((uval & 1) != 0)
+    last = 1;
+  else
+    last = 0;
+  count = 0;
 
-  mb = me;
-  uval >>= 1;
-  while ((uval & 1) != 0)
-    {
-      uval >>= 1;
-      --mb;
-    }
+  /* mb: location of last 0->1 transition */
+  /* me: location of last 1->0 transition */
+  /* count: # transitions */
 
-  if (uval != 0)
+  for (mx = 0, mask = 1L << 31; mx < 32; ++mx, mask >>= 1)
     {
-      if (errmsg != (const char **) NULL)
-	*errmsg = "illegal bitmask";
+      if ((uval & mask) && !last)
+	{
+	  ++count;
+	  mb = mx;
+	  last = 1;
+	}
+      else if (!(uval & mask) && last)
+	{
+	  ++count;
+	  me = mx;
+	  last = 0;
+	}
     }
+  if (me == 0)
+    me = 32;
 
-  return insn | (mb << 6) | (me << 1);
+  if (count != 2 && (count != 0 || ! last))
+    *errmsg = _("illegal bitmask");
+
+  return insn | (mb << 6) | ((me - 1) << 1);
 }
 
 static long
-extract_mbe (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_mbe (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
 {
   long ret;
   int mb, me;
   int i;
 
-  if (invalid != (int *) NULL)
-    *invalid = 1;
+  *invalid = 1;
 
-  ret = 0;
   mb = (insn >> 6) & 0x1f;
   me = (insn >> 1) & 0x1f;
-  for (i = mb; i < me; i++)
-    ret |= 1 << (31 - i);
+  if (mb < me + 1)
+    {
+      ret = 0;
+      for (i = mb; i <= me; i++)
+	ret |= 1L << (31 - i);
+    }
+  else if (mb == me + 1)
+    ret = ~0;
+  else /* (mb > me + 1) */
+    {
+      ret = ~0;
+      for (i = me + 1; i < mb; i++)
+	ret &= ~(1L << (31 - i));
+    }
   return ret;
 }
 
 /* The MB or ME field in an MD or MDS form instruction.  The high bit
    is wrapped to the low end.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_mb6 (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_mb6 (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
   return insn | ((value & 0x1f) << 6) | (value & 0x20);
 }
 
-/*ARGSUSED*/
 static long
-extract_mb6 (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_mb6 (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
 {
   return ((insn >> 6) & 0x1f) | (insn & 0x20);
 }
@@ -1015,24 +1350,10 @@
 /* The NB field in an X form instruction.  The value 32 is stored as
    0.  */
 
-static unsigned long
-insert_nb (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
-{
-  if (value < 0 || value > 32)
-    *errmsg = "value out of range";
-  if (value == 32)
-    value = 0;
-  return insn | ((value & 0x1f) << 11);
-}
-
-/*ARGSUSED*/
 static long
-extract_nb (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_nb (unsigned long insn,
+	    int dialect ATTRIBUTE_UNUSED,
+	    int *invalid ATTRIBUTE_UNUSED)
 {
   long ret;
 
@@ -1047,27 +1368,22 @@
    invalid, since we never want to recognize an instruction which uses
    a field of this type.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_nsi (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_nsi (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
-  return insn | ((- value) & 0xffff);
+  return insn | (-value & 0xffff);
 }
 
 static long
-extract_nsi (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_nsi (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
 {
-  if (invalid != (int *) NULL)
-    *invalid = 1;
-  if ((insn & 0x8000) != 0)
-    return - ((insn & 0xffff) - 0x10000);
-  else
-    return - (insn & 0xffff);
+  *invalid = 1;
+  return -(((insn & 0xffff) ^ 0x8000) - 0x8000);
 }
 
 /* The RA field in a D or X form instruction which is an updating
@@ -1075,13 +1391,13 @@
    equal the RT field.  */
 
 static unsigned long
-insert_ral (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_ral (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
 {
   if (value == 0
-      || value == ((insn >> 21) & 0x1f))
+      || (unsigned long) value == ((insn >> 21) & 0x1f))
     *errmsg = "invalid register operand when updating";
   return insn | ((value & 0x1f) << 16);
 }
@@ -1090,13 +1406,29 @@
    restrictions.  */
 
 static unsigned long
-insert_ram (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_ram (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
 {
-  if (value >= ((insn >> 21) & 0x1f))
-    *errmsg = "index register in load range";
+  if ((unsigned long) value >= ((insn >> 21) & 0x1f))
+    *errmsg = _("index register in load range");
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in the DQ form lq instruction, which has special
+   value restrictions.  */
+
+static unsigned long
+insert_raq (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
+{
+  long rtvalue = (insn & RT_MASK) >> 21;
+
+  if (value == rtvalue)
+    *errmsg = _("source and target register operands must be different");
   return insn | ((value & 0x1f) << 16);
 }
 
@@ -1105,13 +1437,13 @@
    field may not be zero.  */
 
 static unsigned long
-insert_ras (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_ras (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg)
 {
   if (value == 0)
-    *errmsg = "invalid register operand when updating";
+    *errmsg = _("invalid register operand when updating");
   return insn | ((value & 0x1f) << 16);
 }
 
@@ -1121,44 +1453,40 @@
    function just copies the BT field into the BA field, and the
    extraction function just checks that the fields are the same.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_rbs (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_rbs (unsigned long insn,
+	    long value ATTRIBUTE_UNUSED,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
   return insn | (((insn >> 21) & 0x1f) << 11);
 }
 
 static long
-extract_rbs (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_rbs (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid)
 {
-  if (invalid != (int *) NULL
-      && ((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f))
+  if (((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f))
     *invalid = 1;
   return 0;
 }
 
 /* The SH field in an MD form instruction.  This is split.  */
 
-/*ARGSUSED*/
 static unsigned long
-insert_sh6 (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_sh6 (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
   return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
 }
 
-/*ARGSUSED*/
 static long
-extract_sh6 (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_sh6 (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
 {
   return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20);
 }
@@ -1167,22 +1495,63 @@
    lower 5 bits are stored in the upper 5 and vice- versa.  */
 
 static unsigned long
-insert_spr (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_spr (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
   return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
 }
 
 static long
-extract_spr (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_spr (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
 {
   return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
 }
 
+/* Some dialects have 8 SPRG registers instead of the standard 4.  */
+
+static unsigned long
+insert_sprg (unsigned long insn,
+	     long value,
+	     int dialect,
+	     const char **errmsg)
+{
+  /* This check uses PPC_OPCODE_403 because PPC405 is later defined
+     as a synonym.  If ever a 405 specific dialect is added this
+     check should use that instead.  */
+  if (value > 7
+      || (value > 3
+	  && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0))
+    *errmsg = _("invalid sprg number");
+
+  /* If this is mfsprg4..7 then use spr 260..263 which can be read in
+     user mode.  Anything else must use spr 272..279.  */
+  if (value <= 3 || (insn & 0x100) != 0)
+    value |= 0x10;
+
+  return insn | ((value & 0x17) << 16);
+}
+
+static long
+extract_sprg (unsigned long insn,
+	      int dialect,
+	      int *invalid)
+{
+  unsigned long val = (insn >> 16) & 0x1f;
+
+  /* mfsprg can use 260..263 and 272..279.  mtsprg only uses spr 272..279
+     If not BOOKE or 405, then both use only 272..275.  */
+  if (val <= 3
+      || (val < 0x10 && (insn & 0x100) != 0)
+      || (val - 0x10 > 3
+	  && (dialect & (PPC_OPCODE_BOOKE | PPC_OPCODE_403)) == 0))
+    *invalid = 1;
+  return val & 7;
+}
+
 /* The TBR field in an XFX instruction.  This is just like SPR, but it
    is optional.  When TBR is omitted, it must be inserted as 268 (the
    magic number of the TB register).  These functions treat 0
@@ -1194,10 +1563,10 @@
 #define TB (268)
 
 static unsigned long
-insert_tbr (insn, value, errmsg)
-     uint32_t insn;
-     int32_t value;
-     const char **errmsg;
+insert_tbr (unsigned long insn,
+	    long value,
+	    int dialect ATTRIBUTE_UNUSED,
+	    const char **errmsg ATTRIBUTE_UNUSED)
 {
   if (value == 0)
     value = TB;
@@ -1205,9 +1574,9 @@
 }
 
 static long
-extract_tbr (insn, invalid)
-     uint32_t insn;
-     int *invalid;
+extract_tbr (unsigned long insn,
+	     int dialect ATTRIBUTE_UNUSED,
+	     int *invalid ATTRIBUTE_UNUSED)
 {
   long ret;
 
@@ -1220,23 +1589,23 @@
 /* Macros used to form opcodes.  */
 
 /* The main opcode.  */
-#define OP(x) (((x) & 0x3f) << 26)
+#define OP(x) ((((unsigned long)(x)) & 0x3f) << 26)
 #define OP_MASK OP (0x3f)
 
 /* The main opcode combined with a trap code in the TO field of a D
    form instruction.  Used for extended mnemonics for the trap
    instructions.  */
-#define OPTO(x,to) (OP (x) | (((to) & 0x1f) << 21))
+#define OPTO(x,to) (OP (x) | ((((unsigned long)(to)) & 0x1f) << 21))
 #define OPTO_MASK (OP_MASK | TO_MASK)
 
 /* The main opcode combined with a comparison size bit in the L field
    of a D form or X form instruction.  Used for extended mnemonics for
    the comparison instructions.  */
-#define OPL(x,l) (OP (x) | (((l) & 1) << 21))
+#define OPL(x,l) (OP (x) | ((((unsigned long)(l)) & 1) << 21))
 #define OPL_MASK OPL (0x3f,1)
 
 /* An A form instruction.  */
-#define A(op, xop, rc) (OP (op) | (((xop) & 0x1f) << 1) | ((rc) & 1))
+#define A(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1) | (((unsigned long)(rc)) & 1))
 #define A_MASK A (0x3f, 0x1f, 1)
 
 /* An A_MASK with the FRB field fixed.  */
@@ -1248,31 +1617,48 @@
 /* An A_MASK with the FRA and FRC fields fixed.  */
 #define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK)
 
+/* An AFRAFRC_MASK, but with L bit clear.  */
+#define AFRALFRC_MASK (AFRAFRC_MASK & ~((unsigned long) 1 << 16))
+
 /* A B form instruction.  */
-#define B(op, aa, lk) (OP (op) | (((aa) & 1) << 1) | ((lk) & 1))
+#define B(op, aa, lk) (OP (op) | ((((unsigned long)(aa)) & 1) << 1) | ((lk) & 1))
 #define B_MASK B (0x3f, 1, 1)
 
 /* A B form instruction setting the BO field.  */
-#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | (((bo) & 0x1f) << 21))
+#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
 #define BBO_MASK BBO (0x3f, 0x1f, 1, 1)
 
 /* A BBO_MASK with the y bit of the BO field removed.  This permits
    matching a conditional branch regardless of the setting of the y
-   bit.  */
-#define Y_MASK (1 << 21)
-#define BBOY_MASK (BBO_MASK &~ Y_MASK)
+   bit.  Similarly for the 'at' bits used for power4 branch hints.  */
+#define Y_MASK   (((unsigned long) 1) << 21)
+#define AT1_MASK (((unsigned long) 3) << 21)
+#define AT2_MASK (((unsigned long) 9) << 21)
+#define BBOY_MASK  (BBO_MASK &~ Y_MASK)
+#define BBOAT_MASK (BBO_MASK &~ AT1_MASK)
 
 /* A B form instruction setting the BO field and the condition bits of
    the BI field.  */
 #define BBOCB(op, bo, cb, aa, lk) \
-  (BBO ((op), (bo), (aa), (lk)) | (((cb) & 0x3) << 16))
+  (BBO ((op), (bo), (aa), (lk)) | ((((unsigned long)(cb)) & 0x3) << 16))
 #define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1)
 
 /* A BBOCB_MASK with the y bit of the BO field removed.  */
 #define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK)
+#define BBOATCB_MASK (BBOCB_MASK &~ AT1_MASK)
+#define BBOAT2CB_MASK (BBOCB_MASK &~ AT2_MASK)
 
 /* A BBOYCB_MASK in which the BI field is fixed.  */
 #define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
+#define BBOATBI_MASK (BBOAT2CB_MASK | BI_MASK)
+
+/* An Context form instruction.  */
+#define CTX(op, xop)   (OP (op) | (((unsigned long)(xop)) & 0x7))
+#define CTX_MASK CTX(0x3f, 0x7)
+
+/* An User Context form instruction.  */
+#define UCTX(op, xop)  (OP (op) | (((unsigned long)(xop)) & 0x1f))
+#define UCTX_MASK UCTX(0x3f, 0x1f)
 
 /* The main opcode mask with the RA field clear.  */
 #define DRA_MASK (OP_MASK | RA_MASK)
@@ -1281,12 +1667,20 @@
 #define DSO(op, xop) (OP (op) | ((xop) & 0x3))
 #define DS_MASK DSO (0x3f, 3)
 
+/* A DE form instruction.  */
+#define DEO(op, xop) (OP (op) | ((xop) & 0xf))
+#define DE_MASK DEO (0x3e, 0xf)
+
+/* An EVSEL form instruction.  */
+#define EVSEL(op, xop) (OP (op) | (((unsigned long)(xop)) & 0xff) << 3)
+#define EVSEL_MASK EVSEL(0x3f, 0xff)
+
 /* An M form instruction.  */
 #define M(op, rc) (OP (op) | ((rc) & 1))
 #define M_MASK M (0x3f, 1)
 
 /* An M form instruction with the ME field specified.  */
-#define MME(op, me, rc) (M ((op), (rc)) | (((me) & 0x1f) << 1))
+#define MME(op, me, rc) (M ((op), (rc)) | ((((unsigned long)(me)) & 0x1f) << 1))
 
 /* An M_MASK with the MB and ME fields fixed.  */
 #define MMBME_MASK (M_MASK | MB_MASK | ME_MASK)
@@ -1295,7 +1689,7 @@
 #define MSHME_MASK (M_MASK | SH_MASK | ME_MASK)
 
 /* An MD form instruction.  */
-#define MD(op, xop, rc) (OP (op) | (((xop) & 0x7) << 2) | ((rc) & 1))
+#define MD(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x7) << 2) | ((rc) & 1))
 #define MD_MASK MD (0x3f, 0x7, 1)
 
 /* An MD_MASK with the MB field fixed.  */
@@ -1305,60 +1699,121 @@
 #define MDSH_MASK (MD_MASK | SH6_MASK)
 
 /* An MDS form instruction.  */
-#define MDS(op, xop, rc) (OP (op) | (((xop) & 0xf) << 1) | ((rc) & 1))
+#define MDS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0xf) << 1) | ((rc) & 1))
 #define MDS_MASK MDS (0x3f, 0xf, 1)
 
 /* An MDS_MASK with the MB field fixed.  */
 #define MDSMB_MASK (MDS_MASK | MB6_MASK)
 
 /* An SC form instruction.  */
-#define SC(op, sa, lk) (OP (op) | (((sa) & 1) << 1) | ((lk) & 1))
-#define SC_MASK (OP_MASK | (0x3ff << 16) | (1 << 1) | 1)
+#define SC(op, sa, lk) (OP (op) | ((((unsigned long)(sa)) & 1) << 1) | ((lk) & 1))
+#define SC_MASK (OP_MASK | (((unsigned long)0x3ff) << 16) | (((unsigned long)1) << 1) | 1)
+
+/* An VX form instruction.  */
+#define VX(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x7ff))
+
+/* The mask for an VX form instruction.  */
+#define VX_MASK	VX(0x3f, 0x7ff)
+
+/* An VA form instruction.  */
+#define VXA(op, xop) (OP (op) | (((unsigned long)(xop)) & 0x03f))
+
+/* The mask for an VA form instruction.  */
+#define VXA_MASK VXA(0x3f, 0x3f)
+
+/* An VXR form instruction.  */
+#define VXR(op, xop, rc) (OP (op) | (((rc) & 1) << 10) | (((unsigned long)(xop)) & 0x3ff))
+
+/* The mask for a VXR form instruction.  */
+#define VXR_MASK VXR(0x3f, 0x3ff, 1)
 
 /* An X form instruction.  */
-#define X(op, xop) (OP (op) | (((xop) & 0x3ff) << 1))
+#define X(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
+
+/* A Z form instruction.  */
+#define Z(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1))
 
 /* An X form instruction with the RC bit specified.  */
 #define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1))
 
+/* A Z form instruction with the RC bit specified.  */
+#define ZRC(op, xop, rc) (Z ((op), (xop)) | ((rc) & 1))
+
 /* The mask for an X form instruction.  */
 #define X_MASK XRC (0x3f, 0x3ff, 1)
 
+/* The mask for a Z form instruction.  */
+#define Z_MASK ZRC (0x3f, 0x1ff, 1)
+#define Z2_MASK ZRC (0x3f, 0xff, 1)
+
 /* An X_MASK with the RA field fixed.  */
 #define XRA_MASK (X_MASK | RA_MASK)
 
+/* An XRA_MASK with the W field clear.  */
+#define XWRA_MASK (XRA_MASK & ~((unsigned long) 1 << 16))
+
 /* An X_MASK with the RB field fixed.  */
 #define XRB_MASK (X_MASK | RB_MASK)
 
 /* An X_MASK with the RT field fixed.  */
 #define XRT_MASK (X_MASK | RT_MASK)
 
+/* An XRT_MASK mask with the L bits clear.  */
+#define XLRT_MASK (XRT_MASK & ~((unsigned long) 0x3 << 21))
+
 /* An X_MASK with the RA and RB fields fixed.  */
 #define XRARB_MASK (X_MASK | RA_MASK | RB_MASK)
 
+/* An XRARB_MASK, but with the L bit clear.  */
+#define XRLARB_MASK (XRARB_MASK & ~((unsigned long) 1 << 16))
+
 /* An X_MASK with the RT and RA fields fixed.  */
 #define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK)
 
-/* An X form comparison instruction.  */
-#define XCMPL(op, xop, l) (X ((op), (xop)) | (((l) & 1) << 21))
+/* An XRTRA_MASK, but with L bit clear.  */
+#define XRTLRA_MASK (XRTRA_MASK & ~((unsigned long) 1 << 21))
+
+/* An X form instruction with the L bit specified.  */
+#define XOPL(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 1) << 21))
 
 /* The mask for an X form comparison instruction.  */
-#define XCMP_MASK (X_MASK | (1 << 22))
+#define XCMP_MASK (X_MASK | (((unsigned long)1) << 22))
 
 /* The mask for an X form comparison instruction with the L field
    fixed.  */
-#define XCMPL_MASK (XCMP_MASK | (1 << 21))
+#define XCMPL_MASK (XCMP_MASK | (((unsigned long)1) << 21))
 
 /* An X form trap instruction with the TO field specified.  */
-#define XTO(op, xop, to) (X ((op), (xop)) | (((to) & 0x1f) << 21))
+#define XTO(op, xop, to) (X ((op), (xop)) | ((((unsigned long)(to)) & 0x1f) << 21))
 #define XTO_MASK (X_MASK | TO_MASK)
 
+/* An X form tlb instruction with the SH field specified.  */
+#define XTLB(op, xop, sh) (X ((op), (xop)) | ((((unsigned long)(sh)) & 0x1f) << 11))
+#define XTLB_MASK (X_MASK | SH_MASK)
+
+/* An X form sync instruction.  */
+#define XSYNC(op, xop, l) (X ((op), (xop)) | ((((unsigned long)(l)) & 3) << 21))
+
+/* An X form sync instruction with everything filled in except the LS field.  */
+#define XSYNC_MASK (0xff9fffff)
+
+/* An X_MASK, but with the EH bit clear.  */
+#define XEH_MASK (X_MASK & ~((unsigned long )1))
+
+/* An X form AltiVec dss instruction.  */
+#define XDSS(op, xop, a) (X ((op), (xop)) | ((((unsigned long)(a)) & 1) << 25))
+#define XDSS_MASK XDSS(0x3f, 0x3ff, 1)
+
 /* An XFL form instruction.  */
-#define XFL(op, xop, rc) (OP (op) | (((xop) & 0x3ff) << 1) | ((rc) & 1))
-#define XFL_MASK (XFL (0x3f, 0x3ff, 1) | (1 << 25) | (1 << 16))
+#define XFL(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1) | (((unsigned long)(rc)) & 1))
+#define XFL_MASK XFL (0x3f, 0x3ff, 1)
+
+/* An X form isel instruction.  */
+#define XISEL(op, xop)  (OP (op) | ((((unsigned long)(xop)) & 0x1f) << 1))
+#define XISEL_MASK      XISEL(0x3f, 0x1f)
 
 /* An XL form instruction with the LK field set to 0.  */
-#define XL(op, xop) (OP (op) | (((xop) & 0x3ff) << 1))
+#define XL(op, xop) (OP (op) | ((((unsigned long)(xop)) & 0x3ff) << 1))
 
 /* An XL form instruction which uses the LK field.  */
 #define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1))
@@ -1368,18 +1823,18 @@
 
 /* An XL form instruction which explicitly sets the BO field.  */
 #define XLO(op, bo, xop, lk) \
-  (XLLK ((op), (xop), (lk)) | (((bo) & 0x1f) << 21))
+  (XLLK ((op), (xop), (lk)) | ((((unsigned long)(bo)) & 0x1f) << 21))
 #define XLO_MASK (XL_MASK | BO_MASK)
 
 /* An XL form instruction which explicitly sets the y bit of the BO
    field.  */
-#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | (((y) & 1) << 21))
+#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | ((((unsigned long)(y)) & 1) << 21))
 #define XLYLK_MASK (XL_MASK | Y_MASK)
 
 /* An XL form instruction which sets the BO field and the condition
    bits of the BI field.  */
 #define XLOCB(op, bo, cb, xop, lk) \
-  (XLO ((op), (bo), (xop), (lk)) | (((cb) & 3) << 16))
+  (XLO ((op), (bo), (xop), (lk)) | ((((unsigned long)(cb)) & 3) << 16))
 #define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1)
 
 /* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed.  */
@@ -1387,6 +1842,9 @@
 #define XLYBB_MASK (XLYLK_MASK | BB_MASK)
 #define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK)
 
+/* A mask for branch instructions using the BH field.  */
+#define XLBH_MASK (XL_MASK | (0x1c << 11))
+
 /* An XL_MASK with the BO and BB fields fixed.  */
 #define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK)
 
@@ -1395,26 +1853,27 @@
 
 /* An XO form instruction.  */
 #define XO(op, xop, oe, rc) \
-  (OP (op) | (((xop) & 0x1ff) << 1) | (((oe) & 1) << 10) | ((rc) & 1))
+  (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 1) | ((((unsigned long)(oe)) & 1) << 10) | (((unsigned long)(rc)) & 1))
 #define XO_MASK XO (0x3f, 0x1ff, 1, 1)
 
 /* An XO_MASK with the RB field fixed.  */
 #define XORB_MASK (XO_MASK | RB_MASK)
 
 /* An XS form instruction.  */
-#define XS(op, xop, rc) (OP (op) | (((xop) & 0x1ff) << 2) | ((rc) & 1))
+#define XS(op, xop, rc) (OP (op) | ((((unsigned long)(xop)) & 0x1ff) << 2) | (((unsigned long)(rc)) & 1))
 #define XS_MASK XS (0x3f, 0x1ff, 1)
 
 /* A mask for the FXM version of an XFX form instruction.  */
-#define XFXFXM_MASK (X_MASK | (1 << 20) | (1 << 11))
+#define XFXFXM_MASK (X_MASK | (1 << 11) | (1 << 20))
 
 /* An XFX form instruction with the FXM field filled in.  */
-#define XFXM(op, xop, fxm) \
-  (X ((op), (xop)) | (((fxm) & 0xff) << 12))
+#define XFXM(op, xop, fxm, p4) \
+  (X ((op), (xop)) | ((((unsigned long)(fxm)) & 0xff) << 12) \
+   | ((unsigned long)(p4) << 20))
 
 /* An XFX form instruction with the SPR field filled in.  */
 #define XSPR(op, xop, spr) \
-  (X ((op), (xop)) | (((spr) & 0x1f) << 16) | (((spr) & 0x3e0) << 6))
+  (X ((op), (xop)) | ((((unsigned long)(spr)) & 0x1f) << 16) | ((((unsigned long)(spr)) & 0x3e0) << 6))
 #define XSPR_MASK (X_MASK | SPR_MASK)
 
 /* An XFX form instruction with the SPR field filled in except for the
@@ -1423,25 +1882,43 @@
 
 /* An XFX form instruction with the SPR field filled in except for the
    SPRG field.  */
-#define XSPRG_MASK (XSPR_MASK &~ SPRG_MASK)
+#define XSPRG_MASK (XSPR_MASK & ~(0x1f << 16))
+
+/* An X form instruction with everything filled in except the E field.  */
+#define XE_MASK (0xffff7fff)
+
+/* An X form user context instruction.  */
+#define XUC(op, xop)  (OP (op) | (((unsigned long)(xop)) & 0x1f))
+#define XUC_MASK      XUC(0x3f, 0x1f)
 
 /* The BO encodings used in extended conditional branch mnemonics.  */
 #define BODNZF	(0x0)
 #define BODNZFP	(0x1)
 #define BODZF	(0x2)
 #define BODZFP	(0x3)
-#define BOF	(0x4)
-#define BOFP	(0x5)
 #define BODNZT	(0x8)
 #define BODNZTP	(0x9)
 #define BODZT	(0xa)
 #define BODZTP	(0xb)
+
+#define BOF	(0x4)
+#define BOFP	(0x5)
+#define BOFM4	(0x6)
+#define BOFP4	(0x7)
 #define BOT	(0xc)
 #define BOTP	(0xd)
+#define BOTM4	(0xe)
+#define BOTP4	(0xf)
+
 #define BODNZ	(0x10)
 #define BODNZP	(0x11)
 #define BODZ	(0x12)
 #define BODZP	(0x13)
+#define BODNZM4 (0x18)
+#define BODNZP4 (0x19)
+#define BODZM4	(0x1a)
+#define BODZP4	(0x1b)
+
 #define BOU	(0x14)
 
 /* The BI condition bit encodings used in extended conditional branch
@@ -1470,13 +1947,44 @@
 
 /* Smaller names for the flags so each entry in the opcodes table will
    fit on a single line.  */
-#undef PPC
-#define PPC PPC_OPCODE_PPC
-#define POWER PPC_OPCODE_POWER
-#define POWER2 PPC_OPCODE_POWER2
-#define B32 PPC_OPCODE_32
-#define B64 PPC_OPCODE_64
-#define M601 PPC_OPCODE_601
+#undef	PPC
+#define PPC     PPC_OPCODE_PPC
+#define PPCCOM	PPC_OPCODE_PPC | PPC_OPCODE_COMMON
+#define NOPOWER4 PPC_OPCODE_NOPOWER4 | PPCCOM
+#define POWER4	PPC_OPCODE_POWER4
+#define POWER5	PPC_OPCODE_POWER5
+#define POWER6	PPC_OPCODE_POWER6
+#define CELL	PPC_OPCODE_CELL
+#define PPC32   PPC_OPCODE_32 | PPC_OPCODE_PPC
+#define PPC64   PPC_OPCODE_64 | PPC_OPCODE_PPC
+#define PPC403	PPC_OPCODE_403
+#define PPC405	PPC403
+#define PPC440	PPC_OPCODE_440
+#define PPC750	PPC
+#define PPC860	PPC
+#define PPCVEC	PPC_OPCODE_ALTIVEC
+#define	POWER   PPC_OPCODE_POWER
+#define	POWER2	PPC_OPCODE_POWER | PPC_OPCODE_POWER2
+#define PPCPWR2	PPC_OPCODE_PPC | PPC_OPCODE_POWER | PPC_OPCODE_POWER2
+#define	POWER32	PPC_OPCODE_POWER | PPC_OPCODE_32
+#define	COM     PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON
+#define	COM32   PPC_OPCODE_POWER | PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_32
+#define	M601    PPC_OPCODE_POWER | PPC_OPCODE_601
+#define PWRCOM	PPC_OPCODE_POWER | PPC_OPCODE_601 | PPC_OPCODE_COMMON
+#define	MFDEC1	PPC_OPCODE_POWER
+#define	MFDEC2	PPC_OPCODE_PPC | PPC_OPCODE_601 | PPC_OPCODE_BOOKE
+#define BOOKE	PPC_OPCODE_BOOKE
+#define BOOKE64	PPC_OPCODE_BOOKE64
+#define CLASSIC	PPC_OPCODE_CLASSIC
+#define PPCE300 PPC_OPCODE_E300
+#define PPCSPE	PPC_OPCODE_SPE
+#define PPCISEL	PPC_OPCODE_ISEL
+#define PPCEFS	PPC_OPCODE_EFS
+#define PPCBRLK	PPC_OPCODE_BRLOCK
+#define PPCPMR	PPC_OPCODE_PMR
+#define PPCCHLK	PPC_OPCODE_CACHELCK
+#define PPCCHLK64	PPC_OPCODE_CACHELCK | PPC_OPCODE_BOOKE64
+#define PPCRFMCI	PPC_OPCODE_RFMCI
 
 /* The opcode table.
 
@@ -1497,815 +2005,1501 @@
    sorted by major opcode.  */
 
 const struct powerpc_opcode powerpc_opcodes[] = {
-{ "tdlgti",  OPTO(2,TOLGT), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdllti",  OPTO(2,TOLLT), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdeqi",   OPTO(2,TOEQ), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdlgei",  OPTO(2,TOLGE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdlnli",  OPTO(2,TOLNL), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdllei",  OPTO(2,TOLLE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdlngi",  OPTO(2,TOLNG), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdgti",   OPTO(2,TOGT), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdgei",   OPTO(2,TOGE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdnli",   OPTO(2,TONL), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdlti",   OPTO(2,TOLT), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdlei",   OPTO(2,TOLE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdngi",   OPTO(2,TONG), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdnei",   OPTO(2,TONE), OPTO_MASK,	PPC|B64,	{ RA, SI } },
-{ "tdi",     OP(2),	OP_MASK,	PPC|B64,	{ TO, RA, SI } },
+{ "attn",    X(0,256), X_MASK,		POWER4,		{ 0 } },
+{ "tdlgti",  OPTO(2,TOLGT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdllti",  OPTO(2,TOLLT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdeqi",   OPTO(2,TOEQ), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlgei",  OPTO(2,TOLGE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlnli",  OPTO(2,TOLNL), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdllei",  OPTO(2,TOLLE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlngi",  OPTO(2,TOLNG), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdgti",   OPTO(2,TOGT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdgei",   OPTO(2,TOGE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdnli",   OPTO(2,TONL), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlti",   OPTO(2,TOLT), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdlei",   OPTO(2,TOLE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdngi",   OPTO(2,TONG), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdnei",   OPTO(2,TONE), OPTO_MASK,	PPC64,		{ RA, SI } },
+{ "tdi",     OP(2),	OP_MASK,	PPC64,		{ TO, RA, SI } },
 
-{ "twlgti",  OPTO(3,TOLGT), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tlgti",   OPTO(3,TOLGT), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twllti",  OPTO(3,TOLLT), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tllti",   OPTO(3,TOLLT), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "tweqi",   OPTO(3,TOEQ), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "teqi",    OPTO(3,TOEQ), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twlgei",  OPTO(3,TOLGE), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tlgei",   OPTO(3,TOLGE), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twlnli",  OPTO(3,TOLNL), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tlnli",   OPTO(3,TOLNL), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twllei",  OPTO(3,TOLLE), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tllei",   OPTO(3,TOLLE), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twlngi",  OPTO(3,TOLNG), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tlngi",   OPTO(3,TOLNG), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twgti",   OPTO(3,TOGT), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tgti",    OPTO(3,TOGT), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twgei",   OPTO(3,TOGE), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tgei",    OPTO(3,TOGE), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twnli",   OPTO(3,TONL), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tnli",    OPTO(3,TONL), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twlti",   OPTO(3,TOLT), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tlti",    OPTO(3,TOLT), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twlei",   OPTO(3,TOLE), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tlei",    OPTO(3,TOLE), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twngi",   OPTO(3,TONG), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tngi",    OPTO(3,TONG), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twnei",   OPTO(3,TONE), OPTO_MASK,	PPC,		{ RA, SI } },
-{ "tnei",    OPTO(3,TONE), OPTO_MASK,	POWER,		{ RA, SI } },
-{ "twi",     OP(3),	OP_MASK,	PPC,		{ TO, RA, SI } },
-{ "ti",      OP(3),	OP_MASK,	POWER,		{ TO, RA, SI } },
+{ "twlgti",  OPTO(3,TOLGT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlgti",   OPTO(3,TOLGT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twllti",  OPTO(3,TOLLT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tllti",   OPTO(3,TOLLT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "tweqi",   OPTO(3,TOEQ), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "teqi",    OPTO(3,TOEQ), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlgei",  OPTO(3,TOLGE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlgei",   OPTO(3,TOLGE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlnli",  OPTO(3,TOLNL), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlnli",   OPTO(3,TOLNL), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twllei",  OPTO(3,TOLLE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tllei",   OPTO(3,TOLLE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlngi",  OPTO(3,TOLNG), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlngi",   OPTO(3,TOLNG), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twgti",   OPTO(3,TOGT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tgti",    OPTO(3,TOGT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twgei",   OPTO(3,TOGE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tgei",    OPTO(3,TOGE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twnli",   OPTO(3,TONL), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tnli",    OPTO(3,TONL), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlti",   OPTO(3,TOLT), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlti",    OPTO(3,TOLT), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twlei",   OPTO(3,TOLE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tlei",    OPTO(3,TOLE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twngi",   OPTO(3,TONG), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tngi",    OPTO(3,TONG), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twnei",   OPTO(3,TONE), OPTO_MASK,	PPCCOM,		{ RA, SI } },
+{ "tnei",    OPTO(3,TONE), OPTO_MASK,	PWRCOM,		{ RA, SI } },
+{ "twi",     OP(3),	OP_MASK,	PPCCOM,		{ TO, RA, SI } },
+{ "ti",      OP(3),	OP_MASK,	PWRCOM,		{ TO, RA, SI } },
 
-{ "mulli",   OP(7),	OP_MASK,	PPC,		{ RT, RA, SI } },
-{ "muli",    OP(7),	OP_MASK,	POWER,		{ RT, RA, SI } },
+{ "macchw",	XO(4,172,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchw.",	XO(4,172,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwo",	XO(4,172,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwo.",	XO(4,172,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchws",	XO(4,236,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchws.",	XO(4,236,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwso",	XO(4,236,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwso.",	XO(4,236,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwsu",	XO(4,204,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwsu.",	XO(4,204,0,1), XO_MASK, PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwsuo",	XO(4,204,1,0), XO_MASK, PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwsuo.",	XO(4,204,1,1), XO_MASK, PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwu",	XO(4,140,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwu.",	XO(4,140,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwuo",	XO(4,140,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "macchwuo.",	XO(4,140,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhw",	XO(4,44,0,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhw.",	XO(4,44,0,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwo",	XO(4,44,1,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwo.",	XO(4,44,1,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhws",	XO(4,108,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhws.",	XO(4,108,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwso",	XO(4,108,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwso.",	XO(4,108,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwsu",	XO(4,76,0,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwsu.",	XO(4,76,0,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwsuo",	XO(4,76,1,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwsuo.",	XO(4,76,1,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwu",	XO(4,12,0,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwu.",	XO(4,12,0,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwuo",	XO(4,12,1,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "machhwuo.",	XO(4,12,1,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhw",	XO(4,428,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhw.",	XO(4,428,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwo",	XO(4,428,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwo.",	XO(4,428,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhws",	XO(4,492,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhws.",	XO(4,492,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwso",	XO(4,492,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwso.",	XO(4,492,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwsu",	XO(4,460,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwsu.",	XO(4,460,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwsuo",	XO(4,460,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwsuo.",	XO(4,460,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwu",	XO(4,396,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwu.",	XO(4,396,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwuo",	XO(4,396,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "maclhwuo.",	XO(4,396,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulchw",	XRC(4,168,0),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulchw.",	XRC(4,168,1),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulchwu",	XRC(4,136,0),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulchwu.",	XRC(4,136,1),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulhhw",	XRC(4,40,0),   X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulhhw.",	XRC(4,40,1),   X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulhhwu",	XRC(4,8,0),    X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mulhhwu.",	XRC(4,8,1),    X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mullhw",	XRC(4,424,0),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mullhw.",	XRC(4,424,1),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mullhwu",	XRC(4,392,0),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mullhwu.",	XRC(4,392,1),  X_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchw",	XO(4,174,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchw.",	XO(4,174,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchwo",	XO(4,174,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchwo.",	XO(4,174,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchws",	XO(4,238,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchws.",	XO(4,238,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchwso",	XO(4,238,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmacchwso.",	XO(4,238,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhw",	XO(4,46,0,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhw.",	XO(4,46,0,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhwo",	XO(4,46,1,0),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhwo.",	XO(4,46,1,1),  XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhws",	XO(4,110,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhws.",	XO(4,110,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhwso",	XO(4,110,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmachhwso.",	XO(4,110,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhw",	XO(4,430,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhw.",	XO(4,430,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhwo",	XO(4,430,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhwo.",	XO(4,430,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhws",	XO(4,494,0,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhws.",	XO(4,494,0,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhwso",	XO(4,494,1,0), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "nmaclhwso.",	XO(4,494,1,1), XO_MASK,	PPC405|PPC440,	{ RT, RA, RB } },
+{ "mfvscr",  VX(4, 1540), VX_MASK,	PPCVEC,		{ VD } },
+{ "mtvscr",  VX(4, 1604), VX_MASK,	PPCVEC,		{ VB } },
 
-{ "subfic",  OP(8),	OP_MASK,	PPC,		{ RT, RA, SI } },
-{ "sfi",     OP(8),	OP_MASK,	POWER,		{ RT, RA, SI } },
+  /* Double-precision opcodes.  */
+  /* Some of these conflict with AltiVec, so move them before, since
+     PPCVEC includes the PPC_OPCODE_PPC set.  */
+{ "efscfd",   VX(4, 719), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdabs",   VX(4, 740), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efdnabs",  VX(4, 741), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efdneg",   VX(4, 742), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efdadd",   VX(4, 736), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efdsub",   VX(4, 737), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efdmul",   VX(4, 744), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efddiv",   VX(4, 745), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efdcmpgt", VX(4, 748), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdcmplt", VX(4, 749), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdcmpeq", VX(4, 750), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdtstgt", VX(4, 764), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdtstlt", VX(4, 765), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdtsteq", VX(4, 766), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efdcfsi",  VX(4, 753), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfsid", VX(4, 739), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfui",  VX(4, 752), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfuid", VX(4, 738), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfsf",  VX(4, 755), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfuf",  VX(4, 754), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctsi",  VX(4, 757), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctsidz",VX(4, 747), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctsiz", VX(4, 762), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctui",  VX(4, 756), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctuidz",VX(4, 746), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctuiz", VX(4, 760), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctsf",  VX(4, 759), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdctuf",  VX(4, 758), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efdcfs",   VX(4, 751), VX_MASK,	PPCEFS,		{ RS, RB } },
+  /* End of double-precision opcodes.  */
 
-{ "dozi",    OP(9),	OP_MASK,	POWER|M601,	{ RT, RA, SI } },
+{ "vaddcuw", VX(4,  384), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddfp",  VX(4,   10), VX_MASK, 	PPCVEC,		{ VD, VA, VB } },
+{ "vaddsbs", VX(4,  768), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddshs", VX(4,  832), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddsws", VX(4,  896), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vaddubm", VX(4,    0), VX_MASK, 	PPCVEC,		{ VD, VA, VB } },
+{ "vaddubs", VX(4,  512), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduhm", VX(4,   64), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduhs", VX(4,  576), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduwm", VX(4,  128), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vadduws", VX(4,  640), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vand",    VX(4, 1028), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vandc",   VX(4, 1092), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsb",  VX(4, 1282), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsh",  VX(4, 1346), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgsw",  VX(4, 1410), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavgub",  VX(4, 1026), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavguh",  VX(4, 1090), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vavguw",  VX(4, 1154), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vcfsx",   VX(4,  842), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vcfux",   VX(4,  778), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vcmpbfp",   VXR(4, 966, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpbfp.",  VXR(4, 966, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpeqfp",  VXR(4, 198, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpeqfp.", VXR(4, 198, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequb",  VXR(4,   6, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequb.", VXR(4,   6, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequh",  VXR(4,  70, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequh.", VXR(4,  70, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequw",  VXR(4, 134, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpequw.", VXR(4, 134, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgefp",  VXR(4, 454, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgefp.", VXR(4, 454, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtfp",  VXR(4, 710, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtfp.", VXR(4, 710, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsb",  VXR(4, 774, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsb.", VXR(4, 774, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsh",  VXR(4, 838, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsh.", VXR(4, 838, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsw",  VXR(4, 902, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtsw.", VXR(4, 902, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtub",  VXR(4, 518, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtub.", VXR(4, 518, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuh",  VXR(4, 582, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuh.", VXR(4, 582, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuw",  VXR(4, 646, 0), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vcmpgtuw.", VXR(4, 646, 1), VXR_MASK, PPCVEC,	{ VD, VA, VB } },
+{ "vctsxs",    VX(4,  970), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vctuxs",    VX(4,  906), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vexptefp",  VX(4,  394), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vlogefp",   VX(4,  458), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vmaddfp",   VXA(4,  46), VXA_MASK,	PPCVEC,		{ VD, VA, VC, VB } },
+{ "vmaxfp",    VX(4, 1034), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsb",    VX(4,  258), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsh",    VX(4,  322), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxsw",    VX(4,  386), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxub",    VX(4,    2), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxuh",    VX(4,   66), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmaxuw",    VX(4,  130), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmhaddshs", VXA(4,  32), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmhraddshs", VXA(4, 33), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vminfp",    VX(4, 1098), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsb",    VX(4,  770), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsh",    VX(4,  834), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminsw",    VX(4,  898), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminub",    VX(4,  514), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminuh",    VX(4,  578), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vminuw",    VX(4,  642), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmladduhm", VXA(4,  34), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmrghb",    VX(4,   12), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrghh",    VX(4,   76), VX_MASK,    PPCVEC,		{ VD, VA, VB } },
+{ "vmrghw",    VX(4,  140), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglb",    VX(4,  268), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglh",    VX(4,  332), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmrglw",    VX(4,  396), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmsummbm",  VXA(4,  37), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumshm",  VXA(4,  40), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumshs",  VXA(4,  41), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumubm",  VXA(4,  36), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumuhm",  VXA(4,  38), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmsumuhs",  VXA(4,  39), VXA_MASK,   PPCVEC,		{ VD, VA, VB, VC } },
+{ "vmulesb",   VX(4,  776), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulesh",   VX(4,  840), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuleub",   VX(4,  520), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuleuh",   VX(4,  584), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulosb",   VX(4,  264), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulosh",   VX(4,  328), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmuloub",   VX(4,    8), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vmulouh",   VX(4,   72), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vnmsubfp",  VXA(4,  47), VXA_MASK,	PPCVEC,		{ VD, VA, VC, VB } },
+{ "vnor",      VX(4, 1284), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vor",       VX(4, 1156), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vperm",     VXA(4,  43), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vpkpx",     VX(4,  782), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkshss",   VX(4,  398), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkshus",   VX(4,  270), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkswss",   VX(4,  462), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkswus",   VX(4,  334), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuhum",   VX(4,   14), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuhus",   VX(4,  142), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuwum",   VX(4,   78), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vpkuwus",   VX(4,  206), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrefp",     VX(4,  266), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfim",     VX(4,  714), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfin",     VX(4,  522), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfip",     VX(4,  650), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrfiz",     VX(4,  586), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vrlb",      VX(4,    4), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrlh",      VX(4,   68), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrlw",      VX(4,  132), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vrsqrtefp", VX(4,  330), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vsel",      VXA(4,  42), VXA_MASK,	PPCVEC,		{ VD, VA, VB, VC } },
+{ "vsl",       VX(4,  452), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslb",      VX(4,  260), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsldoi",    VXA(4,  44), VXA_MASK,	PPCVEC,		{ VD, VA, VB, SHB } },
+{ "vslh",      VX(4,  324), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslo",      VX(4, 1036), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vslw",      VX(4,  388), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vspltb",    VX(4,  524), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vsplth",    VX(4,  588), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vspltisb",  VX(4,  780), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltish",  VX(4,  844), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltisw",  VX(4,  908), VX_MASK,	PPCVEC,		{ VD, SIMM } },
+{ "vspltw",    VX(4,  652), VX_MASK,	PPCVEC,		{ VD, VB, UIMM } },
+{ "vsr",       VX(4,  708), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrab",     VX(4,  772), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrah",     VX(4,  836), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsraw",     VX(4,  900), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrb",      VX(4,  516), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrh",      VX(4,  580), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsro",      VX(4, 1100), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsrw",      VX(4,  644), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubcuw",   VX(4, 1408), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubfp",    VX(4,   74), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubsbs",   VX(4, 1792), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubshs",   VX(4, 1856), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubsws",   VX(4, 1920), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsububm",   VX(4, 1024), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsububs",   VX(4, 1536), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuhm",   VX(4, 1088), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuhs",   VX(4, 1600), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuwm",   VX(4, 1152), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsubuws",   VX(4, 1664), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsumsws",   VX(4, 1928), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum2sws",  VX(4, 1672), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4sbs",  VX(4, 1800), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4shs",  VX(4, 1608), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vsum4ubs",  VX(4, 1544), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
+{ "vupkhpx",   VX(4,  846), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupkhsb",   VX(4,  526), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupkhsh",   VX(4,  590), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklpx",   VX(4,  974), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklsb",   VX(4,  654), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vupklsh",   VX(4,  718), VX_MASK,	PPCVEC,		{ VD, VB } },
+{ "vxor",      VX(4, 1220), VX_MASK,	PPCVEC,		{ VD, VA, VB } },
 
-{ "cmplwi",  OPL(10,0),	OPL_MASK,	PPC,		{ OBF, RA, UI } },
-{ "cmpldi",  OPL(10,1), OPL_MASK,	PPC|B64,	{ OBF, RA, UI } },
+{ "evaddw",    VX(4, 512), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evaddiw",   VX(4, 514), VX_MASK,	PPCSPE,		{ RS, RB, UIMM } },
+{ "evsubfw",   VX(4, 516), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evsubw",    VX(4, 516), VX_MASK,	PPCSPE,		{ RS, RB, RA } },
+{ "evsubifw",  VX(4, 518), VX_MASK,	PPCSPE,		{ RS, UIMM, RB } },
+{ "evsubiw",   VX(4, 518), VX_MASK,	PPCSPE,		{ RS, RB, UIMM } },
+{ "evabs",     VX(4, 520), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evneg",     VX(4, 521), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evextsb",   VX(4, 522), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evextsh",   VX(4, 523), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evrndw",    VX(4, 524), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evcntlzw",  VX(4, 525), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evcntlsw",  VX(4, 526), VX_MASK,	PPCSPE,		{ RS, RA } },
+
+{ "brinc",     VX(4, 527), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evand",     VX(4, 529), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evandc",    VX(4, 530), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmr",      VX(4, 535), VX_MASK,	PPCSPE,		{ RS, RA, BBA } },
+{ "evor",      VX(4, 535), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evorc",     VX(4, 539), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evxor",     VX(4, 534), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "eveqv",     VX(4, 537), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evnand",    VX(4, 542), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evnot",     VX(4, 536), VX_MASK,	PPCSPE,		{ RS, RA, BBA } },
+{ "evnor",     VX(4, 536), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evrlw",     VX(4, 552), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evrlwi",    VX(4, 554), VX_MASK,	PPCSPE,		{ RS, RA, EVUIMM } },
+{ "evslw",     VX(4, 548), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evslwi",    VX(4, 550), VX_MASK,	PPCSPE,		{ RS, RA, EVUIMM } },
+{ "evsrws",    VX(4, 545), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evsrwu",    VX(4, 544), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evsrwis",   VX(4, 547), VX_MASK,	PPCSPE,		{ RS, RA, EVUIMM } },
+{ "evsrwiu",   VX(4, 546), VX_MASK,	PPCSPE,		{ RS, RA, EVUIMM } },
+{ "evsplati",  VX(4, 553), VX_MASK,	PPCSPE,		{ RS, SIMM } },
+{ "evsplatfi", VX(4, 555), VX_MASK,	PPCSPE,		{ RS, SIMM } },
+{ "evmergehi", VX(4, 556), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmergelo", VX(4, 557), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmergehilo",VX(4,558), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmergelohi",VX(4,559), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evcmpgts",  VX(4, 561), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evcmpgtu",  VX(4, 560), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evcmplts",  VX(4, 563), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evcmpltu",  VX(4, 562), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evcmpeq",   VX(4, 564), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evsel",     EVSEL(4,79),EVSEL_MASK,	PPCSPE,		{ RS, RA, RB, CRFS } },
+
+{ "evldd",     VX(4, 769), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evlddx",    VX(4, 768), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evldw",     VX(4, 771), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evldwx",    VX(4, 770), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evldh",     VX(4, 773), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evldhx",    VX(4, 772), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwhe",    VX(4, 785), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwhex",   VX(4, 784), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwhou",   VX(4, 789), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwhoux",  VX(4, 788), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwhos",   VX(4, 791), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwhosx",  VX(4, 790), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwwsplat",VX(4, 793), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwwsplatx",VX(4, 792), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlwhsplat",VX(4, 797), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evlwhsplatx",VX(4, 796), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlhhesplat",VX(4, 777), VX_MASK,	PPCSPE,		{ RS, EVUIMM_2, RA } },
+{ "evlhhesplatx",VX(4, 776), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlhhousplat",VX(4, 781), VX_MASK,	PPCSPE,		{ RS, EVUIMM_2, RA } },
+{ "evlhhousplatx",VX(4, 780), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evlhhossplat",VX(4, 783), VX_MASK,	PPCSPE,		{ RS, EVUIMM_2, RA } },
+{ "evlhhossplatx",VX(4, 782), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evstdd",    VX(4, 801), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evstddx",   VX(4, 800), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstdw",    VX(4, 803), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evstdwx",   VX(4, 802), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstdh",    VX(4, 805), VX_MASK,	PPCSPE,		{ RS, EVUIMM_8, RA } },
+{ "evstdhx",   VX(4, 804), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstwwe",   VX(4, 825), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evstwwex",  VX(4, 824), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstwwo",   VX(4, 829), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evstwwox",  VX(4, 828), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstwhe",   VX(4, 817), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evstwhex",  VX(4, 816), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evstwho",   VX(4, 821), VX_MASK,	PPCSPE,		{ RS, EVUIMM_4, RA } },
+{ "evstwhox",  VX(4, 820), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evfsabs",   VX(4, 644), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evfsnabs",  VX(4, 645), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evfsneg",   VX(4, 646), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evfsadd",   VX(4, 640), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evfssub",   VX(4, 641), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evfsmul",   VX(4, 648), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evfsdiv",   VX(4, 649), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evfscmpgt", VX(4, 652), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfscmplt", VX(4, 653), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfscmpeq", VX(4, 654), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfststgt", VX(4, 668), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfststlt", VX(4, 669), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfststeq", VX(4, 670), VX_MASK,	PPCSPE,		{ CRFD, RA, RB } },
+{ "evfscfui",  VX(4, 656), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctuiz", VX(4, 664), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfscfsi",  VX(4, 657), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfscfuf",  VX(4, 658), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfscfsf",  VX(4, 659), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctui",  VX(4, 660), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctsi",  VX(4, 661), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctsiz", VX(4, 666), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctuf",  VX(4, 662), VX_MASK,	PPCSPE,		{ RS, RB } },
+{ "evfsctsf",  VX(4, 663), VX_MASK,	PPCSPE,		{ RS, RB } },
+
+{ "efsabs",   VX(4, 708), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efsnabs",  VX(4, 709), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efsneg",   VX(4, 710), VX_MASK,	PPCEFS,		{ RS, RA } },
+{ "efsadd",   VX(4, 704), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efssub",   VX(4, 705), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efsmul",   VX(4, 712), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efsdiv",   VX(4, 713), VX_MASK,	PPCEFS,		{ RS, RA, RB } },
+{ "efscmpgt", VX(4, 716), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efscmplt", VX(4, 717), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efscmpeq", VX(4, 718), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efststgt", VX(4, 732), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efststlt", VX(4, 733), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efststeq", VX(4, 734), VX_MASK,	PPCEFS,		{ CRFD, RA, RB } },
+{ "efscfui",  VX(4, 720), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctuiz", VX(4, 728), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efscfsi",  VX(4, 721), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efscfuf",  VX(4, 722), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efscfsf",  VX(4, 723), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctui",  VX(4, 724), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctsi",  VX(4, 725), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctsiz", VX(4, 730), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctuf",  VX(4, 726), VX_MASK,	PPCEFS,		{ RS, RB } },
+{ "efsctsf",  VX(4, 727), VX_MASK,	PPCEFS,		{ RS, RB } },
+
+{ "evmhossf",  VX(4, 1031), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhossfa", VX(4, 1063), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmf",  VX(4, 1039), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmfa", VX(4, 1071), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmi",  VX(4, 1037), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmia", VX(4, 1069), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhoumi",  VX(4, 1036), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhoumia", VX(4, 1068), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessf",  VX(4, 1027), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessfa", VX(4, 1059), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmf",  VX(4, 1035), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmfa", VX(4, 1067), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmi",  VX(4, 1033), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmia", VX(4, 1065), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheumi",  VX(4, 1032), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheumia", VX(4, 1064), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmhossfaaw",VX(4, 1287), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhossiaaw",VX(4, 1285), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmfaaw",VX(4, 1295), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmiaaw",VX(4, 1293), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhousiaaw",VX(4, 1284), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhoumiaaw",VX(4, 1292), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessfaaw",VX(4, 1283), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessiaaw",VX(4, 1281), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmfaaw",VX(4, 1291), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmiaaw",VX(4, 1289), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheusiaaw",VX(4, 1280), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheumiaaw",VX(4, 1288), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmhossfanw",VX(4, 1415), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhossianw",VX(4, 1413), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmfanw",VX(4, 1423), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhosmianw",VX(4, 1421), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhousianw",VX(4, 1412), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhoumianw",VX(4, 1420), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessfanw",VX(4, 1411), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhessianw",VX(4, 1409), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmfanw",VX(4, 1419), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhesmianw",VX(4, 1417), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheusianw",VX(4, 1408), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmheumianw",VX(4, 1416), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmhogsmfaa",VX(4, 1327), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhogsmiaa",VX(4, 1325), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhogumiaa",VX(4, 1324), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegsmfaa",VX(4, 1323), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegsmiaa",VX(4, 1321), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegumiaa",VX(4, 1320), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmhogsmfan",VX(4, 1455), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhogsmian",VX(4, 1453), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhogumian",VX(4, 1452), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegsmfan",VX(4, 1451), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegsmian",VX(4, 1449), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmhegumian",VX(4, 1448), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwhssf",  VX(4, 1095), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhssfa", VX(4, 1127), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhsmf",  VX(4, 1103), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhsmfa", VX(4, 1135), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhsmi",  VX(4, 1101), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhsmia", VX(4, 1133), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhumi",  VX(4, 1100), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwhumia", VX(4, 1132), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwlumi",  VX(4, 1096), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlumia", VX(4, 1128), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwlssiaaw",VX(4, 1345), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlsmiaaw",VX(4, 1353), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlusiaaw",VX(4, 1344), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlumiaaw",VX(4, 1352), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwlssianw",VX(4, 1473), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlsmianw",VX(4, 1481), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlusianw",VX(4, 1472), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwlumianw",VX(4, 1480), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwssf",   VX(4, 1107), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwssfa",  VX(4, 1139), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmf",   VX(4, 1115), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmfa",  VX(4, 1147), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmi",   VX(4, 1113), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmia",  VX(4, 1145), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwumi",   VX(4, 1112), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwumia",  VX(4, 1144), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwssfaa", VX(4, 1363), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmfaa", VX(4, 1371), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmiaa", VX(4, 1369), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwumiaa", VX(4, 1368), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evmwssfan", VX(4, 1491), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmfan", VX(4, 1499), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwsmian", VX(4, 1497), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evmwumian", VX(4, 1496), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "evaddssiaaw",VX(4, 1217), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evaddsmiaaw",VX(4, 1225), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evaddusiaaw",VX(4, 1216), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evaddumiaaw",VX(4, 1224), VX_MASK,	PPCSPE,		{ RS, RA } },
+
+{ "evsubfssiaaw",VX(4, 1219), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evsubfsmiaaw",VX(4, 1227), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evsubfusiaaw",VX(4, 1218), VX_MASK,	PPCSPE,		{ RS, RA } },
+{ "evsubfumiaaw",VX(4, 1226), VX_MASK,	PPCSPE,		{ RS, RA } },
+
+{ "evmra",    VX(4, 1220), VX_MASK,	PPCSPE,		{ RS, RA } },
+
+{ "evdivws",  VX(4, 1222), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+{ "evdivwu",  VX(4, 1223), VX_MASK,	PPCSPE,		{ RS, RA, RB } },
+
+{ "mulli",   OP(7),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "muli",    OP(7),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+
+{ "subfic",  OP(8),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "sfi",     OP(8),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+
+{ "dozi",    OP(9),	OP_MASK,	M601,		{ RT, RA, SI } },
+
+{ "bce",     B(9,0,0),	B_MASK,		BOOKE64,	{ BO, BI, BD } },
+{ "bcel",    B(9,0,1),	B_MASK,		BOOKE64,	{ BO, BI, BD } },
+{ "bcea",    B(9,1,0),	B_MASK,		BOOKE64,	{ BO, BI, BDA } },
+{ "bcela",   B(9,1,1),	B_MASK,		BOOKE64,	{ BO, BI, BDA } },
+
+{ "cmplwi",  OPL(10,0),	OPL_MASK,	PPCCOM,		{ OBF, RA, UI } },
+{ "cmpldi",  OPL(10,1), OPL_MASK,	PPC64,		{ OBF, RA, UI } },
 { "cmpli",   OP(10),	OP_MASK,	PPC,		{ BF, L, RA, UI } },
-{ "cmpli",   OP(10),	OP_MASK,	POWER,		{ BF, RA, UI } },
+{ "cmpli",   OP(10),	OP_MASK,	PWRCOM,		{ BF, RA, UI } },
 
-{ "cmpwi",   OPL(11,0),	OPL_MASK,	PPC,		{ OBF, RA, SI } },
-{ "cmpdi",   OPL(11,1),	OPL_MASK,	PPC|B64,	{ OBF, RA, SI } },
+{ "cmpwi",   OPL(11,0),	OPL_MASK,	PPCCOM,		{ OBF, RA, SI } },
+{ "cmpdi",   OPL(11,1),	OPL_MASK,	PPC64,		{ OBF, RA, SI } },
 { "cmpi",    OP(11),	OP_MASK,	PPC,		{ BF, L, RA, SI } },
-{ "cmpi",    OP(11),	OP_MASK,	POWER,		{ BF, RA, SI } },
+{ "cmpi",    OP(11),	OP_MASK,	PWRCOM,		{ BF, RA, SI } },
 
-{ "addic",   OP(12),	OP_MASK,	PPC,		{ RT, RA, SI } },
-{ "ai",	     OP(12),	OP_MASK,	POWER,		{ RT, RA, SI } },
-{ "subic",   OP(12),	OP_MASK,	PPC,		{ RT, RA, NSI } },
+{ "addic",   OP(12),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "ai",	     OP(12),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+{ "subic",   OP(12),	OP_MASK,	PPCCOM,		{ RT, RA, NSI } },
 
-{ "addic.",  OP(13),	OP_MASK,	PPC,		{ RT, RA, SI } },
-{ "ai.",     OP(13),	OP_MASK,	POWER,		{ RT, RA, SI } },
-{ "subic.",  OP(13),	OP_MASK,	PPC,		{ RT, RA, NSI } },
+{ "addic.",  OP(13),	OP_MASK,	PPCCOM,		{ RT, RA, SI } },
+{ "ai.",     OP(13),	OP_MASK,	PWRCOM,		{ RT, RA, SI } },
+{ "subic.",  OP(13),	OP_MASK,	PPCCOM,		{ RT, RA, NSI } },
 
-{ "li",	     OP(14),	DRA_MASK,	PPC,		{ RT, SI } },
-{ "lil",     OP(14),	DRA_MASK,	POWER,		{ RT, SI } },
-{ "addi",    OP(14),	OP_MASK,	PPC,		{ RT, RA, SI } },
-{ "cal",     OP(14),	OP_MASK,	POWER,		{ RT, D, RA } },
-{ "subi",    OP(14),	OP_MASK,	PPC,		{ RT, RA, NSI } },
-{ "la",	     OP(14),	OP_MASK,	PPC,		{ RT, D, RA } },
+{ "li",	     OP(14),	DRA_MASK,	PPCCOM,		{ RT, SI } },
+{ "lil",     OP(14),	DRA_MASK,	PWRCOM,		{ RT, SI } },
+{ "addi",    OP(14),	OP_MASK,	PPCCOM,		{ RT, RA0, SI } },
+{ "cal",     OP(14),	OP_MASK,	PWRCOM,		{ RT, D, RA0 } },
+{ "subi",    OP(14),	OP_MASK,	PPCCOM,		{ RT, RA0, NSI } },
+{ "la",	     OP(14),	OP_MASK,	PPCCOM,		{ RT, D, RA0 } },
 
-{ "lis",     OP(15),	DRA_MASK,	PPC,		{ RT, SISIGNOPT } },
-{ "liu",     OP(15),	DRA_MASK,	POWER,		{ RT, SISIGNOPT } },
-{ "addis",   OP(15),	OP_MASK,	PPC,		{ RT,RA,SISIGNOPT } },
-{ "cau",     OP(15),	OP_MASK,	POWER,		{ RT,RA,SISIGNOPT } },
-{ "subis",   OP(15),	OP_MASK,	PPC,		{ RT, RA, NSI } },
+{ "lis",     OP(15),	DRA_MASK,	PPCCOM,		{ RT, SISIGNOPT } },
+{ "liu",     OP(15),	DRA_MASK,	PWRCOM,		{ RT, SISIGNOPT } },
+{ "addis",   OP(15),	OP_MASK,	PPCCOM,		{ RT,RA0,SISIGNOPT } },
+{ "cau",     OP(15),	OP_MASK,	PWRCOM,		{ RT,RA0,SISIGNOPT } },
+{ "subis",   OP(15),	OP_MASK,	PPCCOM,		{ RT, RA0, NSI } },
 
-{ "bdnz-",   BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,	{ BDM } },
-{ "bdnz+",   BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,	{ BDP } },
-{ "bdnz",    BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,	{ BD } },
-{ "bdn",     BBO(16,BODNZ,0,0), BBOYBI_MASK, POWER,	{ BD } },
-{ "bdnzl-",  BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,	{ BDM } },
-{ "bdnzl+",  BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,	{ BDP } },
-{ "bdnzl",   BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,	{ BD } },
-{ "bdnl",    BBO(16,BODNZ,0,1), BBOYBI_MASK, POWER,	{ BD } },
-{ "bdnza-",  BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,	{ BDMA } },
-{ "bdnza+",  BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,	{ BDPA } },
-{ "bdnza",   BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,	{ BDA } },
-{ "bdna",    BBO(16,BODNZ,1,0), BBOYBI_MASK, POWER,	{ BDA } },
-{ "bdnzla-", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,	{ BDMA } },
-{ "bdnzla+", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,	{ BDPA } },
-{ "bdnzla",  BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,	{ BDA } },
-{ "bdnla",   BBO(16,BODNZ,1,1), BBOYBI_MASK, POWER,	{ BDA } },
-{ "bdz-",    BBO(16,BODZ,0,0), BBOYBI_MASK, PPC,	{ BDM } },
-{ "bdz+",    BBO(16,BODZ,0,0), BBOYBI_MASK, PPC,	{ BDP } },
-{ "bdz",     BBO(16,BODZ,0,0), BBOYBI_MASK, PPC|POWER,	{ BD } },
-{ "bdzl-",   BBO(16,BODZ,0,1), BBOYBI_MASK, PPC,	{ BDM } },
-{ "bdzl+",   BBO(16,BODZ,0,1), BBOYBI_MASK, PPC,	{ BDP } },
-{ "bdzl",    BBO(16,BODZ,0,1), BBOYBI_MASK, PPC|POWER,	{ BD } },
-{ "bdza-",   BBO(16,BODZ,1,0), BBOYBI_MASK, PPC,	{ BDMA } },
-{ "bdza+",   BBO(16,BODZ,1,0), BBOYBI_MASK, PPC,	{ BDPA } },
-{ "bdza",    BBO(16,BODZ,1,0), BBOYBI_MASK, PPC|POWER,	{ BDA } },
-{ "bdzla-",  BBO(16,BODZ,1,1), BBOYBI_MASK, PPC,	{ BDMA } },
-{ "bdzla+",  BBO(16,BODZ,1,1), BBOYBI_MASK, PPC,	{ BDPA } },
-{ "bdzla",   BBO(16,BODZ,1,1), BBOYBI_MASK, PPC|POWER,	{ BDA } },
-{ "blt-",    BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "blt+",    BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "blt",     BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bltl-",   BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bltl+",   BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bltl",    BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "blta-",   BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "blta+",   BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "blta",    BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bltla-",  BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bltla+",  BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bltla",   BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bgt-",    BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bgt+",    BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bgt",     BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bgtl-",   BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bgtl+",   BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bgtl",    BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bgta-",   BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bgta+",   BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bgta",    BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bgtla-",  BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bgtla+",  BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bgtla",   BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "beq-",    BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "beq+",    BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "beq",     BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "beql-",   BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "beql+",   BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "beql",    BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "beqa-",   BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "beqa+",   BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "beqa",    BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "beqla-",  BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "beqla+",  BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "beqla",   BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bso-",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bso+",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bso",     BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bsol-",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bsol+",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bsol",    BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bsoa-",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bsoa+",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bsoa",    BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bsola-",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bsola+",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bsola",   BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bun-",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bun+",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bun",     BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BD } },
-{ "bunl-",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bunl+",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bunl",    BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BD } },
-{ "buna-",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "buna+",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "buna",    BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDA } },
-{ "bunla-",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bunla+",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bunla",   BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDA } },
-{ "bge-",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bge+",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bge",     BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bgel-",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bgel+",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bgel",    BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bgea-",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bgea+",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bgea",    BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bgela-",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bgela+",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bgela",   BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bnl-",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bnl+",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bnl",     BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bnll-",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bnll+",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bnll",    BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bnla-",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnla+",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnla",    BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bnlla-",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnlla+",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnlla",   BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "ble-",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "ble+",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "ble",     BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "blel-",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "blel+",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "blel",    BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "blea-",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "blea+",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "blea",    BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "blela-",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "blela+",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "blela",   BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bng-",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bng+",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bng",     BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bngl-",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bngl+",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bngl",    BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bnga-",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnga+",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnga",    BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bngla-",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bngla+",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bngla",   BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bne-",    BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bne+",    BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bne",     BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bnel-",   BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bnel+",   BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bnel",    BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bnea-",   BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnea+",   BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnea",    BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bnela-",  BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnela+",  BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnela",   BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bns-",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bns+",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bns",     BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bnsl-",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bnsl+",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bnsl",    BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
-{ "bnsa-",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnsa+",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnsa",    BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bnsla-",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnsla+",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnsla",   BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
-{ "bnu-",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bnu+",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bnu",     BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC,	{ CR, BD } },
-{ "bnul-",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDM } },
-{ "bnul+",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BDP } },
-{ "bnul",    BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC,	{ CR, BD } },
-{ "bnua-",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnua+",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnua",    BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC,	{ CR, BDA } },
-{ "bnula-",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDMA } },
-{ "bnula+",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDPA } },
-{ "bnula",   BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC,	{ CR, BDA } },
-{ "bdnzt-",  BBO(16,BODNZT,0,0), BBOY_MASK, PPC,	{ BI, BDM } },
-{ "bdnzt+",  BBO(16,BODNZT,0,0), BBOY_MASK, PPC,	{ BI, BDP } },
-{ "bdnzt",   BBO(16,BODNZT,0,0), BBOY_MASK, PPC,	{ BI, BD } },
-{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, PPC,	{ BI, BDM } },
-{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, PPC,	{ BI, BDP } },
-{ "bdnztl",  BBO(16,BODNZT,0,1), BBOY_MASK, PPC,	{ BI, BD } },
-{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, PPC,	{ BI, BDMA } },
-{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, PPC,	{ BI, BDPA } },
-{ "bdnzta",  BBO(16,BODNZT,1,0), BBOY_MASK, PPC,	{ BI, BDA } },
-{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, PPC,	{ BI, BDMA } },
-{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, PPC,	{ BI, BDPA } },
-{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPC,	{ BI, BDA } },
-{ "bdnzf-",  BBO(16,BODNZF,0,0), BBOY_MASK, PPC,	{ BI, BDM } },
-{ "bdnzf+",  BBO(16,BODNZF,0,0), BBOY_MASK, PPC,	{ BI, BDP } },
-{ "bdnzf",   BBO(16,BODNZF,0,0), BBOY_MASK, PPC,	{ BI, BD } },
-{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, PPC,	{ BI, BDM } },
-{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, PPC,	{ BI, BDP } },
-{ "bdnzfl",  BBO(16,BODNZF,0,1), BBOY_MASK, PPC,	{ BI, BD } },
-{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, PPC,	{ BI, BDMA } },
-{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, PPC,	{ BI, BDPA } },
-{ "bdnzfa",  BBO(16,BODNZF,1,0), BBOY_MASK, PPC,	{ BI, BDA } },
-{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, PPC,	{ BI, BDMA } },
-{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, PPC,	{ BI, BDPA } },
-{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPC,	{ BI, BDA } },
-{ "bt-",     BBO(16,BOT,0,0), BBOY_MASK, PPC,		{ BI, BDM } },
-{ "bt+",     BBO(16,BOT,0,0), BBOY_MASK, PPC,		{ BI, BDP } },
-{ "bt",	     BBO(16,BOT,0,0), BBOY_MASK, PPC,		{ BI, BD } },
-{ "bbt",     BBO(16,BOT,0,0), BBOY_MASK, POWER,		{ BI, BD } },
-{ "btl-",    BBO(16,BOT,0,1), BBOY_MASK, PPC,		{ BI, BDM } },
-{ "btl+",    BBO(16,BOT,0,1), BBOY_MASK, PPC,		{ BI, BDP } },
-{ "btl",     BBO(16,BOT,0,1), BBOY_MASK, PPC,		{ BI, BD } },
-{ "bbtl",    BBO(16,BOT,0,1), BBOY_MASK, POWER,		{ BI, BD } },
-{ "bta-",    BBO(16,BOT,1,0), BBOY_MASK, PPC,		{ BI, BDMA } },
-{ "bta+",    BBO(16,BOT,1,0), BBOY_MASK, PPC,		{ BI, BDPA } },
-{ "bta",     BBO(16,BOT,1,0), BBOY_MASK, PPC,		{ BI, BDA } },
-{ "bbta",    BBO(16,BOT,1,0), BBOY_MASK, POWER,		{ BI, BDA } },
-{ "btla-",   BBO(16,BOT,1,1), BBOY_MASK, PPC,		{ BI, BDMA } },
-{ "btla+",   BBO(16,BOT,1,1), BBOY_MASK, PPC,		{ BI, BDPA } },
-{ "btla",    BBO(16,BOT,1,1), BBOY_MASK, PPC,		{ BI, BDA } },
-{ "bbtla",   BBO(16,BOT,1,1), BBOY_MASK, POWER,		{ BI, BDA } },
-{ "bf-",     BBO(16,BOF,0,0), BBOY_MASK, PPC,		{ BI, BDM } },
-{ "bf+",     BBO(16,BOF,0,0), BBOY_MASK, PPC,		{ BI, BDP } },
-{ "bf",	     BBO(16,BOF,0,0), BBOY_MASK, PPC,		{ BI, BD } },
-{ "bbf",     BBO(16,BOF,0,0), BBOY_MASK, POWER,		{ BI, BD } },
-{ "bfl-",    BBO(16,BOF,0,1), BBOY_MASK, PPC,		{ BI, BDM } },
-{ "bfl+",    BBO(16,BOF,0,1), BBOY_MASK, PPC,		{ BI, BDP } },
-{ "bfl",     BBO(16,BOF,0,1), BBOY_MASK, PPC,		{ BI, BD } },
-{ "bbfl",    BBO(16,BOF,0,1), BBOY_MASK, POWER,		{ BI, BD } },
-{ "bfa-",    BBO(16,BOF,1,0), BBOY_MASK, PPC,		{ BI, BDMA } },
-{ "bfa+",    BBO(16,BOF,1,0), BBOY_MASK, PPC,		{ BI, BDPA } },
-{ "bfa",     BBO(16,BOF,1,0), BBOY_MASK, PPC,		{ BI, BDA } },
-{ "bbfa",    BBO(16,BOF,1,0), BBOY_MASK, POWER,		{ BI, BDA } },
-{ "bfla-",   BBO(16,BOF,1,1), BBOY_MASK, PPC,		{ BI, BDMA } },
-{ "bfla+",   BBO(16,BOF,1,1), BBOY_MASK, PPC,		{ BI, BDPA } },
-{ "bfla",    BBO(16,BOF,1,1), BBOY_MASK, PPC,		{ BI, BDA } },
-{ "bbfla",   BBO(16,BOF,1,1), BBOY_MASK, POWER,		{ BI, BDA } },
-{ "bdzt-",   BBO(16,BODZT,0,0), BBOY_MASK, PPC,		{ BI, BDM } },
-{ "bdzt+",   BBO(16,BODZT,0,0), BBOY_MASK, PPC,		{ BI, BDP } },
-{ "bdzt",    BBO(16,BODZT,0,0), BBOY_MASK, PPC,		{ BI, BD } },
-{ "bdztl-",  BBO(16,BODZT,0,1), BBOY_MASK, PPC,		{ BI, BDM } },
-{ "bdztl+",  BBO(16,BODZT,0,1), BBOY_MASK, PPC,		{ BI, BDP } },
-{ "bdztl",   BBO(16,BODZT,0,1), BBOY_MASK, PPC,		{ BI, BD } },
-{ "bdzta-",  BBO(16,BODZT,1,0), BBOY_MASK, PPC,		{ BI, BDMA } },
-{ "bdzta+",  BBO(16,BODZT,1,0), BBOY_MASK, PPC,		{ BI, BDPA } },
-{ "bdzta",   BBO(16,BODZT,1,0), BBOY_MASK, PPC,		{ BI, BDA } },
-{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, PPC,		{ BI, BDMA } },
-{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, PPC,		{ BI, BDPA } },
-{ "bdztla",  BBO(16,BODZT,1,1), BBOY_MASK, PPC,		{ BI, BDA } },
-{ "bdzf-",   BBO(16,BODZF,0,0), BBOY_MASK, PPC,		{ BI, BDM } },
-{ "bdzf+",   BBO(16,BODZF,0,0), BBOY_MASK, PPC,		{ BI, BDP } },
-{ "bdzf",    BBO(16,BODZF,0,0), BBOY_MASK, PPC,		{ BI, BD } },
-{ "bdzfl-",  BBO(16,BODZF,0,1), BBOY_MASK, PPC,		{ BI, BDM } },
-{ "bdzfl+",  BBO(16,BODZF,0,1), BBOY_MASK, PPC,		{ BI, BDP } },
-{ "bdzfl",   BBO(16,BODZF,0,1), BBOY_MASK, PPC,		{ BI, BD } },
-{ "bdzfa-",  BBO(16,BODZF,1,0), BBOY_MASK, PPC,		{ BI, BDMA } },
-{ "bdzfa+",  BBO(16,BODZF,1,0), BBOY_MASK, PPC,		{ BI, BDPA } },
-{ "bdzfa",   BBO(16,BODZF,1,0), BBOY_MASK, PPC,		{ BI, BDA } },
-{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, PPC,		{ BI, BDMA } },
-{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, PPC,		{ BI, BDPA } },
-{ "bdzfla",  BBO(16,BODZF,1,1), BBOY_MASK, PPC,		{ BI, BDA } },
-{ "bc-",     B(16,0,0),	B_MASK,		PPC,		{ BOE, BI, BDM } },
-{ "bc+",     B(16,0,0),	B_MASK,		PPC,		{ BOE, BI, BDP } },
-{ "bc",	     B(16,0,0),	B_MASK,		PPC|POWER,	{ BO, BI, BD } },
-{ "bcl-",    B(16,0,1),	B_MASK,		PPC,		{ BOE, BI, BDM } },
-{ "bcl+",    B(16,0,1),	B_MASK,		PPC,		{ BOE, BI, BDP } },
-{ "bcl",     B(16,0,1),	B_MASK,		PPC|POWER,	{ BO, BI, BD } },
-{ "bca-",    B(16,1,0),	B_MASK,		PPC,		{ BOE, BI, BDMA } },
-{ "bca+",    B(16,1,0),	B_MASK,		PPC,		{ BOE, BI, BDPA } },
-{ "bca",     B(16,1,0),	B_MASK,		PPC|POWER,	{ BO, BI, BDA } },
-{ "bcla-",   B(16,1,1),	B_MASK,		PPC,		{ BOE, BI, BDMA } },
-{ "bcla+",   B(16,1,1),	B_MASK,		PPC,		{ BOE, BI, BDPA } },
-{ "bcla",    B(16,1,1),	B_MASK,		PPC|POWER,	{ BO, BI, BDA } },
+{ "bdnz-",   BBO(16,BODNZ,0,0),      BBOATBI_MASK, PPCCOM,	{ BDM } },
+{ "bdnz+",   BBO(16,BODNZ,0,0),      BBOATBI_MASK, PPCCOM,	{ BDP } },
+{ "bdnz",    BBO(16,BODNZ,0,0),      BBOATBI_MASK, PPCCOM,	{ BD } },
+{ "bdn",     BBO(16,BODNZ,0,0),      BBOATBI_MASK, PWRCOM,	{ BD } },
+{ "bdnzl-",  BBO(16,BODNZ,0,1),      BBOATBI_MASK, PPCCOM,	{ BDM } },
+{ "bdnzl+",  BBO(16,BODNZ,0,1),      BBOATBI_MASK, PPCCOM,	{ BDP } },
+{ "bdnzl",   BBO(16,BODNZ,0,1),      BBOATBI_MASK, PPCCOM,	{ BD } },
+{ "bdnl",    BBO(16,BODNZ,0,1),      BBOATBI_MASK, PWRCOM,	{ BD } },
+{ "bdnza-",  BBO(16,BODNZ,1,0),      BBOATBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdnza+",  BBO(16,BODNZ,1,0),      BBOATBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdnza",   BBO(16,BODNZ,1,0),      BBOATBI_MASK, PPCCOM,	{ BDA } },
+{ "bdna",    BBO(16,BODNZ,1,0),      BBOATBI_MASK, PWRCOM,	{ BDA } },
+{ "bdnzla-", BBO(16,BODNZ,1,1),      BBOATBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdnzla+", BBO(16,BODNZ,1,1),      BBOATBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdnzla",  BBO(16,BODNZ,1,1),      BBOATBI_MASK, PPCCOM,	{ BDA } },
+{ "bdnla",   BBO(16,BODNZ,1,1),      BBOATBI_MASK, PWRCOM,	{ BDA } },
+{ "bdz-",    BBO(16,BODZ,0,0),       BBOATBI_MASK, PPCCOM,	{ BDM } },
+{ "bdz+",    BBO(16,BODZ,0,0),       BBOATBI_MASK, PPCCOM,	{ BDP } },
+{ "bdz",     BBO(16,BODZ,0,0),       BBOATBI_MASK, COM,		{ BD } },
+{ "bdzl-",   BBO(16,BODZ,0,1),       BBOATBI_MASK, PPCCOM,	{ BDM } },
+{ "bdzl+",   BBO(16,BODZ,0,1),       BBOATBI_MASK, PPCCOM,	{ BDP } },
+{ "bdzl",    BBO(16,BODZ,0,1),       BBOATBI_MASK, COM,		{ BD } },
+{ "bdza-",   BBO(16,BODZ,1,0),       BBOATBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdza+",   BBO(16,BODZ,1,0),       BBOATBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdza",    BBO(16,BODZ,1,0),       BBOATBI_MASK, COM,		{ BDA } },
+{ "bdzla-",  BBO(16,BODZ,1,1),       BBOATBI_MASK, PPCCOM,	{ BDMA } },
+{ "bdzla+",  BBO(16,BODZ,1,1),       BBOATBI_MASK, PPCCOM,	{ BDPA } },
+{ "bdzla",   BBO(16,BODZ,1,1),       BBOATBI_MASK, COM,		{ BDA } },
+{ "blt-",    BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "blt+",    BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "blt",     BBOCB(16,BOT,CBLT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bltl-",   BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bltl+",   BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bltl",    BBOCB(16,BOT,CBLT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "blta-",   BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blta+",   BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blta",    BBOCB(16,BOT,CBLT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bltla-",  BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bltla+",  BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bltla",   BBOCB(16,BOT,CBLT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bgt-",    BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgt+",    BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgt",     BBOCB(16,BOT,CBGT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bgtl-",   BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgtl+",   BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgtl",    BBOCB(16,BOT,CBGT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bgta-",   BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgta+",   BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgta",    BBOCB(16,BOT,CBGT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bgtla-",  BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgtla+",  BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgtla",   BBOCB(16,BOT,CBGT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "beq-",    BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "beq+",    BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "beq",     BBOCB(16,BOT,CBEQ,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "beql-",   BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "beql+",   BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "beql",    BBOCB(16,BOT,CBEQ,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "beqa-",   BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "beqa+",   BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "beqa",    BBOCB(16,BOT,CBEQ,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "beqla-",  BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "beqla+",  BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "beqla",   BBOCB(16,BOT,CBEQ,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bso-",    BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bso+",    BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bso",     BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bsol-",   BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bsol+",   BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bsol",    BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bsoa-",   BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bsoa+",   BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bsoa",    BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bsola-",  BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bsola+",  BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bsola",   BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bun-",    BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bun+",    BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bun",     BBOCB(16,BOT,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bunl-",   BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bunl+",   BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bunl",    BBOCB(16,BOT,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BD } },
+{ "buna-",   BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "buna+",   BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "buna",    BBOCB(16,BOT,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bunla-",  BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bunla+",  BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bunla",   BBOCB(16,BOT,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bge-",    BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bge+",    BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bge",     BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bgel-",   BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bgel+",   BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bgel",    BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bgea-",   BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgea+",   BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgea",    BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bgela-",  BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bgela+",  BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bgela",   BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnl-",    BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnl+",    BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnl",     BBOCB(16,BOF,CBLT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnll-",   BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnll+",   BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnll",    BBOCB(16,BOF,CBLT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnla-",   BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnla+",   BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnla",    BBOCB(16,BOF,CBLT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnlla-",  BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnlla+",  BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnlla",   BBOCB(16,BOF,CBLT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "ble-",    BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "ble+",    BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "ble",     BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "blel-",   BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "blel+",   BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "blel",    BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "blea-",   BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blea+",   BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blea",    BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "blela-",  BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "blela+",  BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "blela",   BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bng-",    BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bng+",    BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bng",     BBOCB(16,BOF,CBGT,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bngl-",   BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bngl+",   BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bngl",    BBOCB(16,BOF,CBGT,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnga-",   BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnga+",   BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnga",    BBOCB(16,BOF,CBGT,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bngla-",  BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bngla+",  BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bngla",   BBOCB(16,BOF,CBGT,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bne-",    BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bne+",    BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bne",     BBOCB(16,BOF,CBEQ,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnel-",   BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnel+",   BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnel",    BBOCB(16,BOF,CBEQ,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnea-",   BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnea+",   BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnea",    BBOCB(16,BOF,CBEQ,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnela-",  BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnela+",  BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnela",   BBOCB(16,BOF,CBEQ,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bns-",    BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bns+",    BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bns",     BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnsl-",   BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnsl+",   BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnsl",    BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, COM,		{ CR, BD } },
+{ "bnsa-",   BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnsa+",   BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnsa",    BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnsla-",  BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnsla+",  BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnsla",   BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, COM,		{ CR, BDA } },
+{ "bnu-",    BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnu+",    BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnu",     BBOCB(16,BOF,CBSO,0,0), BBOATCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bnul-",   BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDM } },
+{ "bnul+",   BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BDP } },
+{ "bnul",    BBOCB(16,BOF,CBSO,0,1), BBOATCB_MASK, PPCCOM,	{ CR, BD } },
+{ "bnua-",   BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnua+",   BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnua",    BBOCB(16,BOF,CBSO,1,0), BBOATCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bnula-",  BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDMA } },
+{ "bnula+",  BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDPA } },
+{ "bnula",   BBOCB(16,BOF,CBSO,1,1), BBOATCB_MASK, PPCCOM,	{ CR, BDA } },
+{ "bdnzt-",  BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdnzt+",  BBO(16,BODNZT,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdnzt",   BBO(16,BODNZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdnztl",  BBO(16,BODNZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdnzta",  BBO(16,BODNZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnzf-",  BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdnzf+",  BBO(16,BODNZF,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdnzf",   BBO(16,BODNZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdnzfl",  BBO(16,BODNZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdnzfa",  BBO(16,BODNZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bt-",     BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM,	{ BI, BDM } },
+{ "bt+",     BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM,	{ BI, BDP } },
+{ "bt",	     BBO(16,BOT,0,0), BBOAT_MASK, PPCCOM,	{ BI, BD } },
+{ "bbt",     BBO(16,BOT,0,0), BBOAT_MASK, PWRCOM,	{ BI, BD } },
+{ "btl-",    BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM,	{ BI, BDM } },
+{ "btl+",    BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM,	{ BI, BDP } },
+{ "btl",     BBO(16,BOT,0,1), BBOAT_MASK, PPCCOM,	{ BI, BD } },
+{ "bbtl",    BBO(16,BOT,0,1), BBOAT_MASK, PWRCOM,	{ BI, BD } },
+{ "bta-",    BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bta+",    BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bta",     BBO(16,BOT,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbta",    BBO(16,BOT,1,0), BBOAT_MASK, PWRCOM,	{ BI, BDA } },
+{ "btla-",   BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDMA } },
+{ "btla+",   BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDPA } },
+{ "btla",    BBO(16,BOT,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbtla",   BBO(16,BOT,1,1), BBOAT_MASK, PWRCOM,	{ BI, BDA } },
+{ "bf-",     BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM,	{ BI, BDM } },
+{ "bf+",     BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM,	{ BI, BDP } },
+{ "bf",	     BBO(16,BOF,0,0), BBOAT_MASK, PPCCOM,	{ BI, BD } },
+{ "bbf",     BBO(16,BOF,0,0), BBOAT_MASK, PWRCOM,	{ BI, BD } },
+{ "bfl-",    BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM,	{ BI, BDM } },
+{ "bfl+",    BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM,	{ BI, BDP } },
+{ "bfl",     BBO(16,BOF,0,1), BBOAT_MASK, PPCCOM,	{ BI, BD } },
+{ "bbfl",    BBO(16,BOF,0,1), BBOAT_MASK, PWRCOM,	{ BI, BD } },
+{ "bfa-",    BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bfa+",    BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bfa",     BBO(16,BOF,1,0), BBOAT_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbfa",    BBO(16,BOF,1,0), BBOAT_MASK, PWRCOM,	{ BI, BDA } },
+{ "bfla-",   BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDMA } },
+{ "bfla+",   BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDPA } },
+{ "bfla",    BBO(16,BOF,1,1), BBOAT_MASK, PPCCOM,	{ BI, BDA } },
+{ "bbfla",   BBO(16,BOF,1,1), BBOAT_MASK, PWRCOM,	{ BI, BDA } },
+{ "bdzt-",   BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdzt+",   BBO(16,BODZT,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdzt",    BBO(16,BODZT,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdztl-",  BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdztl+",  BBO(16,BODZT,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdztl",   BBO(16,BODZT,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzta-",  BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdzta+",  BBO(16,BODZT,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdzta",   BBO(16,BODZT,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdztla",  BBO(16,BODZT,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdzf-",   BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdzf+",   BBO(16,BODZF,0,0), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdzf",    BBO(16,BODZF,0,0), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzfl-",  BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDM } },
+{ "bdzfl+",  BBO(16,BODZF,0,1), BBOY_MASK, NOPOWER4,	{ BI, BDP } },
+{ "bdzfl",   BBO(16,BODZF,0,1), BBOY_MASK, PPCCOM,	{ BI, BD } },
+{ "bdzfa-",  BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdzfa+",  BBO(16,BODZF,1,0), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdzfa",   BBO(16,BODZF,1,0), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDMA } },
+{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, NOPOWER4,	{ BI, BDPA } },
+{ "bdzfla",  BBO(16,BODZF,1,1), BBOY_MASK, PPCCOM,	{ BI, BDA } },
+{ "bc-",     B(16,0,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDM } },
+{ "bc+",     B(16,0,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDP } },
+{ "bc",	     B(16,0,0),	B_MASK,		COM,		{ BO, BI, BD } },
+{ "bcl-",    B(16,0,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDM } },
+{ "bcl+",    B(16,0,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDP } },
+{ "bcl",     B(16,0,1),	B_MASK,		COM,		{ BO, BI, BD } },
+{ "bca-",    B(16,1,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDMA } },
+{ "bca+",    B(16,1,0),	B_MASK,		PPCCOM,		{ BOE, BI, BDPA } },
+{ "bca",     B(16,1,0),	B_MASK,		COM,		{ BO, BI, BDA } },
+{ "bcla-",   B(16,1,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDMA } },
+{ "bcla+",   B(16,1,1),	B_MASK,		PPCCOM,		{ BOE, BI, BDPA } },
+{ "bcla",    B(16,1,1),	B_MASK,		COM,		{ BO, BI, BDA } },
 
-{ "sc",      SC(17,1,0), 0xffffffff,	PPC,		{ 0 } },
-{ "svc",     SC(17,0,0), SC_MASK,	POWER,		{ LEV, FL1, FL2 } },
-{ "svcl",    SC(17,0,1), SC_MASK,	POWER,		{ LEV, FL1, FL2 } },
-{ "svca",    SC(17,1,0), SC_MASK,	POWER,		{ SV } },
+{ "sc",      SC(17,1,0), SC_MASK,	PPC,		{ LEV } },
+{ "svc",     SC(17,0,0), SC_MASK,	POWER,		{ SVC_LEV, FL1, FL2 } },
+{ "svcl",    SC(17,0,1), SC_MASK,	POWER,		{ SVC_LEV, FL1, FL2 } },
+{ "svca",    SC(17,1,0), SC_MASK,	PWRCOM,		{ SV } },
 { "svcla",   SC(17,1,1), SC_MASK,	POWER,		{ SV } },
 
-{ "b",	     B(18,0,0),	B_MASK,		PPC|POWER,	{ LI } },
-{ "bl",      B(18,0,1),	B_MASK,		PPC|POWER,	{ LI } },
-{ "ba",      B(18,1,0),	B_MASK,		PPC|POWER,	{ LIA } },
-{ "bla",     B(18,1,1),	B_MASK,		PPC|POWER,	{ LIA } },
+{ "b",	     B(18,0,0),	B_MASK,		COM,		{ LI } },
+{ "bl",      B(18,0,1),	B_MASK,		COM,		{ LI } },
+{ "ba",      B(18,1,0),	B_MASK,		COM,		{ LIA } },
+{ "bla",     B(18,1,1),	B_MASK,		COM,		{ LIA } },
 
-{ "mcrf",    XL(19,0),	XLBB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } },
+{ "mcrf",    XL(19,0),	XLBB_MASK|(3 << 21)|(3 << 16), COM,	{ BF, BFA } },
 
-{ "blr",     XLO(19,BOU,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "br",      XLO(19,BOU,16,0), XLBOBIBB_MASK, POWER,	{ 0 } },
-{ "blrl",    XLO(19,BOU,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "brl",     XLO(19,BOU,16,1), XLBOBIBB_MASK, POWER,	{ 0 } },
-{ "bdnzlr",  XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdzlr",   XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdzlr-",  XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdzlr+",  XLO(19,BODZP,16,0), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdzlrl",  XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, PPC,	{ 0 } },
-{ "bltlr",   XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltlr-",  XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltlr+",  XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltr",    XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "bltlrl",  XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltrl",   XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "bgtlr",   XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtlr-",  XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtlr+",  XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtr",    XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "bgtlrl",  XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtrl",   XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "beqlr",   XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqlr-",  XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqlr+",  XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqr",    XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "beqlrl",  XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqrl",   XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "bsolr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsolr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsolr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsor",    XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "bsolrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsorl",   XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "bunlr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunlr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunlr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunlrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgelr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgelr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgelr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bger",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "bgelrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgerl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnllr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnllr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnllr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnlr",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnllrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnlrl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "blelr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "blelr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "blelr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bler",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "blelrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "blerl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnglr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnglr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnglr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bngr",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnglrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bngrl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnelr",   XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnelr-",  XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnelr+",  XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bner",    XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnelrl",  XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnerl",   XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnslr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnslr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnslr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnsr",    XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnslrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnsrl",   XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } },
-{ "bnulr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnulr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnulr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnulrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "btlr",    XLO(19,BOT,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "btlr-",   XLO(19,BOT,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "btlr+",   XLO(19,BOTP,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bbtr",    XLO(19,BOT,16,0), XLBOBB_MASK, POWER,	{ BI } },
-{ "btlrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "btlrl-",  XLO(19,BOT,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "btlrl+",  XLO(19,BOTP,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bbtrl",   XLO(19,BOT,16,1), XLBOBB_MASK, POWER,	{ BI } },
-{ "bflr",    XLO(19,BOF,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bflr-",   XLO(19,BOF,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bflr+",   XLO(19,BOFP,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bbfr",    XLO(19,BOF,16,0), XLBOBB_MASK, POWER,	{ BI } },
-{ "bflrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bflrl-",  XLO(19,BOF,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bflrl+",  XLO(19,BOFP,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bbfrl",   XLO(19,BOF,16,1), XLBOBB_MASK, POWER,	{ BI } },
-{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdztlr",  XLO(19,BODZT,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdzflr",  XLO(19,BODZF,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bclr",    XLLK(19,16,0), XLYBB_MASK,	PPC,		{ BO, BI } },
-{ "bclrl",   XLLK(19,16,1), XLYBB_MASK,	PPC,		{ BO, BI } },
-{ "bclr+",   XLYLK(19,16,1,0), XLYBB_MASK, PPC,		{ BOE, BI } },
-{ "bclrl+",  XLYLK(19,16,1,1), XLYBB_MASK, PPC,		{ BOE, BI } },
-{ "bclr-",   XLYLK(19,16,0,0), XLYBB_MASK, PPC,		{ BOE, BI } },
-{ "bclrl-",  XLYLK(19,16,0,1), XLYBB_MASK, PPC,		{ BOE, BI } },
-{ "bcr",     XLLK(19,16,0), XLBB_MASK,	POWER,		{ BO, BI } },
-{ "bcrl",    XLLK(19,16,1), XLBB_MASK,	POWER,		{ BO, BI } },
+{ "blr",     XLO(19,BOU,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "br",      XLO(19,BOU,16,0), XLBOBIBB_MASK, PWRCOM,	{ 0 } },
+{ "blrl",    XLO(19,BOU,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "brl",     XLO(19,BOU,16,1), XLBOBIBB_MASK, PWRCOM,	{ 0 } },
+{ "bdnzlr",  XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdnzlr-", XLO(19,BODNZM4,16,0), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdnzlr+", XLO(19,BODNZP4,16,0), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdnzlrl-",XLO(19,BODNZM4,16,1), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdnzlrl+",XLO(19,BODNZP4,16,1), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdzlr",   XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlr-",  XLO(19,BODZ,16,0), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdzlr-",  XLO(19,BODZM4,16,0), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdzlr+",  XLO(19,BODZP,16,0), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdzlr+",  XLO(19,BODZP4,16,0), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdzlrl",  XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPCCOM,	{ 0 } },
+{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdzlrl-", XLO(19,BODZM4,16,1), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, NOPOWER4,	{ 0 } },
+{ "bdzlrl+", XLO(19,BODZP4,16,1), XLBOBIBB_MASK, POWER4,	{ 0 } },
+{ "bltlr",   XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltlr-",  XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltlr-",  XLOCB(19,BOTM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltlr+",  XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltlr+",  XLOCB(19,BOTP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltr",    XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bltlrl",  XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltlrl-", XLOCB(19,BOTM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltlrl+", XLOCB(19,BOTP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltrl",   XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgtlr",   XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtlr-",  XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtlr-",  XLOCB(19,BOTM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtlr+",  XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtlr+",  XLOCB(19,BOTP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtr",    XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgtlrl",  XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtlrl-", XLOCB(19,BOTM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtlrl+", XLOCB(19,BOTP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtrl",   XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "beqlr",   XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqlr-",  XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqlr-",  XLOCB(19,BOTM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqlr+",  XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqlr+",  XLOCB(19,BOTP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqr",    XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "beqlrl",  XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqlrl-", XLOCB(19,BOTM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqlrl+", XLOCB(19,BOTP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqrl",   XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bsolr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsolr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsolr-",  XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsolr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsolr+",  XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsor",    XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bsolrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsolrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsolrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsorl",   XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bunlr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunlr-",  XLOCB(19,BOTM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunlr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunlr+",  XLOCB(19,BOTP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunlrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunlrl-", XLOCB(19,BOTM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunlrl+", XLOCB(19,BOTP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgelr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgelr-",  XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgelr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgelr+",  XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bger",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bgelrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgelrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgelrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgerl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnllr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnllr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnllr-",  XLOCB(19,BOFM4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnllr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnllr+",  XLOCB(19,BOFP4,CBLT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlr",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnllrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnllrl-", XLOCB(19,BOFM4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnllrl+", XLOCB(19,BOFP4,CBLT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlrl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "blelr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blelr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blelr-",  XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blelr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blelr+",  XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bler",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "blelrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blelrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blelrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blerl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnglr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnglr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnglr-",  XLOCB(19,BOFM4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnglr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnglr+",  XLOCB(19,BOFP4,CBGT,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngr",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnglrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnglrl-", XLOCB(19,BOFM4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnglrl+", XLOCB(19,BOFP4,CBGT,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngrl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnelr",   XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnelr-",  XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnelr-",  XLOCB(19,BOFM4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnelr+",  XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnelr+",  XLOCB(19,BOFP4,CBEQ,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bner",    XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnelrl",  XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnelrl-", XLOCB(19,BOFM4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnelrl+", XLOCB(19,BOFP4,CBEQ,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnerl",   XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnslr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnslr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnslr-",  XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnslr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnslr+",  XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsr",    XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnslrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnslrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnslrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsrl",   XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PWRCOM, { CR } },
+{ "bnulr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnulr-",  XLOCB(19,BOFM4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnulr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnulr+",  XLOCB(19,BOFP4,CBSO,16,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnulrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPCCOM, { CR } },
+{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnulrl-", XLOCB(19,BOFM4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnulrl+", XLOCB(19,BOFP4,CBSO,16,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "btlr",    XLO(19,BOT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btlr-",   XLO(19,BOT,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btlr-",   XLO(19,BOTM4,16,0), XLBOBB_MASK, POWER4,	{ BI } },
+{ "btlr+",   XLO(19,BOTP,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btlr+",   XLO(19,BOTP4,16,0), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bbtr",    XLO(19,BOT,16,0), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "btlrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btlrl-",  XLO(19,BOT,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btlrl-",  XLO(19,BOTM4,16,1), XLBOBB_MASK, POWER4,	{ BI } },
+{ "btlrl+",  XLO(19,BOTP,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btlrl+",  XLO(19,BOTP4,16,1), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bbtrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bflr",    XLO(19,BOF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bflr-",   XLO(19,BOF,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bflr-",   XLO(19,BOFM4,16,0), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bflr+",   XLO(19,BOFP,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bflr+",   XLO(19,BOFP4,16,0), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bbfr",    XLO(19,BOF,16,0), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bflrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bflrl-",  XLO(19,BOF,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bflrl-",  XLO(19,BOFM4,16,1), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bflrl+",  XLO(19,BOFP,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bflrl+",  XLO(19,BOFP4,16,1), XLBOBB_MASK, POWER4,	{ BI } },
+{ "bbfrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PWRCOM,	{ BI } },
+{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdztlr",  XLO(19,BODZT,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdzflr",  XLO(19,BODZF,16,0), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bclr+",   XLYLK(19,16,1,0), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclrl+",  XLYLK(19,16,1,1), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclr-",   XLYLK(19,16,0,0), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclrl-",  XLYLK(19,16,0,1), XLYBB_MASK, PPCCOM,	{ BOE, BI } },
+{ "bclr",    XLLK(19,16,0), XLBH_MASK,	PPCCOM,		{ BO, BI, BH } },
+{ "bclrl",   XLLK(19,16,1), XLBH_MASK,	PPCCOM,		{ BO, BI, BH } },
+{ "bcr",     XLLK(19,16,0), XLBB_MASK,	PWRCOM,		{ BO, BI } },
+{ "bcrl",    XLLK(19,16,1), XLBB_MASK,	PWRCOM,		{ BO, BI } },
+{ "bclre",   XLLK(19,17,0), XLBB_MASK,	BOOKE64,	{ BO, BI } },
+{ "bclrel",  XLLK(19,17,1), XLBB_MASK,	BOOKE64,	{ BO, BI } },
 
-{ "crnot",   XL(19,33), XL_MASK,	PPC,		{ BT, BA, BBA } },
-{ "crnor",   XL(19,33),	XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+{ "rfid",    XL(19,18),	0xffffffff,	PPC64,		{ 0 } },
 
-{ "rfi",     XL(19,50),	0xffffffff,	PPC|POWER,	{ 0 } },
-{ "rfci",    XL(19,51),	0xffffffff,	PPC,		{ 0 } },
+{ "crnot",   XL(19,33), XL_MASK,	PPCCOM,		{ BT, BA, BBA } },
+{ "crnor",   XL(19,33),	XL_MASK,	COM,		{ BT, BA, BB } },
+{ "rfmci",    X(19,38), 0xffffffff,	PPCRFMCI,	{ 0 } },
+
+{ "rfi",     XL(19,50),	0xffffffff,	COM,		{ 0 } },
+{ "rfci",    XL(19,51),	0xffffffff,	PPC403 | BOOKE,	{ 0 } },
 
 { "rfsvc",   XL(19,82),	0xffffffff,	POWER,		{ 0 } },
 
-{ "crandc",  XL(19,129), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+{ "crandc",  XL(19,129), XL_MASK,	COM,		{ BT, BA, BB } },
 
-{ "isync",   XL(19,150), 0xffffffff,	PPC,		{ 0 } },
-{ "ics",     XL(19,150), 0xffffffff,	POWER,		{ 0 } },
+{ "isync",   XL(19,150), 0xffffffff,	PPCCOM,		{ 0 } },
+{ "ics",     XL(19,150), 0xffffffff,	PWRCOM,		{ 0 } },
 
-{ "crclr",   XL(19,193), XL_MASK,	PPC,		{ BT, BAT, BBA } },
-{ "crxor",   XL(19,193), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+{ "crclr",   XL(19,193), XL_MASK,	PPCCOM,		{ BT, BAT, BBA } },
+{ "crxor",   XL(19,193), XL_MASK,	COM,		{ BT, BA, BB } },
 
-{ "crnand",  XL(19,225), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+{ "crnand",  XL(19,225), XL_MASK,	COM,		{ BT, BA, BB } },
 
-{ "crand",   XL(19,257), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+{ "crand",   XL(19,257), XL_MASK,	COM,		{ BT, BA, BB } },
 
-{ "crset",   XL(19,289), XL_MASK,	PPC,		{ BT, BAT, BBA } },
-{ "creqv",   XL(19,289), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+{ "hrfid",   XL(19,274), 0xffffffff,	POWER5 | CELL,	{ 0 } },
 
-{ "crorc",   XL(19,417), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+{ "crset",   XL(19,289), XL_MASK,	PPCCOM,		{ BT, BAT, BBA } },
+{ "creqv",   XL(19,289), XL_MASK,	COM,		{ BT, BA, BB } },
 
-{ "crmove",  XL(19,449), XL_MASK,	PPC,		{ BT, BA, BBA } },
-{ "cror",    XL(19,449), XL_MASK,	PPC|POWER,	{ BT, BA, BB } },
+{ "doze",    XL(19,402), 0xffffffff,	POWER6,		{ 0 } },
 
-{ "bctr",    XLO(19,BOU,528,0), XLBOBIBB_MASK, PPC|POWER, { 0 } },
-{ "bctrl",   XLO(19,BOU,528,1), XLBOBIBB_MASK, PPC|POWER, { 0 } },
-{ "bltctr",  XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtctr",  XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqctr",  XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsoctr",  XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunctr",  XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgectr",  XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnlctr",  XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "blectr",  XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bngctr",  XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnectr",  XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnsctr",  XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnuctr",  XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
-{ "btctr",   XLO(19,BOT,528,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "btctr-",  XLO(19,BOT,528,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "btctr+",  XLO(19,BOTP,528,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "btctrl",  XLO(19,BOT,528,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bfctr",   XLO(19,BOF,528,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bfctr-",  XLO(19,BOF,528,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bfctr+",  XLO(19,BOFP,528,0), XLBOBB_MASK, PPC,	{ BI } },
-{ "bfctrl",  XLO(19,BOF,528,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, PPC,	{ BI } },
-{ "bcctr",   XLLK(19,528,0), XLYBB_MASK, PPC,		{ BO, BI } },
-{ "bcctr-",  XLYLK(19,528,0,0), XLYBB_MASK, PPC,	{ BOE, BI } },
-{ "bcctr+",  XLYLK(19,528,1,0), XLYBB_MASK, PPC,	{ BOE, BI } },
-{ "bcctrl",  XLLK(19,528,1), XLYBB_MASK, PPC,		{ BO, BI } },
-{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPC,	{ BOE, BI } },
-{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPC,	{ BOE, BI } },
-{ "bcc",     XLLK(19,528,0), XLBB_MASK,	POWER,		{ BO, BI } },
-{ "bccl",    XLLK(19,528,1), XLBB_MASK,	POWER,		{ BO, BI } },
+{ "crorc",   XL(19,417), XL_MASK,	COM,		{ BT, BA, BB } },
 
-{ "rlwimi",  M(20,0),	M_MASK,		PPC,		{ RA,RS,SH,MBE,ME } },
-{ "rlimi",   M(20,0),	M_MASK,		POWER,		{ RA,RS,SH,MBE,ME } },
+{ "nap",     XL(19,434), 0xffffffff,	POWER6,		{ 0 } },
 
-{ "rlwimi.", M(20,1),	M_MASK,		PPC,		{ RA,RS,SH,MBE,ME } },
-{ "rlimi.",  M(20,1),	M_MASK,		POWER,		{ RA,RS,SH,MBE,ME } },
+{ "crmove",  XL(19,449), XL_MASK,	PPCCOM,		{ BT, BA, BBA } },
+{ "cror",    XL(19,449), XL_MASK,	COM,		{ BT, BA, BB } },
 
-{ "rotlwi",  MME(21,31,0), MMBME_MASK,	PPC,		{ RA, RS, SH } },
-{ "clrlwi",  MME(21,31,0), MSHME_MASK,	PPC,		{ RA, RS, MB } },
-{ "rlwinm",  M(21,0),	M_MASK,		PPC,		{ RA,RS,SH,MBE,ME } },
-{ "rlinm",   M(21,0),	M_MASK,		POWER,		{ RA,RS,SH,MBE,ME } },
-{ "rotlwi.", MME(21,31,1), MMBME_MASK,	PPC,		{ RA,RS,SH } },
-{ "clrlwi.", MME(21,31,1), MSHME_MASK,	PPC,		{ RA, RS, MB } },
-{ "rlwinm.", M(21,1),	M_MASK,		PPC,		{ RA,RS,SH,MBE,ME } },
-{ "rlinm.",  M(21,1),	M_MASK,		POWER,		{ RA,RS,SH,MBE,ME } },
+{ "sleep",   XL(19,466), 0xffffffff,	POWER6,		{ 0 } },
+{ "rvwinkle", XL(19,498), 0xffffffff,	POWER6,		{ 0 } },
 
-{ "rlmi",    M(22,0),	M_MASK,		POWER|M601,	{ RA,RS,RB,MBE,ME } },
-{ "rlmi.",   M(22,1),	M_MASK,		POWER|M601,	{ RA,RS,RB,MBE,ME } },
+{ "bctr",    XLO(19,BOU,528,0), XLBOBIBB_MASK, COM,	{ 0 } },
+{ "bctrl",   XLO(19,BOU,528,1), XLBOBIBB_MASK, COM,	{ 0 } },
+{ "bltctr",  XLOCB(19,BOT,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctr-", XLOCB(19,BOT,CBLT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltctr-", XLOCB(19,BOTM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltctr+", XLOCB(19,BOTP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltctrl", XLOCB(19,BOT,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltctrl-",XLOCB(19,BOTM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bltctrl+",XLOCB(19,BOTP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtctr",  XLOCB(19,BOT,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtctr-", XLOCB(19,BOTM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtctr+", XLOCB(19,BOTP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtctrl-",XLOCB(19,BOTM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgtctrl+",XLOCB(19,BOTP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqctr",  XLOCB(19,BOT,CBEQ,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqctr-", XLOCB(19,BOTM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqctr+", XLOCB(19,BOTP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqctrl-",XLOCB(19,BOTM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "beqctrl+",XLOCB(19,BOTP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsoctr",  XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsoctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsoctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsoctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bsoctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunctr",  XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctr-", XLOCB(19,BOT,CBSO,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunctr-", XLOCB(19,BOTM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunctr+", XLOCB(19,BOTP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunctrl", XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunctrl-",XLOCB(19,BOTM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bunctrl+",XLOCB(19,BOTP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgectr",  XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectr-", XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgectr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgectr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgectrl", XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgectrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bgectrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlctr",  XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnlctr-", XLOCB(19,BOFM4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnlctr+", XLOCB(19,BOFP4,CBLT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnlctrl-",XLOCB(19,BOFM4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnlctrl+",XLOCB(19,BOFP4,CBLT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blectr",  XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectr-", XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blectr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blectr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blectrl", XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "blectrl-",XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blectrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "blectrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngctr",  XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctr-", XLOCB(19,BOF,CBGT,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bngctr-", XLOCB(19,BOFM4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bngctr+", XLOCB(19,BOFP4,CBGT,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngctrl", XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bngctrl-",XLOCB(19,BOFM4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bngctrl+",XLOCB(19,BOFP4,CBGT,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnectr",  XLOCB(19,BOF,CBEQ,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnectr-", XLOCB(19,BOFM4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnectr+", XLOCB(19,BOFP4,CBEQ,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnectrl-",XLOCB(19,BOFM4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnectrl+",XLOCB(19,BOFP4,CBEQ,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsctr",  XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnsctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnsctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnsctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnsctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnuctr",  XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnuctr-", XLOCB(19,BOFM4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnuctr+", XLOCB(19,BOFP4,CBSO,528,0), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, PPCCOM,	{ CR } },
+{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1),  XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnuctrl-",XLOCB(19,BOFM4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, NOPOWER4, { CR } },
+{ "bnuctrl+",XLOCB(19,BOFP4,CBSO,528,1), XLBOCBBB_MASK, POWER4, { CR } },
+{ "btctr",   XLO(19,BOT,528,0),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctr-",  XLO(19,BOT,528,0),  XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btctr-",  XLO(19,BOTM4,528,0), XLBOBB_MASK, POWER4, { BI } },
+{ "btctr+",  XLO(19,BOTP,528,0), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btctr+",  XLO(19,BOTP4,528,0), XLBOBB_MASK, POWER4, { BI } },
+{ "btctrl",  XLO(19,BOT,528,1),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "btctrl-", XLO(19,BOT,528,1),  XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btctrl-", XLO(19,BOTM4,528,1), XLBOBB_MASK, POWER4, { BI } },
+{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, NOPOWER4,	{ BI } },
+{ "btctrl+", XLO(19,BOTP4,528,1), XLBOBB_MASK, POWER4, { BI } },
+{ "bfctr",   XLO(19,BOF,528,0),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctr-",  XLO(19,BOF,528,0),  XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bfctr-",  XLO(19,BOFM4,528,0), XLBOBB_MASK, POWER4, { BI } },
+{ "bfctr+",  XLO(19,BOFP,528,0), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bfctr+",  XLO(19,BOFP4,528,0), XLBOBB_MASK, POWER4, { BI } },
+{ "bfctrl",  XLO(19,BOF,528,1),  XLBOBB_MASK, PPCCOM,	{ BI } },
+{ "bfctrl-", XLO(19,BOF,528,1),  XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bfctrl-", XLO(19,BOFM4,528,1), XLBOBB_MASK, POWER4, { BI } },
+{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, NOPOWER4, { BI } },
+{ "bfctrl+", XLO(19,BOFP4,528,1), XLBOBB_MASK, POWER4, { BI } },
+{ "bcctr-",  XLYLK(19,528,0,0),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctr+",  XLYLK(19,528,1,0),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctrl-", XLYLK(19,528,0,1),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctrl+", XLYLK(19,528,1,1),  XLYBB_MASK,  PPCCOM,	{ BOE, BI } },
+{ "bcctr",   XLLK(19,528,0),     XLBH_MASK,   PPCCOM,	{ BO, BI, BH } },
+{ "bcctrl",  XLLK(19,528,1),     XLBH_MASK,   PPCCOM,	{ BO, BI, BH } },
+{ "bcc",     XLLK(19,528,0),     XLBB_MASK,   PWRCOM,	{ BO, BI } },
+{ "bccl",    XLLK(19,528,1),     XLBB_MASK,   PWRCOM,	{ BO, BI } },
+{ "bcctre",  XLLK(19,529,0),     XLBB_MASK,   BOOKE64,	{ BO, BI } },
+{ "bcctrel", XLLK(19,529,1),     XLBB_MASK,   BOOKE64,	{ BO, BI } },
 
-{ "rotlw",   MME(23,31,0), MMBME_MASK,	PPC,		{ RA, RS, RB } },
-{ "rlwnm",   M(23,0),	M_MASK,		PPC,		{ RA,RS,RB,MBE,ME } },
-{ "rlnm",    M(23,0),	M_MASK,		POWER,		{ RA,RS,RB,MBE,ME } },
-{ "rotlw.",  MME(23,31,1), MMBME_MASK,	PPC,		{ RA, RS, RB } },
-{ "rlwnm.",  M(23,1),	M_MASK,		PPC,		{ RA,RS,RB,MBE,ME } },
-{ "rlnm.",   M(23,1),	M_MASK,		POWER,		{ RA,RS,RB,MBE,ME } },
+{ "rlwimi",  M(20,0),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlimi",   M(20,0),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
 
-{ "nop",     OP(24),	0xffffffff,	PPC,		{ 0 } },
-{ "ori",     OP(24),	OP_MASK,	PPC,		{ RA, RS, UI } },
-{ "oril",    OP(24),	OP_MASK,	POWER,		{ RA, RS, UI } },
+{ "rlwimi.", M(20,1),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlimi.",  M(20,1),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
 
-{ "oris",    OP(25),	OP_MASK,	PPC,		{ RA, RS, UI } },
-{ "oriu",    OP(25),	OP_MASK,	POWER,		{ RA, RS, UI } },
+{ "rotlwi",  MME(21,31,0), MMBME_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "clrlwi",  MME(21,31,0), MSHME_MASK,	PPCCOM,		{ RA, RS, MB } },
+{ "rlwinm",  M(21,0),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlinm",   M(21,0),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rotlwi.", MME(21,31,1), MMBME_MASK,	PPCCOM,		{ RA,RS,SH } },
+{ "clrlwi.", MME(21,31,1), MSHME_MASK,	PPCCOM,		{ RA, RS, MB } },
+{ "rlwinm.", M(21,1),	M_MASK,		PPCCOM,		{ RA,RS,SH,MBE,ME } },
+{ "rlinm.",  M(21,1),	M_MASK,		PWRCOM,		{ RA,RS,SH,MBE,ME } },
 
-{ "xori",    OP(26),	OP_MASK,	PPC,		{ RA, RS, UI } },
-{ "xoril",   OP(26),	OP_MASK,	POWER,		{ RA, RS, UI } },
+{ "rlmi",    M(22,0),	M_MASK,		M601,		{ RA,RS,RB,MBE,ME } },
+{ "rlmi.",   M(22,1),	M_MASK,		M601,		{ RA,RS,RB,MBE,ME } },
 
-{ "xoris",   OP(27),	OP_MASK,	PPC,		{ RA, RS, UI } },
-{ "xoriu",   OP(27),	OP_MASK,	POWER,		{ RA, RS, UI } },
+{ "be",	     B(22,0,0),	B_MASK,		BOOKE64,	{ LI } },
+{ "bel",     B(22,0,1),	B_MASK,		BOOKE64,	{ LI } },
+{ "bea",     B(22,1,0),	B_MASK,		BOOKE64,	{ LIA } },
+{ "bela",    B(22,1,1),	B_MASK,		BOOKE64,	{ LIA } },
 
-{ "andi.",   OP(28),	OP_MASK,	PPC,		{ RA, RS, UI } },
-{ "andil.",  OP(28),	OP_MASK,	POWER,		{ RA, RS, UI } },
+{ "rotlw",   MME(23,31,0), MMBME_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "rlwnm",   M(23,0),	M_MASK,		PPCCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rlnm",    M(23,0),	M_MASK,		PWRCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rotlw.",  MME(23,31,1), MMBME_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "rlwnm.",  M(23,1),	M_MASK,		PPCCOM,		{ RA,RS,RB,MBE,ME } },
+{ "rlnm.",   M(23,1),	M_MASK,		PWRCOM,		{ RA,RS,RB,MBE,ME } },
 
-{ "andis.",  OP(29),	OP_MASK,	PPC,		{ RA, RS, UI } },
-{ "andiu.",  OP(29),	OP_MASK,	POWER,		{ RA, RS, UI } },
+{ "nop",     OP(24),	0xffffffff,	PPCCOM,		{ 0 } },
+{ "ori",     OP(24),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "oril",    OP(24),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
 
-{ "rotldi",  MD(30,0,0), MDMB_MASK,	PPC|B64,	{ RA, RS, SH6 } },
-{ "clrldi",  MD(30,0,0), MDSH_MASK,	PPC|B64,	{ RA, RS, MB6 } },
-{ "rldicl",  MD(30,0,0), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
-{ "rotldi.", MD(30,0,1), MDMB_MASK,	PPC|B64,	{ RA, RS, SH6 } },
-{ "clrldi.", MD(30,0,1), MDSH_MASK,	PPC|B64,	{ RA, RS, MB6 } },
-{ "rldicl.", MD(30,0,1), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+{ "oris",    OP(25),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "oriu",    OP(25),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
 
-{ "rldicr",  MD(30,1,0), MD_MASK,	PPC|B64,	{ RA, RS, SH6, ME6 } },
-{ "rldicr.", MD(30,1,1), MD_MASK,	PPC|B64,	{ RA, RS, SH6, ME6 } },
+{ "xori",    OP(26),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "xoril",   OP(26),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
 
-{ "rldic",   MD(30,2,0), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
-{ "rldic.",  MD(30,2,1), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+{ "xoris",   OP(27),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "xoriu",   OP(27),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
 
-{ "rldimi",  MD(30,3,0), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
-{ "rldimi.", MD(30,3,1), MD_MASK,	PPC|B64,	{ RA, RS, SH6, MB6 } },
+{ "andi.",   OP(28),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "andil.",  OP(28),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
 
-{ "rotld",   MDS(30,8,0), MDSMB_MASK,	PPC|B64,	{ RA, RS, RB } },
-{ "rldcl",   MDS(30,8,0), MDS_MASK,	PPC|B64,	{ RA, RS, RB, MB6 } },
-{ "rotld.",  MDS(30,8,1), MDSMB_MASK,	PPC|B64,	{ RA, RS, RB } },
-{ "rldcl.",  MDS(30,8,1), MDS_MASK,	PPC|B64,	{ RA, RS, RB, MB6 } },
+{ "andis.",  OP(29),	OP_MASK,	PPCCOM,		{ RA, RS, UI } },
+{ "andiu.",  OP(29),	OP_MASK,	PWRCOM,		{ RA, RS, UI } },
 
-{ "rldcr",   MDS(30,9,0), MDS_MASK,	PPC|B64,	{ RA, RS, RB, ME6 } },
-{ "rldcr.",  MDS(30,9,1), MDS_MASK,	PPC|B64,	{ RA, RS, RB, ME6 } },
+{ "rotldi",  MD(30,0,0), MDMB_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "clrldi",  MD(30,0,0), MDSH_MASK,	PPC64,		{ RA, RS, MB6 } },
+{ "rldicl",  MD(30,0,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rotldi.", MD(30,0,1), MDMB_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "clrldi.", MD(30,0,1), MDSH_MASK,	PPC64,		{ RA, RS, MB6 } },
+{ "rldicl.", MD(30,0,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
 
-{ "cmpw",    XCMPL(31,0,0), XCMPL_MASK, PPC,		{ OBF, RA, RB } },
-{ "cmpd",    XCMPL(31,0,1), XCMPL_MASK, PPC|B64,	{ OBF, RA, RB } },
+{ "rldicr",  MD(30,1,0), MD_MASK,	PPC64,		{ RA, RS, SH6, ME6 } },
+{ "rldicr.", MD(30,1,1), MD_MASK,	PPC64,		{ RA, RS, SH6, ME6 } },
+
+{ "rldic",   MD(30,2,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rldic.",  MD(30,2,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+
+{ "rldimi",  MD(30,3,0), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+{ "rldimi.", MD(30,3,1), MD_MASK,	PPC64,		{ RA, RS, SH6, MB6 } },
+
+{ "rotld",   MDS(30,8,0), MDSMB_MASK,	PPC64,		{ RA, RS, RB } },
+{ "rldcl",   MDS(30,8,0), MDS_MASK,	PPC64,		{ RA, RS, RB, MB6 } },
+{ "rotld.",  MDS(30,8,1), MDSMB_MASK,	PPC64,		{ RA, RS, RB } },
+{ "rldcl.",  MDS(30,8,1), MDS_MASK,	PPC64,		{ RA, RS, RB, MB6 } },
+
+{ "rldcr",   MDS(30,9,0), MDS_MASK,	PPC64,		{ RA, RS, RB, ME6 } },
+{ "rldcr.",  MDS(30,9,1), MDS_MASK,	PPC64,		{ RA, RS, RB, ME6 } },
+
+{ "cmpw",    XOPL(31,0,0), XCMPL_MASK, PPCCOM,		{ OBF, RA, RB } },
+{ "cmpd",    XOPL(31,0,1), XCMPL_MASK, PPC64,		{ OBF, RA, RB } },
 { "cmp",     X(31,0),	XCMP_MASK,	PPC,		{ BF, L, RA, RB } },
-{ "cmp",     X(31,0),	XCMPL_MASK,	POWER,		{ BF, RA, RB } },
+{ "cmp",     X(31,0),	XCMPL_MASK,	PWRCOM,		{ BF, RA, RB } },
 
-{ "twlgt",   XTO(31,4,TOLGT), XTO_MASK, PPC,		{ RA, RB } },
-{ "tlgt",    XTO(31,4,TOLGT), XTO_MASK, POWER,		{ RA, RB } },
-{ "twllt",   XTO(31,4,TOLLT), XTO_MASK, PPC,		{ RA, RB } },
-{ "tllt",    XTO(31,4,TOLLT), XTO_MASK, POWER,		{ RA, RB } },
-{ "tweq",    XTO(31,4,TOEQ), XTO_MASK,	PPC,		{ RA, RB } },
-{ "teq",     XTO(31,4,TOEQ), XTO_MASK,	POWER,		{ RA, RB } },
-{ "twlge",   XTO(31,4,TOLGE), XTO_MASK, PPC,		{ RA, RB } },
-{ "tlge",    XTO(31,4,TOLGE), XTO_MASK, POWER,		{ RA, RB } },
-{ "twlnl",   XTO(31,4,TOLNL), XTO_MASK, PPC,		{ RA, RB } },
-{ "tlnl",    XTO(31,4,TOLNL), XTO_MASK, POWER,		{ RA, RB } },
-{ "twlle",   XTO(31,4,TOLLE), XTO_MASK, PPC,		{ RA, RB } },
-{ "tlle",    XTO(31,4,TOLLE), XTO_MASK, POWER,		{ RA, RB } },
-{ "twlng",   XTO(31,4,TOLNG), XTO_MASK, PPC,		{ RA, RB } },
-{ "tlng",    XTO(31,4,TOLNG), XTO_MASK, POWER,		{ RA, RB } },
-{ "twgt",    XTO(31,4,TOGT), XTO_MASK,	PPC,		{ RA, RB } },
-{ "tgt",     XTO(31,4,TOGT), XTO_MASK,	POWER,		{ RA, RB } },
-{ "twge",    XTO(31,4,TOGE), XTO_MASK,	PPC,		{ RA, RB } },
-{ "tge",     XTO(31,4,TOGE), XTO_MASK,	POWER,		{ RA, RB } },
-{ "twnl",    XTO(31,4,TONL), XTO_MASK,	PPC,		{ RA, RB } },
-{ "tnl",     XTO(31,4,TONL), XTO_MASK,	POWER,		{ RA, RB } },
-{ "twlt",    XTO(31,4,TOLT), XTO_MASK,	PPC,		{ RA, RB } },
-{ "tlt",     XTO(31,4,TOLT), XTO_MASK,	POWER,		{ RA, RB } },
-{ "twle",    XTO(31,4,TOLE), XTO_MASK,	PPC,		{ RA, RB } },
-{ "tle",     XTO(31,4,TOLE), XTO_MASK,	POWER,		{ RA, RB } },
-{ "twng",    XTO(31,4,TONG), XTO_MASK,	PPC,		{ RA, RB } },
-{ "tng",     XTO(31,4,TONG), XTO_MASK,	POWER,		{ RA, RB } },
-{ "twne",    XTO(31,4,TONE), XTO_MASK,	PPC,		{ RA, RB } },
-{ "tne",     XTO(31,4,TONE), XTO_MASK,	POWER,		{ RA, RB } },
-{ "trap",    XTO(31,4,TOU), 0xffffffff,	PPC,		{ 0 } },
-{ "tw",      X(31,4),	X_MASK,		PPC,		{ TO, RA, RB } },
-{ "t",       X(31,4),	X_MASK,		POWER,		{ TO, RA, RB } },
+{ "twlgt",   XTO(31,4,TOLGT), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlgt",    XTO(31,4,TOLGT), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twllt",   XTO(31,4,TOLLT), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tllt",    XTO(31,4,TOLLT), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "tweq",    XTO(31,4,TOEQ), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "teq",     XTO(31,4,TOEQ), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twlge",   XTO(31,4,TOLGE), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlge",    XTO(31,4,TOLGE), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlnl",   XTO(31,4,TOLNL), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlnl",    XTO(31,4,TOLNL), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlle",   XTO(31,4,TOLLE), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlle",    XTO(31,4,TOLLE), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twlng",   XTO(31,4,TOLNG), XTO_MASK, PPCCOM,		{ RA, RB } },
+{ "tlng",    XTO(31,4,TOLNG), XTO_MASK, PWRCOM,		{ RA, RB } },
+{ "twgt",    XTO(31,4,TOGT), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tgt",     XTO(31,4,TOGT), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twge",    XTO(31,4,TOGE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tge",     XTO(31,4,TOGE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twnl",    XTO(31,4,TONL), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tnl",     XTO(31,4,TONL), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twlt",    XTO(31,4,TOLT), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tlt",     XTO(31,4,TOLT), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twle",    XTO(31,4,TOLE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tle",     XTO(31,4,TOLE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twng",    XTO(31,4,TONG), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tng",     XTO(31,4,TONG), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "twne",    XTO(31,4,TONE), XTO_MASK,	PPCCOM,		{ RA, RB } },
+{ "tne",     XTO(31,4,TONE), XTO_MASK,	PWRCOM,		{ RA, RB } },
+{ "trap",    XTO(31,4,TOU), 0xffffffff,	PPCCOM,		{ 0 } },
+{ "tw",      X(31,4),	X_MASK,		PPCCOM,		{ TO, RA, RB } },
+{ "t",       X(31,4),	X_MASK,		PWRCOM,		{ TO, RA, RB } },
 
-{ "subfc",   XO(31,8,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "sf",      XO(31,8,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subfc",   XO(31,8,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sf",      XO(31,8,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
 { "subc",    XO(31,8,0,0), XO_MASK,	PPC,		{ RT, RB, RA } },
-{ "subfc.",  XO(31,8,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "sf.",     XO(31,8,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "subc.",   XO(31,8,0,1), XO_MASK,	PPC,		{ RT, RB, RA } },
-{ "subfco",  XO(31,8,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "sfo",     XO(31,8,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subfc.",  XO(31,8,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sf.",     XO(31,8,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subc.",   XO(31,8,0,1), XO_MASK,	PPCCOM,		{ RT, RB, RA } },
+{ "subfco",  XO(31,8,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfo",     XO(31,8,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
 { "subco",   XO(31,8,1,0), XO_MASK,	PPC,		{ RT, RB, RA } },
-{ "subfco.", XO(31,8,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "sfo.",    XO(31,8,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "subfco.", XO(31,8,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfo.",    XO(31,8,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
 { "subco.",  XO(31,8,1,1), XO_MASK,	PPC,		{ RT, RB, RA } },
 
-{ "mulhdu",  XO(31,9,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "mulhdu.", XO(31,9,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "mulhdu",  XO(31,9,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulhdu.", XO(31,9,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
 
-{ "addc",    XO(31,10,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "a",       XO(31,10,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "addc.",   XO(31,10,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "a.",      XO(31,10,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "addco",   XO(31,10,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "ao",      XO(31,10,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "addco.",  XO(31,10,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "ao.",     XO(31,10,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "addc",    XO(31,10,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "a",       XO(31,10,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addc.",   XO(31,10,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "a.",      XO(31,10,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addco",   XO(31,10,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ao",      XO(31,10,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addco.",  XO(31,10,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ao.",     XO(31,10,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
 
 { "mulhwu",  XO(31,11,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "mulhwu.", XO(31,11,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
 
-{ "mfcr",    X(31,19),	XRARB_MASK,	POWER|PPC,	{ RT } },
+{ "isellt",  X(31,15),      X_MASK,	PPCISEL,	{ RT, RA, RB } },
+{ "iselgt",  X(31,47),      X_MASK,	PPCISEL,	{ RT, RA, RB } },
+{ "iseleq",  X(31,79),      X_MASK,	PPCISEL,	{ RT, RA, RB } },
+{ "isel",    XISEL(31,15),  XISEL_MASK,	PPCISEL,	{ RT, RA, RB, CRB } },
 
-{ "lwarx",   X(31,20),	X_MASK,		PPC,		{ RT, RA, RB } },
+{ "mfocrf",  XFXM(31,19,0,1), XFXFXM_MASK, COM,		{ RT, FXM } },
+{ "mfcr",    X(31,19),	XRARB_MASK,	NOPOWER4 | COM,	{ RT } },
+{ "mfcr",    X(31,19),	XFXFXM_MASK,	POWER4,		{ RT, FXM4 } },
 
-{ "ldx",     X(31,21),	X_MASK,		PPC|B64,	{ RT, RA, RB } },
+{ "lwarx",   X(31,20),	XEH_MASK,	PPC,		{ RT, RA0, RB, EH } },
 
-{ "lwzx",    X(31,23),	X_MASK,		PPC,		{ RT, RA, RB } },
-{ "lx",      X(31,23),	X_MASK,		POWER,		{ RT, RA, RB } },
+{ "ldx",     X(31,21),	X_MASK,		PPC64,		{ RT, RA0, RB } },
 
-{ "slw",     XRC(31,24,0), X_MASK,	PPC,		{ RA, RS, RB } },
-{ "sl",      XRC(31,24,0), X_MASK,	POWER,		{ RA, RS, RB } },
-{ "slw.",    XRC(31,24,1), X_MASK,	PPC,		{ RA, RS, RB } },
-{ "sl.",     XRC(31,24,1), X_MASK,	POWER,		{ RA, RS, RB } },
+{ "icbt",    X(31,22),	X_MASK,		BOOKE|PPCE300,	{ CT, RA, RB } },
+{ "icbt",    X(31,262),	XRT_MASK,	PPC403,		{ RA, RB } },
 
-{ "cntlzw",  XRC(31,26,0), XRB_MASK,	PPC,		{ RA, RS } },
-{ "cntlz",   XRC(31,26,0), XRB_MASK,	POWER,		{ RA, RS } },
-{ "cntlzw.", XRC(31,26,1), XRB_MASK,	PPC,		{ RA, RS } },
-{ "cntlz.",  XRC(31,26,1), XRB_MASK, 	POWER,		{ RA, RS } },
+{ "lwzx",    X(31,23),	X_MASK,		PPCCOM,		{ RT, RA0, RB } },
+{ "lx",      X(31,23),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
 
-{ "sld",     XRC(31,27,0), X_MASK,	PPC|B64,	{ RA, RS, RB } },
-{ "sld.",    XRC(31,27,1), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+{ "slw",     XRC(31,24,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sl",      XRC(31,24,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "slw.",    XRC(31,24,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sl.",     XRC(31,24,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
 
-{ "and",     XRC(31,28,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
-{ "and.",    XRC(31,28,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "cntlzw",  XRC(31,26,0), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "cntlz",   XRC(31,26,0), XRB_MASK,	PWRCOM,		{ RA, RS } },
+{ "cntlzw.", XRC(31,26,1), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "cntlz.",  XRC(31,26,1), XRB_MASK, 	PWRCOM,		{ RA, RS } },
 
-{ "maskg",   XRC(31,29,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "maskg.",  XRC(31,29,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "sld",     XRC(31,27,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "sld.",    XRC(31,27,1), X_MASK,	PPC64,		{ RA, RS, RB } },
 
-{ "cmplw",   XCMPL(31,32,0), XCMPL_MASK, PPC,		{ OBF, RA, RB } },
-{ "cmpld",   XCMPL(31,32,1), XCMPL_MASK, PPC|B64,	{ OBF, RA, RB } },
-{ "cmpl",    X(31,32),	XCMP_MASK,	PPC,		{ BF, L, RA, RB } },
-{ "cmpl",    X(31,32),	XCMPL_MASK,	POWER,		{ BF, RA, RB } },
+{ "and",     XRC(31,28,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "and.",    XRC(31,28,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "maskg",   XRC(31,29,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "maskg.",  XRC(31,29,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "icbte",   X(31,30),	X_MASK,		BOOKE64,	{ CT, RA, RB } },
+
+{ "lwzxe",   X(31,31),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "cmplw",   XOPL(31,32,0), XCMPL_MASK, PPCCOM,	{ OBF, RA, RB } },
+{ "cmpld",   XOPL(31,32,1), XCMPL_MASK, PPC64,		{ OBF, RA, RB } },
+{ "cmpl",    X(31,32),	XCMP_MASK,	 PPC,		{ BF, L, RA, RB } },
+{ "cmpl",    X(31,32),	XCMPL_MASK,	 PWRCOM,	{ BF, RA, RB } },
 
 { "subf",    XO(31,40,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "sub",     XO(31,40,0,0), XO_MASK,	PPC,		{ RT, RB, RA } },
@@ -2316,561 +3510,1202 @@
 { "subfo.",  XO(31,40,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "subo.",   XO(31,40,1,1), XO_MASK,	PPC,		{ RT, RB, RA } },
 
-{ "ldux",    X(31,53),	X_MASK,		PPC|B64,	{ RT, RAL, RB } },
+{ "ldux",    X(31,53),	X_MASK,		PPC64,		{ RT, RAL, RB } },
 
 { "dcbst",   X(31,54),	XRT_MASK,	PPC,		{ RA, RB } },
 
-{ "lwzux",   X(31,55),	X_MASK,		PPC,		{ RT, RAL, RB } },
-{ "lux",     X(31,55),	X_MASK,		POWER,		{ RT, RA, RB } },
+{ "lwzux",   X(31,55),	X_MASK,		PPCCOM,		{ RT, RAL, RB } },
+{ "lux",     X(31,55),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
 
-{ "cntlzd",  XRC(31,58,0), XRB_MASK,	PPC|B64,	{ RA, RS } },
-{ "cntlzd.", XRC(31,58,1), XRB_MASK,	PPC|B64,	{ RA, RS } },
+{ "dcbste",  X(31,62),	XRT_MASK,	BOOKE64,	{ RA, RB } },
 
-{ "andc",    XRC(31,60,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
-{ "andc.",   XRC(31,60,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "lwzuxe",  X(31,63),	X_MASK,		BOOKE64,	{ RT, RAL, RB } },
 
-{ "tdlgt",   XTO(31,68,TOLGT), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdllt",   XTO(31,68,TOLLT), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdeq",    XTO(31,68,TOEQ), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdlge",   XTO(31,68,TOLGE), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdlnl",   XTO(31,68,TOLNL), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdlle",   XTO(31,68,TOLLE), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdlng",   XTO(31,68,TOLNG), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdgt",    XTO(31,68,TOGT), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdge",    XTO(31,68,TOGE), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdnl",    XTO(31,68,TONL), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdlt",    XTO(31,68,TOLT), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdle",    XTO(31,68,TOLE), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdng",    XTO(31,68,TONG), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "tdne",    XTO(31,68,TONE), XTO_MASK, PPC|B64,	{ RA, RB } },
-{ "td",	     X(31,68),	X_MASK,		PPC|B64,	{ TO, RA, RB } },
+{ "cntlzd",  XRC(31,58,0), XRB_MASK,	PPC64,		{ RA, RS } },
+{ "cntlzd.", XRC(31,58,1), XRB_MASK,	PPC64,		{ RA, RS } },
 
-{ "mulhd",   XO(31,73,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "mulhd.",  XO(31,73,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "andc",    XRC(31,60,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "andc.",   XRC(31,60,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "tdlgt",   XTO(31,68,TOLGT), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdllt",   XTO(31,68,TOLLT), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdeq",    XTO(31,68,TOEQ), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdlge",   XTO(31,68,TOLGE), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlnl",   XTO(31,68,TOLNL), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlle",   XTO(31,68,TOLLE), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdlng",   XTO(31,68,TOLNG), XTO_MASK, PPC64,		{ RA, RB } },
+{ "tdgt",    XTO(31,68,TOGT), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdge",    XTO(31,68,TOGE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdnl",    XTO(31,68,TONL), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdlt",    XTO(31,68,TOLT), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdle",    XTO(31,68,TOLE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdng",    XTO(31,68,TONG), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "tdne",    XTO(31,68,TONE), XTO_MASK,  PPC64,		{ RA, RB } },
+{ "td",	     X(31,68),	X_MASK,		 PPC64,		{ TO, RA, RB } },
+
+{ "mulhd",   XO(31,73,0,0), XO_MASK,	 PPC64,		{ RT, RA, RB } },
+{ "mulhd.",  XO(31,73,0,1), XO_MASK,	 PPC64,		{ RT, RA, RB } },
 
 { "mulhw",   XO(31,75,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "mulhw.",  XO(31,75,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
 
-{ "mfmsr",   X(31,83),	XRARB_MASK,	PPC|POWER,	{ RT } },
+{ "dlmzb",   XRC(31,78,0),  X_MASK,	PPC403|PPC440,	{ RA, RS, RB } },
+{ "dlmzb.",  XRC(31,78,1),  X_MASK,	PPC403|PPC440,	{ RA, RS, RB } },
 
-{ "ldarx",   X(31,84),	X_MASK,		PPC|B64,	{ RT, RA, RB } },
+{ "mtsrd",   X(31,82),	XRB_MASK|(1<<20), PPC64,	{ SR, RS } },
 
-{ "dcbf",    X(31,86),	XRT_MASK,	PPC,		{ RA, RB } },
+{ "mfmsr",   X(31,83),	XRARB_MASK,	COM,		{ RT } },
 
-{ "lbzx",    X(31,87),	X_MASK,		PPC|POWER,	{ RT, RA, RB } },
+{ "ldarx",   X(31,84),	XEH_MASK,	PPC64,		{ RT, RA0, RB, EH } },
 
-{ "neg",     XO(31,104,0,0), XORB_MASK,	PPC|POWER,	{ RT, RA } },
-{ "neg.",    XO(31,104,0,1), XORB_MASK,	PPC|POWER,	{ RT, RA } },
-{ "nego",    XO(31,104,1,0), XORB_MASK,	PPC|POWER,	{ RT, RA } },
-{ "nego.",   XO(31,104,1,1), XORB_MASK,	PPC|POWER,	{ RT, RA } },
+{ "dcbfl",   XOPL(31,86,1), XRT_MASK,	POWER5,		{ RA, RB } },
+{ "dcbf",    X(31,86),	XLRT_MASK,	PPC,		{ RA, RB, L } },
 
-{ "mul",     XO(31,107,0,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "mul.",    XO(31,107,0,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "mulo",    XO(31,107,1,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "mulo.",   XO(31,107,1,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "lbzx",    X(31,87),	X_MASK,		COM,		{ RT, RA0, RB } },
 
-{ "clf",     X(31,118), XRB_MASK,	POWER,		{ RT, RA } },
+{ "dcbfe",   X(31,94),	XRT_MASK,	BOOKE64,	{ RA, RB } },
 
-{ "lbzux",   X(31,119),	X_MASK,		PPC|POWER,	{ RT, RAL, RB } },
+{ "lbzxe",   X(31,95),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
 
-{ "not",     XRC(31,124,0), X_MASK,	PPC|POWER,	{ RA, RS, RBS } },
-{ "nor",     XRC(31,124,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
-{ "not.",    XRC(31,124,1), X_MASK,	PPC|POWER,	{ RA, RS, RBS } },
-{ "nor.",    XRC(31,124,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "neg",     XO(31,104,0,0), XORB_MASK,	COM,		{ RT, RA } },
+{ "neg.",    XO(31,104,0,1), XORB_MASK,	COM,		{ RT, RA } },
+{ "nego",    XO(31,104,1,0), XORB_MASK,	COM,		{ RT, RA } },
+{ "nego.",   XO(31,104,1,1), XORB_MASK,	COM,		{ RT, RA } },
 
-{ "subfe",   XO(31,136,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "sfe",     XO(31,136,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "subfe.",  XO(31,136,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "sfe.",    XO(31,136,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "subfeo",  XO(31,136,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "sfeo",    XO(31,136,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "subfeo.", XO(31,136,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "sfeo.",   XO(31,136,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "mul",     XO(31,107,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mul.",    XO(31,107,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mulo",    XO(31,107,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "mulo.",   XO(31,107,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
 
-{ "adde",    XO(31,138,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "ae",      XO(31,138,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "adde.",   XO(31,138,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "ae.",     XO(31,138,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "addeo",   XO(31,138,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "aeo",     XO(31,138,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "addeo.",  XO(31,138,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "aeo.",    XO(31,138,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "mtsrdin", X(31,114),	XRA_MASK,	PPC64,		{ RS, RB } },
 
-{ "mtcr",    XFXM(31,144,0xff), XFXFXM_MASK|FXM_MASK, PPC|POWER, { RS }},
-{ "mtcrf",   X(31,144),	XFXFXM_MASK,	PPC|POWER,	{ FXM, RS } },
+{ "clf",     X(31,118), XTO_MASK,	POWER,		{ RA, RB } },
 
-{ "mtmsr",   X(31,146),	XRARB_MASK,	PPC|POWER,	{ RS } },
+{ "lbzux",   X(31,119),	X_MASK,		COM,		{ RT, RAL, RB } },
 
-{ "stdx",    X(31,149), X_MASK,		PPC|B64,	{ RS, RA, RB } },
+{ "popcntb", X(31,122), XRB_MASK,	POWER5,		{ RA, RS } },
 
-{ "stwcx.",  XRC(31,150,1), X_MASK,	PPC,		{ RS, RA, RB } },
+{ "not",     XRC(31,124,0), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "nor",     XRC(31,124,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "not.",    XRC(31,124,1), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "nor.",    XRC(31,124,1), X_MASK,	COM,		{ RA, RS, RB } },
 
-{ "stwx",    X(31,151), X_MASK,		PPC,		{ RS, RA, RB } },
-{ "stx",     X(31,151), X_MASK,		POWER,		{ RS, RA, RB } },
+{ "lwarxe",  X(31,126),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
 
-{ "slq",     XRC(31,152,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "slq.",    XRC(31,152,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "lbzuxe",  X(31,127),	X_MASK,		BOOKE64,	{ RT, RAL, RB } },
 
-{ "sle",     XRC(31,153,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "sle.",    XRC(31,153,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "wrtee",   X(31,131),	XRARB_MASK,	PPC403 | BOOKE,	{ RS } },
 
-{ "stdux",   X(31,181),	X_MASK,		PPC|B64,	{ RS, RAS, RB } },
+{ "dcbtstls",X(31,134),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
 
-{ "stwux",   X(31,183),	X_MASK,		PPC,		{ RS, RAS, RB } },
-{ "stux",    X(31,183),	X_MASK,		POWER,		{ RS, RA, RB } },
+{ "subfe",   XO(31,136,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfe",     XO(31,136,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfe.",  XO(31,136,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfe.",    XO(31,136,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfeo",  XO(31,136,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfeo",    XO(31,136,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "subfeo.", XO(31,136,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "sfeo.",   XO(31,136,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
 
-{ "sliq",    XRC(31,184,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
-{ "sliq.",   XRC(31,184,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "adde",    XO(31,138,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ae",      XO(31,138,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "adde.",   XO(31,138,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "ae.",     XO(31,138,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addeo",   XO(31,138,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "aeo",     XO(31,138,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addeo.",  XO(31,138,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "aeo.",    XO(31,138,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
 
-{ "subfze",  XO(31,200,0,0), XORB_MASK, PPC,		{ RT, RA } },
-{ "sfze",    XO(31,200,0,0), XORB_MASK, POWER,		{ RT, RA } },
-{ "subfze.", XO(31,200,0,1), XORB_MASK, PPC,		{ RT, RA } },
-{ "sfze.",   XO(31,200,0,1), XORB_MASK, POWER,		{ RT, RA } },
-{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPC,		{ RT, RA } },
-{ "sfzeo",   XO(31,200,1,0), XORB_MASK, POWER,		{ RT, RA } },
-{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPC,		{ RT, RA } },
-{ "sfzeo.",  XO(31,200,1,1), XORB_MASK, POWER,		{ RT, RA } },
+{ "dcbtstlse",X(31,142),X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
 
-{ "addze",   XO(31,202,0,0), XORB_MASK, PPC,		{ RT, RA } },
-{ "aze",     XO(31,202,0,0), XORB_MASK, POWER,		{ RT, RA } },
-{ "addze.",  XO(31,202,0,1), XORB_MASK, PPC,		{ RT, RA } },
-{ "aze.",    XO(31,202,0,1), XORB_MASK, POWER,		{ RT, RA } },
-{ "addzeo",  XO(31,202,1,0), XORB_MASK, PPC,		{ RT, RA } },
-{ "azeo",    XO(31,202,1,0), XORB_MASK, POWER,		{ RT, RA } },
-{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPC,		{ RT, RA } },
-{ "azeo.",   XO(31,202,1,1), XORB_MASK, POWER,		{ RT, RA } },
+{ "mtocrf",  XFXM(31,144,0,1), XFXFXM_MASK, COM,	{ FXM, RS } },
+{ "mtcr",    XFXM(31,144,0xff,0), XRARB_MASK, COM,	{ RS }},
+{ "mtcrf",   X(31,144),	XFXFXM_MASK,	COM,		{ FXM, RS } },
 
-{ "mtsr",    X(31,210),	XRB_MASK|(1<<20), PPC|POWER|B32, { SR, RS } },
+{ "mtmsr",   X(31,146),	XRARB_MASK,	COM,		{ RS } },
 
-{ "stdcx.",  XRC(31,214,1), X_MASK,	PPC|B64,	{ RS, RA, RB } },
+{ "stdx",    X(31,149), X_MASK,		PPC64,		{ RS, RA0, RB } },
 
-{ "stbx",    X(31,215),	X_MASK,		PPC|POWER,	{ RS, RA, RB } },
+{ "stwcx.",  XRC(31,150,1), X_MASK,	PPC,		{ RS, RA0, RB } },
 
-{ "sllq",    XRC(31,216,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "sllq.",   XRC(31,216,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "stwx",    X(31,151), X_MASK,		PPCCOM,		{ RS, RA0, RB } },
+{ "stx",     X(31,151), X_MASK,		PWRCOM,		{ RS, RA, RB } },
 
-{ "sleq",    XRC(31,217,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "sleq.",   XRC(31,217,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "stwcxe.", XRC(31,158,1), X_MASK,	BOOKE64,	{ RS, RA0, RB } },
 
-{ "subfme",  XO(31,232,0,0), XORB_MASK, PPC,		{ RT, RA } },
-{ "sfme",    XO(31,232,0,0), XORB_MASK, POWER,		{ RT, RA } },
-{ "subfme.", XO(31,232,0,1), XORB_MASK, PPC,		{ RT, RA } },
-{ "sfme.",   XO(31,232,0,1), XORB_MASK, POWER,		{ RT, RA } },
-{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPC,		{ RT, RA } },
-{ "sfmeo",   XO(31,232,1,0), XORB_MASK, POWER,		{ RT, RA } },
-{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPC,		{ RT, RA } },
-{ "sfmeo.",  XO(31,232,1,1), XORB_MASK, POWER,		{ RT, RA } },
+{ "stwxe",   X(31,159), X_MASK,		BOOKE64,	{ RS, RA0, RB } },
 
-{ "mulld",   XO(31,233,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "mulld.",  XO(31,233,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "mulldo",  XO(31,233,1,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "mulldo.", XO(31,233,1,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "slq",     XRC(31,152,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "slq.",    XRC(31,152,1), X_MASK,	M601,		{ RA, RS, RB } },
 
-{ "addme",   XO(31,234,0,0), XORB_MASK, PPC,		{ RT, RA } },
-{ "ame",     XO(31,234,0,0), XORB_MASK, POWER,		{ RT, RA } },
-{ "addme.",  XO(31,234,0,1), XORB_MASK, PPC,		{ RT, RA } },
-{ "ame.",    XO(31,234,0,1), XORB_MASK, POWER,		{ RT, RA } },
-{ "addmeo",  XO(31,234,1,0), XORB_MASK, PPC,		{ RT, RA } },
-{ "ameo",    XO(31,234,1,0), XORB_MASK, POWER,		{ RT, RA } },
-{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPC,		{ RT, RA } },
-{ "ameo.",   XO(31,234,1,1), XORB_MASK, POWER,		{ RT, RA } },
+{ "sle",     XRC(31,153,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sle.",    XRC(31,153,1), X_MASK,	M601,		{ RA, RS, RB } },
 
-{ "mullw",   XO(31,235,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "muls",    XO(31,235,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "mullw.",  XO(31,235,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "muls.",   XO(31,235,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "mullwo",  XO(31,235,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "mulso",   XO(31,235,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "mullwo.", XO(31,235,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "mulso.",  XO(31,235,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "prtyw",   X(31,154),	XRB_MASK,	POWER6,		{ RA, RS } },
 
-{ "mtsrin",  X(31,242),	XRA_MASK,	PPC|B32,	{ RS, RB } },
-{ "mtsri",   X(31,242),	XRA_MASK,	POWER|B32,	{ RS, RB } },
+{ "wrteei",  X(31,163),	XE_MASK,	PPC403 | BOOKE,	{ E } },
 
-{ "dcbtst",  X(31,246),	XRT_MASK,	PPC,		{ RA, RB } },
+{ "dcbtls",  X(31,166),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+{ "dcbtlse", X(31,174),	X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
 
-{ "stbux",   X(31,247),	X_MASK,		PPC|POWER,	{ RS, RAS, RB } },
+{ "mtmsrd",  X(31,178),	XRLARB_MASK,	PPC64,		{ RS, A_L } },
 
-{ "slliq",   XRC(31,248,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
-{ "slliq.",  XRC(31,248,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "stdux",   X(31,181),	X_MASK,		PPC64,		{ RS, RAS, RB } },
 
-{ "doz",     XO(31,264,0,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "doz.",    XO(31,264,0,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "dozo",    XO(31,264,1,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "dozo.",   XO(31,264,1,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "stwux",   X(31,183),	X_MASK,		PPCCOM,		{ RS, RAS, RB } },
+{ "stux",    X(31,183),	X_MASK,		PWRCOM,		{ RS, RA0, RB } },
 
-{ "add",     XO(31,266,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "cax",     XO(31,266,0,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "add.",    XO(31,266,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "cax.",    XO(31,266,0,1), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "addo",    XO(31,266,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "caxo",    XO(31,266,1,0), XO_MASK,	POWER,		{ RT, RA, RB } },
-{ "addo.",   XO(31,266,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
-{ "caxo.",   XO(31,266,1,1), XO_MASK,	POWER,		{ RT, RA, RB } },
+{ "sliq",    XRC(31,184,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sliq.",   XRC(31,184,1), X_MASK,	M601,		{ RA, RS, SH } },
 
-{ "lscbx",   XRC(31,277,0), X_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "lscbx.",  XRC(31,277,1), X_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "prtyd",   X(31,186),	XRB_MASK,	POWER6,		{ RA, RS } },
 
-{ "dcbt",    X(31,278),	XRT_MASK,	PPC,		{ RA, RB } },
+{ "stwuxe",  X(31,191),	X_MASK,		BOOKE64,	{ RS, RAS, RB } },
 
-{ "lhzx",    X(31,279),	X_MASK,		PPC|POWER,	{ RT, RA, RB } },
+{ "subfze",  XO(31,200,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfze",    XO(31,200,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfze.", XO(31,200,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfze.",   XO(31,200,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfzeo",   XO(31,200,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfzeo.",  XO(31,200,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
 
-{ "icbt",    X(31,262),	XRT_MASK,	PPC,		{ RA, RB } },
+{ "addze",   XO(31,202,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "aze",     XO(31,202,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addze.",  XO(31,202,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "aze.",    XO(31,202,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addzeo",  XO(31,202,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "azeo",    XO(31,202,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "azeo.",   XO(31,202,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
 
-{ "eqv",     XRC(31,284,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
-{ "eqv.",    XRC(31,284,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "mtsr",    X(31,210),	XRB_MASK|(1<<20), COM32,	{ SR, RS } },
 
-{ "tlbie",   X(31,306),	XRTRA_MASK,	PPC,		{ RB } },
-{ "tlbi",    X(31,306),	XRTRA_MASK,	POWER,		{ RB } },
+{ "stdcx.",  XRC(31,214,1), X_MASK,	PPC64,		{ RS, RA0, RB } },
+
+{ "stbx",    X(31,215),	X_MASK,		COM,		{ RS, RA0, RB } },
+
+{ "sllq",    XRC(31,216,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sllq.",   XRC(31,216,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "sleq",    XRC(31,217,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sleq.",   XRC(31,217,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "stbxe",   X(31,223),	X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "icblc",   X(31,230),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+
+{ "subfme",  XO(31,232,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfme",    XO(31,232,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfme.", XO(31,232,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfme.",   XO(31,232,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfmeo",   XO(31,232,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "sfmeo.",  XO(31,232,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "mulld",   XO(31,233,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulld.",  XO(31,233,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulldo",  XO(31,233,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "mulldo.", XO(31,233,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addme",   XO(31,234,0,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ame",     XO(31,234,0,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addme.",  XO(31,234,0,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ame.",    XO(31,234,0,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addmeo",  XO(31,234,1,0), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ameo",    XO(31,234,1,0), XORB_MASK, PWRCOM,		{ RT, RA } },
+{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM,		{ RT, RA } },
+{ "ameo.",   XO(31,234,1,1), XORB_MASK, PWRCOM,		{ RT, RA } },
+
+{ "mullw",   XO(31,235,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "muls",    XO(31,235,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullw.",  XO(31,235,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "muls.",   XO(31,235,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullwo",  XO(31,235,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "mulso",   XO(31,235,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "mullwo.", XO(31,235,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "mulso.",  XO(31,235,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "icblce",  X(31,238),	X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
+{ "mtsrin",  X(31,242),	XRA_MASK,	PPC32,		{ RS, RB } },
+{ "mtsri",   X(31,242),	XRA_MASK,	POWER32,	{ RS, RB } },
+
+{ "dcbtst",  X(31,246),	X_MASK,	PPC,			{ CT, RA, RB } },
+
+{ "stbux",   X(31,247),	X_MASK,		COM,		{ RS, RAS, RB } },
+
+{ "slliq",   XRC(31,248,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "slliq.",  XRC(31,248,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "dcbtste", X(31,253),	X_MASK,		BOOKE64,	{ CT, RA, RB } },
+
+{ "stbuxe",  X(31,255),	X_MASK,		BOOKE64,	{ RS, RAS, RB } },
+
+{ "mfdcrx",  X(31,259),	X_MASK,		BOOKE,		{ RS, RA } },
+
+{ "doz",     XO(31,264,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "doz.",    XO(31,264,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "dozo",    XO(31,264,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "dozo.",   XO(31,264,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
+
+{ "add",     XO(31,266,0,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "cax",     XO(31,266,0,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "add.",    XO(31,266,0,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "cax.",    XO(31,266,0,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addo",    XO(31,266,1,0), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "caxo",    XO(31,266,1,0), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+{ "addo.",   XO(31,266,1,1), XO_MASK,	PPCCOM,		{ RT, RA, RB } },
+{ "caxo.",   XO(31,266,1,1), XO_MASK,	PWRCOM,		{ RT, RA, RB } },
+
+{ "tlbiel",  X(31,274), XRTLRA_MASK,	POWER4,		{ RB, L } },
+
+{ "mfapidi", X(31,275), X_MASK,		BOOKE,		{ RT, RA } },
+
+{ "lscbx",   XRC(31,277,0), X_MASK,	M601,		{ RT, RA, RB } },
+{ "lscbx.",  XRC(31,277,1), X_MASK,	M601,		{ RT, RA, RB } },
+
+{ "dcbt",    X(31,278),	X_MASK,		PPC,		{ CT, RA, RB } },
+
+{ "lhzx",    X(31,279),	X_MASK,		COM,		{ RT, RA0, RB } },
+
+{ "eqv",     XRC(31,284,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "eqv.",    XRC(31,284,1), X_MASK,	COM,		{ RA, RS, RB } },
+
+{ "dcbte",   X(31,286),	X_MASK,		BOOKE64,	{ CT, RA, RB } },
+
+{ "lhzxe",   X(31,287),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "tlbie",   X(31,306),	XRTLRA_MASK,	PPC,		{ RB, L } },
+{ "tlbi",    X(31,306),	XRT_MASK,	POWER,		{ RA0, RB } },
 
 { "eciwx",   X(31,310), X_MASK,		PPC,		{ RT, RA, RB } },
 
-{ "lhzux",   X(31,311),	X_MASK,		PPC|POWER,	{ RT, RAL, RB } },
+{ "lhzux",   X(31,311),	X_MASK,		COM,		{ RT, RAL, RB } },
 
-{ "xor",     XRC(31,316,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
-{ "xor.",    XRC(31,316,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "xor",     XRC(31,316,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "xor.",    XRC(31,316,1), X_MASK,	COM,		{ RA, RS, RB } },
 
-{ "mfdcr",   X(31,323),	X_MASK,		PPC,		{ RT, SPR } },
+{ "lhzuxe",  X(31,319),	X_MASK,		BOOKE64,	{ RT, RAL, RB } },
 
-{ "div",     XO(31,331,0,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "div.",    XO(31,331,0,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "divo",    XO(31,331,1,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "divo.",   XO(31,331,1,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "mfexisr",  XSPR(31,323,64),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfexier",  XSPR(31,323,66),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr0",    XSPR(31,323,128), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr1",    XSPR(31,323,129), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr2",    XSPR(31,323,130), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr3",    XSPR(31,323,131), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr4",    XSPR(31,323,132), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr5",    XSPR(31,323,133), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr6",    XSPR(31,323,134), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbr7",    XSPR(31,323,135), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbear",   XSPR(31,323,144), XSPR_MASK, PPC403,	{ RT } },
+{ "mfbesr",   XSPR(31,323,145), XSPR_MASK, PPC403,	{ RT } },
+{ "mfiocr",   XSPR(31,323,160), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr0", XSPR(31,323,192), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact0", XSPR(31,323,193), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada0", XSPR(31,323,194), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa0", XSPR(31,323,195), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc0", XSPR(31,323,196), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr1", XSPR(31,323,200), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact1", XSPR(31,323,201), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada1", XSPR(31,323,202), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa1", XSPR(31,323,203), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc1", XSPR(31,323,204), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr2", XSPR(31,323,208), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact2", XSPR(31,323,209), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada2", XSPR(31,323,210), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa2", XSPR(31,323,211), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc2", XSPR(31,323,212), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacr3", XSPR(31,323,216), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmact3", XSPR(31,323,217), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmada3", XSPR(31,323,218), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasa3", XSPR(31,323,219), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmacc3", XSPR(31,323,220), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdmasr",  XSPR(31,323,224), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdcr",    X(31,323),	X_MASK,	PPC403 | BOOKE,	{ RT, SPR } },
 
-{ "mfmq",    XSPR(31,339,0), XSPR_MASK,	POWER|M601,	{ RT } },
-{ "mfxer",   XSPR(31,339,1), XSPR_MASK,	PPC|POWER,	{ RT } },
-{ "mfrtcu",  XSPR(31,339,4), XSPR_MASK, PPC|POWER,	{ RT } },
-{ "mfrtcl",  XSPR(31,339,5), XSPR_MASK, PPC|POWER,	{ RT } },
-{ "mfdec",   XSPR(31,339,6), XSPR_MASK, POWER|M601,	{ RT } },
-{ "mflr",    XSPR(31,339,8), XSPR_MASK,	PPC|POWER,	{ RT } },
-{ "mfctr",   XSPR(31,339,9), XSPR_MASK,	PPC|POWER,	{ RT } },
-{ "mftid",   XSPR(31,339,17), XSPR_MASK, POWER,		{ RT } },
-{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, PPC|POWER,	{ RT } },
-{ "mfdar",   XSPR(31,339,19), XSPR_MASK, PPC|POWER,	{ RT } },
-{ "mfdec",   XSPR(31,339,22), XSPR_MASK, PPC,		{ RT } },
-{ "mfsdr0",  XSPR(31,339,24), XSPR_MASK, POWER,		{ RT } },
-{ "mfsdr1",  XSPR(31,339,25), XSPR_MASK, PPC|POWER,	{ RT } },
-{ "mfsrr0",  XSPR(31,339,26), XSPR_MASK, PPC|POWER,	{ RT } },
-{ "mfsrr1",  XSPR(31,339,27), XSPR_MASK, PPC|POWER,	{ RT } },
-{ "mfsprg",  XSPR(31,339,272), XSPRG_MASK, PPC,		{ RT, SPRG } },
-{ "mfasr",   XSPR(31,339,280), XSPR_MASK, PPC|B64,	{ RT } },
-{ "mfear",   XSPR(31,339,282), XSPR_MASK, PPC,		{ RT } },
-{ "mfpvr",   XSPR(31,339,287), XSPR_MASK, PPC,		{ RT } },
-{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
-{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
-{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
-{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
-{ "mfspr",   X(31,339),	X_MASK,		PPC|POWER,	{ RT, SPR } },
+{ "div",     XO(31,331,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "div.",    XO(31,331,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divo",    XO(31,331,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divo.",   XO(31,331,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
 
-{ "lwax",    X(31,341),	X_MASK,		PPC|B64,	{ RT, RA, RB } },
+{ "mfpmr",   X(31,334),	X_MASK,		PPCPMR,		{ RT, PMR }},
 
-{ "lhax",    X(31,343),	X_MASK,		PPC|POWER,	{ RT, RA, RB } },
+{ "mfmq",       XSPR(31,339,0),    XSPR_MASK, M601,	{ RT } },
+{ "mfxer",      XSPR(31,339,1),    XSPR_MASK, COM,	{ RT } },
+{ "mfrtcu",     XSPR(31,339,4),    XSPR_MASK, COM,	{ RT } },
+{ "mfrtcl",     XSPR(31,339,5),    XSPR_MASK, COM,	{ RT } },
+{ "mfdec",      XSPR(31,339,6),    XSPR_MASK, MFDEC1,	{ RT } },
+{ "mfdec",      XSPR(31,339,22),   XSPR_MASK, MFDEC2,	{ RT } },
+{ "mflr",       XSPR(31,339,8),    XSPR_MASK, COM,	{ RT } },
+{ "mfctr",      XSPR(31,339,9),    XSPR_MASK, COM,	{ RT } },
+{ "mftid",      XSPR(31,339,17),   XSPR_MASK, POWER,	{ RT } },
+{ "mfdsisr",    XSPR(31,339,18),   XSPR_MASK, COM,	{ RT } },
+{ "mfdar",      XSPR(31,339,19),   XSPR_MASK, COM,	{ RT } },
+{ "mfsdr0",     XSPR(31,339,24),   XSPR_MASK, POWER,	{ RT } },
+{ "mfsdr1",     XSPR(31,339,25),   XSPR_MASK, COM,	{ RT } },
+{ "mfsrr0",     XSPR(31,339,26),   XSPR_MASK, COM,	{ RT } },
+{ "mfsrr1",     XSPR(31,339,27),   XSPR_MASK, COM,	{ RT } },
+{ "mfcfar",     XSPR(31,339,28),   XSPR_MASK, POWER6,	{ RT } },
+{ "mfpid",      XSPR(31,339,48),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfpid",      XSPR(31,339,945),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfcsrr0",    XSPR(31,339,58),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfcsrr1",    XSPR(31,339,59),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfdear",     XSPR(31,339,61),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfdear",     XSPR(31,339,981),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfesr",      XSPR(31,339,62),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfesr",      XSPR(31,339,980),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfivpr",     XSPR(31,339,63),   XSPR_MASK, BOOKE,    { RT } },
+{ "mfcmpa",     XSPR(31,339,144),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpb",     XSPR(31,339,145),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpc",     XSPR(31,339,146),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpd",     XSPR(31,339,147),  XSPR_MASK, PPC860,	{ RT } },
+{ "mficr",      XSPR(31,339,148),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfder",      XSPR(31,339,149),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcounta",   XSPR(31,339,150),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcountb",   XSPR(31,339,151),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpe",     XSPR(31,339,152),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpf",     XSPR(31,339,153),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmpg",     XSPR(31,339,154),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfcmph",     XSPR(31,339,155),  XSPR_MASK, PPC860,	{ RT } },
+{ "mflctrl1",   XSPR(31,339,156),  XSPR_MASK, PPC860,	{ RT } },
+{ "mflctrl2",   XSPR(31,339,157),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfictrl",    XSPR(31,339,158),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfbar",      XSPR(31,339,159),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfvrsave",   XSPR(31,339,256),  XSPR_MASK, PPCVEC,	{ RT } },
+{ "mfusprg0",   XSPR(31,339,256),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftb",       X(31,371),	   X_MASK,    CLASSIC,	{ RT, TBR } },
+{ "mftb",       XSPR(31,339,268),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftbl",      XSPR(31,371,268),  XSPR_MASK, CLASSIC,	{ RT } },
+{ "mftbl",      XSPR(31,339,268),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftbu",      XSPR(31,371,269),  XSPR_MASK, CLASSIC,	{ RT } },
+{ "mftbu",      XSPR(31,339,269),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfsprg",     XSPR(31,339,256),  XSPRG_MASK, PPC,	{ RT, SPRG } },
+{ "mfsprg0",    XSPR(31,339,272),  XSPR_MASK, PPC,	{ RT } },
+{ "mfsprg1",    XSPR(31,339,273),  XSPR_MASK, PPC,	{ RT } },
+{ "mfsprg2",    XSPR(31,339,274),  XSPR_MASK, PPC,	{ RT } },
+{ "mfsprg3",    XSPR(31,339,275),  XSPR_MASK, PPC,	{ RT } },
+{ "mfsprg4",    XSPR(31,339,260),  XSPR_MASK, PPC405 | BOOKE,	{ RT } },
+{ "mfsprg5",    XSPR(31,339,261),  XSPR_MASK, PPC405 | BOOKE,	{ RT } },
+{ "mfsprg6",    XSPR(31,339,262),  XSPR_MASK, PPC405 | BOOKE,	{ RT } },
+{ "mfsprg7",    XSPR(31,339,263),  XSPR_MASK, PPC405 | BOOKE,	{ RT } },
+{ "mfasr",      XSPR(31,339,280),  XSPR_MASK, PPC64,	{ RT } },
+{ "mfear",      XSPR(31,339,282),  XSPR_MASK, PPC,	{ RT } },
+{ "mfpir",      XSPR(31,339,286),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfpvr",      XSPR(31,339,287),  XSPR_MASK, PPC,	{ RT } },
+{ "mfdbsr",     XSPR(31,339,304),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdbsr",     XSPR(31,339,1008), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdbcr0",    XSPR(31,339,308),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdbcr0",    XSPR(31,339,1010), XSPR_MASK, PPC405,	{ RT } },
+{ "mfdbcr1",    XSPR(31,339,309),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdbcr1",    XSPR(31,339,957),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfdbcr2",    XSPR(31,339,310),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac1",     XSPR(31,339,312),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac1",     XSPR(31,339,1012), XSPR_MASK, PPC403,	{ RT } },
+{ "mfiac2",     XSPR(31,339,313),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac2",     XSPR(31,339,1013), XSPR_MASK, PPC403,	{ RT } },
+{ "mfiac3",     XSPR(31,339,314),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac3",     XSPR(31,339,948),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfiac4",     XSPR(31,339,315),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfiac4",     XSPR(31,339,949),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfdac1",     XSPR(31,339,316),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdac1",     XSPR(31,339,1014), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdac2",     XSPR(31,339,317),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdac2",     XSPR(31,339,1015), XSPR_MASK, PPC403,	{ RT } },
+{ "mfdvc1",     XSPR(31,339,318),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdvc1",     XSPR(31,339,950),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfdvc2",     XSPR(31,339,319),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfdvc2",     XSPR(31,339,951),  XSPR_MASK, PPC405,	{ RT } },
+{ "mftsr",      XSPR(31,339,336),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftsr",      XSPR(31,339,984),  XSPR_MASK, PPC403,	{ RT } },
+{ "mftcr",      XSPR(31,339,340),  XSPR_MASK, BOOKE,    { RT } },
+{ "mftcr",      XSPR(31,339,986),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfivor0",    XSPR(31,339,400),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor1",    XSPR(31,339,401),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor2",    XSPR(31,339,402),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor3",    XSPR(31,339,403),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor4",    XSPR(31,339,404),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor5",    XSPR(31,339,405),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor6",    XSPR(31,339,406),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor7",    XSPR(31,339,407),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor8",    XSPR(31,339,408),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor9",    XSPR(31,339,409),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor10",   XSPR(31,339,410),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor11",   XSPR(31,339,411),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor12",   XSPR(31,339,412),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor13",   XSPR(31,339,413),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor14",   XSPR(31,339,414),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfivor15",   XSPR(31,339,415),  XSPR_MASK, BOOKE,    { RT } },
+{ "mfspefscr",  XSPR(31,339,512),  XSPR_MASK, PPCSPE,	{ RT } },
+{ "mfbbear",    XSPR(31,339,513),  XSPR_MASK, PPCBRLK,  { RT } },
+{ "mfbbtar",    XSPR(31,339,514),  XSPR_MASK, PPCBRLK,  { RT } },
+{ "mfivor32",   XSPR(31,339,528),  XSPR_MASK, PPCSPE,	{ RT } },
+{ "mfivor33",   XSPR(31,339,529),  XSPR_MASK, PPCSPE,	{ RT } },
+{ "mfivor34",   XSPR(31,339,530),  XSPR_MASK, PPCSPE,	{ RT } },
+{ "mfivor35",   XSPR(31,339,531),  XSPR_MASK, PPCPMR,	{ RT } },
+{ "mfibatu",    XSPR(31,339,528),  XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfibatl",    XSPR(31,339,529),  XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfdbatu",    XSPR(31,339,536),  XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfdbatl",    XSPR(31,339,537),  XSPRBAT_MASK, PPC,	{ RT, SPRBAT } },
+{ "mfic_cst",   XSPR(31,339,560),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfic_adr",   XSPR(31,339,561),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfic_dat",   XSPR(31,339,562),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfdc_cst",   XSPR(31,339,568),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfdc_adr",   XSPR(31,339,569),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmcsrr0",   XSPR(31,339,570),  XSPR_MASK, PPCRFMCI, { RT } },
+{ "mfdc_dat",   XSPR(31,339,570),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmcsrr1",   XSPR(31,339,571),  XSPR_MASK, PPCRFMCI, { RT } },
+{ "mfmcsr",     XSPR(31,339,572),  XSPR_MASK, PPCRFMCI, { RT } },
+{ "mfmcar",     XSPR(31,339,573),  XSPR_MASK, PPCRFMCI, { RT } },
+{ "mfdpdr",     XSPR(31,339,630),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfdpir",     XSPR(31,339,631),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfimmr",     XSPR(31,339,638),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_ctr",   XSPR(31,339,784),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_ap",    XSPR(31,339,786),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_epn",   XSPR(31,339,787),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_twc",   XSPR(31,339,789),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_rpn",   XSPR(31,339,790),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_ctr",   XSPR(31,339,792),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfm_casid",  XSPR(31,339,793),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_ap",    XSPR(31,339,794),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_epn",   XSPR(31,339,795),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_twb",   XSPR(31,339,796),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_twc",   XSPR(31,339,797),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_rpn",   XSPR(31,339,798),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfm_tw",     XSPR(31,339,799),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbcam", XSPR(31,339,816),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbram0",XSPR(31,339,817),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmi_dbram1",XSPR(31,339,818),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbcam", XSPR(31,339,824),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbram0",XSPR(31,339,825),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfmd_dbram1",XSPR(31,339,826),  XSPR_MASK, PPC860,	{ RT } },
+{ "mfummcr0",   XSPR(31,339,936),  XSPR_MASK, PPC750,   { RT } },
+{ "mfupmc1",    XSPR(31,339,937),  XSPR_MASK, PPC750,   { RT } },
+{ "mfupmc2",    XSPR(31,339,938),  XSPR_MASK, PPC750,   { RT } },
+{ "mfusia",     XSPR(31,339,939),  XSPR_MASK, PPC750,   { RT } },
+{ "mfummcr1",   XSPR(31,339,940),  XSPR_MASK, PPC750,   { RT } },
+{ "mfupmc3",    XSPR(31,339,941),  XSPR_MASK, PPC750,   { RT } },
+{ "mfupmc4",    XSPR(31,339,942),  XSPR_MASK, PPC750,   { RT } },
+{ "mfzpr",   	XSPR(31,339,944),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfccr0",  	XSPR(31,339,947),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfmmcr0",	XSPR(31,339,952),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfpmc1",	XSPR(31,339,953),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsgr",	XSPR(31,339,953),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfpmc2",	XSPR(31,339,954),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfdcwr", 	XSPR(31,339,954),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfsia",	XSPR(31,339,955),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsler",	XSPR(31,339,955),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfmmcr1",	XSPR(31,339,956),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfsu0r",	XSPR(31,339,956),  XSPR_MASK, PPC405,	{ RT } },
+{ "mfpmc3",	XSPR(31,339,957),  XSPR_MASK, PPC750,	{ RT } },
+{ "mfpmc4",	XSPR(31,339,958),  XSPR_MASK, PPC750,	{ RT } },
+{ "mficdbdr",   XSPR(31,339,979),  XSPR_MASK, PPC403,   { RT } },
+{ "mfevpr",     XSPR(31,339,982),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfcdbcr",    XSPR(31,339,983),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfpit",      XSPR(31,339,987),  XSPR_MASK, PPC403,	{ RT } },
+{ "mftbhi",     XSPR(31,339,988),  XSPR_MASK, PPC403,	{ RT } },
+{ "mftblo",     XSPR(31,339,989),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfsrr2",     XSPR(31,339,990),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfsrr3",     XSPR(31,339,991),  XSPR_MASK, PPC403,	{ RT } },
+{ "mfl2cr",     XSPR(31,339,1017), XSPR_MASK, PPC750,   { RT } },
+{ "mfdccr",     XSPR(31,339,1018), XSPR_MASK, PPC403,	{ RT } },
+{ "mficcr",     XSPR(31,339,1019), XSPR_MASK, PPC403,	{ RT } },
+{ "mfictc",     XSPR(31,339,1019), XSPR_MASK, PPC750,   { RT } },
+{ "mfpbl1",     XSPR(31,339,1020), XSPR_MASK, PPC403,	{ RT } },
+{ "mfthrm1",    XSPR(31,339,1020), XSPR_MASK, PPC750,   { RT } },
+{ "mfpbu1",     XSPR(31,339,1021), XSPR_MASK, PPC403,	{ RT } },
+{ "mfthrm2",    XSPR(31,339,1021), XSPR_MASK, PPC750,   { RT } },
+{ "mfpbl2",     XSPR(31,339,1022), XSPR_MASK, PPC403,	{ RT } },
+{ "mfthrm3",    XSPR(31,339,1022), XSPR_MASK, PPC750,   { RT } },
+{ "mfpbu2",     XSPR(31,339,1023), XSPR_MASK, PPC403,	{ RT } },
+{ "mfspr",      X(31,339),	   X_MASK,    COM,	{ RT, SPR } },
 
-{ "dccci",   X(31,454),	XRT_MASK,	PPC,		{ RA, RB } },
+{ "lwax",    X(31,341),	X_MASK,		PPC64,		{ RT, RA0, RB } },
 
-{ "abs",     XO(31,360,0,0), XORB_MASK, POWER|M601,	{ RT, RA } },
-{ "abs.",    XO(31,360,0,1), XORB_MASK, POWER|M601,	{ RT, RA } },
-{ "abso",    XO(31,360,1,0), XORB_MASK, POWER|M601,	{ RT, RA } },
-{ "abso.",   XO(31,360,1,1), XORB_MASK, POWER|M601,	{ RT, RA } },
+{ "dst",     XDSS(31,342,0), XDSS_MASK,	PPCVEC,		{ RA, RB, STRM } },
+{ "dstt",    XDSS(31,342,1), XDSS_MASK,	PPCVEC,		{ RA, RB, STRM } },
 
-{ "divs",    XO(31,363,0,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "divs.",   XO(31,363,0,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "divso",   XO(31,363,1,0), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
-{ "divso.",  XO(31,363,1,1), XO_MASK,	POWER|M601,	{ RT, RA, RB } },
+{ "lhax",    X(31,343),	X_MASK,		COM,		{ RT, RA0, RB } },
+
+{ "lhaxe",   X(31,351),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "dstst",   XDSS(31,374,0), XDSS_MASK,	PPCVEC,		{ RA, RB, STRM } },
+{ "dststt",  XDSS(31,374,1), XDSS_MASK,	PPCVEC,		{ RA, RB, STRM } },
+
+{ "dccci",   X(31,454),	XRT_MASK,	PPC403|PPC440,	{ RA, RB } },
+
+{ "abs",     XO(31,360,0,0), XORB_MASK, M601,		{ RT, RA } },
+{ "abs.",    XO(31,360,0,1), XORB_MASK, M601,		{ RT, RA } },
+{ "abso",    XO(31,360,1,0), XORB_MASK, M601,		{ RT, RA } },
+{ "abso.",   XO(31,360,1,1), XORB_MASK, M601,		{ RT, RA } },
+
+{ "divs",    XO(31,363,0,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divs.",   XO(31,363,0,1), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divso",   XO(31,363,1,0), XO_MASK,	M601,		{ RT, RA, RB } },
+{ "divso.",  XO(31,363,1,1), XO_MASK,	M601,		{ RT, RA, RB } },
 
 { "tlbia",   X(31,370),	0xffffffff,	PPC,		{ 0 } },
 
-{ "mftbu",   XSPR(31,371,269), XSPR_MASK, PPC,		{ RT } },
-{ "mftb",    X(31,371),	X_MASK,		PPC,		{ RT, TBR } },
+{ "lwaux",   X(31,373),	X_MASK,		PPC64,		{ RT, RAL, RB } },
 
-{ "lwaux",   X(31,373),	X_MASK,		PPC|B64,	{ RT, RAL, RB } },
+{ "lhaux",   X(31,375),	X_MASK,		COM,		{ RT, RAL, RB } },
 
-{ "lhaux",   X(31,375),	X_MASK,		PPC|POWER,	{ RT, RAL, RB } },
+{ "lhauxe",  X(31,383),	X_MASK,		BOOKE64,	{ RT, RAL, RB } },
 
-{ "sthx",    X(31,407),	X_MASK,		PPC|POWER,	{ RS, RA, RB } },
+{ "mtdcrx",  X(31,387),	X_MASK,		BOOKE,		{ RA, RS } },
+
+{ "dcblc",   X(31,390),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+
+{ "subfe64", XO(31,392,0,0), XO_MASK,	BOOKE64,	{ RT, RA, RB } },
+{ "subfe64o",XO(31,392,1,0), XO_MASK,	BOOKE64,	{ RT, RA, RB } },
+
+{ "adde64",  XO(31,394,0,0), XO_MASK,	BOOKE64,	{ RT, RA, RB } },
+{ "adde64o", XO(31,394,1,0), XO_MASK,	BOOKE64,	{ RT, RA, RB } },
+
+{ "dcblce",  X(31,398),	X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
+
+{ "slbmte",  X(31,402), XRA_MASK,	PPC64,		{ RS, RB } },
+
+{ "sthx",    X(31,407),	X_MASK,		COM,		{ RS, RA0, RB } },
+
+{ "cmpb",    X(31,508),	X_MASK,		POWER6,		{ RA, RS, RB } },
 
 { "lfqx",    X(31,791),	X_MASK,		POWER2,		{ FRT, RA, RB } },
 
+{ "lfdpx",   X(31,791),	X_MASK,		POWER6,		{ FRT, RA, RB } },
+
 { "lfqux",   X(31,823),	X_MASK,		POWER2,		{ FRT, RA, RB } },
 
 { "stfqx",   X(31,919),	X_MASK,		POWER2,		{ FRS, RA, RB } },
 
+{ "stfdpx",  X(31,919),	X_MASK,		POWER6,		{ FRS, RA, RB } },
+
 { "stfqux",  X(31,951),	X_MASK,		POWER2,		{ FRS, RA, RB } },
 
-{ "orc",     XRC(31,412,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
-{ "orc.",    XRC(31,412,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "orc",     XRC(31,412,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "orc.",    XRC(31,412,1), X_MASK,	COM,		{ RA, RS, RB } },
 
-{ "sradi",   XS(31,413,0), XS_MASK,	PPC|B64,	{ RA, RS, SH6 } },
-{ "sradi.",  XS(31,413,1), XS_MASK,	PPC|B64,	{ RA, RS, SH6 } },
+{ "sradi",   XS(31,413,0), XS_MASK,	PPC64,		{ RA, RS, SH6 } },
+{ "sradi.",  XS(31,413,1), XS_MASK,	PPC64,		{ RA, RS, SH6 } },
 
-{ "slbie",   X(31,434),	XRTRA_MASK,	PPC|B64,	{ RB } },
+{ "sthxe",   X(31,415),	X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "slbie",   X(31,434),	XRTRA_MASK,	PPC64,		{ RB } },
 
 { "ecowx",   X(31,438),	X_MASK,		PPC,		{ RT, RA, RB } },
 
-{ "sthux",   X(31,439),	X_MASK,		PPC|POWER,	{ RS, RAS, RB } },
+{ "sthux",   X(31,439),	X_MASK,		COM,		{ RS, RAS, RB } },
 
-{ "mr",	     XRC(31,444,0), X_MASK,	PPC|POWER,	{ RA, RS, RBS } },
-{ "or",      XRC(31,444,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
-{ "mr.",     XRC(31,444,1), X_MASK,	PPC|POWER,	{ RA, RS, RBS } },
-{ "or.",     XRC(31,444,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "sthuxe",  X(31,447),	X_MASK,		BOOKE64,	{ RS, RAS, RB } },
 
-{ "mtdcr",   X(31,451),	X_MASK,		PPC,		{ SPR, RS } },
+{ "cctpl",   0x7c210b78,    0xffffffff,	CELL,		{ 0 }},
+{ "cctpm",   0x7c421378,    0xffffffff,	CELL,		{ 0 }},
+{ "cctph",   0x7c631b78,    0xffffffff,	CELL,		{ 0 }},
+{ "db8cyc",  0x7f9ce378,    0xffffffff,	CELL,		{ 0 }},
+{ "db10cyc", 0x7fbdeb78,    0xffffffff,	CELL,		{ 0 }},
+{ "db12cyc", 0x7fdef378,    0xffffffff,	CELL,		{ 0 }},
+{ "db16cyc", 0x7ffffb78,    0xffffffff,	CELL,		{ 0 }},
+{ "mr",	     XRC(31,444,0), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "or",      XRC(31,444,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "mr.",     XRC(31,444,1), X_MASK,	COM,		{ RA, RS, RBS } },
+{ "or.",     XRC(31,444,1), X_MASK,	COM,		{ RA, RS, RB } },
 
-{ "divdu",   XO(31,457,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "divdu.",  XO(31,457,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "divduo",  XO(31,457,1,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "divduo.", XO(31,457,1,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "mtexisr",  XSPR(31,451,64),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtexier",  XSPR(31,451,66),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr0",    XSPR(31,451,128), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr1",    XSPR(31,451,129), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr2",    XSPR(31,451,130), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr3",    XSPR(31,451,131), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr4",    XSPR(31,451,132), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr5",    XSPR(31,451,133), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr6",    XSPR(31,451,134), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbr7",    XSPR(31,451,135), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbear",   XSPR(31,451,144), XSPR_MASK, PPC403,	{ RS } },
+{ "mtbesr",   XSPR(31,451,145), XSPR_MASK, PPC403,	{ RS } },
+{ "mtiocr",   XSPR(31,451,160), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacr0", XSPR(31,451,192), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmact0", XSPR(31,451,193), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmada0", XSPR(31,451,194), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasa0", XSPR(31,451,195), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacc0", XSPR(31,451,196), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacr1", XSPR(31,451,200), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmact1", XSPR(31,451,201), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmada1", XSPR(31,451,202), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasa1", XSPR(31,451,203), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacc1", XSPR(31,451,204), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacr2", XSPR(31,451,208), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmact2", XSPR(31,451,209), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmada2", XSPR(31,451,210), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasa2", XSPR(31,451,211), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacc2", XSPR(31,451,212), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacr3", XSPR(31,451,216), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmact3", XSPR(31,451,217), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmada3", XSPR(31,451,218), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasa3", XSPR(31,451,219), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmacc3", XSPR(31,451,220), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdmasr",  XSPR(31,451,224), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdcr",    X(31,451),	X_MASK,	PPC403 | BOOKE,	{ SPR, RS } },
+
+{ "subfze64",XO(31,456,0,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "subfze64o",XO(31,456,1,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+
+{ "divdu",   XO(31,457,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdu.",  XO(31,457,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divduo",  XO(31,457,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divduo.", XO(31,457,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addze64", XO(31,458,0,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "addze64o",XO(31,458,1,0), XORB_MASK, BOOKE64,	{ RT, RA } },
 
 { "divwu",   XO(31,459,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "divwu.",  XO(31,459,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "divwuo",  XO(31,459,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "divwuo.", XO(31,459,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
 
-{ "mtmq",    XSPR(31,467,0), XSPR_MASK,	POWER|M601,	{ RS } },
-{ "mtxer",   XSPR(31,467,1), XSPR_MASK,	PPC|POWER,	{ RS } },
-{ "mtlr",    XSPR(31,467,8), XSPR_MASK,	PPC|POWER,	{ RS } },
-{ "mtctr",   XSPR(31,467,9), XSPR_MASK,	PPC|POWER,	{ RS } },
-{ "mttid",   XSPR(31,467,17), XSPR_MASK, POWER,		{ RS } },
-{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, PPC|POWER,	{ RS } },
-{ "mtdar",   XSPR(31,467,19), XSPR_MASK, PPC|POWER,	{ RS } },
-{ "mtrtcu",  XSPR(31,467,20), XSPR_MASK, PPC|POWER,	{ RS } },
-{ "mtrtcl",  XSPR(31,467,21), XSPR_MASK, PPC|POWER,	{ RS } },
-{ "mtdec",   XSPR(31,467,22), XSPR_MASK, PPC|POWER,	{ RS } },
-{ "mtsdr0",  XSPR(31,467,24), XSPR_MASK, POWER,		{ RS } },
-{ "mtsdr1",  XSPR(31,467,25), XSPR_MASK, PPC|POWER,	{ RS } },
-{ "mtsrr0",  XSPR(31,467,26), XSPR_MASK, PPC|POWER,	{ RS } },
-{ "mtsrr1",  XSPR(31,467,27), XSPR_MASK, PPC|POWER,	{ RS } },
-{ "mtsprg",  XSPR(31,467,272), XSPRG_MASK, PPC,		{ SPRG, RS } },
-{ "mtasr",   XSPR(31,467,280), XSPR_MASK, PPC|B64,	{ RS } },
-{ "mtear",   XSPR(31,467,282), XSPR_MASK, PPC,		{ RS } },
-{ "mttbl",   XSPR(31,467,284), XSPR_MASK, PPC,		{ RS } },
-{ "mttbu",   XSPR(31,467,285), XSPR_MASK, PPC,		{ RS } },
-{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
-{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
-{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
-{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
-{ "mtspr",   X(31,467),	X_MASK,		PPC|POWER,	{ SPR, RS } },
+{ "mtmq",      XSPR(31,467,0),    XSPR_MASK, M601,	{ RS } },
+{ "mtxer",     XSPR(31,467,1),    XSPR_MASK, COM,	{ RS } },
+{ "mtlr",      XSPR(31,467,8),    XSPR_MASK, COM,	{ RS } },
+{ "mtctr",     XSPR(31,467,9),    XSPR_MASK, COM,	{ RS } },
+{ "mttid",     XSPR(31,467,17),   XSPR_MASK, POWER,	{ RS } },
+{ "mtdsisr",   XSPR(31,467,18),   XSPR_MASK, COM,	{ RS } },
+{ "mtdar",     XSPR(31,467,19),   XSPR_MASK, COM,	{ RS } },
+{ "mtrtcu",    XSPR(31,467,20),   XSPR_MASK, COM,	{ RS } },
+{ "mtrtcl",    XSPR(31,467,21),   XSPR_MASK, COM,	{ RS } },
+{ "mtdec",     XSPR(31,467,22),   XSPR_MASK, COM,	{ RS } },
+{ "mtsdr0",    XSPR(31,467,24),   XSPR_MASK, POWER,	{ RS } },
+{ "mtsdr1",    XSPR(31,467,25),   XSPR_MASK, COM,	{ RS } },
+{ "mtsrr0",    XSPR(31,467,26),   XSPR_MASK, COM,	{ RS } },
+{ "mtsrr1",    XSPR(31,467,27),   XSPR_MASK, COM,	{ RS } },
+{ "mtcfar",    XSPR(31,467,28),   XSPR_MASK, POWER6,	{ RS } },
+{ "mtpid",     XSPR(31,467,48),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtpid",     XSPR(31,467,945),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtdecar",   XSPR(31,467,54),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtcsrr0",   XSPR(31,467,58),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtcsrr1",   XSPR(31,467,59),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtdear",    XSPR(31,467,61),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtdear",    XSPR(31,467,981),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtesr",     XSPR(31,467,62),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtesr",     XSPR(31,467,980),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtivpr",    XSPR(31,467,63),   XSPR_MASK, BOOKE,     { RS } },
+{ "mtcmpa",    XSPR(31,467,144),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpb",    XSPR(31,467,145),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpc",    XSPR(31,467,146),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpd",    XSPR(31,467,147),  XSPR_MASK, PPC860,	{ RS } },
+{ "mticr",     XSPR(31,467,148),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtder",     XSPR(31,467,149),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcounta",  XSPR(31,467,150),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcountb",  XSPR(31,467,151),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpe",    XSPR(31,467,152),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpf",    XSPR(31,467,153),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmpg",    XSPR(31,467,154),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtcmph",    XSPR(31,467,155),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtlctrl1",  XSPR(31,467,156),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtlctrl2",  XSPR(31,467,157),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtictrl",   XSPR(31,467,158),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtbar",     XSPR(31,467,159),  XSPR_MASK, PPC860,	{ RS } },
+{ "mtvrsave",  XSPR(31,467,256),  XSPR_MASK, PPCVEC,	{ RS } },
+{ "mtusprg0",  XSPR(31,467,256),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtsprg",    XSPR(31,467,256),  XSPRG_MASK,PPC,	{ SPRG, RS } },
+{ "mtsprg0",   XSPR(31,467,272),  XSPR_MASK, PPC,	{ RS } },
+{ "mtsprg1",   XSPR(31,467,273),  XSPR_MASK, PPC,	{ RS } },
+{ "mtsprg2",   XSPR(31,467,274),  XSPR_MASK, PPC,	{ RS } },
+{ "mtsprg3",   XSPR(31,467,275),  XSPR_MASK, PPC,	{ RS } },
+{ "mtsprg4",   XSPR(31,467,276),  XSPR_MASK, PPC405 | BOOKE, { RS } },
+{ "mtsprg5",   XSPR(31,467,277),  XSPR_MASK, PPC405 | BOOKE, { RS } },
+{ "mtsprg6",   XSPR(31,467,278),  XSPR_MASK, PPC405 | BOOKE, { RS } },
+{ "mtsprg7",   XSPR(31,467,279),  XSPR_MASK, PPC405 | BOOKE, { RS } },
+{ "mtasr",     XSPR(31,467,280),  XSPR_MASK, PPC64,	{ RS } },
+{ "mtear",     XSPR(31,467,282),  XSPR_MASK, PPC,	{ RS } },
+{ "mttbl",     XSPR(31,467,284),  XSPR_MASK, PPC,	{ RS } },
+{ "mttbu",     XSPR(31,467,285),  XSPR_MASK, PPC,	{ RS } },
+{ "mtdbsr",    XSPR(31,467,304),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdbsr",    XSPR(31,467,1008), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdbcr0",   XSPR(31,467,308),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdbcr0",   XSPR(31,467,1010), XSPR_MASK, PPC405,	{ RS } },
+{ "mtdbcr1",   XSPR(31,467,309),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdbcr1",   XSPR(31,467,957),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtdbcr2",   XSPR(31,467,310),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac1",    XSPR(31,467,312),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac1",    XSPR(31,467,1012), XSPR_MASK, PPC403,	{ RS } },
+{ "mtiac2",    XSPR(31,467,313),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac2",    XSPR(31,467,1013), XSPR_MASK, PPC403,	{ RS } },
+{ "mtiac3",    XSPR(31,467,314),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac3",    XSPR(31,467,948),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtiac4",    XSPR(31,467,315),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtiac4",    XSPR(31,467,949),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtdac1",    XSPR(31,467,316),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdac1",    XSPR(31,467,1014), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdac2",    XSPR(31,467,317),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdac2",    XSPR(31,467,1015), XSPR_MASK, PPC403,	{ RS } },
+{ "mtdvc1",    XSPR(31,467,318),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdvc1",    XSPR(31,467,950),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtdvc2",    XSPR(31,467,319),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtdvc2",    XSPR(31,467,951),  XSPR_MASK, PPC405,	{ RS } },
+{ "mttsr",     XSPR(31,467,336),  XSPR_MASK, BOOKE,     { RS } },
+{ "mttsr",     XSPR(31,467,984),  XSPR_MASK, PPC403,	{ RS } },
+{ "mttcr",     XSPR(31,467,340),  XSPR_MASK, BOOKE,     { RS } },
+{ "mttcr",     XSPR(31,467,986),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtivor0",   XSPR(31,467,400),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor1",   XSPR(31,467,401),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor2",   XSPR(31,467,402),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor3",   XSPR(31,467,403),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor4",   XSPR(31,467,404),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor5",   XSPR(31,467,405),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor6",   XSPR(31,467,406),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor7",   XSPR(31,467,407),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor8",   XSPR(31,467,408),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor9",   XSPR(31,467,409),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor10",  XSPR(31,467,410),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor11",  XSPR(31,467,411),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor12",  XSPR(31,467,412),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor13",  XSPR(31,467,413),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor14",  XSPR(31,467,414),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtivor15",  XSPR(31,467,415),  XSPR_MASK, BOOKE,     { RS } },
+{ "mtspefscr",  XSPR(31,467,512),  XSPR_MASK, PPCSPE,   { RS } },
+{ "mtbbear",   XSPR(31,467,513),  XSPR_MASK, PPCBRLK,   { RS } },
+{ "mtbbtar",   XSPR(31,467,514),  XSPR_MASK, PPCBRLK,  { RS } },
+{ "mtivor32",  XSPR(31,467,528),  XSPR_MASK, PPCSPE,	{ RS } },
+{ "mtivor33",  XSPR(31,467,529),  XSPR_MASK, PPCSPE,	{ RS } },
+{ "mtivor34",  XSPR(31,467,530),  XSPR_MASK, PPCSPE,	{ RS } },
+{ "mtivor35",  XSPR(31,467,531),  XSPR_MASK, PPCPMR,	{ RS } },
+{ "mtibatu",   XSPR(31,467,528),  XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtibatl",   XSPR(31,467,529),  XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtdbatu",   XSPR(31,467,536),  XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtdbatl",   XSPR(31,467,537),  XSPRBAT_MASK, PPC,	{ SPRBAT, RS } },
+{ "mtmcsrr0",  XSPR(31,467,570),  XSPR_MASK, PPCRFMCI,  { RS } },
+{ "mtmcsrr1",  XSPR(31,467,571),  XSPR_MASK, PPCRFMCI,  { RS } },
+{ "mtmcsr",    XSPR(31,467,572),  XSPR_MASK, PPCRFMCI,  { RS } },
+{ "mtummcr0",  XSPR(31,467,936),  XSPR_MASK, PPC750,    { RS } },
+{ "mtupmc1",   XSPR(31,467,937),  XSPR_MASK, PPC750,    { RS } },
+{ "mtupmc2",   XSPR(31,467,938),  XSPR_MASK, PPC750,    { RS } },
+{ "mtusia",    XSPR(31,467,939),  XSPR_MASK, PPC750,    { RS } },
+{ "mtummcr1",  XSPR(31,467,940),  XSPR_MASK, PPC750,    { RS } },
+{ "mtupmc3",   XSPR(31,467,941),  XSPR_MASK, PPC750,    { RS } },
+{ "mtupmc4",   XSPR(31,467,942),  XSPR_MASK, PPC750,    { RS } },
+{ "mtzpr",     XSPR(31,467,944),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtccr0",    XSPR(31,467,947),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtmmcr0",   XSPR(31,467,952),  XSPR_MASK, PPC750,    { RS } },
+{ "mtsgr",     XSPR(31,467,953),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtpmc1",    XSPR(31,467,953),  XSPR_MASK, PPC750,    { RS } },
+{ "mtdcwr",    XSPR(31,467,954),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtpmc2",    XSPR(31,467,954),  XSPR_MASK, PPC750,    { RS } },
+{ "mtsler",    XSPR(31,467,955),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtsia",     XSPR(31,467,955),  XSPR_MASK, PPC750,    { RS } },
+{ "mtsu0r",    XSPR(31,467,956),  XSPR_MASK, PPC405,	{ RS } },
+{ "mtmmcr1",   XSPR(31,467,956),  XSPR_MASK, PPC750,    { RS } },
+{ "mtpmc3",    XSPR(31,467,957),  XSPR_MASK, PPC750,    { RS } },
+{ "mtpmc4",    XSPR(31,467,958),  XSPR_MASK, PPC750,    { RS } },
+{ "mticdbdr",  XSPR(31,467,979),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtevpr",    XSPR(31,467,982),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtcdbcr",   XSPR(31,467,983),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtpit",     XSPR(31,467,987),  XSPR_MASK, PPC403,	{ RS } },
+{ "mttbhi",    XSPR(31,467,988),  XSPR_MASK, PPC403,	{ RS } },
+{ "mttblo",    XSPR(31,467,989),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtsrr2",    XSPR(31,467,990),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtsrr3",    XSPR(31,467,991),  XSPR_MASK, PPC403,	{ RS } },
+{ "mtl2cr",    XSPR(31,467,1017), XSPR_MASK, PPC750,    { RS } },
+{ "mtdccr",    XSPR(31,467,1018), XSPR_MASK, PPC403,	{ RS } },
+{ "mticcr",    XSPR(31,467,1019), XSPR_MASK, PPC403,	{ RS } },
+{ "mtictc",    XSPR(31,467,1019), XSPR_MASK, PPC750,    { RS } },
+{ "mtpbl1",    XSPR(31,467,1020), XSPR_MASK, PPC403,	{ RS } },
+{ "mtthrm1",   XSPR(31,467,1020), XSPR_MASK, PPC750,    { RS } },
+{ "mtpbu1",    XSPR(31,467,1021), XSPR_MASK, PPC403,	{ RS } },
+{ "mtthrm2",   XSPR(31,467,1021), XSPR_MASK, PPC750,    { RS } },
+{ "mtpbl2",    XSPR(31,467,1022), XSPR_MASK, PPC403,	{ RS } },
+{ "mtthrm3",   XSPR(31,467,1022), XSPR_MASK, PPC750,    { RS } },
+{ "mtpbu2",    XSPR(31,467,1023), XSPR_MASK, PPC403,	{ RS } },
+{ "mtspr",     X(31,467),	  X_MASK,    COM,	{ SPR, RS } },
 
 { "dcbi",    X(31,470),	XRT_MASK,	PPC,		{ RA, RB } },
 
-{ "nand",    XRC(31,476,0), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
-{ "nand.",   XRC(31,476,1), X_MASK,	PPC|POWER,	{ RA, RS, RB } },
+{ "nand",    XRC(31,476,0), X_MASK,	COM,		{ RA, RS, RB } },
+{ "nand.",   XRC(31,476,1), X_MASK,	COM,		{ RA, RS, RB } },
 
-{ "nabs",    XO(31,488,0,0), XORB_MASK, POWER|M601,	{ RT, RA } },
-{ "nabs.",   XO(31,488,0,1), XORB_MASK, POWER|M601,	{ RT, RA } },
-{ "nabso",   XO(31,488,1,0), XORB_MASK, POWER|M601,	{ RT, RA } },
-{ "nabso.",  XO(31,488,1,1), XORB_MASK, POWER|M601,	{ RT, RA } },
+{ "dcbie",   X(31,478),	XRT_MASK,	BOOKE64,	{ RA, RB } },
 
-{ "divd",    XO(31,489,0,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "divd.",   XO(31,489,0,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "divdo",   XO(31,489,1,0), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
-{ "divdo.",  XO(31,489,1,1), XO_MASK,	PPC|B64,	{ RT, RA, RB } },
+{ "dcread",  X(31,486),	X_MASK,		PPC403|PPC440,	{ RT, RA, RB }},
+
+{ "mtpmr",   X(31,462),	X_MASK,		PPCPMR,		{ PMR, RS }},
+
+{ "icbtls",  X(31,486),	X_MASK,		PPCCHLK,	{ CT, RA, RB }},
+
+{ "nabs",    XO(31,488,0,0), XORB_MASK, M601,		{ RT, RA } },
+{ "subfme64",XO(31,488,0,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "nabs.",   XO(31,488,0,1), XORB_MASK, M601,		{ RT, RA } },
+{ "nabso",   XO(31,488,1,0), XORB_MASK, M601,		{ RT, RA } },
+{ "subfme64o",XO(31,488,1,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "nabso.",  XO(31,488,1,1), XORB_MASK, M601,		{ RT, RA } },
+
+{ "divd",    XO(31,489,0,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divd.",   XO(31,489,0,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdo",   XO(31,489,1,0), XO_MASK,	PPC64,		{ RT, RA, RB } },
+{ "divdo.",  XO(31,489,1,1), XO_MASK,	PPC64,		{ RT, RA, RB } },
+
+{ "addme64", XO(31,490,0,0), XORB_MASK, BOOKE64,	{ RT, RA } },
+{ "addme64o",XO(31,490,1,0), XORB_MASK, BOOKE64,	{ RT, RA } },
 
 { "divw",    XO(31,491,0,0), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "divw.",   XO(31,491,0,1), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "divwo",   XO(31,491,1,0), XO_MASK,	PPC,		{ RT, RA, RB } },
 { "divwo.",  XO(31,491,1,1), XO_MASK,	PPC,		{ RT, RA, RB } },
 
-{ "slbia",   X(31,498),	0xffffffff,	PPC|B64,	{ 0 } },
+{ "icbtlse", X(31,494),	X_MASK,		PPCCHLK64,	{ CT, RA, RB }},
+
+{ "slbia",   X(31,498),	0xffffffff,	PPC64,		{ 0 } },
 
 { "cli",     X(31,502), XRB_MASK,	POWER,		{ RT, RA } },
 
-{ "mcrxr",   X(31,512),	XRARB_MASK|(3<<21), PPC|POWER,	{ BF } },
+{ "stdcxe.", XRC(31,511,1), X_MASK,	BOOKE64,	{ RS, RA, RB } },
 
-{ "clcs",    X(31,531), XRB_MASK,	POWER|M601,	{ RT, RA } },
+{ "mcrxr",   X(31,512),	XRARB_MASK|(3<<21), COM,	{ BF } },
 
-{ "lswx",    X(31,533),	X_MASK,		PPC,		{ RT, RA, RB } },
-{ "lsx",     X(31,533),	X_MASK,		POWER,		{ RT, RA, RB } },
+{ "bblels",  X(31,518),	X_MASK,		PPCBRLK,	{ 0 }},
+{ "mcrxr64", X(31,544),	XRARB_MASK|(3<<21), BOOKE64,	{ BF } },
 
-{ "lwbrx",   X(31,534),	X_MASK,		PPC,		{ RT, RA, RB } },
-{ "lbrx",    X(31,534),	X_MASK,		POWER,		{ RT, RA, RB } },
+{ "clcs",    X(31,531), XRB_MASK,	M601,		{ RT, RA } },
 
-{ "lfsx",    X(31,535),	X_MASK,		PPC|POWER,	{ FRT, RA, RB } },
+{ "ldbrx",   X(31,532),	X_MASK,		CELL,		{ RT, RA0, RB } },
 
-{ "srw",     XRC(31,536,0), X_MASK,	PPC,		{ RA, RS, RB } },
-{ "sr",      XRC(31,536,0), X_MASK,	POWER,		{ RA, RS, RB } },
-{ "srw.",    XRC(31,536,1), X_MASK,	PPC,		{ RA, RS, RB } },
-{ "sr.",     XRC(31,536,1), X_MASK,	POWER,		{ RA, RS, RB } },
+{ "lswx",    X(31,533),	X_MASK,		PPCCOM,		{ RT, RA0, RB } },
+{ "lsx",     X(31,533),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
 
-{ "rrib",    XRC(31,537,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "rrib.",   XRC(31,537,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "lwbrx",   X(31,534),	X_MASK,		PPCCOM,		{ RT, RA0, RB } },
+{ "lbrx",    X(31,534),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
 
-{ "srd",     XRC(31,539,0), X_MASK,	PPC|B64,	{ RA, RS, RB } },
-{ "srd.",    XRC(31,539,1), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+{ "lfsx",    X(31,535),	X_MASK,		COM,		{ FRT, RA0, RB } },
 
-{ "maskir",  XRC(31,541,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "maskir.", XRC(31,541,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "srw",     XRC(31,536,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sr",      XRC(31,536,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "srw.",    XRC(31,536,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sr.",     XRC(31,536,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+
+{ "rrib",    XRC(31,537,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "rrib.",   XRC(31,537,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "srd",     XRC(31,539,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "srd.",    XRC(31,539,1), X_MASK,	PPC64,		{ RA, RS, RB } },
+
+{ "maskir",  XRC(31,541,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "maskir.", XRC(31,541,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "lwbrxe",  X(31,542),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "lfsxe",   X(31,543),	X_MASK,		BOOKE64,	{ FRT, RA0, RB } },
+
+{ "bbelr",   X(31,550),	X_MASK,		PPCBRLK,	{ 0 }},
 
 { "tlbsync", X(31,566),	0xffffffff,	PPC,		{ 0 } },
 
-{ "lfsux",   X(31,567),	X_MASK,		PPC|POWER,	{ FRT, RAS, RB } },
+{ "lfsux",   X(31,567),	X_MASK,		COM,		{ FRT, RAS, RB } },
 
-{ "mfsr",    X(31,595),	XRB_MASK|(1<<20), PPC|POWER|B32, { RT, SR } },
+{ "lfsuxe",  X(31,575),	X_MASK,		BOOKE64,	{ FRT, RAS, RB } },
 
-{ "lswi",    X(31,597),	X_MASK,		PPC,		{ RT, RA, NB } },
-{ "lsi",     X(31,597),	X_MASK,		POWER,		{ RT, RA, NB } },
+{ "mfsr",    X(31,595),	XRB_MASK|(1<<20), COM32,	{ RT, SR } },
 
-{ "sync",    X(31,598), 0xffffffff,	PPC,		{ 0 } },
-{ "dcs",     X(31,598), 0xffffffff,	POWER,		{ 0 } },
+{ "lswi",    X(31,597),	X_MASK,		PPCCOM,		{ RT, RA0, NB } },
+{ "lsi",     X(31,597),	X_MASK,		PWRCOM,		{ RT, RA0, NB } },
 
-{ "lfdx",    X(31,599), X_MASK,		PPC|POWER,	{ FRT, RA, RB } },
+{ "lwsync",  XSYNC(31,598,1), 0xffffffff, PPC,		{ 0 } },
+{ "ptesync", XSYNC(31,598,2), 0xffffffff, PPC64,	{ 0 } },
+{ "msync",   X(31,598), 0xffffffff,	BOOKE,		{ 0 } },
+{ "sync",    X(31,598), XSYNC_MASK,	PPCCOM,		{ LS } },
+{ "dcs",     X(31,598), 0xffffffff,	PWRCOM,		{ 0 } },
 
-{ "mfsri",   X(31,627), X_MASK,		POWER,		{ RT, RA, RB } },
+{ "lfdx",    X(31,599), X_MASK,		COM,		{ FRT, RA0, RB } },
 
-{ "dclst",   X(31,630), XRB_MASK,	POWER,		{ RS, RA } },
+{ "lfdxe",   X(31,607), X_MASK,		BOOKE64,	{ FRT, RA0, RB } },
 
-{ "lfdux",   X(31,631), X_MASK,		PPC|POWER,	{ FRT, RAS, RB } },
+{ "mffgpr",  XRC(31,607,0), XRA_MASK,	POWER6,		{ FRT, RB } },
 
-{ "mfsrin",  X(31,659), XRA_MASK,	PPC|B32,	{ RT, RB } },
+{ "mfsri",   X(31,627), X_MASK,		PWRCOM,		{ RT, RA, RB } },
 
-{ "stswx",   X(31,661), X_MASK,		PPC,		{ RS, RA, RB } },
-{ "stsx",    X(31,661), X_MASK,		POWER,		{ RS, RA, RB } },
+{ "dclst",   X(31,630), XRB_MASK,	PWRCOM,		{ RS, RA } },
 
-{ "stwbrx",  X(31,662), X_MASK,		PPC,		{ RS, RA, RB } },
-{ "stbrx",   X(31,662), X_MASK,		POWER,		{ RS, RA, RB } },
+{ "lfdux",   X(31,631), X_MASK,		COM,		{ FRT, RAS, RB } },
 
-{ "stfsx",   X(31,663), X_MASK,		PPC|POWER,	{ FRS, RA, RB } },
+{ "lfduxe",  X(31,639), X_MASK,		BOOKE64,	{ FRT, RAS, RB } },
 
-{ "srq",     XRC(31,664,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "srq.",    XRC(31,664,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "mfsrin",  X(31,659), XRA_MASK,	PPC32,		{ RT, RB } },
 
-{ "sre",     XRC(31,665,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "sre.",    XRC(31,665,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "stdbrx",  X(31,660), X_MASK,		CELL,		{ RS, RA0, RB } },
 
-{ "stfsux",  X(31,695),	X_MASK,		PPC|POWER,	{ FRS, RAS, RB } },
+{ "stswx",   X(31,661), X_MASK,		PPCCOM,		{ RS, RA0, RB } },
+{ "stsx",    X(31,661), X_MASK,		PWRCOM,		{ RS, RA0, RB } },
 
-{ "sriq",    XRC(31,696,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
-{ "sriq.",   XRC(31,696,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "stwbrx",  X(31,662), X_MASK,		PPCCOM,		{ RS, RA0, RB } },
+{ "stbrx",   X(31,662), X_MASK,		PWRCOM,		{ RS, RA0, RB } },
 
-{ "stswi",   X(31,725),	X_MASK,		PPC,		{ RS, RA, NB } },
-{ "stsi",    X(31,725),	X_MASK,		POWER,		{ RS, RA, NB } },
+{ "stfsx",   X(31,663), X_MASK,		COM,		{ FRS, RA0, RB } },
 
-{ "stfdx",   X(31,727),	X_MASK,		PPC|POWER,	{ FRS, RA, RB } },
+{ "srq",     XRC(31,664,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srq.",    XRC(31,664,1), X_MASK,	M601,		{ RA, RS, RB } },
 
-{ "srlq",    XRC(31,728,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "srlq.",   XRC(31,728,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "sre",     XRC(31,665,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sre.",    XRC(31,665,1), X_MASK,	M601,		{ RA, RS, RB } },
 
-{ "sreq",    XRC(31,729,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "sreq.",   XRC(31,729,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "stwbrxe", X(31,670), X_MASK,		BOOKE64,	{ RS, RA0, RB } },
 
-{ "stfdux",  X(31,759),	X_MASK,		PPC|POWER,	{ FRS, RAS, RB } },
+{ "stfsxe",  X(31,671), X_MASK,		BOOKE64,	{ FRS, RA0, RB } },
 
-{ "srliq",   XRC(31,760,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
-{ "srliq.",  XRC(31,760,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "stfsux",  X(31,695),	X_MASK,		COM,		{ FRS, RAS, RB } },
 
-{ "lhbrx",   X(31,790),	X_MASK,		PPC|POWER,	{ RT, RA, RB } },
+{ "sriq",    XRC(31,696,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sriq.",   XRC(31,696,1), X_MASK,	M601,		{ RA, RS, SH } },
 
-{ "sraw",    XRC(31,792,0), X_MASK,	PPC,		{ RA, RS, RB } },
-{ "sra",     XRC(31,792,0), X_MASK,	POWER,		{ RA, RS, RB } },
-{ "sraw.",   XRC(31,792,1), X_MASK,	PPC,		{ RA, RS, RB } },
-{ "sra.",    XRC(31,792,1), X_MASK,	POWER,		{ RA, RS, RB } },
+{ "stfsuxe", X(31,703),	X_MASK,		BOOKE64,	{ FRS, RAS, RB } },
 
-{ "srad",    XRC(31,794,0), X_MASK,	PPC|B64,	{ RA, RS, RB } },
-{ "srad.",   XRC(31,794,1), X_MASK,	PPC|B64,	{ RA, RS, RB } },
+{ "stswi",   X(31,725),	X_MASK,		PPCCOM,		{ RS, RA0, NB } },
+{ "stsi",    X(31,725),	X_MASK,		PWRCOM,		{ RS, RA0, NB } },
 
-{ "rac",     X(31,818),	X_MASK,		POWER,		{ RT, RA, RB } },
+{ "stfdx",   X(31,727),	X_MASK,		COM,		{ FRS, RA0, RB } },
 
-{ "srawi",   XRC(31,824,0), X_MASK,	PPC,		{ RA, RS, SH } },
-{ "srai",    XRC(31,824,0), X_MASK,	POWER,		{ RA, RS, SH } },
-{ "srawi.",  XRC(31,824,1), X_MASK,	PPC,		{ RA, RS, SH } },
-{ "srai.",   XRC(31,824,1), X_MASK,	POWER,		{ RA, RS, SH } },
+{ "srlq",    XRC(31,728,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srlq.",   XRC(31,728,1), X_MASK,	M601,		{ RA, RS, RB } },
 
+{ "sreq",    XRC(31,729,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sreq.",   XRC(31,729,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "stfdxe",  X(31,735),	X_MASK,		BOOKE64,	{ FRS, RA0, RB } },
+
+{ "mftgpr",  XRC(31,735,0), XRA_MASK,	POWER6,		{ RT, FRB } },
+
+{ "dcba",    X(31,758),	XRT_MASK,	PPC405 | BOOKE,	{ RA, RB } },
+
+{ "stfdux",  X(31,759),	X_MASK,		COM,		{ FRS, RAS, RB } },
+
+{ "srliq",   XRC(31,760,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "srliq.",  XRC(31,760,1), X_MASK,	M601,		{ RA, RS, SH } },
+
+{ "dcbae",   X(31,766),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+
+{ "stfduxe", X(31,767),	X_MASK,		BOOKE64,	{ FRS, RAS, RB } },
+
+{ "tlbivax", X(31,786),	XRT_MASK,	BOOKE,		{ RA, RB } },
+{ "tlbivaxe",X(31,787),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+
+{ "lwzcix",  X(31,789),	X_MASK,		POWER6,		{ RT, RA0, RB } },
+
+{ "lhbrx",   X(31,790),	X_MASK,		COM,		{ RT, RA0, RB } },
+
+{ "sraw",    XRC(31,792,0), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sra",     XRC(31,792,0), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+{ "sraw.",   XRC(31,792,1), X_MASK,	PPCCOM,		{ RA, RS, RB } },
+{ "sra.",    XRC(31,792,1), X_MASK,	PWRCOM,		{ RA, RS, RB } },
+
+{ "srad",    XRC(31,794,0), X_MASK,	PPC64,		{ RA, RS, RB } },
+{ "srad.",   XRC(31,794,1), X_MASK,	PPC64,		{ RA, RS, RB } },
+
+{ "lhbrxe",  X(31,798),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "ldxe",    X(31,799),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+{ "lduxe",   X(31,831),	X_MASK,		BOOKE64,	{ RT, RA0, RB } },
+
+{ "rac",     X(31,818),	X_MASK,		PWRCOM,		{ RT, RA, RB } },
+
+{ "lhzcix",  X(31,821),	X_MASK,		POWER6,		{ RT, RA0, RB } },
+
+{ "dss",     XDSS(31,822,0), XDSS_MASK,	PPCVEC,		{ STRM } },
+{ "dssall",  XDSS(31,822,1), XDSS_MASK,	PPCVEC,		{ 0 } },
+
+{ "srawi",   XRC(31,824,0), X_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "srai",    XRC(31,824,0), X_MASK,	PWRCOM,		{ RA, RS, SH } },
+{ "srawi.",  XRC(31,824,1), X_MASK,	PPCCOM,		{ RA, RS, SH } },
+{ "srai.",   XRC(31,824,1), X_MASK,	PWRCOM,		{ RA, RS, SH } },
+
+{ "slbmfev", X(31,851), XRA_MASK,	PPC64,		{ RT, RB } },
+
+{ "lbzcix",  X(31,853),	X_MASK,		POWER6,		{ RT, RA0, RB } },
+
+{ "mbar",    X(31,854),	X_MASK,		BOOKE,		{ MO } },
 { "eieio",   X(31,854),	0xffffffff,	PPC,		{ 0 } },
 
-{ "sthbrx",  X(31,918),	X_MASK,		PPC|POWER,	{ RS, RA, RB } },
+{ "lfiwax",  X(31,855),	X_MASK,		POWER6,		{ FRT, RA0, RB } },
 
-{ "sraq",    XRC(31,920,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "sraq.",   XRC(31,920,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "ldcix",   X(31,885),	X_MASK,		POWER6,		{ RT, RA0, RB } },
 
-{ "srea",    XRC(31,921,0), X_MASK,	POWER|M601,	{ RA, RS, RB } },
-{ "srea.",   XRC(31,921,1), X_MASK,	POWER|M601,	{ RA, RS, RB } },
+{ "tlbsx",   XRC(31,914,0), X_MASK, 	PPC403|BOOKE,	{ RTO, RA, RB } },
+{ "tlbsx.",  XRC(31,914,1), X_MASK, 	PPC403|BOOKE,	{ RTO, RA, RB } },
+{ "tlbsxe",  XRC(31,915,0), X_MASK,	BOOKE64,	{ RTO, RA, RB } },
+{ "tlbsxe.", XRC(31,915,1), X_MASK,	BOOKE64,	{ RTO, RA, RB } },
 
-{ "extsh",   XRC(31,922,0), XRB_MASK,	PPC,		{ RA, RS } },
-{ "exts",    XRC(31,922,0), XRB_MASK,	POWER,		{ RA, RS } },
-{ "extsh.",  XRC(31,922,1), XRB_MASK,	PPC,		{ RA, RS } },
-{ "exts.",   XRC(31,922,1), XRB_MASK,	POWER,		{ RA, RS } },
+{ "slbmfee", X(31,915), XRA_MASK,	PPC64,		{ RT, RB } },
 
-{ "sraiq",   XRC(31,952,0), X_MASK,	POWER|M601,	{ RA, RS, SH } },
-{ "sraiq.",  XRC(31,952,1), X_MASK,	POWER|M601,	{ RA, RS, SH } },
+{ "stwcix",  X(31,917),	X_MASK,		POWER6,		{ RS, RA0, RB } },
+
+{ "sthbrx",  X(31,918),	X_MASK,		COM,		{ RS, RA0, RB } },
+
+{ "sraq",    XRC(31,920,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "sraq.",   XRC(31,920,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "srea",    XRC(31,921,0), X_MASK,	M601,		{ RA, RS, RB } },
+{ "srea.",   XRC(31,921,1), X_MASK,	M601,		{ RA, RS, RB } },
+
+{ "extsh",   XRC(31,922,0), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "exts",    XRC(31,922,0), XRB_MASK,	PWRCOM,		{ RA, RS } },
+{ "extsh.",  XRC(31,922,1), XRB_MASK,	PPCCOM,		{ RA, RS } },
+{ "exts.",   XRC(31,922,1), XRB_MASK,	PWRCOM,		{ RA, RS } },
+
+{ "sthbrxe", X(31,926),	X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "stdxe",   X(31,927), X_MASK,		BOOKE64,	{ RS, RA0, RB } },
+
+{ "tlbrehi", XTLB(31,946,0), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbrelo", XTLB(31,946,1), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbre",   X(31,946),	X_MASK,		PPC403|BOOKE,	{ RSO, RAOPT, SHO } },
+
+{ "sthcix",  X(31,949),	X_MASK,		POWER6,		{ RS, RA0, RB } },
+
+{ "sraiq",   XRC(31,952,0), X_MASK,	M601,		{ RA, RS, SH } },
+{ "sraiq.",  XRC(31,952,1), X_MASK,	M601,		{ RA, RS, SH } },
 
 { "extsb",   XRC(31,954,0), XRB_MASK,	PPC,		{ RA, RS} },
 { "extsb.",  XRC(31,954,1), XRB_MASK,	PPC,		{ RA, RS} },
 
-{ "iccci",   X(31,966),	XRT_MASK,	PPC,		{ RA, RB } },
+{ "stduxe",  X(31,959),	X_MASK,		BOOKE64,	{ RS, RAS, RB } },
+
+{ "iccci",   X(31,966),	XRT_MASK,	PPC403|PPC440,	{ RA, RB } },
+
+{ "tlbwehi", XTLB(31,978,0), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbwelo", XTLB(31,978,1), XTLB_MASK,	PPC403,		{ RT, RA } },
+{ "tlbwe",   X(31,978),	X_MASK,		PPC403|BOOKE,	{ RSO, RAOPT, SHO } },
+{ "tlbld",   X(31,978),	XRTRA_MASK,	PPC,		{ RB } },
+
+{ "stbcix",  X(31,981),	X_MASK,		POWER6,		{ RS, RA0, RB } },
 
 { "icbi",    X(31,982),	XRT_MASK,	PPC,		{ RA, RB } },
 
-{ "stfiwx",  X(31,983),	X_MASK,		PPC,		{ FRS, RA, RB } },
+{ "stfiwx",  X(31,983),	X_MASK,		PPC,		{ FRS, RA0, RB } },
 
-{ "extsw",   XRC(31,986,0), XRB_MASK,	PPC,		{ RA, RS } },
-{ "extsw.",  XRC(31,986,1), XRB_MASK,	PPC,		{ RA, RS } },
+{ "extsw",   XRC(31,986,0), XRB_MASK,	PPC64 | BOOKE64,{ RA, RS } },
+{ "extsw.",  XRC(31,986,1), XRB_MASK,	PPC64,		{ RA, RS } },
 
+{ "icread",  X(31,998),	XRT_MASK,	PPC403|PPC440,	{ RA, RB } },
+
+{ "icbie",   X(31,990),	XRT_MASK,	BOOKE64,	{ RA, RB } },
+{ "stfiwxe", X(31,991),	X_MASK,		BOOKE64,	{ FRS, RA0, RB } },
+
+{ "tlbli",   X(31,1010), XRTRA_MASK,	PPC,		{ RB } },
+
+{ "stdcix",  X(31,1013), X_MASK,	POWER6,		{ RS, RA0, RB } },
+
+{ "dcbzl",   XOPL(31,1014,1), XRT_MASK,POWER4,            { RA, RB } },
 { "dcbz",    X(31,1014), XRT_MASK,	PPC,		{ RA, RB } },
 { "dclz",    X(31,1014), XRT_MASK,	PPC,		{ RA, RB } },
 
-{ "lwz",     OP(32),	OP_MASK,	PPC,		{ RT, D, RA } },
-{ "l",	     OP(32),	OP_MASK,	POWER,		{ RT, D, RA } },
+{ "dcbze",   X(31,1022), XRT_MASK,	BOOKE64,	{ RA, RB } },
 
-{ "lwzu",    OP(33),	OP_MASK,	PPC,		{ RT, D, RAL } },
-{ "lu",      OP(33),	OP_MASK,	POWER,		{ RT, D, RA } },
+{ "lvebx",   X(31,   7), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvehx",   X(31,  39), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvewx",   X(31,  71), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvsl",    X(31,   6), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvsr",    X(31,  38), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvx",     X(31, 103), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "lvxl",    X(31, 359), X_MASK,	PPCVEC,		{ VD, RA, RB } },
+{ "stvebx",  X(31, 135), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvehx",  X(31, 167), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvewx",  X(31, 199), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvx",    X(31, 231), X_MASK,	PPCVEC,		{ VS, RA, RB } },
+{ "stvxl",   X(31, 487), X_MASK,	PPCVEC,		{ VS, RA, RB } },
 
-{ "lbz",     OP(34),	OP_MASK,	PPC|POWER,	{ RT, D, RA } },
+/* New load/store left/right index vector instructions that are in the Cell only.  */
+{ "lvlx",    X(31, 519), X_MASK,	CELL,		{ VD, RA0, RB } },
+{ "lvlxl",   X(31, 775), X_MASK,	CELL,		{ VD, RA0, RB } },
+{ "lvrx",    X(31, 551), X_MASK,	CELL,		{ VD, RA0, RB } },
+{ "lvrxl",   X(31, 807), X_MASK,	CELL,		{ VD, RA0, RB } },
+{ "stvlx",   X(31, 647), X_MASK,	CELL,		{ VS, RA0, RB } },
+{ "stvlxl",  X(31, 903), X_MASK,	CELL,		{ VS, RA0, RB } },
+{ "stvrx",   X(31, 679), X_MASK,	CELL,		{ VS, RA0, RB } },
+{ "stvrxl",  X(31, 935), X_MASK,	CELL,		{ VS, RA0, RB } },
 
-{ "lbzu",    OP(35),	OP_MASK,	PPC|POWER,	{ RT, D, RAL } },
+{ "lwz",     OP(32),	OP_MASK,	PPCCOM,		{ RT, D, RA0 } },
+{ "l",	     OP(32),	OP_MASK,	PWRCOM,		{ RT, D, RA0 } },
 
-{ "stw",     OP(36),	OP_MASK,	PPC,		{ RS, D, RA } },
-{ "st",      OP(36),	OP_MASK,	POWER,		{ RS, D, RA } },
+{ "lwzu",    OP(33),	OP_MASK,	PPCCOM,		{ RT, D, RAL } },
+{ "lu",      OP(33),	OP_MASK,	PWRCOM,		{ RT, D, RA0 } },
 
-{ "stwu",    OP(37),	OP_MASK,	PPC,		{ RS, D, RAS } },
-{ "stu",     OP(37),	OP_MASK,	POWER,		{ RS, D, RA } },
+{ "lbz",     OP(34),	OP_MASK,	COM,		{ RT, D, RA0 } },
 
-{ "stb",     OP(38),	OP_MASK,	PPC|POWER,	{ RS, D, RA } },
+{ "lbzu",    OP(35),	OP_MASK,	COM,		{ RT, D, RAL } },
 
-{ "stbu",    OP(39),	OP_MASK,	PPC|POWER,	{ RS, D, RAS } },
+{ "stw",     OP(36),	OP_MASK,	PPCCOM,		{ RS, D, RA0 } },
+{ "st",      OP(36),	OP_MASK,	PWRCOM,		{ RS, D, RA0 } },
 
-{ "lhz",     OP(40),	OP_MASK,	PPC|POWER,	{ RT, D, RA } },
+{ "stwu",    OP(37),	OP_MASK,	PPCCOM,		{ RS, D, RAS } },
+{ "stu",     OP(37),	OP_MASK,	PWRCOM,		{ RS, D, RA0 } },
 
-{ "lhzu",    OP(41),	OP_MASK,	PPC|POWER,	{ RT, D, RAL } },
+{ "stb",     OP(38),	OP_MASK,	COM,		{ RS, D, RA0 } },
 
-{ "lha",     OP(42),	OP_MASK,	PPC|POWER,	{ RT, D, RA } },
+{ "stbu",    OP(39),	OP_MASK,	COM,		{ RS, D, RAS } },
 
-{ "lhau",    OP(43),	OP_MASK,	PPC|POWER,	{ RT, D, RAL } },
+{ "lhz",     OP(40),	OP_MASK,	COM,		{ RT, D, RA0 } },
 
-{ "sth",     OP(44),	OP_MASK,	PPC|POWER,	{ RS, D, RA } },
+{ "lhzu",    OP(41),	OP_MASK,	COM,		{ RT, D, RAL } },
 
-{ "sthu",    OP(45),	OP_MASK,	PPC|POWER,	{ RS, D, RAS } },
+{ "lha",     OP(42),	OP_MASK,	COM,		{ RT, D, RA0 } },
 
-{ "lmw",     OP(46),	OP_MASK,	PPC,		{ RT, D, RAM } },
-{ "lm",      OP(46),	OP_MASK,	POWER,		{ RT, D, RA } },
+{ "lhau",    OP(43),	OP_MASK,	COM,		{ RT, D, RAL } },
 
-{ "stmw",    OP(47),	OP_MASK,	PPC,		{ RS, D, RA } },
-{ "stm",     OP(47),	OP_MASK,	POWER,		{ RS, D, RA } },
+{ "sth",     OP(44),	OP_MASK,	COM,		{ RS, D, RA0 } },
 
-{ "lfs",     OP(48),	OP_MASK,	PPC|POWER,	{ FRT, D, RA } },
+{ "sthu",    OP(45),	OP_MASK,	COM,		{ RS, D, RAS } },
 
-{ "lfsu",    OP(49),	OP_MASK,	PPC|POWER,	{ FRT, D, RAS } },
+{ "lmw",     OP(46),	OP_MASK,	PPCCOM,		{ RT, D, RAM } },
+{ "lm",      OP(46),	OP_MASK,	PWRCOM,		{ RT, D, RA0 } },
 
-{ "lfd",     OP(50),	OP_MASK,	PPC|POWER,	{ FRT, D, RA } },
+{ "stmw",    OP(47),	OP_MASK,	PPCCOM,		{ RS, D, RA0 } },
+{ "stm",     OP(47),	OP_MASK,	PWRCOM,		{ RS, D, RA0 } },
 
-{ "lfdu",    OP(51),	OP_MASK,	PPC|POWER,	{ FRT, D, RAS } },
+{ "lfs",     OP(48),	OP_MASK,	COM,		{ FRT, D, RA0 } },
 
-{ "stfs",    OP(52),	OP_MASK,	PPC|POWER,	{ FRS, D, RA } },
+{ "lfsu",    OP(49),	OP_MASK,	COM,		{ FRT, D, RAS } },
 
-{ "stfsu",   OP(53),	OP_MASK,	PPC|POWER,	{ FRS, D, RAS } },
+{ "lfd",     OP(50),	OP_MASK,	COM,		{ FRT, D, RA0 } },
 
-{ "stfd",    OP(54),	OP_MASK,	PPC|POWER,	{ FRS, D, RA } },
+{ "lfdu",    OP(51),	OP_MASK,	COM,		{ FRT, D, RAS } },
 
-{ "stfdu",   OP(55),	OP_MASK,	PPC|POWER,	{ FRS, D, RAS } },
+{ "stfs",    OP(52),	OP_MASK,	COM,		{ FRS, D, RA0 } },
 
-{ "lfq",     OP(56),	OP_MASK,	POWER2,		{ FRT, D, RA } },
+{ "stfsu",   OP(53),	OP_MASK,	COM,		{ FRS, D, RAS } },
 
-{ "lfqu",    OP(57),	OP_MASK,	POWER2,		{ FRT, D, RA } },
+{ "stfd",    OP(54),	OP_MASK,	COM,		{ FRS, D, RA0 } },
 
-{ "ld",      DSO(58,0),	DS_MASK,	PPC|B64,	{ RT, DS, RA } },
+{ "stfdu",   OP(55),	OP_MASK,	COM,		{ FRS, D, RAS } },
 
-{ "ldu",     DSO(58,1), DS_MASK,	PPC|B64,	{ RT, DS, RAL } },
+{ "lq",      OP(56),	OP_MASK,	POWER4,		{ RTQ, DQ, RAQ } },
 
-{ "lwa",     DSO(58,2), DS_MASK,	PPC|B64,	{ RT, DS, RA } },
+{ "lfq",     OP(56),	OP_MASK,	POWER2,		{ FRT, D, RA0 } },
+
+{ "lfqu",    OP(57),	OP_MASK,	POWER2,		{ FRT, D, RA0 } },
+
+{ "lfdp",    OP(57),	OP_MASK,	POWER6,		{ FRT, D, RA0 } },
+
+{ "lbze",    DEO(58,0), DE_MASK,	BOOKE64,	{ RT, DE, RA0 } },
+{ "lbzue",   DEO(58,1), DE_MASK,	BOOKE64,	{ RT, DE, RAL } },
+{ "lhze",    DEO(58,2), DE_MASK,	BOOKE64,	{ RT, DE, RA0 } },
+{ "lhzue",   DEO(58,3), DE_MASK,	BOOKE64,	{ RT, DE, RAL } },
+{ "lhae",    DEO(58,4), DE_MASK,	BOOKE64,	{ RT, DE, RA0 } },
+{ "lhaue",   DEO(58,5), DE_MASK,	BOOKE64,	{ RT, DE, RAL } },
+{ "lwze",    DEO(58,6), DE_MASK,	BOOKE64,	{ RT, DE, RA0 } },
+{ "lwzue",   DEO(58,7), DE_MASK,	BOOKE64,	{ RT, DE, RAL } },
+{ "stbe",    DEO(58,8), DE_MASK,	BOOKE64,	{ RS, DE, RA0 } },
+{ "stbue",   DEO(58,9), DE_MASK,	BOOKE64,	{ RS, DE, RAS } },
+{ "sthe",    DEO(58,10), DE_MASK,	BOOKE64,	{ RS, DE, RA0 } },
+{ "sthue",   DEO(58,11), DE_MASK,	BOOKE64,	{ RS, DE, RAS } },
+{ "stwe",    DEO(58,14), DE_MASK,	BOOKE64,	{ RS, DE, RA0 } },
+{ "stwue",   DEO(58,15), DE_MASK,	BOOKE64,	{ RS, DE, RAS } },
+
+{ "ld",      DSO(58,0),	DS_MASK,	PPC64,		{ RT, DS, RA0 } },
+
+{ "ldu",     DSO(58,1), DS_MASK,	PPC64,		{ RT, DS, RAL } },
+
+{ "lwa",     DSO(58,2), DS_MASK,	PPC64,		{ RT, DS, RA0 } },
+
+{ "dadd",    XRC(59,2,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dadd.",   XRC(59,2,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "dqua",    ZRC(59,3,0), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+{ "dqua.",   ZRC(59,3,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
 
 { "fdivs",   A(59,18,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
 { "fdivs.",  A(59,18,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
@@ -2884,12 +4719,15 @@
 { "fsqrts",  A(59,22,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
 { "fsqrts.", A(59,22,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
 
-{ "fres",    A(59,24,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
-{ "fres.",   A(59,24,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "fres",    A(59,24,0), AFRALFRC_MASK,	PPC,		{ FRT, FRB, A_L } },
+{ "fres.",   A(59,24,1), AFRALFRC_MASK,	PPC,		{ FRT, FRB, A_L } },
 
 { "fmuls",   A(59,25,0), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
 { "fmuls.",  A(59,25,1), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
 
+{ "frsqrtes", A(59,26,0), AFRALFRC_MASK,POWER5,		{ FRT, FRB, A_L } },
+{ "frsqrtes.",A(59,26,1), AFRALFRC_MASK,POWER5,		{ FRT, FRB, A_L } },
+
 { "fmsubs",  A(59,28,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
 { "fmsubs.", A(59,28,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
 
@@ -2902,117 +4740,277 @@
 { "fnmadds", A(59,31,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
 { "fnmadds.",A(59,31,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
 
+{ "dmul",    XRC(59,34,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dmul.",   XRC(59,34,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "drrnd",   ZRC(59,35,0), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+{ "drrnd.",  ZRC(59,35,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+
+{ "dscli",   ZRC(59,66,0), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+{ "dscli.",  ZRC(59,66,1), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+
+{ "dquai",   ZRC(59,67,0), Z2_MASK,	POWER6,		{ TE,  FRT, FRB, RMC } },
+{ "dquai.",  ZRC(59,67,1), Z2_MASK,	POWER6,		{ TE,  FRT, FRB, RMC } },
+
+{ "dscri",   ZRC(59,98,0), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+{ "dscri.",  ZRC(59,98,1), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+
+{ "drintx",  ZRC(59,99,0), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+{ "drintx.", ZRC(59,99,1), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+
+{ "dcmpo",   X(59,130),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "dtstex",  X(59,162),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+{ "dtstdc",  Z(59,194),	   Z_MASK,	POWER6,		{ BF,  FRA, DCM } },
+{ "dtstdg",  Z(59,226),	   Z_MASK,	POWER6,		{ BF,  FRA, DGM } },
+
+{ "drintn",  ZRC(59,227,0), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+{ "drintn.", ZRC(59,227,1), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+
+{ "dctdp",   XRC(59,258,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dctdp.",  XRC(59,258,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "dctfix",  XRC(59,290,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dctfix.", XRC(59,290,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "ddedpd",  XRC(59,322,0), X_MASK,	POWER6,		{ SP, FRT, FRB } },
+{ "ddedpd.", XRC(59,322,1), X_MASK,	POWER6,		{ SP, FRT, FRB } },
+
+{ "dxex",    XRC(59,354,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dxex.",   XRC(59,354,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "dsub",    XRC(59,514,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dsub.",   XRC(59,514,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "ddiv",    XRC(59,546,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "ddiv.",   XRC(59,546,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "dcmpu",   X(59,642),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "dtstsf",  X(59,674),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "drsp",    XRC(59,770,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "drsp.",   XRC(59,770,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "dcffix",  XRC(59,802,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dcffix.", XRC(59,802,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "denbcd",  XRC(59,834,0), X_MASK,	POWER6,		{ S, FRT, FRB } },
+{ "denbcd.", XRC(59,834,1), X_MASK,	POWER6,		{ S, FRT, FRB } },
+
+{ "diex",    XRC(59,866,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "diex.",   XRC(59,866,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
 { "stfq",    OP(60),	OP_MASK,	POWER2,		{ FRS, D, RA } },
 
 { "stfqu",   OP(61),	OP_MASK,	POWER2,		{ FRS, D, RA } },
 
-{ "std",     DSO(62,0),	DS_MASK,	PPC|B64,	{ RS, DS, RA } },
+{ "stfdp",   OP(61),	OP_MASK,	POWER6,		{ FRT, D, RA0 } },
 
-{ "stdu",    DSO(62,1),	DS_MASK,	PPC|B64,	{ RS, DS, RAS } },
+{ "lde",     DEO(62,0), DE_MASK,	BOOKE64,	{ RT, DES, RA0 } },
+{ "ldue",    DEO(62,1), DE_MASK,	BOOKE64,	{ RT, DES, RA0 } },
+{ "lfse",    DEO(62,4), DE_MASK,	BOOKE64,	{ FRT, DES, RA0 } },
+{ "lfsue",   DEO(62,5), DE_MASK,	BOOKE64,	{ FRT, DES, RAS } },
+{ "lfde",    DEO(62,6), DE_MASK,	BOOKE64,	{ FRT, DES, RA0 } },
+{ "lfdue",   DEO(62,7), DE_MASK,	BOOKE64,	{ FRT, DES, RAS } },
+{ "stde",    DEO(62,8), DE_MASK,	BOOKE64,	{ RS, DES, RA0 } },
+{ "stdue",   DEO(62,9), DE_MASK,	BOOKE64,	{ RS, DES, RAS } },
+{ "stfse",   DEO(62,12), DE_MASK,	BOOKE64,	{ FRS, DES, RA0 } },
+{ "stfsue",  DEO(62,13), DE_MASK,	BOOKE64,	{ FRS, DES, RAS } },
+{ "stfde",   DEO(62,14), DE_MASK,	BOOKE64,	{ FRS, DES, RA0 } },
+{ "stfdue",  DEO(62,15), DE_MASK,	BOOKE64,	{ FRS, DES, RAS } },
 
-{ "fcmpu",   X(63,0),	X_MASK|(3<<21),	PPC|POWER,	{ BF, FRA, FRB } },
+{ "std",     DSO(62,0),	DS_MASK,	PPC64,		{ RS, DS, RA0 } },
 
-{ "frsp",    XRC(63,12,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
-{ "frsp.",   XRC(63,12,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "stdu",    DSO(62,1),	DS_MASK,	PPC64,		{ RS, DS, RAS } },
 
-{ "fctiw",   XRC(63,14,0), XRA_MASK,	PPC,		{ FRT, FRB } },
+{ "stq",     DSO(62,2),	DS_MASK,	POWER4,		{ RSQ, DS, RA0 } },
+
+{ "fcmpu",   X(63,0),	X_MASK|(3<<21),	COM,		{ BF, FRA, FRB } },
+
+{ "daddq",   XRC(63,2,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "daddq.",  XRC(63,2,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "dquaq",   ZRC(63,3,0), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+{ "dquaq.",  ZRC(63,3,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+
+{ "fcpsgn",  XRC(63,8,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "fcpsgn.", XRC(63,8,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "frsp",    XRC(63,12,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "frsp.",   XRC(63,12,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "fctiw",   XRC(63,14,0), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
 { "fcir",    XRC(63,14,0), XRA_MASK,	POWER2,		{ FRT, FRB } },
-{ "fctiw.",  XRC(63,14,1), XRA_MASK,	PPC,		{ FRT, FRB } },
+{ "fctiw.",  XRC(63,14,1), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
 { "fcir.",   XRC(63,14,1), XRA_MASK,	POWER2,		{ FRT, FRB } },
 
-{ "fctiwz",  XRC(63,15,0), XRA_MASK,	PPC,		{ FRT, FRB } },
+{ "fctiwz",  XRC(63,15,0), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
 { "fcirz",   XRC(63,15,0), XRA_MASK,	POWER2,		{ FRT, FRB } },
-{ "fctiwz.", XRC(63,15,1), XRA_MASK,	PPC,		{ FRT, FRB } },
+{ "fctiwz.", XRC(63,15,1), XRA_MASK,	PPCCOM,		{ FRT, FRB } },
 { "fcirz.",  XRC(63,15,1), XRA_MASK,	POWER2,		{ FRT, FRB } },
 
-{ "fdiv",    A(63,18,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
-{ "fd",      A(63,18,0), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
-{ "fdiv.",   A(63,18,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
-{ "fd.",     A(63,18,1), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+{ "fdiv",    A(63,18,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fd",      A(63,18,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fdiv.",   A(63,18,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fd.",     A(63,18,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
 
-{ "fsub",    A(63,20,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
-{ "fs",      A(63,20,0), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
-{ "fsub.",   A(63,20,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
-{ "fs.",     A(63,20,1), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+{ "fsub",    A(63,20,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fs",      A(63,20,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fsub.",   A(63,20,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fs.",     A(63,20,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
 
-{ "fadd",    A(63,21,0), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
-{ "fa",      A(63,21,0), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
-{ "fadd.",   A(63,21,1), AFRC_MASK,	PPC,		{ FRT, FRA, FRB } },
-{ "fa.",     A(63,21,1), AFRC_MASK,	POWER,		{ FRT, FRA, FRB } },
+{ "fadd",    A(63,21,0), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fa",      A(63,21,0), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
+{ "fadd.",   A(63,21,1), AFRC_MASK,	PPCCOM,		{ FRT, FRA, FRB } },
+{ "fa.",     A(63,21,1), AFRC_MASK,	PWRCOM,		{ FRT, FRA, FRB } },
 
-{ "fsqrt",   A(63,22,0), AFRAFRC_MASK,	PPC|POWER2,	{ FRT, FRB } },
-{ "fsqrt.",  A(63,22,1), AFRAFRC_MASK,	PPC|POWER2,	{ FRT, FRB } },
+{ "fsqrt",   A(63,22,0), AFRAFRC_MASK,	PPCPWR2,	{ FRT, FRB } },
+{ "fsqrt.",  A(63,22,1), AFRAFRC_MASK,	PPCPWR2,	{ FRT, FRB } },
 
 { "fsel",    A(63,23,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
 { "fsel.",   A(63,23,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
 
-{ "fmul",    A(63,25,0), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
-{ "fm",      A(63,25,0), AFRB_MASK,	POWER,		{ FRT, FRA, FRC } },
-{ "fmul.",   A(63,25,1), AFRB_MASK,	PPC,		{ FRT, FRA, FRC } },
-{ "fm.",     A(63,25,1), AFRB_MASK,	POWER,		{ FRT, FRA, FRC } },
+{ "fre",     A(63,24,0), AFRALFRC_MASK,	POWER5,		{ FRT, FRB, A_L } },
+{ "fre.",    A(63,24,1), AFRALFRC_MASK,	POWER5,		{ FRT, FRB, A_L } },
 
-{ "frsqrte", A(63,26,0), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
-{ "frsqrte.",A(63,26,1), AFRAFRC_MASK,	PPC,		{ FRT, FRB } },
+{ "fmul",    A(63,25,0), AFRB_MASK,	PPCCOM,		{ FRT, FRA, FRC } },
+{ "fm",      A(63,25,0), AFRB_MASK,	PWRCOM,		{ FRT, FRA, FRC } },
+{ "fmul.",   A(63,25,1), AFRB_MASK,	PPCCOM,		{ FRT, FRA, FRC } },
+{ "fm.",     A(63,25,1), AFRB_MASK,	PWRCOM,		{ FRT, FRA, FRC } },
 
-{ "fmsub",   A(63,28,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
-{ "fms",     A(63,28,0), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
-{ "fmsub.",  A(63,28,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
-{ "fms.",    A(63,28,1), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+{ "frsqrte", A(63,26,0), AFRALFRC_MASK,	PPC,		{ FRT, FRB, A_L } },
+{ "frsqrte.",A(63,26,1), AFRALFRC_MASK,	PPC,		{ FRT, FRB, A_L } },
 
-{ "fmadd",   A(63,29,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
-{ "fma",     A(63,29,0), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
-{ "fmadd.",  A(63,29,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
-{ "fma.",    A(63,29,1), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+{ "fmsub",   A(63,28,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fms",     A(63,28,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fmsub.",  A(63,28,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fms.",    A(63,28,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
 
-{ "fnmsub",  A(63,30,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
-{ "fnms",    A(63,30,0), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
-{ "fnmsub.", A(63,30,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
-{ "fnms.",   A(63,30,1), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+{ "fmadd",   A(63,29,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fma",     A(63,29,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fmadd.",  A(63,29,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fma.",    A(63,29,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
 
-{ "fnmadd",  A(63,31,0), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
-{ "fnma",    A(63,31,0), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
-{ "fnmadd.", A(63,31,1), A_MASK,	PPC,		{ FRT,FRA,FRC,FRB } },
-{ "fnma.",   A(63,31,1), A_MASK,	POWER,		{ FRT,FRA,FRC,FRB } },
+{ "fnmsub",  A(63,30,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnms",    A(63,30,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnmsub.", A(63,30,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnms.",   A(63,30,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
 
-{ "fcmpo",   X(63,30),	X_MASK|(3<<21),	PPC|POWER,	{ BF, FRA, FRB } },
+{ "fnmadd",  A(63,31,0), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnma",    A(63,31,0), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnmadd.", A(63,31,1), A_MASK,	PPCCOM,		{ FRT,FRA,FRC,FRB } },
+{ "fnma.",   A(63,31,1), A_MASK,	PWRCOM,		{ FRT,FRA,FRC,FRB } },
 
-{ "mtfsb1",  XRC(63,38,0), XRARB_MASK,	PPC|POWER,	{ BT } },
-{ "mtfsb1.", XRC(63,38,1), XRARB_MASK,	PPC|POWER,	{ BT } },
+{ "fcmpo",   X(63,32),	X_MASK|(3<<21),	COM,		{ BF, FRA, FRB } },
 
-{ "fneg",    XRC(63,40,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
-{ "fneg.",   XRC(63,40,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "dmulq",   XRC(63,34,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dmulq.",  XRC(63,34,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
 
-{ "mcrfs",   X(63,64),	XRB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } },
+{ "drrndq",  ZRC(63,35,0), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
+{ "drrndq.", ZRC(63,35,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
 
-{ "mtfsb0",  XRC(63,70,0), XRARB_MASK,	PPC|POWER,	{ BT } },
-{ "mtfsb0.", XRC(63,70,1), XRARB_MASK,	PPC|POWER,	{ BT } },
+{ "mtfsb1",  XRC(63,38,0), XRARB_MASK,	COM,		{ BT } },
+{ "mtfsb1.", XRC(63,38,1), XRARB_MASK,	COM,		{ BT } },
 
-{ "fmr",     XRC(63,72,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
-{ "fmr.",    XRC(63,72,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "fneg",    XRC(63,40,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fneg.",   XRC(63,40,1), XRA_MASK,	COM,		{ FRT, FRB } },
 
-{ "mtfsfi",  XRC(63,134,0), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } },
-{ "mtfsfi.", XRC(63,134,1), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } },
+{ "mcrfs",   X(63,64),	XRB_MASK|(3<<21)|(3<<16), COM,	{ BF, BFA } },
 
-{ "fnabs",   XRC(63,136,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
-{ "fnabs.",  XRC(63,136,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "dscliq",  ZRC(63,66,0), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+{ "dscliq.", ZRC(63,66,1), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
 
-{ "fabs",    XRC(63,264,0), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
-{ "fabs.",   XRC(63,264,1), XRA_MASK,	PPC|POWER,	{ FRT, FRB } },
+{ "dquaiq",  ZRC(63,67,0), Z2_MASK,	POWER6,		{ TE,  FRT, FRB, RMC } },
+{ "dquaiq.", ZRC(63,67,1), Z2_MASK,	POWER6,		{ FRT, FRA, FRB, RMC } },
 
-{ "mffs",    XRC(63,583,0), XRARB_MASK,	PPC|POWER,	{ FRT } },
-{ "mffs.",   XRC(63,583,1), XRARB_MASK,	PPC|POWER,	{ FRT } },
+{ "mtfsb0",  XRC(63,70,0), XRARB_MASK,	COM,		{ BT } },
+{ "mtfsb0.", XRC(63,70,1), XRARB_MASK,	COM,		{ BT } },
 
-{ "mtfsf",   XFL(63,711,0), XFL_MASK,	PPC|POWER,	{ FLM, FRB } },
-{ "mtfsf.",  XFL(63,711,1), XFL_MASK,	PPC|POWER,	{ FLM, FRB } },
+{ "fmr",     XRC(63,72,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fmr.",    XRC(63,72,1), XRA_MASK,	COM,		{ FRT, FRB } },
 
-{ "fctid",   XRC(63,814,0), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
-{ "fctid.",  XRC(63,814,1), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+{ "dscriq",  ZRC(63,98,0), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
+{ "dscriq.", ZRC(63,98,1), Z_MASK,	POWER6,		{ FRT, FRA, SH16 } },
 
-{ "fctidz",  XRC(63,815,0), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
-{ "fctidz.", XRC(63,815,1), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+{ "drintxq", ZRC(63,99,0), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+{ "drintxq.",ZRC(63,99,1), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
 
-{ "fcfid",   XRC(63,846,0), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
-{ "fcfid.",  XRC(63,846,1), XRA_MASK,	PPC|B64,	{ FRT, FRB } },
+{ "dcmpoq",  X(63,130),	   X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "mtfsfi",  XRC(63,134,0), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } },
+{ "mtfsfi.", XRC(63,134,1), XWRA_MASK|(3<<21)|(1<<11), COM, { BFF, U, W } },
+
+{ "fnabs",   XRC(63,136,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fnabs.",  XRC(63,136,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "dtstexq", X(63,162),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+{ "dtstdcq", Z(63,194),	    Z_MASK,	POWER6,		{ BF,  FRA, DCM } },
+{ "dtstdgq", Z(63,226),	    Z_MASK,	POWER6,		{ BF,  FRA, DGM } },
+
+{ "drintnq", ZRC(63,227,0), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+{ "drintnq.",ZRC(63,227,1), Z2_MASK,	POWER6,		{ R, FRT, FRB, RMC } },
+
+{ "dctqpq",  XRC(63,258,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dctqpq.", XRC(63,258,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "fabs",    XRC(63,264,0), XRA_MASK,	COM,		{ FRT, FRB } },
+{ "fabs.",   XRC(63,264,1), XRA_MASK,	COM,		{ FRT, FRB } },
+
+{ "dctfixq", XRC(63,290,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dctfixq.",XRC(63,290,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "ddedpdq", XRC(63,322,0), X_MASK,	POWER6,		{ SP, FRT, FRB } },
+{ "ddedpdq.",XRC(63,322,1), X_MASK,	POWER6,		{ SP, FRT, FRB } },
+
+{ "dxexq",   XRC(63,354,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dxexq.",  XRC(63,354,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "frin",    XRC(63,392,0), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frin.",   XRC(63,392,1), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "friz",    XRC(63,424,0), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "friz.",   XRC(63,424,1), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frip",    XRC(63,456,0), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frip.",   XRC(63,456,1), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frim",    XRC(63,488,0), XRA_MASK,	POWER5,		{ FRT, FRB } },
+{ "frim.",   XRC(63,488,1), XRA_MASK,	POWER5,		{ FRT, FRB } },
+
+{ "dsubq",   XRC(63,514,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "dsubq.",  XRC(63,514,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "ddivq",   XRC(63,546,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "ddivq.",  XRC(63,546,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+
+{ "mffs",    XRC(63,583,0), XRARB_MASK,	COM,		{ FRT } },
+{ "mffs.",   XRC(63,583,1), XRARB_MASK,	COM,		{ FRT } },
+
+{ "dcmpuq",  X(63,642),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "dtstsfq", X(63,674),	    X_MASK,	POWER6,		{ BF,  FRA, FRB } },
+
+{ "mtfsf",   XFL(63,711,0), XFL_MASK,	COM,		{ FLM, FRB, XFL_L, W } },
+{ "mtfsf.",  XFL(63,711,1), XFL_MASK,	COM,		{ FLM, FRB, XFL_L, W } },
+
+{ "drdpq",   XRC(63,770,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "drdpq.",  XRC(63,770,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "dcffixq", XRC(63,802,0), X_MASK,	POWER6,		{ FRT, FRB } },
+{ "dcffixq.",XRC(63,802,1), X_MASK,	POWER6,		{ FRT, FRB } },
+
+{ "fctid",   XRC(63,814,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fctid.",  XRC(63,814,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+{ "fctidz",  XRC(63,815,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fctidz.", XRC(63,815,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+{ "denbcdq", XRC(63,834,0), X_MASK,	POWER6,		{ S, FRT, FRB } },
+{ "denbcdq.",XRC(63,834,1), X_MASK,	POWER6,		{ S, FRT, FRB } },
+
+{ "fcfid",   XRC(63,846,0), XRA_MASK,	PPC64,		{ FRT, FRB } },
+{ "fcfid.",  XRC(63,846,1), XRA_MASK,	PPC64,		{ FRT, FRB } },
+
+{ "diexq",   XRC(63,866,0), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
+{ "diexq.",  XRC(63,866,1), X_MASK,	POWER6,		{ FRT, FRA, FRB } },
 
 };
 
@@ -3021,87 +5019,252 @@
 
 /* The macro table.  This is only used by the assembler.  */
 
+/* The expressions of the form (-x ! 31) & (x | 31) have the value 0
+   when x=0; 32-x when x is between 1 and 31; are negative if x is
+   negative; and are 32 or more otherwise.  This is what you want
+   when, for instance, you are emulating a right shift by a
+   rotate-left-and-mask, because the underlying instructions support
+   shifts of size 0 but not shifts of size 32.  By comparison, when
+   extracting x bits from some word you want to use just 32-x, because
+   the underlying instructions don't support extracting 0 bits but do
+   support extracting the whole word (32 bits in this case).  */
+
 const struct powerpc_macro powerpc_macros[] = {
-{ "extldi",  4,   PPC|B64,	"rldicr %0,%1,%3,(%2)-1" },
-{ "extldi.", 4,   PPC|B64,	"rldicr. %0,%1,%3,(%2)-1" },
-{ "extrdi",  4,   PPC|B64,	"rldicl %0,%1,(%2)+(%3),64-(%2)" },
-{ "extrdi.", 4,   PPC|B64,	"rldicl. %0,%1,(%2)+(%3),64-(%2)" },
-{ "insrdi",  4,   PPC|B64,	"rldimi %0,%1,64-((%2)+(%3)),%3" },
-{ "insrdi.", 4,   PPC|B64,	"rldimi. %0,%1,64-((%2)+(%3)),%3" },
-{ "rotrdi",  3,   PPC|B64,	"rldicl %0,%1,64-(%2),0" },
-{ "rotrdi.", 3,   PPC|B64,	"rldicl. %0,%1,64-(%2),0" },
-{ "sldi",    3,   PPC|B64,	"rldicr %0,%1,%2,63-(%2)" },
-{ "sldi.",   3,   PPC|B64,	"rldicr. %0,%1,%2,63-(%2)" },
-{ "srdi",    3,   PPC|B64,	"rldicl %0,%1,64-(%2),%2" },
-{ "srdi.",   3,   PPC|B64,	"rldicl. %0,%1,64-(%2),%2" },
-{ "clrrdi",  3,   PPC|B64,	"rldicr %0,%1,0,63-(%2)" },
-{ "clrrdi.", 3,   PPC|B64,	"rldicr. %0,%1,0,63-(%2)" },
-{ "clrlsldi",4,   PPC|B64,	"rldic %0,%1,%3,(%2)-(%3)" },
-{ "clrlsldi.",4,  PPC|B64,	"rldic. %0,%1,%3,(%2)-(%3)" },
+{ "extldi",  4,   PPC64,	"rldicr %0,%1,%3,(%2)-1" },
+{ "extldi.", 4,   PPC64,	"rldicr. %0,%1,%3,(%2)-1" },
+{ "extrdi",  4,   PPC64,	"rldicl %0,%1,(%2)+(%3),64-(%2)" },
+{ "extrdi.", 4,   PPC64,	"rldicl. %0,%1,(%2)+(%3),64-(%2)" },
+{ "insrdi",  4,   PPC64,	"rldimi %0,%1,64-((%2)+(%3)),%3" },
+{ "insrdi.", 4,   PPC64,	"rldimi. %0,%1,64-((%2)+(%3)),%3" },
+{ "rotrdi",  3,   PPC64,	"rldicl %0,%1,(-(%2)!63)&((%2)|63),0" },
+{ "rotrdi.", 3,   PPC64,	"rldicl. %0,%1,(-(%2)!63)&((%2)|63),0" },
+{ "sldi",    3,   PPC64,	"rldicr %0,%1,%2,63-(%2)" },
+{ "sldi.",   3,   PPC64,	"rldicr. %0,%1,%2,63-(%2)" },
+{ "srdi",    3,   PPC64,	"rldicl %0,%1,(-(%2)!63)&((%2)|63),%2" },
+{ "srdi.",   3,   PPC64,	"rldicl. %0,%1,(-(%2)!63)&((%2)|63),%2" },
+{ "clrrdi",  3,   PPC64,	"rldicr %0,%1,0,63-(%2)" },
+{ "clrrdi.", 3,   PPC64,	"rldicr. %0,%1,0,63-(%2)" },
+{ "clrlsldi",4,   PPC64,	"rldic %0,%1,%3,(%2)-(%3)" },
+{ "clrlsldi.",4,  PPC64,	"rldic. %0,%1,%3,(%2)-(%3)" },
 
-{ "extlwi",  4,   PPC,		"rlwinm %0,%1,%3,0,(%2)-1" },
-{ "extlwi.", 4,   PPC,		"rlwinm. %0,%1,%3,0,(%2)-1" },
-{ "extrwi",  4,   PPC,		"rlwinm %0,%1,(%2)+(%3),32-(%2),31" },
-{ "extrwi.", 4,   PPC,		"rlwinm. %0,%1,(%2)+(%3),32-(%2),31" },
-{ "inslwi",  4,   PPC,		"rlwimi %0,%1,32-(%3),%3,(%2)+(%3)-1" },
-{ "inslwi.", 4,   PPC,		"rlwimi. %0,%1,32-(%3),%3,(%2)+(%3)-1" },
-{ "insrwi",  4,   PPC,		"rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" },
-{ "insrwi.", 4,   PPC,		"rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"},
-{ "rotrwi",  3,   PPC,		"rlwinm %0,%1,32-(%2),0,31" },
-{ "rotrwi.", 3,   PPC,		"rlwinm. %0,%1,32-(%2),0,31" },
-{ "slwi",    3,   PPC,		"rlwinm %0,%1,%2,0,31-(%2)" },
-{ "sli",     3,   POWER,	"rlinm %0,%1,%2,0,31-(%2)" },
-{ "slwi.",   3,   PPC,		"rlwinm. %0,%1,%2,0,31-(%2)" },
-{ "sli.",    3,   POWER,	"rlinm. %0,%1,%2,0,31-(%2)" },
-{ "srwi",    3,   PPC,		"rlwinm %0,%1,32-(%2),%2,31" },
-{ "sri",     3,   POWER,	"rlinm %0,%1,32-(%2),%2,31" },
-{ "srwi.",   3,   PPC,		"rlwinm. %0,%1,32-(%2),%2,31" },
-{ "sri.",    3,   POWER,	"rlinm. %0,%1,32-(%2),%2,31" },
-{ "clrrwi",  3,   PPC,		"rlwinm %0,%1,0,0,31-(%2)" },
-{ "clrrwi.", 3,   PPC,		"rlwinm. %0,%1,0,0,31-(%2)" },
-{ "clrlslwi",4,   PPC,		"rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" },
-{ "clrlslwi.",4,  PPC,		"rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" },
-
+{ "extlwi",  4,   PPCCOM,	"rlwinm %0,%1,%3,0,(%2)-1" },
+{ "extlwi.", 4,   PPCCOM,	"rlwinm. %0,%1,%3,0,(%2)-1" },
+{ "extrwi",  4,   PPCCOM,	"rlwinm %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" },
+{ "extrwi.", 4,   PPCCOM,	"rlwinm. %0,%1,((%2)+(%3))&((%2)+(%3)<>32),32-(%2),31" },
+{ "inslwi",  4,   PPCCOM,	"rlwimi %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1" },
+{ "inslwi.", 4,   PPCCOM,	"rlwimi. %0,%1,(-(%3)!31)&((%3)|31),%3,(%2)+(%3)-1"},
+{ "insrwi",  4,   PPCCOM,	"rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" },
+{ "insrwi.", 4,   PPCCOM,	"rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"},
+{ "rotrwi",  3,   PPCCOM,	"rlwinm %0,%1,(-(%2)!31)&((%2)|31),0,31" },
+{ "rotrwi.", 3,   PPCCOM,	"rlwinm. %0,%1,(-(%2)!31)&((%2)|31),0,31" },
+{ "slwi",    3,   PPCCOM,	"rlwinm %0,%1,%2,0,31-(%2)" },
+{ "sli",     3,   PWRCOM,	"rlinm %0,%1,%2,0,31-(%2)" },
+{ "slwi.",   3,   PPCCOM,	"rlwinm. %0,%1,%2,0,31-(%2)" },
+{ "sli.",    3,   PWRCOM,	"rlinm. %0,%1,%2,0,31-(%2)" },
+{ "srwi",    3,   PPCCOM,	"rlwinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "sri",     3,   PWRCOM,	"rlinm %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "srwi.",   3,   PPCCOM,	"rlwinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "sri.",    3,   PWRCOM,	"rlinm. %0,%1,(-(%2)!31)&((%2)|31),%2,31" },
+{ "clrrwi",  3,   PPCCOM,	"rlwinm %0,%1,0,0,31-(%2)" },
+{ "clrrwi.", 3,   PPCCOM,	"rlwinm. %0,%1,0,0,31-(%2)" },
+{ "clrlslwi",4,   PPCCOM,	"rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" },
+{ "clrlslwi.",4,  PPCCOM,	"rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" },
 };
 
 const int powerpc_num_macros =
   sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
 
+
+/* This file provides several disassembler functions, all of which use
+   the disassembler interface defined in dis-asm.h.  Several functions
+   are provided because this file handles disassembly for the PowerPC
+   in both big and little endian mode and also for the POWER (RS/6000)
+   chip.  */
+
+static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int);
+
+/* Determine which set of machines to disassemble for.  PPC403/601 or
+   BookE.  For convenience, also disassemble instructions supported
+   by the AltiVec vector unit.  */
+
 static int
-print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr,
-		    int dialect);
-
-/* Print a big endian PowerPC instruction.  For convenience, also
-   disassemble instructions supported by the Motorola PowerPC 601.  */
-
-int print_insn_ppc (bfd_vma pc, disassemble_info *info)
+powerpc_dialect (struct disassemble_info *info)
 {
-    uint32_t opc;
-    bfd_byte buf[4];
+  int dialect = PPC_OPCODE_PPC;
 
-    (*info->read_memory_func)(pc, buf, 4, info);
-    if (info->endian == BFD_ENDIAN_BIG)
-        opc = bfd_getb32(buf);
-    else
-        opc = bfd_getl32(buf);
-    if (info->mach == bfd_mach_ppc64) {
-        return print_insn_powerpc (info, opc, pc,
-                                   PPC | B64);
-    } else {
-        return print_insn_powerpc (info, opc, pc,
-                                   PPC | B32 | M601);
+  if (BFD_DEFAULT_TARGET_SIZE == 64)
+    dialect |= PPC_OPCODE_64;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "booke") != NULL)
+    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
+  else if ((info->mach == bfd_mach_ppc_e500)
+	   || (info->disassembler_options
+	       && strstr (info->disassembler_options, "e500") != NULL))
+    dialect |= (PPC_OPCODE_BOOKE
+		| PPC_OPCODE_SPE | PPC_OPCODE_ISEL
+		| PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
+		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
+		| PPC_OPCODE_RFMCI);
+  else if (info->disassembler_options
+	   && strstr (info->disassembler_options, "efs") != NULL)
+    dialect |= PPC_OPCODE_EFS;
+  else if (info->disassembler_options
+	   && strstr (info->disassembler_options, "e300") != NULL)
+    dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON;
+  else if (info->disassembler_options
+	   && strstr (info->disassembler_options, "440") != NULL)
+    dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32
+      | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI;
+  else
+    dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
+		| PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC);
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "power4") != NULL)
+    dialect |= PPC_OPCODE_POWER4;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "power5") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "cell") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "power6") != NULL)
+    dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC;
+
+  if (info->disassembler_options
+      && strstr (info->disassembler_options, "any") != NULL)
+    dialect |= PPC_OPCODE_ANY;
+
+  if (info->disassembler_options)
+    {
+      if (strstr (info->disassembler_options, "32") != NULL)
+	dialect &= ~PPC_OPCODE_64;
+      else if (strstr (info->disassembler_options, "64") != NULL)
+	dialect |= PPC_OPCODE_64;
     }
+
+  info->private_data = (char *) 0 + dialect;
+  return dialect;
+}
+
+/* Qemu default */
+int
+print_insn_ppc (bfd_vma memaddr, struct disassemble_info *info)
+{
+  int dialect = (char *) info->private_data - (char *) 0;
+  return print_insn_powerpc (memaddr, info, 1, dialect);
+}
+
+/* Print a big endian PowerPC instruction.  */
+
+int
+print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
+{
+  int dialect = (char *) info->private_data - (char *) 0;
+  return print_insn_powerpc (memaddr, info, 1, dialect);
+}
+
+/* Print a little endian PowerPC instruction.  */
+
+int
+print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
+{
+  int dialect = (char *) info->private_data - (char *) 0;
+  return print_insn_powerpc (memaddr, info, 0, dialect);
+}
+
+/* Print a POWER (RS/6000) instruction.  */
+
+int
+print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
+}
+
+/* Extract the operand value from the PowerPC or POWER instruction.  */
+
+static long
+operand_value_powerpc (const struct powerpc_operand *operand,
+		       unsigned long insn, int dialect)
+{
+  long value;
+  int invalid;
+  /* Extract the value from the instruction.  */
+  if (operand->extract)
+    value = (*operand->extract) (insn, dialect, &invalid);
+  else
+    {
+      value = (insn >> operand->shift) & operand->bitm;
+      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+	{
+	  /* BITM is always some number of zeros followed by some
+	     number of ones, followed by some numer of zeros.  */
+	  unsigned long top = operand->bitm;
+	  /* top & -top gives the rightmost 1 bit, so this
+	     fills in any trailing zeros.  */
+	  top |= (top & -top) - 1;
+	  top &= ~(top >> 1);
+	  value = (value ^ top) - top;
+	}
+    }
+
+  return value;
+}
+
+/* Determine whether the optional operand(s) should be printed.  */
+
+static int
+skip_optional_operands (const unsigned char *opindex,
+			unsigned long insn, int dialect)
+{
+  const struct powerpc_operand *operand;
+
+  for (; *opindex != 0; opindex++)
+    {
+      operand = &powerpc_operands[*opindex];
+      if ((operand->flags & PPC_OPERAND_NEXT) != 0
+	  || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+	      && operand_value_powerpc (operand, insn, dialect) != 0))
+	return 0;
+    }
+
+  return 1;
 }
 
 /* Print a PowerPC or POWER instruction.  */
 
 static int
-print_insn_powerpc (disassemble_info *info, uint32_t insn, unsigned memaddr,
+print_insn_powerpc (bfd_vma memaddr,
+		    struct disassemble_info *info,
+		    int bigendian,
 		    int dialect)
 {
+  bfd_byte buffer[4];
+  int status;
+  unsigned long insn;
   const struct powerpc_opcode *opcode;
   const struct powerpc_opcode *opcode_end;
-  uint32_t op;
+  unsigned long op;
+
+  if (dialect == 0)
+    dialect = powerpc_dialect (info);
+
+  status = (*info->read_memory_func) (memaddr, buffer, 4, info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  if (bigendian)
+    insn = bfd_getb32 (buffer);
+  else
+    insn = bfd_getl32 (buffer);
 
   /* Get the major opcode of the instruction.  */
   op = PPC_OP (insn);
@@ -3109,120 +5272,117 @@
   /* Find the first match in the opcode table.  We could speed this up
      a bit by doing a binary search on the major opcode.  */
   opcode_end = powerpc_opcodes + powerpc_num_opcodes;
+ again:
   for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
     {
-      uint32_t table_op;
+      unsigned long table_op;
       const unsigned char *opindex;
       const struct powerpc_operand *operand;
       int invalid;
       int need_comma;
       int need_paren;
+      int skip_optional;
 
       table_op = PPC_OP (opcode->opcode);
       if (op < table_op)
-		break;
+	break;
       if (op > table_op)
-		continue;
+	continue;
 
       if ((insn & opcode->mask) != opcode->opcode
 	  || (opcode->flags & dialect) == 0)
-		continue;
+	continue;
 
       /* Make two passes over the operands.  First see if any of them
-		 have extraction functions, and, if they do, make sure the
-		 instruction is valid.  */
+	 have extraction functions, and, if they do, make sure the
+	 instruction is valid.  */
       invalid = 0;
       for (opindex = opcode->operands; *opindex != 0; opindex++)
-		{
-		  operand = powerpc_operands + *opindex;
-		  if (operand->extract)
-		    (*operand->extract) (insn, &invalid);
-		}
+	{
+	  operand = powerpc_operands + *opindex;
+	  if (operand->extract)
+	    (*operand->extract) (insn, dialect, &invalid);
+	}
       if (invalid)
-		continue;
+	continue;
 
       /* The instruction is valid.  */
-      (*info->fprintf_func)(info->stream, "%s", opcode->name);
       if (opcode->operands[0] != 0)
-		(*info->fprintf_func)(info->stream, "\t");
+	(*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
+      else
+	(*info->fprintf_func) (info->stream, "%s", opcode->name);
 
       /* Now extract and print the operands.  */
       need_comma = 0;
       need_paren = 0;
+      skip_optional = -1;
       for (opindex = opcode->operands; *opindex != 0; opindex++)
+	{
+	  long value;
+
+	  operand = powerpc_operands + *opindex;
+
+	  /* Operands that are marked FAKE are simply ignored.  We
+	     already made sure that the extract function considered
+	     the instruction to be valid.  */
+	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
+	    continue;
+
+	  /* If all of the optional operands have the value zero,
+	     then don't print any of them.  */
+	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
+	    {
+	      if (skip_optional < 0)
+		skip_optional = skip_optional_operands (opindex, insn,
+							dialect);
+	      if (skip_optional)
+		continue;
+	    }
+
+	  value = operand_value_powerpc (operand, insn, dialect);
+
+	  if (need_comma)
+	    {
+	      (*info->fprintf_func) (info->stream, ",");
+	      need_comma = 0;
+	    }
+
+	  /* Print the operand as directed by the flags.  */
+	  if ((operand->flags & PPC_OPERAND_GPR) != 0
+	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
+	    (*info->fprintf_func) (info->stream, "r%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
+	    (*info->fprintf_func) (info->stream, "f%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
+	    (*info->fprintf_func) (info->stream, "v%ld", value);
+	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
+	    (*info->print_address_func) (memaddr + value, info);
+	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
+	  else if ((operand->flags & PPC_OPERAND_CR) == 0
+		   || (dialect & PPC_OPCODE_PPC) == 0)
+	    (*info->fprintf_func) (info->stream, "%ld", value);
+	  else
+	    {
+	      if (operand->bitm == 7)
+		(*info->fprintf_func) (info->stream, "cr%ld", value);
+	      else
 		{
-		  int32_t value;
+		  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
+		  int cr;
+		  int cc;
 
-		  operand = powerpc_operands + *opindex;
-
-		  /* Operands that are marked FAKE are simply ignored.  We
-		     already made sure that the extract function considered
-		     the instruction to be valid.  */
-		  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
-		    continue;
-
-		  /* Extract the value from the instruction.  */
-		  if (operand->extract)
-		    value = (*operand->extract) (insn, (int *) 0);
-		  else
-		    {
-		      value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
-		      if ((operand->flags & PPC_OPERAND_SIGNED) != 0
-			  && (value & (1 << (operand->bits - 1))) != 0)
-			value -= 1 << operand->bits;
-		    }
-
-		  /* If the operand is optional, and the value is zero, don't
-		     print anything.  */
-		  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
-		      && (operand->flags & PPC_OPERAND_NEXT) == 0
-		      && value == 0)
-		    continue;
-
-		  if (need_comma)
-		    {
-		      (*info->fprintf_func)(info->stream, ",");
-		      need_comma = 0;
-		    }
-
-		  /* Print the operand as directed by the flags.  */
-		  if ((operand->flags & PPC_OPERAND_GPR) != 0)
-		    (*info->fprintf_func)(info->stream, "r%d", value);
-		  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
-		    (*info->fprintf_func)(info->stream, "f%d", value);
-		  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
-		    (*info->fprintf_func)(info->stream, "%08X", memaddr + value);
-		  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
-		    (*info->fprintf_func)(info->stream, "%08X", value & 0xffffffff);
-		  else if ((operand->flags & PPC_OPERAND_CR) == 0
-			   || (dialect & PPC_OPCODE_PPC) == 0)
-		    (*info->fprintf_func)(info->stream, "%d", value);
-		  else
-		    {
-		      if (operand->bits == 3)
-				(*info->fprintf_func)(info->stream, "cr%d", value);
-		      else
-			{
-			  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
-			  int cr;
-			  int cc;
-
-			  cr = value >> 2;
-			  if (cr != 0)
-			    (*info->fprintf_func)(info->stream, "4*cr%d", cr);
-			  cc = value & 3;
-			  if (cc != 0)
-			    {
-			      if (cr != 0)
-					(*info->fprintf_func)(info->stream, "+");
-			      (*info->fprintf_func)(info->stream, "%s", cbnames[cc]);
-			    }
-			}
+		  cr = value >> 2;
+		  if (cr != 0)
+		    (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
+		  cc = value & 3;
+		  (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
+		}
 	    }
 
 	  if (need_paren)
 	    {
-	      (*info->fprintf_func)(info->stream, ")");
+	      (*info->fprintf_func) (info->stream, ")");
 	      need_paren = 0;
 	    }
 
@@ -3230,7 +5390,7 @@
 	    need_comma = 1;
 	  else
 	    {
-	      (*info->fprintf_func)(info->stream, "(");
+	      (*info->fprintf_func) (info->stream, "(");
 	      need_paren = 1;
 	    }
 	}
@@ -3239,8 +5399,14 @@
       return 4;
     }
 
+  if ((dialect & PPC_OPCODE_ANY) != 0)
+    {
+      dialect = ~PPC_OPCODE_ANY;
+      goto again;
+    }
+
   /* We could not find a match.  */
-  (*info->fprintf_func)(info->stream, ".long 0x%x", insn);
+  (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
 
   return 4;
 }
diff --git a/qemu-aio.h b/qemu-aio.h
new file mode 100644
index 0000000..f262344
--- /dev/null
+++ b/qemu-aio.h
@@ -0,0 +1,46 @@
+/*
+ * QEMU aio implementation
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_AIO_H
+#define QEMU_AIO_H
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+
+/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
+typedef int (AioFlushHandler)(void *opaque);
+
+/* Flush any pending AIO operation. This function will block until all
+ * outstanding AIO operations have been completed or cancelled. */
+void qemu_aio_flush(void);
+
+/* Wait for a single AIO completion to occur.  This function will wait
+ * until a single AIO event has completed and it will ensure something
+ * has moved before returning. This can issue new pending aio as
+ * result of executing I/O completion or bh callbacks. */
+void qemu_aio_wait(void);
+
+/* Register a file descriptor and associated callbacks.  Behaves very similarly
+ * to qemu_set_fd_handler2.  Unlike qemu_set_fd_handler2, these callbacks will
+ * be invoked when using either qemu_aio_wait() or qemu_aio_flush().
+ *
+ * Code that invokes AIO completion functions should rely on this function
+ * instead of qemu_set_fd_handler[2].
+ */
+int qemu_aio_set_fd_handler(int fd,
+                            IOHandler *io_read,
+                            IOHandler *io_write,
+                            AioFlushHandler *io_flush,
+                            void *opaque);
+
+#endif
diff --git a/qemu-char-android.c b/qemu-char-android.c
new file mode 100644
index 0000000..05f80e7
--- /dev/null
+++ b/qemu-char-android.c
@@ -0,0 +1,2268 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "sockets.h"
+#include "net.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "block.h"
+#include "hw/usb.h"
+#include "hw/baum.h"
+#include "hw/msmouse.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+#ifndef _WIN32
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#ifdef __NetBSD__
+#include <net/if_tap.h>
+#endif
+#ifdef __linux__
+#include <linux/if_tun.h>
+#endif
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+#ifdef HOST_BSD
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <libutil.h>
+#include <dev/ppbus/ppi.h>
+#include <dev/ppbus/ppbconf.h>
+#elif defined(__DragonFly__)
+#include <libutil.h>
+#include <dev/misc/ppi/ppi.h>
+#include <bus/ppbus/ppbconf.h>
+#else
+#include <util.h>
+#endif
+#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+#include <freebsd/stdlib.h>
+#else
+#ifdef __linux__
+#include <pty.h>
+
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+#endif
+#ifdef __sun__
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
+#endif
+#endif
+#endif
+
+#include "qemu_socket.h"
+
+/* ANDROID */
+#include "charpipe.h"
+#include "modem_driver.h"
+#include "android/gps.h"
+#include "android/hw-kmsg.h"
+#include "android/hw-qemud.h"
+
+/***********************************************************/
+/* character device */
+
+static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
+    TAILQ_HEAD_INITIALIZER(chardevs);
+static int initial_reset_issued;
+
+static void qemu_chr_event(CharDriverState *s, int event)
+{
+    if (!s->chr_event)
+        return;
+    s->chr_event(s->handler_opaque, event);
+}
+
+static void qemu_chr_reset_bh(void *opaque)
+{
+    CharDriverState *s = opaque;
+    qemu_chr_event(s, CHR_EVENT_RESET);
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+}
+
+void qemu_chr_reset(CharDriverState *s)
+{
+    if (s->bh == NULL && initial_reset_issued) {
+	s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
+	qemu_bh_schedule(s->bh);
+    }
+}
+
+void qemu_chr_initial_reset(void)
+{
+    CharDriverState *chr;
+
+    initial_reset_issued = 1;
+
+    TAILQ_FOREACH(chr, &chardevs, next) {
+        qemu_chr_reset(chr);
+    }
+}
+
+int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
+{
+    return s->chr_write(s, buf, len);
+}
+
+int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
+{
+    if (!s->chr_ioctl)
+        return -ENOTSUP;
+    return s->chr_ioctl(s, cmd, arg);
+}
+
+int qemu_chr_can_read(CharDriverState *s)
+{
+    if (!s->chr_can_read)
+        return 0;
+    return s->chr_can_read(s->handler_opaque);
+}
+
+void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
+{
+    s->chr_read(s->handler_opaque, buf, len);
+}
+
+void qemu_chr_accept_input(CharDriverState *s)
+{
+    if (s->chr_accept_input)
+        s->chr_accept_input(s);
+}
+
+void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+{
+    char buf[4096];
+    va_list ap;
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    qemu_chr_write(s, (uint8_t *)buf, strlen(buf));
+    va_end(ap);
+}
+
+void qemu_chr_send_event(CharDriverState *s, int event)
+{
+    if (s->chr_send_event)
+        s->chr_send_event(s, event);
+}
+
+void qemu_chr_add_handlers(CharDriverState *s,
+                           IOCanRWHandler *fd_can_read,
+                           IOReadHandler *fd_read,
+                           IOEventHandler *fd_event,
+                           void *opaque)
+{
+    s->chr_can_read = fd_can_read;
+    s->chr_read = fd_read;
+    s->chr_event = fd_event;
+    s->handler_opaque = opaque;
+    if (s->chr_update_read_handler)
+        s->chr_update_read_handler(s);
+}
+
+static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    return len;
+}
+
+static CharDriverState *qemu_chr_open_null(void)
+{
+    CharDriverState *chr;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->chr_write = null_chr_write;
+    return chr;
+}
+
+/* MUX driver for serial I/O splitting */
+#define MAX_MUX 4
+#define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
+#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
+typedef struct {
+    IOCanRWHandler *chr_can_read[MAX_MUX];
+    IOReadHandler *chr_read[MAX_MUX];
+    IOEventHandler *chr_event[MAX_MUX];
+    void *ext_opaque[MAX_MUX];
+    CharDriverState *drv;
+    int mux_cnt;
+    int term_got_escape;
+    int max_size;
+    /* Intermediate input buffer allows to catch escape sequences even if the
+       currently active device is not accepting any input - but only until it
+       is full as well. */
+    unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
+    int prod[MAX_MUX];
+    int cons[MAX_MUX];
+    int timestamps;
+    int linestart;
+    int64_t timestamps_start;
+} MuxDriver;
+
+
+static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MuxDriver *d = chr->opaque;
+    int ret;
+    if (!d->timestamps) {
+        ret = d->drv->chr_write(d->drv, buf, len);
+    } else {
+        int i;
+
+        ret = 0;
+        for (i = 0; i < len; i++) {
+            if (d->linestart) {
+                char buf1[64];
+                int64_t ti;
+                int secs;
+
+                ti = qemu_get_clock(rt_clock);
+                if (d->timestamps_start == -1)
+                    d->timestamps_start = ti;
+                ti -= d->timestamps_start;
+                secs = ti / 1000;
+                snprintf(buf1, sizeof(buf1),
+                         "[%02d:%02d:%02d.%03d] ",
+                         secs / 3600,
+                         (secs / 60) % 60,
+                         secs % 60,
+                         (int)(ti % 1000));
+                d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
+                d->linestart = 0;
+            }
+            ret += d->drv->chr_write(d->drv, buf+i, 1);
+            if (buf[i] == '\n') {
+                d->linestart = 1;
+            }
+        }
+    }
+    return ret;
+}
+
+static const char * const mux_help[] = {
+    "% h    print this help\n\r",
+    "% x    exit emulator\n\r",
+    "% s    save disk data back to file (if -snapshot)\n\r",
+    "% t    toggle console timestamps\n\r"
+    "% b    send break (magic sysrq)\n\r",
+    "% c    switch between console and monitor\n\r",
+    "% %  sends %\n\r",
+    NULL
+};
+
+int term_escape_char = 0x01; /* ctrl-a is used for escape */
+static void mux_print_help(CharDriverState *chr)
+{
+    int i, j;
+    char ebuf[15] = "Escape-Char";
+    char cbuf[50] = "\n\r";
+
+    if (term_escape_char > 0 && term_escape_char < 26) {
+        snprintf(cbuf, sizeof(cbuf), "\n\r");
+        snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
+    } else {
+        snprintf(cbuf, sizeof(cbuf),
+                 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
+                 term_escape_char);
+    }
+    chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf));
+    for (i = 0; mux_help[i] != NULL; i++) {
+        for (j=0; mux_help[i][j] != '\0'; j++) {
+            if (mux_help[i][j] == '%')
+                chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf));
+            else
+                chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);
+        }
+    }
+}
+
+static void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
+{
+    if (d->chr_event[mux_nr])
+        d->chr_event[mux_nr](d->ext_opaque[mux_nr], event);
+}
+
+static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
+{
+    if (d->term_got_escape) {
+        d->term_got_escape = 0;
+        if (ch == term_escape_char)
+            goto send_char;
+        switch(ch) {
+        case '?':
+        case 'h':
+            mux_print_help(chr);
+            break;
+        case 'x':
+            {
+                 const char *term =  "QEMU: Terminated\n\r";
+                 chr->chr_write(chr,(uint8_t *)term,strlen(term));
+                 exit(0);
+                 break;
+            }
+        case 's':
+            {
+                int i;
+                for (i = 0; i < nb_drives; i++) {
+                        bdrv_commit(drives_table[i].bdrv);
+                }
+            }
+            break;
+        case 'b':
+            qemu_chr_event(chr, CHR_EVENT_BREAK);
+            break;
+        case 'c':
+            /* Switch to the next registered device */
+            mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_OUT);
+            chr->focus++;
+            if (chr->focus >= d->mux_cnt)
+                chr->focus = 0;
+            mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN);
+            break;
+        case 't':
+            d->timestamps = !d->timestamps;
+            d->timestamps_start = -1;
+            d->linestart = 0;
+            break;
+        }
+    } else if (ch == term_escape_char) {
+        d->term_got_escape = 1;
+    } else {
+    send_char:
+        return 1;
+    }
+    return 0;
+}
+
+static void mux_chr_accept_input(CharDriverState *chr)
+{
+    int m = chr->focus;
+    MuxDriver *d = chr->opaque;
+
+    while (d->prod[m] != d->cons[m] &&
+           d->chr_can_read[m] &&
+           d->chr_can_read[m](d->ext_opaque[m])) {
+        d->chr_read[m](d->ext_opaque[m],
+                       &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
+    }
+}
+
+static int mux_chr_can_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int m = chr->focus;
+
+    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
+        return 1;
+    if (d->chr_can_read[m])
+        return d->chr_can_read[m](d->ext_opaque[m]);
+    return 0;
+}
+
+static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int m = chr->focus;
+    int i;
+
+    mux_chr_accept_input (opaque);
+
+    for(i = 0; i < size; i++)
+        if (mux_proc_byte(chr, d, buf[i])) {
+            if (d->prod[m] == d->cons[m] &&
+                d->chr_can_read[m] &&
+                d->chr_can_read[m](d->ext_opaque[m]))
+                d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
+            else
+                d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
+        }
+}
+
+static void mux_chr_event(void *opaque, int event)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int i;
+
+    /* Send the event to all registered listeners */
+    for (i = 0; i < d->mux_cnt; i++)
+        mux_chr_send_event(d, i, event);
+}
+
+static void mux_chr_update_read_handler(CharDriverState *chr)
+{
+    MuxDriver *d = chr->opaque;
+
+    if (d->mux_cnt >= MAX_MUX) {
+        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
+        return;
+    }
+    d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
+    d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
+    d->chr_read[d->mux_cnt] = chr->chr_read;
+    d->chr_event[d->mux_cnt] = chr->chr_event;
+    /* Fix up the real driver with mux routines */
+    if (d->mux_cnt == 0) {
+        qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
+                              mux_chr_event, chr);
+    }
+    chr->focus = d->mux_cnt;
+    d->mux_cnt++;
+}
+
+static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+{
+    CharDriverState *chr;
+    MuxDriver *d;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    d = qemu_mallocz(sizeof(MuxDriver));
+
+    chr->opaque = d;
+    d->drv = drv;
+    chr->focus = -1;
+    chr->chr_write = mux_chr_write;
+    chr->chr_update_read_handler = mux_chr_update_read_handler;
+    chr->chr_accept_input = mux_chr_accept_input;
+    return chr;
+}
+
+
+#ifdef _WIN32
+int send_all(int fd, const void *buf, int len1)
+{
+#if 1
+	return socket_send(fd, buf, len1);
+#else
+    int ret, len;
+
+    len = len1;
+    while (len > 0) {
+        ret = send(fd, buf, len, 0);
+        if (ret < 0) {
+            errno = WSAGetLastError();
+            if (errno != WSAEWOULDBLOCK) {
+                return -1;
+            }
+        } else if (ret == 0) {
+            break;
+        } else {
+            buf += ret;
+            len -= ret;
+        }
+    }
+    return len1 - len;
+#endif	
+}
+
+#else
+
+static int unix_write(int fd, const uint8_t *buf, int len1)
+{
+    int ret, len;
+
+    len = len1;
+    while (len > 0) {
+        ret = write(fd, buf, len);
+        if (ret < 0) {
+            if (errno != EINTR && errno != EAGAIN)
+                return -1;
+        } else if (ret == 0) {
+            break;
+        } else {
+            buf += ret;
+            len -= ret;
+        }
+    }
+    return len1 - len;
+}
+
+int send_all(int fd, const void *buf, int len1)
+{
+    return unix_write(fd, buf, len1);
+}
+#endif /* !_WIN32 */
+
+#ifndef _WIN32
+
+typedef struct {
+    int fd_in, fd_out;
+    int max_size;
+} FDCharDriver;
+
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients = 0;
+
+static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    FDCharDriver *s = chr->opaque;
+    return send_all(s->fd_out, buf, len);
+}
+
+static int fd_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+static void fd_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+    int size, len;
+    uint8_t buf[1024];
+
+    len = sizeof(buf);
+    if (len > s->max_size)
+        len = s->max_size;
+    if (len == 0)
+        return;
+    size = read(s->fd_in, buf, len);
+    if (size == 0) {
+        /* FD has been closed. Remove it from the active list.  */
+        qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
+        return;
+    }
+    if (size > 0) {
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void fd_chr_update_read_handler(CharDriverState *chr)
+{
+    FDCharDriver *s = chr->opaque;
+
+    if (s->fd_in >= 0) {
+        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
+        } else {
+            qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
+                                 fd_chr_read, NULL, chr);
+        }
+    }
+}
+
+static void fd_chr_close(struct CharDriverState *chr)
+{
+    FDCharDriver *s = chr->opaque;
+
+    if (s->fd_in >= 0) {
+        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
+        } else {
+            qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
+        }
+    }
+
+    qemu_free(s);
+}
+
+/* open a character device to a unix fd */
+static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
+{
+    CharDriverState *chr;
+    FDCharDriver *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(FDCharDriver));
+    s->fd_in = fd_in;
+    s->fd_out = fd_out;
+    chr->opaque = s;
+    chr->chr_write = fd_chr_write;
+    chr->chr_update_read_handler = fd_chr_update_read_handler;
+    chr->chr_close = fd_chr_close;
+
+    qemu_chr_reset(chr);
+
+    return chr;
+}
+
+static CharDriverState *qemu_chr_open_file_out(const char *file_out)
+{
+    int fd_out;
+
+    TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
+    if (fd_out < 0)
+        return NULL;
+    return qemu_chr_open_fd(-1, fd_out);
+}
+
+static CharDriverState *qemu_chr_open_pipe(const char *filename)
+{
+    int fd_in, fd_out;
+    char filename_in[256], filename_out[256];
+
+    snprintf(filename_in, 256, "%s.in", filename);
+    snprintf(filename_out, 256, "%s.out", filename);
+    TFR(fd_in = open(filename_in, O_RDWR | O_BINARY));
+    TFR(fd_out = open(filename_out, O_RDWR | O_BINARY));
+    if (fd_in < 0 || fd_out < 0) {
+	if (fd_in >= 0)
+	    close(fd_in);
+	if (fd_out >= 0)
+	    close(fd_out);
+        TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
+        if (fd_in < 0)
+            return NULL;
+    }
+    return qemu_chr_open_fd(fd_in, fd_out);
+}
+
+static CharDriverState *qemu_chr_open_fdpair(const char *fd_pair)
+{
+    int fd_in, fd_out;
+    char *endptr;
+
+    /* fd_pair should contain two decimal fd values, separated by
+     * a colon. */
+    endptr = NULL;
+    fd_in = strtol(fd_pair, &endptr, 10);
+    if (endptr == NULL || endptr == fd_pair || *endptr != ':')
+        return NULL;
+    endptr++;   // skip colon
+    fd_pair = endptr;
+    endptr = NULL;
+    fd_out = strtol(fd_pair, &endptr, 10);
+    if (endptr == NULL || endptr == fd_pair || *endptr != '\0')
+        return NULL;
+
+    return qemu_chr_open_fd(fd_in, fd_out);
+}
+
+/* for STDIO, we handle the case where several clients use it
+   (nographic mode) */
+
+#define TERM_FIFO_MAX_SIZE 1
+
+static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
+static int term_fifo_size;
+
+static int stdio_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+
+    /* try to flush the queue if needed */
+    if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
+        qemu_chr_read(chr, term_fifo, 1);
+        term_fifo_size = 0;
+    }
+    /* see if we can absorb more chars */
+    if (term_fifo_size == 0)
+        return 1;
+    else
+        return 0;
+}
+
+static void stdio_read(void *opaque)
+{
+    int size;
+    uint8_t buf[1];
+    CharDriverState *chr = opaque;
+
+    size = read(0, buf, 1);
+    if (size == 0) {
+        /* stdin has been closed. Remove it from the active list.  */
+        qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
+        return;
+    }
+    if (size > 0) {
+        if (qemu_chr_can_read(chr) > 0) {
+            qemu_chr_read(chr, buf, 1);
+        } else if (term_fifo_size == 0) {
+            term_fifo[term_fifo_size++] = buf[0];
+        }
+    }
+}
+
+/* init terminal so that we can grab keys */
+static struct termios oldtty;
+static int old_fd0_flags;
+static int term_atexit_done;
+
+static void term_exit(void)
+{
+    tcsetattr (0, TCSANOW, &oldtty);
+    fcntl(0, F_SETFL, old_fd0_flags);
+}
+
+static void term_init(void)
+{
+    struct termios tty;
+
+    tcgetattr (0, &tty);
+    oldtty = tty;
+    old_fd0_flags = fcntl(0, F_GETFL);
+
+    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                          |INLCR|IGNCR|ICRNL|IXON);
+    tty.c_oflag |= OPOST;
+    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+    /* if graphical mode, we allow Ctrl-C handling */
+    if (display_type == DT_NOGRAPHIC)
+        tty.c_lflag &= ~ISIG;
+    tty.c_cflag &= ~(CSIZE|PARENB);
+    tty.c_cflag |= CS8;
+    tty.c_cc[VMIN] = 1;
+    tty.c_cc[VTIME] = 0;
+
+    tcsetattr (0, TCSANOW, &tty);
+
+    if (!term_atexit_done++)
+        atexit(term_exit);
+
+    fcntl(0, F_SETFL, O_NONBLOCK);
+}
+
+static void qemu_chr_close_stdio(struct CharDriverState *chr)
+{
+    term_exit();
+    stdio_nb_clients--;
+    qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
+    fd_chr_close(chr);
+}
+
+static CharDriverState *qemu_chr_open_stdio(void)
+{
+    CharDriverState *chr;
+
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
+        return NULL;
+    chr = qemu_chr_open_fd(0, 1);
+    chr->chr_close = qemu_chr_close_stdio;
+    qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
+    stdio_nb_clients++;
+    term_init();
+
+    return chr;
+}
+
+#ifdef __sun__
+/* Once Solaris has openpty(), this is going to be removed. */
+static int openpty(int *amaster, int *aslave, char *name,
+                   struct termios *termp, struct winsize *winp)
+{
+        const char *slave;
+        int mfd = -1, sfd = -1;
+
+        *amaster = *aslave = -1;
+
+        mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
+        if (mfd < 0)
+                goto err;
+
+        if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
+                goto err;
+
+        if ((slave = ptsname(mfd)) == NULL)
+                goto err;
+
+        if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
+                goto err;
+
+        if (ioctl(sfd, I_PUSH, "ptem") == -1 ||
+            (termp != NULL && tcgetattr(sfd, termp) < 0))
+                goto err;
+
+        if (amaster)
+                *amaster = mfd;
+        if (aslave)
+                *aslave = sfd;
+        if (winp)
+                ioctl(sfd, TIOCSWINSZ, winp);
+
+        return 0;
+
+err:
+        if (sfd != -1)
+                close(sfd);
+        close(mfd);
+        return -1;
+}
+
+static void cfmakeraw (struct termios *termios_p)
+{
+        termios_p->c_iflag &=
+                ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+        termios_p->c_oflag &= ~OPOST;
+        termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+        termios_p->c_cflag &= ~(CSIZE|PARENB);
+        termios_p->c_cflag |= CS8;
+
+        termios_p->c_cc[VMIN] = 0;
+        termios_p->c_cc[VTIME] = 0;
+}
+#endif
+
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+
+typedef struct {
+    int fd;
+    int connected;
+    int polling;
+    int read_bytes;
+    QEMUTimer *timer;
+} PtyCharDriver;
+
+static void pty_chr_update_read_handler(CharDriverState *chr);
+static void pty_chr_state(CharDriverState *chr, int connected);
+
+static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    if (!s->connected) {
+        /* guest sends data, check for (re-)connect */
+        pty_chr_update_read_handler(chr);
+        return 0;
+    }
+    return send_all(s->fd, buf, len);
+}
+
+static int pty_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+
+    s->read_bytes = qemu_chr_can_read(chr);
+    return s->read_bytes;
+}
+
+static void pty_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+    int size, len;
+    uint8_t buf[1024];
+
+    len = sizeof(buf);
+    if (len > s->read_bytes)
+        len = s->read_bytes;
+    if (len == 0)
+        return;
+    size = read(s->fd, buf, len);
+    if ((size == -1 && errno == EIO) ||
+        (size == 0)) {
+        pty_chr_state(chr, 0);
+        return;
+    }
+    if (size > 0) {
+        pty_chr_state(chr, 1);
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void pty_chr_update_read_handler(CharDriverState *chr)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
+                         pty_chr_read, NULL, chr);
+    s->polling = 1;
+    /*
+     * Short timeout here: just need wait long enougth that qemu makes
+     * it through the poll loop once.  When reconnected we want a
+     * short timeout so we notice it almost instantly.  Otherwise
+     * read() gives us -EIO instantly, making pty_chr_state() reset the
+     * timeout to the normal (much longer) poll interval before the
+     * timer triggers.
+     */
+    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
+}
+
+static void pty_chr_state(CharDriverState *chr, int connected)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    if (!connected) {
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+        s->connected = 0;
+        s->polling = 0;
+        /* (re-)connect poll interval for idle guests: once per second.
+         * We check more frequently in case the guests sends data to
+         * the virtual device linked to our pty. */
+        qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
+    } else {
+        if (!s->connected)
+            qemu_chr_reset(chr);
+        s->connected = 1;
+    }
+}
+
+static void pty_chr_timer(void *opaque)
+{
+    struct CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+
+    if (s->connected)
+        return;
+    if (s->polling) {
+        /* If we arrive here without polling being cleared due
+         * read returning -EIO, then we are (re-)connected */
+        pty_chr_state(chr, 1);
+        return;
+    }
+
+    /* Next poll ... */
+    pty_chr_update_read_handler(chr);
+}
+
+static void pty_chr_close(struct CharDriverState *chr)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    close(s->fd);
+    qemu_del_timer(s->timer);
+    qemu_free_timer(s->timer);
+    qemu_free(s);
+}
+
+static CharDriverState *qemu_chr_open_pty(void)
+{
+    CharDriverState *chr;
+    PtyCharDriver *s;
+    struct termios tty;
+    int slave_fd, len;
+#if defined(__OpenBSD__) || defined(__DragonFly__)
+    char pty_name[PATH_MAX];
+#define q_ptsname(x) pty_name
+#else
+    char *pty_name = NULL;
+#define q_ptsname(x) ptsname(x)
+    extern char* ptsname(int);
+#endif
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(PtyCharDriver));
+
+    if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
+        return NULL;
+    }
+
+    /* Set raw attributes on the pty. */
+    tcgetattr(slave_fd, &tty);
+    cfmakeraw(&tty);
+    tcsetattr(slave_fd, TCSAFLUSH, &tty);
+    close(slave_fd);
+
+    len = strlen(q_ptsname(s->fd)) + 5;
+    chr->filename = qemu_malloc(len);
+    snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
+    fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
+
+    chr->opaque = s;
+    chr->chr_write = pty_chr_write;
+    chr->chr_update_read_handler = pty_chr_update_read_handler;
+    chr->chr_close = pty_chr_close;
+
+    s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
+
+    return chr;
+}
+
+static void tty_serial_init(int fd, int speed,
+                            int parity, int data_bits, int stop_bits)
+{
+    struct termios tty;
+    speed_t spd;
+
+#if 0
+    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
+           speed, parity, data_bits, stop_bits);
+#endif
+    tcgetattr (fd, &tty);
+
+#define MARGIN 1.1
+    if (speed <= 50 * MARGIN)
+        spd = B50;
+    else if (speed <= 75 * MARGIN)
+        spd = B75;
+    else if (speed <= 300 * MARGIN)
+        spd = B300;
+    else if (speed <= 600 * MARGIN)
+        spd = B600;
+    else if (speed <= 1200 * MARGIN)
+        spd = B1200;
+    else if (speed <= 2400 * MARGIN)
+        spd = B2400;
+    else if (speed <= 4800 * MARGIN)
+        spd = B4800;
+    else if (speed <= 9600 * MARGIN)
+        spd = B9600;
+    else if (speed <= 19200 * MARGIN)
+        spd = B19200;
+    else if (speed <= 38400 * MARGIN)
+        spd = B38400;
+    else if (speed <= 57600 * MARGIN)
+        spd = B57600;
+    else if (speed <= 115200 * MARGIN)
+        spd = B115200;
+    else
+        spd = B115200;
+
+    cfsetispeed(&tty, spd);
+    cfsetospeed(&tty, spd);
+
+    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                          |INLCR|IGNCR|ICRNL|IXON);
+    tty.c_oflag |= OPOST;
+    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
+    tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
+    switch(data_bits) {
+    default:
+    case 8:
+        tty.c_cflag |= CS8;
+        break;
+    case 7:
+        tty.c_cflag |= CS7;
+        break;
+    case 6:
+        tty.c_cflag |= CS6;
+        break;
+    case 5:
+        tty.c_cflag |= CS5;
+        break;
+    }
+    switch(parity) {
+    default:
+    case 'N':
+        break;
+    case 'E':
+        tty.c_cflag |= PARENB;
+        break;
+    case 'O':
+        tty.c_cflag |= PARENB | PARODD;
+        break;
+    }
+    if (stop_bits == 2)
+        tty.c_cflag |= CSTOPB;
+
+    tcsetattr (fd, TCSANOW, &tty);
+}
+
+static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    FDCharDriver *s = chr->opaque;
+
+    switch(cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        {
+            QEMUSerialSetParams *ssp = arg;
+            tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
+                            ssp->data_bits, ssp->stop_bits);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_BREAK:
+        {
+            int enable = *(int *)arg;
+            if (enable)
+                tcsendbreak(s->fd_in, 1);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_GET_TIOCM:
+        {
+            int sarg = 0;
+            int *targ = (int *)arg;
+            ioctl(s->fd_in, TIOCMGET, &sarg);
+            *targ = 0;
+            if (sarg & TIOCM_CTS)
+                *targ |= CHR_TIOCM_CTS;
+            if (sarg & TIOCM_CAR)
+                *targ |= CHR_TIOCM_CAR;
+            if (sarg & TIOCM_DSR)
+                *targ |= CHR_TIOCM_DSR;
+            if (sarg & TIOCM_RI)
+                *targ |= CHR_TIOCM_RI;
+            if (sarg & TIOCM_DTR)
+                *targ |= CHR_TIOCM_DTR;
+            if (sarg & TIOCM_RTS)
+                *targ |= CHR_TIOCM_RTS;
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_TIOCM:
+        {
+            int sarg = *(int *)arg;
+            int targ = 0;
+            ioctl(s->fd_in, TIOCMGET, &targ);
+            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
+                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
+            if (sarg & CHR_TIOCM_CTS)
+                targ |= TIOCM_CTS;
+            if (sarg & CHR_TIOCM_CAR)
+                targ |= TIOCM_CAR;
+            if (sarg & CHR_TIOCM_DSR)
+                targ |= TIOCM_DSR;
+            if (sarg & CHR_TIOCM_RI)
+                targ |= TIOCM_RI;
+            if (sarg & CHR_TIOCM_DTR)
+                targ |= TIOCM_DTR;
+            if (sarg & CHR_TIOCM_RTS)
+                targ |= TIOCM_RTS;
+            ioctl(s->fd_in, TIOCMSET, &targ);
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static CharDriverState *qemu_chr_open_tty(const char *filename)
+{
+    CharDriverState *chr;
+    int fd;
+
+    TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
+    tty_serial_init(fd, 115200, 'N', 8, 1);
+    chr = qemu_chr_open_fd(fd, fd);
+    if (!chr) {
+        close(fd);
+        return NULL;
+    }
+    chr->chr_ioctl = tty_serial_ioctl;
+    qemu_chr_reset(chr);
+    return chr;
+}
+#else  /* ! __linux__ && ! __sun__ */
+static CharDriverState *qemu_chr_open_pty(void)
+{
+    return NULL;
+}
+#endif /* __linux__ || __sun__ */
+
+#if defined(__linux__)
+typedef struct {
+    int fd;
+    int mode;
+} ParallelCharDriver;
+
+static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
+{
+    if (s->mode != mode) {
+	int m = mode;
+        if (ioctl(s->fd, PPSETMODE, &m) < 0)
+            return 0;
+	s->mode = mode;
+    }
+    return 1;
+}
+
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    ParallelCharDriver *drv = chr->opaque;
+    int fd = drv->fd;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPRDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPRCONTROL, &b) < 0)
+            return -ENOTSUP;
+	/* Linux gives only the lowest bits, and no way to know data
+	   direction! For better compatibility set the fixed upper
+	   bits. */
+        *(uint8_t *)arg = b | 0xc0;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWCONTROL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPRSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_DATA_DIR:
+        if (ioctl(fd, PPDATADIR, (int *)arg) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_EPP_READ_ADDR:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = read(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_READ:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = read(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = write(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = write(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void pp_close(CharDriverState *chr)
+{
+    ParallelCharDriver *drv = chr->opaque;
+    int fd = drv->fd;
+
+    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
+    ioctl(fd, PPRELEASE);
+    close(fd);
+    qemu_free(drv);
+}
+
+static CharDriverState *qemu_chr_open_pp(const char *filename)
+{
+    CharDriverState *chr;
+    ParallelCharDriver *drv;
+    int fd;
+
+    TFR(fd = open(filename, O_RDWR));
+    if (fd < 0)
+        return NULL;
+
+    if (ioctl(fd, PPCLAIM) < 0) {
+        close(fd);
+        return NULL;
+    }
+
+    drv = qemu_mallocz(sizeof(ParallelCharDriver));
+    drv->fd = fd;
+    drv->mode = IEEE1284_MODE_COMPAT;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->chr_write = null_chr_write;
+    chr->chr_ioctl = pp_ioctl;
+    chr->chr_close = pp_close;
+    chr->opaque = drv;
+
+    qemu_chr_reset(chr);
+
+    return chr;
+}
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    int fd = (int)chr->opaque;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPIGDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPISDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPIGCTRL, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPISCTRL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPIGSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static CharDriverState *qemu_chr_open_pp(const char *filename)
+{
+    CharDriverState *chr;
+    int fd;
+
+    fd = open(filename, O_RDWR);
+    if (fd < 0)
+        return NULL;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->opaque = (void *)fd;
+    chr->chr_write = null_chr_write;
+    chr->chr_ioctl = pp_ioctl;
+    return chr;
+}
+#endif
+
+#else /* _WIN32 */
+
+typedef struct {
+    int max_size;
+    HANDLE hcom, hrecv, hsend;
+    OVERLAPPED orecv, osend;
+    BOOL fpipe;
+    DWORD len;
+} WinCharState;
+
+#define NSENDBUF 2048
+#define NRECVBUF 2048
+#define MAXCONNECT 1
+#define NTIMEOUT 5000
+
+static int win_chr_poll(void *opaque);
+static int win_chr_pipe_poll(void *opaque);
+
+static void win_chr_close(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    if (s->hsend) {
+        CloseHandle(s->hsend);
+        s->hsend = NULL;
+    }
+    if (s->hrecv) {
+        CloseHandle(s->hrecv);
+        s->hrecv = NULL;
+    }
+    if (s->hcom) {
+        CloseHandle(s->hcom);
+        s->hcom = NULL;
+    }
+    if (s->fpipe)
+        qemu_del_polling_cb(win_chr_pipe_poll, chr);
+    else
+        qemu_del_polling_cb(win_chr_poll, chr);
+}
+
+static int win_chr_init(CharDriverState *chr, const char *filename)
+{
+    WinCharState *s = chr->opaque;
+    COMMCONFIG comcfg;
+    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
+    COMSTAT comstat;
+    DWORD size;
+    DWORD err;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+
+    s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
+        fprintf(stderr, "Failed SetupComm\n");
+        goto fail;
+    }
+
+    ZeroMemory(&comcfg, sizeof(COMMCONFIG));
+    size = sizeof(COMMCONFIG);
+    GetDefaultCommConfig(filename, &comcfg, &size);
+    comcfg.dcb.DCBlength = sizeof(DCB);
+    CommConfigDialog(filename, NULL, &comcfg);
+
+    if (!SetCommState(s->hcom, &comcfg.dcb)) {
+        fprintf(stderr, "Failed SetCommState\n");
+        goto fail;
+    }
+
+    if (!SetCommMask(s->hcom, EV_ERR)) {
+        fprintf(stderr, "Failed SetCommMask\n");
+        goto fail;
+    }
+
+    cto.ReadIntervalTimeout = MAXDWORD;
+    if (!SetCommTimeouts(s->hcom, &cto)) {
+        fprintf(stderr, "Failed SetCommTimeouts\n");
+        goto fail;
+    }
+
+    if (!ClearCommError(s->hcom, &err, &comstat)) {
+        fprintf(stderr, "Failed ClearCommError\n");
+        goto fail;
+    }
+    qemu_add_polling_cb(win_chr_poll, chr);
+    return 0;
+
+ fail:
+    win_chr_close(chr);
+    return -1;
+}
+
+static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
+{
+    WinCharState *s = chr->opaque;
+    DWORD len, ret, size, err;
+
+    len = len1;
+    ZeroMemory(&s->osend, sizeof(s->osend));
+    s->osend.hEvent = s->hsend;
+    while (len > 0) {
+        if (s->hsend)
+            ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
+        else
+            ret = WriteFile(s->hcom, buf, len, &size, NULL);
+        if (!ret) {
+            err = GetLastError();
+            if (err == ERROR_IO_PENDING) {
+                ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
+                if (ret) {
+                    buf += size;
+                    len -= size;
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        } else {
+            buf += size;
+            len -= size;
+        }
+    }
+    return len1 - len;
+}
+
+static int win_chr_read_poll(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+static void win_chr_readfile(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+    int ret, err;
+    uint8_t buf[1024];
+    DWORD size;
+
+    ZeroMemory(&s->orecv, sizeof(s->orecv));
+    s->orecv.hEvent = s->hrecv;
+    ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
+    if (!ret) {
+        err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
+        }
+    }
+
+    if (size > 0) {
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void win_chr_read(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    if (s->len > s->max_size)
+        s->len = s->max_size;
+    if (s->len == 0)
+        return;
+
+    win_chr_readfile(chr);
+}
+
+static int win_chr_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    WinCharState *s = chr->opaque;
+    COMSTAT status;
+    DWORD comerr;
+
+    ClearCommError(s->hcom, &comerr, &status);
+    if (status.cbInQue > 0) {
+        s->len = status.cbInQue;
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
+        return 1;
+    }
+    return 0;
+}
+
+static CharDriverState *qemu_chr_open_win(const char *filename)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_close = win_chr_close;
+
+    if (win_chr_init(chr, filename) < 0) {
+        free(s);
+        free(chr);
+        return NULL;
+    }
+    qemu_chr_reset(chr);
+    return chr;
+}
+
+static int win_chr_pipe_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    WinCharState *s = chr->opaque;
+    DWORD size;
+
+    PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
+    if (size > 0) {
+        s->len = size;
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
+        return 1;
+    }
+    return 0;
+}
+
+static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
+{
+    WinCharState *s = chr->opaque;
+    OVERLAPPED ov;
+    int ret;
+    DWORD size;
+    char openname[256];
+
+    s->fpipe = TRUE;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+
+    snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
+    s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
+                              PIPE_WAIT,
+                              MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    ZeroMemory(&ov, sizeof(ov));
+    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    ret = ConnectNamedPipe(s->hcom, &ov);
+    if (ret) {
+        fprintf(stderr, "Failed ConnectNamedPipe\n");
+        goto fail;
+    }
+
+    ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
+    if (!ret) {
+        fprintf(stderr, "Failed GetOverlappedResult\n");
+        if (ov.hEvent) {
+            CloseHandle(ov.hEvent);
+            ov.hEvent = NULL;
+        }
+        goto fail;
+    }
+
+    if (ov.hEvent) {
+        CloseHandle(ov.hEvent);
+        ov.hEvent = NULL;
+    }
+    qemu_add_polling_cb(win_chr_pipe_poll, chr);
+    return 0;
+
+ fail:
+    win_chr_close(chr);
+    return -1;
+}
+
+
+static CharDriverState *qemu_chr_open_win_pipe(const char *filename)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_close = win_chr_close;
+
+    if (win_chr_pipe_init(chr, filename) < 0) {
+        free(s);
+        free(chr);
+        return NULL;
+    }
+    qemu_chr_reset(chr);
+    return chr;
+}
+
+static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    s->hcom = fd_out;
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    qemu_chr_reset(chr);
+    return chr;
+}
+
+static CharDriverState *qemu_chr_open_win_con(const char *filename)
+{
+    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
+}
+
+static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
+{
+    HANDLE fd_out;
+
+    fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (fd_out == INVALID_HANDLE_VALUE)
+        return NULL;
+
+    return qemu_chr_open_win_file(fd_out);
+}
+#endif /* !_WIN32 */
+
+/***********************************************************/
+/* UDP Net console */
+
+typedef struct {
+    int fd;
+    SockAddress  daddr;
+    uint8_t buf[1024];
+    int bufcnt;
+    int bufptr;
+    int max_size;
+} NetCharDriver;
+
+static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    NetCharDriver *s = chr->opaque;
+
+    return socket_sendto(s->fd, (const void *)buf, len, &s->daddr);
+}
+
+static int udp_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    NetCharDriver *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+
+    /* If there were any stray characters in the queue process them
+     * first
+     */
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        s->bufptr++;
+        s->max_size = qemu_chr_can_read(chr);
+    }
+    return s->max_size;
+}
+
+static void udp_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    NetCharDriver *s = chr->opaque;
+
+    if (s->max_size == 0)
+        return;
+    s->bufcnt = socket_recv(s->fd, (void *)s->buf, sizeof(s->buf));
+    s->bufptr = s->bufcnt;
+    if (s->bufcnt <= 0)
+        return;
+
+    s->bufptr = 0;
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        s->bufptr++;
+        s->max_size = qemu_chr_can_read(chr);
+    }
+}
+
+static void udp_chr_update_read_handler(CharDriverState *chr)
+{
+    NetCharDriver *s = chr->opaque;
+
+    if (s->fd >= 0) {
+        qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
+                             udp_chr_read, NULL, chr);
+    }
+}
+
+static void udp_chr_close(CharDriverState *chr)
+{
+    NetCharDriver *s = chr->opaque;
+    if (s->fd >= 0) {
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        socket_close(s->fd);
+    }
+    qemu_free(s);
+}
+
+static CharDriverState *qemu_chr_open_udp(const char *def)
+{
+    CharDriverState *chr = NULL;
+    NetCharDriver *s = NULL;
+    int fd = -1;
+    SockAddress  saddr;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s   = qemu_mallocz(sizeof(NetCharDriver));
+
+    fd = socket_create_inet(SOCKET_DGRAM);
+    if (fd < 0) {
+        perror("socket(PF_INET, SOCK_DGRAM)");
+        goto return_err;
+    }
+
+    if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
+        printf("Could not parse: %s\n", def);
+        goto return_err;
+    }
+
+    if (socket_bind(fd, &saddr) < 0) {
+        perror("bind");
+        goto return_err;
+    }
+
+    s->fd = fd;
+    s->bufcnt = 0;
+    s->bufptr = 0;
+    chr->opaque = s;
+    chr->chr_write = udp_chr_write;
+    chr->chr_update_read_handler = udp_chr_update_read_handler;
+    chr->chr_close = udp_chr_close;
+    return chr;
+
+return_err:
+    if (chr)
+        free(chr);
+    if (s)
+        free(s);
+    if (fd >= 0)
+        closesocket(fd);
+    return NULL;
+}
+
+/***********************************************************/
+/* TCP Net console */
+
+typedef struct {
+    int fd, listen_fd;
+    int connected;
+    int max_size;
+    int do_telnetopt;
+    int do_nodelay;
+    int is_unix;
+} TCPCharDriver;
+
+static void tcp_chr_accept(void *opaque);
+
+static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->connected) {
+        return send_all(s->fd, buf, len);
+    } else {
+        /* XXX: indicate an error ? */
+        return len;
+    }
+}
+
+static int tcp_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    if (!s->connected)
+        return 0;
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+#define IAC 255
+#define IAC_BREAK 243
+static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
+                                      TCPCharDriver *s,
+                                      uint8_t *buf, int *size)
+{
+    /* Handle any telnet client's basic IAC options to satisfy char by
+     * char mode with no echo.  All IAC options will be removed from
+     * the buf and the do_telnetopt variable will be used to track the
+     * state of the width of the IAC information.
+     *
+     * IAC commands come in sets of 3 bytes with the exception of the
+     * "IAC BREAK" command and the double IAC.
+     */
+
+    int i;
+    int j = 0;
+
+    for (i = 0; i < *size; i++) {
+        if (s->do_telnetopt > 1) {
+            if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+                /* Double IAC means send an IAC */
+                if (j != i)
+                    buf[j] = buf[i];
+                j++;
+                s->do_telnetopt = 1;
+            } else {
+                if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
+                    /* Handle IAC break commands by sending a serial break */
+                    qemu_chr_event(chr, CHR_EVENT_BREAK);
+                    s->do_telnetopt++;
+                }
+                s->do_telnetopt++;
+            }
+            if (s->do_telnetopt >= 4) {
+                s->do_telnetopt = 1;
+            }
+        } else {
+            if ((unsigned char)buf[i] == IAC) {
+                s->do_telnetopt = 2;
+            } else {
+                if (j != i)
+                    buf[j] = buf[i];
+                j++;
+            }
+        }
+    }
+    *size = j;
+}
+
+static void tcp_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    uint8_t buf[1024];
+    int len, size;
+
+    if (!s->connected || s->max_size <= 0)
+        return;
+    len = sizeof(buf);
+    if (len > s->max_size)
+        len = s->max_size;
+    size = socket_recv(s->fd, (void *)buf, len);
+    if (size == 0) {
+        /* connection closed */
+        s->connected = 0;
+        if (s->listen_fd >= 0) {
+            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        }
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        socket_close(s->fd);
+        s->fd = -1;
+    } else if (size > 0) {
+        if (s->do_telnetopt)
+            tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+        if (size > 0)
+            qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void tcp_chr_connect(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+
+    s->connected = 1;
+    qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
+                         tcp_chr_read, NULL, chr);
+    qemu_chr_reset(chr);
+}
+
+#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
+static void tcp_chr_telnet_init(int fd)
+{
+    char buf[3];
+    /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
+    IACSET(buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
+    socket_send(fd, (char *)buf, 3);
+    IACSET(buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
+    socket_send(fd, (char *)buf, 3);
+    IACSET(buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
+    socket_send(fd, (char *)buf, 3);
+    IACSET(buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
+    socket_send(fd, (char *)buf, 3);
+}
+
+static void tcp_chr_accept(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    int fd;
+
+    for(;;) {
+        fd = socket_accept(s->listen_fd, NULL);
+        if (fd < 0) {
+            return;
+        } else if (fd >= 0) {
+            if (s->do_telnetopt)
+                tcp_chr_telnet_init(fd);
+            break;
+        }
+    }
+    socket_set_nonblock(fd);
+    if (s->do_nodelay)
+        socket_set_nodelay(fd);
+    s->fd = fd;
+    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+    tcp_chr_connect(chr);
+}
+
+static void tcp_chr_close(CharDriverState *chr)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->fd >= 0) {
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+    }
+    if (s->listen_fd >= 0) {
+        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+        closesocket(s->listen_fd);
+    }
+    qemu_free(s);
+}
+
+static CharDriverState *qemu_chr_open_tcp(const char *host_str,
+                                          int is_telnet,
+					  int is_unix)
+{
+    CharDriverState *chr = NULL;
+    TCPCharDriver *s = NULL;
+    int fd = -1, offset = 0;
+    int is_listen = 0;
+    int is_waitconnect = 1;
+    int do_nodelay = 0;
+    const char *ptr;
+
+    ptr = host_str;
+    while((ptr = strchr(ptr,','))) {
+        ptr++;
+        if (!strncmp(ptr,"server",6)) {
+            is_listen = 1;
+        } else if (!strncmp(ptr,"nowait",6)) {
+            is_waitconnect = 0;
+        } else if (!strncmp(ptr,"nodelay",6)) {
+            do_nodelay = 1;
+        } else if (!strncmp(ptr,"to=",3)) {
+            /* nothing, inet_listen() parses this one */;
+        } else if (!strncmp(ptr,"ipv4",4)) {
+            /* nothing, inet_connect() and inet_listen() parse this one */;
+        } else if (!strncmp(ptr,"ipv6",4)) {
+            /* nothing, inet_connect() and inet_listen() parse this one */;
+        } else {
+            printf("Unknown option: %s\n", ptr);
+            goto fail;
+        }
+    }
+    if (!is_listen)
+        is_waitconnect = 0;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(TCPCharDriver));
+
+    if (is_listen) {
+        chr->filename = qemu_malloc(256);
+        if (is_unix) {
+            pstrcpy(chr->filename, 256, "unix:");
+        } else if (is_telnet) {
+            pstrcpy(chr->filename, 256, "telnet:");
+        } else {
+            pstrcpy(chr->filename, 256, "tcp:");
+        }
+        offset = strlen(chr->filename);
+    }
+    if (is_unix) {
+        if (is_listen) {
+            fd = unix_listen(host_str, chr->filename + offset, 256 - offset);
+        } else {
+            fd = unix_connect(host_str);
+        }
+    } else {
+        if (is_listen) {
+            fd = inet_listen(host_str, chr->filename + offset, 256 - offset,
+                             SOCKET_STREAM, 0);
+        } else {
+            fd = inet_connect(host_str, SOCKET_STREAM);
+        }
+    }
+    if (fd < 0)
+        goto fail;
+
+    if (!is_waitconnect)
+        socket_set_nonblock(fd);
+
+    s->connected = 0;
+    s->fd = -1;
+    s->listen_fd = -1;
+    s->is_unix = is_unix;
+    s->do_nodelay = do_nodelay && !is_unix;
+
+    chr->opaque = s;
+    chr->chr_write = tcp_chr_write;
+    chr->chr_close = tcp_chr_close;
+
+    if (is_listen) {
+        s->listen_fd = fd;
+        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        if (is_telnet)
+            s->do_telnetopt = 1;
+    } else {
+        s->connected = 1;
+        s->fd = fd;
+        socket_set_nodelay(fd);
+        tcp_chr_connect(chr);
+    }
+
+    if (is_listen && is_waitconnect) {
+        printf("QEMU waiting for connection on: %s\n",
+               chr->filename ? chr->filename : host_str);
+        tcp_chr_accept(chr);
+        socket_set_nonblock(s->listen_fd);
+    }
+
+    return chr;
+ fail:
+    if (fd >= 0)
+        closesocket(fd);
+    qemu_free(s);
+    qemu_free(chr);
+    return NULL;
+}
+
+CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
+{
+    const char *p;
+    CharDriverState *chr;
+
+    if (!strcmp(filename, "vc")) {
+        chr = text_console_init(0);
+    } else
+    if (strstart(filename, "vc:", &p)) {
+        chr = text_console_init(p);
+    } else
+    if (!strcmp(filename, "null")) {
+        chr = qemu_chr_open_null();
+    } else
+    if (strstart(filename, "tcp:", &p)) {
+        chr = qemu_chr_open_tcp(p, 0, 0);
+    } else
+    if (strstart(filename, "telnet:", &p)) {
+        chr = qemu_chr_open_tcp(p, 1, 0);
+    } else
+    if (strstart(filename, "udp:", &p)) {
+        chr = qemu_chr_open_udp(p);
+    } else
+    if (strstart(filename, "mon:", &p)) {
+        chr = qemu_chr_open(label, p, NULL);
+        if (chr) {
+            chr = qemu_chr_open_mux(chr);
+            monitor_init(chr, MONITOR_USE_READLINE);
+        } else {
+            printf("Unable to open driver: %s\n", p);
+        }
+    } else if (!strcmp(filename, "msmouse")) {
+        chr = qemu_chr_open_msmouse();
+    } else
+#ifndef _WIN32
+    if (strstart(filename, "unix:", &p)) {
+	chr = qemu_chr_open_tcp(p, 0, 1);
+    } else if (strstart(filename, "file:", &p)) {
+        chr = qemu_chr_open_file_out(p);
+    } else if (strstart(filename, "pipe:", &p)) {
+        chr = qemu_chr_open_pipe(p);
+    } else if (strstart(filename, "fdpair:", &p)) {
+        chr = qemu_chr_open_fdpair(p);
+    } else if (!strcmp(filename, "pty")) {
+        chr = qemu_chr_open_pty();
+    } else if (!strcmp(filename, "stdio")) {
+        chr = qemu_chr_open_stdio();
+    } else
+#if defined(__linux__)
+    if (strstart(filename, "/dev/parport", NULL)) {
+        chr = qemu_chr_open_pp(filename);
+    } else
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+    if (strstart(filename, "/dev/ppi", NULL)) {
+        chr = qemu_chr_open_pp(filename);
+    } else
+#endif
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+    if (strstart(filename, "/dev/", NULL)) {
+        chr = qemu_chr_open_tty(filename);
+    } else
+#endif
+#else /* !_WIN32 */
+    if (strstart(filename, "COM", NULL)) {
+        chr = qemu_chr_open_win(filename);
+    } else
+    if (strstart(filename, "pipe:", &p)) {
+        chr = qemu_chr_open_win_pipe(p);
+    } else
+    if (strstart(filename, "con:", NULL)) {
+        chr = qemu_chr_open_win_con(filename);
+    } else
+    if (strstart(filename, "file:", &p)) {
+        chr = qemu_chr_open_win_file_out(p);
+    } else
+#endif
+    if (!strcmp(filename, "android-modem")) {
+        CharDriverState*  cs;
+        qemu_chr_open_charpipe( &cs, &android_modem_cs );
+        return cs;
+    } else if (!strcmp(filename, "android-gps")) {
+        CharDriverState*  cs;
+        qemu_chr_open_charpipe( &cs, &android_gps_cs );
+        return cs;
+    } else if (!strcmp(filename, "android-kmsg")) {
+        return android_kmsg_get_cs();
+    } else if (!strcmp(filename, "android-qemud")) {
+        return android_qemud_get_cs();
+    } else
+#ifdef CONFIG_BRLAPI
+    if (!strcmp(filename, "braille")) {
+        chr = chr_baum_init();
+    } else
+#endif
+    {
+        chr = NULL;
+    }
+
+    if (chr) {
+        if (!chr->filename)
+            chr->filename = qemu_strdup(filename);
+        chr->init = init;
+        chr->label = qemu_strdup(label);
+        TAILQ_INSERT_TAIL(&chardevs, chr, next);
+    }
+    return chr;
+}
+
+void qemu_chr_close(CharDriverState *chr)
+{
+    TAILQ_REMOVE(&chardevs, chr, next);
+    if (chr->chr_close)
+        chr->chr_close(chr);
+    qemu_free(chr->filename);
+    qemu_free(chr->label);
+    qemu_free(chr);
+}
+
+void qemu_chr_info(Monitor *mon)
+{
+    CharDriverState *chr;
+
+    TAILQ_FOREACH(chr, &chardevs, next) {
+        monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename);
+    }
+}
diff --git a/qemu-char.c b/qemu-char.c
new file mode 100644
index 0000000..287e0cd
--- /dev/null
+++ b/qemu-char.c
@@ -0,0 +1,2244 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "net.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "block.h"
+#include "hw/usb.h"
+#include "hw/baum.h"
+#include "hw/msmouse.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+#ifndef _WIN32
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#ifdef __NetBSD__
+#include <net/if_tap.h>
+#endif
+#ifdef __linux__
+#include <linux/if_tun.h>
+#endif
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+#ifdef HOST_BSD
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <libutil.h>
+#include <dev/ppbus/ppi.h>
+#include <dev/ppbus/ppbconf.h>
+#elif defined(__DragonFly__)
+#include <libutil.h>
+#include <dev/misc/ppi/ppi.h>
+#include <bus/ppbus/ppbconf.h>
+#else
+#include <util.h>
+#endif
+#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+#include <freebsd/stdlib.h>
+#else
+#ifdef __linux__
+#include <pty.h>
+
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+#endif
+#ifdef __sun__
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
+#endif
+#endif
+#endif
+
+#include "qemu_socket.h"
+
+/***********************************************************/
+/* character device */
+
+static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
+    TAILQ_HEAD_INITIALIZER(chardevs);
+static int initial_reset_issued;
+
+static void qemu_chr_event(CharDriverState *s, int event)
+{
+    if (!s->chr_event)
+        return;
+    s->chr_event(s->handler_opaque, event);
+}
+
+static void qemu_chr_reset_bh(void *opaque)
+{
+    CharDriverState *s = opaque;
+    qemu_chr_event(s, CHR_EVENT_RESET);
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+}
+
+void qemu_chr_reset(CharDriverState *s)
+{
+    if (s->bh == NULL && initial_reset_issued) {
+	s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
+	qemu_bh_schedule(s->bh);
+    }
+}
+
+void qemu_chr_initial_reset(void)
+{
+    CharDriverState *chr;
+
+    initial_reset_issued = 1;
+
+    TAILQ_FOREACH(chr, &chardevs, next) {
+        qemu_chr_reset(chr);
+    }
+}
+
+int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
+{
+    return s->chr_write(s, buf, len);
+}
+
+int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
+{
+    if (!s->chr_ioctl)
+        return -ENOTSUP;
+    return s->chr_ioctl(s, cmd, arg);
+}
+
+int qemu_chr_can_read(CharDriverState *s)
+{
+    if (!s->chr_can_read)
+        return 0;
+    return s->chr_can_read(s->handler_opaque);
+}
+
+void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
+{
+    s->chr_read(s->handler_opaque, buf, len);
+}
+
+void qemu_chr_accept_input(CharDriverState *s)
+{
+    if (s->chr_accept_input)
+        s->chr_accept_input(s);
+}
+
+void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
+{
+    char buf[4096];
+    va_list ap;
+    va_start(ap, fmt);
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    qemu_chr_write(s, (uint8_t *)buf, strlen(buf));
+    va_end(ap);
+}
+
+void qemu_chr_send_event(CharDriverState *s, int event)
+{
+    if (s->chr_send_event)
+        s->chr_send_event(s, event);
+}
+
+void qemu_chr_add_handlers(CharDriverState *s,
+                           IOCanRWHandler *fd_can_read,
+                           IOReadHandler *fd_read,
+                           IOEventHandler *fd_event,
+                           void *opaque)
+{
+    s->chr_can_read = fd_can_read;
+    s->chr_read = fd_read;
+    s->chr_event = fd_event;
+    s->handler_opaque = opaque;
+    if (s->chr_update_read_handler)
+        s->chr_update_read_handler(s);
+}
+
+static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    return len;
+}
+
+static CharDriverState *qemu_chr_open_null(void)
+{
+    CharDriverState *chr;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->chr_write = null_chr_write;
+    return chr;
+}
+
+/* MUX driver for serial I/O splitting */
+#define MAX_MUX 4
+#define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
+#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
+typedef struct {
+    IOCanRWHandler *chr_can_read[MAX_MUX];
+    IOReadHandler *chr_read[MAX_MUX];
+    IOEventHandler *chr_event[MAX_MUX];
+    void *ext_opaque[MAX_MUX];
+    CharDriverState *drv;
+    int mux_cnt;
+    int term_got_escape;
+    int max_size;
+    /* Intermediate input buffer allows to catch escape sequences even if the
+       currently active device is not accepting any input - but only until it
+       is full as well. */
+    unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
+    int prod[MAX_MUX];
+    int cons[MAX_MUX];
+    int timestamps;
+    int linestart;
+    int64_t timestamps_start;
+} MuxDriver;
+
+
+static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MuxDriver *d = chr->opaque;
+    int ret;
+    if (!d->timestamps) {
+        ret = d->drv->chr_write(d->drv, buf, len);
+    } else {
+        int i;
+
+        ret = 0;
+        for (i = 0; i < len; i++) {
+            if (d->linestart) {
+                char buf1[64];
+                int64_t ti;
+                int secs;
+
+                ti = qemu_get_clock(rt_clock);
+                if (d->timestamps_start == -1)
+                    d->timestamps_start = ti;
+                ti -= d->timestamps_start;
+                secs = ti / 1000;
+                snprintf(buf1, sizeof(buf1),
+                         "[%02d:%02d:%02d.%03d] ",
+                         secs / 3600,
+                         (secs / 60) % 60,
+                         secs % 60,
+                         (int)(ti % 1000));
+                d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
+                d->linestart = 0;
+            }
+            ret += d->drv->chr_write(d->drv, buf+i, 1);
+            if (buf[i] == '\n') {
+                d->linestart = 1;
+            }
+        }
+    }
+    return ret;
+}
+
+static const char * const mux_help[] = {
+    "% h    print this help\n\r",
+    "% x    exit emulator\n\r",
+    "% s    save disk data back to file (if -snapshot)\n\r",
+    "% t    toggle console timestamps\n\r"
+    "% b    send break (magic sysrq)\n\r",
+    "% c    switch between console and monitor\n\r",
+    "% %  sends %\n\r",
+    NULL
+};
+
+int term_escape_char = 0x01; /* ctrl-a is used for escape */
+static void mux_print_help(CharDriverState *chr)
+{
+    int i, j;
+    char ebuf[15] = "Escape-Char";
+    char cbuf[50] = "\n\r";
+
+    if (term_escape_char > 0 && term_escape_char < 26) {
+        snprintf(cbuf, sizeof(cbuf), "\n\r");
+        snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
+    } else {
+        snprintf(cbuf, sizeof(cbuf),
+                 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
+                 term_escape_char);
+    }
+    chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf));
+    for (i = 0; mux_help[i] != NULL; i++) {
+        for (j=0; mux_help[i][j] != '\0'; j++) {
+            if (mux_help[i][j] == '%')
+                chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf));
+            else
+                chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);
+        }
+    }
+}
+
+static void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
+{
+    if (d->chr_event[mux_nr])
+        d->chr_event[mux_nr](d->ext_opaque[mux_nr], event);
+}
+
+static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
+{
+    if (d->term_got_escape) {
+        d->term_got_escape = 0;
+        if (ch == term_escape_char)
+            goto send_char;
+        switch(ch) {
+        case '?':
+        case 'h':
+            mux_print_help(chr);
+            break;
+        case 'x':
+            {
+                 const char *term =  "QEMU: Terminated\n\r";
+                 chr->chr_write(chr,(uint8_t *)term,strlen(term));
+                 exit(0);
+                 break;
+            }
+        case 's':
+            {
+                int i;
+                for (i = 0; i < nb_drives; i++) {
+                        bdrv_commit(drives_table[i].bdrv);
+                }
+            }
+            break;
+        case 'b':
+            qemu_chr_event(chr, CHR_EVENT_BREAK);
+            break;
+        case 'c':
+            /* Switch to the next registered device */
+            mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_OUT);
+            chr->focus++;
+            if (chr->focus >= d->mux_cnt)
+                chr->focus = 0;
+            mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN);
+            break;
+        case 't':
+            d->timestamps = !d->timestamps;
+            d->timestamps_start = -1;
+            d->linestart = 0;
+            break;
+        }
+    } else if (ch == term_escape_char) {
+        d->term_got_escape = 1;
+    } else {
+    send_char:
+        return 1;
+    }
+    return 0;
+}
+
+static void mux_chr_accept_input(CharDriverState *chr)
+{
+    int m = chr->focus;
+    MuxDriver *d = chr->opaque;
+
+    while (d->prod[m] != d->cons[m] &&
+           d->chr_can_read[m] &&
+           d->chr_can_read[m](d->ext_opaque[m])) {
+        d->chr_read[m](d->ext_opaque[m],
+                       &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
+    }
+}
+
+static int mux_chr_can_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int m = chr->focus;
+
+    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
+        return 1;
+    if (d->chr_can_read[m])
+        return d->chr_can_read[m](d->ext_opaque[m]);
+    return 0;
+}
+
+static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int m = chr->focus;
+    int i;
+
+    mux_chr_accept_input (opaque);
+
+    for(i = 0; i < size; i++)
+        if (mux_proc_byte(chr, d, buf[i])) {
+            if (d->prod[m] == d->cons[m] &&
+                d->chr_can_read[m] &&
+                d->chr_can_read[m](d->ext_opaque[m]))
+                d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
+            else
+                d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
+        }
+}
+
+static void mux_chr_event(void *opaque, int event)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int i;
+
+    /* Send the event to all registered listeners */
+    for (i = 0; i < d->mux_cnt; i++)
+        mux_chr_send_event(d, i, event);
+}
+
+static void mux_chr_update_read_handler(CharDriverState *chr)
+{
+    MuxDriver *d = chr->opaque;
+
+    if (d->mux_cnt >= MAX_MUX) {
+        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
+        return;
+    }
+    d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
+    d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
+    d->chr_read[d->mux_cnt] = chr->chr_read;
+    d->chr_event[d->mux_cnt] = chr->chr_event;
+    /* Fix up the real driver with mux routines */
+    if (d->mux_cnt == 0) {
+        qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
+                              mux_chr_event, chr);
+    }
+    chr->focus = d->mux_cnt;
+    d->mux_cnt++;
+}
+
+static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+{
+    CharDriverState *chr;
+    MuxDriver *d;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    d = qemu_mallocz(sizeof(MuxDriver));
+
+    chr->opaque = d;
+    d->drv = drv;
+    chr->focus = -1;
+    chr->chr_write = mux_chr_write;
+    chr->chr_update_read_handler = mux_chr_update_read_handler;
+    chr->chr_accept_input = mux_chr_accept_input;
+    return chr;
+}
+
+
+#ifdef _WIN32
+int send_all(int fd, const void *buf, int len1)
+{
+    int ret, len;
+
+    len = len1;
+    while (len > 0) {
+        ret = send(fd, buf, len, 0);
+        if (ret < 0) {
+            errno = WSAGetLastError();
+            if (errno != WSAEWOULDBLOCK) {
+                return -1;
+            }
+        } else if (ret == 0) {
+            break;
+        } else {
+            buf += ret;
+            len -= ret;
+        }
+    }
+    return len1 - len;
+}
+
+#else
+
+static int unix_write(int fd, const uint8_t *buf, int len1)
+{
+    int ret, len;
+
+    len = len1;
+    while (len > 0) {
+        ret = write(fd, buf, len);
+        if (ret < 0) {
+            if (errno != EINTR && errno != EAGAIN)
+                return -1;
+        } else if (ret == 0) {
+            break;
+        } else {
+            buf += ret;
+            len -= ret;
+        }
+    }
+    return len1 - len;
+}
+
+int send_all(int fd, const void *buf, int len1)
+{
+    return unix_write(fd, buf, len1);
+}
+#endif /* !_WIN32 */
+
+#ifndef _WIN32
+
+typedef struct {
+    int fd_in, fd_out;
+    int max_size;
+} FDCharDriver;
+
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients = 0;
+
+static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    FDCharDriver *s = chr->opaque;
+    return send_all(s->fd_out, buf, len);
+}
+
+static int fd_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+static void fd_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+    int size, len;
+    uint8_t buf[1024];
+
+    len = sizeof(buf);
+    if (len > s->max_size)
+        len = s->max_size;
+    if (len == 0)
+        return;
+    size = read(s->fd_in, buf, len);
+    if (size == 0) {
+        /* FD has been closed. Remove it from the active list.  */
+        qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
+        return;
+    }
+    if (size > 0) {
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void fd_chr_update_read_handler(CharDriverState *chr)
+{
+    FDCharDriver *s = chr->opaque;
+
+    if (s->fd_in >= 0) {
+        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
+        } else {
+            qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
+                                 fd_chr_read, NULL, chr);
+        }
+    }
+}
+
+static void fd_chr_close(struct CharDriverState *chr)
+{
+    FDCharDriver *s = chr->opaque;
+
+    if (s->fd_in >= 0) {
+        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
+        } else {
+            qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
+        }
+    }
+
+    qemu_free(s);
+}
+
+/* open a character device to a unix fd */
+static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
+{
+    CharDriverState *chr;
+    FDCharDriver *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(FDCharDriver));
+    s->fd_in = fd_in;
+    s->fd_out = fd_out;
+    chr->opaque = s;
+    chr->chr_write = fd_chr_write;
+    chr->chr_update_read_handler = fd_chr_update_read_handler;
+    chr->chr_close = fd_chr_close;
+
+    qemu_chr_reset(chr);
+
+    return chr;
+}
+
+static CharDriverState *qemu_chr_open_file_out(const char *file_out)
+{
+    int fd_out;
+
+    TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
+    if (fd_out < 0)
+        return NULL;
+    return qemu_chr_open_fd(-1, fd_out);
+}
+
+static CharDriverState *qemu_chr_open_pipe(const char *filename)
+{
+    int fd_in, fd_out;
+    char filename_in[256], filename_out[256];
+
+    snprintf(filename_in, 256, "%s.in", filename);
+    snprintf(filename_out, 256, "%s.out", filename);
+    TFR(fd_in = open(filename_in, O_RDWR | O_BINARY));
+    TFR(fd_out = open(filename_out, O_RDWR | O_BINARY));
+    if (fd_in < 0 || fd_out < 0) {
+	if (fd_in >= 0)
+	    close(fd_in);
+	if (fd_out >= 0)
+	    close(fd_out);
+        TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
+        if (fd_in < 0)
+            return NULL;
+    }
+    return qemu_chr_open_fd(fd_in, fd_out);
+}
+
+
+/* for STDIO, we handle the case where several clients use it
+   (nographic mode) */
+
+#define TERM_FIFO_MAX_SIZE 1
+
+static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
+static int term_fifo_size;
+
+static int stdio_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+
+    /* try to flush the queue if needed */
+    if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
+        qemu_chr_read(chr, term_fifo, 1);
+        term_fifo_size = 0;
+    }
+    /* see if we can absorb more chars */
+    if (term_fifo_size == 0)
+        return 1;
+    else
+        return 0;
+}
+
+static void stdio_read(void *opaque)
+{
+    int size;
+    uint8_t buf[1];
+    CharDriverState *chr = opaque;
+
+    size = read(0, buf, 1);
+    if (size == 0) {
+        /* stdin has been closed. Remove it from the active list.  */
+        qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
+        return;
+    }
+    if (size > 0) {
+        if (qemu_chr_can_read(chr) > 0) {
+            qemu_chr_read(chr, buf, 1);
+        } else if (term_fifo_size == 0) {
+            term_fifo[term_fifo_size++] = buf[0];
+        }
+    }
+}
+
+/* init terminal so that we can grab keys */
+static struct termios oldtty;
+static int old_fd0_flags;
+static int term_atexit_done;
+
+static void term_exit(void)
+{
+    tcsetattr (0, TCSANOW, &oldtty);
+    fcntl(0, F_SETFL, old_fd0_flags);
+}
+
+static void term_init(void)
+{
+    struct termios tty;
+
+    tcgetattr (0, &tty);
+    oldtty = tty;
+    old_fd0_flags = fcntl(0, F_GETFL);
+
+    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                          |INLCR|IGNCR|ICRNL|IXON);
+    tty.c_oflag |= OPOST;
+    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+    /* if graphical mode, we allow Ctrl-C handling */
+    if (display_type == DT_NOGRAPHIC)
+        tty.c_lflag &= ~ISIG;
+    tty.c_cflag &= ~(CSIZE|PARENB);
+    tty.c_cflag |= CS8;
+    tty.c_cc[VMIN] = 1;
+    tty.c_cc[VTIME] = 0;
+
+    tcsetattr (0, TCSANOW, &tty);
+
+    if (!term_atexit_done++)
+        atexit(term_exit);
+
+    fcntl(0, F_SETFL, O_NONBLOCK);
+}
+
+static void qemu_chr_close_stdio(struct CharDriverState *chr)
+{
+    term_exit();
+    stdio_nb_clients--;
+    qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
+    fd_chr_close(chr);
+}
+
+static CharDriverState *qemu_chr_open_stdio(void)
+{
+    CharDriverState *chr;
+
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
+        return NULL;
+    chr = qemu_chr_open_fd(0, 1);
+    chr->chr_close = qemu_chr_close_stdio;
+    qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
+    stdio_nb_clients++;
+    term_init();
+
+    return chr;
+}
+
+#ifdef __sun__
+/* Once Solaris has openpty(), this is going to be removed. */
+static int openpty(int *amaster, int *aslave, char *name,
+                   struct termios *termp, struct winsize *winp)
+{
+        const char *slave;
+        int mfd = -1, sfd = -1;
+
+        *amaster = *aslave = -1;
+
+        mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
+        if (mfd < 0)
+                goto err;
+
+        if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
+                goto err;
+
+        if ((slave = ptsname(mfd)) == NULL)
+                goto err;
+
+        if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
+                goto err;
+
+        if (ioctl(sfd, I_PUSH, "ptem") == -1 ||
+            (termp != NULL && tcgetattr(sfd, termp) < 0))
+                goto err;
+
+        if (amaster)
+                *amaster = mfd;
+        if (aslave)
+                *aslave = sfd;
+        if (winp)
+                ioctl(sfd, TIOCSWINSZ, winp);
+
+        return 0;
+
+err:
+        if (sfd != -1)
+                close(sfd);
+        close(mfd);
+        return -1;
+}
+
+static void cfmakeraw (struct termios *termios_p)
+{
+        termios_p->c_iflag &=
+                ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+        termios_p->c_oflag &= ~OPOST;
+        termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+        termios_p->c_cflag &= ~(CSIZE|PARENB);
+        termios_p->c_cflag |= CS8;
+
+        termios_p->c_cc[VMIN] = 0;
+        termios_p->c_cc[VTIME] = 0;
+}
+#endif
+
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+
+typedef struct {
+    int fd;
+    int connected;
+    int polling;
+    int read_bytes;
+    QEMUTimer *timer;
+} PtyCharDriver;
+
+static void pty_chr_update_read_handler(CharDriverState *chr);
+static void pty_chr_state(CharDriverState *chr, int connected);
+
+static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    if (!s->connected) {
+        /* guest sends data, check for (re-)connect */
+        pty_chr_update_read_handler(chr);
+        return 0;
+    }
+    return send_all(s->fd, buf, len);
+}
+
+static int pty_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+
+    s->read_bytes = qemu_chr_can_read(chr);
+    return s->read_bytes;
+}
+
+static void pty_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+    int size, len;
+    uint8_t buf[1024];
+
+    len = sizeof(buf);
+    if (len > s->read_bytes)
+        len = s->read_bytes;
+    if (len == 0)
+        return;
+    size = read(s->fd, buf, len);
+    if ((size == -1 && errno == EIO) ||
+        (size == 0)) {
+        pty_chr_state(chr, 0);
+        return;
+    }
+    if (size > 0) {
+        pty_chr_state(chr, 1);
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void pty_chr_update_read_handler(CharDriverState *chr)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
+                         pty_chr_read, NULL, chr);
+    s->polling = 1;
+    /*
+     * Short timeout here: just need wait long enougth that qemu makes
+     * it through the poll loop once.  When reconnected we want a
+     * short timeout so we notice it almost instantly.  Otherwise
+     * read() gives us -EIO instantly, making pty_chr_state() reset the
+     * timeout to the normal (much longer) poll interval before the
+     * timer triggers.
+     */
+    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
+}
+
+static void pty_chr_state(CharDriverState *chr, int connected)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    if (!connected) {
+        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+        s->connected = 0;
+        s->polling = 0;
+        /* (re-)connect poll interval for idle guests: once per second.
+         * We check more frequently in case the guests sends data to
+         * the virtual device linked to our pty. */
+        qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
+    } else {
+        if (!s->connected)
+            qemu_chr_reset(chr);
+        s->connected = 1;
+    }
+}
+
+static void pty_chr_timer(void *opaque)
+{
+    struct CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+
+    if (s->connected)
+        return;
+    if (s->polling) {
+        /* If we arrive here without polling being cleared due
+         * read returning -EIO, then we are (re-)connected */
+        pty_chr_state(chr, 1);
+        return;
+    }
+
+    /* Next poll ... */
+    pty_chr_update_read_handler(chr);
+}
+
+static void pty_chr_close(struct CharDriverState *chr)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    close(s->fd);
+    qemu_del_timer(s->timer);
+    qemu_free_timer(s->timer);
+    qemu_free(s);
+}
+
+static CharDriverState *qemu_chr_open_pty(void)
+{
+    CharDriverState *chr;
+    PtyCharDriver *s;
+    struct termios tty;
+    int slave_fd, len;
+#if defined(__OpenBSD__) || defined(__DragonFly__)
+    char pty_name[PATH_MAX];
+#define q_ptsname(x) pty_name
+#else
+    char *pty_name = NULL;
+#define q_ptsname(x) ptsname(x)
+#endif
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(PtyCharDriver));
+
+    if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
+        return NULL;
+    }
+
+    /* Set raw attributes on the pty. */
+    tcgetattr(slave_fd, &tty);
+    cfmakeraw(&tty);
+    tcsetattr(slave_fd, TCSAFLUSH, &tty);
+    close(slave_fd);
+
+    len = strlen(q_ptsname(s->fd)) + 5;
+    chr->filename = qemu_malloc(len);
+    snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
+    fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
+
+    chr->opaque = s;
+    chr->chr_write = pty_chr_write;
+    chr->chr_update_read_handler = pty_chr_update_read_handler;
+    chr->chr_close = pty_chr_close;
+
+    s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
+
+    return chr;
+}
+
+static void tty_serial_init(int fd, int speed,
+                            int parity, int data_bits, int stop_bits)
+{
+    struct termios tty;
+    speed_t spd;
+
+#if 0
+    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
+           speed, parity, data_bits, stop_bits);
+#endif
+    tcgetattr (fd, &tty);
+
+#define MARGIN 1.1
+    if (speed <= 50 * MARGIN)
+        spd = B50;
+    else if (speed <= 75 * MARGIN)
+        spd = B75;
+    else if (speed <= 300 * MARGIN)
+        spd = B300;
+    else if (speed <= 600 * MARGIN)
+        spd = B600;
+    else if (speed <= 1200 * MARGIN)
+        spd = B1200;
+    else if (speed <= 2400 * MARGIN)
+        spd = B2400;
+    else if (speed <= 4800 * MARGIN)
+        spd = B4800;
+    else if (speed <= 9600 * MARGIN)
+        spd = B9600;
+    else if (speed <= 19200 * MARGIN)
+        spd = B19200;
+    else if (speed <= 38400 * MARGIN)
+        spd = B38400;
+    else if (speed <= 57600 * MARGIN)
+        spd = B57600;
+    else if (speed <= 115200 * MARGIN)
+        spd = B115200;
+    else
+        spd = B115200;
+
+    cfsetispeed(&tty, spd);
+    cfsetospeed(&tty, spd);
+
+    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                          |INLCR|IGNCR|ICRNL|IXON);
+    tty.c_oflag |= OPOST;
+    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
+    tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
+    switch(data_bits) {
+    default:
+    case 8:
+        tty.c_cflag |= CS8;
+        break;
+    case 7:
+        tty.c_cflag |= CS7;
+        break;
+    case 6:
+        tty.c_cflag |= CS6;
+        break;
+    case 5:
+        tty.c_cflag |= CS5;
+        break;
+    }
+    switch(parity) {
+    default:
+    case 'N':
+        break;
+    case 'E':
+        tty.c_cflag |= PARENB;
+        break;
+    case 'O':
+        tty.c_cflag |= PARENB | PARODD;
+        break;
+    }
+    if (stop_bits == 2)
+        tty.c_cflag |= CSTOPB;
+
+    tcsetattr (fd, TCSANOW, &tty);
+}
+
+static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    FDCharDriver *s = chr->opaque;
+
+    switch(cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        {
+            QEMUSerialSetParams *ssp = arg;
+            tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
+                            ssp->data_bits, ssp->stop_bits);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_BREAK:
+        {
+            int enable = *(int *)arg;
+            if (enable)
+                tcsendbreak(s->fd_in, 1);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_GET_TIOCM:
+        {
+            int sarg = 0;
+            int *targ = (int *)arg;
+            ioctl(s->fd_in, TIOCMGET, &sarg);
+            *targ = 0;
+            if (sarg & TIOCM_CTS)
+                *targ |= CHR_TIOCM_CTS;
+            if (sarg & TIOCM_CAR)
+                *targ |= CHR_TIOCM_CAR;
+            if (sarg & TIOCM_DSR)
+                *targ |= CHR_TIOCM_DSR;
+            if (sarg & TIOCM_RI)
+                *targ |= CHR_TIOCM_RI;
+            if (sarg & TIOCM_DTR)
+                *targ |= CHR_TIOCM_DTR;
+            if (sarg & TIOCM_RTS)
+                *targ |= CHR_TIOCM_RTS;
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_TIOCM:
+        {
+            int sarg = *(int *)arg;
+            int targ = 0;
+            ioctl(s->fd_in, TIOCMGET, &targ);
+            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
+                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
+            if (sarg & CHR_TIOCM_CTS)
+                targ |= TIOCM_CTS;
+            if (sarg & CHR_TIOCM_CAR)
+                targ |= TIOCM_CAR;
+            if (sarg & CHR_TIOCM_DSR)
+                targ |= TIOCM_DSR;
+            if (sarg & CHR_TIOCM_RI)
+                targ |= TIOCM_RI;
+            if (sarg & CHR_TIOCM_DTR)
+                targ |= TIOCM_DTR;
+            if (sarg & CHR_TIOCM_RTS)
+                targ |= TIOCM_RTS;
+            ioctl(s->fd_in, TIOCMSET, &targ);
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static CharDriverState *qemu_chr_open_tty(const char *filename)
+{
+    CharDriverState *chr;
+    int fd;
+
+    TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
+    tty_serial_init(fd, 115200, 'N', 8, 1);
+    chr = qemu_chr_open_fd(fd, fd);
+    if (!chr) {
+        close(fd);
+        return NULL;
+    }
+    chr->chr_ioctl = tty_serial_ioctl;
+    qemu_chr_reset(chr);
+    return chr;
+}
+#else  /* ! __linux__ && ! __sun__ */
+static CharDriverState *qemu_chr_open_pty(void)
+{
+    return NULL;
+}
+#endif /* __linux__ || __sun__ */
+
+#if defined(__linux__)
+typedef struct {
+    int fd;
+    int mode;
+} ParallelCharDriver;
+
+static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
+{
+    if (s->mode != mode) {
+	int m = mode;
+        if (ioctl(s->fd, PPSETMODE, &m) < 0)
+            return 0;
+	s->mode = mode;
+    }
+    return 1;
+}
+
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    ParallelCharDriver *drv = chr->opaque;
+    int fd = drv->fd;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPRDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPRCONTROL, &b) < 0)
+            return -ENOTSUP;
+	/* Linux gives only the lowest bits, and no way to know data
+	   direction! For better compatibility set the fixed upper
+	   bits. */
+        *(uint8_t *)arg = b | 0xc0;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWCONTROL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPRSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_DATA_DIR:
+        if (ioctl(fd, PPDATADIR, (int *)arg) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_EPP_READ_ADDR:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = read(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_READ:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = read(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = write(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = write(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void pp_close(CharDriverState *chr)
+{
+    ParallelCharDriver *drv = chr->opaque;
+    int fd = drv->fd;
+
+    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
+    ioctl(fd, PPRELEASE);
+    close(fd);
+    qemu_free(drv);
+}
+
+static CharDriverState *qemu_chr_open_pp(const char *filename)
+{
+    CharDriverState *chr;
+    ParallelCharDriver *drv;
+    int fd;
+
+    TFR(fd = open(filename, O_RDWR));
+    if (fd < 0)
+        return NULL;
+
+    if (ioctl(fd, PPCLAIM) < 0) {
+        close(fd);
+        return NULL;
+    }
+
+    drv = qemu_mallocz(sizeof(ParallelCharDriver));
+    drv->fd = fd;
+    drv->mode = IEEE1284_MODE_COMPAT;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->chr_write = null_chr_write;
+    chr->chr_ioctl = pp_ioctl;
+    chr->chr_close = pp_close;
+    chr->opaque = drv;
+
+    qemu_chr_reset(chr);
+
+    return chr;
+}
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    int fd = (int)chr->opaque;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPIGDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPISDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPIGCTRL, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPISCTRL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPIGSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static CharDriverState *qemu_chr_open_pp(const char *filename)
+{
+    CharDriverState *chr;
+    int fd;
+
+    fd = open(filename, O_RDWR);
+    if (fd < 0)
+        return NULL;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    chr->opaque = (void *)fd;
+    chr->chr_write = null_chr_write;
+    chr->chr_ioctl = pp_ioctl;
+    return chr;
+}
+#endif
+
+#else /* _WIN32 */
+
+typedef struct {
+    int max_size;
+    HANDLE hcom, hrecv, hsend;
+    OVERLAPPED orecv, osend;
+    BOOL fpipe;
+    DWORD len;
+} WinCharState;
+
+#define NSENDBUF 2048
+#define NRECVBUF 2048
+#define MAXCONNECT 1
+#define NTIMEOUT 5000
+
+static int win_chr_poll(void *opaque);
+static int win_chr_pipe_poll(void *opaque);
+
+static void win_chr_close(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    if (s->hsend) {
+        CloseHandle(s->hsend);
+        s->hsend = NULL;
+    }
+    if (s->hrecv) {
+        CloseHandle(s->hrecv);
+        s->hrecv = NULL;
+    }
+    if (s->hcom) {
+        CloseHandle(s->hcom);
+        s->hcom = NULL;
+    }
+    if (s->fpipe)
+        qemu_del_polling_cb(win_chr_pipe_poll, chr);
+    else
+        qemu_del_polling_cb(win_chr_poll, chr);
+}
+
+static int win_chr_init(CharDriverState *chr, const char *filename)
+{
+    WinCharState *s = chr->opaque;
+    COMMCONFIG comcfg;
+    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
+    COMSTAT comstat;
+    DWORD size;
+    DWORD err;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+
+    s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
+                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
+        fprintf(stderr, "Failed SetupComm\n");
+        goto fail;
+    }
+
+    ZeroMemory(&comcfg, sizeof(COMMCONFIG));
+    size = sizeof(COMMCONFIG);
+    GetDefaultCommConfig(filename, &comcfg, &size);
+    comcfg.dcb.DCBlength = sizeof(DCB);
+    CommConfigDialog(filename, NULL, &comcfg);
+
+    if (!SetCommState(s->hcom, &comcfg.dcb)) {
+        fprintf(stderr, "Failed SetCommState\n");
+        goto fail;
+    }
+
+    if (!SetCommMask(s->hcom, EV_ERR)) {
+        fprintf(stderr, "Failed SetCommMask\n");
+        goto fail;
+    }
+
+    cto.ReadIntervalTimeout = MAXDWORD;
+    if (!SetCommTimeouts(s->hcom, &cto)) {
+        fprintf(stderr, "Failed SetCommTimeouts\n");
+        goto fail;
+    }
+
+    if (!ClearCommError(s->hcom, &err, &comstat)) {
+        fprintf(stderr, "Failed ClearCommError\n");
+        goto fail;
+    }
+    qemu_add_polling_cb(win_chr_poll, chr);
+    return 0;
+
+ fail:
+    win_chr_close(chr);
+    return -1;
+}
+
+static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
+{
+    WinCharState *s = chr->opaque;
+    DWORD len, ret, size, err;
+
+    len = len1;
+    ZeroMemory(&s->osend, sizeof(s->osend));
+    s->osend.hEvent = s->hsend;
+    while (len > 0) {
+        if (s->hsend)
+            ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
+        else
+            ret = WriteFile(s->hcom, buf, len, &size, NULL);
+        if (!ret) {
+            err = GetLastError();
+            if (err == ERROR_IO_PENDING) {
+                ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
+                if (ret) {
+                    buf += size;
+                    len -= size;
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        } else {
+            buf += size;
+            len -= size;
+        }
+    }
+    return len1 - len;
+}
+
+static int win_chr_read_poll(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+static void win_chr_readfile(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+    int ret, err;
+    uint8_t buf[1024];
+    DWORD size;
+
+    ZeroMemory(&s->orecv, sizeof(s->orecv));
+    s->orecv.hEvent = s->hrecv;
+    ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
+    if (!ret) {
+        err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
+        }
+    }
+
+    if (size > 0) {
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void win_chr_read(CharDriverState *chr)
+{
+    WinCharState *s = chr->opaque;
+
+    if (s->len > s->max_size)
+        s->len = s->max_size;
+    if (s->len == 0)
+        return;
+
+    win_chr_readfile(chr);
+}
+
+static int win_chr_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    WinCharState *s = chr->opaque;
+    COMSTAT status;
+    DWORD comerr;
+
+    ClearCommError(s->hcom, &comerr, &status);
+    if (status.cbInQue > 0) {
+        s->len = status.cbInQue;
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
+        return 1;
+    }
+    return 0;
+}
+
+static CharDriverState *qemu_chr_open_win(const char *filename)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_close = win_chr_close;
+
+    if (win_chr_init(chr, filename) < 0) {
+        free(s);
+        free(chr);
+        return NULL;
+    }
+    qemu_chr_reset(chr);
+    return chr;
+}
+
+static int win_chr_pipe_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    WinCharState *s = chr->opaque;
+    DWORD size;
+
+    PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
+    if (size > 0) {
+        s->len = size;
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
+        return 1;
+    }
+    return 0;
+}
+
+static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
+{
+    WinCharState *s = chr->opaque;
+    OVERLAPPED ov;
+    int ret;
+    DWORD size;
+    char openname[256];
+
+    s->fpipe = TRUE;
+
+    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hsend) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (!s->hrecv) {
+        fprintf(stderr, "Failed CreateEvent\n");
+        goto fail;
+    }
+
+    snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
+    s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
+                              PIPE_WAIT,
+                              MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
+    if (s->hcom == INVALID_HANDLE_VALUE) {
+        fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());
+        s->hcom = NULL;
+        goto fail;
+    }
+
+    ZeroMemory(&ov, sizeof(ov));
+    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+    ret = ConnectNamedPipe(s->hcom, &ov);
+    if (ret) {
+        fprintf(stderr, "Failed ConnectNamedPipe\n");
+        goto fail;
+    }
+
+    ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
+    if (!ret) {
+        fprintf(stderr, "Failed GetOverlappedResult\n");
+        if (ov.hEvent) {
+            CloseHandle(ov.hEvent);
+            ov.hEvent = NULL;
+        }
+        goto fail;
+    }
+
+    if (ov.hEvent) {
+        CloseHandle(ov.hEvent);
+        ov.hEvent = NULL;
+    }
+    qemu_add_polling_cb(win_chr_pipe_poll, chr);
+    return 0;
+
+ fail:
+    win_chr_close(chr);
+    return -1;
+}
+
+
+static CharDriverState *qemu_chr_open_win_pipe(const char *filename)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    chr->chr_close = win_chr_close;
+
+    if (win_chr_pipe_init(chr, filename) < 0) {
+        free(s);
+        free(chr);
+        return NULL;
+    }
+    qemu_chr_reset(chr);
+    return chr;
+}
+
+static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
+{
+    CharDriverState *chr;
+    WinCharState *s;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(WinCharState));
+    s->hcom = fd_out;
+    chr->opaque = s;
+    chr->chr_write = win_chr_write;
+    qemu_chr_reset(chr);
+    return chr;
+}
+
+static CharDriverState *qemu_chr_open_win_con(const char *filename)
+{
+    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
+}
+
+static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
+{
+    HANDLE fd_out;
+
+    fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (fd_out == INVALID_HANDLE_VALUE)
+        return NULL;
+
+    return qemu_chr_open_win_file(fd_out);
+}
+#endif /* !_WIN32 */
+
+/***********************************************************/
+/* UDP Net console */
+
+typedef struct {
+    int fd;
+    struct sockaddr_in daddr;
+    uint8_t buf[1024];
+    int bufcnt;
+    int bufptr;
+    int max_size;
+} NetCharDriver;
+
+static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    NetCharDriver *s = chr->opaque;
+
+    return sendto(s->fd, (const void *)buf, len, 0,
+                  (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));
+}
+
+static int udp_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    NetCharDriver *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
+
+    /* If there were any stray characters in the queue process them
+     * first
+     */
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        s->bufptr++;
+        s->max_size = qemu_chr_can_read(chr);
+    }
+    return s->max_size;
+}
+
+static void udp_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    NetCharDriver *s = chr->opaque;
+
+    if (s->max_size == 0)
+        return;
+    s->bufcnt = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
+    s->bufptr = s->bufcnt;
+    if (s->bufcnt <= 0)
+        return;
+
+    s->bufptr = 0;
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
+        s->bufptr++;
+        s->max_size = qemu_chr_can_read(chr);
+    }
+}
+
+static void udp_chr_update_read_handler(CharDriverState *chr)
+{
+    NetCharDriver *s = chr->opaque;
+
+    if (s->fd >= 0) {
+        qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
+                             udp_chr_read, NULL, chr);
+    }
+}
+
+static void udp_chr_close(CharDriverState *chr)
+{
+    NetCharDriver *s = chr->opaque;
+    if (s->fd >= 0) {
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+    }
+    qemu_free(s);
+}
+
+static CharDriverState *qemu_chr_open_udp(const char *def)
+{
+    CharDriverState *chr = NULL;
+    NetCharDriver *s = NULL;
+    int fd = -1;
+    struct sockaddr_in saddr;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(NetCharDriver));
+
+    fd = socket(PF_INET, SOCK_DGRAM, 0);
+    if (fd < 0) {
+        perror("socket(PF_INET, SOCK_DGRAM)");
+        goto return_err;
+    }
+
+    if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
+        printf("Could not parse: %s\n", def);
+        goto return_err;
+    }
+
+    if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+    {
+        perror("bind");
+        goto return_err;
+    }
+
+    s->fd = fd;
+    s->bufcnt = 0;
+    s->bufptr = 0;
+    chr->opaque = s;
+    chr->chr_write = udp_chr_write;
+    chr->chr_update_read_handler = udp_chr_update_read_handler;
+    chr->chr_close = udp_chr_close;
+    return chr;
+
+return_err:
+    if (chr)
+        free(chr);
+    if (s)
+        free(s);
+    if (fd >= 0)
+        closesocket(fd);
+    return NULL;
+}
+
+/***********************************************************/
+/* TCP Net console */
+
+typedef struct {
+    int fd, listen_fd;
+    int connected;
+    int max_size;
+    int do_telnetopt;
+    int do_nodelay;
+    int is_unix;
+} TCPCharDriver;
+
+static void tcp_chr_accept(void *opaque);
+
+static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->connected) {
+        return send_all(s->fd, buf, len);
+    } else {
+        /* XXX: indicate an error ? */
+        return len;
+    }
+}
+
+static int tcp_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    if (!s->connected)
+        return 0;
+    s->max_size = qemu_chr_can_read(chr);
+    return s->max_size;
+}
+
+#define IAC 255
+#define IAC_BREAK 243
+static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
+                                      TCPCharDriver *s,
+                                      uint8_t *buf, int *size)
+{
+    /* Handle any telnet client's basic IAC options to satisfy char by
+     * char mode with no echo.  All IAC options will be removed from
+     * the buf and the do_telnetopt variable will be used to track the
+     * state of the width of the IAC information.
+     *
+     * IAC commands come in sets of 3 bytes with the exception of the
+     * "IAC BREAK" command and the double IAC.
+     */
+
+    int i;
+    int j = 0;
+
+    for (i = 0; i < *size; i++) {
+        if (s->do_telnetopt > 1) {
+            if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+                /* Double IAC means send an IAC */
+                if (j != i)
+                    buf[j] = buf[i];
+                j++;
+                s->do_telnetopt = 1;
+            } else {
+                if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
+                    /* Handle IAC break commands by sending a serial break */
+                    qemu_chr_event(chr, CHR_EVENT_BREAK);
+                    s->do_telnetopt++;
+                }
+                s->do_telnetopt++;
+            }
+            if (s->do_telnetopt >= 4) {
+                s->do_telnetopt = 1;
+            }
+        } else {
+            if ((unsigned char)buf[i] == IAC) {
+                s->do_telnetopt = 2;
+            } else {
+                if (j != i)
+                    buf[j] = buf[i];
+                j++;
+            }
+        }
+    }
+    *size = j;
+}
+
+static void tcp_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    uint8_t buf[1024];
+    int len, size;
+
+    if (!s->connected || s->max_size <= 0)
+        return;
+    len = sizeof(buf);
+    if (len > s->max_size)
+        len = s->max_size;
+    size = recv(s->fd, (void *)buf, len, 0);
+    if (size == 0) {
+        /* connection closed */
+        s->connected = 0;
+        if (s->listen_fd >= 0) {
+            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        }
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+        s->fd = -1;
+    } else if (size > 0) {
+        if (s->do_telnetopt)
+            tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+        if (size > 0)
+            qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void tcp_chr_connect(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+
+    s->connected = 1;
+    qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
+                         tcp_chr_read, NULL, chr);
+    qemu_chr_reset(chr);
+}
+
+#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
+static void tcp_chr_telnet_init(int fd)
+{
+    char buf[3];
+    /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
+    IACSET(buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
+    send(fd, (char *)buf, 3, 0);
+    IACSET(buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
+    send(fd, (char *)buf, 3, 0);
+}
+
+static void socket_set_nodelay(int fd)
+{
+    int val = 1;
+    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+}
+
+static void tcp_chr_accept(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    TCPCharDriver *s = chr->opaque;
+    struct sockaddr_in saddr;
+#ifndef _WIN32
+    struct sockaddr_un uaddr;
+#endif
+    struct sockaddr *addr;
+    socklen_t len;
+    int fd;
+
+    for(;;) {
+#ifndef _WIN32
+	if (s->is_unix) {
+	    len = sizeof(uaddr);
+	    addr = (struct sockaddr *)&uaddr;
+	} else
+#endif
+	{
+	    len = sizeof(saddr);
+	    addr = (struct sockaddr *)&saddr;
+	}
+        fd = accept(s->listen_fd, addr, &len);
+        if (fd < 0 && errno != EINTR) {
+            return;
+        } else if (fd >= 0) {
+            if (s->do_telnetopt)
+                tcp_chr_telnet_init(fd);
+            break;
+        }
+    }
+    socket_set_nonblock(fd);
+    if (s->do_nodelay)
+        socket_set_nodelay(fd);
+    s->fd = fd;
+    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+    tcp_chr_connect(chr);
+}
+
+static void tcp_chr_close(CharDriverState *chr)
+{
+    TCPCharDriver *s = chr->opaque;
+    if (s->fd >= 0) {
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        closesocket(s->fd);
+    }
+    if (s->listen_fd >= 0) {
+        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
+        closesocket(s->listen_fd);
+    }
+    qemu_free(s);
+}
+
+static CharDriverState *qemu_chr_open_tcp(const char *host_str,
+                                          int is_telnet,
+					  int is_unix)
+{
+    CharDriverState *chr = NULL;
+    TCPCharDriver *s = NULL;
+    int fd = -1, offset = 0;
+    int is_listen = 0;
+    int is_waitconnect = 1;
+    int do_nodelay = 0;
+    const char *ptr;
+
+    ptr = host_str;
+    while((ptr = strchr(ptr,','))) {
+        ptr++;
+        if (!strncmp(ptr,"server",6)) {
+            is_listen = 1;
+        } else if (!strncmp(ptr,"nowait",6)) {
+            is_waitconnect = 0;
+        } else if (!strncmp(ptr,"nodelay",6)) {
+            do_nodelay = 1;
+        } else if (!strncmp(ptr,"to=",3)) {
+            /* nothing, inet_listen() parses this one */;
+        } else if (!strncmp(ptr,"ipv4",4)) {
+            /* nothing, inet_connect() and inet_listen() parse this one */;
+        } else if (!strncmp(ptr,"ipv6",4)) {
+            /* nothing, inet_connect() and inet_listen() parse this one */;
+        } else {
+            printf("Unknown option: %s\n", ptr);
+            goto fail;
+        }
+    }
+    if (!is_listen)
+        is_waitconnect = 0;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    s = qemu_mallocz(sizeof(TCPCharDriver));
+
+    if (is_listen) {
+        chr->filename = qemu_malloc(256);
+        if (is_unix) {
+            pstrcpy(chr->filename, 256, "unix:");
+        } else if (is_telnet) {
+            pstrcpy(chr->filename, 256, "telnet:");
+        } else {
+            pstrcpy(chr->filename, 256, "tcp:");
+        }
+        offset = strlen(chr->filename);
+    }
+    if (is_unix) {
+        if (is_listen) {
+            fd = unix_listen(host_str, chr->filename + offset, 256 - offset);
+        } else {
+            fd = unix_connect(host_str);
+        }
+    } else {
+        if (is_listen) {
+            fd = inet_listen(host_str, chr->filename + offset, 256 - offset,
+                             SOCK_STREAM, 0);
+        } else {
+            fd = inet_connect(host_str, SOCK_STREAM);
+        }
+    }
+    if (fd < 0)
+        goto fail;
+
+    if (!is_waitconnect)
+        socket_set_nonblock(fd);
+
+    s->connected = 0;
+    s->fd = -1;
+    s->listen_fd = -1;
+    s->is_unix = is_unix;
+    s->do_nodelay = do_nodelay && !is_unix;
+
+    chr->opaque = s;
+    chr->chr_write = tcp_chr_write;
+    chr->chr_close = tcp_chr_close;
+
+    if (is_listen) {
+        s->listen_fd = fd;
+        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+        if (is_telnet)
+            s->do_telnetopt = 1;
+    } else {
+        s->connected = 1;
+        s->fd = fd;
+        socket_set_nodelay(fd);
+        tcp_chr_connect(chr);
+    }
+
+    if (is_listen && is_waitconnect) {
+        printf("QEMU waiting for connection on: %s\n",
+               chr->filename ? chr->filename : host_str);
+        tcp_chr_accept(chr);
+        socket_set_nonblock(s->listen_fd);
+    }
+
+    return chr;
+ fail:
+    if (fd >= 0)
+        closesocket(fd);
+    qemu_free(s);
+    qemu_free(chr);
+    return NULL;
+}
+
+CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
+{
+    const char *p;
+    CharDriverState *chr;
+
+    if (!strcmp(filename, "vc")) {
+        chr = text_console_init(0);
+    } else
+    if (strstart(filename, "vc:", &p)) {
+        chr = text_console_init(p);
+    } else
+    if (!strcmp(filename, "null")) {
+        chr = qemu_chr_open_null();
+    } else
+    if (strstart(filename, "tcp:", &p)) {
+        chr = qemu_chr_open_tcp(p, 0, 0);
+    } else
+    if (strstart(filename, "telnet:", &p)) {
+        chr = qemu_chr_open_tcp(p, 1, 0);
+    } else
+    if (strstart(filename, "udp:", &p)) {
+        chr = qemu_chr_open_udp(p);
+    } else
+    if (strstart(filename, "mon:", &p)) {
+        chr = qemu_chr_open(label, p, NULL);
+        if (chr) {
+            chr = qemu_chr_open_mux(chr);
+            monitor_init(chr, MONITOR_USE_READLINE);
+        } else {
+            printf("Unable to open driver: %s\n", p);
+        }
+    } else if (!strcmp(filename, "msmouse")) {
+        chr = qemu_chr_open_msmouse();
+    } else
+#ifndef _WIN32
+    if (strstart(filename, "unix:", &p)) {
+	chr = qemu_chr_open_tcp(p, 0, 1);
+    } else if (strstart(filename, "file:", &p)) {
+        chr = qemu_chr_open_file_out(p);
+    } else if (strstart(filename, "pipe:", &p)) {
+        chr = qemu_chr_open_pipe(p);
+    } else if (!strcmp(filename, "pty")) {
+        chr = qemu_chr_open_pty();
+    } else if (!strcmp(filename, "stdio")) {
+        chr = qemu_chr_open_stdio();
+    } else
+#if defined(__linux__)
+    if (strstart(filename, "/dev/parport", NULL)) {
+        chr = qemu_chr_open_pp(filename);
+    } else
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+    if (strstart(filename, "/dev/ppi", NULL)) {
+        chr = qemu_chr_open_pp(filename);
+    } else
+#endif
+#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+    if (strstart(filename, "/dev/", NULL)) {
+        chr = qemu_chr_open_tty(filename);
+    } else
+#endif
+#else /* !_WIN32 */
+    if (strstart(filename, "COM", NULL)) {
+        chr = qemu_chr_open_win(filename);
+    } else
+    if (strstart(filename, "pipe:", &p)) {
+        chr = qemu_chr_open_win_pipe(p);
+    } else
+    if (strstart(filename, "con:", NULL)) {
+        chr = qemu_chr_open_win_con(filename);
+    } else
+    if (strstart(filename, "file:", &p)) {
+        chr = qemu_chr_open_win_file_out(p);
+    } else
+#endif
+#ifdef CONFIG_BRLAPI
+    if (!strcmp(filename, "braille")) {
+        chr = chr_baum_init();
+    } else
+#endif
+    {
+        chr = NULL;
+    }
+
+    if (chr) {
+        if (!chr->filename)
+            chr->filename = qemu_strdup(filename);
+        chr->init = init;
+        chr->label = qemu_strdup(label);
+        TAILQ_INSERT_TAIL(&chardevs, chr, next);
+    }
+    return chr;
+}
+
+void qemu_chr_close(CharDriverState *chr)
+{
+    TAILQ_REMOVE(&chardevs, chr, next);
+    if (chr->chr_close)
+        chr->chr_close(chr);
+    qemu_free(chr->filename);
+    qemu_free(chr->label);
+    qemu_free(chr);
+}
+
+void qemu_chr_info(Monitor *mon)
+{
+    CharDriverState *chr;
+
+    TAILQ_FOREACH(chr, &chardevs, next) {
+        monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename);
+    }
+}
diff --git a/qemu-char.h b/qemu-char.h
index 439e2c8..e1aa8db 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -2,12 +2,15 @@
 #define QEMU_CHAR_H
 
 #include "qemu-common.h"
+#include "sys-queue.h"
 
 /* character device */
 
-#define CHR_EVENT_BREAK 0 /* serial break char */
-#define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */
-#define CHR_EVENT_RESET 2 /* new connection established */
+#define CHR_EVENT_BREAK   0 /* serial break char */
+#define CHR_EVENT_FOCUS   1 /* focus to this terminal (modal input needed) */
+#define CHR_EVENT_RESET   2 /* new connection established */
+#define CHR_EVENT_MUX_IN  3 /* mux-focus was set to this terminal */
+#define CHR_EVENT_MUX_OUT 4 /* mux-focus will move on */
 
 
 #define CHR_IOCTL_SERIAL_SET_PARAMS   1
@@ -44,6 +47,7 @@
 typedef void IOEventHandler(void *opaque, int event);
 
 struct CharDriverState {
+    void (*init)(struct CharDriverState *s);
     int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
     void (*chr_update_read_handler)(struct CharDriverState *s);
     int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
@@ -57,9 +61,12 @@
     void *opaque;
     int focus;
     QEMUBH *bh;
+    char *label;
+    char *filename;
+    TAILQ_ENTRY(CharDriverState) next;
 };
 
-CharDriverState *qemu_chr_open(const char *filename);
+CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s));
 void qemu_chr_close(CharDriverState *chr);
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
 int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len);
@@ -71,9 +78,13 @@
                            void *opaque);
 int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
 void qemu_chr_reset(CharDriverState *s);
+void qemu_chr_initial_reset(void);
 int qemu_chr_can_read(CharDriverState *s);
 void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
 void qemu_chr_accept_input(CharDriverState *s);
+void qemu_chr_info(Monitor *mon);
+
+extern int term_escape_char;
 
 /* async I/O support */
 
diff --git a/qemu-common.h b/qemu-common.h
index 391717c..9983303 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -2,12 +2,19 @@
 #ifndef QEMU_COMMON_H
 #define QEMU_COMMON_H
 
+#define QEMU_NORETURN __attribute__ ((__noreturn__))
+
+/* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that
+   cannot include the following headers without conflicts. This condition has
+   to be removed once dyngen is gone. */
+#ifndef __DYNGEN_EXEC_H__
+
 /* we put basic includes here to avoid repeating them in device drivers */
 #include <stdlib.h>
 #include <stdio.h>
-#include <stddef.h>
 #include <stdarg.h>
 #include <string.h>
+#include <strings.h>
 #include <inttypes.h>
 #include <limits.h>
 #include <time.h>
@@ -16,6 +23,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <assert.h>
+#include "config-host.h"
 
 #ifndef O_LARGEFILE
 #define O_LARGEFILE 0
@@ -28,6 +37,16 @@
 #define ENOMEDIUM ENODEV
 #endif
 
+#ifndef HAVE_IOVEC
+#define HAVE_IOVEC
+struct iovec {
+    void *iov_base;
+    size_t iov_len;
+};
+#else
+#include <sys/uio.h>
+#endif
+
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
@@ -53,7 +72,6 @@
 /* FIXME: Remove NEED_CPU_H.  */
 #ifndef NEED_CPU_H
 
-#include "config-host.h"
 #include <setjmp.h>
 #include "osdep.h"
 #include "bswap.h"
@@ -71,6 +89,13 @@
 
 QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
 void qemu_bh_schedule(QEMUBH *bh);
+/* Bottom halfs that are scheduled from a bottom half handler are instantly
+ * invoked.  This can create an infinite loop if a bottom half handler
+ * schedules itself.  qemu_bh_schedule_idle() avoids this infinite loop by
+ * ensuring that the bottom half isn't executed until the next main loop
+ * iteration.
+ */
+void qemu_bh_schedule_idle(QEMUBH *bh);
 void qemu_bh_cancel(QEMUBH *bh);
 void qemu_bh_delete(QEMUBH *bh);
 int qemu_bh_poll(void);
@@ -86,21 +111,38 @@
 int strstart(const char *str, const char *val, const char **ptr);
 int stristart(const char *str, const char *val, const char **ptr);
 time_t mktimegm(struct tm *tm);
+int qemu_fls(int i);
+
+#define qemu_isalnum(c)		isalnum((unsigned char)(c))
+#define qemu_isalpha(c)		isalpha((unsigned char)(c))
+#define qemu_iscntrl(c)		iscntrl((unsigned char)(c))
+#define qemu_isdigit(c)		isdigit((unsigned char)(c))
+#define qemu_isgraph(c)		isgraph((unsigned char)(c))
+#define qemu_islower(c)		islower((unsigned char)(c))
+#define qemu_isprint(c)		isprint((unsigned char)(c))
+#define qemu_ispunct(c)		ispunct((unsigned char)(c))
+#define qemu_isspace(c)		isspace((unsigned char)(c))
+#define qemu_isupper(c)		isupper((unsigned char)(c))
+#define qemu_isxdigit(c)	isxdigit((unsigned char)(c))
+#define qemu_tolower(c)		tolower((unsigned char)(c))
+#define qemu_toupper(c)		toupper((unsigned char)(c))
+#define qemu_isascii(c)		isascii((unsigned char)(c))
+#define qemu_toascii(c)		toascii((unsigned char)(c))
 
 void *qemu_malloc(size_t size);
 void *qemu_realloc(void *ptr, size_t size);
 void *qemu_mallocz(size_t size);
 void qemu_free(void *ptr);
 char *qemu_strdup(const char *str);
+char *qemu_strndup(const char *str, size_t size);
 
 void *get_mmap_addr(unsigned long size);
 
 
 /* Error handling.  */
 
-void hw_error(const char *fmt, ...)
-    __attribute__ ((__format__ (__printf__, 1, 2)))
-    __attribute__ ((__noreturn__));
+void QEMU_NORETURN hw_error(const char *fmt, ...)
+    __attribute__ ((__format__ (__printf__, 1, 2)));
 
 /* IO callbacks.  */
 typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
@@ -117,9 +159,14 @@
 /* A load of opaque types so that device init declarations don't have to
    pull in all the real definitions.  */
 typedef struct NICInfo NICInfo;
+typedef struct HCIInfo HCIInfo;
 typedef struct AudioState AudioState;
 typedef struct BlockDriverState BlockDriverState;
 typedef struct DisplayState DisplayState;
+typedef struct DisplayChangeListener DisplayChangeListener;
+typedef struct DisplaySurface DisplaySurface;
+typedef struct DisplayAllocator DisplayAllocator;
+typedef struct PixelFormat PixelFormat;
 typedef struct TextConsole TextConsole;
 typedef TextConsole QEMUConsole;
 typedef struct CharDriverState CharDriverState;
@@ -133,10 +180,53 @@
 typedef struct PCIDevice PCIDevice;
 typedef struct SerialState SerialState;
 typedef struct IRQState *qemu_irq;
-struct pcmcia_card_s;
+typedef struct PCMCIACardState PCMCIACardState;
+typedef struct MouseTransformInfo MouseTransformInfo;
+typedef struct uWireSlave uWireSlave;
+typedef struct I2SCodec I2SCodec;
+typedef struct DeviceState DeviceState;
+typedef struct SSIBus SSIBus;
 
 /* CPU save/load.  */
 void cpu_save(QEMUFile *f, void *opaque);
 int cpu_load(QEMUFile *f, void *opaque, int version_id);
 
+/* Force QEMU to stop what it's doing and service IO */
+void qemu_service_io(void);
+
+/* Force QEMU to process pending events */
+void qemu_notify_event(void);
+
+/* Unblock cpu */
+void qemu_cpu_kick(void *env);
+int qemu_cpu_self(void *env);
+
+#ifdef CONFIG_USER_ONLY
+#define qemu_init_vcpu(env) do { } while (0)
+#else
+void qemu_init_vcpu(void *env);
+#endif
+
+typedef struct QEMUIOVector {
+    struct iovec *iov;
+    int niov;
+    int nalloc;
+    size_t size;
+} QEMUIOVector;
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
+void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
+void qemu_iovec_destroy(QEMUIOVector *qiov);
+void qemu_iovec_reset(QEMUIOVector *qiov);
+void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
+void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count);
+
+struct Monitor;
+typedef struct Monitor Monitor;
+
+#include "module.h"
+
+#endif /* dyngen-exec.h hack */
+
 #endif
diff --git a/qemu-io.c b/qemu-io.c
new file mode 100644
index 0000000..f0a17b9
--- /dev/null
+++ b/qemu-io.c
@@ -0,0 +1,1143 @@
+/*
+ * Command line utility to exercise the QEMU I/O path.
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <getopt.h>
+
+#include "qemu-common.h"
+#include "block_int.h"
+#include "cmd.h"
+
+#define VERSION	"0.0.1"
+
+#define CMD_NOFILE_OK	0x01
+
+char *progname;
+static BlockDriverState *bs;
+
+static int misalign;
+
+/*
+ * Memory allocation helpers.
+ *
+ * Make sure memory is aligned by default, or purposefully misaligned if
+ * that is specified on the command line.
+ */
+
+#define MISALIGN_OFFSET		16
+static void *qemu_io_alloc(size_t len, int pattern)
+{
+	void *buf;
+
+	if (misalign)
+		len += MISALIGN_OFFSET;
+	buf = qemu_memalign(512, len);
+	memset(buf, pattern, len);
+	if (misalign)
+		buf += MISALIGN_OFFSET;
+	return buf;
+}
+
+static void qemu_io_free(void *p)
+{
+	if (misalign)
+		p -= MISALIGN_OFFSET;
+	qemu_vfree(p);
+}
+
+static void
+dump_buffer(char *buffer, int64_t offset, int len)
+{
+	int i, j;
+	char *p;
+
+	for (i = 0, p = buffer; i < len; i += 16) {
+		char    *s = p;
+
+		printf("%08llx:  ", (unsigned long long)offset + i);
+		for (j = 0; j < 16 && i + j < len; j++, p++)
+			printf("%02x ", *p);
+		printf(" ");
+		for (j = 0; j < 16 && i + j < len; j++, s++) {
+			if (isalnum((int)*s))
+				printf("%c", *s);
+			else
+				printf(".");
+		}
+		printf("\n");
+	}
+}
+
+static void
+print_report(const char *op, struct timeval *t, int64_t offset,
+		int count, int total, int cnt, int Cflag)
+{
+	char s1[64], s2[64], ts[64];
+
+	timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
+	if (!Cflag) {
+		cvtstr((double)total, s1, sizeof(s1));
+		cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
+		printf("%s %d/%d bytes at offset %lld\n",
+			op, total, count, (long long)offset);
+		printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
+			s1, cnt, ts, s2, tdiv((double)cnt, *t));
+	} else {/* bytes,ops,time,bytes/sec,ops/sec */
+		printf("%d,%d,%s,%.3f,%.3f\n",
+			total, cnt, ts,
+			tdiv((double)total, *t),
+			tdiv((double)cnt, *t));
+	}
+}
+
+static int do_read(char *buf, int64_t offset, int count, int *total)
+{
+	int ret;
+
+	ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+	if (ret < 0)
+		return ret;
+	*total = count;
+	return 1;
+}
+
+static int do_write(char *buf, int64_t offset, int count, int *total)
+{
+	int ret;
+
+	ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+	if (ret < 0)
+		return ret;
+	*total = count;
+	return 1;
+}
+
+static int do_pread(char *buf, int64_t offset, int count, int *total)
+{
+	*total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
+	if (*total < 0)
+		return *total;
+	return 1;
+}
+
+static int do_pwrite(char *buf, int64_t offset, int count, int *total)
+{
+	*total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
+	if (*total < 0)
+		return *total;
+	return 1;
+}
+
+#define NOT_DONE 0x7fffffff
+static void aio_rw_done(void *opaque, int ret)
+{
+	*(int *)opaque = ret;
+}
+
+static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
+{
+	BlockDriverAIOCB *acb;
+	int async_ret = NOT_DONE;
+
+	acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
+			     aio_rw_done, &async_ret);
+	if (!acb)
+		return -EIO;
+
+	while (async_ret == NOT_DONE)
+		qemu_aio_wait();
+
+	*total = qiov->size;
+	return async_ret < 0 ? async_ret : 1;
+}
+
+static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
+{
+	BlockDriverAIOCB *acb;
+	int async_ret = NOT_DONE;
+
+	acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
+			      aio_rw_done, &async_ret);
+	if (!acb)
+		return -EIO;
+
+	while (async_ret == NOT_DONE)
+		qemu_aio_wait();
+
+	*total = qiov->size;
+	return async_ret < 0 ? async_ret : 1;
+}
+
+
+static const cmdinfo_t read_cmd;
+
+static void
+read_help(void)
+{
+	printf(
+"\n"
+" reads a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -l, -- length for pattern verification (only with -P)\n"
+" -p, -- use bdrv_pread to read the file\n"
+" -P, -- use a pattern to verify read data\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+" -s, -- start offset for pattern verification (only with -P)\n"
+" -v, -- dump buffer to standard output\n"
+"\n");
+}
+
+static int
+read_f(int argc, char **argv)
+{
+	struct timeval t1, t2;
+	int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
+	int Pflag = 0, sflag = 0, lflag = 0;
+	int c, cnt;
+	char *buf;
+	int64_t offset;
+	int count;
+        /* Some compilers get confused and warn if this is not initialized.  */
+        int total = 0;
+	int pattern = 0, pattern_offset = 0, pattern_count = 0;
+
+	while ((c = getopt(argc, argv, "Cl:pP:qs:v")) != EOF) {
+		switch (c) {
+		case 'C':
+			Cflag = 1;
+			break;
+		case 'l':
+			lflag = 1;
+			pattern_count = cvtnum(optarg);
+			if (pattern_count < 0) {
+				printf("non-numeric length argument -- %s\n", optarg);
+				return 0;
+			}
+			break;
+		case 'p':
+			pflag = 1;
+			break;
+		case 'P':
+			Pflag = 1;
+			pattern = atoi(optarg);
+			break;
+		case 'q':
+			qflag = 1;
+			break;
+		case 's':
+			sflag = 1;
+			pattern_offset = cvtnum(optarg);
+			if (pattern_offset < 0) {
+				printf("non-numeric length argument -- %s\n", optarg);
+				return 0;
+			}
+			break;
+		case 'v':
+			vflag = 1;
+			break;
+		default:
+			return command_usage(&read_cmd);
+		}
+	}
+
+	if (optind != argc - 2)
+		return command_usage(&read_cmd);
+
+	offset = cvtnum(argv[optind]);
+	if (offset < 0) {
+		printf("non-numeric length argument -- %s\n", argv[optind]);
+		return 0;
+	}
+
+	optind++;
+	count = cvtnum(argv[optind]);
+	if (count < 0) {
+		printf("non-numeric length argument -- %s\n", argv[optind]);
+		return 0;
+	}
+
+    if (!Pflag && (lflag || sflag)) {
+        return command_usage(&read_cmd);
+    }
+
+    if (!lflag) {
+        pattern_count = count - pattern_offset;
+    }
+
+    if ((pattern_count < 0) || (pattern_count + pattern_offset > count))  {
+        printf("pattern verfication range exceeds end of read data\n");
+        return 0;
+    }
+
+	if (!pflag)
+		if (offset & 0x1ff) {
+			printf("offset %lld is not sector aligned\n",
+				(long long)offset);
+			return 0;
+
+		if (count & 0x1ff) {
+			printf("count %d is not sector aligned\n",
+				count);
+			return 0;
+		}
+	}
+
+	buf = qemu_io_alloc(count, 0xab);
+
+	gettimeofday(&t1, NULL);
+	if (pflag)
+		cnt = do_pread(buf, offset, count, &total);
+	else
+		cnt = do_read(buf, offset, count, &total);
+	gettimeofday(&t2, NULL);
+
+	if (cnt < 0) {
+		printf("read failed: %s\n", strerror(-cnt));
+		return 0;
+	}
+
+	if (Pflag) {
+		void* cmp_buf = malloc(pattern_count);
+		memset(cmp_buf, pattern, pattern_count);
+		if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
+			printf("Pattern verification failed at offset %lld, "
+				"%d bytes\n",
+				(long long) offset + pattern_offset, pattern_count);
+		}
+		free(cmp_buf);
+	}
+
+	if (qflag)
+		return 0;
+
+        if (vflag)
+		dump_buffer(buf, offset, count);
+
+	/* Finally, report back -- -C gives a parsable format */
+	t2 = tsub(t2, t1);
+	print_report("read", &t2, offset, count, total, cnt, Cflag);
+
+	qemu_io_free(buf);
+
+	return 0;
+}
+
+static const cmdinfo_t read_cmd = {
+	.name		= "read",
+	.altname	= "r",
+	.cfunc		= read_f,
+	.argmin		= 2,
+	.argmax		= -1,
+	.args		= "[-aCpqv] [-P pattern [-s off] [-l len]] off len",
+	.oneline	= "reads a number of bytes at a specified offset",
+	.help		= read_help,
+};
+
+static const cmdinfo_t readv_cmd;
+
+static void
+readv_help(void)
+{
+	printf(
+"\n"
+" reads a range of bytes from the given offset into multiple buffers\n"
+"\n"
+" Example:\n"
+" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" Uses multiple iovec buffers if more than one byte range is specified.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -P, -- use a pattern to verify read data\n"
+" -v, -- dump buffer to standard output\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int
+readv_f(int argc, char **argv)
+{
+	struct timeval t1, t2;
+	int Cflag = 0, qflag = 0, vflag = 0;
+	int c, cnt;
+	char *buf, *p;
+	int64_t offset;
+	int count = 0, total;
+	int nr_iov, i;
+	QEMUIOVector qiov;
+	int pattern = 0;
+	int Pflag = 0;
+
+	while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+		switch (c) {
+		case 'C':
+			Cflag = 1;
+			break;
+		case 'P':
+			Pflag = 1;
+			pattern = atoi(optarg);
+			break;
+		case 'q':
+			qflag = 1;
+			break;
+		case 'v':
+			vflag = 1;
+			break;
+		default:
+			return command_usage(&readv_cmd);
+		}
+	}
+
+	if (optind > argc - 2)
+		return command_usage(&readv_cmd);
+
+
+	offset = cvtnum(argv[optind]);
+	if (offset < 0) {
+		printf("non-numeric length argument -- %s\n", argv[optind]);
+		return 0;
+	}
+	optind++;
+
+	if (offset & 0x1ff) {
+		printf("offset %lld is not sector aligned\n",
+			(long long)offset);
+		return 0;
+	}
+
+	if (count & 0x1ff) {
+		printf("count %d is not sector aligned\n",
+			count);
+		return 0;
+	}
+
+	for (i = optind; i < argc; i++) {
+	        size_t len;
+
+		len = cvtnum(argv[i]);
+		if (len < 0) {
+			printf("non-numeric length argument -- %s\n", argv[i]);
+			return 0;
+		}
+		count += len;
+	}
+
+	nr_iov = argc - optind;
+	qemu_iovec_init(&qiov, nr_iov);
+	buf = p = qemu_io_alloc(count, 0xab);
+	for (i = 0; i < nr_iov; i++) {
+	        size_t len;
+
+		len = cvtnum(argv[optind]);
+		if (len < 0) {
+			printf("non-numeric length argument -- %s\n",
+				argv[optind]);
+			return 0;
+		}
+
+		qemu_iovec_add(&qiov, p, len);
+		p += len;
+		optind++;
+	}
+
+	gettimeofday(&t1, NULL);
+	cnt = do_aio_readv(&qiov, offset, &total);
+	gettimeofday(&t2, NULL);
+
+	if (cnt < 0) {
+		printf("readv failed: %s\n", strerror(-cnt));
+		return 0;
+	}
+
+	if (Pflag) {
+		void* cmp_buf = malloc(count);
+		memset(cmp_buf, pattern, count);
+		if (memcmp(buf, cmp_buf, count)) {
+			printf("Pattern verification failed at offset %lld, "
+				"%d bytes\n",
+				(long long) offset, count);
+		}
+		free(cmp_buf);
+	}
+
+	if (qflag)
+		return 0;
+
+        if (vflag)
+		dump_buffer(buf, offset, qiov.size);
+
+	/* Finally, report back -- -C gives a parsable format */
+	t2 = tsub(t2, t1);
+	print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
+
+	qemu_io_free(buf);
+
+	return 0;
+}
+
+static const cmdinfo_t readv_cmd = {
+	.name		= "readv",
+	.cfunc		= readv_f,
+	.argmin		= 2,
+	.argmax		= -1,
+	.args		= "[-Cqv] [-P pattern ] off len [len..]",
+	.oneline	= "reads a number of bytes at a specified offset",
+	.help		= readv_help,
+};
+
+static const cmdinfo_t write_cmd;
+
+static void
+write_help(void)
+{
+	printf(
+"\n"
+" writes a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" -p, -- use bdrv_pwrite to write the file\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int
+write_f(int argc, char **argv)
+{
+	struct timeval t1, t2;
+	int Cflag = 0, pflag = 0, qflag = 0;
+	int c, cnt;
+	char *buf;
+	int64_t offset;
+	int count;
+        /* Some compilers get confused and warn if this is not initialized.  */
+        int total = 0;
+	int pattern = 0xcd;
+
+	while ((c = getopt(argc, argv, "CpP:q")) != EOF) {
+		switch (c) {
+		case 'C':
+			Cflag = 1;
+			break;
+		case 'p':
+			pflag = 1;
+			break;
+		case 'P':
+			pattern = atoi(optarg);
+			break;
+		case 'q':
+			qflag = 1;
+			break;
+		default:
+			return command_usage(&write_cmd);
+		}
+	}
+
+	if (optind != argc - 2)
+		return command_usage(&write_cmd);
+
+	offset = cvtnum(argv[optind]);
+	if (offset < 0) {
+		printf("non-numeric length argument -- %s\n", argv[optind]);
+		return 0;
+	}
+
+	optind++;
+	count = cvtnum(argv[optind]);
+	if (count < 0) {
+		printf("non-numeric length argument -- %s\n", argv[optind]);
+		return 0;
+	}
+
+	if (!pflag) {
+		if (offset & 0x1ff) {
+			printf("offset %lld is not sector aligned\n",
+				(long long)offset);
+			return 0;
+		}
+
+		if (count & 0x1ff) {
+			printf("count %d is not sector aligned\n",
+				count);
+			return 0;
+		}
+	}
+
+	buf = qemu_io_alloc(count, pattern);
+
+	gettimeofday(&t1, NULL);
+	if (pflag)
+		cnt = do_pwrite(buf, offset, count, &total);
+	else
+		cnt = do_write(buf, offset, count, &total);
+	gettimeofday(&t2, NULL);
+
+	if (cnt < 0) {
+		printf("write failed: %s\n", strerror(-cnt));
+		return 0;
+	}
+
+	if (qflag)
+		return 0;
+
+	/* Finally, report back -- -C gives a parsable format */
+	t2 = tsub(t2, t1);
+	print_report("wrote", &t2, offset, count, total, cnt, Cflag);
+
+	qemu_io_free(buf);
+
+	return 0;
+}
+
+static const cmdinfo_t write_cmd = {
+	.name		= "write",
+	.altname	= "w",
+	.cfunc		= write_f,
+	.argmin		= 2,
+	.argmax		= -1,
+	.args		= "[-aCpq] [-P pattern ] off len",
+	.oneline	= "writes a number of bytes at a specified offset",
+	.help		= write_help,
+};
+
+static const cmdinfo_t writev_cmd;
+
+static void
+writev_help(void)
+{
+	printf(
+"\n"
+" writes a range of bytes from the given offset source from multiple buffers\n"
+"\n"
+" Example:\n"
+" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quite mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int
+writev_f(int argc, char **argv)
+{
+	struct timeval t1, t2;
+	int Cflag = 0, qflag = 0;
+	int c, cnt;
+	char *buf, *p;
+	int64_t offset;
+	int count = 0, total;
+	int nr_iov, i;
+	int pattern = 0xcd;
+	QEMUIOVector qiov;
+
+	while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+		switch (c) {
+		case 'C':
+			Cflag = 1;
+			break;
+		case 'q':
+			qflag = 1;
+			break;
+		case 'P':
+			pattern = atoi(optarg);
+			break;
+		default:
+			return command_usage(&writev_cmd);
+		}
+	}
+
+	if (optind > argc - 2)
+		return command_usage(&writev_cmd);
+
+	offset = cvtnum(argv[optind]);
+	if (offset < 0) {
+		printf("non-numeric length argument -- %s\n", argv[optind]);
+		return 0;
+	}
+	optind++;
+
+	if (offset & 0x1ff) {
+		printf("offset %lld is not sector aligned\n",
+			(long long)offset);
+		return 0;
+	}
+
+	if (count & 0x1ff) {
+		printf("count %d is not sector aligned\n",
+			count);
+		return 0;
+	}
+
+
+	for (i = optind; i < argc; i++) {
+	        size_t len;
+
+		len = cvtnum(argv[optind]);
+		if (len < 0) {
+			printf("non-numeric length argument -- %s\n", argv[i]);
+			return 0;
+		}
+		count += len;
+	}
+
+	nr_iov = argc - optind;
+	qemu_iovec_init(&qiov, nr_iov);
+	buf = p = qemu_io_alloc(count, pattern);
+	for (i = 0; i < nr_iov; i++) {
+	        size_t len;
+
+		len = cvtnum(argv[optind]);
+		if (len < 0) {
+			printf("non-numeric length argument -- %s\n",
+				argv[optind]);
+			return 0;
+		}
+
+		qemu_iovec_add(&qiov, p, len);
+		p += len;
+		optind++;
+	}
+
+	gettimeofday(&t1, NULL);
+	cnt = do_aio_writev(&qiov, offset, &total);
+	gettimeofday(&t2, NULL);
+
+	if (cnt < 0) {
+		printf("writev failed: %s\n", strerror(-cnt));
+		return 0;
+	}
+
+	if (qflag)
+		return 0;
+
+	/* Finally, report back -- -C gives a parsable format */
+	t2 = tsub(t2, t1);
+	print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
+
+	qemu_io_free(buf);
+
+	return 0;
+}
+
+static const cmdinfo_t writev_cmd = {
+	.name		= "writev",
+	.cfunc		= writev_f,
+	.argmin		= 2,
+	.argmax		= -1,
+	.args		= "[-Cq] [-P pattern ] off len [len..]",
+	.oneline	= "writes a number of bytes at a specified offset",
+	.help		= writev_help,
+};
+
+static int
+flush_f(int argc, char **argv)
+{
+	bdrv_flush(bs);
+	return 0;
+}
+
+static const cmdinfo_t flush_cmd = {
+	.name		= "flush",
+	.altname	= "f",
+	.cfunc		= flush_f,
+	.oneline	= "flush all in-core file state to disk",
+};
+
+static int
+truncate_f(int argc, char **argv)
+{
+	int64_t offset;
+	int ret;
+
+	offset = cvtnum(argv[1]);
+	if (offset < 0) {
+		printf("non-numeric truncate argument -- %s\n", argv[1]);
+		return 0;
+	}
+
+	ret = bdrv_truncate(bs, offset);
+	if (ret < 0) {
+		printf("truncate: %s", strerror(ret));
+		return 0;
+	}
+
+	return 0;
+}
+
+static const cmdinfo_t truncate_cmd = {
+	.name		= "truncate",
+	.altname	= "t",
+	.cfunc		= truncate_f,
+	.argmin		= 1,
+	.argmax		= 1,
+	.args		= "off",
+	.oneline	= "truncates the current file at the given offset",
+};
+
+static int
+length_f(int argc, char **argv)
+{
+        int64_t size;
+	char s1[64];
+
+	size = bdrv_getlength(bs);
+	if (size < 0) {
+		printf("getlength: %s", strerror(size));
+		return 0;
+	}
+
+	cvtstr(size, s1, sizeof(s1));
+	printf("%s\n", s1);
+	return 0;
+}
+
+
+static const cmdinfo_t length_cmd = {
+	.name		= "length",
+	.altname	= "l",
+	.cfunc		= length_f,
+	.oneline	= "gets the length of the current file",
+};
+
+
+static int
+info_f(int argc, char **argv)
+{
+	BlockDriverInfo bdi;
+	char s1[64], s2[64];
+	int ret;
+
+	if (bs->drv && bs->drv->format_name)
+		printf("format name: %s\n", bs->drv->format_name);
+	if (bs->drv && bs->drv->protocol_name)
+		printf("format name: %s\n", bs->drv->protocol_name);
+
+	ret = bdrv_get_info(bs, &bdi);
+	if (ret)
+		return 0;
+
+	cvtstr(bdi.cluster_size, s1, sizeof(s1));
+	cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
+
+	printf("cluster size: %s\n", s1);
+	printf("vm state offset: %s\n", s2);
+
+	return 0;
+}
+
+
+
+static const cmdinfo_t info_cmd = {
+	.name		= "info",
+	.altname	= "i",
+	.cfunc		= info_f,
+	.oneline	= "prints information about the current file",
+};
+
+static int
+alloc_f(int argc, char **argv)
+{
+	int64_t offset;
+	int nb_sectors;
+	char s1[64];
+	int num;
+	int ret;
+	const char *retstr;
+
+	offset = cvtnum(argv[1]);
+	if (offset & 0x1ff) {
+		printf("offset %lld is not sector aligned\n",
+			(long long)offset);
+		return 0;
+	}
+
+	if (argc == 3)
+		nb_sectors = cvtnum(argv[2]);
+	else
+		nb_sectors = 1;
+
+	ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
+
+	cvtstr(offset, s1, sizeof(s1));
+
+	retstr = ret ? "allocated" : "not allocated";
+	if (nb_sectors == 1)
+		printf("sector %s at offset %s\n", retstr, s1);
+	else
+		printf("%d/%d sectors %s at offset %s\n",
+			num, nb_sectors, retstr, s1);
+	return 0;
+}
+
+static const cmdinfo_t alloc_cmd = {
+	.name		= "alloc",
+	.altname	= "a",
+	.argmin		= 1,
+	.argmax		= 2,
+	.cfunc		= alloc_f,
+	.args		= "off [sectors]",
+	.oneline	= "checks if a sector is present in the file",
+};
+
+static int
+close_f(int argc, char **argv)
+{
+	bdrv_close(bs);
+	bs = NULL;
+	return 0;
+}
+
+static const cmdinfo_t close_cmd = {
+	.name		= "close",
+	.altname	= "c",
+	.cfunc		= close_f,
+	.oneline	= "close the current open file",
+};
+
+static int openfile(char *name, int flags)
+{
+	if (bs) {
+		fprintf(stderr, "file open already, try 'help close'\n");
+		return 1;
+	}
+
+	bs = bdrv_new("hda");
+	if (!bs)
+		return 1;
+
+	if (bdrv_open(bs, name, flags) == -1) {
+		fprintf(stderr, "%s: can't open device %s\n", progname, name);
+		bs = NULL;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+open_help(void)
+{
+	printf(
+"\n"
+" opens a new file in the requested mode\n"
+"\n"
+" Example:\n"
+" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
+"\n"
+" Opens a file for subsequent use by all of the other qemu-io commands.\n"
+" -C, -- create new file if it doesn't exist\n"
+" -r, -- open file read-only\n"
+" -s, -- use snapshot file\n"
+" -n, -- disable host cache\n"
+"\n");
+}
+
+static const cmdinfo_t open_cmd;
+
+static int
+open_f(int argc, char **argv)
+{
+	int flags = 0;
+	int readonly = 0;
+	int c;
+
+	while ((c = getopt(argc, argv, "snCr")) != EOF) {
+		switch (c) {
+		case 's':
+			flags |= BDRV_O_SNAPSHOT;
+			break;
+		case 'n':
+			flags |= BDRV_O_NOCACHE;
+			break;
+		case 'C':
+			flags |= BDRV_O_CREAT;
+			break;
+		case 'r':
+			readonly = 1;
+			break;
+		default:
+			return command_usage(&open_cmd);
+		}
+	}
+
+	if (readonly)
+		flags |= BDRV_O_RDONLY;
+	else
+		flags |= BDRV_O_RDWR;
+
+	if (optind != argc - 1)
+		return command_usage(&open_cmd);
+
+	return openfile(argv[optind], flags);
+}
+
+static const cmdinfo_t open_cmd = {
+	.name		= "open",
+	.altname	= "o",
+	.cfunc		= open_f,
+	.argmin		= 1,
+	.argmax		= -1,
+	.flags		= CMD_NOFILE_OK,
+	.args		= "[-Crsn] [path]",
+	.oneline	= "open the file specified by path",
+	.help		= open_help,
+};
+
+static int
+init_args_command(
+        int     index)
+{
+	/* only one device allowed so far */
+	if (index >= 1)
+		return 0;
+	return ++index;
+}
+
+static int
+init_check_command(
+	const cmdinfo_t *ct)
+{
+	if (ct->flags & CMD_FLAG_GLOBAL)
+		return 1;
+	if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+		fprintf(stderr, "no file open, try 'help open'\n");
+		return 0;
+	}
+	return 1;
+}
+
+static void usage(const char *name)
+{
+	printf(
+"Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n"
+"QEMU Disk excerciser\n"
+"\n"
+"  -C, --create         create new file if it doesn't exist\n"
+"  -c, --cmd            command to execute\n"
+"  -r, --read-only      export read-only\n"
+"  -s, --snapshot       use snapshot file\n"
+"  -n, --nocache        disable host cache\n"
+"  -m, --misalign       misalign allocations for O_DIRECT\n"
+"  -h, --help           display this help and exit\n"
+"  -V, --version        output version information and exit\n"
+"\n",
+	name);
+}
+
+
+int main(int argc, char **argv)
+{
+	int readonly = 0;
+	const char *sopt = "hVc:Crsnm";
+	struct option lopt[] = {
+		{ "help", 0, 0, 'h' },
+		{ "version", 0, 0, 'V' },
+		{ "offset", 1, 0, 'o' },
+		{ "cmd", 1, 0, 'c' },
+		{ "create", 0, 0, 'C' },
+		{ "read-only", 0, 0, 'r' },
+		{ "snapshot", 0, 0, 's' },
+		{ "nocache", 0, 0, 'n' },
+		{ "misalign", 0, 0, 'm' },
+		{ NULL, 0, 0, 0 }
+	};
+	int c;
+	int opt_index = 0;
+	int flags = 0;
+
+	progname = basename(argv[0]);
+
+	while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
+		switch (c) {
+		case 's':
+			flags |= BDRV_O_SNAPSHOT;
+			break;
+		case 'n':
+			flags |= BDRV_O_NOCACHE;
+			break;
+		case 'c':
+			add_user_command(optarg);
+			break;
+		case 'C':
+			flags |= BDRV_O_CREAT;
+			break;
+		case 'r':
+			readonly = 1;
+			break;
+		case 'm':
+			misalign = 1;
+			break;
+		case 'V':
+			printf("%s version %s\n", progname, VERSION);
+			exit(0);
+		case 'h':
+			usage(progname);
+			exit(0);
+		default:
+			usage(progname);
+			exit(1);
+		}
+	}
+
+	if ((argc - optind) > 1) {
+		usage(progname);
+		exit(1);
+	}
+
+	bdrv_init();
+
+	/* initialize commands */
+	quit_init();
+	help_init();
+	add_command(&open_cmd);
+	add_command(&close_cmd);
+	add_command(&read_cmd);
+	add_command(&readv_cmd);
+	add_command(&write_cmd);
+	add_command(&writev_cmd);
+	add_command(&flush_cmd);
+	add_command(&truncate_cmd);
+	add_command(&length_cmd);
+	add_command(&info_cmd);
+	add_command(&alloc_cmd);
+
+	add_args_command(init_args_command);
+	add_check_command(init_check_command);
+
+	/* open the device */
+	if (readonly)
+		flags |= BDRV_O_RDONLY;
+	else
+		flags |= BDRV_O_RDWR;
+
+	if ((argc - optind) == 1)
+		openfile(argv[optind], flags);
+	command_loop();
+
+	if (bs)
+		bdrv_close(bs);
+	return 0;
+}
diff --git a/qemu-lock.h b/qemu-lock.h
index fdd8da9..26661ba 100644
--- a/qemu-lock.h
+++ b/qemu-lock.h
@@ -13,7 +13,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 
 /* Locking primitives.  Most of this code should be redundant -
@@ -58,17 +58,16 @@
 
 #endif
 
-#if defined(__powerpc__)
+#if defined(_ARCH_PPC)
 static inline int testandset (int *p)
 {
     int ret;
     __asm__ __volatile__ (
-                          "0:    lwarx %0,0,%1\n"
+                          "      lwarx %0,0,%1\n"
                           "      xor. %0,%3,%0\n"
-                          "      bne 1f\n"
+                          "      bne $+12\n"
                           "      stwcx. %2,0,%1\n"
-                          "      bne- 0b\n"
-                          "1:    "
+                          "      bne- $-16\n"
                           : "=&r" (ret)
                           : "r" (p), "r" (1), "r" (0)
                           : "cr0", "memory");
diff --git a/qemu-log.h b/qemu-log.h
index 1ebea81..fccfb110 100644
--- a/qemu-log.h
+++ b/qemu-log.h
@@ -1,7 +1,93 @@
 #ifndef QEMU_LOG_H
 #define QEMU_LOG_H
 
+/* The deprecated global variables: */
 extern FILE *logfile;
 extern int loglevel;
 
+
+/* 
+ * The new API:
+ *
+ */
+
+/* Log settings checking macros: */
+
+/* Returns true if qemu_log() will really write somewhere
+ */
+#define qemu_log_enabled() (logfile != NULL)
+
+/* Returns true if a bit is set in the current loglevel mask
+ */
+#define qemu_loglevel_mask(b) ((loglevel & (b)) != 0)
+
+
+/* Logging functions: */
+
+/* main logging function
+ */
+#define qemu_log(...) do {                 \
+        if (logfile)                       \
+            fprintf(logfile, ## __VA_ARGS__); \
+    } while (0)
+
+/* vfprintf-like logging function
+ */
+#define qemu_log_vprintf(fmt, va) do {     \
+        if (logfile)                       \
+            vfprintf(logfile, fmt, va);    \
+    } while (0)
+
+/* log only if a bit is set on the current loglevel mask
+ */
+#define qemu_log_mask(b, ...) do {         \
+        if (loglevel & (b))                \
+            fprintf(logfile, ## __VA_ARGS__); \
+    } while (0)
+
+
+
+
+/* Special cases: */
+
+/* cpu_dump_state() logging functions: */
+#define log_cpu_state(env, f) cpu_dump_state((env), logfile, fprintf, (f));
+#define log_cpu_state_mask(b, env, f) do {           \
+      if (loglevel & (b)) log_cpu_state((env), (f)); \
+  } while (0)
+
+/* disas() and target_disas() to logfile: */
+#define log_target_disas(start, len, flags) \
+        target_disas(logfile, (start), (len), (flags))
+#define log_disas(start, len) \
+        disas(logfile, (start), (len))
+
+/* page_dump() output to the log file: */
+#define log_page_dump() page_dump(logfile)
+
+
+
+/* Maintenance: */
+
+/* fflush() the log file */
+#define qemu_log_flush() fflush(logfile)
+
+/* Close the log file */
+#define qemu_log_close() do { \
+        fclose(logfile);      \
+        logfile = NULL;       \
+    } while (0)
+
+/* Set up a new log file */
+#define qemu_log_set_file(f) do { \
+        logfile = (f);            \
+    } while (0)
+
+/* Set up a new log file, only if none is set */
+#define qemu_log_try_set_file(f) do { \
+        if (!logfile)                 \
+            logfile = (f);            \
+    } while (0)
+
+
 #endif
diff --git a/qemu-malloc.c b/qemu-malloc.c
new file mode 100644
index 0000000..295d185
--- /dev/null
+++ b/qemu-malloc.c
@@ -0,0 +1,95 @@
+/*
+ * malloc-like functions for system emulation.
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include <stdlib.h>
+
+static void *oom_check(void *ptr)
+{
+    if (ptr == NULL) {
+        abort();
+    }
+    return ptr;
+}
+
+void *get_mmap_addr(unsigned long size)
+{
+    return NULL;
+}
+
+void qemu_free(void *ptr)
+{
+    free(ptr);
+}
+
+void *qemu_malloc(size_t size)
+{
+    if (!size) {
+        abort();
+    }
+    return oom_check(malloc(size));
+}
+
+void *qemu_realloc(void *ptr, size_t size)
+{
+    if (size) {
+        return oom_check(realloc(ptr, size));
+    } else {
+        if (ptr) {
+            return realloc(ptr, size);
+        }
+    }
+    abort();
+}
+
+void *qemu_mallocz(size_t size)
+{
+    void *ptr;
+    ptr = qemu_malloc(size);
+    memset(ptr, 0, size);
+    return ptr;
+}
+
+char *qemu_strdup(const char *str)
+{
+    char *ptr;
+    size_t len = strlen(str);
+    ptr = qemu_malloc(len + 1);
+    memcpy(ptr, str, len + 1);
+    return ptr;
+}
+
+char *qemu_strndup(const char *str, size_t size)
+{
+    const char *end = memchr(str, 0, size);
+    char *new;
+
+    if (end) {
+        size = end - str;
+    }
+
+    new = qemu_malloc(size + 1);
+    new[size] = 0;
+
+    return memcpy(new, str, size);
+}
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
new file mode 100644
index 0000000..fa48527
--- /dev/null
+++ b/qemu-monitor.hx
@@ -0,0 +1,616 @@
+HXCOMM Use DEFHEADING() to define headings in both help text and texi
+HXCOMM Text between STEXI and ETEXI are copied to texi version and
+HXCOMM discarded from C version
+HXCOMM DEF(command, args, callback, arg_string, help) is used to construct
+HXCOMM monitor commands
+HXCOMM HXCOMM can be used for comments, discarded from both texi and C
+
+STEXI
+@table @option
+ETEXI
+
+    { "help|?", "s?", help_cmd, "[cmd]", "show the help" },
+STEXI
+@item help or ? [@var{cmd}]
+Show the help for all commands or just for command @var{cmd}.
+ETEXI
+
+    { "commit", "s", do_commit,
+      "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" },
+STEXI
+@item commit
+Commit changes to the disk images (if -snapshot is used) or backing files.
+ETEXI
+
+    { "info", "s?", do_info,
+      "[subcommand]", "show various information about the system state" },
+STEXI
+@item info @var{subcommand}
+Show various information about the system state.
+
+@table @option
+@item info version
+show the version of QEMU
+@item info network
+show the various VLANs and the associated devices
+@item info chardev
+show the character devices
+@item info block
+show the block devices
+@item info block
+show block device statistics
+@item info registers
+show the cpu registers
+@item info cpus
+show infos for each CPU
+@item info history
+show the command line history
+@item info irq
+show the interrupts statistics (if available)
+@item info pic
+show i8259 (PIC) state
+@item info pci
+show emulated PCI device info
+@item info tlb
+show virtual to physical memory mappings (i386 only)
+@item info mem
+show the active virtual memory mappings (i386 only)
+@item info hpet
+show state of HPET (i386 only)
+@item info kqemu
+show KQEMU information
+@item info kvm
+show KVM information
+@item info usb
+show USB devices plugged on the virtual USB hub
+@item info usbhost
+show all USB host devices
+@item info profile
+show profiling information
+@item info capture
+show information about active capturing
+@item info snapshots
+show list of VM snapshots
+@item info status
+show the current VM status (running|paused)
+@item info pcmcia
+show guest PCMCIA status
+@item info mice
+show which guest mouse is receiving events
+@item info vnc
+show the vnc server status
+@item info name
+show the current VM name
+@item info uuid
+show the current VM UUID
+@item info cpustats
+show CPU statistics
+@item info slirp
+show SLIRP statistics (if available)
+@item info migrate
+show migration status
+@item info balloon
+show balloon information
+@item info qtree
+show device tree
+@end table
+ETEXI
+
+    { "q|quit", "", do_quit,
+      "", "quit the emulator" },
+STEXI
+@item q or quit
+Quit the emulator.
+ETEXI
+
+    { "eject", "-fB", do_eject,
+      "[-f] device", "eject a removable medium (use -f to force it)" },
+STEXI
+@item eject [-f] @var{device}
+Eject a removable medium (use -f to force it).
+ETEXI
+
+    { "change", "BFs?", do_change,
+      "device filename [format]", "change a removable medium, optional format" },
+STEXI
+@item change @var{device} @var{setting}
+
+Change the configuration of a device.
+
+@table @option
+@item change @var{diskdevice} @var{filename} [@var{format}]
+Change the medium for a removable disk device to point to @var{filename}. eg
+
+@example
+(qemu) change ide1-cd0 /path/to/some.iso
+@end example
+
+@var{format} is optional.
+
+@item change vnc @var{display},@var{options}
+Change the configuration of the VNC server. The valid syntax for @var{display}
+and @var{options} are described at @ref{sec_invocation}. eg
+
+@example
+(qemu) change vnc localhost:1
+@end example
+
+@item change vnc password [@var{password}]
+
+Change the password associated with the VNC server. If the new password is not
+supplied, the monitor will prompt for it to be entered. VNC passwords are only
+significant up to 8 letters. eg
+
+@example
+(qemu) change vnc password
+Password: ********
+@end example
+
+@end table
+ETEXI
+
+    { "screendump", "F", do_screen_dump,
+      "filename", "save screen into PPM image 'filename'" },
+STEXI
+@item screendump @var{filename}
+Save screen into PPM image @var{filename}.
+ETEXI
+
+    { "logfile", "F", do_logfile,
+      "filename", "output logs to 'filename'" },
+STEXI
+@item logfile @var{filename}
+Output logs to @var{filename}.
+ETEXI
+
+    { "log", "s", do_log,
+      "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
+STEXI
+@item log @var{item1}[,...]
+Activate logging of the specified items to @file{/tmp/qemu.log}.
+ETEXI
+
+    { "savevm", "s?", do_savevm,
+      "[tag|id]", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" },
+STEXI
+@item savevm [@var{tag}|@var{id}]
+Create a snapshot of the whole virtual machine. If @var{tag} is
+provided, it is used as human readable identifier. If there is already
+a snapshot with the same tag or ID, it is replaced. More info at
+@ref{vm_snapshots}.
+ETEXI
+
+    { "loadvm", "s", do_loadvm,
+      "tag|id", "restore a VM snapshot from its tag or id" },
+STEXI
+@item loadvm @var{tag}|@var{id}
+Set the whole virtual machine to the snapshot identified by the tag
+@var{tag} or the unique snapshot ID @var{id}.
+ETEXI
+
+    { "delvm", "s", do_delvm,
+      "tag|id", "delete a VM snapshot from its tag or id" },
+STEXI
+@item delvm @var{tag}|@var{id}
+Delete the snapshot identified by @var{tag} or @var{id}.
+ETEXI
+
+    { "singlestep", "s?", do_singlestep,
+      "[on|off]", "run emulation in singlestep mode or switch to normal mode", },
+STEXI
+@item singlestep [off]
+Run the emulation in single step mode.
+If called with option off, the emulation returns to normal mode.
+ETEXI
+
+    { "stop", "", do_stop,
+      "", "stop emulation", },
+STEXI
+@item stop
+Stop emulation.
+ETEXI
+
+    { "c|cont", "", do_cont,
+      "", "resume emulation", },
+STEXI
+@item c or cont
+Resume emulation.
+ETEXI
+
+    { "gdbserver", "s?", do_gdbserver,
+      "[device]", "start gdbserver on given device (default 'tcp::1234'), stop with 'none'", },
+STEXI
+@item gdbserver [@var{port}]
+Start gdbserver session (default @var{port}=1234)
+ETEXI
+
+    { "x", "/l", do_memory_dump,
+      "/fmt addr", "virtual memory dump starting at 'addr'", },
+STEXI
+@item x/fmt @var{addr}
+Virtual memory dump starting at @var{addr}.
+ETEXI
+
+    { "xp", "/l", do_physical_memory_dump,
+      "/fmt addr", "physical memory dump starting at 'addr'", },
+STEXI
+@item xp /@var{fmt} @var{addr}
+Physical memory dump starting at @var{addr}.
+
+@var{fmt} is a format which tells the command how to format the
+data. Its syntax is: @option{/@{count@}@{format@}@{size@}}
+
+@table @var
+@item count
+is the number of items to be dumped.
+
+@item format
+can be x (hex), d (signed decimal), u (unsigned decimal), o (octal),
+c (char) or i (asm instruction).
+
+@item size
+can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86,
+@code{h} or @code{w} can be specified with the @code{i} format to
+respectively select 16 or 32 bit code instruction size.
+
+@end table
+
+Examples:
+@itemize
+@item
+Dump 10 instructions at the current instruction pointer:
+@example
+(qemu) x/10i $eip
+0x90107063:  ret
+0x90107064:  sti
+0x90107065:  lea    0x0(%esi,1),%esi
+0x90107069:  lea    0x0(%edi,1),%edi
+0x90107070:  ret
+0x90107071:  jmp    0x90107080
+0x90107073:  nop
+0x90107074:  nop
+0x90107075:  nop
+0x90107076:  nop
+@end example
+
+@item
+Dump 80 16 bit values at the start of the video memory.
+@smallexample
+(qemu) xp/80hx 0xb8000
+0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42
+0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41
+0x000b8020: 0x0b42 0x0b69 0x0b6f 0x0b73 0x0b20 0x0b63 0x0b75 0x0b72
+0x000b8030: 0x0b72 0x0b65 0x0b6e 0x0b74 0x0b2d 0x0b63 0x0b76 0x0b73
+0x000b8040: 0x0b20 0x0b30 0x0b35 0x0b20 0x0b4e 0x0b6f 0x0b76 0x0b20
+0x000b8050: 0x0b32 0x0b30 0x0b30 0x0b33 0x0720 0x0720 0x0720 0x0720
+0x000b8060: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
+0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
+0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
+0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720
+@end smallexample
+@end itemize
+ETEXI
+
+    { "p|print", "/l", do_print,
+      "/fmt expr", "print expression value (use $reg for CPU register access)", },
+STEXI
+@item p or print/@var{fmt} @var{expr}
+
+Print expression value. Only the @var{format} part of @var{fmt} is
+used.
+ETEXI
+
+    { "i", "/ii.", do_ioport_read,
+      "/fmt addr", "I/O port read" },
+STEXI
+Read I/O port.
+ETEXI
+
+
+    { "sendkey", "si?", do_sendkey,
+      "keys [hold_ms]", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)" },
+STEXI
+@item sendkey @var{keys}
+
+Send @var{keys} to the emulator. @var{keys} could be the name of the
+key or @code{#} followed by the raw value in either decimal or hexadecimal
+format. Use @code{-} to press several keys simultaneously. Example:
+@example
+sendkey ctrl-alt-f1
+@end example
+
+This command is useful to send keys that your graphical user interface
+intercepts at low level, such as @code{ctrl-alt-f1} in X Window.
+ETEXI
+
+    { "system_reset", "", do_system_reset,
+      "", "reset the system" },
+STEXI
+@item system_reset
+
+Reset the system.
+ETEXI
+
+    { "system_powerdown", "", do_system_powerdown,
+      "", "send system power down event" },
+STEXI
+@item system_powerdown
+
+Power down the system (if supported).
+ETEXI
+
+    { "sum", "ii", do_sum,
+      "addr size", "compute the checksum of a memory region" },
+STEXI
+@item sum @var{addr} @var{size}
+
+Compute the checksum of a memory region.
+ETEXI
+
+    { "usb_add", "s", do_usb_add,
+      "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" },
+STEXI
+@item usb_add @var{devname}
+
+Add the USB device @var{devname}.  For details of available devices see
+@ref{usb_devices}
+ETEXI
+
+    { "usb_del", "s", do_usb_del,
+      "device", "remove USB device 'bus.addr'" },
+STEXI
+@item usb_del @var{devname}
+
+Remove the USB device @var{devname} from the QEMU virtual USB
+hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor
+command @code{info usb} to see the devices you can remove.
+ETEXI
+
+    { "cpu", "i", do_cpu_set,
+      "index", "set the default CPU" },
+STEXI
+Set the default CPU.
+ETEXI
+
+    { "mouse_move", "sss?", do_mouse_move,
+      "dx dy [dz]", "send mouse move events" },
+STEXI
+@item mouse_move @var{dx} @var{dy} [@var{dz}]
+Move the active mouse to the specified coordinates @var{dx} @var{dy}
+with optional scroll axis @var{dz}.
+ETEXI
+
+    { "mouse_button", "i", do_mouse_button,
+      "state", "change mouse button state (1=L, 2=M, 4=R)" },
+STEXI
+@item mouse_button @var{val}
+Change the active mouse button state @var{val} (1=L, 2=M, 4=R).
+ETEXI
+
+    { "mouse_set", "i", do_mouse_set,
+      "index", "set which mouse device receives events" },
+STEXI
+@item mouse_set @var{index}
+Set which mouse device receives events at given @var{index}, index
+can be obtained with
+@example
+info mice
+@end example
+ETEXI
+
+#ifdef HAS_AUDIO
+    { "wavcapture", "si?i?i?", do_wav_capture,
+      "path [frequency [bits [channels]]]",
+      "capture audio to a wave file (default frequency=44100 bits=16 channels=2)" },
+#endif
+STEXI
+@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]]
+Capture audio into @var{filename}. Using sample rate @var{frequency}
+bits per sample @var{bits} and number of channels @var{channels}.
+
+Defaults:
+@itemize @minus
+@item Sample rate = 44100 Hz - CD quality
+@item Bits = 16
+@item Number of channels = 2 - Stereo
+@end itemize
+ETEXI
+
+#ifdef HAS_AUDIO
+    { "stopcapture", "i", do_stop_capture,
+      "capture index", "stop capture" },
+#endif
+STEXI
+@item stopcapture @var{index}
+Stop capture with a given @var{index}, index can be obtained with
+@example
+info capture
+@end example
+ETEXI
+
+    { "memsave", "lis", do_memory_save,
+      "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", },
+STEXI
+@item memsave @var{addr} @var{size} @var{file}
+save to disk virtual memory dump starting at @var{addr} of size @var{size}.
+ETEXI
+
+    { "pmemsave", "lis", do_physical_memory_save,
+      "addr size file", "save to disk physical memory dump starting at 'addr' of size 'size'", },
+STEXI
+@item pmemsave @var{addr} @var{size} @var{file}
+save to disk physical memory dump starting at @var{addr} of size @var{size}.
+ETEXI
+
+    { "boot_set", "s", do_boot_set,
+      "bootdevice", "define new values for the boot device list" },
+STEXI
+@item boot_set @var{bootdevicelist}
+
+Define new values for the boot device list. Those values will override
+the values specified on the command line through the @code{-boot} option.
+
+The values that can be specified here depend on the machine type, but are
+the same that can be specified in the @code{-boot} command line option.
+ETEXI
+
+#if defined(TARGET_I386)
+    { "nmi", "i", do_inject_nmi,
+      "cpu", "inject an NMI on the given CPU", },
+#endif
+STEXI
+@item nmi @var{cpu}
+Inject an NMI on the given CPU (x86 only).
+ETEXI
+
+    { "migrate", "-ds", do_migrate,
+      "[-d] uri", "migrate to URI (using -d to not wait for completion)" },
+STEXI
+@item migrate [-d] @var{uri}
+Migrate to @var{uri} (using -d to not wait for completion).
+ETEXI
+
+    { "migrate_cancel", "", do_migrate_cancel,
+      "", "cancel the current VM migration" },
+STEXI
+@item migrate_cancel
+Cancel the current VM migration.
+ETEXI
+
+    { "migrate_set_speed", "s", do_migrate_set_speed,
+      "value", "set maximum speed (in bytes) for migrations" },
+STEXI
+@item migrate_set_speed @var{value}
+Set maximum speed to @var{value} (in bytes) for migrations.
+ETEXI
+
+    { "migrate_set_downtime", "s", do_migrate_set_downtime,
+      "value", "set maximum tolerated downtime (in seconds) for migrations" },
+
+STEXI
+@item migrate_set_downtime @var{second}
+Set maximum tolerated downtime (in seconds) for migration.
+ETEXI
+
+#if defined(TARGET_I386)
+    { "drive_add", "ss", drive_hot_add, "pci_addr=[[<domain>:]<bus>:]<slot>\n"
+                                         "[file=file][,if=type][,bus=n]\n"
+                                        "[,unit=m][,media=d][index=i]\n"
+                                        "[,cyls=c,heads=h,secs=s[,trans=t]]\n"
+                                        "[snapshot=on|off][,cache=on|off]",
+                                        "add drive to PCI storage controller" },
+#endif
+STEXI
+@item drive_add
+Add drive to PCI storage controller.
+ETEXI
+
+#if defined(TARGET_I386)
+    { "pci_add", "sss", pci_device_hot_add, "pci_addr=auto|[[<domain>:]<bus>:]<slot> nic|storage [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...", "hot-add PCI device" },
+#endif
+STEXI
+@item pci_add
+Hot-add PCI device.
+ETEXI
+
+#if defined(TARGET_I386)
+    { "pci_del", "s", pci_device_hot_remove, "pci_addr=[[<domain>:]<bus>:]<slot>", "hot remove PCI device" },
+#endif
+STEXI
+@item pci_del
+Hot remove PCI device.
+ETEXI
+
+    { "host_net_add", "ss?", net_host_device_add,
+      "tap|user|socket|vde|dump [options]", "add host VLAN client" },
+STEXI
+@item host_net_add
+Add host VLAN client.
+ETEXI
+
+    { "host_net_remove", "is", net_host_device_remove,
+      "vlan_id name", "remove host VLAN client" },
+STEXI
+@item host_net_remove
+Remove host VLAN client.
+ETEXI
+
+#ifdef CONFIG_SLIRP
+    { "host_net_redir", "ss?", net_slirp_redir,
+      "[tcp|udp]:host-port:[guest-host]:guest-port", "redirect TCP or UDP connections from host to guest (requires -net user)\n"
+      "host_net_redir remove [tcp:|udp:]host-port -- remove redirection\n"
+      "host_net_redir list -- show all redirections" },
+#endif
+STEXI
+@item host_net_redir
+Redirect TCP or UDP connections from host to guest (requires -net user).
+ETEXI
+
+    { "balloon", "i", do_balloon,
+      "target", "request VM to change it's memory allocation (in MB)" },
+STEXI
+@item balloon @var{value}
+Request VM to change its memory allocation to @var{value} (in MB).
+ETEXI
+
+    { "set_link", "ss", do_set_link,
+      "name up|down", "change the link status of a network adapter" },
+STEXI
+@item set_link @var{name} [up|down]
+Set link @var{name} up or down.
+ETEXI
+
+    { "watchdog_action", "s", do_watchdog_action,
+      "[reset|shutdown|poweroff|pause|debug|none]", "change watchdog action" },
+STEXI
+@item watchdog_action
+Change watchdog action.
+ETEXI
+
+    { "acl", "sss?i?", do_acl, "<command> <aclname> [<match> [<index>]]\n",
+                               "acl show vnc.username\n"
+                               "acl policy vnc.username deny\n"
+                               "acl allow vnc.username fred\n"
+                               "acl deny vnc.username bob\n"
+                               "acl reset vnc.username\n" },
+STEXI
+@item acl @var{subcommand} @var{aclname} @var{match} @var{index}
+
+Manage access control lists for network services. There are currently
+two named access control lists, @var{vnc.x509dname} and @var{vnc.username}
+matching on the x509 client certificate distinguished name, and SASL
+username respectively.
+
+@table @option
+@item acl show <aclname>
+list all the match rules in the access control list, and the default
+policy
+@item acl policy <aclname> @code{allow|deny}
+set the default access control list policy, used in the event that
+none of the explicit rules match. The default policy at startup is
+always @code{deny}
+@item acl allow <aclname> <match> [<index>]
+add a match to the access control list, allowing access. The match will
+normally be an exact username or x509 distinguished name, but can
+optionally include wildcard globs. eg @code{*@@EXAMPLE.COM} to allow
+all users in the @code{EXAMPLE.COM} kerberos realm. The match will
+normally be appended to the end of the ACL, but can be inserted
+earlier in the list if the optional @code{index} parameter is supplied.
+@item acl deny <aclname> <match> [<index>]
+add a match to the access control list, denying access. The match will
+normally be an exact username or x509 distinguished name, but can
+optionally include wildcard globs. eg @code{*@@EXAMPLE.COM} to allow
+all users in the @code{EXAMPLE.COM} kerberos realm. The match will
+normally be appended to the end of the ACL, but can be inserted
+earlier in the list if the optional @code{index} parameter is supplied.
+@item acl remove <aclname> <match>
+remove the specified match rule from the access control list.
+@item acl reset <aclname>
+remove all matches from the access control list, and set the default
+policy back to @code{deny}.
+@end table
+ETEXI
+
+STEXI
+@end table
+ETEXI
diff --git a/qemu-option.c b/qemu-option.c
new file mode 100644
index 0000000..646bbad
--- /dev/null
+++ b/qemu-option.c
@@ -0,0 +1,362 @@
+/*
+ * Commandline option parsing functions
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "qemu-common.h"
+#include "qemu-option.h"
+
+/*
+ * Extracts the name of an option from the parameter string (p points at the
+ * first byte of the option name)
+ *
+ * The option name is delimited by delim (usually , or =) or the string end
+ * and is copied into buf. If the option name is longer than buf_size, it is
+ * truncated. buf is always zero terminated.
+ *
+ * The return value is the position of the delimiter/zero byte after the option
+ * name in p.
+ */
+const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
+{
+    char *q;
+
+    q = buf;
+    while (*p != '\0' && *p != delim) {
+        if (q && (q - buf) < buf_size - 1)
+            *q++ = *p;
+        p++;
+    }
+    if (q)
+        *q = '\0';
+
+    return p;
+}
+
+/*
+ * Extracts the value of an option from the parameter string p (p points at the
+ * first byte of the option value)
+ *
+ * This function is comparable to get_opt_name with the difference that the
+ * delimiter is fixed to be comma which starts a new option. To specify an
+ * option value that contains commas, double each comma.
+ */
+const char *get_opt_value(char *buf, int buf_size, const char *p)
+{
+    char *q;
+
+    q = buf;
+    while (*p != '\0') {
+        if (*p == ',') {
+            if (*(p + 1) != ',')
+                break;
+            p++;
+        }
+        if (q && (q - buf) < buf_size - 1)
+            *q++ = *p;
+        p++;
+    }
+    if (q)
+        *q = '\0';
+
+    return p;
+}
+
+/*
+ * Searches an option list for an option with the given name
+ */
+QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
+    const char *name)
+{
+    while (list && list->name) {
+        if (!strcmp(list->name, name)) {
+            return list;
+        }
+        list++;
+    }
+
+    return NULL;
+}
+
+/*
+ * Sets the value of a parameter in a given option list. The parsing of the
+ * value depends on the type of option:
+ *
+ * OPT_FLAG (uses value.n):
+ *      If no value is given, the flag is set to 1.
+ *      Otherwise the value must be "on" (set to 1) or "off" (set to 0)
+ *
+ * OPT_STRING (uses value.s):
+ *      value is strdup()ed and assigned as option value
+ *
+ * OPT_SIZE (uses value.n):
+ *      The value is converted to an integer. Suffixes for kilobytes etc. are
+ *      allowed (powers of 1024).
+ *
+ * Returns 0 on succes, -1 in error cases
+ */
+int set_option_parameter(QEMUOptionParameter *list, const char *name,
+    const char *value)
+{
+    // Find a matching parameter
+    list = get_option_parameter(list, name);
+    if (list == NULL) {
+        fprintf(stderr, "Unknown option '%s'\n", name);
+        return -1;
+    }
+
+    // Process parameter
+    switch (list->type) {
+    case OPT_FLAG:
+        if (value != NULL) {
+            if (!strcmp(value, "on")) {
+                list->value.n = 1;
+            } else if (!strcmp(value, "off")) {
+                list->value.n = 0;
+            } else {
+                fprintf(stderr, "Option '%s': Use 'on' or 'off'\n", name);
+                return -1;
+            }
+        } else {
+            list->value.n = 1;
+        }
+        break;
+
+    case OPT_STRING:
+        if (value != NULL) {
+            list->value.s = strdup(value);
+        } else {
+            fprintf(stderr, "Option '%s' needs a parameter\n", name);
+            return -1;
+        }
+        break;
+
+    case OPT_SIZE:
+        if (value != NULL) {
+            double sizef = strtod(value, (char**) &value);
+
+            switch (*value) {
+            case 'T':
+                sizef *= 1024;
+            case 'G':
+                sizef *= 1024;
+            case 'M':
+                sizef *= 1024;
+            case 'K':
+            case 'k':
+                sizef *= 1024;
+            case 'b':
+            case '\0':
+                list->value.n = (uint64_t) sizef;
+                break;
+            default:
+                fprintf(stderr, "Option '%s' needs size as parameter\n", name);
+                fprintf(stderr, "You may use k, M, G or T suffixes for "
+                    "kilobytes, megabytes, gigabytes and terabytes.\n");
+                return -1;
+            }
+        } else {
+            fprintf(stderr, "Option '%s' needs a parameter\n", name);
+            return -1;
+        }
+        break;
+    default:
+        fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Sets the given parameter to an integer instead of a string.
+ * This function cannot be used to set string options.
+ *
+ * Returns 0 on success, -1 in error cases
+ */
+int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
+    uint64_t value)
+{
+    // Find a matching parameter
+    list = get_option_parameter(list, name);
+    if (list == NULL) {
+        fprintf(stderr, "Unknown option '%s'\n", name);
+        return -1;
+    }
+
+    // Process parameter
+    switch (list->type) {
+    case OPT_FLAG:
+    case OPT_NUMBER:
+    case OPT_SIZE:
+        list->value.n = value;
+        break;
+
+    default:
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Frees a option list. If it contains strings, the strings are freed as well.
+ */
+void free_option_parameters(QEMUOptionParameter *list)
+{
+    QEMUOptionParameter *cur = list;
+
+    while (cur && cur->name) {
+        if (cur->type == OPT_STRING) {
+            free(cur->value.s);
+        }
+        cur++;
+    }
+
+    free(list);
+}
+
+/*
+ * Parses a parameter string (param) into an option list (dest).
+ *
+ * list is the templace is. If dest is NULL, a new copy of list is created for
+ * it. If list is NULL, this function fails.
+ *
+ * A parameter string consists of one or more parameters, separated by commas.
+ * Each parameter consists of its name and possibly of a value. In the latter
+ * case, the value is delimited by an = character. To specify a value which
+ * contains commas, double each comma so it won't be recognized as the end of
+ * the parameter.
+ *
+ * For more details of the parsing see above.
+ *
+ * Returns a pointer to the first element of dest (or the newly allocated copy)
+ * or NULL in error cases
+ */
+QEMUOptionParameter *parse_option_parameters(const char *param,
+    QEMUOptionParameter *list, QEMUOptionParameter *dest)
+{
+    QEMUOptionParameter *cur;
+    QEMUOptionParameter *allocated = NULL;
+    char name[256];
+    char value[256];
+    char *param_delim, *value_delim;
+    char next_delim;
+    size_t num_options;
+
+    if (list == NULL) {
+        return NULL;
+    }
+
+    if (dest == NULL) {
+        // Count valid options
+        num_options = 0;
+        cur = list;
+        while (cur->name) {
+            num_options++;
+            cur++;
+        }
+
+        // Create a copy of the option list to fill in values
+        dest = qemu_mallocz((num_options + 1) * sizeof(QEMUOptionParameter));
+        allocated = dest;
+        memcpy(dest, list, (num_options + 1) * sizeof(QEMUOptionParameter));
+    }
+
+    while (*param) {
+
+        // Find parameter name and value in the string
+        param_delim = strchr(param, ',');
+        value_delim = strchr(param, '=');
+
+        if (value_delim && (value_delim < param_delim || !param_delim)) {
+            next_delim = '=';
+        } else {
+            next_delim = ',';
+            value_delim = NULL;
+        }
+
+        param = get_opt_name(name, sizeof(name), param, next_delim);
+        if (value_delim) {
+            param = get_opt_value(value, sizeof(value), param + 1);
+        }
+        if (*param != '\0') {
+            param++;
+        }
+
+        // Set the parameter
+        if (set_option_parameter(dest, name, value_delim ? value : NULL)) {
+            goto fail;
+        }
+    }
+
+    return dest;
+
+fail:
+    // Only free the list if it was newly allocated
+    free_option_parameters(allocated);
+    return NULL;
+}
+
+/*
+ * Prints all options of a list that have a value to stdout
+ */
+void print_option_parameters(QEMUOptionParameter *list)
+{
+    while (list && list->name) {
+        switch (list->type) {
+            case OPT_STRING:
+                 if (list->value.s != NULL) {
+                     printf("%s='%s' ", list->name, list->value.s);
+                 }
+                break;
+            case OPT_FLAG:
+                printf("%s=%s ", list->name, list->value.n ? "on" : "off");
+                break;
+            case OPT_SIZE:
+            case OPT_NUMBER:
+                printf("%s=%" PRId64 " ", list->name, list->value.n);
+                break;
+            default:
+                printf("%s=(unkown type) ", list->name);
+                break;
+        }
+        list++;
+    }
+}
+
+/*
+ * Prints an overview of all available options
+ */
+void print_option_help(QEMUOptionParameter *list)
+{
+    printf("Supported options:\n");
+    while (list && list->name) {
+        printf("%-16s %s\n", list->name,
+            list->help ? list->help : "No description available");
+        list++;
+    }
+}
diff --git a/qemu-option.h b/qemu-option.h
new file mode 100644
index 0000000..059c0a4
--- /dev/null
+++ b/qemu-option.h
@@ -0,0 +1,69 @@
+/*
+ * Commandline option parsing functions
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_OPTIONS_H
+#define QEMU_OPTIONS_H
+
+enum QEMUOptionParType {
+    OPT_FLAG,
+    OPT_NUMBER,
+    OPT_SIZE,
+    OPT_STRING,
+};
+
+typedef struct QEMUOptionParameter {
+    const char *name;
+    enum QEMUOptionParType type;
+    union {
+        uint64_t n;
+        char* s;
+    } value;
+    const char *help;
+} QEMUOptionParameter;
+
+
+const char *get_opt_name(char *buf, int buf_size, const char *p, char delim);
+const char *get_opt_value(char *buf, int buf_size, const char *p);
+
+
+/*
+ * The following functions take a parameter list as input. This is a pointer to
+ * the first element of a QEMUOptionParameter array which is terminated by an
+ * entry with entry->name == NULL.
+ */
+
+QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
+    const char *name);
+int set_option_parameter(QEMUOptionParameter *list, const char *name,
+    const char *value);
+int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
+    uint64_t value);
+QEMUOptionParameter *parse_option_parameters(const char *param,
+    QEMUOptionParameter *list, QEMUOptionParameter *dest);
+void free_option_parameters(QEMUOptionParameter *list);
+void print_option_parameters(QEMUOptionParameter *list);
+void print_option_help(QEMUOptionParameter *list);
+
+#endif
diff --git a/qemu-options.hx b/qemu-options.hx
new file mode 100644
index 0000000..0864e2d
--- /dev/null
+++ b/qemu-options.hx
@@ -0,0 +1,1606 @@
+HXCOMM Use DEFHEADING() to define headings in both help text and texi
+HXCOMM Text between STEXI and ETEXI are copied to texi version and
+HXCOMM discarded from C version
+HXCOMM DEF(option, HAS_ARG/0, opt_enum, opt_help) is used to construct
+HXCOMM option structures, enums and help message.
+HXCOMM HXCOMM can be used for comments, discarded from both texi and C
+
+DEFHEADING(Standard options:)
+STEXI
+@table @option
+ETEXI
+
+DEF("help", 0, QEMU_OPTION_h,
+    "-h or -help     display this help and exit\n")
+STEXI
+@item -h
+Display help and exit
+ETEXI
+
+DEF("version", 0, QEMU_OPTION_version,
+    "-version        display version information and exit\n")
+STEXI
+@item -version
+Display version information and exit
+ETEXI
+
+DEF("M", HAS_ARG, QEMU_OPTION_M,
+    "-M machine      select emulated machine (-M ? for list)\n")
+STEXI
+@item -M @var{machine}
+Select the emulated @var{machine} (@code{-M ?} for list)
+ETEXI
+
+DEF("cpu", HAS_ARG, QEMU_OPTION_cpu,
+    "-cpu cpu        select CPU (-cpu ? for list)\n")
+STEXI
+@item -cpu @var{model}
+Select CPU model (-cpu ? for list and additional feature selection)
+ETEXI
+
+DEF("smp", HAS_ARG, QEMU_OPTION_smp,
+    "-smp n          set the number of CPUs to 'n' [default=1]\n")
+STEXI
+@item -smp @var{n}
+Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255
+CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs
+to 4.
+ETEXI
+
+DEF("numa", HAS_ARG, QEMU_OPTION_numa,
+    "-numa node[,mem=size][,cpus=cpu[-cpu]][,nodeid=node]\n")
+STEXI
+@item -numa @var{opts}
+Simulate a multi node NUMA system. If mem and cpus are omitted, resources
+are split equally.
+ETEXI
+
+DEF("fda", HAS_ARG, QEMU_OPTION_fda,
+    "-fda/-fdb file  use 'file' as floppy disk 0/1 image\n")
+DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "")
+STEXI
+@item -fda @var{file}
+@item -fdb @var{file}
+Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can
+use the host floppy by using @file{/dev/fd0} as filename (@pxref{host_drives}).
+ETEXI
+
+DEF("hda", HAS_ARG, QEMU_OPTION_hda,
+    "-hda/-hdb file  use 'file' as IDE hard disk 0/1 image\n")
+DEF("hdb", HAS_ARG, QEMU_OPTION_hdb, "")
+DEF("hdc", HAS_ARG, QEMU_OPTION_hdc,
+    "-hdc/-hdd file  use 'file' as IDE hard disk 2/3 image\n")
+DEF("hdd", HAS_ARG, QEMU_OPTION_hdd, "")
+STEXI
+@item -hda @var{file}
+@item -hdb @var{file}
+@item -hdc @var{file}
+@item -hdd @var{file}
+Use @var{file} as hard disk 0, 1, 2 or 3 image (@pxref{disk_images}).
+ETEXI
+
+DEF("cdrom", HAS_ARG, QEMU_OPTION_cdrom,
+    "-cdrom file     use 'file' as IDE cdrom image (cdrom is ide1 master)\n")
+STEXI
+@item -cdrom @var{file}
+Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and
+@option{-cdrom} at the same time). You can use the host CD-ROM by
+using @file{/dev/cdrom} as filename (@pxref{host_drives}).
+ETEXI
+
+DEF("drive", HAS_ARG, QEMU_OPTION_drive,
+    "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
+    "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
+    "       [,cache=writethrough|writeback|none][,format=f][,serial=s]\n"
+    "                use 'file' as a drive image\n")
+STEXI
+@item -drive @var{option}[,@var{option}[,@var{option}[,...]]]
+
+Define a new drive. Valid options are:
+
+@table @code
+@item file=@var{file}
+This option defines which disk image (@pxref{disk_images}) to use with
+this drive. If the filename contains comma, you must double it
+(for instance, "file=my,,file" to use file "my,file").
+@item if=@var{interface}
+This option defines on which type on interface the drive is connected.
+Available types are: ide, scsi, sd, mtd, floppy, pflash, virtio.
+@item bus=@var{bus},unit=@var{unit}
+These options define where is connected the drive by defining the bus number and
+the unit id.
+@item index=@var{index}
+This option defines where is connected the drive by using an index in the list
+of available connectors of a given interface type.
+@item media=@var{media}
+This option defines the type of the media: disk or cdrom.
+@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
+These options have the same definition as they have in @option{-hdachs}.
+@item snapshot=@var{snapshot}
+@var{snapshot} is "on" or "off" and allows to enable snapshot for given drive (see @option{-snapshot}).
+@item cache=@var{cache}
+@var{cache} is "none", "writeback", or "writethrough" and controls how the host cache is used to access block data.
+@item format=@var{format}
+Specify which disk @var{format} will be used rather than detecting
+the format.  Can be used to specifiy format=raw to avoid interpreting
+an untrusted format header.
+@item serial=@var{serial}
+This option specifies the serial number to assign to the device.
+@end table
+
+By default, writethrough caching is used for all block device.  This means that
+the host page cache will be used to read and write data but write notification
+will be sent to the guest only when the data has been reported as written by
+the storage subsystem.
+
+Writeback caching will report data writes as completed as soon as the data is
+present in the host page cache.  This is safe as long as you trust your host.
+If your host crashes or loses power, then the guest may experience data
+corruption.  When using the @option{-snapshot} option, writeback caching is
+used by default.
+
+The host page cache can be avoided entirely with @option{cache=none}.  This will
+attempt to do disk IO directly to the guests memory.  QEMU may still perform
+an internal copy of the data.
+
+Some block drivers perform badly with @option{cache=writethrough}, most notably,
+qcow2.  If performance is more important than correctness,
+@option{cache=writeback} should be used with qcow2.  By default, if no explicit
+caching is specified for a qcow2 disk image, @option{cache=writeback} will be
+used.  For all other disk types, @option{cache=writethrough} is the default.
+
+Instead of @option{-cdrom} you can use:
+@example
+qemu -drive file=file,index=2,media=cdrom
+@end example
+
+Instead of @option{-hda}, @option{-hdb}, @option{-hdc}, @option{-hdd}, you can
+use:
+@example
+qemu -drive file=file,index=0,media=disk
+qemu -drive file=file,index=1,media=disk
+qemu -drive file=file,index=2,media=disk
+qemu -drive file=file,index=3,media=disk
+@end example
+
+You can connect a CDROM to the slave of ide0:
+@example
+qemu -drive file=file,if=ide,index=1,media=cdrom
+@end example
+
+If you don't specify the "file=" argument, you define an empty drive:
+@example
+qemu -drive if=ide,index=1,media=cdrom
+@end example
+
+You can connect a SCSI disk with unit ID 6 on the bus #0:
+@example
+qemu -drive file=file,if=scsi,bus=0,unit=6
+@end example
+
+Instead of @option{-fda}, @option{-fdb}, you can use:
+@example
+qemu -drive file=file,index=0,if=floppy
+qemu -drive file=file,index=1,if=floppy
+@end example
+
+By default, @var{interface} is "ide" and @var{index} is automatically
+incremented:
+@example
+qemu -drive file=a -drive file=b"
+@end example
+is interpreted like:
+@example
+qemu -hda a -hdb b
+@end example
+ETEXI
+
+DEF("mtdblock", HAS_ARG, QEMU_OPTION_mtdblock,
+    "-mtdblock file  use 'file' as on-board Flash memory image\n")
+STEXI
+
+@item -mtdblock file
+Use 'file' as on-board Flash memory image.
+ETEXI
+
+DEF("sd", HAS_ARG, QEMU_OPTION_sd,
+    "-sd file        use 'file' as SecureDigital card image\n")
+STEXI
+@item -sd file
+Use 'file' as SecureDigital card image.
+ETEXI
+
+DEF("pflash", HAS_ARG, QEMU_OPTION_pflash,
+    "-pflash file    use 'file' as a parallel flash image\n")
+STEXI
+@item -pflash file
+Use 'file' as a parallel flash image.
+ETEXI
+
+DEF("boot", HAS_ARG, QEMU_OPTION_boot,
+    "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n")
+STEXI
+@item -boot [a|c|d|n]
+Boot on floppy (a), hard disk (c), CD-ROM (d), or Etherboot (n). Hard disk boot
+is the default.
+ETEXI
+
+DEF("snapshot", 0, QEMU_OPTION_snapshot,
+    "-snapshot       write to temporary files instead of disk image files\n")
+STEXI
+@item -snapshot
+Write to temporary files instead of disk image files. In this case,
+the raw disk image you use is not written back. You can however force
+the write back by pressing @key{C-a s} (@pxref{disk_images}).
+ETEXI
+
+DEF("m", HAS_ARG, QEMU_OPTION_m,
+    "-m megs         set virtual RAM size to megs MB [default=%d]\n")
+STEXI
+@item -m @var{megs}
+Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB.  Optionally,
+a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or
+gigabytes respectively.
+ETEXI
+
+DEF("k", HAS_ARG, QEMU_OPTION_k,
+    "-k language     use keyboard layout (for example 'fr' for French)\n")
+STEXI
+@item -k @var{language}
+
+Use keyboard layout @var{language} (for example @code{fr} for
+French). This option is only needed where it is not easy to get raw PC
+keycodes (e.g. on Macs, with some X11 servers or with a VNC
+display). You don't normally need to use it on PC/Linux or PC/Windows
+hosts.
+
+The available layouts are:
+@example
+ar  de-ch  es  fo     fr-ca  hu  ja  mk     no  pt-br  sv
+da  en-gb  et  fr     fr-ch  is  lt  nl     pl  ru     th
+de  en-us  fi  fr-be  hr     it  lv  nl-be  pt  sl     tr
+@end example
+
+The default is @code{en-us}.
+ETEXI
+
+
+#ifdef HAS_AUDIO
+DEF("audio-help", 0, QEMU_OPTION_audio_help,
+    "-audio-help     print list of audio drivers and their options\n")
+#endif
+STEXI
+@item -audio-help
+
+Will show the audio subsystem help: list of drivers, tunable
+parameters.
+ETEXI
+
+#ifdef HAS_AUDIO
+DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw,
+    "-soundhw c1,... enable audio support\n"
+    "                and only specified sound cards (comma separated list)\n"
+    "                use -soundhw ? to get the list of supported cards\n"
+    "                use -soundhw all to enable all of them\n")
+#endif
+STEXI
+@item -soundhw @var{card1}[,@var{card2},...] or -soundhw all
+
+Enable audio and selected sound hardware. Use ? to print all
+available sound hardware.
+
+@example
+qemu -soundhw sb16,adlib disk.img
+qemu -soundhw es1370 disk.img
+qemu -soundhw ac97 disk.img
+qemu -soundhw all disk.img
+qemu -soundhw ?
+@end example
+
+Note that Linux's i810_audio OSS kernel (for AC97) module might
+require manually specifying clocking.
+
+@example
+modprobe i810_audio clocking=48000
+@end example
+ETEXI
+
+STEXI
+@end table
+ETEXI
+
+DEF("usb", 0, QEMU_OPTION_usb,
+    "-usb            enable the USB driver (will be the default soon)\n")
+STEXI
+USB options:
+@table @option
+
+@item -usb
+Enable the USB driver (will be the default soon)
+ETEXI
+
+DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice,
+    "-usbdevice name add the host or guest USB device 'name'\n")
+STEXI
+
+@item -usbdevice @var{devname}
+Add the USB device @var{devname}. @xref{usb_devices}.
+
+@table @code
+
+@item mouse
+Virtual Mouse. This will override the PS/2 mouse emulation when activated.
+
+@item tablet
+Pointer device that uses absolute coordinates (like a touchscreen). This
+means qemu is able to report the mouse position without having to grab the
+mouse. Also overrides the PS/2 mouse emulation when activated.
+
+@item disk:[format=@var{format}]:file
+Mass storage device based on file. The optional @var{format} argument
+will be used rather than detecting the format. Can be used to specifiy
+format=raw to avoid interpreting an untrusted format header.
+
+@item host:bus.addr
+Pass through the host device identified by bus.addr (Linux only).
+
+@item host:vendor_id:product_id
+Pass through the host device identified by vendor_id:product_id (Linux only).
+
+@item serial:[vendorid=@var{vendor_id}][,productid=@var{product_id}]:@var{dev}
+Serial converter to host character device @var{dev}, see @code{-serial} for the
+available devices.
+
+@item braille
+Braille device.  This will use BrlAPI to display the braille output on a real
+or fake device.
+
+@item net:options
+Network adapter that supports CDC ethernet and RNDIS protocols.
+
+@end table
+ETEXI
+
+DEF("name", HAS_ARG, QEMU_OPTION_name,
+    "-name string    set the name of the guest\n")
+STEXI
+@item -name @var{name}
+Sets the @var{name} of the guest.
+This name will be displayed in the SDL window caption.
+The @var{name} will also be used for the VNC server.
+ETEXI
+
+DEF("uuid", HAS_ARG, QEMU_OPTION_uuid,
+    "-uuid %%08x-%%04x-%%04x-%%04x-%%012x\n"
+    "                specify machine UUID\n")
+STEXI
+@item -uuid @var{uuid}
+Set system UUID.
+ETEXI
+
+STEXI
+@end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(Display options:)
+
+STEXI
+@table @option
+ETEXI
+
+DEF("nographic", 0, QEMU_OPTION_nographic,
+    "-nographic      disable graphical output and redirect serial I/Os to console\n")
+STEXI
+@item -nographic
+
+Normally, QEMU uses SDL to display the VGA output. With this option,
+you can totally disable graphical output so that QEMU is a simple
+command line application. The emulated serial port is redirected on
+the console. Therefore, you can still use QEMU to debug a Linux kernel
+with a serial console.
+ETEXI
+
+#ifdef CONFIG_CURSES
+DEF("curses", 0, QEMU_OPTION_curses,
+    "-curses         use a curses/ncurses interface instead of SDL\n")
+#endif
+STEXI
+@item -curses
+
+Normally, QEMU uses SDL to display the VGA output.  With this option,
+QEMU can display the VGA output when in text mode using a
+curses/ncurses interface.  Nothing is displayed in graphical mode.
+ETEXI
+
+#ifdef CONFIG_SDL
+DEF("no-frame", 0, QEMU_OPTION_no_frame,
+    "-no-frame       open SDL window without a frame and window decorations\n")
+#endif
+STEXI
+@item -no-frame
+
+Do not use decorations for SDL windows and start them using the whole
+available screen space. This makes the using QEMU in a dedicated desktop
+workspace more convenient.
+ETEXI
+
+#ifdef CONFIG_SDL
+DEF("alt-grab", 0, QEMU_OPTION_alt_grab,
+    "-alt-grab       use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n")
+#endif
+STEXI
+@item -alt-grab
+
+Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt).
+ETEXI
+
+#ifdef CONFIG_SDL
+DEF("no-quit", 0, QEMU_OPTION_no_quit,
+    "-no-quit        disable SDL window close capability\n")
+#endif
+STEXI
+@item -no-quit
+
+Disable SDL window close capability.
+ETEXI
+
+#ifdef CONFIG_SDL
+DEF("sdl", 0, QEMU_OPTION_sdl,
+    "-sdl            enable SDL\n")
+#endif
+STEXI
+@item -sdl
+
+Enable SDL.
+ETEXI
+
+DEF("portrait", 0, QEMU_OPTION_portrait,
+    "-portrait       rotate graphical output 90 deg left (only PXA LCD)\n")
+STEXI
+@item -portrait
+
+Rotate graphical output 90 deg left (only PXA LCD).
+ETEXI
+
+DEF("vga", HAS_ARG, QEMU_OPTION_vga,
+    "-vga [std|cirrus|vmware|xenfb|none]\n"
+    "                select video card type\n")
+STEXI
+@item -vga @var{type}
+Select type of VGA card to emulate. Valid values for @var{type} are
+@table @code
+@item cirrus
+Cirrus Logic GD5446 Video card. All Windows versions starting from
+Windows 95 should recognize and use this graphic card. For optimal
+performances, use 16 bit color depth in the guest and the host OS.
+(This one is the default)
+@item std
+Standard VGA card with Bochs VBE extensions.  If your guest OS
+supports the VESA 2.0 VBE extensions (e.g. Windows XP) and if you want
+to use high resolution modes (>= 1280x1024x16) then you should use
+this option.
+@item vmware
+VMWare SVGA-II compatible adapter. Use it if you have sufficiently
+recent XFree86/XOrg server or Windows guest with a driver for this
+card.
+@item none
+Disable VGA card.
+@end table
+ETEXI
+
+DEF("full-screen", 0, QEMU_OPTION_full_screen,
+    "-full-screen    start in full screen\n")
+STEXI
+@item -full-screen
+Start in full screen.
+ETEXI
+
+#if defined(TARGET_PPC) || defined(TARGET_SPARC)
+DEF("g", 1, QEMU_OPTION_g ,
+    "-g WxH[xDEPTH]  Set the initial graphical resolution and depth\n")
+#endif
+STEXI
+ETEXI
+
+DEF("vnc", HAS_ARG, QEMU_OPTION_vnc ,
+    "-vnc display    start a VNC server on display\n")
+STEXI
+@item -vnc @var{display}[,@var{option}[,@var{option}[,...]]]
+
+Normally, QEMU uses SDL to display the VGA output.  With this option,
+you can have QEMU listen on VNC display @var{display} and redirect the VGA
+display over the VNC session.  It is very useful to enable the usb
+tablet device when using this option (option @option{-usbdevice
+tablet}). When using the VNC display, you must use the @option{-k}
+parameter to set the keyboard layout if you are not using en-us. Valid
+syntax for the @var{display} is
+
+@table @code
+
+@item @var{host}:@var{d}
+
+TCP connections will only be allowed from @var{host} on display @var{d}.
+By convention the TCP port is 5900+@var{d}. Optionally, @var{host} can
+be omitted in which case the server will accept connections from any host.
+
+@item @code{unix}:@var{path}
+
+Connections will be allowed over UNIX domain sockets where @var{path} is the
+location of a unix socket to listen for connections on.
+
+@item none
+
+VNC is initialized but not started. The monitor @code{change} command
+can be used to later start the VNC server.
+
+@end table
+
+Following the @var{display} value there may be one or more @var{option} flags
+separated by commas. Valid options are
+
+@table @code
+
+@item reverse
+
+Connect to a listening VNC client via a ``reverse'' connection. The
+client is specified by the @var{display}. For reverse network
+connections (@var{host}:@var{d},@code{reverse}), the @var{d} argument
+is a TCP port number, not a display number.
+
+@item password
+
+Require that password based authentication is used for client connections.
+The password must be set separately using the @code{change} command in the
+@ref{pcsys_monitor}
+
+@item tls
+
+Require that client use TLS when communicating with the VNC server. This
+uses anonymous TLS credentials so is susceptible to a man-in-the-middle
+attack. It is recommended that this option be combined with either the
+@var{x509} or @var{x509verify} options.
+
+@item x509=@var{/path/to/certificate/dir}
+
+Valid if @option{tls} is specified. Require that x509 credentials are used
+for negotiating the TLS session. The server will send its x509 certificate
+to the client. It is recommended that a password be set on the VNC server
+to provide authentication of the client when this is used. The path following
+this option specifies where the x509 certificates are to be loaded from.
+See the @ref{vnc_security} section for details on generating certificates.
+
+@item x509verify=@var{/path/to/certificate/dir}
+
+Valid if @option{tls} is specified. Require that x509 credentials are used
+for negotiating the TLS session. The server will send its x509 certificate
+to the client, and request that the client send its own x509 certificate.
+The server will validate the client's certificate against the CA certificate,
+and reject clients when validation fails. If the certificate authority is
+trusted, this is a sufficient authentication mechanism. You may still wish
+to set a password on the VNC server as a second authentication layer. The
+path following this option specifies where the x509 certificates are to
+be loaded from. See the @ref{vnc_security} section for details on generating
+certificates.
+
+@item sasl
+
+Require that the client use SASL to authenticate with the VNC server.
+The exact choice of authentication method used is controlled from the
+system / user's SASL configuration file for the 'qemu' service. This
+is typically found in /etc/sasl2/qemu.conf. If running QEMU as an
+unprivileged user, an environment variable SASL_CONF_PATH can be used
+to make it search alternate locations for the service config.
+While some SASL auth methods can also provide data encryption (eg GSSAPI),
+it is recommended that SASL always be combined with the 'tls' and
+'x509' settings to enable use of SSL and server certificates. This
+ensures a data encryption preventing compromise of authentication
+credentials. See the @ref{vnc_security} section for details on using
+SASL authentication.
+
+@item acl
+
+Turn on access control lists for checking of the x509 client certificate
+and SASL party. For x509 certs, the ACL check is made against the
+certificate's distinguished name. This is something that looks like
+@code{C=GB,O=ACME,L=Boston,CN=bob}. For SASL party, the ACL check is
+made against the username, which depending on the SASL plugin, may
+include a realm component, eg @code{bob} or @code{bob@@EXAMPLE.COM}.
+When the @option{acl} flag is set, the initial access list will be
+empty, with a @code{deny} policy. Thus no one will be allowed to
+use the VNC server until the ACLs have been loaded. This can be
+achieved using the @code{acl} monitor command.
+
+@end table
+ETEXI
+
+STEXI
+@end table
+ETEXI
+
+DEFHEADING()
+
+#ifdef TARGET_I386
+DEFHEADING(i386 target only:)
+#endif
+STEXI
+@table @option
+ETEXI
+
+#ifdef TARGET_I386
+DEF("win2k-hack", 0, QEMU_OPTION_win2k_hack,
+    "-win2k-hack     use it when installing Windows 2000 to avoid a disk full bug\n")
+#endif
+STEXI
+@item -win2k-hack
+Use it when installing Windows 2000 to avoid a disk full bug. After
+Windows 2000 is installed, you no longer need this option (this option
+slows down the IDE transfers).
+ETEXI
+
+#ifdef TARGET_I386
+DEF("rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack,
+    "-rtc-td-hack    use it to fix time drift in Windows ACPI HAL\n")
+#endif
+STEXI
+@item -rtc-td-hack
+Use it if you experience time drift problem in Windows with ACPI HAL.
+This option will try to figure out how many timer interrupts were not
+processed by the Windows guest and will re-inject them.
+ETEXI
+
+#ifdef TARGET_I386
+DEF("no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk,
+    "-no-fd-bootchk  disable boot signature checking for floppy disks\n")
+#endif
+STEXI
+@item -no-fd-bootchk
+Disable boot signature checking for floppy disks in Bochs BIOS. It may
+be needed to boot from old floppy disks.
+ETEXI
+
+#ifdef TARGET_I386
+DEF("no-acpi", 0, QEMU_OPTION_no_acpi,
+           "-no-acpi        disable ACPI\n")
+#endif
+STEXI
+@item -no-acpi
+Disable ACPI (Advanced Configuration and Power Interface) support. Use
+it if your guest OS complains about ACPI problems (PC target machine
+only).
+ETEXI
+
+#ifdef TARGET_I386
+DEF("no-hpet", 0, QEMU_OPTION_no_hpet,
+    "-no-hpet        disable HPET\n")
+#endif
+STEXI
+@item -no-hpet
+Disable HPET support.
+ETEXI
+
+#ifdef TARGET_I386
+DEF("no-virtio-balloon", 0, QEMU_OPTION_no_virtio_balloon,
+    "-no-virtio-balloon disable virtio balloon device\n")
+#endif
+STEXI
+@item -no-virtio-balloon
+Disable virtio-balloon device.
+ETEXI
+
+#ifdef TARGET_I386
+DEF("acpitable", HAS_ARG, QEMU_OPTION_acpitable,
+    "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...]\n"
+    "                ACPI table description\n")
+#endif
+STEXI
+@item -acpitable [sig=@var{str}][,rev=@var{n}][,oem_id=@var{str}][,oem_table_id=@var{str}][,oem_rev=@var{n}] [,asl_compiler_id=@var{str}][,asl_compiler_rev=@var{n}][,data=@var{file1}[:@var{file2}]...]
+Add ACPI table with specified header fields and context from specified files.
+ETEXI
+
+#ifdef TARGET_I386
+DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
+    "-smbios file=binary\n"
+    "                Load SMBIOS entry from binary file\n"
+    "-smbios type=0[,vendor=str][,version=str][,date=str][,release=%%d.%%d]\n"
+    "                Specify SMBIOS type 0 fields\n"
+    "-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str]\n"
+    "              [,uuid=uuid][,sku=str][,family=str]\n"
+    "                Specify SMBIOS type 1 fields\n")
+#endif
+STEXI
+@item -smbios file=@var{binary}
+Load SMBIOS entry from binary file.
+
+@item -smbios type=0[,vendor=@var{str}][,version=@var{str}][,date=@var{str}][,release=@var{%d.%d}]
+Specify SMBIOS type 0 fields
+
+@item -smbios type=1[,manufacturer=@var{str}][,product=@var{str}][,version=@var{str}][,serial=@var{str}][,uuid=@var{uuid}][,sku=@var{str}][,family=@var{str}]
+Specify SMBIOS type 1 fields
+ETEXI
+
+#ifdef TARGET_I386
+DEFHEADING()
+#endif
+STEXI
+@end table
+ETEXI
+
+DEFHEADING(Network options:)
+STEXI
+@table @option
+ETEXI
+
+DEF("net", HAS_ARG, QEMU_OPTION_net,
+    "-net nic[,vlan=n][,macaddr=addr][,model=type][,name=str]\n"
+    "                create a new Network Interface Card and connect it to VLAN 'n'\n"
+#ifdef CONFIG_SLIRP
+    "-net user[,vlan=n][,name=str][,hostname=host]\n"
+    "                connect the user mode network stack to VLAN 'n' and send\n"
+    "                hostname 'host' to DHCP clients\n"
+#endif
+#ifdef _WIN32
+    "-net tap[,vlan=n][,name=str],ifname=name\n"
+    "                connect the host TAP network interface to VLAN 'n'\n"
+#else
+    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile]\n"
+    "                connect the host TAP network interface to VLAN 'n' and use the\n"
+    "                network scripts 'file' (default=%s)\n"
+    "                and 'dfile' (default=%s);\n"
+    "                use '[down]script=no' to disable script execution;\n"
+    "                use 'fd=h' to connect to an already opened TAP interface\n"
+#endif
+    "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
+    "                connect the vlan 'n' to another VLAN using a socket connection\n"
+    "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n"
+    "                connect the vlan 'n' to multicast maddr and port\n"
+#ifdef CONFIG_VDE
+    "-net vde[,vlan=n][,name=str][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n"
+    "                connect the vlan 'n' to port 'n' of a vde switch running\n"
+    "                on host and listening for incoming connections on 'socketpath'.\n"
+    "                Use group 'groupname' and mode 'octalmode' to change default\n"
+    "                ownership and permissions for communication port.\n"
+#endif
+    "-net dump[,vlan=n][,file=f][,len=n]\n"
+    "                dump traffic on vlan 'n' to file 'f' (max n bytes per packet)\n"
+    "-net none       use it alone to have zero network devices; if no -net option\n"
+    "                is provided, the default is '-net nic -net user'\n")
+STEXI
+@item -net nic[,vlan=@var{n}][,macaddr=@var{addr}][,model=@var{type}][,name=@var{name}]
+Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
+= 0 is the default). The NIC is an ne2k_pci by default on the PC
+target. Optionally, the MAC address can be changed to @var{addr}
+and a @var{name} can be assigned for use in monitor commands. If no
+@option{-net} option is specified, a single NIC is created.
+Qemu can emulate several different models of network card.
+Valid values for @var{type} are
+@code{i82551}, @code{i82557b}, @code{i82559er},
+@code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139},
+@code{e1000}, @code{smc91c111}, @code{lance} and @code{mcf_fec}.
+Not all devices are supported on all targets.  Use -net nic,model=?
+for a list of available devices for your target.
+
+@item -net user[,vlan=@var{n}][,hostname=@var{name}][,name=@var{name}]
+Use the user mode network stack which requires no administrator
+privilege to run.  @option{hostname=name} can be used to specify the client
+hostname reported by the builtin DHCP server.
+
+@item -net channel,@var{port}:@var{dev}
+Forward @option{user} TCP connection to port @var{port} to character device @var{dev}
+
+@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}]
+Connect the host TAP network interface @var{name} to VLAN @var{n}, use
+the network script @var{file} to configure it and the network script
+@var{dfile} to deconfigure it. If @var{name} is not provided, the OS
+automatically provides one. @option{fd}=@var{h} can be used to specify
+the handle of an already opened host TAP interface. The default network
+configure script is @file{/etc/qemu-ifup} and the default network
+deconfigure script is @file{/etc/qemu-ifdown}. Use @option{script=no}
+or @option{downscript=no} to disable script execution. Example:
+
+@example
+qemu linux.img -net nic -net tap
+@end example
+
+More complicated example (two NICs, each one connected to a TAP device)
+@example
+qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
+               -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
+@end example
+
+@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
+
+Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
+machine using a TCP socket connection. If @option{listen} is
+specified, QEMU waits for incoming connections on @var{port}
+(@var{host} is optional). @option{connect} is used to connect to
+another QEMU instance using the @option{listen} option. @option{fd}=@var{h}
+specifies an already opened TCP socket.
+
+Example:
+@example
+# launch a first QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+               -net socket,listen=:1234
+# connect the VLAN 0 of this instance to the VLAN 0
+# of the first instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
+               -net socket,connect=127.0.0.1:1234
+@end example
+
+@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}]
+
+Create a VLAN @var{n} shared with another QEMU virtual
+machines using a UDP multicast socket, effectively making a bus for
+every QEMU with same multicast address @var{maddr} and @var{port}.
+NOTES:
+@enumerate
+@item
+Several QEMU can be running on different hosts and share same bus (assuming
+correct multicast setup for these hosts).
+@item
+mcast support is compatible with User Mode Linux (argument @option{eth@var{N}=mcast}), see
+@url{http://user-mode-linux.sf.net}.
+@item
+Use @option{fd=h} to specify an already opened UDP multicast socket.
+@end enumerate
+
+Example:
+@example
+# launch one QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+               -net socket,mcast=230.0.0.1:1234
+# launch another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
+               -net socket,mcast=230.0.0.1:1234
+# launch yet another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:58 \
+               -net socket,mcast=230.0.0.1:1234
+@end example
+
+Example (User Mode Linux compat.):
+@example
+# launch QEMU instance (note mcast address selected
+# is UML's default)
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
+               -net socket,mcast=239.192.168.1:1102
+# launch UML
+/path/to/linux ubd0=/path/to/root_fs eth0=mcast
+@end example
+
+@item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}][,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
+Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and
+listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}
+and MODE @var{octalmode} to change default ownership and permissions for
+communication port. This option is available only if QEMU has been compiled
+with vde support enabled.
+
+Example:
+@example
+# launch vde switch
+vde_switch -F -sock /tmp/myswitch
+# launch QEMU instance
+qemu linux.img -net nic -net vde,sock=/tmp/myswitch
+@end example
+
+@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
+Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
+At most @var{len} bytes (64k by default) per packet are stored. The file format is
+libpcap, so it can be analyzed with tools such as tcpdump or Wireshark.
+
+@item -net none
+Indicate that no network devices should be configured. It is used to
+override the default configuration (@option{-net nic -net user}) which
+is activated if no @option{-net} options are provided.
+ETEXI
+
+#ifdef CONFIG_SLIRP
+DEF("tftp", HAS_ARG, QEMU_OPTION_tftp, \
+    "-tftp dir       allow tftp access to files in dir [-net user]\n")
+#endif
+STEXI
+@item -tftp @var{dir}
+When using the user mode network stack, activate a built-in TFTP
+server. The files in @var{dir} will be exposed as the root of a TFTP server.
+The TFTP client on the guest must be configured in binary mode (use the command
+@code{bin} of the Unix TFTP client). The host IP address on the guest is as
+usual 10.0.2.2.
+ETEXI
+
+#ifdef CONFIG_SLIRP
+DEF("bootp", HAS_ARG, QEMU_OPTION_bootp, \
+    "-bootp file     advertise file in BOOTP replies\n")
+#endif
+STEXI
+@item -bootp @var{file}
+When using the user mode network stack, broadcast @var{file} as the BOOTP
+filename.  In conjunction with @option{-tftp}, this can be used to network boot
+a guest from a local directory.
+
+Example (using pxelinux):
+@example
+qemu -hda linux.img -boot n -tftp /path/to/tftp/files -bootp /pxelinux.0
+@end example
+ETEXI
+
+#ifndef _WIN32
+DEF("smb", HAS_ARG, QEMU_OPTION_smb, \
+           "-smb dir        allow SMB access to files in 'dir' [-net user]\n")
+#endif
+STEXI
+@item -smb @var{dir}
+When using the user mode network stack, activate a built-in SMB
+server so that Windows OSes can access to the host files in @file{@var{dir}}
+transparently.
+
+In the guest Windows OS, the line:
+@example
+10.0.2.4 smbserver
+@end example
+must be added in the file @file{C:\WINDOWS\LMHOSTS} (for windows 9x/Me)
+or @file{C:\WINNT\SYSTEM32\DRIVERS\ETC\LMHOSTS} (Windows NT/2000).
+
+Then @file{@var{dir}} can be accessed in @file{\\smbserver\qemu}.
+
+Note that a SAMBA server must be installed on the host OS in
+@file{/usr/sbin/smbd}. QEMU was tested successfully with smbd version
+2.2.7a from the Red Hat 9 and version 3.0.10-1.fc3 from Fedora Core 3.
+ETEXI
+
+#ifdef CONFIG_SLIRP
+DEF("redir", HAS_ARG, QEMU_OPTION_redir, \
+    "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" \
+    "                redirect TCP or UDP connections from host to guest [-net user]\n")
+#endif
+STEXI
+@item -redir [tcp|udp]:@var{host-port}:[@var{guest-host}]:@var{guest-port}
+
+When using the user mode network stack, redirect incoming TCP or UDP
+connections to the host port @var{host-port} to the guest
+@var{guest-host} on guest port @var{guest-port}. If @var{guest-host}
+is not specified, its value is 10.0.2.15 (default address given by the
+built-in DHCP server). If no connection type is specified, TCP is used.
+
+For example, to redirect host X11 connection from screen 1 to guest
+screen 0, use the following:
+
+@example
+# on the host
+qemu -redir tcp:6001::6000 [...]
+# this host xterm should open in the guest X11 server
+xterm -display :1
+@end example
+
+To redirect telnet connections from host port 5555 to telnet port on
+the guest, use the following:
+
+@example
+# on the host
+qemu -redir tcp:5555::23 [...]
+telnet localhost 5555
+@end example
+
+Then when you use on the host @code{telnet localhost 5555}, you
+connect to the guest telnet server.
+
+@end table
+ETEXI
+
+DEF("bt", HAS_ARG, QEMU_OPTION_bt, \
+    "\n" \
+    "-bt hci,null    dumb bluetooth HCI - doesn't respond to commands\n" \
+    "-bt hci,host[:id]\n" \
+    "                use host's HCI with the given name\n" \
+    "-bt hci[,vlan=n]\n" \
+    "                emulate a standard HCI in virtual scatternet 'n'\n" \
+    "-bt vhci[,vlan=n]\n" \
+    "                add host computer to virtual scatternet 'n' using VHCI\n" \
+    "-bt device:dev[,vlan=n]\n" \
+    "                emulate a bluetooth device 'dev' in scatternet 'n'\n")
+STEXI
+Bluetooth(R) options:
+@table @option
+
+@item -bt hci[...]
+Defines the function of the corresponding Bluetooth HCI.  -bt options
+are matched with the HCIs present in the chosen machine type.  For
+example when emulating a machine with only one HCI built into it, only
+the first @code{-bt hci[...]} option is valid and defines the HCI's
+logic.  The Transport Layer is decided by the machine type.  Currently
+the machines @code{n800} and @code{n810} have one HCI and all other
+machines have none.
+
+@anchor{bt-hcis}
+The following three types are recognized:
+
+@table @code
+@item -bt hci,null
+(default) The corresponding Bluetooth HCI assumes no internal logic
+and will not respond to any HCI commands or emit events.
+
+@item -bt hci,host[:@var{id}]
+(@code{bluez} only) The corresponding HCI passes commands / events
+to / from the physical HCI identified by the name @var{id} (default:
+@code{hci0}) on the computer running QEMU.  Only available on @code{bluez}
+capable systems like Linux.
+
+@item -bt hci[,vlan=@var{n}]
+Add a virtual, standard HCI that will participate in the Bluetooth
+scatternet @var{n} (default @code{0}).  Similarly to @option{-net}
+VLANs, devices inside a bluetooth network @var{n} can only communicate
+with other devices in the same network (scatternet).
+@end table
+
+@item -bt vhci[,vlan=@var{n}]
+(Linux-host only) Create a HCI in scatternet @var{n} (default 0) attached
+to the host bluetooth stack instead of to the emulated target.  This
+allows the host and target machines to participate in a common scatternet
+and communicate.  Requires the Linux @code{vhci} driver installed.  Can
+be used as following:
+
+@example
+qemu [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5
+@end example
+
+@item -bt device:@var{dev}[,vlan=@var{n}]
+Emulate a bluetooth device @var{dev} and place it in network @var{n}
+(default @code{0}).  QEMU can only emulate one type of bluetooth devices
+currently:
+
+@table @code
+@item keyboard
+Virtual wireless keyboard implementing the HIDP bluetooth profile.
+@end table
+@end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(Linux boot specific:)
+STEXI
+When using these options, you can use a given
+Linux kernel without installing it in the disk image. It can be useful
+for easier testing of various kernels.
+
+@table @option
+ETEXI
+
+DEF("kernel", HAS_ARG, QEMU_OPTION_kernel, \
+    "-kernel bzImage use 'bzImage' as kernel image\n")
+STEXI
+@item -kernel @var{bzImage}
+Use @var{bzImage} as kernel image.
+ETEXI
+
+DEF("append", HAS_ARG, QEMU_OPTION_append, \
+    "-append cmdline use 'cmdline' as kernel command line\n")
+STEXI
+@item -append @var{cmdline}
+Use @var{cmdline} as kernel command line
+ETEXI
+
+DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \
+           "-initrd file    use 'file' as initial ram disk\n")
+STEXI
+@item -initrd @var{file}
+Use @var{file} as initial ram disk.
+ETEXI
+
+STEXI
+@end table
+ETEXI
+
+DEFHEADING()
+
+DEFHEADING(Debug/Expert options:)
+
+STEXI
+@table @option
+ETEXI
+
+DEF("serial", HAS_ARG, QEMU_OPTION_serial, \
+    "-serial dev     redirect the serial port to char device 'dev'\n")
+STEXI
+@item -serial @var{dev}
+Redirect the virtual serial port to host character device
+@var{dev}. The default device is @code{vc} in graphical mode and
+@code{stdio} in non graphical mode.
+
+This option can be used several times to simulate up to 4 serial
+ports.
+
+Use @code{-serial none} to disable all serial ports.
+
+Available character devices are:
+@table @code
+@item vc[:WxH]
+Virtual console. Optionally, a width and height can be given in pixel with
+@example
+vc:800x600
+@end example
+It is also possible to specify width or height in characters:
+@example
+vc:80Cx24C
+@end example
+@item pty
+[Linux only] Pseudo TTY (a new PTY is automatically allocated)
+@item none
+No device is allocated.
+@item null
+void device
+@item /dev/XXX
+[Linux only] Use host tty, e.g. @file{/dev/ttyS0}. The host serial port
+parameters are set according to the emulated ones.
+@item /dev/parport@var{N}
+[Linux only, parallel port only] Use host parallel port
+@var{N}. Currently SPP and EPP parallel port features can be used.
+@item file:@var{filename}
+Write output to @var{filename}. No character can be read.
+@item stdio
+[Unix only] standard input/output
+@item pipe:@var{filename}
+name pipe @var{filename}
+@item COM@var{n}
+[Windows only] Use host serial port @var{n}
+@item udp:[@var{remote_host}]:@var{remote_port}[@@[@var{src_ip}]:@var{src_port}]
+This implements UDP Net Console.
+When @var{remote_host} or @var{src_ip} are not specified
+they default to @code{0.0.0.0}.
+When not using a specified @var{src_port} a random port is automatically chosen.
+@item msmouse
+Three button serial mouse. Configure the guest to use Microsoft protocol.
+
+If you just want a simple readonly console you can use @code{netcat} or
+@code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as:
+@code{nc -u -l -p 4555}. Any time qemu writes something to that port it
+will appear in the netconsole session.
+
+If you plan to send characters back via netconsole or you want to stop
+and start qemu a lot of times, you should have qemu use the same
+source port each time by using something like @code{-serial
+udp::4555@@:4556} to qemu. Another approach is to use a patched
+version of netcat which can listen to a TCP port and send and receive
+characters via udp.  If you have a patched version of netcat which
+activates telnet remote echo and single char transfer, then you can
+use the following options to step up a netcat redirector to allow
+telnet on port 5555 to access the qemu port.
+@table @code
+@item Qemu Options:
+-serial udp::4555@@:4556
+@item netcat options:
+-u -P 4555 -L 0.0.0.0:4556 -t -p 5555 -I -T
+@item telnet options:
+localhost 5555
+@end table
+
+@item tcp:[@var{host}]:@var{port}[,@var{server}][,nowait][,nodelay]
+The TCP Net Console has two modes of operation.  It can send the serial
+I/O to a location or wait for a connection from a location.  By default
+the TCP Net Console is sent to @var{host} at the @var{port}.  If you use
+the @var{server} option QEMU will wait for a client socket application
+to connect to the port before continuing, unless the @code{nowait}
+option was specified.  The @code{nodelay} option disables the Nagle buffering
+algorithm.  If @var{host} is omitted, 0.0.0.0 is assumed. Only
+one TCP connection at a time is accepted. You can use @code{telnet} to
+connect to the corresponding character device.
+@table @code
+@item Example to send tcp console to 192.168.0.2 port 4444
+-serial tcp:192.168.0.2:4444
+@item Example to listen and wait on port 4444 for connection
+-serial tcp::4444,server
+@item Example to not wait and listen on ip 192.168.0.100 port 4444
+-serial tcp:192.168.0.100:4444,server,nowait
+@end table
+
+@item telnet:@var{host}:@var{port}[,server][,nowait][,nodelay]
+The telnet protocol is used instead of raw tcp sockets.  The options
+work the same as if you had specified @code{-serial tcp}.  The
+difference is that the port acts like a telnet server or client using
+telnet option negotiation.  This will also allow you to send the
+MAGIC_SYSRQ sequence if you use a telnet that supports sending the break
+sequence.  Typically in unix telnet you do it with Control-] and then
+type "send break" followed by pressing the enter key.
+
+@item unix:@var{path}[,server][,nowait]
+A unix domain socket is used instead of a tcp socket.  The option works the
+same as if you had specified @code{-serial tcp} except the unix domain socket
+@var{path} is used for connections.
+
+@item mon:@var{dev_string}
+This is a special option to allow the monitor to be multiplexed onto
+another serial port.  The monitor is accessed with key sequence of
+@key{Control-a} and then pressing @key{c}. See monitor access
+@ref{pcsys_keys} in the -nographic section for more keys.
+@var{dev_string} should be any one of the serial devices specified
+above.  An example to multiplex the monitor onto a telnet server
+listening on port 4444 would be:
+@table @code
+@item -serial mon:telnet::4444,server,nowait
+@end table
+
+@item braille
+Braille device.  This will use BrlAPI to display the braille output on a real
+or fake device.
+
+@end table
+ETEXI
+
+DEF("parallel", HAS_ARG, QEMU_OPTION_parallel, \
+    "-parallel dev   redirect the parallel port to char device 'dev'\n")
+STEXI
+@item -parallel @var{dev}
+Redirect the virtual parallel port to host device @var{dev} (same
+devices as the serial port). On Linux hosts, @file{/dev/parportN} can
+be used to use hardware devices connected on the corresponding host
+parallel port.
+
+This option can be used several times to simulate up to 3 parallel
+ports.
+
+Use @code{-parallel none} to disable all parallel ports.
+ETEXI
+
+DEF("monitor", HAS_ARG, QEMU_OPTION_monitor, \
+    "-monitor dev    redirect the monitor to char device 'dev'\n")
+STEXI
+@item -monitor @var{dev}
+Redirect the monitor to host device @var{dev} (same devices as the
+serial port).
+The default device is @code{vc} in graphical mode and @code{stdio} in
+non graphical mode.
+ETEXI
+
+DEF("pidfile", HAS_ARG, QEMU_OPTION_pidfile, \
+    "-pidfile file   write PID to 'file'\n")
+STEXI
+@item -pidfile @var{file}
+Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
+from a script.
+ETEXI
+
+DEF("singlestep", 0, QEMU_OPTION_singlestep, \
+    "-singlestep   always run in singlestep mode\n")
+STEXI
+@item -singlestep
+Run the emulation in single step mode.
+ETEXI
+
+DEF("S", 0, QEMU_OPTION_S, \
+    "-S              freeze CPU at startup (use 'c' to start execution)\n")
+STEXI
+@item -S
+Do not start CPU at startup (you must type 'c' in the monitor).
+ETEXI
+
+DEF("gdb", HAS_ARG, QEMU_OPTION_gdb, \
+    "-gdb dev        wait for gdb connection on 'dev'\n")
+STEXI
+@item -gdb @var{dev}
+Wait for gdb connection on device @var{dev} (@pxref{gdb_usage}). Typical
+connections will likely be TCP-based, but also UDP, pseudo TTY, or even
+stdio are reasonable use case. The latter is allowing to start qemu from
+within gdb and establish the connection via a pipe:
+@example
+(gdb) target remote | exec qemu -gdb stdio ...
+@end example
+ETEXI
+
+DEF("s", 0, QEMU_OPTION_s, \
+    "-s              shorthand for -gdb tcp::%s\n")
+STEXI
+@item -s
+Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234
+(@pxref{gdb_usage}).
+ETEXI
+
+DEF("d", HAS_ARG, QEMU_OPTION_d, \
+    "-d item1,...    output log to %s (use -d ? for a list of log items)\n")
+STEXI
+@item -d
+Output log in /tmp/qemu.log
+ETEXI
+
+DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
+    "-hdachs c,h,s[,t]\n" \
+    "                force hard disk 0 physical geometry and the optional BIOS\n" \
+    "                translation (t=none or lba) (usually qemu can guess them)\n")
+STEXI
+@item -hdachs @var{c},@var{h},@var{s},[,@var{t}]
+Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
+@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
+translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
+all those parameters. This option is useful for old MS-DOS disk
+images.
+ETEXI
+
+DEF("L", HAS_ARG, QEMU_OPTION_L, \
+    "-L path         set the directory for the BIOS, VGA BIOS and keymaps\n")
+STEXI
+@item -L  @var{path}
+Set the directory for the BIOS, VGA BIOS and keymaps.
+ETEXI
+
+DEF("bios", HAS_ARG, QEMU_OPTION_bios, \
+    "-bios file      set the filename for the BIOS\n")
+STEXI
+@item -bios @var{file}
+Set the filename for the BIOS.
+ETEXI
+
+#ifdef CONFIG_KQEMU
+DEF("kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu, \
+    "-kernel-kqemu   enable KQEMU full virtualization (default is user mode only)\n")
+#endif
+STEXI
+@item -kernel-kqemu
+Enable KQEMU full virtualization (default is user mode only).
+ETEXI
+
+#ifdef CONFIG_KQEMU
+DEF("no-kqemu", 0, QEMU_OPTION_no_kqemu, \
+    "-no-kqemu       disable KQEMU kernel module usage\n")
+#endif
+STEXI
+@item -no-kqemu
+Disable KQEMU kernel module usage. KQEMU options are only available if
+KQEMU support is enabled when compiling.
+ETEXI
+
+#ifdef CONFIG_KVM
+DEF("enable-kvm", 0, QEMU_OPTION_enable_kvm, \
+    "-enable-kvm     enable KVM full virtualization support\n")
+#endif
+STEXI
+@item -enable-kvm
+Enable KVM full virtualization support. This option is only available
+if KVM support is enabled when compiling.
+ETEXI
+
+#ifdef CONFIG_XEN
+DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
+    "-xen-domid id   specify xen guest domain id\n")
+DEF("xen-create", 0, QEMU_OPTION_xen_create,
+    "-xen-create     create domain using xen hypercalls, bypassing xend\n"
+    "                warning: should not be used when xend is in use\n")
+DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
+    "-xen-attach     attach to existing xen domain\n"
+    "                xend will use this when starting qemu\n")
+#endif
+
+DEF("no-reboot", 0, QEMU_OPTION_no_reboot, \
+    "-no-reboot      exit instead of rebooting\n")
+STEXI
+@item -no-reboot
+Exit instead of rebooting.
+ETEXI
+
+DEF("no-shutdown", 0, QEMU_OPTION_no_shutdown, \
+    "-no-shutdown    stop before shutdown\n")
+STEXI
+@item -no-shutdown
+Don't exit QEMU on guest shutdown, but instead only stop the emulation.
+This allows for instance switching to monitor to commit changes to the
+disk image.
+ETEXI
+
+DEF("loadvm", HAS_ARG, QEMU_OPTION_loadvm, \
+    "-loadvm [tag|id]\n" \
+    "                start right away with a saved state (loadvm in monitor)\n")
+STEXI
+@item -loadvm @var{file}
+Start right away with a saved state (@code{loadvm} in monitor)
+ETEXI
+
+#ifndef _WIN32
+DEF("daemonize", 0, QEMU_OPTION_daemonize, \
+    "-daemonize      daemonize QEMU after initializing\n")
+#endif
+STEXI
+@item -daemonize
+Daemonize the QEMU process after initialization.  QEMU will not detach from
+standard IO until it is ready to receive connections on any of its devices.
+This option is a useful way for external programs to launch QEMU without having
+to cope with initialization race conditions.
+ETEXI
+
+DEF("option-rom", HAS_ARG, QEMU_OPTION_option_rom, \
+    "-option-rom rom load a file, rom, into the option ROM space\n")
+STEXI
+@item -option-rom @var{file}
+Load the contents of @var{file} as an option ROM.
+This option is useful to load things like EtherBoot.
+ETEXI
+
+DEF("clock", HAS_ARG, QEMU_OPTION_clock, \
+    "-clock          force the use of the given methods for timer alarm.\n" \
+    "                To see what timers are available use -clock ?\n")
+STEXI
+@item -clock @var{method}
+Force the use of the given methods for timer alarm. To see what timers
+are available use -clock ?.
+ETEXI
+
+DEF("localtime", 0, QEMU_OPTION_localtime, \
+    "-localtime      set the real time clock to local time [default=utc]\n")
+STEXI
+@item -localtime
+Set the real time clock to local time (the default is to UTC
+time). This option is needed to have correct date in MS-DOS or
+Windows.
+ETEXI
+
+DEF("startdate", HAS_ARG, QEMU_OPTION_startdate, \
+    "-startdate      select initial date of the clock\n")
+STEXI
+
+@item -startdate @var{date}
+Set the initial date of the real time clock. Valid formats for
+@var{date} are: @code{now} or @code{2006-06-17T16:01:21} or
+@code{2006-06-17}. The default value is @code{now}.
+ETEXI
+
+DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
+    "-icount [N|auto]\n" \
+    "                enable virtual instruction counter with 2^N clock ticks per\n" \
+    "                instruction\n")
+STEXI
+@item -icount [N|auto]
+Enable virtual instruction counter.  The virtual cpu will execute one
+instruction every 2^N ns of virtual time.  If @code{auto} is specified
+then the virtual cpu speed will be automatically adjusted to keep virtual
+time within a few seconds of real time.
+
+Note that while this option can give deterministic behavior, it does not
+provide cycle accurate emulation.  Modern CPUs contain superscalar out of
+order cores with complex cache hierarchies.  The number of instructions
+executed often has little or no correlation with actual performance.
+ETEXI
+
+DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
+    "-watchdog i6300esb|ib700\n" \
+    "                enable virtual hardware watchdog [default=none]\n")
+STEXI
+@item -watchdog @var{model}
+Create a virtual hardware watchdog device.  Once enabled (by a guest
+action), the watchdog must be periodically polled by an agent inside
+the guest or else the guest will be restarted.
+
+The @var{model} is the model of hardware watchdog to emulate.  Choices
+for model are: @code{ib700} (iBASE 700) which is a very simple ISA
+watchdog with a single timer, or @code{i6300esb} (Intel 6300ESB I/O
+controller hub) which is a much more featureful PCI-based dual-timer
+watchdog.  Choose a model for which your guest has drivers.
+
+Use @code{-watchdog ?} to list available hardware models.  Only one
+watchdog can be enabled for a guest.
+ETEXI
+
+DEF("watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action, \
+    "-watchdog-action reset|shutdown|poweroff|pause|debug|none\n" \
+    "                action when watchdog fires [default=reset]\n")
+STEXI
+@item -watchdog-action @var{action}
+
+The @var{action} controls what QEMU will do when the watchdog timer
+expires.
+The default is
+@code{reset} (forcefully reset the guest).
+Other possible actions are:
+@code{shutdown} (attempt to gracefully shutdown the guest),
+@code{poweroff} (forcefully poweroff the guest),
+@code{pause} (pause the guest),
+@code{debug} (print a debug message and continue), or
+@code{none} (do nothing).
+
+Note that the @code{shutdown} action requires that the guest responds
+to ACPI signals, which it may not be able to do in the sort of
+situations where the watchdog would have expired, and thus
+@code{-watchdog-action shutdown} is not recommended for production use.
+
+Examples:
+
+@table @code
+@item -watchdog i6300esb -watchdog-action pause
+@item -watchdog ib700
+@end table
+ETEXI
+
+DEF("echr", HAS_ARG, QEMU_OPTION_echr, \
+    "-echr chr       set terminal escape character instead of ctrl-a\n")
+STEXI
+
+@item -echr numeric_ascii_value
+Change the escape character used for switching to the monitor when using
+monitor and serial sharing.  The default is @code{0x01} when using the
+@code{-nographic} option.  @code{0x01} is equal to pressing
+@code{Control-a}.  You can select a different character from the ascii
+control keys where 1 through 26 map to Control-a through Control-z.  For
+instance you could use the either of the following to change the escape
+character to Control-t.
+@table @code
+@item -echr 0x14
+@item -echr 20
+@end table
+ETEXI
+
+DEF("virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon, \
+    "-virtioconsole c\n" \
+    "                set virtio console\n")
+STEXI
+@item -virtioconsole @var{c}
+Set virtio console.
+ETEXI
+
+DEF("show-cursor", 0, QEMU_OPTION_show_cursor, \
+    "-show-cursor    show cursor\n")
+STEXI
+ETEXI
+
+DEF("tb-size", HAS_ARG, QEMU_OPTION_tb_size, \
+    "-tb-size n      set TB size\n")
+STEXI
+ETEXI
+
+DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
+    "-incoming p     prepare for incoming migration, listen on port p\n")
+STEXI
+ETEXI
+
+#ifndef _WIN32
+DEF("chroot", HAS_ARG, QEMU_OPTION_chroot, \
+    "-chroot dir     Chroot to dir just before starting the VM.\n")
+#endif
+STEXI
+@item -chroot dir
+Immediately before starting guest execution, chroot to the specified
+directory.  Especially useful in combination with -runas.
+ETEXI
+
+#ifndef _WIN32
+DEF("runas", HAS_ARG, QEMU_OPTION_runas, \
+    "-runas user     Change to user id user just before starting the VM.\n")
+#endif
+STEXI
+@item -runas user
+Immediately before starting guest execution, drop root privileges, switching
+to the specified user.
+ETEXI
+
+STEXI
+@end table
+ETEXI
+
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
+DEF("prom-env", HAS_ARG, QEMU_OPTION_prom_env,
+    "-prom-env variable=value\n"
+    "                set OpenBIOS nvram variables\n")
+#endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
+DEF("semihosting", 0, QEMU_OPTION_semihosting,
+    "-semihosting    semihosting mode\n")
+#endif
+#if defined(TARGET_ARM)
+DEF("old-param", 0, QEMU_OPTION_old_param,
+    "-old-param      old param mode\n")
+#endif
+
+#ifdef CONFIG_TRACE
+DEF("tracing", HAS_ARG, QEMU_OPTION_tracing, \
+    "-tracing on|off enable/disable tracing\n")
+
+DEF("trace", HAS_ARG, QEMU_OPTION_trace, \
+    "-trace name\n" \
+    "                set trace directory\n")
+
+DEF("nand", HAS_ARG, QEMU_OPTION_nand, \
+    "-nand <params>  enable NAND Flash partition\n")
+
+#endif /* CONFIG_TRACE */
+
+#if 1 /* ANDROID */
+
+DEF("mic", HAS_ARG, QEMU_OPTION_mic, \
+    "-mic <file>     read audio input from wav file\n")
+
+#endif
diff --git a/qemu-sockets-android.c b/qemu-sockets-android.c
new file mode 100644
index 0000000..c22f352
--- /dev/null
+++ b/qemu-sockets-android.c
@@ -0,0 +1,357 @@
+/*
+ *  inet and unix socket functions for qemu
+ *
+ *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "qemu_socket.h"
+#include "qemu-common.h" /* for qemu_isdigit */
+
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+
+static int sockets_debug = 0;
+static const int on=1, off=0;
+
+static const char *sock_address_strfamily(SockAddress *s)
+{
+    switch (sock_address_get_family(s)) {
+    case SOCKET_IN6:   return "ipv6";
+    case SOCKET_INET:  return "ipv4";
+    case SOCKET_UNIX:  return "unix";
+    default:           return "????";
+    }
+}
+
+int inet_listen(const char *str, char *ostr, int olen,
+                SocketType socktype, int port_offset)
+{
+    SockAddress**  list;
+    SockAddress*   e;
+    unsigned       flags = SOCKET_LIST_PASSIVE;
+    char addr[64];
+    char port[33];
+    char uaddr[256+1];
+    const char *opts, *h;
+    int slisten,pos,to,try_next,nn;
+
+    /* parse address */
+    if (str[0] == ':') {
+        /* no host given */
+        addr[0] = '\0';
+        if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
+            fprintf(stderr, "%s: portonly parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+    } else if (str[0] == '[') {
+        /* IPv6 addr */
+        if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        flags |= SOCKET_LIST_FORCE_IN6;
+    } else if (qemu_isdigit(str[0])) {
+        /* IPv4 addr */
+        if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        flags |= SOCKET_LIST_FORCE_INET;
+    } else {
+        /* hostname */
+        if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: hostname parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+    }
+
+    /* parse options */
+    opts = str + pos;
+    h = strstr(opts, ",to=");
+    to = h ? atoi(h+4) : 0;
+    if (strstr(opts, ",ipv4")) {
+        flags &= ~SOCKET_LIST_FORCE_IN6;
+        flags |= SOCKET_LIST_FORCE_INET;
+    }
+    if (strstr(opts, ",ipv6")) {
+        flags &= SOCKET_LIST_FORCE_INET;
+        flags |= SOCKET_LIST_FORCE_IN6;
+    }
+
+    /* lookup */
+    if (port_offset)
+        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+
+    list = sock_address_list_create( strlen(addr) ? addr : NULL,
+                                       port,
+                                       flags );
+    if (list == NULL) {
+        fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,
+                addr, port, errno_str);
+        return -1;
+    }
+
+    /* create socket + bind */
+    for (nn = 0; list[nn] != NULL; nn++) {
+        SocketFamily  family;
+
+        e      = list[nn];
+        family = sock_address_get_family(e);
+        slisten = socket_create(family, socktype);
+        if (slisten < 0) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+                    sock_address_strfamily(e), errno_str);
+            continue;
+        }
+
+        socket_set_xreuseaddr(slisten);
+#ifdef IPV6_V6ONLY
+        /* listen on both ipv4 and ipv6 */
+        if (family == PF_INET6) {
+            socket_set_ipv6only(slisten);
+        }
+#endif
+
+        for (;;) {
+            if (socket_bind(slisten, e) == 0) {
+                if (sockets_debug)
+                    fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
+                        sock_address_strfamily(e), uaddr, sock_address_get_port(e));
+                goto listen;
+            }
+            socket_close(slisten);
+            try_next = to && (sock_address_get_port(e) <= to + port_offset);
+            if (!try_next || sockets_debug)
+                fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
+                        sock_address_strfamily(e), uaddr, sock_address_get_port(e),
+                        strerror(errno));
+            if (try_next) {
+                sock_address_set_port(e, sock_address_get_port(e) + 1);
+                continue;
+            }
+            break;
+        }
+    }
+    sock_address_list_free(list);
+    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
+    return -1;
+
+listen:
+    if (socket_listen(slisten,1) != 0) {
+        perror("listen");
+        socket_close(slisten);
+        return -1;
+    }
+    if (ostr) {
+        if (flags & SOCKET_LIST_FORCE_IN6) {
+            snprintf(ostr, olen, "[%s]:%d%s", uaddr,
+                     sock_address_get_port(e) - port_offset, opts);
+        } else {
+            snprintf(ostr, olen, "%s:%d%s", uaddr,
+                     sock_address_get_port(e) - port_offset, opts);
+        }
+    }
+    sock_address_list_free(list);
+    return slisten;
+}
+
+int inet_connect(const char *str, SocketType socktype)
+{
+    SockAddress**  list;
+    SockAddress*   e;
+    unsigned       flags = 0;
+    char addr[64];
+    char port[33];
+    int sock, nn;
+
+    /* parse address */
+    if (str[0] == '[') {
+        /* IPv6 addr */
+        if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) {
+            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        flags |= SOCKET_LIST_FORCE_IN6;
+    } else if (qemu_isdigit(str[0])) {
+        /* IPv4 addr */
+        if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) {
+            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        flags |= SOCKET_LIST_FORCE_INET;
+    } else {
+        /* hostname */
+        if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) {
+            fprintf(stderr, "%s: hostname parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+    }
+
+    /* parse options */
+    if (strstr(str, ",ipv4")) {
+        flags &= SOCKET_LIST_FORCE_IN6;
+        flags |= SOCKET_LIST_FORCE_INET;
+    }
+    if (strstr(str, ",ipv6")) {
+        flags &= SOCKET_LIST_FORCE_INET;
+        flags |= SOCKET_LIST_FORCE_IN6;
+    }
+
+    /* lookup */
+    list = sock_address_list_create(addr, port, flags);
+    if (list == NULL) {
+        fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
+                addr, port, errno_str);
+        return -1;
+    }
+
+    for (nn = 0; list[nn] != NULL; nn++) {
+        e     = list[nn];
+        sock = socket_create(sock_address_get_family(e), socktype);
+        if (sock < 0) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+            sock_address_strfamily(e), errno_str);
+            continue;
+        }
+        socket_set_xreuseaddr(sock);
+
+        /* connect to peer */
+        if (socket_connect(sock,e) < 0) {
+            if (sockets_debug)
+                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
+                        sock_address_strfamily(e),
+                        sock_address_to_string(e), addr, port, strerror(errno));
+            socket_close(sock);
+            continue;
+        }
+        if (sockets_debug)
+            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
+                        sock_address_strfamily(e),
+                        sock_address_to_string(e), addr, port);
+
+        goto EXIT;
+    }
+    sock = -1;
+EXIT:
+    sock_address_list_free(list);
+    return sock;
+}
+
+#ifndef _WIN32
+
+int unix_listen(const char *str, char *ostr, int olen)
+{
+    SockAddress  un;
+    char         unpath[PATH_MAX];
+    char *path, *upath, *opts;
+    int sock, fd, len;
+
+    opts = strchr(str, ',');
+    if (opts) {
+        len = opts - str;
+        path = qemu_malloc(len+1);
+        snprintf(path, len+1, "%.*s", len, str);
+    } else
+        path = qemu_strdup(str);
+
+    if (path || strlen(path) > 0) {
+        upath = path;
+    } else {
+        char *tmpdir = getenv("TMPDIR");
+        snprintf(unpath, sizeof(unpath), "%s/qemu-socket-XXXXXX",
+                 tmpdir ? tmpdir : "/tmp");
+        /*
+         * This dummy fd usage silences the mktemp() unsecure warning.
+         * Using mkstemp() doesn't make things more secure here
+         * though.  bind() complains about existing files, so we have
+         * to unlink first and thus re-open the race window.  The
+         * worst case possible is bind() failing, i.e. a DoS attack.
+         */
+        fd = mkstemp(unpath); close(fd);
+        upath = unpath;
+    }
+    snprintf(ostr, olen, "%s%s", path, opts ? opts : "");
+
+    sock = socket_unix_server(upath, SOCKET_STREAM);
+    sock_address_done(&un);
+
+    if (sock < 0) {
+        fprintf(stderr, "bind(unix:%s): %s\n", upath, errno_str);
+        goto err;
+    }
+
+    if (sockets_debug)
+        fprintf(stderr, "bind(unix:%s): OK\n", upath);
+
+    qemu_free(path);
+    return sock;
+
+err:
+    qemu_free(path);
+    socket_close(sock);
+    return -1;
+}
+
+int unix_connect(const char *path)
+{
+    SockAddress  un;
+    int ret, sock;
+
+    sock = socket_create_unix(SOCKET_STREAM);
+    if (sock < 0) {
+        perror("socket(unix)");
+        return -1;
+    }
+
+    sock_address_init_unix(&un, path);
+    ret = socket_connect(sock, &un);
+    sock_address_done(&un);
+    if (ret < 0) {
+        fprintf(stderr, "connect(unix:%s): %s\n", path, errno_str);
+        return -1;
+    }
+
+
+    if (sockets_debug)
+        fprintf(stderr, "connect(unix:%s): OK\n", path);
+    return sock;
+}
+
+#else
+
+int unix_listen(const char *path, char *ostr, int olen)
+{
+    fprintf(stderr, "unix sockets are not available on windows\n");
+    return -1;
+}
+
+int unix_connect(const char *path)
+{
+    fprintf(stderr, "unix sockets are not available on windows\n");
+    return -1;
+}
+
+#endif
diff --git a/qemu-sockets.c b/qemu-sockets.c
new file mode 100644
index 0000000..bd49d29
--- /dev/null
+++ b/qemu-sockets.c
@@ -0,0 +1,417 @@
+/*
+ *  inet and unix socket functions for qemu
+ *
+ *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "qemu_socket.h"
+#include "qemu-common.h" /* for qemu_isdigit */
+
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+
+static int sockets_debug = 0;
+static const int on=1, off=0;
+
+static int inet_getport(struct addrinfo *e)
+{
+    struct sockaddr_in *i4;
+    struct sockaddr_in6 *i6;
+
+    switch (e->ai_family) {
+    case PF_INET6:
+        i6 = (void*)e->ai_addr;
+        return ntohs(i6->sin6_port);
+    case PF_INET:
+        i4 = (void*)e->ai_addr;
+        return ntohs(i4->sin_port);
+    default:
+        return 0;
+    }
+}
+
+static void inet_setport(struct addrinfo *e, int port)
+{
+    struct sockaddr_in *i4;
+    struct sockaddr_in6 *i6;
+
+    switch (e->ai_family) {
+    case PF_INET6:
+        i6 = (void*)e->ai_addr;
+        i6->sin6_port = htons(port);
+        break;
+    case PF_INET:
+        i4 = (void*)e->ai_addr;
+        i4->sin_port = htons(port);
+        break;
+    }
+}
+
+static const char *inet_strfamily(int family)
+{
+    switch (family) {
+    case PF_INET6: return "ipv6";
+    case PF_INET:  return "ipv4";
+    case PF_UNIX:  return "unix";
+    }
+    return "????";
+}
+
+static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
+{
+    struct addrinfo *e;
+    char uaddr[INET6_ADDRSTRLEN+1];
+    char uport[33];
+
+    for (e = res; e != NULL; e = e->ai_next) {
+        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
+                    uaddr,INET6_ADDRSTRLEN,uport,32,
+                    NI_NUMERICHOST | NI_NUMERICSERV);
+        fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n",
+                tag, inet_strfamily(e->ai_family), uaddr, uport);
+    }
+}
+
+int inet_listen(const char *str, char *ostr, int olen,
+                int socktype, int port_offset)
+{
+    struct addrinfo ai,*res,*e;
+    char addr[64];
+    char port[33];
+    char uaddr[INET6_ADDRSTRLEN+1];
+    char uport[33];
+    const char *opts, *h;
+    int slisten,rc,pos,to,try_next;
+
+    memset(&ai,0, sizeof(ai));
+    ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+    ai.ai_family = PF_UNSPEC;
+    ai.ai_socktype = socktype;
+
+    /* parse address */
+    if (str[0] == ':') {
+        /* no host given */
+        addr[0] = '\0';
+        if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
+            fprintf(stderr, "%s: portonly parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+    } else if (str[0] == '[') {
+        /* IPv6 addr */
+        if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        ai.ai_family = PF_INET6;
+    } else if (qemu_isdigit(str[0])) {
+        /* IPv4 addr */
+        if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        ai.ai_family = PF_INET;
+    } else {
+        /* hostname */
+        if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
+            fprintf(stderr, "%s: hostname parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+    }
+
+    /* parse options */
+    opts = str + pos;
+    h = strstr(opts, ",to=");
+    to = h ? atoi(h+4) : 0;
+    if (strstr(opts, ",ipv4"))
+        ai.ai_family = PF_INET;
+    if (strstr(opts, ",ipv6"))
+        ai.ai_family = PF_INET6;
+
+    /* lookup */
+    if (port_offset)
+        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+    rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
+    if (rc != 0) {
+        fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,
+                addr, port, gai_strerror(rc));
+        return -1;
+    }
+    if (sockets_debug)
+        inet_print_addrinfo(__FUNCTION__, res);
+
+    /* create socket + bind */
+    for (e = res; e != NULL; e = e->ai_next) {
+        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
+		        uaddr,INET6_ADDRSTRLEN,uport,32,
+		        NI_NUMERICHOST | NI_NUMERICSERV);
+        slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol);
+        if (slisten < 0) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+                    inet_strfamily(e->ai_family), strerror(errno));
+            continue;
+        }
+
+        setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
+#ifdef IPV6_V6ONLY
+        if (e->ai_family == PF_INET6) {
+            /* listen on both ipv4 and ipv6 */
+            setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,
+                sizeof(off));
+        }
+#endif
+
+        for (;;) {
+            if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
+                if (sockets_debug)
+                    fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
+                        inet_strfamily(e->ai_family), uaddr, inet_getport(e));
+                goto listen;
+            }
+            try_next = to && (inet_getport(e) <= to + port_offset);
+            if (!try_next || sockets_debug)
+                fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
+                        inet_strfamily(e->ai_family), uaddr, inet_getport(e),
+                        strerror(errno));
+            if (try_next) {
+                inet_setport(e, inet_getport(e) + 1);
+                continue;
+            }
+            break;
+        }
+        closesocket(slisten);
+    }
+    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
+    freeaddrinfo(res);
+    return -1;
+
+listen:
+    if (listen(slisten,1) != 0) {
+        perror("listen");
+        closesocket(slisten);
+        freeaddrinfo(res);
+        return -1;
+    }
+    if (ostr) {
+        if (e->ai_family == PF_INET6) {
+            snprintf(ostr, olen, "[%s]:%d%s", uaddr,
+                     inet_getport(e) - port_offset, opts);
+        } else {
+            snprintf(ostr, olen, "%s:%d%s", uaddr,
+                     inet_getport(e) - port_offset, opts);
+        }
+    }
+    freeaddrinfo(res);
+    return slisten;
+}
+
+int inet_connect(const char *str, int socktype)
+{
+    struct addrinfo ai,*res,*e;
+    char addr[64];
+    char port[33];
+    char uaddr[INET6_ADDRSTRLEN+1];
+    char uport[33];
+    int sock,rc;
+
+    memset(&ai,0, sizeof(ai));
+    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
+    ai.ai_family = PF_UNSPEC;
+    ai.ai_socktype = socktype;
+
+    /* parse address */
+    if (str[0] == '[') {
+        /* IPv6 addr */
+        if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) {
+            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        ai.ai_family = PF_INET6;
+    } else if (qemu_isdigit(str[0])) {
+        /* IPv4 addr */
+        if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) {
+            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+        ai.ai_family = PF_INET;
+    } else {
+        /* hostname */
+        if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) {
+            fprintf(stderr, "%s: hostname parse error (%s)\n",
+                    __FUNCTION__, str);
+            return -1;
+        }
+    }
+
+    /* parse options */
+    if (strstr(str, ",ipv4"))
+        ai.ai_family = PF_INET;
+    if (strstr(str, ",ipv6"))
+        ai.ai_family = PF_INET6;
+
+    /* lookup */
+    if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
+        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc),
+                addr, port);
+	return -1;
+    }
+    if (sockets_debug)
+        inet_print_addrinfo(__FUNCTION__, res);
+
+    for (e = res; e != NULL; e = e->ai_next) {
+        if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
+                            uaddr,INET6_ADDRSTRLEN,uport,32,
+                            NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+            fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
+            continue;
+        }
+        sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol);
+        if (sock < 0) {
+            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
+            inet_strfamily(e->ai_family), strerror(errno));
+            continue;
+        }
+        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
+
+        /* connect to peer */
+        if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
+            if (sockets_debug || NULL == e->ai_next)
+                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
+                        inet_strfamily(e->ai_family),
+                        e->ai_canonname, uaddr, uport, strerror(errno));
+            closesocket(sock);
+            continue;
+        }
+        if (sockets_debug)
+            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
+                    inet_strfamily(e->ai_family),
+                    e->ai_canonname, uaddr, uport);
+        freeaddrinfo(res);
+        return sock;
+    }
+    freeaddrinfo(res);
+    return -1;
+}
+
+#ifndef _WIN32
+
+int unix_listen(const char *str, char *ostr, int olen)
+{
+    struct sockaddr_un un;
+    char *path, *opts;
+    int sock, fd, len;
+
+    sock = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        perror("socket(unix)");
+        return -1;
+    }
+
+    opts = strchr(str, ',');
+    if (opts) {
+        len = opts - str;
+        path = qemu_malloc(len+1);
+        snprintf(path, len+1, "%.*s", len, str);
+    } else
+        path = qemu_strdup(str);
+
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    if (path && strlen(path)) {
+        snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+    } else {
+        char *tmpdir = getenv("TMPDIR");
+        snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
+                 tmpdir ? tmpdir : "/tmp");
+        /*
+         * This dummy fd usage silences the mktemp() unsecure warning.
+         * Using mkstemp() doesn't make things more secure here
+         * though.  bind() complains about existing files, so we have
+         * to unlink first and thus re-open the race window.  The
+         * worst case possible is bind() failing, i.e. a DoS attack.
+         */
+        fd = mkstemp(un.sun_path); close(fd);
+    }
+    snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : "");
+
+    unlink(un.sun_path);
+    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
+        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+    if (listen(sock, 1) < 0) {
+        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
+        goto err;
+    }
+
+    if (sockets_debug)
+        fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
+    qemu_free(path);
+    return sock;
+
+err:
+    qemu_free(path);
+    closesocket(sock);
+    return -1;
+}
+
+int unix_connect(const char *path)
+{
+    struct sockaddr_un un;
+    int sock;
+
+    sock = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        perror("socket(unix)");
+        return -1;
+    }
+
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
+    if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
+        fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
+	return -1;
+    }
+
+    if (sockets_debug)
+        fprintf(stderr, "connect(unix:%s): OK\n", path);
+    return sock;
+}
+
+#else
+
+int unix_listen(const char *path, char *ostr, int olen)
+{
+    fprintf(stderr, "unix sockets are not available on windows\n");
+    return -1;
+}
+
+int unix_connect(const char *path)
+{
+    fprintf(stderr, "unix sockets are not available on windows\n");
+    return -1;
+}
+
+#endif
diff --git a/qemu-thread.c b/qemu-thread.c
new file mode 100644
index 0000000..719cfcd
--- /dev/null
+++ b/qemu-thread.c
@@ -0,0 +1,163 @@
+/*
+ * Wrappers around mutex/cond/thread functions
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Author:
+ *  Marcelo Tosatti <mtosatti@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include "qemu-thread.h"
+
+static void error_exit(int err, const char *msg)
+{
+    fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
+    exit(1);
+}
+
+void qemu_mutex_init(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_init(&mutex->lock, NULL);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_mutex_lock(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_lock(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+int qemu_mutex_trylock(QemuMutex *mutex)
+{
+    return pthread_mutex_trylock(&mutex->lock);
+}
+
+static void timespec_add_ms(struct timespec *ts, uint64_t msecs)
+{
+    ts->tv_sec = ts->tv_sec + (long)(msecs / 1000);
+    ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000);
+    if (ts->tv_nsec >= 1000000000) {
+        ts->tv_nsec -= 1000000000;
+        ts->tv_sec++;
+    }
+}
+
+int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs)
+{
+    int err;
+    struct timespec ts;
+
+    clock_gettime(CLOCK_REALTIME, &ts);
+    timespec_add_ms(&ts, msecs);
+
+    err = pthread_mutex_timedlock(&mutex->lock, &ts);
+    if (err && err != ETIMEDOUT)
+        error_exit(err, __func__);
+    return err;
+}
+
+void qemu_mutex_unlock(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_unlock(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_init(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_init(&cond->cond, NULL);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_signal(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_signal(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_broadcast(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_broadcast(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_cond_wait(&cond->cond, &mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
+int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs)
+{
+    struct timespec ts;
+    int err;
+
+    clock_gettime(CLOCK_REALTIME, &ts);
+    timespec_add_ms(&ts, msecs);
+
+    err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts);
+    if (err && err != ETIMEDOUT)
+        error_exit(err, __func__);
+    return err;
+}
+
+void qemu_thread_create(QemuThread *thread,
+                       void *(*start_routine)(void*),
+                       void *arg)
+{
+    int err;
+
+    err = pthread_create(&thread->thread, NULL, start_routine, arg);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_thread_signal(QemuThread *thread, int sig)
+{
+    int err;
+
+    err = pthread_kill(thread->thread, sig);
+    if (err)
+        error_exit(err, __func__);
+}
+
+void qemu_thread_self(QemuThread *thread)
+{
+    thread->thread = pthread_self();
+}
+
+int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
+{
+   return (thread1->thread == thread2->thread);
+}
+
diff --git a/qemu-thread.h b/qemu-thread.h
new file mode 100644
index 0000000..5ef4a3a
--- /dev/null
+++ b/qemu-thread.h
@@ -0,0 +1,40 @@
+#ifndef __QEMU_THREAD_H
+#define __QEMU_THREAD_H 1
+#include "semaphore.h"
+#include "pthread.h"
+
+struct QemuMutex {
+    pthread_mutex_t lock;
+};
+
+struct QemuCond {
+    pthread_cond_t cond;
+};
+
+struct QemuThread {
+    pthread_t thread;
+};
+
+typedef struct QemuMutex QemuMutex;
+typedef struct QemuCond QemuCond;
+typedef struct QemuThread QemuThread;
+
+void qemu_mutex_init(QemuMutex *mutex);
+void qemu_mutex_lock(QemuMutex *mutex);
+int qemu_mutex_trylock(QemuMutex *mutex);
+int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs);
+void qemu_mutex_unlock(QemuMutex *mutex);
+
+void qemu_cond_init(QemuCond *cond);
+void qemu_cond_signal(QemuCond *cond);
+void qemu_cond_broadcast(QemuCond *cond);
+void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
+int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs);
+
+void qemu_thread_create(QemuThread *thread,
+                       void *(*start_routine)(void*),
+                       void *arg);
+void qemu_thread_signal(QemuThread *thread, int sig);
+void qemu_thread_self(QemuThread *thread);
+int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2);
+#endif
diff --git a/qemu_socket.h b/qemu_socket.h
index 896a0b5..cf65f5a 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -1,8 +1,22 @@
-#ifndef _qemu_socket_h
-#define _qemu_socket_h
+/* headers to use the BSD sockets */
+#ifndef QEMU__SOCKET_H
+#define QEMU__SOCKET_H
 
 #include "sockets.h"
-#define  socket_error()  socket_errno
+#define  socket_error()  errno
 #define  closesocket     socket_close
 
-#endif /* _qemu_socket_h */
+/* New, ipv6-ready socket helper functions, see qemu-sockets.c */
+int inet_listen(const char *str, char *ostr, int olen,
+                SocketType socktype, int port_offset);
+int inet_connect(const char *str, SocketType socktype);
+
+int unix_listen(const char *path, char *ostr, int olen);
+int unix_connect(const char *path);
+
+/* Old, ipv4 only bits.  Don't use for new code. */
+int parse_host_port(SockAddress*  saddr, const char *str);
+int parse_host_src_port(SockAddress*  haddr, SockAddress*  saddr,
+                        const char *str);
+
+#endif /* QEMU__SOCKET_H */
diff --git a/readline.c b/readline.c
index 81bc491..7834af0 100644
--- a/readline.c
+++ b/readline.c
@@ -21,12 +21,8 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "qemu-common.h"
-#include "console.h"
-
-#define TERM_CMD_BUF_SIZE 4095
-#define TERM_MAX_CMDS 64
-#define NB_COMPLETIONS_MAX 256
+#include "readline.h"
+#include "monitor.h"
 
 #define IS_NORM 0
 #define IS_ESC  1
@@ -34,142 +30,112 @@
 
 #define printf do_not_use_printf
 
-static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
-static int term_cmd_buf_index;
-static int term_cmd_buf_size;
-
-static char term_last_cmd_buf[TERM_CMD_BUF_SIZE + 1];
-static int term_last_cmd_buf_index;
-static int term_last_cmd_buf_size;
-
-static int term_esc_state;
-static int term_esc_param;
-
-static char *term_history[TERM_MAX_CMDS];
-static int term_hist_entry = -1;
-
-static int nb_completions;
-int completion_index;
-static char *completions[NB_COMPLETIONS_MAX];
-
-static ReadLineFunc *term_readline_func;
-static int term_is_password;
-static char term_prompt[256];
-static void *term_readline_opaque;
-
-static void term_show_prompt2(void)
+void readline_show_prompt(ReadLineState *rs)
 {
-    term_printf("%s", term_prompt);
-    term_flush();
-    term_last_cmd_buf_index = 0;
-    term_last_cmd_buf_size = 0;
-    term_esc_state = IS_NORM;
-}
-
-static void term_show_prompt(void)
-{
-    term_show_prompt2();
-    term_cmd_buf_index = 0;
-    term_cmd_buf_size = 0;
+    monitor_printf(rs->mon, "%s", rs->prompt);
+    monitor_flush(rs->mon);
+    rs->last_cmd_buf_index = 0;
+    rs->last_cmd_buf_size = 0;
+    rs->esc_state = IS_NORM;
 }
 
 /* update the displayed command line */
-static void term_update(void)
+static void readline_update(ReadLineState *rs)
 {
     int i, delta, len;
 
-    if (term_cmd_buf_size != term_last_cmd_buf_size ||
-        memcmp(term_cmd_buf, term_last_cmd_buf, term_cmd_buf_size) != 0) {
-        for(i = 0; i < term_last_cmd_buf_index; i++) {
-            term_printf("\033[D");
+    if (rs->cmd_buf_size != rs->last_cmd_buf_size ||
+        memcmp(rs->cmd_buf, rs->last_cmd_buf, rs->cmd_buf_size) != 0) {
+        for(i = 0; i < rs->last_cmd_buf_index; i++) {
+            monitor_printf(rs->mon, "\033[D");
         }
-        term_cmd_buf[term_cmd_buf_size] = '\0';
-        if (term_is_password) {
-            len = strlen(term_cmd_buf);
+        rs->cmd_buf[rs->cmd_buf_size] = '\0';
+        if (rs->read_password) {
+            len = strlen(rs->cmd_buf);
             for(i = 0; i < len; i++)
-                term_printf("*");
+                monitor_printf(rs->mon, "*");
         } else {
-            term_printf("%s", term_cmd_buf);
+            monitor_printf(rs->mon, "%s", rs->cmd_buf);
         }
-        term_printf("\033[K");
-        memcpy(term_last_cmd_buf, term_cmd_buf, term_cmd_buf_size);
-        term_last_cmd_buf_size = term_cmd_buf_size;
-        term_last_cmd_buf_index = term_cmd_buf_size;
+        monitor_printf(rs->mon, "\033[K");
+        memcpy(rs->last_cmd_buf, rs->cmd_buf, rs->cmd_buf_size);
+        rs->last_cmd_buf_size = rs->cmd_buf_size;
+        rs->last_cmd_buf_index = rs->cmd_buf_size;
     }
-    if (term_cmd_buf_index != term_last_cmd_buf_index) {
-        delta = term_cmd_buf_index - term_last_cmd_buf_index;
+    if (rs->cmd_buf_index != rs->last_cmd_buf_index) {
+        delta = rs->cmd_buf_index - rs->last_cmd_buf_index;
         if (delta > 0) {
             for(i = 0;i < delta; i++) {
-                term_printf("\033[C");
+                monitor_printf(rs->mon, "\033[C");
             }
         } else {
             delta = -delta;
             for(i = 0;i < delta; i++) {
-                term_printf("\033[D");
+                monitor_printf(rs->mon, "\033[D");
             }
         }
-        term_last_cmd_buf_index = term_cmd_buf_index;
+        rs->last_cmd_buf_index = rs->cmd_buf_index;
     }
-    term_flush();
+    monitor_flush(rs->mon);
 }
 
-static void term_insert_char(int ch)
+static void readline_insert_char(ReadLineState *rs, int ch)
 {
-    if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
-        memmove(term_cmd_buf + term_cmd_buf_index + 1,
-                term_cmd_buf + term_cmd_buf_index,
-                term_cmd_buf_size - term_cmd_buf_index);
-        term_cmd_buf[term_cmd_buf_index] = ch;
-        term_cmd_buf_size++;
-        term_cmd_buf_index++;
+    if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) {
+        memmove(rs->cmd_buf + rs->cmd_buf_index + 1,
+                rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf_size - rs->cmd_buf_index);
+        rs->cmd_buf[rs->cmd_buf_index] = ch;
+        rs->cmd_buf_size++;
+        rs->cmd_buf_index++;
     }
 }
 
-static void term_backward_char(void)
+static void readline_backward_char(ReadLineState *rs)
 {
-    if (term_cmd_buf_index > 0) {
-        term_cmd_buf_index--;
+    if (rs->cmd_buf_index > 0) {
+        rs->cmd_buf_index--;
     }
 }
 
-static void term_forward_char(void)
+static void readline_forward_char(ReadLineState *rs)
 {
-    if (term_cmd_buf_index < term_cmd_buf_size) {
-        term_cmd_buf_index++;
+    if (rs->cmd_buf_index < rs->cmd_buf_size) {
+        rs->cmd_buf_index++;
     }
 }
 
-static void term_delete_char(void)
+static void readline_delete_char(ReadLineState *rs)
 {
-    if (term_cmd_buf_index < term_cmd_buf_size) {
-        memmove(term_cmd_buf + term_cmd_buf_index,
-                term_cmd_buf + term_cmd_buf_index + 1,
-                term_cmd_buf_size - term_cmd_buf_index - 1);
-        term_cmd_buf_size--;
+    if (rs->cmd_buf_index < rs->cmd_buf_size) {
+        memmove(rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf + rs->cmd_buf_index + 1,
+                rs->cmd_buf_size - rs->cmd_buf_index - 1);
+        rs->cmd_buf_size--;
     }
 }
 
-static void term_backspace(void)
+static void readline_backspace(ReadLineState *rs)
 {
-    if (term_cmd_buf_index > 0) {
-        term_backward_char();
-        term_delete_char();
+    if (rs->cmd_buf_index > 0) {
+        readline_backward_char(rs);
+        readline_delete_char(rs);
     }
 }
 
-static void term_backword(void)
+static void readline_backword(ReadLineState *rs)
 {
     int start;
 
-    if (term_cmd_buf_index == 0 || term_cmd_buf_index > term_cmd_buf_size) {
+    if (rs->cmd_buf_index == 0 || rs->cmd_buf_index > rs->cmd_buf_size) {
         return;
     }
 
-    start = term_cmd_buf_index - 1;
+    start = rs->cmd_buf_index - 1;
 
     /* find first word (backwards) */
     while (start > 0) {
-        if (!isspace(term_cmd_buf[start])) {
+        if (!qemu_isspace(rs->cmd_buf[start])) {
             break;
         }
 
@@ -178,7 +144,7 @@
 
     /* find first space (backwards) */
     while (start > 0) {
-        if (isspace(term_cmd_buf[start])) {
+        if (qemu_isspace(rs->cmd_buf[start])) {
             ++start;
             break;
         }
@@ -187,61 +153,63 @@
     }
 
     /* remove word */
-    if (start < term_cmd_buf_index) {
-        memmove(term_cmd_buf + start,
-                term_cmd_buf + term_cmd_buf_index,
-                term_cmd_buf_size - term_cmd_buf_index);
-        term_cmd_buf_size -= term_cmd_buf_index - start;
-        term_cmd_buf_index = start;
+    if (start < rs->cmd_buf_index) {
+        memmove(rs->cmd_buf + start,
+                rs->cmd_buf + rs->cmd_buf_index,
+                rs->cmd_buf_size - rs->cmd_buf_index);
+        rs->cmd_buf_size -= rs->cmd_buf_index - start;
+        rs->cmd_buf_index = start;
     }
 }
 
-static void term_bol(void)
+static void readline_bol(ReadLineState *rs)
 {
-    term_cmd_buf_index = 0;
+    rs->cmd_buf_index = 0;
 }
 
-static void term_eol(void)
+static void readline_eol(ReadLineState *rs)
 {
-    term_cmd_buf_index = term_cmd_buf_size;
+    rs->cmd_buf_index = rs->cmd_buf_size;
 }
 
-static void term_up_char(void)
+static void readline_up_char(ReadLineState *rs)
 {
     int idx;
 
-    if (term_hist_entry == 0)
+    if (rs->hist_entry == 0)
 	return;
-    if (term_hist_entry == -1) {
+    if (rs->hist_entry == -1) {
 	/* Find latest entry */
-	for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
-	    if (term_history[idx] == NULL)
+	for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
+	    if (rs->history[idx] == NULL)
 		break;
 	}
-	term_hist_entry = idx;
+	rs->hist_entry = idx;
     }
-    term_hist_entry--;
-    if (term_hist_entry >= 0) {
-	pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
-                term_history[term_hist_entry]);
-	term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
+    rs->hist_entry--;
+    if (rs->hist_entry >= 0) {
+	pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
+                rs->history[rs->hist_entry]);
+	rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
     }
 }
 
-static void term_down_char(void)
+static void readline_down_char(ReadLineState *rs)
 {
-    if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1)
-	return;
-    if (term_history[++term_hist_entry] != NULL) {
-	pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
-                term_history[term_hist_entry]);
+    if (rs->hist_entry == -1)
+        return;
+    if (rs->hist_entry < READLINE_MAX_CMDS - 1 &&
+        rs->history[++rs->hist_entry] != NULL) {
+	pstrcpy(rs->cmd_buf, sizeof(rs->cmd_buf),
+                rs->history[rs->hist_entry]);
     } else {
-	term_hist_entry = -1;
+        rs->cmd_buf[0] = 0;
+	rs->hist_entry = -1;
     }
-    term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
+    rs->cmd_buf_index = rs->cmd_buf_size = strlen(rs->cmd_buf);
 }
 
-static void term_hist_add(const char *cmdline)
+static void readline_hist_add(ReadLineState *rs, const char *cmdline)
 {
     char *hist_entry, *new_entry;
     int idx;
@@ -249,95 +217,99 @@
     if (cmdline[0] == '\0')
 	return;
     new_entry = NULL;
-    if (term_hist_entry != -1) {
+    if (rs->hist_entry != -1) {
 	/* We were editing an existing history entry: replace it */
-	hist_entry = term_history[term_hist_entry];
-	idx = term_hist_entry;
+	hist_entry = rs->history[rs->hist_entry];
+	idx = rs->hist_entry;
 	if (strcmp(hist_entry, cmdline) == 0) {
 	    goto same_entry;
 	}
     }
     /* Search cmdline in history buffers */
-    for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
-	hist_entry = term_history[idx];
+    for (idx = 0; idx < READLINE_MAX_CMDS; idx++) {
+	hist_entry = rs->history[idx];
 	if (hist_entry == NULL)
 	    break;
 	if (strcmp(hist_entry, cmdline) == 0) {
 	same_entry:
 	    new_entry = hist_entry;
 	    /* Put this entry at the end of history */
-	    memmove(&term_history[idx], &term_history[idx + 1],
-		    (TERM_MAX_CMDS - idx + 1) * sizeof(char *));
-	    term_history[TERM_MAX_CMDS - 1] = NULL;
-	    for (; idx < TERM_MAX_CMDS; idx++) {
-		if (term_history[idx] == NULL)
+	    memmove(&rs->history[idx], &rs->history[idx + 1],
+		    (READLINE_MAX_CMDS - idx + 1) * sizeof(char *));
+	    rs->history[READLINE_MAX_CMDS - 1] = NULL;
+	    for (; idx < READLINE_MAX_CMDS; idx++) {
+		if (rs->history[idx] == NULL)
 		    break;
 	    }
 	    break;
 	}
     }
-    if (idx == TERM_MAX_CMDS) {
+    if (idx == READLINE_MAX_CMDS) {
 	/* Need to get one free slot */
-	free(term_history[0]);
-	memcpy(term_history, &term_history[1],
-	       (TERM_MAX_CMDS - 1) * sizeof(char *));
-	term_history[TERM_MAX_CMDS - 1] = NULL;
-	idx = TERM_MAX_CMDS - 1;
+	free(rs->history[0]);
+	memcpy(rs->history, &rs->history[1],
+	       (READLINE_MAX_CMDS - 1) * sizeof(char *));
+	rs->history[READLINE_MAX_CMDS - 1] = NULL;
+	idx = READLINE_MAX_CMDS - 1;
     }
     if (new_entry == NULL)
 	new_entry = strdup(cmdline);
-    term_history[idx] = new_entry;
-    term_hist_entry = -1;
+    rs->history[idx] = new_entry;
+    rs->hist_entry = -1;
 }
 
 /* completion support */
 
-void add_completion(const char *str)
+void readline_add_completion(ReadLineState *rs, const char *str)
 {
-    if (nb_completions < NB_COMPLETIONS_MAX) {
-        completions[nb_completions++] = qemu_strdup(str);
+    if (rs->nb_completions < READLINE_MAX_COMPLETIONS) {
+        rs->completions[rs->nb_completions++] = qemu_strdup(str);
     }
 }
 
-static void term_completion(void)
+void readline_set_completion_index(ReadLineState *rs, int index)
 {
+    rs->completion_index = index;
+}
+
+static void readline_completion(ReadLineState *rs)
+{
+    Monitor *mon = cur_mon;
     int len, i, j, max_width, nb_cols, max_prefix;
     char *cmdline;
 
-    nb_completions = 0;
+    rs->nb_completions = 0;
 
-    cmdline = qemu_malloc(term_cmd_buf_index + 1);
-    if (!cmdline)
-        return;
-    memcpy(cmdline, term_cmd_buf, term_cmd_buf_index);
-    cmdline[term_cmd_buf_index] = '\0';
-    readline_find_completion(cmdline);
+    cmdline = qemu_malloc(rs->cmd_buf_index + 1);
+    memcpy(cmdline, rs->cmd_buf, rs->cmd_buf_index);
+    cmdline[rs->cmd_buf_index] = '\0';
+    rs->completion_finder(cmdline);
     qemu_free(cmdline);
 
     /* no completion found */
-    if (nb_completions <= 0)
+    if (rs->nb_completions <= 0)
         return;
-    if (nb_completions == 1) {
-        len = strlen(completions[0]);
-        for(i = completion_index; i < len; i++) {
-            term_insert_char(completions[0][i]);
+    if (rs->nb_completions == 1) {
+        len = strlen(rs->completions[0]);
+        for(i = rs->completion_index; i < len; i++) {
+            readline_insert_char(rs, rs->completions[0][i]);
         }
         /* extra space for next argument. XXX: make it more generic */
-        if (len > 0 && completions[0][len - 1] != '/')
-            term_insert_char(' ');
+        if (len > 0 && rs->completions[0][len - 1] != '/')
+            readline_insert_char(rs, ' ');
     } else {
-        term_printf("\n");
+        monitor_printf(mon, "\n");
         max_width = 0;
         max_prefix = 0;	
-        for(i = 0; i < nb_completions; i++) {
-            len = strlen(completions[i]);
+        for(i = 0; i < rs->nb_completions; i++) {
+            len = strlen(rs->completions[i]);
             if (i==0) {
                 max_prefix = len;
             } else {
                 if (len < max_prefix)
                     max_prefix = len;
                 for(j=0; j<max_prefix; j++) {
-                    if (completions[i][j] != completions[0][j])
+                    if (rs->completions[i][j] != rs->completions[0][j])
                         max_prefix = j;
                 }
             }
@@ -345,8 +317,8 @@
                 max_width = len;
         }
         if (max_prefix > 0) 
-            for(i = completion_index; i < max_prefix; i++) {
-                term_insert_char(completions[0][i]);
+            for(i = rs->completion_index; i < max_prefix; i++) {
+                readline_insert_char(rs, rs->completions[0][i]);
             }
         max_width += 2;
         if (max_width < 10)
@@ -355,134 +327,149 @@
             max_width = 80;
         nb_cols = 80 / max_width;
         j = 0;
-        for(i = 0; i < nb_completions; i++) {
-            term_printf("%-*s", max_width, completions[i]);
-            if (++j == nb_cols || i == (nb_completions - 1)) {
-                term_printf("\n");
+        for(i = 0; i < rs->nb_completions; i++) {
+            monitor_printf(rs->mon, "%-*s", max_width, rs->completions[i]);
+            if (++j == nb_cols || i == (rs->nb_completions - 1)) {
+                monitor_printf(rs->mon, "\n");
                 j = 0;
             }
         }
-        term_show_prompt2();
+        readline_show_prompt(rs);
     }
 }
 
 /* return true if command handled */
-void readline_handle_byte(int ch)
+void readline_handle_byte(ReadLineState *rs, int ch)
 {
-    switch(term_esc_state) {
+    switch(rs->esc_state) {
     case IS_NORM:
         switch(ch) {
         case 1:
-            term_bol();
+            readline_bol(rs);
             break;
         case 4:
-            term_delete_char();
+            readline_delete_char(rs);
             break;
         case 5:
-            term_eol();
+            readline_eol(rs);
             break;
         case 9:
-            term_completion();
+            readline_completion(rs);
             break;
         case 10:
         case 13:
-            term_cmd_buf[term_cmd_buf_size] = '\0';
-            if (!term_is_password)
-                term_hist_add(term_cmd_buf);
-            term_printf("\n");
-            term_cmd_buf_index = 0;
-            term_cmd_buf_size = 0;
-            term_last_cmd_buf_index = 0;
-            term_last_cmd_buf_size = 0;
-            /* NOTE: readline_start can be called here */
-            term_readline_func(term_readline_opaque, term_cmd_buf);
+            rs->cmd_buf[rs->cmd_buf_size] = '\0';
+            if (!rs->read_password)
+                readline_hist_add(rs, rs->cmd_buf);
+            monitor_printf(rs->mon, "\n");
+            rs->cmd_buf_index = 0;
+            rs->cmd_buf_size = 0;
+            rs->last_cmd_buf_index = 0;
+            rs->last_cmd_buf_size = 0;
+            rs->readline_func(rs->mon, rs->cmd_buf, rs->readline_opaque);
             break;
         case 23:
             /* ^W */
-            term_backword();
+            readline_backword(rs);
             break;
         case 27:
-            term_esc_state = IS_ESC;
+            rs->esc_state = IS_ESC;
             break;
         case 127:
         case 8:
-            term_backspace();
+            readline_backspace(rs);
             break;
 	case 155:
-            term_esc_state = IS_CSI;
+            rs->esc_state = IS_CSI;
 	    break;
         default:
             if (ch >= 32) {
-                term_insert_char(ch);
+                readline_insert_char(rs, ch);
             }
             break;
         }
         break;
     case IS_ESC:
         if (ch == '[') {
-            term_esc_state = IS_CSI;
-            term_esc_param = 0;
+            rs->esc_state = IS_CSI;
+            rs->esc_param = 0;
         } else {
-            term_esc_state = IS_NORM;
+            rs->esc_state = IS_NORM;
         }
         break;
     case IS_CSI:
         switch(ch) {
 	case 'A':
 	case 'F':
-	    term_up_char();
+	    readline_up_char(rs);
 	    break;
 	case 'B':
 	case 'E':
-	    term_down_char();
+	    readline_down_char(rs);
 	    break;
         case 'D':
-            term_backward_char();
+            readline_backward_char(rs);
             break;
         case 'C':
-            term_forward_char();
+            readline_forward_char(rs);
             break;
         case '0' ... '9':
-            term_esc_param = term_esc_param * 10 + (ch - '0');
+            rs->esc_param = rs->esc_param * 10 + (ch - '0');
             goto the_end;
         case '~':
-            switch(term_esc_param) {
+            switch(rs->esc_param) {
             case 1:
-                term_bol();
+                readline_bol(rs);
                 break;
             case 3:
-                term_delete_char();
+                readline_delete_char(rs);
                 break;
             case 4:
-                term_eol();
+                readline_eol(rs);
                 break;
             }
             break;
         default:
             break;
         }
-        term_esc_state = IS_NORM;
+        rs->esc_state = IS_NORM;
     the_end:
         break;
     }
-    term_update();
+    readline_update(rs);
 }
 
-void readline_start(const char *prompt, int is_password,
+void readline_start(ReadLineState *rs, const char *prompt, int read_password,
                     ReadLineFunc *readline_func, void *opaque)
 {
-    pstrcpy(term_prompt, sizeof(term_prompt), prompt);
-    term_readline_func = readline_func;
-    term_readline_opaque = opaque;
-    term_is_password = is_password;
-    term_show_prompt();
+    pstrcpy(rs->prompt, sizeof(rs->prompt), prompt);
+    rs->readline_func = readline_func;
+    rs->readline_opaque = opaque;
+    rs->read_password = read_password;
+    readline_restart(rs);
 }
 
-const char *readline_get_history(unsigned int index)
+void readline_restart(ReadLineState *rs)
 {
-    if (index >= TERM_MAX_CMDS)
-        return NULL;
-    return term_history[index];
+    rs->cmd_buf_index = 0;
+    rs->cmd_buf_size = 0;
 }
 
+const char *readline_get_history(ReadLineState *rs, unsigned int index)
+{
+    if (index >= READLINE_MAX_CMDS)
+        return NULL;
+    return rs->history[index];
+}
 
+ReadLineState *readline_init(Monitor *mon,
+                             ReadLineCompletionFunc *completion_finder)
+{
+    ReadLineState *rs = qemu_mallocz(sizeof(*rs));
+
+    rs->hist_entry = -1;
+    rs->mon = mon;
+    rs->completion_finder = completion_finder;
+
+    return rs;
+}
diff --git a/readline.h b/readline.h
new file mode 100644
index 0000000..fc9806e
--- /dev/null
+++ b/readline.h
@@ -0,0 +1,55 @@
+#ifndef READLINE_H
+#define READLINE_H
+
+#include "qemu-common.h"
+
+#define READLINE_CMD_BUF_SIZE 4095
+#define READLINE_MAX_CMDS 64
+#define READLINE_MAX_COMPLETIONS 256
+
+typedef void ReadLineFunc(Monitor *mon, const char *str, void *opaque);
+typedef void ReadLineCompletionFunc(const char *cmdline);
+
+typedef struct ReadLineState {
+    char cmd_buf[READLINE_CMD_BUF_SIZE + 1];
+    int cmd_buf_index;
+    int cmd_buf_size;
+
+    char last_cmd_buf[READLINE_CMD_BUF_SIZE + 1];
+    int last_cmd_buf_index;
+    int last_cmd_buf_size;
+
+    int esc_state;
+    int esc_param;
+
+    char *history[READLINE_MAX_CMDS];
+    int hist_entry;
+
+    ReadLineCompletionFunc *completion_finder;
+    char *completions[READLINE_MAX_COMPLETIONS];
+    int nb_completions;
+    int completion_index;
+
+    ReadLineFunc *readline_func;
+    void *readline_opaque;
+    int read_password;
+    char prompt[256];
+    Monitor *mon;
+} ReadLineState;
+
+void readline_add_completion(ReadLineState *rs, const char *str);
+void readline_set_completion_index(ReadLineState *rs, int completion_index);
+
+const char *readline_get_history(ReadLineState *rs, unsigned int index);
+
+void readline_handle_byte(ReadLineState *rs, int ch);
+
+void readline_start(ReadLineState *rs, const char *prompt, int read_password,
+                    ReadLineFunc *readline_func, void *opaque);
+void readline_restart(ReadLineState *rs);
+void readline_show_prompt(ReadLineState *rs);
+
+ReadLineState *readline_init(Monitor *mon,
+                             ReadLineCompletionFunc *completion_finder);
+
+#endif /* !READLINE_H */
diff --git a/savevm.c b/savevm.c
new file mode 100644
index 0000000..1157c08
--- /dev/null
+++ b/savevm.c
@@ -0,0 +1,1409 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+/* Needed early for HOST_BSD etc. */
+#include "config-host.h"
+
+#ifndef _WIN32
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#if defined(__NetBSD__)
+#include <net/if_tap.h>
+#endif
+#ifdef __linux__
+#include <linux/if_tun.h>
+#endif
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+#ifdef HOST_BSD
+#include <sys/stat.h>
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <libutil.h>
+#else
+#include <util.h>
+#endif
+#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+#include <freebsd/stdlib.h>
+#else
+#ifdef __linux__
+#include <pty.h>
+#include <malloc.h>
+#include <linux/rtc.h>
+#endif
+#endif
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <malloc.h>
+#include <sys/timeb.h>
+#include <mmsystem.h>
+#define getopt_long_only getopt_long
+#define memalign(align, size) malloc(size)
+#endif
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "net.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "block.h"
+#include "audio/audio.h"
+#include "migration.h"
+#include "qemu_socket.h"
+#include "qemu_file.h"
+
+/* point to the block driver where the snapshots are managed */
+static BlockDriverState *bs_snapshots;
+
+#define SELF_ANNOUNCE_ROUNDS 5
+#define ETH_P_EXPERIMENTAL 0x01F1 /* just a number */
+//#define ETH_P_EXPERIMENTAL 0x0012 /* make it the size of the packet */
+#define EXPERIMENTAL_MAGIC 0xf1f23f4f
+
+static int announce_self_create(uint8_t *buf, 
+				uint8_t *mac_addr)
+{
+    uint32_t magic = EXPERIMENTAL_MAGIC;
+    uint16_t proto = htons(ETH_P_EXPERIMENTAL);
+
+    /* FIXME: should we send a different packet (arp/rarp/ping)? */
+
+    memset(buf, 0, 64);
+    memset(buf, 0xff, 6);         /* h_dst */
+    memcpy(buf + 6, mac_addr, 6); /* h_src */
+    memcpy(buf + 12, &proto, 2);  /* h_proto */
+    memcpy(buf + 14, &magic, 4);  /* magic */
+
+    return 64; /* len */
+}
+
+static void qemu_announce_self_once(void *opaque)
+{
+    int i, len;
+    VLANState *vlan;
+    VLANClientState *vc;
+    uint8_t buf[256];
+    static int count = SELF_ANNOUNCE_ROUNDS;
+    QEMUTimer *timer = *(QEMUTimer **)opaque;
+
+    for (i = 0; i < MAX_NICS; i++) {
+        if (!nd_table[i].used)
+            continue;
+        len = announce_self_create(buf, nd_table[i].macaddr);
+        vlan = nd_table[i].vlan;
+	for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
+            vc->receive(vc, buf, len);
+        }
+    }
+    if (count--) {
+	    qemu_mod_timer(timer, qemu_get_clock(rt_clock) + 100);
+    } else {
+	    qemu_del_timer(timer);
+	    qemu_free_timer(timer);
+    }
+}
+
+void qemu_announce_self(void)
+{
+	static QEMUTimer *timer;
+	timer = qemu_new_timer(rt_clock, qemu_announce_self_once, &timer);
+	qemu_announce_self_once(&timer);
+}
+
+/***********************************************************/
+/* savevm/loadvm support */
+
+#define IO_BUF_SIZE 32768
+
+struct QEMUFile {
+    QEMUFilePutBufferFunc *put_buffer;
+    QEMUFileGetBufferFunc *get_buffer;
+    QEMUFileCloseFunc *close;
+    QEMUFileRateLimit *rate_limit;
+    QEMUFileSetRateLimit *set_rate_limit;
+    void *opaque;
+    int is_write;
+
+    int64_t buf_offset; /* start of buffer when writing, end of buffer
+                           when reading */
+    int buf_index;
+    int buf_size; /* 0 when writing */
+    uint8_t buf[IO_BUF_SIZE];
+
+    int has_error;
+};
+
+typedef struct QEMUFilePopen
+{
+    FILE *popen_file;
+    QEMUFile *file;
+} QEMUFilePopen;
+
+typedef struct QEMUFileSocket
+{
+    int fd;
+    QEMUFile *file;
+} QEMUFileSocket;
+
+static int file_socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileSocket *s = opaque;
+    ssize_t len;
+
+    do {
+        len = recv(s->fd, (void *)buf, size, 0);
+    } while (len == -1 && socket_error() == EINTR);
+
+    if (len == -1)
+        len = -socket_error();
+
+    return len;
+}
+
+static int file_socket_close(void *opaque)
+{
+    QEMUFileSocket *s = opaque;
+    qemu_free(s);
+    return 0;
+}
+
+static int popen_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFilePopen *s = opaque;
+    return fwrite(buf, 1, size, s->popen_file);
+}
+
+static int popen_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFilePopen *s = opaque;
+    FILE *fp = s->popen_file;
+    int bytes;
+
+    do {
+        clearerr(fp);
+        bytes = fread(buf, 1, size, fp);
+    } while ((bytes == 0) && ferror(fp) && (errno == EINTR));
+    return bytes;
+}
+
+static int popen_close(void *opaque)
+{
+    QEMUFilePopen *s = opaque;
+    pclose(s->popen_file);
+    qemu_free(s);
+    return 0;
+}
+
+QEMUFile *qemu_popen(FILE *popen_file, const char *mode)
+{
+    QEMUFilePopen *s;
+
+    if (popen_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
+        fprintf(stderr, "qemu_popen: Argument validity check failed\n");
+        return NULL;
+    }
+
+    s = qemu_mallocz(sizeof(QEMUFilePopen));
+
+    s->popen_file = popen_file;
+
+    if(mode[0] == 'r') {
+        s->file = qemu_fopen_ops(s, NULL, popen_get_buffer, popen_close, NULL, NULL);
+    } else {
+        s->file = qemu_fopen_ops(s, popen_put_buffer, NULL, popen_close, NULL, NULL);
+    }
+    return s->file;
+}
+
+QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
+{
+    FILE *popen_file;
+
+    popen_file = popen(command, mode);
+    if(popen_file == NULL) {
+        return NULL;
+    }
+
+    return qemu_popen(popen_file, mode);
+}
+
+int qemu_popen_fd(QEMUFile *f)
+{
+    QEMUFilePopen *p;
+    int fd;
+
+    p = (QEMUFilePopen *)f->opaque;
+    fd = fileno(p->popen_file);
+
+    return fd;
+}
+
+QEMUFile *qemu_fopen_socket(int fd)
+{
+    QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
+
+    s->fd = fd;
+    s->file = qemu_fopen_ops(s, NULL, file_socket_get_buffer, file_socket_close, NULL, NULL);
+    return s->file;
+}
+
+typedef struct QEMUFileStdio
+{
+    FILE *outfile;
+} QEMUFileStdio;
+
+static int file_put_buffer(void *opaque, const uint8_t *buf,
+                            int64_t pos, int size)
+{
+    QEMUFileStdio *s = opaque;
+    fseek(s->outfile, pos, SEEK_SET);
+    fwrite(buf, 1, size, s->outfile);
+    return size;
+}
+
+static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileStdio *s = opaque;
+    fseek(s->outfile, pos, SEEK_SET);
+    return fread(buf, 1, size, s->outfile);
+}
+
+static int file_close(void *opaque)
+{
+    QEMUFileStdio *s = opaque;
+    fclose(s->outfile);
+    qemu_free(s);
+    return 0;
+}
+
+QEMUFile *qemu_fopen(const char *filename, const char *mode)
+{
+    QEMUFileStdio *s;
+
+    s = qemu_mallocz(sizeof(QEMUFileStdio));
+
+    s->outfile = fopen(filename, mode);
+    if (!s->outfile)
+        goto fail;
+
+    if (!strcmp(mode, "wb"))
+        return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL, NULL);
+    else if (!strcmp(mode, "rb"))
+        return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL, NULL);
+
+fail:
+    if (s->outfile)
+        fclose(s->outfile);
+    qemu_free(s);
+    return NULL;
+}
+
+typedef struct QEMUFileBdrv
+{
+    BlockDriverState *bs;
+    int64_t base_offset;
+} QEMUFileBdrv;
+
+static int block_put_buffer(void *opaque, const uint8_t *buf,
+                           int64_t pos, int size)
+{
+    QEMUFileBdrv *s = opaque;
+    bdrv_put_buffer(s->bs, buf, s->base_offset + pos, size);
+    return size;
+}
+
+static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+{
+    QEMUFileBdrv *s = opaque;
+    return bdrv_get_buffer(s->bs, buf, s->base_offset + pos, size);
+}
+
+static int bdrv_fclose(void *opaque)
+{
+    QEMUFileBdrv *s = opaque;
+    qemu_free(s);
+    return 0;
+}
+
+static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
+{
+    QEMUFileBdrv *s;
+
+    s = qemu_mallocz(sizeof(QEMUFileBdrv));
+
+    s->bs = bs;
+    s->base_offset = offset;
+
+    if (is_writable)
+        return qemu_fopen_ops(s, block_put_buffer, NULL, bdrv_fclose, NULL, NULL);
+
+    return qemu_fopen_ops(s, NULL, block_get_buffer, bdrv_fclose, NULL, NULL);
+}
+
+QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
+                         QEMUFileGetBufferFunc *get_buffer,
+                         QEMUFileCloseFunc *close,
+                         QEMUFileRateLimit *rate_limit,
+                         QEMUFileSetRateLimit *set_rate_limit)
+{
+    QEMUFile *f;
+
+    f = qemu_mallocz(sizeof(QEMUFile));
+
+    f->opaque = opaque;
+    f->put_buffer = put_buffer;
+    f->get_buffer = get_buffer;
+    f->close = close;
+    f->rate_limit = rate_limit;
+    f->set_rate_limit = set_rate_limit;
+    f->is_write = 0;
+
+    return f;
+}
+
+int qemu_file_has_error(QEMUFile *f)
+{
+    return f->has_error;
+}
+
+void qemu_file_set_error(QEMUFile *f)
+{
+    f->has_error = 1;
+}
+
+void qemu_fflush(QEMUFile *f)
+{
+    if (!f->put_buffer)
+        return;
+
+    if (f->is_write && f->buf_index > 0) {
+        int len;
+
+        len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
+        if (len > 0)
+            f->buf_offset += f->buf_index;
+        else
+            f->has_error = 1;
+        f->buf_index = 0;
+    }
+}
+
+static void qemu_fill_buffer(QEMUFile *f)
+{
+    int len;
+
+    if (!f->get_buffer)
+        return;
+
+    if (f->is_write)
+        abort();
+
+    len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE);
+    if (len > 0) {
+        f->buf_index = 0;
+        f->buf_size = len;
+        f->buf_offset += len;
+    } else if (len != -EAGAIN)
+        f->has_error = 1;
+}
+
+int qemu_fclose(QEMUFile *f)
+{
+    int ret = 0;
+    qemu_fflush(f);
+    if (f->close)
+        ret = f->close(f->opaque);
+    qemu_free(f);
+    return ret;
+}
+
+void qemu_file_put_notify(QEMUFile *f)
+{
+    f->put_buffer(f->opaque, NULL, 0, 0);
+}
+
+void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
+{
+    int l;
+
+    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+        fprintf(stderr,
+                "Attempted to write to buffer while read buffer is not empty\n");
+        abort();
+    }
+
+    while (!f->has_error && size > 0) {
+        l = IO_BUF_SIZE - f->buf_index;
+        if (l > size)
+            l = size;
+        memcpy(f->buf + f->buf_index, buf, l);
+        f->is_write = 1;
+        f->buf_index += l;
+        buf += l;
+        size -= l;
+        if (f->buf_index >= IO_BUF_SIZE)
+            qemu_fflush(f);
+    }
+}
+
+void qemu_put_byte(QEMUFile *f, int v)
+{
+    if (!f->has_error && f->is_write == 0 && f->buf_index > 0) {
+        fprintf(stderr,
+                "Attempted to write to buffer while read buffer is not empty\n");
+        abort();
+    }
+
+    f->buf[f->buf_index++] = v;
+    f->is_write = 1;
+    if (f->buf_index >= IO_BUF_SIZE)
+        qemu_fflush(f);
+}
+
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
+{
+    int size, l;
+
+    if (f->is_write)
+        abort();
+
+    size = size1;
+    while (size > 0) {
+        l = f->buf_size - f->buf_index;
+        if (l == 0) {
+            qemu_fill_buffer(f);
+            l = f->buf_size - f->buf_index;
+            if (l == 0)
+                break;
+        }
+        if (l > size)
+            l = size;
+        memcpy(buf, f->buf + f->buf_index, l);
+        f->buf_index += l;
+        buf += l;
+        size -= l;
+    }
+    return size1 - size;
+}
+
+int qemu_get_byte(QEMUFile *f)
+{
+    if (f->is_write)
+        abort();
+
+    if (f->buf_index >= f->buf_size) {
+        qemu_fill_buffer(f);
+        if (f->buf_index >= f->buf_size)
+            return 0;
+    }
+    return f->buf[f->buf_index++];
+}
+
+int64_t qemu_ftell(QEMUFile *f)
+{
+    return f->buf_offset - f->buf_size + f->buf_index;
+}
+
+int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
+{
+    if (whence == SEEK_SET) {
+        /* nothing to do */
+    } else if (whence == SEEK_CUR) {
+        pos += qemu_ftell(f);
+    } else {
+        /* SEEK_END not supported */
+        return -1;
+    }
+    if (f->put_buffer) {
+        qemu_fflush(f);
+        f->buf_offset = pos;
+    } else {
+        f->buf_offset = pos;
+        f->buf_index = 0;
+        f->buf_size = 0;
+    }
+    return pos;
+}
+
+int qemu_file_rate_limit(QEMUFile *f)
+{
+    if (f->rate_limit)
+        return f->rate_limit(f->opaque);
+
+    return 0;
+}
+
+size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate)
+{
+    if (f->set_rate_limit)
+        return f->set_rate_limit(f->opaque, new_rate);
+
+    return 0;
+}
+
+void qemu_put_be16(QEMUFile *f, unsigned int v)
+{
+    qemu_put_byte(f, v >> 8);
+    qemu_put_byte(f, v);
+}
+
+void qemu_put_be32(QEMUFile *f, unsigned int v)
+{
+    qemu_put_byte(f, v >> 24);
+    qemu_put_byte(f, v >> 16);
+    qemu_put_byte(f, v >> 8);
+    qemu_put_byte(f, v);
+}
+
+void qemu_put_be64(QEMUFile *f, uint64_t v)
+{
+    qemu_put_be32(f, v >> 32);
+    qemu_put_be32(f, v);
+}
+
+unsigned int qemu_get_be16(QEMUFile *f)
+{
+    unsigned int v;
+    v = qemu_get_byte(f) << 8;
+    v |= qemu_get_byte(f);
+    return v;
+}
+
+unsigned int qemu_get_be32(QEMUFile *f)
+{
+    unsigned int v;
+    v = qemu_get_byte(f) << 24;
+    v |= qemu_get_byte(f) << 16;
+    v |= qemu_get_byte(f) << 8;
+    v |= qemu_get_byte(f);
+    return v;
+}
+
+uint64_t qemu_get_be64(QEMUFile *f)
+{
+    uint64_t v;
+    v = (uint64_t)qemu_get_be32(f) << 32;
+    v |= qemu_get_be32(f);
+    return v;
+}
+
+void  qemu_put_struct(QEMUFile*  f, const QField*  fields, const void*  s)
+{
+    const QField*  qf = fields;
+
+    for (;;) {
+        uint8_t*  p = (uint8_t*)s + qf->offset;
+
+        switch (qf->type) {
+            case Q_FIELD_END:
+                break;
+            case Q_FIELD_BYTE:
+                qemu_put_byte(f, p[0]);
+                break;
+            case Q_FIELD_INT16:
+                qemu_put_be16(f, ((uint16_t*)p)[0]);
+                break;
+            case Q_FIELD_INT32:
+                qemu_put_be32(f, ((uint32_t*)p)[0]);
+                break;
+            case Q_FIELD_INT64:
+                qemu_put_be64(f, ((uint64_t*)p)[0]);
+                break;
+            case Q_FIELD_BUFFER:
+                if (fields[1].type != Q_FIELD_BUFFER_SIZE ||
+                    fields[2].type != Q_FIELD_BUFFER_SIZE)
+                {
+                    fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n",
+                            __FUNCTION__ );
+                    exit(1);
+                }
+                else
+                {
+                    uint32_t  size = ((uint32_t)fields[1].offset << 16) | (uint32_t)fields[2].offset;
+
+                    qemu_put_buffer(f, p, size);
+                    qf += 2;
+                }
+                break;
+            default:
+                fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
+                exit(1);
+        }
+        qf++;
+    }
+}
+
+int   qemu_get_struct(QEMUFile*  f, const QField*  fields, void*  s)
+{
+    const QField*  qf = fields;
+
+    for (;;) {
+        uint8_t*  p = (uint8_t*)s + qf->offset;
+
+        switch (qf->type) {
+            case Q_FIELD_END:
+                break;
+            case Q_FIELD_BYTE:
+                p[0] = qemu_get_byte(f);
+                break;
+            case Q_FIELD_INT16:
+                ((uint16_t*)p)[0] = qemu_get_be16(f);
+                break;
+            case Q_FIELD_INT32:
+                ((uint32_t*)p)[0] = qemu_get_be32(f);
+                break;
+            case Q_FIELD_INT64:
+                ((uint64_t*)p)[0] = qemu_get_be64(f);
+                break;
+            case Q_FIELD_BUFFER:
+                if (fields[1].type != Q_FIELD_BUFFER_SIZE ||
+                    fields[2].type != Q_FIELD_BUFFER_SIZE)
+                {
+                    fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n",
+                            __FUNCTION__ );
+                    return -1;
+                }
+                else
+                {
+                    uint32_t  size = ((uint32_t)fields[1].offset << 16) | (uint32_t)fields[2].offset;
+                    int       ret  = qemu_get_buffer(f, p, size);
+
+                    if (ret != size) {
+                        fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__);
+                        return -1;
+                    }
+                    qf += 2;
+                }
+                break;
+            default:
+                fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
+                exit(1);
+        }
+        qf++;
+    }
+    return 0;
+}
+
+typedef struct SaveStateEntry {
+    char idstr[256];
+    int instance_id;
+    int version_id;
+    int section_id;
+    SaveLiveStateHandler *save_live_state;
+    SaveStateHandler *save_state;
+    LoadStateHandler *load_state;
+    void *opaque;
+    struct SaveStateEntry *next;
+} SaveStateEntry;
+
+static SaveStateEntry *first_se;
+
+/* TODO: Individual devices generally have very little idea about the rest
+   of the system, so instance_id should be removed/replaced.
+   Meanwhile pass -1 as instance_id if you do not already have a clearly
+   distinguishing id for all instances of your device class. */
+int register_savevm_live(const char *idstr,
+                         int instance_id,
+                         int version_id,
+                         SaveLiveStateHandler *save_live_state,
+                         SaveStateHandler *save_state,
+                         LoadStateHandler *load_state,
+                         void *opaque)
+{
+    SaveStateEntry *se, **pse;
+    static int global_section_id;
+
+    se = qemu_malloc(sizeof(SaveStateEntry));
+    pstrcpy(se->idstr, sizeof(se->idstr), idstr);
+    se->instance_id = (instance_id == -1) ? 0 : instance_id;
+    se->version_id = version_id;
+    se->section_id = global_section_id++;
+    se->save_live_state = save_live_state;
+    se->save_state = save_state;
+    se->load_state = load_state;
+    se->opaque = opaque;
+    se->next = NULL;
+
+    /* add at the end of list */
+    pse = &first_se;
+    while (*pse != NULL) {
+        if (instance_id == -1
+                && strcmp(se->idstr, (*pse)->idstr) == 0
+                && se->instance_id <= (*pse)->instance_id)
+            se->instance_id = (*pse)->instance_id + 1;
+        pse = &(*pse)->next;
+    }
+    *pse = se;
+    return 0;
+}
+
+int register_savevm(const char *idstr,
+                    int instance_id,
+                    int version_id,
+                    SaveStateHandler *save_state,
+                    LoadStateHandler *load_state,
+                    void *opaque)
+{
+    return register_savevm_live(idstr, instance_id, version_id,
+                                NULL, save_state, load_state, opaque);
+}
+
+void unregister_savevm(const char *idstr, void *opaque)
+{
+    SaveStateEntry **pse;
+
+    pse = &first_se;
+    while (*pse != NULL) {
+        if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) {
+            SaveStateEntry *next = (*pse)->next;
+            qemu_free(*pse);
+            *pse = next;
+            continue;
+        }
+        pse = &(*pse)->next;
+    }
+}
+
+#define QEMU_VM_FILE_MAGIC           0x5145564d
+#define QEMU_VM_FILE_VERSION_COMPAT  0x00000002
+#define QEMU_VM_FILE_VERSION         0x00000003
+
+#define QEMU_VM_EOF                  0x00
+#define QEMU_VM_SECTION_START        0x01
+#define QEMU_VM_SECTION_PART         0x02
+#define QEMU_VM_SECTION_END          0x03
+#define QEMU_VM_SECTION_FULL         0x04
+
+int qemu_savevm_state_begin(QEMUFile *f)
+{
+    SaveStateEntry *se;
+
+    qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
+    qemu_put_be32(f, QEMU_VM_FILE_VERSION);
+
+    for (se = first_se; se != NULL; se = se->next) {
+        int len;
+
+        if (se->save_live_state == NULL)
+            continue;
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_START);
+        qemu_put_be32(f, se->section_id);
+
+        /* ID string */
+        len = strlen(se->idstr);
+        qemu_put_byte(f, len);
+        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+
+        qemu_put_be32(f, se->instance_id);
+        qemu_put_be32(f, se->version_id);
+
+        se->save_live_state(f, QEMU_VM_SECTION_START, se->opaque);
+    }
+
+    if (qemu_file_has_error(f))
+        return -EIO;
+
+    return 0;
+}
+
+int qemu_savevm_state_iterate(QEMUFile *f)
+{
+    SaveStateEntry *se;
+    int ret = 1;
+
+    for (se = first_se; se != NULL; se = se->next) {
+        if (se->save_live_state == NULL)
+            continue;
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_PART);
+        qemu_put_be32(f, se->section_id);
+
+        ret &= !!se->save_live_state(f, QEMU_VM_SECTION_PART, se->opaque);
+    }
+
+    if (ret)
+        return 1;
+
+    if (qemu_file_has_error(f))
+        return -EIO;
+
+    return 0;
+}
+
+int qemu_savevm_state_complete(QEMUFile *f)
+{
+    SaveStateEntry *se;
+
+    for (se = first_se; se != NULL; se = se->next) {
+        if (se->save_live_state == NULL)
+            continue;
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_END);
+        qemu_put_be32(f, se->section_id);
+
+        se->save_live_state(f, QEMU_VM_SECTION_END, se->opaque);
+    }
+
+    for(se = first_se; se != NULL; se = se->next) {
+        int len;
+
+	if (se->save_state == NULL)
+	    continue;
+
+        /* Section type */
+        qemu_put_byte(f, QEMU_VM_SECTION_FULL);
+        qemu_put_be32(f, se->section_id);
+
+        /* ID string */
+        len = strlen(se->idstr);
+        qemu_put_byte(f, len);
+        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+
+        qemu_put_be32(f, se->instance_id);
+        qemu_put_be32(f, se->version_id);
+
+        se->save_state(f, se->opaque);
+    }
+
+    qemu_put_byte(f, QEMU_VM_EOF);
+
+    if (qemu_file_has_error(f))
+        return -EIO;
+
+    return 0;
+}
+
+int qemu_savevm_state(QEMUFile *f)
+{
+    int saved_vm_running;
+    int ret;
+
+    saved_vm_running = vm_running;
+    vm_stop(0);
+
+    bdrv_flush_all();
+
+    ret = qemu_savevm_state_begin(f);
+    if (ret < 0)
+        goto out;
+
+    do {
+        ret = qemu_savevm_state_iterate(f);
+        if (ret < 0)
+            goto out;
+    } while (ret == 0);
+
+    ret = qemu_savevm_state_complete(f);
+
+out:
+    if (qemu_file_has_error(f))
+        ret = -EIO;
+
+    if (!ret && saved_vm_running)
+        vm_start();
+
+    return ret;
+}
+
+static SaveStateEntry *find_se(const char *idstr, int instance_id)
+{
+    SaveStateEntry *se;
+
+    for(se = first_se; se != NULL; se = se->next) {
+        if (!strcmp(se->idstr, idstr) &&
+            instance_id == se->instance_id)
+            return se;
+    }
+    return NULL;
+}
+
+typedef struct LoadStateEntry {
+    SaveStateEntry *se;
+    int section_id;
+    int version_id;
+    struct LoadStateEntry *next;
+} LoadStateEntry;
+
+static int qemu_loadvm_state_v2(QEMUFile *f)
+{
+    SaveStateEntry *se;
+    int len, ret, instance_id, record_len, version_id;
+    int64_t total_len, end_pos, cur_pos;
+    char idstr[256];
+
+    total_len = qemu_get_be64(f);
+    end_pos = total_len + qemu_ftell(f);
+    for(;;) {
+        if (qemu_ftell(f) >= end_pos)
+            break;
+        len = qemu_get_byte(f);
+        qemu_get_buffer(f, (uint8_t *)idstr, len);
+        idstr[len] = '\0';
+        instance_id = qemu_get_be32(f);
+        version_id = qemu_get_be32(f);
+        record_len = qemu_get_be32(f);
+        cur_pos = qemu_ftell(f);
+        se = find_se(idstr, instance_id);
+        if (!se) {
+            fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
+                    instance_id, idstr);
+        } else {
+            ret = se->load_state(f, se->opaque, version_id);
+            if (ret < 0) {
+                fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
+                        instance_id, idstr);
+                return ret;
+            }
+        }
+        /* always seek to exact end of record */
+        qemu_fseek(f, cur_pos + record_len, SEEK_SET);
+    }
+
+    if (qemu_file_has_error(f))
+        return -EIO;
+
+    return 0;
+}
+
+int qemu_loadvm_state(QEMUFile *f)
+{
+    LoadStateEntry *first_le = NULL;
+    uint8_t section_type;
+    unsigned int v;
+    int ret;
+
+    v = qemu_get_be32(f);
+    if (v != QEMU_VM_FILE_MAGIC)
+        return -EINVAL;
+
+    v = qemu_get_be32(f);
+    if (v == QEMU_VM_FILE_VERSION_COMPAT)
+        return qemu_loadvm_state_v2(f);
+    if (v != QEMU_VM_FILE_VERSION)
+        return -ENOTSUP;
+
+    while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
+        uint32_t instance_id, version_id, section_id;
+        LoadStateEntry *le;
+        SaveStateEntry *se;
+        char idstr[257];
+        int len;
+
+        switch (section_type) {
+        case QEMU_VM_SECTION_START:
+        case QEMU_VM_SECTION_FULL:
+            /* Read section start */
+            section_id = qemu_get_be32(f);
+            len = qemu_get_byte(f);
+            qemu_get_buffer(f, (uint8_t *)idstr, len);
+            idstr[len] = 0;
+            instance_id = qemu_get_be32(f);
+            version_id = qemu_get_be32(f);
+
+            /* Find savevm section */
+            se = find_se(idstr, instance_id);
+            if (se == NULL) {
+                fprintf(stderr, "Unknown savevm section or instance '%s' %d\n", idstr, instance_id);
+                ret = -EINVAL;
+                goto out;
+            }
+
+            /* Validate version */
+            if (version_id > se->version_id) {
+                fprintf(stderr, "savevm: unsupported version %d for '%s' v%d\n",
+                        version_id, idstr, se->version_id);
+                ret = -EINVAL;
+                goto out;
+            }
+
+            /* Add entry */
+            le = qemu_mallocz(sizeof(*le));
+
+            le->se = se;
+            le->section_id = section_id;
+            le->version_id = version_id;
+            le->next = first_le;
+            first_le = le;
+
+            le->se->load_state(f, le->se->opaque, le->version_id);
+            break;
+        case QEMU_VM_SECTION_PART:
+        case QEMU_VM_SECTION_END:
+            section_id = qemu_get_be32(f);
+
+            for (le = first_le; le && le->section_id != section_id; le = le->next);
+            if (le == NULL) {
+                fprintf(stderr, "Unknown savevm section %d\n", section_id);
+                ret = -EINVAL;
+                goto out;
+            }
+
+            le->se->load_state(f, le->se->opaque, le->version_id);
+            break;
+        default:
+            fprintf(stderr, "Unknown savevm section type %d\n", section_type);
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    ret = 0;
+
+out:
+    while (first_le) {
+        LoadStateEntry *le = first_le;
+        first_le = first_le->next;
+        qemu_free(le);
+    }
+
+    if (qemu_file_has_error(f))
+        ret = -EIO;
+
+    return ret;
+}
+
+/* device can contain snapshots */
+static int bdrv_can_snapshot(BlockDriverState *bs)
+{
+    return (bs &&
+            !bdrv_is_removable(bs) &&
+            !bdrv_is_read_only(bs));
+}
+
+/* device must be snapshots in order to have a reliable snapshot */
+static int bdrv_has_snapshot(BlockDriverState *bs)
+{
+    return (bs &&
+            !bdrv_is_removable(bs) &&
+            !bdrv_is_read_only(bs));
+}
+
+static BlockDriverState *get_bs_snapshots(void)
+{
+    BlockDriverState *bs;
+    int i;
+
+    if (bs_snapshots)
+        return bs_snapshots;
+    for(i = 0; i <= nb_drives; i++) {
+        bs = drives_table[i].bdrv;
+        if (bdrv_can_snapshot(bs))
+            goto ok;
+    }
+    return NULL;
+ ok:
+    bs_snapshots = bs;
+    return bs;
+}
+
+static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
+                              const char *name)
+{
+    QEMUSnapshotInfo *sn_tab, *sn;
+    int nb_sns, i, ret;
+
+    ret = -ENOENT;
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    if (nb_sns < 0)
+        return ret;
+    for(i = 0; i < nb_sns; i++) {
+        sn = &sn_tab[i];
+        if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
+            *sn_info = *sn;
+            ret = 0;
+            break;
+        }
+    }
+    qemu_free(sn_tab);
+    return ret;
+}
+
+void do_savevm(Monitor *mon, const char *name)
+{
+    BlockDriverState *bs, *bs1;
+    QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
+    int must_delete, ret, i;
+    BlockDriverInfo bdi1, *bdi = &bdi1;
+    QEMUFile *f;
+    int saved_vm_running;
+    uint32_t vm_state_size;
+#ifdef _WIN32
+    struct _timeb tb;
+#else
+    struct timeval tv;
+#endif
+
+    bs = get_bs_snapshots();
+    if (!bs) {
+        monitor_printf(mon, "No block device can accept snapshots\n");
+        return;
+    }
+
+    /* ??? Should this occur after vm_stop?  */
+    qemu_aio_flush();
+
+    saved_vm_running = vm_running;
+    vm_stop(0);
+
+    must_delete = 0;
+    if (name) {
+        ret = bdrv_snapshot_find(bs, old_sn, name);
+        if (ret >= 0) {
+            must_delete = 1;
+        }
+    }
+    memset(sn, 0, sizeof(*sn));
+    if (must_delete) {
+        pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
+        pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
+    } else {
+        if (name)
+            pstrcpy(sn->name, sizeof(sn->name), name);
+    }
+
+    /* fill auxiliary fields */
+#ifdef _WIN32
+    _ftime(&tb);
+    sn->date_sec = tb.time;
+    sn->date_nsec = tb.millitm * 1000000;
+#else
+    gettimeofday(&tv, NULL);
+    sn->date_sec = tv.tv_sec;
+    sn->date_nsec = tv.tv_usec * 1000;
+#endif
+    sn->vm_clock_nsec = qemu_get_clock(vm_clock);
+
+    if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
+        monitor_printf(mon, "Device %s does not support VM state snapshots\n",
+                       bdrv_get_device_name(bs));
+        goto the_end;
+    }
+
+    /* save the VM state */
+    f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1);
+    if (!f) {
+        monitor_printf(mon, "Could not open VM state file\n");
+        goto the_end;
+    }
+    ret = qemu_savevm_state(f);
+    vm_state_size = qemu_ftell(f);
+    qemu_fclose(f);
+    if (ret < 0) {
+        monitor_printf(mon, "Error %d while writing VM\n", ret);
+        goto the_end;
+    }
+
+    /* create the snapshots */
+
+    for(i = 0; i < nb_drives; i++) {
+        bs1 = drives_table[i].bdrv;
+        if (bdrv_has_snapshot(bs1)) {
+            if (must_delete) {
+                ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
+                if (ret < 0) {
+                    monitor_printf(mon,
+                                   "Error while deleting snapshot on '%s'\n",
+                                   bdrv_get_device_name(bs1));
+                }
+            }
+            /* Write VM state size only to the image that contains the state */
+            sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
+            ret = bdrv_snapshot_create(bs1, sn);
+            if (ret < 0) {
+                monitor_printf(mon, "Error while creating snapshot on '%s'\n",
+                               bdrv_get_device_name(bs1));
+            }
+        }
+    }
+
+ the_end:
+    if (saved_vm_running)
+        vm_start();
+}
+
+void do_loadvm(Monitor *mon, const char *name)
+{
+    BlockDriverState *bs, *bs1;
+    BlockDriverInfo bdi1, *bdi = &bdi1;
+    QEMUSnapshotInfo sn;
+    QEMUFile *f;
+    int i, ret;
+    int saved_vm_running;
+
+    bs = get_bs_snapshots();
+    if (!bs) {
+        monitor_printf(mon, "No block device supports snapshots\n");
+        return;
+    }
+
+    /* Flush all IO requests so they don't interfere with the new state.  */
+    qemu_aio_flush();
+
+    saved_vm_running = vm_running;
+    vm_stop(0);
+
+    for(i = 0; i <= nb_drives; i++) {
+        bs1 = drives_table[i].bdrv;
+        if (bdrv_has_snapshot(bs1)) {
+            ret = bdrv_snapshot_goto(bs1, name);
+            if (ret < 0) {
+                if (bs != bs1)
+                    monitor_printf(mon, "Warning: ");
+                switch(ret) {
+                case -ENOTSUP:
+                    monitor_printf(mon,
+                                   "Snapshots not supported on device '%s'\n",
+                                   bdrv_get_device_name(bs1));
+                    break;
+                case -ENOENT:
+                    monitor_printf(mon, "Could not find snapshot '%s' on "
+                                   "device '%s'\n",
+                                   name, bdrv_get_device_name(bs1));
+                    break;
+                default:
+                    monitor_printf(mon, "Error %d while activating snapshot on"
+                                   " '%s'\n", ret, bdrv_get_device_name(bs1));
+                    break;
+                }
+                /* fatal on snapshot block device */
+                if (bs == bs1)
+                    goto the_end;
+            }
+        }
+    }
+
+    if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
+        monitor_printf(mon, "Device %s does not support VM state snapshots\n",
+                       bdrv_get_device_name(bs));
+        return;
+    }
+
+    /* Don't even try to load empty VM states */
+    ret = bdrv_snapshot_find(bs, &sn, name);
+    if ((ret >= 0) && (sn.vm_state_size == 0))
+        goto the_end;
+
+    /* restore the VM state */
+    f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);
+    if (!f) {
+        monitor_printf(mon, "Could not open VM state file\n");
+        goto the_end;
+    }
+    ret = qemu_loadvm_state(f);
+    qemu_fclose(f);
+    if (ret < 0) {
+        monitor_printf(mon, "Error %d while loading VM state\n", ret);
+    }
+ the_end:
+    if (saved_vm_running)
+        vm_start();
+}
+
+void do_delvm(Monitor *mon, const char *name)
+{
+    BlockDriverState *bs, *bs1;
+    int i, ret;
+
+    bs = get_bs_snapshots();
+    if (!bs) {
+        monitor_printf(mon, "No block device supports snapshots\n");
+        return;
+    }
+
+    for(i = 0; i <= nb_drives; i++) {
+        bs1 = drives_table[i].bdrv;
+        if (bdrv_has_snapshot(bs1)) {
+            ret = bdrv_snapshot_delete(bs1, name);
+            if (ret < 0) {
+                if (ret == -ENOTSUP)
+                    monitor_printf(mon,
+                                   "Snapshots not supported on device '%s'\n",
+                                   bdrv_get_device_name(bs1));
+                else
+                    monitor_printf(mon, "Error %d while deleting snapshot on "
+                                   "'%s'\n", ret, bdrv_get_device_name(bs1));
+            }
+        }
+    }
+}
+
+void do_info_snapshots(Monitor *mon)
+{
+    BlockDriverState *bs, *bs1;
+    QEMUSnapshotInfo *sn_tab, *sn;
+    int nb_sns, i;
+    char buf[256];
+
+    bs = get_bs_snapshots();
+    if (!bs) {
+        monitor_printf(mon, "No available block device supports snapshots\n");
+        return;
+    }
+    monitor_printf(mon, "Snapshot devices:");
+    for(i = 0; i <= nb_drives; i++) {
+        bs1 = drives_table[i].bdrv;
+        if (bdrv_has_snapshot(bs1)) {
+            if (bs == bs1)
+                monitor_printf(mon, " %s", bdrv_get_device_name(bs1));
+        }
+    }
+    monitor_printf(mon, "\n");
+
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    if (nb_sns < 0) {
+        monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
+        return;
+    }
+    monitor_printf(mon, "Snapshot list (from %s):\n",
+                   bdrv_get_device_name(bs));
+    monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
+    for(i = 0; i < nb_sns; i++) {
+        sn = &sn_tab[i];
+        monitor_printf(mon, "%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
+    }
+    qemu_free(sn_tab);
+}
diff --git a/sdl_keysym.h b/sdl_keysym.h
index 9a74142..c213ef8 100644
--- a/sdl_keysym.h
+++ b/sdl_keysym.h
@@ -1,8 +1,7 @@
-typedef struct {
-	const char* name;
-	int keysym;
-} name2keysym_t;
-static name2keysym_t name2keysym[]={
+
+#include "keymaps.h"
+
+static const name2keysym_t name2keysym[]={
 /* ascii */
     { "space",                0x020},
     { "exclam",               0x021},
diff --git a/slirp2/COPYRIGHT b/slirp-android/COPYRIGHT
similarity index 93%
rename from slirp2/COPYRIGHT
rename to slirp-android/COPYRIGHT
index 2e86862..1bc83d4 100644
--- a/slirp2/COPYRIGHT
+++ b/slirp-android/COPYRIGHT
@@ -16,7 +16,7 @@
 ---BEGIN---
 
  Copyright (c) 1995,1996 Danny Gasparovski.  All rights reserved.
- 
+
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:
@@ -25,9 +25,6 @@
  2. Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
- 3. All advertising materials mentioning features or use of this software
-    must display the following acknowledgment:
-      This product includes software developed by Danny Gasparovski.
 
  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
diff --git a/slirp-android/bootp.c b/slirp-android/bootp.c
new file mode 100644
index 0000000..814b030
--- /dev/null
+++ b/slirp-android/bootp.c
@@ -0,0 +1,330 @@
+/*
+ * QEMU BOOTP/DHCP server
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <slirp.h>
+#include "helper.h"
+
+/* XXX: only DHCP is supported */
+
+#define NB_ADDR 16
+
+#define START_ADDR 15
+
+#define LEASE_TIME (24 * 3600)
+
+typedef struct {
+    uint8_t allocated;
+    uint8_t macaddr[6];
+} BOOTPClient;
+
+static BOOTPClient bootp_clients[NB_ADDR];
+
+const char *bootp_filename;
+
+static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
+
+#ifdef DEBUG
+#define dprintf(fmt, ...) \
+if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ##  __VA_ARGS__); fflush(dfd); }
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static BOOTPClient *get_new_addr(SockAddress*  paddr,
+                                 const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_ADDR; i++) {
+        bc = &bootp_clients[i];
+        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &bootp_clients[i];
+    bc->allocated = 1;
+    sock_address_init_inet( paddr, 
+                            special_addr_ip | (i+START_ADDR),
+                            BOOTP_CLIENT );
+    return bc;
+}
+
+static BOOTPClient *request_addr(const ipaddr_t *paddr,
+                                 const uint8_t *macaddr)
+{
+    uint32_t req_addr  = ip_geth(*paddr);
+    uint32_t spec_addr = special_addr_ip;
+    BOOTPClient *bc;
+
+    if (req_addr >= (spec_addr | START_ADDR) &&
+        req_addr < (spec_addr | (NB_ADDR + START_ADDR))) {
+        bc = &bootp_clients[(req_addr & 0xff) - START_ADDR];
+        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
+            bc->allocated = 1;
+            return bc;
+        }
+    }
+    return NULL;
+}
+
+static BOOTPClient *find_addr(SockAddress *paddr, const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_ADDR; i++) {
+        if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &bootp_clients[i];
+    bc->allocated = 1;
+    sock_address_init_inet( paddr,
+                            special_addr_ip | (i + START_ADDR),
+                            BOOTP_CLIENT );
+    return bc;
+}
+
+static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
+                        const ipaddr_t **preq_addr)
+{
+    const uint8_t *p, *p_end;
+    int len, tag;
+
+    *pmsg_type = 0;
+    *preq_addr = NULL;
+
+    p = bp->bp_vend;
+    p_end = p + DHCP_OPT_LEN;
+    if (memcmp(p, rfc1533_cookie, 4) != 0)
+        return;
+    p += 4;
+    while (p < p_end) {
+        tag = p[0];
+        if (tag == RFC1533_PAD) {
+            p++;
+        } else if (tag == RFC1533_END) {
+            break;
+        } else {
+            p++;
+            if (p >= p_end)
+                break;
+            len = *p++;
+            dprintf("dhcp: tag=%d len=%d\n", tag, len);
+
+            switch(tag) {
+            case RFC2132_MSG_TYPE:
+                if (len >= 1)
+                    *pmsg_type = p[0];
+                break;
+            case RFC2132_REQ_ADDR:
+                if (len >= 4)
+                    *preq_addr = (const ipaddr_t *)p;
+                break;
+            default:
+                break;
+            }
+            p += len;
+        }
+    }
+    if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr) {
+        *preq_addr = (const ipaddr_t*)&bp->bp_ciaddr;
+    }
+}
+
+static void bootp_reply(const struct bootp_t *bp)
+{
+    BOOTPClient *bc = NULL;
+    struct mbuf *m;
+    struct bootp_t *rbp;
+    SockAddress  saddr, daddr;
+    uint32_t     dns_addr;
+    const ipaddr_t *preq_addr;
+    int dhcp_msg_type, val;
+    uint8_t *q;
+
+    /* extract exact DHCP msg type */
+    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
+    dprintf("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
+    if (preq_addr) {
+        dprintf(" req_addr=%08x\n", ntohl(*preq_addr));
+    } else {
+        dprintf("\n");
+    }
+    if (dhcp_msg_type == 0)
+        dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
+
+    if (dhcp_msg_type != DHCPDISCOVER &&
+        dhcp_msg_type != DHCPREQUEST)
+        return;
+    /* XXX: this is a hack to get the client mac address */
+    memcpy(client_ethaddr, bp->bp_hwaddr, 6);
+
+    if ((m = m_get()) == NULL)
+        return;
+    m->m_data += IF_MAXLINKHDR;
+    rbp = (struct bootp_t *)m->m_data;
+    m->m_data += sizeof(struct udpiphdr);
+    memset(rbp, 0, sizeof(struct bootp_t));
+
+    if (dhcp_msg_type == DHCPDISCOVER) {
+        if (preq_addr) {
+            bc = request_addr(preq_addr, client_ethaddr);
+            if (bc) {
+				sock_address_init_inet(&daddr, ip_geth(*preq_addr), BOOTP_CLIENT);
+            }
+        }
+        if (!bc) {
+         new_addr:
+	        bc = get_new_addr(&daddr, client_ethaddr);
+            if (!bc) {
+                dprintf("no address left\n");
+                return;
+            }
+        }
+        memcpy(bc->macaddr, client_ethaddr, 6);
+    } else if (preq_addr) {
+        bc = request_addr(preq_addr, client_ethaddr);
+        if (bc) {
+			sock_address_init_inet(&daddr, ip_geth(*preq_addr), BOOTP_CLIENT);
+            memcpy(bc->macaddr, client_ethaddr, 6);
+        } else {
+            sock_address_init_inet(&daddr, 0, BOOTP_CLIENT);
+        }
+    } else {
+        bc = find_addr(&daddr, bp->bp_hwaddr);
+        if (!bc) {
+            /* if never assigned, behaves as if it was already
+               assigned (windows fix because it remembers its address) */
+            goto new_addr;
+        }
+    }
+
+    sock_address_init_inet( &saddr, special_addr_ip | CTL_ALIAS,
+                            BOOTP_SERVER );
+
+    rbp->bp_op = BOOTP_REPLY;
+    rbp->bp_xid = bp->bp_xid;
+    rbp->bp_htype = 1;
+    rbp->bp_hlen = 6;
+    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
+
+    rbp->bp_yiaddr = htonl(sock_address_get_ip(&daddr)); /* Client IP address */
+    rbp->bp_siaddr = htonl(sock_address_get_ip(&saddr)); /* Server IP address */
+
+    q = rbp->bp_vend;
+    memcpy(q, rfc1533_cookie, 4);
+    q += 4;
+
+    if (bc) {
+        uint32_t  saddr_ip = htonl(sock_address_get_ip(&saddr));
+        dprintf("%s addr=%08x\n",
+                (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
+                sock_address_get_ip(&daddr));
+
+        if (dhcp_msg_type == DHCPDISCOVER) {
+            *q++ = RFC2132_MSG_TYPE;
+            *q++ = 1;
+            *q++ = DHCPOFFER;
+        } else /* DHCPREQUEST */ {
+            *q++ = RFC2132_MSG_TYPE;
+            *q++ = 1;
+            *q++ = DHCPACK;
+        }
+
+        if (bootp_filename)
+            snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
+                     bootp_filename);
+
+        *q++ = RFC2132_SRV_ID;
+        *q++ = 4;
+        memcpy(q, &saddr_ip, 4);
+        q += 4;
+
+        *q++ = RFC1533_NETMASK;
+        *q++ = 4;
+        *q++ = 0xff;
+        *q++ = 0xff;
+        *q++ = 0xff;
+        *q++ = 0x00;
+
+        if (!slirp_restrict) {
+            *q++ = RFC1533_GATEWAY;
+            *q++ = 4;
+            memcpy(q, &saddr_ip, 4);
+            q += 4;
+
+            *q++ = RFC1533_DNS;
+            *q++ = 4;
+            dns_addr = htonl(special_addr_ip | CTL_DNS);
+            memcpy(q, &dns_addr, 4);
+            q += 4;
+        }
+
+        *q++ = RFC2132_LEASE_TIME;
+        *q++ = 4;
+        val = htonl(LEASE_TIME);
+        memcpy(q, &val, 4);
+        q += 4;
+
+        if (*slirp_hostname) {
+            val = strlen(slirp_hostname);
+            *q++ = RFC1533_HOSTNAME;
+            *q++ = val;
+            memcpy(q, slirp_hostname, val);
+            q += val;
+        }
+    } else {
+        static const char nak_msg[] = "requested address not available";
+
+        dprintf("nak'ed addr=%08x\n", ip_geth(*preq_addr));
+
+        *q++ = RFC2132_MSG_TYPE;
+        *q++ = 1;
+        *q++ = DHCPNAK;
+
+        *q++ = RFC2132_MESSAGE;
+        *q++ = sizeof(nak_msg) - 1;
+        memcpy(q, nak_msg, sizeof(nak_msg) - 1);
+        q += sizeof(nak_msg) - 1;
+    }
+    *q++ = RFC1533_END;
+
+	sock_address_init_inet(&daddr, 0xffffffffu, BOOTP_CLIENT);
+
+    m->m_len = sizeof(struct bootp_t) -
+        sizeof(struct ip) - sizeof(struct udphdr);
+    udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+}
+
+void bootp_input(struct mbuf *m)
+{
+    struct bootp_t *bp = mtod(m, struct bootp_t *);
+
+    if (bp->bp_op == BOOTP_REQUEST) {
+        bootp_reply(bp);
+    }
+}
diff --git a/slirp2/bootp.h b/slirp-android/bootp.h
similarity index 96%
rename from slirp2/bootp.h
rename to slirp-android/bootp.h
index fbc96ac..289066f 100644
--- a/slirp2/bootp.h
+++ b/slirp-android/bootp.h
@@ -63,6 +63,7 @@
 #define RFC2132_MSG_TYPE	53
 #define RFC2132_SRV_ID		54
 #define RFC2132_PARAM_LIST	55
+#define RFC2132_MESSAGE		56
 #define RFC2132_MAX_SIZE	57
 #define RFC2132_RENEWAL_TIME    58
 #define RFC2132_REBIND_TIME     59
@@ -71,6 +72,7 @@
 #define DHCPOFFER		2
 #define DHCPREQUEST		3
 #define DHCPACK			5
+#define DHCPNAK			6
 
 #define RFC1533_VENDOR_MAJOR	0
 #define RFC1533_VENDOR_MINOR	0
@@ -110,4 +112,4 @@
     uint8_t bp_vend[DHCP_OPT_LEN];
 };
 
-void bootp_input(MBuf m);
+void bootp_input(struct mbuf *m);
diff --git a/slirp2/cksum.c b/slirp-android/cksum.c
similarity index 90%
rename from slirp2/cksum.c
rename to slirp-android/cksum.c
index 9474b9e..34977ff 100644
--- a/slirp2/cksum.c
+++ b/slirp-android/cksum.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -41,14 +37,14 @@
  *
  * This routine is very heavily used in the network
  * code and should be modified for each CPU to be as fast as possible.
- * 
+ *
  * XXX Since we will never span more than 1 mbuf, we can optimise this
  */
 
 #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
 
-int cksum(MBuf m, int len)
+int cksum(struct mbuf *m, int len)
 {
 	register u_int16_t *w;
 	register int sum = 0;
@@ -63,13 +59,13 @@
 		u_int16_t s[2];
 		u_int32_t l;
 	} l_util;
-	
+
 	if (m->m_len == 0)
 	   goto cont;
-	w = MBUF_TO(m, u_int16_t *);
-	
+	w = mtod(m, u_int16_t *);
+
 	mlen = m->m_len;
-	
+
 	if (len < mlen)
 	   mlen = len;
 	len -= mlen;
@@ -107,7 +103,7 @@
 	while ((mlen -= 2) >= 0) {
 		sum += *w++;
 	}
-	
+
 	if (byte_swapped) {
 		REDUCE;
 		sum <<= 8;
@@ -117,11 +113,11 @@
 			sum += s_util.s;
 			mlen = 0;
 		} else
-		   
+
 		   mlen = -1;
 	} else if (mlen == -1)
 	   s_util.c[0] = *(u_int8_t *)w;
-	
+
 cont:
 #ifdef DEBUG
 	if (len) {
diff --git a/slirp2/ctl.h b/slirp-android/ctl.h
similarity index 100%
rename from slirp2/ctl.h
rename to slirp-android/ctl.h
diff --git a/slirp2/debug.c b/slirp-android/debug.c
similarity index 95%
rename from slirp2/debug.c
rename to slirp-android/debug.c
index f3a424d..8e41010 100644
--- a/slirp2/debug.c
+++ b/slirp-android/debug.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
  * Portions copyright (c) 2000 Kelly Price.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -32,7 +32,7 @@
 	/* Close the old debugging file */
 	if (dfd)
 	   fclose(dfd);
-	
+
 	dfd = fopen(file,"w");
 	if (dfd != NULL) {
 #if 0
@@ -58,7 +58,7 @@
 {
 	u_char *pptr = (u_char *)dat;
 	int j,k;
-	
+
 	n /= 16;
 	n++;
 	DEBUG_MISC((dfd, "PACKET DUMPED: \n"));
@@ -74,24 +74,24 @@
 #if 0
 /*
  * Statistic routines
- * 
+ *
  * These will print statistics to the screen, the debug file (dfd), or
  * a buffer, depending on "type", so that the stats can be sent over
  * the link as well.
  */
 
-void
+static void
 ttystats(ttyp)
 	struct ttys *ttyp;
 {
 	struct slirp_ifstats *is = &ttyp->ifstats;
 	char buff[512];
-	
+
 	lprint(" \r\n");
-	
-	if (if_comp & IF_COMPRESS)
+
+	if (IF_COMP & IF_COMPRESS)
 	   strcpy(buff, "on");
-	else if (if_comp & IF_NOCOMPRESS)
+	else if (IF_COMP & IF_NOCOMPRESS)
 	   strcpy(buff, "off");
 	else
 	   strcpy(buff, "off (for now)");
@@ -119,20 +119,19 @@
 	lprint("  %6d bad input packets\r\n", is->in_mbad);
 }
 
-void
-allttystats()
+static void
+allttystats(void)
 {
 	struct ttys *ttyp;
-	
+
 	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
 	   ttystats(ttyp);
 }
-#endif
 
-void
-ipstats()
+static void
+ipstats(void)
 {
-	lprint(" \r\n");	
+	lprint(" \r\n");
 
 	lprint("IP stats:\r\n");
 	lprint("  %6d total packets received (%d were unaligned)\r\n",
@@ -153,14 +152,13 @@
 	lprint("  %6d total packets delivered\r\n", ipstat.ips_delivered);
 }
 
-#if 0
-void
-vjstats()
+static void
+vjstats(void)
 {
 	lprint(" \r\n");
-	
+
 	lprint("VJ compression stats:\r\n");
-	
+
 	lprint("  %6d outbound packets (%d compressed)\r\n",
 	       comp_s.sls_packets, comp_s.sls_compressed);
 	lprint("  %6d searches for connection stats (%d misses)\r\n",
@@ -170,15 +168,14 @@
 	lprint("  %6d inbound unknown type packets\r\n", comp_s.sls_errorin);
 	lprint("  %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed);
 }
-#endif
 
-void
-tcpstats()
+static void
+tcpstats(void)
 {
 	lprint(" \r\n");
 
 	lprint("TCP stats:\r\n");
-	
+
 	lprint("  %6d packets sent\r\n", tcpstat.tcps_sndtotal);
 	lprint("          %6d data packets (%d bytes)\r\n",
 			tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte);
@@ -191,8 +188,8 @@
 	lprint("          %6d window update packets\r\n", tcpstat.tcps_sndwinup);
 	lprint("          %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl);
 	lprint("          %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin);
-	
-	lprint("  %6d packets received\r\n", tcpstat.tcps_rcvtotal);       
+
+	lprint("  %6d packets received\r\n", tcpstat.tcps_rcvtotal);
 	lprint("          %6d acks (for %d bytes)\r\n",
 			tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte);
 	lprint("          %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack);
@@ -201,7 +198,7 @@
 			tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte);
         lprint("          %6d completely duplicate packets (%d bytes)\r\n",
 			tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte);
-	
+
 	lprint("          %6d packets with some duplicate data (%d bytes duped)\r\n",
 			tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte);
 	lprint("          %6d out-of-order packets (%d bytes)\r\n",
@@ -214,7 +211,7 @@
 	lprint("          %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum);
 	lprint("          %6d discarded for bad header offset fields\r\n",
 			tcpstat.tcps_rcvbadoff);
-	
+
 	lprint("  %6d connection requests\r\n", tcpstat.tcps_connattempt);
 	lprint("  %6d connection accepts\r\n", tcpstat.tcps_accepts);
 	lprint("  %6d connections established (including accepts)\r\n", tcpstat.tcps_connects);
@@ -233,15 +230,15 @@
 	lprint("  %6d correct ACK header predictions\r\n", tcpstat.tcps_predack);
 	lprint("  %6d correct data packet header predictions\n", tcpstat.tcps_preddat);
 	lprint("  %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss);
-	
-	
+
+
 /*	lprint("    Packets received too short:		%d\r\n", tcpstat.tcps_rcvshort); */
 /*	lprint("    Segments dropped due to PAWS:	%d\r\n", tcpstat.tcps_pawsdrop); */
 
 }
 
-void
-udpstats()
+static void
+udpstats(void)
 {
         lprint(" \r\n");
 
@@ -254,8 +251,8 @@
 	lprint("  %6d datagrams sent\r\n", udpstat.udps_opackets);
 }
 
-void
-icmpstats()
+static void
+icmpstats(void)
 {
 	lprint(" \r\n");
 	lprint("ICMP stats:\r\n");
@@ -267,20 +264,20 @@
 	lprint("  %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect);
 }
 
-void
-sockstats()
+static void
+sockstats(void)
 {
 	char buff[256];
 	int n;
 	struct socket *so;
 
         lprint(" \r\n");
-	
+
 	lprint(
 	   "Proto[state]     Sock     Local Address, Port  Remote Address, Port RecvQ SendQ\r\n");
-			
+
 	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
-		
+
 		n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE");
 		while (n < 17)
 		   buff[n++] = ' ';
@@ -292,9 +289,9 @@
 				inet_iptostr(so->so_faddr_ip), so->so_faddr_port,
 				so->so_rcv.sb_cc, so->so_snd.sb_cc);
 	}
-		   
+
 	for (so = udb.so_next; so != &udb; so = so->so_next) {
-		
+
 		n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000);
 		while (n < 17)
 		   buff[n++] = ' ';
@@ -307,6 +304,7 @@
 				so->so_rcv.sb_cc, so->so_snd.sb_cc);
 	}
 }
+#endif
 
 #if 0
 void
@@ -314,7 +312,7 @@
 	int exit_status;
 {
 	struct ttys *ttyp;
-	
+
 	DEBUG_CALL("slirp_exit");
 	DEBUG_ARG("exit_status = %d", exit_status);
 
@@ -323,7 +321,7 @@
 		if (!dfd)
 		   debug_init("slirp_stats", 0xf);
 		lprint_arg = (char **)&dfd;
-		
+
 		ipstats();
 		tcpstats();
 		udpstats();
@@ -333,17 +331,17 @@
 		allttystats();
 		vjstats();
 	}
-	
+
 	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
 	   tty_detached(ttyp, 1);
-	
+
 	if (slirp_forked) {
 		/* Menendez time */
 		if (kill(getppid(), SIGQUIT) < 0)
 			lprint("Couldn't kill parent process %ld!\n",
 			    (long) getppid());
     	}
-	
+
 	/* Restore the terminal if we gotta */
 	if(slirp_tty_restore)
 	  tcsetattr(0,TCSANOW, &slirp_tty_settings);  /* NOW DAMMIT! */
diff --git a/slirp2/debug.h b/slirp-android/debug.h
similarity index 74%
rename from slirp2/debug.h
rename to slirp-android/debug.h
index 6e8444d..c43eff7 100644
--- a/slirp2/debug.h
+++ b/slirp-android/debug.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -37,14 +37,3 @@
 #endif
 
 void debug_init _P((char *, int));
-//void ttystats _P((struct ttys *));
-void allttystats _P((void));
-void ipstats _P((void));
-void vjstats _P((void));
-void tcpstats _P((void));
-void udpstats _P((void));
-void icmpstats _P((void));
-void mbufstats _P((void));
-void sockstats _P((void));
-void slirp_exit _P((int));
-
diff --git a/slirp2/helper.h b/slirp-android/helper.h
similarity index 84%
rename from slirp2/helper.h
rename to slirp-android/helper.h
index e247f46..afccb54 100644
--- a/slirp2/helper.h
+++ b/slirp-android/helper.h
@@ -32,6 +32,10 @@
 #ifndef _SLIRP_HELPER_H
 #define _SLIRP_HELPER_H
 
+#ifdef _WIN32
+#  include <winsock2.h>  /* for ntohl */
+#endif
+
 typedef union {
     u_int32_t   addr;
     u_int8_t    data[4];
@@ -69,6 +73,34 @@
     return ip;
 }
 
+static __inline__ ipaddr_t
+ip_read( const void*  buf )
+{
+    ipaddr_t  ip;
+    memcpy(ip.data, buf, 4);
+    return ip;
+}
+
+static __inline__ void
+ip_write( ipaddr_t  ip, void*  buf )
+{
+    memcpy(buf, ip.data, 4);
+}
+
+static __inline__ uint32_t
+ip_read32h( const void* buf )
+{
+    ipaddr_t  addr = ip_read(buf);
+    return ip_geth(addr);
+}
+
+static __inline__ void
+ip_write32h( uint32_t  ip, void*  buf )
+{
+    ipaddr_t  addr = ip_seth(ip);
+    ip_write(addr, buf);
+}
+
 static __inline__ int
 ip_equal( ipaddr_t  ip1, ipaddr_t  ip2 )
 {
diff --git a/slirp2/icmp_var.h b/slirp-android/icmp_var.h
similarity index 88%
copy from slirp2/icmp_var.h
copy to slirp-android/icmp_var.h
index 03fc8c3..99d4c9e 100644
--- a/slirp2/icmp_var.h
+++ b/slirp-android/icmp_var.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -64,6 +60,8 @@
 	{ "stats", CTLTYPE_STRUCT }, \
 }
 
+#ifdef LOG_ENABLED
 extern struct icmpstat icmpstat;
+#endif
 
 #endif
diff --git a/slirp2/if.c b/slirp-android/if.c
similarity index 86%
rename from slirp2/if.c
rename to slirp-android/if.c
index cd96e65..60d5b58 100644
--- a/slirp2/if.c
+++ b/slirp-android/if.c
@@ -7,12 +7,7 @@
 
 #include <slirp.h>
 
-int if_mtu, if_mru;
-int if_comp;
-int if_maxlinkhdr;
 int     if_queued = 0;                  /* Number of packets queued so far */
-int     if_thresh = 10;                 /* Number of packets queued before we start sending
-					 * (to prevent allocing too many mbufs) */
 
 struct  mbuf if_fastq;                  /* fast queue (for interactive data) */
 struct  mbuf if_batchq;                 /* queue for non-interactive data */
@@ -20,9 +15,8 @@
 
 #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
 
-void
-ifs_insque(ifm, ifmhead)
-	MBuf ifm, ifmhead;
+static void
+ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
 {
 	ifm->ifs_next = ifmhead->ifs_next;
 	ifmhead->ifs_next = ifm;
@@ -30,34 +24,16 @@
 	ifm->ifs_next->ifs_prev = ifm;
 }
 
-void
-ifs_remque(ifm)
-	MBuf ifm;
+static void
+ifs_remque(struct mbuf *ifm)
 {
 	ifm->ifs_prev->ifs_next = ifm->ifs_next;
 	ifm->ifs_next->ifs_prev = ifm->ifs_prev;
 }
 
 void
-if_init()
+if_init(void)
 {
-#if 0
-	/*
-	 * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP,
-	 * and 8 bytes for PPP, but need to have it on an 8byte boundary
-	 */
-#ifdef USE_PPP
-	if_maxlinkhdr = 48;
-#else
-	if_maxlinkhdr = 40;
-#endif
-#else
-        /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
-        if_maxlinkhdr = 2 + 14 + 40;
-#endif
-	if_mtu = 1500;
-	if_mru = 1500;
-	if_comp = IF_AUTOCOMP;
 	if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq;
 	if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq;
         //	sl_compress_init(&comp_s);
@@ -77,12 +53,12 @@
 {
 	int ret;
 	int total;
-	
+
 	/* This should succeed most of the time */
 	ret = socket_send(fd, bptr, n);
 	if (ret == n || ret <= 0)
 	   return ret;
-	
+
 	/* Didn't write everything, go into the loop */
 	total = ret;
 	while (n > total) {
@@ -97,7 +73,7 @@
 /*
  * if_input - read() the tty, do "top level" processing (ie: check for any escapes),
  * and pass onto (*ttyp->if_input)
- * 
+ *
  * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet.
  */
 #define INBUFF_SIZE 2048 /* XXX */
@@ -107,14 +83,14 @@
 {
 	u_char if_inbuff[INBUFF_SIZE];
 	int if_n;
-	
+
 	DEBUG_CALL("if_input");
 	DEBUG_ARG("ttyp = %lx", (long)ttyp);
-	
+
 	if_n = socket_recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE);
-	
+
 	DEBUG_MISC((dfd, " read %d bytes\n", if_n));
-	
+
 	if (if_n <= 0) {
 		if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) {
 			if (ttyp->up)
@@ -138,36 +114,34 @@
 		}
 	}
 	ttyp->ones = ttyp->zeros = 0;
-	
+
 	(*ttyp->if_input)(ttyp, if_inbuff, if_n);
 }
-#endif	
-	
+#endif
+
 /*
  * if_output: Queue packet into an output queue.
- * There are 2 output queue's, if_fastq and if_batchq. 
+ * There are 2 output queue's, if_fastq and if_batchq.
  * Each output queue is a doubly linked list of double linked lists
  * of mbufs, each list belonging to one "session" (socket).  This
  * way, we can output packets fairly by sending one packet from each
  * session, instead of all the packets from one session, then all packets
- * from the next session, etc.  Packets on the if_fastq get absolute 
+ * from the next session, etc.  Packets on the if_fastq get absolute
  * priority, but if one session hogs the link, it gets "downgraded"
  * to the batchq until it runs out of packets, then it'll return
  * to the fastq (eg. if the user does an ls -alR in a telnet session,
  * it'll temporarily get downgraded to the batchq)
  */
 void
-if_output(so, ifm)
-	struct socket *so;
-	MBuf ifm;
+if_output(struct socket *so, struct mbuf *ifm)
 {
-	MBuf ifq;
+	struct mbuf *ifq;
 	int on_fastq = 1;
-	
+
 	DEBUG_CALL("if_output");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("ifm = %lx", (long)ifm);
-	
+
 	/*
 	 * First remove the mbuf from m_usedlist,
 	 * since we're gonna use m_next and m_prev ourselves
@@ -177,9 +151,9 @@
 		remque(ifm);
 		ifm->m_flags &= ~M_USEDLIST;
 	}
-	
+
 	/*
-	 * See if there's already a batchq list for this session.  
+	 * See if there's already a batchq list for this session.
 	 * This can include an interactive session, which should go on fastq,
 	 * but gets too greedy... hence it'll be downgraded from fastq to batchq.
 	 * We mustn't put this packet back on the fastq (or we'll send it out of order)
@@ -193,7 +167,7 @@
 			goto diddit;
 		}
 	}
-	
+
 	/* No match, check which queue to put it on */
 	if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
 		ifq = if_fastq.ifq_prev;
@@ -209,15 +183,15 @@
 		}
 	} else
 		ifq = if_batchq.ifq_prev;
-	
+
 	/* Create a new doubly linked list for this session */
 	ifm->ifq_so = so;
 	ifs_init(ifm);
 	insque(ifm, ifq);
-	
+
 diddit:
 	++if_queued;
-	
+
 	if (so) {
 		/* Update *_queued */
 		so->so_queued++;
@@ -229,12 +203,12 @@
 		 * have been sent over the link
 		 * (XXX These are arbitrary numbers, probably not optimal..)
 		 */
-		if (on_fastq && ((so->so_nqueued >= 6) && 
+		if (on_fastq && ((so->so_nqueued >= 6) &&
 				 (so->so_nqueued - so->so_queued) >= 3)) {
-			
+
 			/* Remove from current queue... */
 			remque(ifm->ifs_next);
-			
+
 			/* ...And insert in the new.  That'll teach ya! */
 			insque(ifm->ifs_next, &if_batchq);
 		}
@@ -266,13 +240,13 @@
 void
 if_start(void)
 {
-	MBuf ifm, ifqt;
-	
+	struct mbuf *ifm, *ifqt;
+
 	DEBUG_CALL("if_start");
-	
+
 	if (if_queued == 0)
 	   return; /* Nothing to do */
-	
+
  again:
         /* check if we can really output */
         if (!slirp_can_output())
@@ -290,7 +264,7 @@
 		   ifm = next_m;
 		else
 		   ifm = if_batchq.ifq_next;
-		
+
 		/* Set which packet to send on next iteration */
 		next_m = ifm->ifq_next;
 	}
@@ -298,24 +272,24 @@
 	ifqt = ifm->ifq_prev;
 	remque(ifm);
 	--if_queued;
-	
+
 	/* If there are more packets for this session, re-queue them */
 	if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) {
 		insque(ifm->ifs_next, ifqt);
 		ifs_remque(ifm);
 	}
-	
+
 	/* Update so_queued */
 	if (ifm->ifq_so) {
 		if (--ifm->ifq_so->so_queued == 0)
 		   /* If there's no more queued, reset nqueued */
 		   ifm->ifq_so->so_nqueued = 0;
 	}
-	
-	/* Encapsulate the packet for sending */
-        if_encap(ifm->m_data, ifm->m_len);
 
-        mbuf_free(ifm);
+	/* Encapsulate the packet for sending */
+        if_encap((uint8_t *)ifm->m_data, ifm->m_len);
+
+        m_free(ifm);
 
 	if (if_queued)
 	   goto again;
diff --git a/slirp2/if.h b/slirp-android/if.h
similarity index 69%
copy from slirp2/if.h
copy to slirp-android/if.h
index f22f161..bed7152 100644
--- a/slirp2/if.h
+++ b/slirp-android/if.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -13,22 +13,34 @@
 #define IF_AUTOCOMP	0x04	/* Autodetect (default) */
 #define IF_NOCIDCOMP	0x08	/* CID compression */
 
-/* Needed for FreeBSD */
-#undef if_mtu
-extern int	if_mtu;
-extern int	if_mru;	/* MTU and MRU */
-extern int	if_comp;	/* Flags for compression */
-extern int	if_maxlinkhdr;
+#define IF_MTU 1500
+#define IF_MRU 1500
+#define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
+
+#if 0
+/*
+ * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP,
+ * and 8 bytes for PPP, but need to have it on an 8byte boundary
+ */
+#ifdef USE_PPP
+#define IF_MAXLINKHDR 48
+#else
+#define IF_MAXLINKHDR 40
+#endif
+#else
+        /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
+#define IF_MAXLINKHDR (2 + 14 + 40)
+#endif
+
 extern int	if_queued;	/* Number of packets queued so far */
-extern int	if_thresh;	/* Number of packets queued before we start sending
-				 * (to prevent allocing too many mbufs) */
 
 extern	struct mbuf if_fastq;                  /* fast queue (for interactive data) */
 extern	struct mbuf if_batchq;                 /* queue for non-interactive data */
-extern	MBuf next_m;
+extern	struct mbuf *next_m;
 
 #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
 
+#ifdef LOG_ENABLED
 /* Interface statistics */
 struct slirp_ifstats {
 	u_int out_pkts;		/* Output packets */
@@ -39,12 +51,13 @@
 	u_int in_bytes;		/* Input bytes */
 	u_int in_errpkts;		/* Input Error Packets */
 	u_int in_errbytes;	/* Input Error Bytes */
-	
+
 	u_int bytes_saved;	/* Number of bytes that compression "saved" */
 				/* ie: number of bytes that didn't need to be sent over the link
 				 * because of compression */
-	
+
 	u_int in_mbad;		/* Bad incoming packets */
 };
+#endif
 
 #endif
diff --git a/slirp2/ip.h b/slirp-android/ip.h
similarity index 89%
rename from slirp2/ip.h
rename to slirp-android/ip.h
index 8cdb735..c0ecc55 100644
--- a/slirp2/ip.h
+++ b/slirp-android/ip.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -96,7 +92,7 @@
 	u_int8_t ip_ttl;			/* time to live */
 	u_int8_t ip_p;			/* protocol */
 	u_int16_t	ip_sum;			/* checksum */
-        ipaddr_t        ip_src, ip_dst; /* source and dest address */
+    ipaddr_t        ip_src, ip_dst; /* source and dest address */
 };
 
 #define	IP_MAXPACKET	65535		/* maximum packet size */
@@ -187,23 +183,23 @@
 
 #if SIZEOF_CHAR_P == 4
 struct mbuf_ptr {
-    struct mbuf *mptr;
-    uint32_t     dummy;
+	struct mbuf *mptr;
+	uint32_t dummy;
 };
 #else
 struct mbuf_ptr {
-    struct mbuf *mptr;
+	struct mbuf *mptr;
 };
 #endif
 struct qlink {
-    void*  next, *prev;
+	void *next, *prev;
 };
 
 /*
  * Overlay for ip header used by other protocols (tcp, udp).
  */
 struct ipovly {
-	struct mbuf_ptr ih_mbuf;      /* backpointer to mbuf */
+	struct mbuf_ptr ih_mbuf;	/* backpointer to mbuf */
 	u_int8_t	ih_x1;			/* (unused) */
 	u_int8_t	ih_pr;			/* protocol */
 	u_int16_t	ih_len;			/* protocol length */
@@ -219,8 +215,8 @@
  * size 28 bytes
  */
 struct ipq {
-        struct qlink  frag_link;  /* to ip headers of fragments */
-        struct qlink  ip_link;    /* to other reass headers */
+        struct qlink frag_link;			/* to ip headers of fragments */
+	struct qlink ip_link;				/* to other reass headers */
 	u_int8_t	ipq_ttl;		/* time for reass q to live */
 	u_int8_t	ipq_p;			/* protocol of this fragment */
 	u_int16_t	ipq_id;			/* sequence id for reassembly */
@@ -230,18 +226,18 @@
 /*
  * Ip header, when holding a fragment.
  *
- * Note: ipf_next must be at same offset as frag_link above
+ * Note: ipf_link must be at same offset as frag_link above
  */
 struct	ipasfrag {
-        struct qlink ipf_link;
-        struct ip    ipf_ip;
+	struct qlink ipf_link;
+	struct ip ipf_ip;
 };
 
-#define ipf_off  ipf_ip.ip_off
-#define ipf_tos  ipf_ip.ip_tos
-#define ipf_len  ipf_ip.ip_len
-#define ipf_next ipf_link.next
-#define ipf_prev ipf_link.prev
+#define ipf_off      ipf_ip.ip_off
+#define ipf_tos      ipf_ip.ip_tos
+#define ipf_len      ipf_ip.ip_len
+#define ipf_next     ipf_link.next
+#define ipf_prev     ipf_link.prev 
 
 /*
  * Structure stored in mbuf in inpcb.ip_options
@@ -256,6 +252,7 @@
 	int8_t	  ipopt_list[MAX_IPOPTLEN];	/* options proper */
 };
 
+#ifdef LOG_ENABLED
 /*
  * Structure attached to inpcb.ip_moptions and
  * passed to ip_output when IP multicast options are in use.
@@ -290,8 +287,9 @@
 };
 
 extern struct	ipstat	ipstat;
+#endif
+
 extern struct	ipq	ipq;			/* ip reass. queue */
 extern u_int16_t	ip_id;				/* ip packet ctr, for ids */
-extern int	ip_defttl;			/* default IP ttl */
 
 #endif
diff --git a/slirp2/ip_icmp.c b/slirp-android/ip_icmp.c
similarity index 85%
rename from slirp2/ip_icmp.c
rename to slirp-android/ip_icmp.c
index 6594ec4..c1edd6b 100644
--- a/slirp2/ip_icmp.c
+++ b/slirp-android/ip_icmp.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -38,14 +34,16 @@
 #include "ip_icmp.h"
 #include "sockets.h"
 
+#ifdef LOG_ENABLED
 struct icmpstat icmpstat;
+#endif
 
 /* The message sent when emulating PING */
-/* Be nice and tell them it's just a psuedo-ping packet */
-char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
+/* Be nice and tell them it's just a pseudo-ping packet */
+static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
 
 /* list of actions for icmp_error() on RX of an icmp message */
-static int icmp_flush[19] = {
+static const int icmp_flush[19] = {
 /*  ECHO REPLY (0)  */   0,
 		         1,
 		         1,
@@ -71,12 +69,10 @@
  * Process a received ICMP message.
  */
 void
-icmp_input(m, hlen)
-     MBuf m;
-     int hlen;
+icmp_input(struct mbuf *m, int hlen)
 {
   register struct icmp *icp;
-  register struct ip *ip=MBUF_TO(m, struct ip *);
+  register struct ip *ip=mtod(m, struct ip *);
   int icmplen=ip->ip_len;
   /* int code; */
 
@@ -84,24 +80,24 @@
   DEBUG_ARG("m = %lx", (long )m);
   DEBUG_ARG("m_len = %d", m->m_len);
 
-  icmpstat.icps_received++;
+  STAT(icmpstat.icps_received++);
 
   /*
    * Locate icmp structure in mbuf, and check
    * that its not corrupted and of at least minimum length.
    */
   if (icmplen < ICMP_MINLEN) {          /* min 8 bytes payload */
-    icmpstat.icps_tooshort++;
+    STAT(icmpstat.icps_tooshort++);
   freeit:
-    mbuf_free(m);
+    m_freem(m);
     goto end_error;
   }
 
   m->m_len -= hlen;
   m->m_data += hlen;
-  icp = MBUF_TO(m, struct icmp *);
+  icp = mtod(m, struct icmp *);
   if (cksum(m, icmplen)) {
-    icmpstat.icps_checksum++;
+    STAT(icmpstat.icps_checksum++);
     goto freeit;
   }
   m->m_len += hlen;
@@ -128,7 +124,7 @@
 	DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
 		    errno,errno_str));
 	sofree(so);
-	mbuf_free(m);
+	m_free(m);
 	goto end_error;
       }
       so->so_m = m;
@@ -172,17 +168,17 @@
   case ICMP_TSTAMP:
   case ICMP_MASKREQ:
   case ICMP_REDIRECT:
-    icmpstat.icps_notsupp++;
-    mbuf_free(m);
+    STAT(icmpstat.icps_notsupp++);
+    m_freem(m);
     break;
 
   default:
-    icmpstat.icps_badtype++;
-    mbuf_free(m);
+    STAT(icmpstat.icps_badtype++);
+    m_freem(m);
   } /* swith */
 
 end_error:
-  /* m is mbuf_free()'d xor put in a socket xor or given to ip_send */
+  /* m is m_free()'d xor put in a socket xor or given to ip_send */
   return;
 }
 
@@ -198,7 +194,7 @@
  */
 /*
  * Send ICMP_UNREACH back to the source regarding msrc.
- * mbuf *msrc is used as a template, but is NOT mbuf_free()'d.
+ * mbuf *msrc is used as a template, but is NOT m_free()'d.
  * It is reported as the bad ip packet.  The header should
  * be fully correct and in host byte order.
  * ICMP fragmentation is illegal.  All machines must accept 576 bytes in one
@@ -207,17 +203,13 @@
 
 #define ICMP_MAXDATALEN (IP_MSS-28)
 void
-icmp_error(msrc, type, code, minsize, message)
-     MBuf msrc;
-     u_char type;
-     u_char code;
-     int minsize;
-     const char *message;
+icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+           const char *message)
 {
   unsigned hlen, shlen, s_ip_len;
   register struct ip *ip;
   register struct icmp *icp;
-  register MBuf m;
+  register struct mbuf *m;
 
   DEBUG_CALL("icmp_error");
   DEBUG_ARG("msrc = %lx", (long )msrc);
@@ -227,8 +219,8 @@
 
   /* check msrc */
   if(!msrc) goto end_error;
-  ip = MBUF_TO(msrc, struct ip *);
-#if DEBUG
+  ip = mtod(msrc, struct ip *);
+#ifdef DEBUG
   { char bufa[20], bufb[20];
     strcpy(bufa, inet_iptostr(ip_geth(ip->ip_src)));
     strcpy(bufb, inet_iptostr(ip_geth(ip->ip_dst)));
@@ -249,23 +241,23 @@
   }
 
   /* make a copy */
-  if(!(m=mbuf_alloc())) goto end_error;               /* get mbuf */
+  if(!(m=m_get())) goto end_error;               /* get mbuf */
   { int new_m_size;
     new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
-    if(new_m_size>m->m_size) mbuf_ensure(m, new_m_size);
+    if(new_m_size>m->m_size) m_inc(m, new_m_size);
   }
   memcpy(m->m_data, msrc->m_data, msrc->m_len);
   m->m_len = msrc->m_len;                        /* copy msrc to m */
 
   /* make the header of the reply packet */
-  ip  = MBUF_TO(m, struct ip *);
+  ip  = mtod(m, struct ip *);
   hlen= sizeof(struct ip );     /* no options in reply */
 
   /* fill in icmp */
   m->m_data += hlen;
   m->m_len -= hlen;
 
-  icp = MBUF_TO(m, struct icmp *);
+  icp = mtod(m, struct icmp *);
 
   if(minsize) s_ip_len=shlen+ICMP_MINLEN;   /* return header+8b only */
   else if(s_ip_len>ICMP_MAXDATALEN)         /* maximum size */
@@ -285,7 +277,7 @@
   HTONS(icp->icmp_ip.ip_id);
   HTONS(icp->icmp_ip.ip_off);
 
-#if DEBUG
+#ifdef DEBUG
   if(message) {           /* DEBUG : append message to ICMP packet */
     int message_len;
     char *cpnt;
@@ -316,7 +308,7 @@
 
   (void ) ip_output((struct socket *)NULL, m);
 
-  icmpstat.icps_reflect++;
+  STAT(icmpstat.icps_reflect++);
 
 end_error:
   return;
@@ -327,10 +319,9 @@
  * Reflect the ip packet back to the source
  */
 void
-icmp_reflect(m)
-     MBuf m;
+icmp_reflect(struct mbuf *m)
 {
-  register struct ip *ip = MBUF_TO(m, struct ip *);
+  register struct ip *ip = mtod(m, struct ip *);
   int hlen = ip->ip_hl << 2;
   int optlen = hlen - sizeof(struct ip );
   register struct icmp *icp;
@@ -341,7 +332,7 @@
    */
   m->m_data += hlen;
   m->m_len -= hlen;
-  icp = MBUF_TO(m, struct icmp *);
+  icp = mtod(m, struct icmp *);
 
   icp->icmp_cksum = 0;
   icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
@@ -373,5 +364,5 @@
 
   (void ) ip_output((struct socket *)NULL, m);
 
-  icmpstat.icps_reflect++;
+  STAT(icmpstat.icps_reflect++);
 }
diff --git a/slirp2/ip_icmp.h b/slirp-android/ip_icmp.h
similarity index 93%
rename from slirp2/ip_icmp.h
rename to slirp-android/ip_icmp.h
index bc0be51..9be47e4 100644
--- a/slirp2/ip_icmp.h
+++ b/slirp-android/ip_icmp.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -159,8 +155,9 @@
 	(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
 	(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
 
-void icmp_input _P((MBuf , int));
-void icmp_error _P((MBuf , u_char, u_char, int, const char *));
-void icmp_reflect _P((MBuf ));
+void icmp_input _P((struct mbuf *, int));
+void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+                const char *message);
+void icmp_reflect _P((struct mbuf *));
 
 #endif
diff --git a/slirp2/ip_input.c b/slirp-android/ip_input.c
similarity index 78%
rename from slirp2/ip_input.c
rename to slirp-android/ip_input.c
index fa99a5d..aa6a6d5 100644
--- a/slirp2/ip_input.c
+++ b/slirp-android/ip_input.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -37,7 +33,7 @@
 /*
  * Changes and additions relating to SLiRP are
  * Copyright (c) 1995 Danny Gasparovski.
- * 
+ *
  * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
@@ -46,22 +42,30 @@
 #include <osdep.h>
 #include "ip_icmp.h"
 
-int ip_defttl;
+#ifdef LOG_ENABLED
 struct ipstat ipstat;
+#endif
+
 struct ipq ipq;
 
+static struct ip *ip_reass(register struct ip *ip,
+                           register struct ipq *fp);
+static void ip_freef(struct ipq *fp);
+static void ip_enq(register struct ipasfrag *p,
+                   register struct ipasfrag *prev);
+static void ip_deq(register struct ipasfrag *p);
+
 /*
  * IP initialization: fill in IP protocol switch table.
  * All protocols not implemented in kernel go to raw IP protocol handler.
  */
 void
-ip_init()
+ip_init(void)
 {
 	ipq.ip_link.next = ipq.ip_link.prev = &ipq.ip_link;
 	ip_id = tt.tv_sec & 0xffff;
 	udp_init();
 	tcp_init();
-	ip_defttl = IPDEFTTL;
 }
 
 /*
@@ -69,42 +73,41 @@
  * try to reassemble.  Process options.  Pass to next level.
  */
 void
-ip_input(m)
-	MBuf m;
+ip_input(struct mbuf *m)
 {
 	register struct ip *ip;
 	int hlen;
-	
+
 	DEBUG_CALL("ip_input");
 	DEBUG_ARG("m = %lx", (long)m);
 	DEBUG_ARG("m_len = %d", m->m_len);
 
-	ipstat.ips_total++;
-	
+	STAT(ipstat.ips_total++);
+
 	if (m->m_len < sizeof (struct ip)) {
-		ipstat.ips_toosmall++;
+		STAT(ipstat.ips_toosmall++);
 		return;
 	}
-	
-	ip = MBUF_TO(m, struct ip *);
-	
+
+	ip = mtod(m, struct ip *);
+
 	if (ip->ip_v != IPVERSION) {
-		ipstat.ips_badvers++;
+		STAT(ipstat.ips_badvers++);
 		goto bad;
 	}
 
 	hlen = ip->ip_hl << 2;
 	if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
-	  ipstat.ips_badhlen++;                     /* or packet too short */
+	  STAT(ipstat.ips_badhlen++);                     /* or packet too short */
 	  goto bad;
 	}
 
         /* keep ip header intact for ICMP reply
-	 * ip->ip_sum = cksum(m, hlen); 
-	 * if (ip->ip_sum) { 
+	 * ip->ip_sum = cksum(m, hlen);
+	 * if (ip->ip_sum) {
 	 */
 	if(cksum(m,hlen)) {
-	  ipstat.ips_badsum++;
+	  STAT(ipstat.ips_badsum++);
 	  goto bad;
 	}
 
@@ -113,7 +116,7 @@
 	 */
 	NTOHS(ip->ip_len);
 	if (ip->ip_len < hlen) {
-		ipstat.ips_badlen++;
+		STAT(ipstat.ips_badlen++);
 		goto bad;
 	}
 	NTOHS(ip->ip_id);
@@ -126,12 +129,33 @@
 	 * Drop packet if shorter than we expect.
 	 */
 	if (m->m_len < ip->ip_len) {
-		ipstat.ips_tooshort++;
+		STAT(ipstat.ips_tooshort++);
 		goto bad;
 	}
+
+    if (slirp_restrict) {
+        if (ip_geth(ip->ip_dst) != special_addr_ip) {
+            if (ip_getn(ip->ip_dst) == 0xffffffffu && ip->ip_p != IPPROTO_UDP)
+                goto bad;
+        } else {
+            int host = ip_geth(ip->ip_dst) & 0xff;
+            struct ex_list *ex_ptr;
+
+            if (host == 0xff)
+                goto bad;
+
+            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+                if (ex_ptr->ex_addr == host)
+                    break;
+
+            if (!ex_ptr)
+                goto bad;
+        }
+    }
+
 	/* Should drop packet if mbuf too long? hmmm... */
 	if (m->m_len > ip->ip_len)
-	   mbuf_trim(m, ip->ip_len - m->m_len);
+	   m_adj(m, ip->ip_len - m->m_len);
 
 	/* check ip_ttl for a correct ICMP reply */
 	if(ip->ip_ttl==0 || ip->ip_ttl==1) {
@@ -155,25 +179,25 @@
 	 * (We could look in the reassembly queue to see
 	 * if the packet was previously fragmented,
 	 * but it's not worth the time; just let them time out.)
-	 * 
+	 *
 	 * XXX This should fail, don't fragment yet
 	 */
 	if (ip->ip_off &~ IP_DF) {
 	  register struct ipq *fp;
-	  struct qlink *l;
+      struct qlink *l;
 		/*
 		 * Look for queue of fragments
 		 * of this datagram.
 		 */
 		for (l = ipq.ip_link.next; l != &ipq.ip_link; l = l->next) {
-		  fp = container_of(l, struct ipq, ip_link);
-		  if (ip->ip_id == fp->ipq_id &&
+            fp = container_of(l, struct ipq, ip_link);
+            if (ip->ip_id == fp->ipq_id &&
 		      ip_equal(ip->ip_src, fp->ipq_src) &&
 		      ip_equal(ip->ip_dst, fp->ipq_dst) &&
 		      ip->ip_p == fp->ipq_p)
-		  goto found;
-		}
-		fp = NULL;
+		    goto found;
+        }
+        fp = NULL;
 	found:
 
 		/*
@@ -184,7 +208,7 @@
 		ip->ip_len -= hlen;
 		if (ip->ip_off & IP_MF)
 		  ip->ip_tos |= 1;
-		else 
+		else
 		  ip->ip_tos &= ~1;
 
 		ip->ip_off <<= 3;
@@ -195,12 +219,12 @@
 		 * attempt reassembly; if it succeeds, proceed.
 		 */
 		if (ip->ip_tos & 1 || ip->ip_off) {
-			ipstat.ips_fragments++;
+			STAT(ipstat.ips_fragments++);
 			ip = ip_reass(ip, fp);
-			if (ip == 0)
+			if (ip == NULL)
 				return;
-			ipstat.ips_reassembled++;
-			m = MBUF_FROM(ip);
+			STAT(ipstat.ips_reassembled++);
+			m = dtom(ip);
 		} else
 			if (fp)
 		   	   ip_freef(fp);
@@ -211,7 +235,7 @@
 	/*
 	 * Switch out to protocol's input routine.
 	 */
-	ipstat.ips_delivered++;
+	STAT(ipstat.ips_delivered++);
 	switch (ip->ip_p) {
 	 case IPPROTO_TCP:
 		tcp_input(m, hlen, (struct socket *)NULL);
@@ -223,34 +247,31 @@
 		icmp_input(m, hlen);
 		break;
 	 default:
-		ipstat.ips_noproto++;
-		mbuf_free(m);
+		STAT(ipstat.ips_noproto++);
+		m_free(m);
 	}
 	return;
 bad:
-	mbuf_free(m);
+	m_freem(m);
 	return;
 }
 
 #define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink)))
 #define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink)))
-
 /*
  * Take incoming datagram fragment and try to
  * reassemble it into whole datagram.  If a chain for
  * reassembly of this datagram already exists, then it
  * is given as fp; otherwise have to make a chain.
  */
-struct ip *
-ip_reass(ip, fp)
-	register struct ip *ip;
-	register struct ipq *fp;
+static struct ip *
+ip_reass(register struct ip *ip, register struct ipq *fp)
 {
-	register MBuf m = MBUF_FROM(ip);
+	register struct mbuf *m = dtom(ip);
 	register struct ipasfrag *q;
 	int hlen = ip->ip_hl << 2;
 	int i, next;
-	
+
 	DEBUG_CALL("ip_reass");
 	DEBUG_ARG("ip = %lx", (long)ip);
 	DEBUG_ARG("fp = %lx", (long)fp);
@@ -267,40 +288,41 @@
 	/*
 	 * If first fragment to arrive, create a reassembly queue.
 	 */
-	if (fp == 0) {
-	  MBuf t;
-	  if ((t = mbuf_alloc()) == NULL) goto dropfrag;
-	  fp = MBUF_TO(t, struct ipq *);
+    if (fp == NULL) {
+	  struct mbuf *t;
+	  if ((t = m_get()) == NULL) goto dropfrag;
+	  fp = mtod(t, struct ipq *);
 	  insque(&fp->ip_link, &ipq.ip_link);
 	  fp->ipq_ttl = IPFRAGTTL;
 	  fp->ipq_p = ip->ip_p;
 	  fp->ipq_id = ip->ip_id;
 	  fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
 	  fp->ipq_src = ip->ip_src;
-	  fp->ipq_dst = ip->ip_src;
+	  fp->ipq_dst = ip->ip_dst;
 	  q = (struct ipasfrag *)fp;
 	  goto insert;
 	}
-	
+
 	/*
 	 * Find a segment which begins after this one does.
 	 */
-        for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
-             q = q->ipf_next)
-                if (q->ipf_off > ip->ip_off)
-                    break;
+	for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
+            q = q->ipf_next)
+		if (q->ipf_off > ip->ip_off)
+			break;
+
 	/*
 	 * If there is a preceding segment, it may provide some of
 	 * our data already.  If so, drop the data from the incoming
 	 * segment.  If it provides all of our data, drop us.
 	 */
-        if (q->ipf_prev != &fp->frag_link) {
-            struct ipasfrag *pq = q->ipf_prev;
-                i = pq->ipf_off + pq->ipf_len - ip->ip_off;
+	if (q->ipf_prev != &fp->frag_link) {
+        struct ipasfrag *pq = q->ipf_prev;
+		i = pq->ipf_off + pq->ipf_len - ip->ip_off;
 		if (i > 0) {
 			if (i >= ip->ip_len)
 				goto dropfrag;
-			mbuf_trim(MBUF_FROM(ip), i);
+			m_adj(dtom(ip), i);
 			ip->ip_off += i;
 			ip->ip_len -= i;
 		}
@@ -310,17 +332,17 @@
 	 * While we overlap succeeding segments trim them or,
 	 * if they are completely covered, dequeue them.
 	 */
-	while (q != (struct ipasfrag *)&fp->frag_link &&
-	     ip->ip_off + ip->ip_len > q->ipf_off) {
-	       i = (ip->ip_off + ip->ip_len) - q->ipf_off;
-	       if (i < q->ipf_len) {
-	           q->ipf_len -= i;
-	           q->ipf_off += i;
-                   mbuf_trim(MBUF_FROM(q), i);
-                   break;
+	while (q != (struct ipasfrag*)&fp->frag_link &&
+            ip->ip_off + ip->ip_len > q->ipf_off) {
+		i = (ip->ip_off + ip->ip_len) - q->ipf_off;
+		if (i < q->ipf_len) {
+			q->ipf_len -= i;
+			q->ipf_off += i;
+			m_adj(dtom(q), i);
+			break;
 		}
 		q = q->ipf_next;
-		mbuf_free(MBUF_FROM(q->ipf_prev));
+		m_freem(dtom(q->ipf_prev));
 		ip_deq(q->ipf_prev);
 	}
 
@@ -331,28 +353,26 @@
 	 */
 	ip_enq(iptofrag(ip), q->ipf_prev);
 	next = 0;
-	for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
-	     q = q->ipf_next) 
-        {
-            if (q->ipf_off != next)
-                return (0);
-
-            next += q->ipf_len;
+	for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link;
+            q = q->ipf_next) {
+		if (q->ipf_off != next)
+                        return NULL;
+		next += q->ipf_len;
 	}
 	if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
-		return (0);
+                return NULL;
 
 	/*
 	 * Reassembly is complete; concatenate fragments.
 	 */
-	q = fp->frag_link.next;
-	m = MBUF_FROM(q);
+    q = fp->frag_link.next;
+	m = dtom(q);
 
 	q = (struct ipasfrag *) q->ipf_next;
-	while (q != (struct ipasfrag *)&fp->frag_link) {
-	  MBuf t = MBUF_FROM(q);
+	while (q != (struct ipasfrag*)&fp->frag_link) {
+	  struct mbuf *t = dtom(q);
 	  q = (struct ipasfrag *) q->ipf_next;
-	  mbuf_append(m, t);
+	  m_cat(m, t);
 	}
 
 	/*
@@ -361,7 +381,7 @@
 	 * dequeue and discard fragment reassembly header.
 	 * Make header visible.
 	 */
-        q = fp->frag_link.next;
+	q = fp->frag_link.next;
 
 	/*
 	 * If the fragments concatenated to an mbuf that's
@@ -375,57 +395,55 @@
 	  q = (struct ipasfrag *)(m->m_ext + delta);
 	}
 
-	/* DEBUG_ARG("ip = %lx", (long)ip); 
+	/* DEBUG_ARG("ip = %lx", (long)ip);
 	 * ip=(struct ipasfrag *)m->m_data; */
 
-        ip = fragtoip(q);
-	ip->ip_len  = next;
+    ip = fragtoip(q);
+	ip->ip_len = next;
 	ip->ip_tos &= ~1;
-	ip->ip_src  = fp->ipq_src;
-	ip->ip_dst  = fp->ipq_dst;
+	ip->ip_src = fp->ipq_src;
+	ip->ip_dst = fp->ipq_dst;
 	remque(&fp->ip_link);
-	(void) mbuf_free(MBUF_FROM(fp));
+	(void) m_free(dtom(fp));
 	m->m_len += (ip->ip_hl << 2);
 	m->m_data -= (ip->ip_hl << 2);
 
 	return ip;
 
 dropfrag:
-	ipstat.ips_fragdropped++;
-	mbuf_free(m);
-	return (0);
+	STAT(ipstat.ips_fragdropped++);
+	m_freem(m);
+    return NULL;
 }
 
 /*
  * Free a fragment reassembly header and all
  * associated datagrams.
  */
-void
-ip_freef(fp)
-	struct ipq *fp;
+static void
+ip_freef(struct ipq *fp)
 {
 	register struct ipasfrag *q, *p;
 
-	for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; q = p) {
+	for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
 		p = q->ipf_next;
 		ip_deq(q);
-		mbuf_free(MBUF_FROM(q));
+		m_freem(dtom(q));
 	}
 	remque(&fp->ip_link);
-	(void) mbuf_free(MBUF_FROM(fp));
+	(void) m_free(dtom(fp));
 }
 
 /*
  * Put an ip fragment on a reassembly chain.
  * Like insque, but pointers in middle of structure.
  */
-void
-ip_enq(p, prev)
-	register struct ipasfrag *p, *prev;
+static void
+ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
 {
 	DEBUG_CALL("ip_enq");
 	DEBUG_ARG("prev = %lx", (long)prev);
-	p->ipf_prev = prev;
+	p->ipf_prev =  prev;
 	p->ipf_next = prev->ipf_next;
 	((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
 	prev->ipf_next = p;
@@ -434,9 +452,8 @@
 /*
  * To ip_enq as remque is to insque.
  */
-void
-ip_deq(p)
-	register struct ipasfrag *p;
+static void
+ip_deq(register struct ipasfrag *p)
 {
 	((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
 	((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
@@ -448,21 +465,22 @@
  * queue, discard it.
  */
 void
-ip_slowtimo()
+ip_slowtimo(void)
 {
-        struct qlink *l;
-	
+    struct qlink *l;
+
 	DEBUG_CALL("ip_slowtimo");
-	
-	l = ipq.ip_link.next;
-	if (l == 0)
+
+    l = ipq.ip_link.next;
+
+    if (l == NULL)
 	   return;
 
-        while (l != &ipq.ip_link) {
-            struct ipq *fp = container_of(l, struct ipq, ip_link);
-            l = l->next;
-            if (--fp->ipq_ttl == 0) {
-			ipstat.ips_fragtimeout++;
+	while (l != &ipq.ip_link) {
+        struct ipq *fp = container_of(l, struct ipq, ip_link);
+        l = l->next;
+		if (--fp->ipq_ttl == 0) {
+			STAT(ipstat.ips_fragtimeout++);
 			ip_freef(fp);
 		}
 	}
@@ -480,9 +498,9 @@
 
 int
 ip_dooptions(m)
-	MBuf m;
+	struct mbuf *m;
 {
-	register struct ip *ip = MBUF_TO(m, struct ip *);
+	register struct ip *ip = mtod(m, struct ip *);
 	register u_char *cp;
 	register struct ip_timestamp *ipt;
 	register struct in_ifaddr *ia;
@@ -669,7 +687,7 @@
 /* Not yet */
  	icmp_error(m, type, code, 0, 0);
 
-	ipstat.ips_badoptions++;
+	STAT(ipstat.ips_badoptions++);
 	return (1);
 }
 
@@ -683,12 +701,10 @@
  * (XXX) should be deleted; last arg currently ignored.
  */
 void
-ip_stripoptions(m, mopt)
-	register MBuf m;
-	MBuf mopt;
+ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
 {
 	register int i;
-	struct ip *ip = MBUF_TO(m, struct ip *);
+	struct ip *ip = mtod(m, struct ip *);
 	register caddr_t opts;
 	int olen;
 
@@ -697,6 +713,6 @@
 	i = m->m_len - (sizeof (struct ip) + olen);
 	memcpy(opts, opts  + olen, (unsigned)i);
 	m->m_len -= olen;
-	
+
 	ip->ip_hl = sizeof(struct ip) >> 2;
 }
diff --git a/slirp2/ip_output.c b/slirp-android/ip_output.c
similarity index 82%
rename from slirp2/ip_output.c
rename to slirp-android/ip_output.c
index 42d789c..5bce520 100644
--- a/slirp2/ip_output.c
+++ b/slirp-android/ip_output.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -46,6 +42,10 @@
 
 u_int16_t ip_id;
 
+/* Number of packets queued before we start sending
+ * (to prevent allocing too many mbufs) */
+#define IF_THRESH 10
+
 /*
  * IP output.  The packet in mbuf chain m contains a skeletal IP
  * header (with len, off, ttl, proto, tos, src, dst).
@@ -53,26 +53,24 @@
  * The mbuf opt, if present, will not be freed.
  */
 int
-ip_output(so, m0)
-	struct socket *so;
-	MBuf m0;
+ip_output(struct socket *so, struct mbuf *m0)
 {
 	register struct ip *ip;
-	register MBuf m = m0;
+	register struct mbuf *m = m0;
 	register int hlen = sizeof(struct ip );
 	int len, off, error = 0;
 
 	DEBUG_CALL("ip_output");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m0 = %lx", (long)m0);
-	
+
 	/* We do no options */
 /*	if (opt) {
  *		m = ip_insertoptions(m, opt, &len);
  *		hlen = len;
  *	}
  */
-	ip = MBUF_TO(m, struct ip *);
+	ip = mtod(m, struct ip *);
 	/*
 	 * Fill in IP header.
 	 */
@@ -80,23 +78,23 @@
 	ip->ip_off &= IP_DF;
 	ip->ip_id = htons(ip_id++);
 	ip->ip_hl = hlen >> 2;
-	ipstat.ips_localout++;
+	STAT(ipstat.ips_localout++);
 
 	/*
 	 * Verify that we have any chance at all of being able to queue
 	 *      the packet or packet fragments
 	 */
 	/* XXX Hmmm... */
-/*	if (if_queued > if_thresh && towrite <= 0) {
+/*	if (if_queued > IF_THRESH && towrite <= 0) {
  *		error = ENOBUFS;
  *		goto bad;
  *	}
  */
-	
+
 	/*
 	 * If small enough for interface, can just send directly.
 	 */
-	if ((u_int16_t)ip->ip_len <= if_mtu) {
+	if ((u_int16_t)ip->ip_len <= IF_MTU) {
 		ip->ip_len = htons((u_int16_t)ip->ip_len);
 		ip->ip_off = htons((u_int16_t)ip->ip_off);
 		ip->ip_sum = 0;
@@ -112,11 +110,11 @@
 	 */
 	if (ip->ip_off & IP_DF) {
 		error = -1;
-		ipstat.ips_cantfrag++;
+		STAT(ipstat.ips_cantfrag++);
 		goto bad;
 	}
-	
-	len = (if_mtu - hlen) &~ 7;       /* ip databytes per packet */
+
+	len = (IF_MTU - hlen) &~ 7;       /* ip databytes per packet */
 	if (len < 8) {
 		error = -1;
 		goto bad;
@@ -124,7 +122,7 @@
 
     {
 	int mhlen, firstlen = len;
-	MBuf *mnext = &m->m_nextpkt;
+	struct mbuf **mnext = &m->m_nextpkt;
 
 	/*
 	 * Loop through length of segment after first fragment,
@@ -134,16 +132,16 @@
 	mhlen = sizeof (struct ip);
 	for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) {
 	  register struct ip *mhip;
-	  m = mbuf_alloc();
-	  if (m == 0) {
+	  m = m_get();
+          if (m == NULL) {
 	    error = -1;
-	    ipstat.ips_odropped++;
+	    STAT(ipstat.ips_odropped++);
 	    goto sendorfree;
 	  }
-	  m->m_data += if_maxlinkhdr;
-	  mhip = MBUF_TO(m, struct ip *);
+	  m->m_data += IF_MAXLINKHDR;
+	  mhip = mtod(m, struct ip *);
 	  *mhip = *ip;
-		
+
 		/* No options */
 /*		if (hlen > sizeof (struct ip)) {
  *			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
@@ -156,28 +154,28 @@
 	    mhip->ip_off |= IP_MF;
 	  if (off + len >= (u_int16_t)ip->ip_len)
 	    len = (u_int16_t)ip->ip_len - off;
-	  else 
+	  else
 	    mhip->ip_off |= IP_MF;
 	  mhip->ip_len = htons((u_int16_t)(len + mhlen));
-	  
-	  if (mbuf_copy(m, m0, off, len) < 0) {
+
+	  if (m_copy(m, m0, off, len) < 0) {
 	    error = -1;
 	    goto sendorfree;
 	  }
-	  
+
 	  mhip->ip_off = htons((u_int16_t)mhip->ip_off);
 	  mhip->ip_sum = 0;
 	  mhip->ip_sum = cksum(m, mhlen);
 	  *mnext = m;
 	  mnext = &m->m_nextpkt;
-	  ipstat.ips_ofragments++;
+	  STAT(ipstat.ips_ofragments++);
 	}
 	/*
 	 * Update first fragment by trimming what's been copied out
 	 * and updating header, then send each fragment (in order).
 	 */
 	m = m0;
-	mbuf_trim(m, hlen + firstlen - (u_int16_t)ip->ip_len);
+	m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len);
 	ip->ip_len = htons((u_int16_t)m->m_len);
 	ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF));
 	ip->ip_sum = 0;
@@ -185,21 +183,21 @@
 sendorfree:
 	for (m = m0; m; m = m0) {
 		m0 = m->m_nextpkt;
-		m->m_nextpkt = 0;
+                m->m_nextpkt = NULL;
 		if (error == 0)
 			if_output(so, m);
 		else
-			mbuf_free(m);
+			m_freem(m);
 	}
 
 	if (error == 0)
-		ipstat.ips_fragmented++;
+		STAT(ipstat.ips_fragmented++);
     }
 
 done:
 	return (error);
 
 bad:
-	mbuf_free(m0);
+	m_freem(m0);
 	goto done;
 }
diff --git a/slirp2/libslirp.h b/slirp-android/libslirp.h
similarity index 62%
rename from slirp2/libslirp.h
rename to slirp-android/libslirp.h
index e74e71e..6086384 100644
--- a/slirp2/libslirp.h
+++ b/slirp-android/libslirp.h
@@ -19,7 +19,7 @@
 int    inet_strtoip(const char*  str, uint32_t  *ip);
 char*  inet_iptostr(uint32_t  ip);
 
-void slirp_init(void);
+void slirp_init(int restricted, const char *special_ip);
 
 void slirp_select_fill(int *pnfds,
                        fd_set *readfds, fd_set *writefds, fd_set *xfds);
@@ -32,6 +32,11 @@
 int slirp_can_output(void);
 void slirp_output(const uint8_t *pkt, int pkt_len);
 
+void slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+                                   const SockAddress *laddr,
+                                   const SockAddress *faddr),
+                     void *opaque);
+int slirp_redir_rm(int is_udp, int host_port);
 int slirp_redir(int is_udp, int host_port,
                 uint32_t guest_addr, int guest_port);
 
@@ -39,9 +44,17 @@
 
 int slirp_add_dns_server(const SockAddress*  dns_addr);
 int slirp_get_system_dns_servers(void);
+int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
+                   int guest_port);
 
 extern const char *tftp_prefix;
 extern char slirp_hostname[33];
+extern const char *bootp_filename;
+
+void slirp_stats(void);
+void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
+		int size);
+size_t slirp_socket_can_recv(int addr_low_byte, int guest_port);
 
 #ifdef __cplusplus
 }
diff --git a/slirp2/main.h b/slirp-android/main.h
similarity index 88%
rename from slirp2/main.h
rename to slirp-android/main.h
index 159e5f4..353462a 100644
--- a/slirp2/main.h
+++ b/slirp-android/main.h
@@ -19,6 +19,7 @@
 extern u_int32_t slirp_socket_addr;
 extern char *slirp_socket_passwd;
 extern int ctty_closed;
+extern int slirp_restrict;
 
 /*
  * Get the difference in 2 times from updtim()
@@ -45,9 +46,10 @@
 extern char *socket_path;
 extern int towrite_max;
 extern int ppp_exit;
-extern int so_options;
 extern int tcp_keepintvl;
 extern uint8_t client_ethaddr[6];
+extern const char *slirp_special_ip;
+extern int slirp_restrict;
 
 #define PROTO_SLIP 0x1
 #ifdef USE_PPP
@@ -55,3 +57,4 @@
 #endif
 
 void if_encap(const uint8_t *ip_data, int ip_data_len);
+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
diff --git a/slirp-android/mbuf.c b/slirp-android/mbuf.c
new file mode 100644
index 0000000..1d30a63
--- /dev/null
+++ b/slirp-android/mbuf.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+/*
+ * mbuf's in SLiRP are much simpler than the real mbufs in
+ * FreeBSD.  They are fixed size, determined by the MTU,
+ * so that one whole packet can fit.  Mbuf's cannot be
+ * chained together.  If there's more data than the mbuf
+ * could hold, an external malloced buffer is pointed to
+ * by m_ext (and the data pointers) and M_EXT is set in
+ * the flags
+ */
+
+#include <slirp.h>
+
+int mbuf_alloced = 0;
+struct mbuf m_freelist, m_usedlist;
+#define MBUF_THRESH 30
+int mbuf_max = 0;
+
+/*
+ * Find a nice value for msize
+ * XXX if_maxlinkhdr already in mtu
+ */
+#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6)
+
+void
+m_init(void)
+{
+	m_freelist.m_next = m_freelist.m_prev = &m_freelist;
+	m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist;
+}
+
+/*
+ * Get an mbuf from the free list, if there are none
+ * malloc one
+ *
+ * Because fragmentation can occur if we alloc new mbufs and
+ * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
+ * which tells m_free to actually free() it
+ */
+struct mbuf *
+m_get(void)
+{
+	register struct mbuf *m;
+	int flags = 0;
+
+	DEBUG_CALL("m_get");
+
+	if (m_freelist.m_next == &m_freelist) {
+		m = (struct mbuf *)malloc(SLIRP_MSIZE);
+		if (m == NULL) goto end_error;
+		mbuf_alloced++;
+		if (mbuf_alloced > MBUF_THRESH)
+			flags = M_DOFREE;
+		if (mbuf_alloced > mbuf_max)
+			mbuf_max = mbuf_alloced;
+	} else {
+		m = m_freelist.m_next;
+		remque(m);
+	}
+
+	/* Insert it in the used list */
+	insque(m,&m_usedlist);
+	m->m_flags = (flags | M_USEDLIST);
+
+	/* Initialise it */
+	m->m_size = SLIRP_MSIZE - sizeof(struct m_hdr);
+	m->m_data = m->m_dat;
+	m->m_len = 0;
+        m->m_nextpkt = NULL;
+        m->m_prevpkt = NULL;
+end_error:
+	DEBUG_ARG("m = %lx", (long )m);
+	return m;
+}
+
+void
+m_free(struct mbuf *m)
+{
+
+  DEBUG_CALL("m_free");
+  DEBUG_ARG("m = %lx", (long )m);
+
+  if(m) {
+	/* Remove from m_usedlist */
+	if (m->m_flags & M_USEDLIST)
+	   remque(m);
+
+	/* If it's M_EXT, free() it */
+	if (m->m_flags & M_EXT)
+	   free(m->m_ext);
+
+	/*
+	 * Either free() it or put it on the free list
+	 */
+	if (m->m_flags & M_DOFREE) {
+		free(m);
+		mbuf_alloced--;
+	} else if ((m->m_flags & M_FREELIST) == 0) {
+		insque(m,&m_freelist);
+		m->m_flags = M_FREELIST; /* Clobber other flags */
+	}
+  } /* if(m) */
+}
+
+/*
+ * Copy data from one mbuf to the end of
+ * the other.. if result is too big for one mbuf, malloc()
+ * an M_EXT data segment
+ */
+void
+m_cat(struct mbuf *m, struct mbuf *n)
+{
+	/*
+	 * If there's no room, realloc
+	 */
+	if (M_FREEROOM(m) < n->m_len)
+		m_inc(m,m->m_size+MINCSIZE);
+
+	memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
+	m->m_len += n->m_len;
+
+	m_free(n);
+}
+
+
+/* make m size bytes large */
+void
+m_inc(struct mbuf *m, int size)
+{
+	int datasize;
+
+	/* some compiles throw up on gotos.  This one we can fake. */
+        if(m->m_size>size) return;
+
+        if (m->m_flags & M_EXT) {
+	  datasize = m->m_data - m->m_ext;
+	  m->m_ext = (char *)realloc(m->m_ext,size);
+/*		if (m->m_ext == NULL)
+ *			return (struct mbuf *)NULL;
+ */
+	  m->m_data = m->m_ext + datasize;
+        } else {
+	  char *dat;
+	  datasize = m->m_data - m->m_dat;
+	  dat = (char *)malloc(size);
+/*		if (dat == NULL)
+ *			return (struct mbuf *)NULL;
+ */
+	  memcpy(dat, m->m_dat, m->m_size);
+
+	  m->m_ext = dat;
+	  m->m_data = m->m_ext + datasize;
+	  m->m_flags |= M_EXT;
+        }
+
+        m->m_size = size;
+
+}
+
+
+
+void
+m_adj(struct mbuf *m, int len)
+{
+	if (m == NULL)
+		return;
+	if (len >= 0) {
+		/* Trim from head */
+		m->m_data += len;
+		m->m_len -= len;
+	} else {
+		/* Trim from tail */
+		len = -len;
+		m->m_len -= len;
+	}
+}
+
+
+/*
+ * Copy len bytes from m, starting off bytes into n
+ */
+int
+m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
+{
+	if (len > M_FREEROOM(n))
+		return -1;
+
+	memcpy((n->m_data + n->m_len), (m->m_data + off), len);
+	n->m_len += len;
+	return 0;
+}
+
+
+/*
+ * Given a pointer into an mbuf, return the mbuf
+ * XXX This is a kludge, I should eliminate the need for it
+ * Fortunately, it's not used often
+ */
+struct mbuf *
+dtom(void *dat)
+{
+	struct mbuf *m;
+
+	DEBUG_CALL("dtom");
+	DEBUG_ARG("dat = %lx", (long )dat);
+
+	/* bug corrected for M_EXT buffers */
+	for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) {
+	  if (m->m_flags & M_EXT) {
+	    if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) )
+	      return m;
+	  } else {
+	    if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) )
+	      return m;
+	  }
+	}
+
+	DEBUG_ERROR((dfd, "dtom failed"));
+
+	return (struct mbuf *)0;
+}
diff --git a/slirp-android/mbuf.h b/slirp-android/mbuf.h
new file mode 100644
index 0000000..5527373
--- /dev/null
+++ b/slirp-android/mbuf.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)mbuf.h	8.3 (Berkeley) 1/21/94
+ * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
+ */
+
+#ifndef _MBUF_H_
+#define _MBUF_H_
+
+#define m_freem m_free
+
+
+#define MINCSIZE 4096	/* Amount to increase mbuf if too small */
+
+/*
+ * Macros for type conversion
+ * mtod(m,t) -	convert mbuf pointer to data pointer of correct type
+ * dtom(x) -	convert data pointer within mbuf to mbuf pointer (XXX)
+ */
+#define mtod(m,t)	((t)(m)->m_data)
+/* #define	dtom(x)		((struct mbuf *)((int)(x) & ~(M_SIZE-1))) */
+
+/* XXX About mbufs for slirp:
+ * Only one mbuf is ever used in a chain, for each "cell" of data.
+ * m_nextpkt points to the next packet, if fragmented.
+ * If the data is too large, the M_EXT is used, and a larger block
+ * is alloced.  Therefore, m_free[m] must check for M_EXT and if set
+ * free the m_ext.  This is inefficient memory-wise, but who cares.
+ */
+
+/* XXX should union some of these! */
+/* header at beginning of each mbuf: */
+struct m_hdr {
+	struct	mbuf *mh_next;		/* Linked list of mbufs */
+	struct	mbuf *mh_prev;
+	struct	mbuf *mh_nextpkt;	/* Next packet in queue/record */
+	struct	mbuf *mh_prevpkt; /* Flags aren't used in the output queue */
+	int	mh_flags;	  /* Misc flags */
+
+	int	mh_size;		/* Size of data */
+	struct	socket *mh_so;
+
+	caddr_t	mh_data;		/* Location of data */
+	int	mh_len;			/* Amount of data in this mbuf */
+};
+
+/*
+ * How much room is in the mbuf, from m_data to the end of the mbuf
+ */
+#define M_ROOM(m) ((m->m_flags & M_EXT)? \
+			(((m)->m_ext + (m)->m_size) - (m)->m_data) \
+		   : \
+			(((m)->m_dat + (m)->m_size) - (m)->m_data))
+
+/*
+ * How much free room there is
+ */
+#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
+#define M_TRAILINGSPACE M_FREEROOM
+
+struct mbuf {
+	struct	m_hdr m_hdr;
+	union M_dat {
+		char	m_dat_[1]; /* ANSI don't like 0 sized arrays */
+		char	*m_ext_;
+	} M_dat;
+};
+
+#define m_next		m_hdr.mh_next
+#define m_prev		m_hdr.mh_prev
+#define m_nextpkt	m_hdr.mh_nextpkt
+#define m_prevpkt	m_hdr.mh_prevpkt
+#define m_flags		m_hdr.mh_flags
+#define	m_len		m_hdr.mh_len
+#define	m_data		m_hdr.mh_data
+#define m_size		m_hdr.mh_size
+#define m_dat		M_dat.m_dat_
+#define m_ext		M_dat.m_ext_
+#define m_so		m_hdr.mh_so
+
+#define ifq_prev m_prev
+#define ifq_next m_next
+#define ifs_prev m_prevpkt
+#define ifs_next m_nextpkt
+#define ifq_so m_so
+
+#define M_EXT			0x01	/* m_ext points to more (malloced) data */
+#define M_FREELIST		0x02	/* mbuf is on free list */
+#define M_USEDLIST		0x04	/* XXX mbuf is on used list (for dtom()) */
+#define M_DOFREE		0x08	/* when m_free is called on the mbuf, free()
+					 * it rather than putting it on the free list */
+
+/*
+ * Mbuf statistics. XXX
+ */
+
+struct mbstat {
+	int mbs_alloced;		/* Number of mbufs allocated */
+
+};
+
+extern struct	mbstat mbstat;
+extern int mbuf_alloced;
+extern struct mbuf m_freelist, m_usedlist;
+extern int mbuf_max;
+
+void m_init _P((void));
+struct mbuf * m_get _P((void));
+void m_free _P((struct mbuf *));
+void m_cat _P((register struct mbuf *, register struct mbuf *));
+void m_inc _P((struct mbuf *, int));
+void m_adj _P((struct mbuf *, int));
+int m_copy _P((struct mbuf *, struct mbuf *, int, int));
+struct mbuf * dtom _P((void *));
+
+#endif
diff --git a/slirp-android/misc.c b/slirp-android/misc.c
new file mode 100644
index 0000000..fb8ec5f
--- /dev/null
+++ b/slirp-android/misc.c
@@ -0,0 +1,870 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#define WANT_SYS_IOCTL_H
+#include <slirp.h>
+
+u_int curtime, time_fasttimo, last_slowtimo, detach_time;
+u_int detach_wait = 600000;	/* 10 minutes */
+struct emu_t *tcpemu;
+
+int
+inet_strtoip(const char*  str, uint32_t  *ip)
+{
+    int  comp[4];
+
+    if (sscanf(str, "%d.%d.%d.%d", &comp[0], &comp[1], &comp[2], &comp[3]) != 4)
+        return -1;
+
+    if ((unsigned)comp[0] >= 256 ||
+        (unsigned)comp[1] >= 256 ||
+        (unsigned)comp[2] >= 256 ||
+        (unsigned)comp[3] >= 256)
+        return -1;
+
+    *ip = (uint32_t)((comp[0] << 24) | (comp[1] << 16) |
+                     (comp[2] << 8)  |  comp[3]);
+    return 0;
+}
+
+char*  inet_iptostr(uint32_t  ip)
+{
+    static char  buff[32];
+
+    snprintf(buff, sizeof(buff), "%d.%d.%d.%d",
+             (ip >> 24) & 255,
+             (ip >> 16) & 255,
+             (ip >> 8) & 255,
+             ip & 255);
+    return buff;
+}
+
+/*
+ * Get our IP address and put it in our_addr
+ */
+void
+getouraddr()
+{
+    char*        hostname = host_name();
+    SockAddress  hostaddr;
+
+    our_addr_ip = loopback_addr_ip;
+
+    if (sock_address_init_resolve( &hostaddr, hostname, 0, 0 ) < 0)
+        return;
+
+    our_addr_ip = sock_address_get_ip(&hostaddr);
+    if (our_addr_ip == (uint32_t)-1)
+        our_addr_ip = loopback_addr_ip;
+}
+
+struct quehead {
+	struct quehead *qh_link;
+	struct quehead *qh_rlink;
+};
+
+inline void
+insque(void *a, void *b)
+{
+	register struct quehead *element = (struct quehead *) a;
+	register struct quehead *head = (struct quehead *) b;
+	element->qh_link = head->qh_link;
+	head->qh_link = (struct quehead *)element;
+	element->qh_rlink = (struct quehead *)head;
+	((struct quehead *)(element->qh_link))->qh_rlink
+	= (struct quehead *)element;
+}
+
+inline void
+remque(void *a)
+{
+  register struct quehead *element = (struct quehead *) a;
+  ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
+  ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
+  element->qh_rlink = NULL;
+  /*  element->qh_link = NULL;  TCP FIN1 crashes if you do this.  Why ? */
+}
+
+/* #endif */
+
+
+int
+add_exec(struct ex_list **ex_ptr, int do_pty, char *exec, int addr, int port)
+{
+	struct ex_list *tmp_ptr;
+
+	/* First, check if the port is "bound" */
+	for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
+		if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr)
+		   return -1;
+	}
+
+	tmp_ptr = *ex_ptr;
+	*ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
+	(*ex_ptr)->ex_fport = port;
+	(*ex_ptr)->ex_addr = addr;
+	(*ex_ptr)->ex_pty = do_pty;
+	(*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec);
+	(*ex_ptr)->ex_next = tmp_ptr;
+	return 0;
+}
+
+#ifndef HAVE_STRERROR
+
+/*
+ * For systems with no strerror
+ */
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(error)
+	int error;
+{
+	if (error < sys_nerr)
+	   return sys_errlist[error];
+	else
+	   return "Unknown error.";
+}
+
+#endif
+
+
+#ifdef _WIN32
+
+int
+fork_exec(struct socket *so, const char *ex, int do_pty)
+{
+    /* not implemented */
+    return 0;
+}
+
+#else
+
+#ifndef CONFIG_QEMU
+int
+slirp_openpty(amaster, aslave)
+     int *amaster, *aslave;
+{
+	register int master, slave;
+
+#ifdef HAVE_GRANTPT
+	char *ptr;
+
+	if ((master = open("/dev/ptmx", O_RDWR)) < 0 ||
+	    grantpt(master) < 0 ||
+	    unlockpt(master) < 0 ||
+	    (ptr = ptsname(master)) == NULL)  {
+		close(master);
+		return -1;
+	}
+
+	if ((slave = open(ptr, O_RDWR)) < 0 ||
+	    ioctl(slave, I_PUSH, "ptem") < 0 ||
+	    ioctl(slave, I_PUSH, "ldterm") < 0 ||
+	    ioctl(slave, I_PUSH, "ttcompat") < 0) {
+		close(master);
+		close(slave);
+		return -1;
+	}
+
+	*amaster = master;
+	*aslave = slave;
+	return 0;
+
+#else
+
+	static char line[] = "/dev/ptyXX";
+	register const char *cp1, *cp2;
+
+	for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
+		line[8] = *cp1;
+		for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
+			line[9] = *cp2;
+			if ((master = open(line, O_RDWR, 0)) == -1) {
+				if (errno == ENOENT)
+				   return (-1);    /* out of ptys */
+			} else {
+				line[5] = 't';
+				/* These will fail */
+				(void) chown(line, getuid(), 0);
+				(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
+#ifdef HAVE_REVOKE
+				(void) revoke(line);
+#endif
+				if ((slave = open(line, O_RDWR, 0)) != -1) {
+					*amaster = master;
+					*aslave = slave;
+					return 0;
+				}
+				(void) close(master);
+				line[5] = 'p';
+			}
+		}
+	}
+	errno = ENOENT; /* out of ptys */
+	return (-1);
+#endif
+}
+#endif
+
+/*
+ * XXX This is ugly
+ * We create and bind a socket, then fork off to another
+ * process, which connects to this socket, after which we
+ * exec the wanted program.  If something (strange) happens,
+ * the accept() call could block us forever.
+ *
+ * do_pty = 0   Fork/exec inetd style
+ * do_pty = 1   Fork/exec using slirp.telnetd
+ * do_ptr = 2   Fork/exec using pty
+ */
+int
+fork_exec(struct socket *so, const char *ex, int do_pty)
+{
+	int s;
+        int master = -1;
+	const char *argv[256];
+#if 0
+	char buff[256];
+#endif
+	/* don't want to clobber the original */
+	char *bptr;
+	const char *curarg;
+	int c, i;
+
+	DEBUG_CALL("fork_exec");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("ex = %lx", (long)ex);
+	DEBUG_ARG("do_pty = %lx", (long)do_pty);
+
+	if (do_pty == 2) {
+#if 0
+		if (slirp_openpty(&master, &s) == -1) {
+			lprint("Error: openpty failed: %s\n", strerror(errno));
+			return 0;
+		}
+#else
+                return 0;
+#endif
+	} else {
+		if ((s = socket_anyaddr_server(0, SOCKET_STREAM)) < 0) {
+			lprint("Error: inet socket: %s\n", errno_str);
+			return 0;
+		}
+	}
+
+	switch(fork()) {
+	 case -1:
+		lprint("Error: fork failed: %s\n", strerror(errno));
+		close(s);
+		if (do_pty == 2)
+		   close(master);
+		return 0;
+
+	 case 0:
+		/* Set the DISPLAY */
+		if (do_pty == 2) {
+			(void) close(master);
+#ifdef TIOCSCTTY /* XXXXX */
+			(void) setsid();
+			ioctl(s, TIOCSCTTY, (char *)NULL);
+#endif
+		} else {
+			SockAddress  addr;
+			socket_get_address(s, &addr);
+			socket_close(s);
+			/*
+			 * Connect to the socket
+			 * XXX If any of these fail, we're in trouble!
+	 		 */
+            s = socket_loopback_client(sock_address_get_port(&addr), SOCKET_STREAM);
+		}
+
+#if 0
+		if (x_port >= 0) {
+#ifdef HAVE_SETENV
+			sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
+			setenv("DISPLAY", buff, 1);
+#else
+			sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
+			putenv(buff);
+#endif
+		}
+#endif
+		dup2(s, 0);
+		dup2(s, 1);
+		dup2(s, 2);
+		for (s = getdtablesize() - 1; s >= 3; s--)
+		   close(s);
+
+		i = 0;
+		bptr = strdup(ex); /* No need to free() this */
+		if (do_pty == 1) {
+			/* Setup "slirp.telnetd -x" */
+			argv[i++] = "slirp.telnetd";
+			argv[i++] = "-x";
+			argv[i++] = bptr;
+		} else
+		   do {
+			/* Change the string into argv[] */
+			curarg = bptr;
+			while (*bptr != ' ' && *bptr != (char)0)
+			   bptr++;
+			c = *bptr;
+			*bptr++ = (char)0;
+			argv[i++] = strdup(curarg);
+		   } while (c);
+
+                argv[i] = NULL;
+		execvp(argv[0], (char **)argv);
+
+		/* Ooops, failed, let's tell the user why */
+		  {
+			  char buff[256];
+
+			  snprintf(buff, sizeof(buff),
+                                   "Error: execvp of %s failed: %s\n",
+                                   argv[0], strerror(errno));
+			  write(2, buff, strlen(buff)+1);
+		  }
+		close(0); close(1); close(2); /* XXX */
+		exit(1);
+
+	 default:
+		if (do_pty == 2) {
+			close(s);
+			so->s = master;
+		} else {
+			/*
+			 * XXX this could block us...
+			 * XXX Should set a timer here, and if accept() doesn't
+		 	 * return after X seconds, declare it a failure
+		 	 * The only reason this will block forever is if socket()
+		 	 * of connect() fail in the child process
+		 	 */
+             so->s = socket_accept(s, NULL);
+			 socket_set_xreuseaddr(so->s);
+             socket_set_oobinline(so->s);
+		}
+		socket_set_nonblock(so->s);
+
+		/* Append the telnet options now */
+                if (so->so_m != NULL && do_pty == 1)  {
+			sbappend(so, so->so_m);
+                        so->so_m = NULL;
+		}
+
+		return 1;
+	}
+}
+#endif
+
+#ifndef HAVE_STRDUP
+char *
+strdup(const char*  str)
+{
+	char *bptr;
+	int   len = strlen(str);
+
+	bptr = (char *)malloc(len+1);
+	memcpy(bptr, str, len+1);
+
+	return bptr;
+}
+#endif
+
+#if 0
+void
+snooze_hup(num)
+	int num;
+{
+	int s, ret;
+#ifndef NO_UNIX_SOCKETS
+	struct sockaddr_un sock_un;
+#endif
+	struct sockaddr_in sock_in;
+	char buff[256];
+
+	ret = -1;
+	if (slirp_socket_passwd) {
+		s = socket(AF_INET, SOCK_STREAM, 0);
+		if (s < 0)
+		   slirp_exit(1);
+		sock_in.sin_family = AF_INET;
+		sock_in.sin_addr.s_addr = slirp_socket_addr;
+		sock_in.sin_port = htons(slirp_socket_port);
+		if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0)
+		   slirp_exit(1); /* just exit...*/
+		sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit);
+		write(s, buff, strlen(buff)+1);
+	}
+#ifndef NO_UNIX_SOCKETS
+	  else {
+		s = socket(AF_UNIX, SOCK_STREAM, 0);
+		if (s < 0)
+		   slirp_exit(1);
+		sock_un.sun_family = AF_UNIX;
+		strcpy(sock_un.sun_path, socket_path);
+		if (connect(s, (struct sockaddr *)&sock_un,
+			      sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0)
+		   slirp_exit(1);
+		sprintf(buff, "kill none:%d", slirp_socket_unit);
+		write(s, buff, strlen(buff)+1);
+	}
+#endif
+	slirp_exit(0);
+}
+
+
+void
+snooze()
+{
+	sigset_t s;
+	int i;
+
+	/* Don't need our data anymore */
+	/* XXX This makes SunOS barf */
+/*	brk(0); */
+
+	/* Close all fd's */
+	for (i = 255; i >= 0; i--)
+	   close(i);
+
+	signal(SIGQUIT, slirp_exit);
+	signal(SIGHUP, snooze_hup);
+	sigemptyset(&s);
+
+	/* Wait for any signal */
+	sigsuspend(&s);
+
+	/* Just in case ... */
+	exit(255);
+}
+
+void
+relay(s)
+	int s;
+{
+	char buf[8192];
+	int n;
+	fd_set readfds;
+	struct ttys *ttyp;
+
+	/* Don't need our data anymore */
+	/* XXX This makes SunOS barf */
+/*	brk(0); */
+
+	signal(SIGQUIT, slirp_exit);
+	signal(SIGHUP, slirp_exit);
+        signal(SIGINT, slirp_exit);
+	signal(SIGTERM, slirp_exit);
+
+	/* Fudge to get term_raw and term_restore to work */
+	if (NULL == (ttyp = tty_attach (0, slirp_tty))) {
+         lprint ("Error: tty_attach failed in misc.c:relay()\r\n");
+         slirp_exit (1);
+    }
+	ttyp->fd = 0;
+	ttyp->flags |= TTY_CTTY;
+	term_raw(ttyp);
+
+	while (1) {
+		FD_ZERO(&readfds);
+
+		FD_SET(0, &readfds);
+		FD_SET(s, &readfds);
+
+		n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
+
+		if (n <= 0)
+		   slirp_exit(0);
+
+		if (FD_ISSET(0, &readfds)) {
+			n = read(0, buf, 8192);
+			if (n <= 0)
+			   slirp_exit(0);
+			n = writen(s, buf, n);
+			if (n <= 0)
+			   slirp_exit(0);
+		}
+
+		if (FD_ISSET(s, &readfds)) {
+			n = read(s, buf, 8192);
+			if (n <= 0)
+			   slirp_exit(0);
+			n = writen(0, buf, n);
+			if (n <= 0)
+			   slirp_exit(0);
+		}
+	}
+
+	/* Just in case.... */
+	exit(1);
+}
+#endif
+
+#ifdef CONFIG_QEMU
+#include "monitor.h"
+
+void lprint(const char *format, ...)
+{
+    va_list args;
+
+    va_start(args, format);
+    monitor_vprintf(cur_mon, format, args);
+    va_end(args);
+}
+#else
+int (*lprint_print) _P((void *, const char *, va_list));
+char *lprint_ptr, *lprint_ptr2, **lprint_arg;
+
+void
+#ifdef __STDC__
+lprint(const char *format, ...)
+#else
+lprint(va_alist) va_dcl
+#endif
+{
+	va_list args;
+
+#ifdef __STDC__
+        va_start(args, format);
+#else
+        char *format;
+        va_start(args);
+        format = va_arg(args, char *);
+#endif
+#if 0
+	/* If we're printing to an sbuf, make sure there's enough room */
+	/* XXX +100? */
+	if (lprint_sb) {
+		if ((lprint_ptr - lprint_sb->sb_wptr) >=
+		    (lprint_sb->sb_datalen - (strlen(format) + 100))) {
+			int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data;
+			int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data;
+			int deltap = lprint_ptr -         lprint_sb->sb_data;
+
+			lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data,
+							     lprint_sb->sb_datalen + TCP_SNDSPACE);
+
+			/* Adjust all values */
+			lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw;
+			lprint_sb->sb_rptr = lprint_sb->sb_data + deltar;
+			lprint_ptr =         lprint_sb->sb_data + deltap;
+
+			lprint_sb->sb_datalen += TCP_SNDSPACE;
+		}
+	}
+#endif
+	if (lprint_print)
+	   lprint_ptr += (*lprint_print)(*lprint_arg, format, args);
+
+	/* Check if they want output to be logged to file as well */
+	if (lfd) {
+		/*
+		 * Remove \r's
+		 * otherwise you'll get ^M all over the file
+		 */
+		int len = strlen(format);
+		char *bptr1, *bptr2;
+
+		bptr1 = bptr2 = strdup(format);
+
+		while (len--) {
+			if (*bptr1 == '\r')
+			   memcpy(bptr1, bptr1+1, len+1);
+			else
+			   bptr1++;
+		}
+		vfprintf(lfd, bptr2, args);
+		free(bptr2);
+	}
+	va_end(args);
+}
+
+void
+add_emu(buff)
+	char *buff;
+{
+	u_int lport, fport;
+	u_int8_t tos = 0, emu = 0;
+	char buff1[256], buff2[256], buff4[128];
+	char *buff3 = buff4;
+	struct emu_t *emup;
+	struct socket *so;
+
+	if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) {
+		lprint("Error: Bad arguments\r\n");
+		return;
+	}
+
+	if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) {
+		lport = 0;
+		if (sscanf(buff1, "%d", &fport) != 1) {
+			lprint("Error: Bad first argument\r\n");
+			return;
+		}
+	}
+
+	if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) {
+		buff3 = 0;
+		if (sscanf(buff2, "%256s", buff1) != 1) {
+			lprint("Error: Bad second argument\r\n");
+			return;
+		}
+	}
+
+	if (buff3) {
+		if (strcmp(buff3, "lowdelay") == 0)
+		   tos = IPTOS_LOWDELAY;
+		else if (strcmp(buff3, "throughput") == 0)
+		   tos = IPTOS_THROUGHPUT;
+		else {
+			lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n");
+			return;
+		}
+	}
+
+	if (strcmp(buff1, "ftp") == 0)
+	   emu = EMU_FTP;
+	else if (strcmp(buff1, "irc") == 0)
+	   emu = EMU_IRC;
+	else if (strcmp(buff1, "none") == 0)
+	   emu = EMU_NONE; /* ie: no emulation */
+	else {
+		lprint("Error: Unknown service\r\n");
+		return;
+	}
+
+	/* First, check that it isn't already emulated */
+	for (emup = tcpemu; emup; emup = emup->next) {
+		if (emup->lport == lport && emup->fport == fport) {
+			lprint("Error: port already emulated\r\n");
+			return;
+		}
+	}
+
+	/* link it */
+	emup = (struct emu_t *)malloc(sizeof (struct emu_t));
+	emup->lport = (u_int16_t)lport;
+	emup->fport = (u_int16_t)fport;
+	emup->tos = tos;
+	emup->emu = emu;
+	emup->next = tcpemu;
+	tcpemu = emup;
+
+	/* And finally, mark all current sessions, if any, as being emulated */
+	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
+		if ((lport && lport == so->so_laddr_port) ||
+		    (fport && fport == so->so_faddr_port)) {
+			if (emu)
+			   so->so_emu = emu;
+			if (tos)
+			   so->so_iptos = tos;
+		}
+	}
+
+	lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport);
+}
+#endif
+
+#ifdef BAD_SPRINTF
+
+#undef vsprintf
+#undef sprintf
+
+/*
+ * Some BSD-derived systems have a sprintf which returns char *
+ */
+
+int
+vsprintf_len(string, format, args)
+	char *string;
+	const char *format;
+	va_list args;
+{
+	vsprintf(string, format, args);
+	return strlen(string);
+}
+
+int
+#ifdef __STDC__
+sprintf_len(char *string, const char *format, ...)
+#else
+sprintf_len(va_alist) va_dcl
+#endif
+{
+	va_list args;
+#ifdef __STDC__
+	va_start(args, format);
+#else
+	char *string;
+	char *format;
+	va_start(args);
+	string = va_arg(args, char *);
+	format = va_arg(args, char *);
+#endif
+	vsprintf(string, format, args);
+	return strlen(string);
+}
+
+#endif
+
+#if 0
+void
+u_sleep(int usec)
+{
+	struct timeval t;
+	fd_set fdset;
+
+	FD_ZERO(&fdset);
+
+	t.tv_sec = 0;
+	t.tv_usec = usec * 1000;
+
+	select(0, &fdset, &fdset, &fdset, &t);
+}
+#endif
+
+/*
+ * Set fd blocking and non-blocking
+ */
+
+void
+fd_nonblock(int fd)
+{
+#ifdef FIONBIO
+#ifdef _WIN32
+        unsigned long opt = 1;
+#else
+        int opt = 1;
+#endif
+
+	ioctlsocket(fd, FIONBIO, &opt);
+#else
+	int opt;
+
+	opt = fcntl(fd, F_GETFL, 0);
+	opt |= O_NONBLOCK;
+	fcntl(fd, F_SETFL, opt);
+#endif
+}
+
+void
+fd_block(int fd)
+{
+#ifdef FIONBIO
+#ifdef _WIN32
+        unsigned long opt = 0;
+#else
+	int opt = 0;
+#endif
+
+	ioctlsocket(fd, FIONBIO, &opt);
+#else
+	int opt;
+
+	opt = fcntl(fd, F_GETFL, 0);
+	opt &= ~O_NONBLOCK;
+	fcntl(fd, F_SETFL, opt);
+#endif
+}
+
+
+#if 0
+/*
+ * invoke RSH
+ */
+int
+rsh_exec(so,ns, user, host, args)
+	struct socket *so;
+	struct socket *ns;
+	char *user;
+	char *host;
+	char *args;
+{
+	int fd[2];
+	int fd0[2];
+	int s;
+	char buff[256];
+
+	DEBUG_CALL("rsh_exec");
+	DEBUG_ARG("so = %lx", (long)so);
+
+	if (pipe(fd)<0) {
+          lprint("Error: pipe failed: %s\n", strerror(errno));
+          return 0;
+	}
+/* #ifdef HAVE_SOCKETPAIR */
+#if 1
+        if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) {
+          close(fd[0]);
+          close(fd[1]);
+          lprint("Error: openpty failed: %s\n", strerror(errno));
+          return 0;
+        }
+#else
+        if (slirp_openpty(&fd0[0], &fd0[1]) == -1) {
+          close(fd[0]);
+          close(fd[1]);
+          lprint("Error: openpty failed: %s\n", strerror(errno));
+          return 0;
+        }
+#endif
+
+	switch(fork()) {
+	 case -1:
+           lprint("Error: fork failed: %s\n", strerror(errno));
+           close(fd[0]);
+           close(fd[1]);
+           close(fd0[0]);
+           close(fd0[1]);
+           return 0;
+
+	 case 0:
+           close(fd[0]);
+           close(fd0[0]);
+
+		/* Set the DISPLAY */
+           if (x_port >= 0) {
+#ifdef HAVE_SETENV
+             sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
+             setenv("DISPLAY", buff, 1);
+#else
+             sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
+             putenv(buff);
+#endif
+           }
+
+           dup2(fd0[1], 0);
+           dup2(fd0[1], 1);
+           dup2(fd[1], 2);
+           for (s = 3; s <= 255; s++)
+             close(s);
+
+           execlp("rsh","rsh","-l", user, host, args, NULL);
+
+           /* Ooops, failed, let's tell the user why */
+
+           sprintf(buff, "Error: execlp of %s failed: %s\n",
+                   "rsh", strerror(errno));
+           write(2, buff, strlen(buff)+1);
+           close(0); close(1); close(2); /* XXX */
+           exit(1);
+
+        default:
+          close(fd[1]);
+          close(fd0[1]);
+          ns->s=fd[0];
+          so->s=fd0[0];
+
+          return 1;
+	}
+}
+#endif
diff --git a/slirp-android/misc.h b/slirp-android/misc.h
new file mode 100644
index 0000000..ad64474
--- /dev/null
+++ b/slirp-android/misc.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _MISC_H_
+#define _MISC_H_
+
+struct ex_list {
+	int ex_pty;			/* Do we want a pty? */
+	int ex_addr;			/* The last byte of the address */
+	int ex_fport;                   /* Port to telnet to */
+	const char *ex_exec;            /* Command line of what to exec */
+	struct ex_list *ex_next;
+};
+
+extern struct ex_list *exec_list;
+extern u_int time_fasttimo, last_slowtimo;
+
+extern int (*lprint_print) _P((void *, const char *, va_list));
+extern char *lprint_ptr, *lprint_ptr2, **lprint_arg;
+extern struct sbuf *lprint_sb;
+
+#ifndef HAVE_STRDUP
+char *strdup _P((const char *));
+#endif
+
+void do_wait _P((int));
+
+#define EMU_NONE 0x0
+
+/* TCP emulations */
+#define EMU_CTL 0x1
+#define EMU_FTP 0x2
+#define EMU_KSH 0x3
+#define EMU_IRC 0x4
+#define EMU_REALAUDIO 0x5
+#define EMU_RLOGIN 0x6
+#define EMU_IDENT 0x7
+#define EMU_RSH 0x8
+
+#define EMU_NOCONNECT 0x10	/* Don't connect */
+
+/* UDP emulations */
+#define EMU_TALK	0x1
+#define EMU_NTALK	0x2
+#define EMU_CUSEEME	0x3
+
+struct tos_t {
+	u_int16_t lport;
+	u_int16_t fport;
+	u_int8_t tos;
+	u_int8_t emu;
+};
+
+struct emu_t {
+	u_int16_t lport;
+	u_int16_t fport;
+	u_int8_t tos;
+	u_int8_t emu;
+	struct emu_t *next;
+};
+
+#ifndef CONFIG_QEMU
+extern struct emu_t *tcpemu;
+#endif
+
+void getouraddr _P((void));
+void slirp_insque _P((void *, void *));
+void slirp_remque _P((void *));
+int add_exec _P((struct ex_list **, int, char *, int, int));
+int slirp_openpty _P((int *, int *));
+int fork_exec(struct socket *so, const char *ex, int do_pty);
+void snooze_hup _P((int));
+void snooze _P((void));
+void relay _P((int));
+void add_emu _P((char *));
+
+#endif
diff --git a/slirp2/sbuf.c b/slirp-android/sbuf.c
similarity index 69%
rename from slirp2/sbuf.c
rename to slirp-android/sbuf.c
index abececa..5375414 100644
--- a/slirp2/sbuf.c
+++ b/slirp-android/sbuf.c
@@ -1,24 +1,34 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
 #include <slirp.h>
 
+static void sbappendsb(struct sbuf *sb, struct mbuf *m);
+
+/* Done as a macro in socket.h */
+/* int
+ * sbspace(struct sockbuff *sb)
+ * {
+ *	return SB_DATALEN - sb->sb_cc;
+ * }
+ */
+
 void
-sbuf_free(SBuf  sb)
+sbfree(struct sbuf *sb)
 {
 	free(sb->sb_data);
 }
 
 void
-sbuf_drop(SBuf  sb, int  num)
+sbdrop(struct sbuf *sb, int num)
 {
-	/* 
+	/*
 	 * We can only drop how much we have
-	 * This should never succeed 
+	 * This should never succeed
 	 */
 	if(num > sb->sb_cc)
 		num = sb->sb_cc;
@@ -26,21 +36,30 @@
 	sb->sb_rptr += num;
 	if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
 		sb->sb_rptr -= sb->sb_datalen;
-   
+
 }
 
 void
-sbuf_reserve(SBuf  sb, int  size)
+sbreserve(struct sbuf *sb, int size)
 {
-    if (sb->sb_datalen == size)
-        return;
-
-    sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
-    sb->sb_cc = 0;
-    if (sb->sb_wptr)
-       sb->sb_datalen = size;
-    else
-       sb->sb_datalen = 0;
+	if (sb->sb_data) {
+		/* Already alloced, realloc if necessary */
+		if (sb->sb_datalen != size) {
+			sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
+			sb->sb_cc = 0;
+			if (sb->sb_wptr)
+			   sb->sb_datalen = size;
+			else
+			   sb->sb_datalen = 0;
+		}
+	} else {
+		sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
+		sb->sb_cc = 0;
+		if (sb->sb_wptr)
+		   sb->sb_datalen = size;
+		else
+		   sb->sb_datalen = 0;
+	}
 }
 
 /*
@@ -50,71 +69,70 @@
  * (the socket is non-blocking, so we won't hang)
  */
 void
-sbuf_append(struct socket *so, MBuf  m)
+sbappend(struct socket *so, struct mbuf *m)
 {
 	int ret = 0;
 
-	DEBUG_CALL("sbuf_append");
+	DEBUG_CALL("sbappend");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m = %lx", (long)m);
 	DEBUG_ARG("m->m_len = %d", m->m_len);
-	
+
 	/* Shouldn't happen, but...  e.g. foreign host closes connection */
 	if (m->m_len <= 0) {
-		mbuf_free(m);
+		m_free(m);
 		return;
 	}
-	
+
 	/*
 	 * If there is urgent data, call sosendoob
 	 * if not all was sent, sowrite will take care of the rest
 	 * (The rest of this function is just an optimisation)
 	 */
 	if (so->so_urgc) {
-		sbuf_appendsb(&so->so_rcv, m);
-		mbuf_free(m);
+		sbappendsb(&so->so_rcv, m);
+		m_free(m);
 		sosendoob(so);
 		return;
 	}
-	
+
 	/*
 	 * We only write if there's nothing in the buffer,
 	 * ottherwise it'll arrive out of order, and hence corrupt
 	 */
-	if (!so->so_rcv.sb_cc) {
-	   ret = socket_send(so->s, m->m_data, m->m_len);
-        }
+	if (!so->so_rcv.sb_cc)
+	   ret = slirp_send(so, m->m_data, m->m_len, 0);
 
 	if (ret <= 0) {
-		/* 
+		/*
 		 * Nothing was written
 		 * It's possible that the socket has closed, but
 		 * we don't need to check because if it has closed,
 		 * it will be detected in the normal way by soread()
 		 */
-		sbuf_appendsb(&so->so_rcv, m);
+		sbappendsb(&so->so_rcv, m);
 	} else if (ret != m->m_len) {
 		/*
 		 * Something was written, but not everything..
-		 * sbuf_appendsb the rest
+		 * sbappendsb the rest
 		 */
 		m->m_len -= ret;
 		m->m_data += ret;
-		sbuf_appendsb(&so->so_rcv, m);
+		sbappendsb(&so->so_rcv, m);
 	} /* else */
 	/* Whatever happened, we free the mbuf */
-	mbuf_free(m);
+	m_free(m);
 }
 
 /*
  * Copy the data from m into sb
  * The caller is responsible to make sure there's enough room
  */
-void
-sbuf_appendsb(SBuf  sb, MBuf  m)
+static void
+sbappendsb(struct sbuf *sb, struct mbuf *m)
 {
 	int len, n,  nn;
-	
+
 	len = m->m_len;
 
 	if (sb->sb_wptr < sb->sb_rptr) {
@@ -136,7 +154,7 @@
 		}
 	}
 
-	sb->sb_cc   += n;
+	sb->sb_cc += n;
 	sb->sb_wptr += n;
 	if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
 		sb->sb_wptr -= sb->sb_datalen;
@@ -148,10 +166,10 @@
  * done in sbdrop when the data is acked
  */
 void
-sbuf_copy(SBuf  sb, int  off, int  len, char*  to)
+sbcopy(struct sbuf *sb, int off, int len, char *to)
 {
 	char *from;
-	
+
 	from = sb->sb_rptr + off;
 	if (from >= sb->sb_data + sb->sb_datalen)
 		from -= sb->sb_datalen;
@@ -169,4 +187,3 @@
 		   memcpy(to+off,sb->sb_data,len);
 	}
 }
-		
diff --git a/slirp-android/sbuf.h b/slirp-android/sbuf.h
new file mode 100644
index 0000000..a4f1036
--- /dev/null
+++ b/slirp-android/sbuf.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _SBUF_H_
+#define _SBUF_H_
+
+#define sbflush(sb) sbdrop((sb),(sb)->sb_cc)
+#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
+
+struct sbuf {
+	u_int	sb_cc;		/* actual chars in buffer */
+	u_int	sb_datalen;	/* Length of data  */
+	char	*sb_wptr;	/* write pointer. points to where the next
+				 * bytes should be written in the sbuf */
+	char	*sb_rptr;	/* read pointer. points to where the next
+				 * byte should be read from the sbuf */
+	char	*sb_data;	/* Actual data */
+};
+
+void sbfree _P((struct sbuf *));
+void sbdrop _P((struct sbuf *, int));
+void sbreserve _P((struct sbuf *, int));
+void sbappend _P((struct socket *, struct mbuf *));
+void sbcopy _P((struct sbuf *, int, int, char *));
+
+#endif
diff --git a/slirp-android/slirp.c b/slirp-android/slirp.c
new file mode 100644
index 0000000..dc94a99
--- /dev/null
+++ b/slirp-android/slirp.c
@@ -0,0 +1,1181 @@
+/*
+ * libslirp glue
+ *
+ * Copyright (c) 2004-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "slirp.h"
+#include "proxy_common.h"
+#include "hw/hw.h"
+
+#include "android/utils/debug.h"  /* for dprint */
+#include "android/utils/bufprint.h"
+#include "android/android.h"
+#include "sockets.h"
+
+#define  D(...)   VERBOSE_PRINT(slirp,__VA_ARGS__)
+#define  DN(...)  do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0)
+
+/* host address */
+uint32_t our_addr_ip;
+/* host dns address */
+uint32_t dns_addr[DNS_ADDR_MAX];
+int      dns_addr_count;
+
+/* host loopback address */
+uint32_t loopback_addr_ip;
+
+/* address for slirp virtual addresses */
+uint32_t  special_addr_ip;
+
+/* virtual address alias for host */
+uint32_t alias_addr_ip;
+
+static const uint8_t special_ethaddr[6] = {
+    0x52, 0x54, 0x00, 0x12, 0x35, 0x00
+};
+
+/* ARP cache for the guest IP addresses (XXX: allow many entries) */
+uint8_t client_ethaddr[6];
+static ipaddr_t  client_ip;
+
+static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
+
+const char *slirp_special_ip = CTL_SPECIAL;
+int slirp_restrict;
+static int do_slowtimo;
+int link_up;
+struct timeval tt;
+FILE *lfd;
+struct ex_list *exec_list;
+
+/* XXX: suppress those select globals */
+fd_set *global_readfds, *global_writefds, *global_xfds;
+
+char slirp_hostname[33];
+
+int slirp_add_dns_server(const SockAddress*  new_dns_addr)
+{
+    int   dns_ip;
+
+    if (dns_addr_count >= DNS_ADDR_MAX)
+        return -1;
+
+    dns_ip = sock_address_get_ip(new_dns_addr);
+    if (dns_ip < 0)
+        return -1;
+
+    dns_addr[dns_addr_count++] = dns_ip;
+    return 0;
+}
+
+
+#ifdef _WIN32
+
+int slirp_get_system_dns_servers(void)
+{
+    FIXED_INFO *FixedInfo=NULL;
+    ULONG    BufLen;
+    DWORD    ret;
+    IP_ADDR_STRING *pIPAddr;
+
+    if (dns_addr_count > 0)
+        return dns_addr_count;
+
+    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
+    BufLen = sizeof(FIXED_INFO);
+
+    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        FixedInfo = GlobalAlloc(GPTR, BufLen);
+    }
+
+    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
+        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        return -1;
+    }
+
+    D( "DNS Servers:");
+    pIPAddr = &(FixedInfo->DnsServerList);
+    while (pIPAddr && dns_addr_count < DNS_ADDR_MAX) {
+        uint32_t  ip;
+        D( "  %s", pIPAddr->IpAddress.String );
+        if (inet_strtoip(pIPAddr->IpAddress.String, &ip) == 0) {
+            if (ip == loopback_addr_ip)
+                ip = our_addr_ip;
+            if (dns_addr_count < DNS_ADDR_MAX)
+                dns_addr[dns_addr_count++] = ip;
+        }
+        pIPAddr = pIPAddr->Next;
+    }
+
+    if (FixedInfo) {
+        GlobalFree(FixedInfo);
+        FixedInfo = NULL;
+    }
+    if (dns_addr_count <= 0)
+        return -1;
+
+    return dns_addr_count;
+}
+
+#else
+
+int slirp_get_system_dns_servers(void)
+{
+    char buff[512];
+    char buff2[257];
+    FILE *f;
+
+    if (dns_addr_count > 0)
+        return dns_addr_count;
+
+#ifdef CONFIG_DARWIN
+    /* on Darwin /etc/resolv.conf is a symlink to /private/var/run/resolv.conf
+     * in some siutations, the symlink can be destroyed and the system will not
+     * re-create it. Darwin-aware applications will continue to run, but "legacy"
+     * Unix ones will not.
+     */
+     f = fopen("/private/var/run/resolv.conf", "r");
+     if (!f)
+        f = fopen("/etc/resolv.conf", "r");  /* desperate attempt to sanity */
+#else
+    f = fopen("/etc/resolv.conf", "r");
+#endif
+    if (!f)
+        return -1;
+
+    DN("emulator: IP address of your DNS(s): ");
+    while (fgets(buff, 512, f) != NULL) {
+        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
+            uint32_t  tmp_ip;
+
+            if (inet_strtoip(buff2, &tmp_ip) < 0)
+                continue;
+            if (tmp_ip == loopback_addr_ip)
+                tmp_ip = our_addr_ip;
+            if (dns_addr_count < DNS_ADDR_MAX) {
+                dns_addr[dns_addr_count++] = tmp_ip;
+                if (dns_addr_count > 1)
+                    DN(", ");
+                DN("%s", inet_iptostr(tmp_ip));
+            } else {
+                DN("(more)");
+                break;
+            }
+        }
+    }
+    DN("\n");
+    fclose(f);
+
+    if (!dns_addr_count)
+        return -1;
+
+    return dns_addr_count;
+}
+
+#endif
+
+static void slirp_state_save(QEMUFile *f, void *opaque);
+static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
+
+void slirp_init(int restricted, const char *special_ip)
+{
+#if DEBUG
+    int   slirp_logmask = 0;
+    char  slirp_logfile[512];
+    {
+        const char*  env = getenv( "ANDROID_SLIRP_LOGMASK" );
+        if (env != NULL)
+            slirp_logmask = atoi(env);
+         else if (VERBOSE_CHECK(slirp))
+            slirp_logmask = DEBUG_DEFAULT;
+    }
+
+    {
+        char*  p   = slirp_logfile;
+        char*  end = p + sizeof(slirp_logfile);
+
+        p = bufprint_temp_file( p, end, "slirp.log" );
+        if (p >= end) {
+            dprint( "cannot create slirp log file in temporary directory" );
+            slirp_logmask = 0;
+        }
+    }
+    if (slirp_logmask) {
+        dprint( "sending slirp logs with mask %x to %s", slirp_logmask, slirp_logfile );
+        debug_init( slirp_logfile, slirp_logmask );
+    }
+#endif
+
+    link_up = 1;
+    slirp_restrict = restricted;
+
+    if_init();
+    ip_init();
+
+    /* Initialise mbufs *after* setting the MTU */
+    m_init();
+
+    /* set default addresses */
+    inet_strtoip("127.0.0.1", &loopback_addr_ip);
+
+    if (dns_addr_count == 0) {
+        if (slirp_get_system_dns_servers() < 0) {
+            dns_addr[0]    = loopback_addr_ip;
+            dns_addr_count = 1;
+            fprintf (stderr, "Warning: No DNS servers found\n");
+        }
+    }
+
+    inet_strtoip(CTL_SPECIAL, &special_addr_ip);
+
+    alias_addr_ip = special_addr_ip | CTL_ALIAS;
+    getouraddr();
+    register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
+}
+
+#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
+
+/*
+ * curtime kept to an accuracy of 1ms
+ */
+#ifdef _WIN32
+static void updtime(void)
+{
+    struct _timeb tb;
+
+    _ftime(&tb);
+    curtime = (u_int)tb.time * (u_int)1000;
+    curtime += (u_int)tb.millitm;
+}
+#else
+static void updtime(void)
+{
+        gettimeofday(&tt, NULL);
+
+	curtime = (u_int)tt.tv_sec * (u_int)1000;
+	curtime += (u_int)tt.tv_usec / (u_int)1000;
+
+	if ((tt.tv_usec % 1000) >= 500)
+	   curtime++;
+}
+#endif
+
+void slirp_select_fill(int *pnfds,
+                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
+{
+    struct socket *so, *so_next;
+    struct timeval timeout;
+    int nfds;
+    int tmp_time;
+
+    /* fail safe */
+    global_readfds = NULL;
+    global_writefds = NULL;
+    global_xfds = NULL;
+
+    nfds = *pnfds;
+	/*
+	 * First, TCP sockets
+	 */
+	do_slowtimo = 0;
+	if (link_up) {
+		/*
+		 * *_slowtimo needs calling if there are IP fragments
+		 * in the fragment queue, or there are TCP connections active
+		 */
+		do_slowtimo = ((tcb.so_next != &tcb) ||
+                (&ipq.ip_link != ipq.ip_link.next));
+
+		for (so = tcb.so_next; so != &tcb; so = so_next) {
+			so_next = so->so_next;
+
+			/*
+			 * See if we need a tcp_fasttimo
+			 */
+			if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
+			   time_fasttimo = curtime; /* Flag when we want a fasttimo */
+
+			/*
+			 * NOFDREF can include still connecting to local-host,
+			 * newly socreated() sockets etc. Don't want to select these.
+	 		 */
+			if (so->so_state & SS_NOFDREF || so->s == -1)
+			   continue;
+
+            /*
+             * don't register proxified socked connections here
+             */
+            if ((so->so_state & SS_PROXIFIED) != 0)
+	            continue;
+
+			/*
+			 * Set for reading sockets which are accepting
+			 */
+			if (so->so_state & SS_FACCEPTCONN) {
+                                FD_SET(so->s, readfds);
+				UPD_NFDS(so->s);
+				continue;
+			}
+
+			/*
+			 * Set for writing sockets which are connecting
+			 */
+			if (so->so_state & SS_ISFCONNECTING) {
+				FD_SET(so->s, writefds);
+				UPD_NFDS(so->s);
+				continue;
+			}
+
+			/*
+			 * Set for writing if we are connected, can send more, and
+			 * we have something to send
+			 */
+			if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+				FD_SET(so->s, writefds);
+				UPD_NFDS(so->s);
+			}
+
+			/*
+			 * Set for reading (and urgent data) if we are connected, can
+			 * receive more, and we have room for it XXX /2 ?
+			 */
+			if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+				FD_SET(so->s, readfds);
+				FD_SET(so->s, xfds);
+				UPD_NFDS(so->s);
+			}
+		}
+
+		/*
+		 * UDP sockets
+		 */
+		for (so = udb.so_next; so != &udb; so = so_next) {
+			so_next = so->so_next;
+
+            if ((so->so_state & SS_PROXIFIED) != 0)
+                continue;
+
+			/*
+			 * See if it's timed out
+			 */
+			if (so->so_expire) {
+				if (so->so_expire <= curtime) {
+					udp_detach(so);
+					continue;
+				} else
+					do_slowtimo = 1; /* Let socket expire */
+			}
+
+			/*
+			 * When UDP packets are received from over the
+			 * link, they're sendto()'d straight away, so
+			 * no need for setting for writing
+			 * Limit the number of packets queued by this session
+			 * to 4.  Note that even though we try and limit this
+			 * to 4 packets, the session could have more queued
+			 * if the packets needed to be fragmented
+			 * (XXX <= 4 ?)
+			 */
+			if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
+				FD_SET(so->s, readfds);
+				UPD_NFDS(so->s);
+			}
+		}
+	}
+
+	/*
+	 * Setup timeout to use minimum CPU usage, especially when idle
+	 */
+
+	/*
+	 * First, see the timeout needed by *timo
+	 */
+	timeout.tv_sec = 0;
+	timeout.tv_usec = -1;
+	/*
+	 * If a slowtimo is needed, set timeout to 500ms from the last
+	 * slow timeout. If a fast timeout is needed, set timeout within
+	 * 200ms of when it was requested.
+	 */
+	if (do_slowtimo) {
+		/* XXX + 10000 because some select()'s aren't that accurate */
+		timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
+		if (timeout.tv_usec < 0)
+		   timeout.tv_usec = 0;
+		else if (timeout.tv_usec > 510000)
+		   timeout.tv_usec = 510000;
+
+		/* Can only fasttimo if we also slowtimo */
+		if (time_fasttimo) {
+			tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
+			if (tmp_time < 0)
+			   tmp_time = 0;
+
+			/* Choose the smallest of the 2 */
+			if (tmp_time < timeout.tv_usec)
+			   timeout.tv_usec = (u_int)tmp_time;
+		}
+	}
+    /*
+     * now, the proxified sockets
+     */
+    proxy_manager_select_fill(&nfds, readfds, writefds, xfds);
+
+        *pnfds = nfds;
+}
+
+void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
+{
+    struct socket *so, *so_next;
+    int ret;
+
+    global_readfds = readfds;
+    global_writefds = writefds;
+    global_xfds = xfds;
+
+	/* Update time */
+	updtime();
+
+	/*
+	 * See if anything has timed out
+	 */
+	if (link_up) {
+		if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
+			tcp_fasttimo();
+			time_fasttimo = 0;
+		}
+		if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
+			ip_slowtimo();
+			tcp_slowtimo();
+			last_slowtimo = curtime;
+		}
+	}
+
+	/*
+	 * Check sockets
+	 */
+	if (link_up) {
+		/*
+		 * Check TCP sockets
+		 */
+		for (so = tcb.so_next; so != &tcb; so = so_next) {
+			so_next = so->so_next;
+
+			/*
+			 * FD_ISSET is meaningless on these sockets
+			 * (and they can crash the program)
+			 */
+			if (so->so_state & SS_NOFDREF || so->s == -1)
+			   continue;
+
+            /*
+             * proxified sockets are polled later in this
+             * function.
+             */
+            if ((so->so_state & SS_PROXIFIED) != 0)
+                continue;
+
+			/*
+			 * Check for URG data
+			 * This will soread as well, so no need to
+			 * test for readfds below if this succeeds
+			 */
+			if (FD_ISSET(so->s, xfds))
+			   sorecvoob(so);
+			/*
+			 * Check sockets for reading
+			 */
+			else if (FD_ISSET(so->s, readfds)) {
+				/*
+				 * Check for incoming connections
+				 */
+				if (so->so_state & SS_FACCEPTCONN) {
+					tcp_connect(so);
+					continue;
+				} /* else */
+				ret = soread(so);
+
+				/* Output it if we read something */
+				if (ret > 0)
+				   tcp_output(sototcpcb(so));
+			}
+
+			/*
+			 * Check sockets for writing
+			 */
+			if (FD_ISSET(so->s, writefds)) {
+			  /*
+			   * Check for non-blocking, still-connecting sockets
+			   */
+			  if (so->so_state & SS_ISFCONNECTING) {
+			    /* Connected */
+			    so->so_state &= ~SS_ISFCONNECTING;
+
+			    ret = socket_send(so->s, (const void *)&ret, 0);
+			    if (ret < 0) {
+			      /* XXXXX Must fix, zero bytes is a NOP */
+			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				  errno == EINPROGRESS || errno == ENOTCONN)
+				continue;
+
+			      /* else failed */
+			      so->so_state = SS_NOFDREF;
+			    }
+			    /* else so->so_state &= ~SS_ISFCONNECTING; */
+
+			    /*
+			     * Continue tcp_input
+			     */
+			    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+			    /* continue; */
+			  } else
+			    ret = sowrite(so);
+			  /*
+			   * XXXXX If we wrote something (a lot), there
+			   * could be a need for a window update.
+			   * In the worst case, the remote will send
+			   * a window probe to get things going again
+			   */
+			}
+
+			/*
+			 * Probe a still-connecting, non-blocking socket
+			 * to check if it's still alive
+	 	 	 */
+#ifdef PROBE_CONN
+			if (so->so_state & SS_ISFCONNECTING) {
+			  ret = socket_recv(so->s, (char *)&ret, 0);
+
+			  if (ret < 0) {
+			    /* XXX */
+			    if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				errno == EINPROGRESS || errno == ENOTCONN)
+			      continue; /* Still connecting, continue */
+
+			    /* else failed */
+			    so->so_state = SS_NOFDREF;
+
+			    /* tcp_input will take care of it */
+			  } else {
+			    ret = socket_send(so->s, &ret, 0);
+			    if (ret < 0) {
+			      /* XXX */
+			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				  errno == EINPROGRESS || errno == ENOTCONN)
+				continue;
+			      /* else failed */
+			      so->so_state = SS_NOFDREF;
+			    } else
+			      so->so_state &= ~SS_ISFCONNECTING;
+
+			  }
+			  tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
+			} /* SS_ISFCONNECTING */
+#endif
+		}
+
+		/*
+		 * Now UDP sockets.
+		 * Incoming packets are sent straight away, they're not buffered.
+		 * Incoming UDP data isn't buffered either.
+		 */
+		for (so = udb.so_next; so != &udb; so = so_next) {
+			so_next = so->so_next;
+
+            if ((so->so_state & SS_PROXIFIED) != 0)
+                continue;
+
+			if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                            sorecvfrom(so);
+                        }
+		}
+	}
+
+    /*
+     * Now the proxified sockets
+     */
+    proxy_manager_poll(readfds, writefds, xfds);
+
+	/*
+	 * See if we can start outputting
+	 */
+	if (if_queued && link_up)
+	   if_start();
+
+	/* clear global file descriptor sets.
+	 * these reside on the stack in vl.c
+	 * so they're unusable if we're not in
+	 * slirp_select_fill or slirp_select_poll.
+	 */
+	 global_readfds = NULL;
+	 global_writefds = NULL;
+	 global_xfds = NULL;
+}
+
+#define ETH_ALEN 6
+#define ETH_HLEN 14
+
+#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
+#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
+
+#define	ARPOP_REQUEST	1		/* ARP request			*/
+#define	ARPOP_REPLY	2		/* ARP reply			*/
+
+struct ethhdr
+{
+	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+	unsigned short	h_proto;		/* packet type ID field	*/
+};
+
+struct arphdr
+{
+	unsigned short	ar_hrd;		/* format of hardware address	*/
+	unsigned short	ar_pro;		/* format of protocol address	*/
+	unsigned char	ar_hln;		/* length of hardware address	*/
+	unsigned char	ar_pln;		/* length of protocol address	*/
+	unsigned short	ar_op;		/* ARP opcode (command)		*/
+
+	 /*
+	  *	 Ethernet looks like this : This bit is variable sized however...
+	  */
+	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
+	unsigned char		ar_sip[4];		/* sender IP address		*/
+	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
+	unsigned char		ar_tip[4];		/* target IP address		*/
+};
+
+static void arp_input(const uint8_t *pkt, int pkt_len)
+{
+    struct ethhdr *eh = (struct ethhdr *)pkt;
+    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
+    uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
+    struct ethhdr *reh = (struct ethhdr *)arp_reply;
+    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
+    int ar_op;
+    struct ex_list *ex_ptr;
+
+    ar_op = ntohs(ah->ar_op);
+    switch(ar_op) {
+        uint32_t    ar_tip_ip;
+
+    case ARPOP_REQUEST:
+        ar_tip_ip = ip_read32h(ah->ar_tip);
+        if ((ar_tip_ip & 0xffffff00) == special_addr_ip) {
+            uint32_t  ar_tip_low = ar_tip_ip & 0xff;
+            if ( CTL_IS_DNS(ar_tip_low) || ar_tip_low == CTL_ALIAS)
+                goto arp_ok;
+            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+                if (ex_ptr->ex_addr == ar_tip_low)
+                    goto arp_ok;
+            }
+            return;
+        arp_ok:
+            /* XXX: make an ARP request to have the client address */
+            memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
+
+            /* ARP request for alias/dns mac address */
+            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
+            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
+            reh->h_source[5] = ar_tip_low;
+            reh->h_proto = htons(ETH_P_ARP);
+
+            rah->ar_hrd = htons(1);
+            rah->ar_pro = htons(ETH_P_IP);
+            rah->ar_hln = ETH_ALEN;
+            rah->ar_pln = 4;
+            rah->ar_op = htons(ARPOP_REPLY);
+            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
+            memcpy(rah->ar_sip, ah->ar_tip, 4);
+            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
+            memcpy(rah->ar_tip, ah->ar_sip, 4);
+            slirp_output(arp_reply, sizeof(arp_reply));
+        }
+        break;
+    case ARPOP_REPLY:
+        /* reply to request of client mac address ? */
+        if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
+            ip_equal( ip_read(ah->ar_sip), client_ip )) {
+            memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+void slirp_input(const uint8_t *pkt, int pkt_len)
+{
+    struct mbuf *m;
+    int proto;
+
+    if (pkt_len < ETH_HLEN)
+        return;
+
+    proto = ntohs(*(uint16_t *)(pkt + 12));
+    switch(proto) {
+    case ETH_P_ARP:
+        arp_input(pkt, pkt_len);
+        break;
+    case ETH_P_IP:
+        m = m_get();
+        if (!m)
+            return;
+        /* Note: we add to align the IP header */
+        if (M_FREEROOM(m) < pkt_len + 2) {
+            m_inc(m, pkt_len + 2);
+        }
+        m->m_len = pkt_len + 2;
+        memcpy(m->m_data + 2, pkt, pkt_len);
+
+        m->m_data += 2 + ETH_HLEN;
+        m->m_len -= 2 + ETH_HLEN;
+
+        ip_input(m);
+        break;
+    default:
+        break;
+    }
+}
+
+/* output the IP packet to the ethernet device */
+void if_encap(const uint8_t *ip_data, int ip_data_len)
+{
+    uint8_t buf[1600];
+    struct ethhdr *eh = (struct ethhdr *)buf;
+
+    if (ip_data_len + ETH_HLEN > sizeof(buf))
+        return;
+
+    if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
+        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
+        struct ethhdr *reh = (struct ethhdr *)arp_req;
+        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
+        const struct ip *iph = (const struct ip *)ip_data;
+
+        /* If the client addr is not known, there is no point in
+           sending the packet to it. Normally the sender should have
+           done an ARP request to get its MAC address. Here we do it
+           in place of sending the packet and we hope that the sender
+           will retry sending its packet. */
+        memset(reh->h_dest, 0xff, ETH_ALEN);
+        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
+        reh->h_source[5] = CTL_ALIAS;
+        reh->h_proto = htons(ETH_P_ARP);
+        rah->ar_hrd = htons(1);
+        rah->ar_pro = htons(ETH_P_IP);
+        rah->ar_hln = ETH_ALEN;
+        rah->ar_pln = 4;
+        rah->ar_op = htons(ARPOP_REQUEST);
+        /* source hw addr */
+        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
+        rah->ar_sha[5] = CTL_ALIAS;
+        /* source IP */
+        ip_write32h(alias_addr_ip, rah->ar_sip);
+        /* target hw addr (none) */
+        memset(rah->ar_tha, 0, ETH_ALEN);
+        /* target IP */
+        ip_write( iph->ip_dst, rah->ar_tip );
+        client_ip   = iph->ip_dst;
+        slirp_output(arp_req, sizeof(arp_req));
+    } else {
+        memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
+        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
+        /* XXX: not correct */
+        eh->h_source[5] = CTL_ALIAS;
+        eh->h_proto = htons(ETH_P_IP);
+        memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
+        slirp_output(buf, ip_data_len + ETH_HLEN);
+    }
+}
+
+static void _slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+                                           const SockAddress *laddr,
+                                           const SockAddress *faddr),
+                              void *opaque, int is_udp)
+{
+    struct socket *head = (is_udp ? &udb : &tcb);
+    struct socket *so;
+
+    for (so = head->so_next; so != head; so = so->so_next) {
+        SockAddress  local, foreign;
+	
+		sock_address_init_inet(&local, so->so_laddr_ip, so->so_laddr_port);
+		sock_address_init_inet(&foreign, so->so_faddr_ip, so->so_faddr_port);
+        func(opaque, is_udp,
+             &local, &foreign);
+    }
+}
+
+void slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+                                   const SockAddress *laddr,
+                                   const SockAddress *faddr),
+                     void *opaque)
+{
+    _slirp_redir_loop(func, opaque, 0);
+    _slirp_redir_loop(func, opaque, 1);
+}
+
+/* Unlistens a redirection
+ *
+ * Return value: number of redirs removed */
+int slirp_redir_rm(int is_udp, int host_port)
+{
+    struct socket *so;
+    struct socket *head = (is_udp ? &udb : &tcb);
+    int n = 0;
+
+ loop_again:
+    for (so = head->so_next; so != head; so = so->so_next) {
+        if (so->so_faddr_port == host_port) {
+            close(so->s);
+            sofree(so);
+            n++;
+            goto loop_again;
+        }
+    }
+
+    return n;
+}
+
+int slirp_redir(int is_udp, int host_port,
+                uint32_t  guest_ip, int guest_port)
+{
+    if (is_udp) {
+        if (!udp_listen(host_port,
+                        guest_ip,
+                        guest_port, 0))
+            return -1;
+    } else {
+        if (!solisten(host_port, guest_ip, guest_port, 0))
+            return -1;
+    }
+    return 0;
+}
+
+int  slirp_unredir(int  is_udp, int  host_port)
+{
+    if (is_udp)
+        return udp_unlisten( host_port );
+    else
+        return sounlisten( host_port );
+}
+
+int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
+                  int guest_port)
+{
+    return add_exec(&exec_list, do_pty, (char *)args,
+                    addr_low_byte, htons(guest_port));
+}
+
+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
+{
+	if (so->s == -1 && so->extra) {
+		qemu_chr_write(so->extra, buf, len);
+		return len;
+	}
+
+	return send(so->s, buf, len, flags);
+}
+
+static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port)
+{
+	struct socket *so;
+
+	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
+		if ((so->so_faddr_ip & 0xffffff00) ==
+				special_addr_ip
+				&& ((so->so_faddr_port & 0xff) ==
+				addr_low_byte)
+				&& so->so_faddr_port == guest_port)
+			return so;
+	}
+
+	return NULL;
+}
+
+size_t slirp_socket_can_recv(int addr_low_byte, int guest_port)
+{
+	struct iovec iov[2];
+	struct socket *so;
+
+    if (!link_up)
+        return 0;
+
+	so = slirp_find_ctl_socket(addr_low_byte, guest_port);
+
+	if (!so || so->so_state & SS_NOFDREF)
+		return 0;
+
+	if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
+		return 0;
+
+	return sopreprbuf(so, iov, NULL);
+}
+
+void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
+        int size)
+{
+    int ret;
+    struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port);
+   
+    if (!so)
+        return;
+
+    ret = soreadbuf(so, (const char *)buf, size);
+
+    if (ret > 0)
+        tcp_output(sototcpcb(so));
+}
+
+static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
+{
+    int i;
+
+    qemu_put_sbe16(f, tp->t_state);
+    for (i = 0; i < TCPT_NTIMERS; i++)
+        qemu_put_sbe16(f, tp->t_timer[i]);
+    qemu_put_sbe16(f, tp->t_rxtshift);
+    qemu_put_sbe16(f, tp->t_rxtcur);
+    qemu_put_sbe16(f, tp->t_dupacks);
+    qemu_put_be16(f, tp->t_maxseg);
+    qemu_put_sbyte(f, tp->t_force);
+    qemu_put_be16(f, tp->t_flags);
+    qemu_put_be32(f, tp->snd_una);
+    qemu_put_be32(f, tp->snd_nxt);
+    qemu_put_be32(f, tp->snd_up);
+    qemu_put_be32(f, tp->snd_wl1);
+    qemu_put_be32(f, tp->snd_wl2);
+    qemu_put_be32(f, tp->iss);
+    qemu_put_be32(f, tp->snd_wnd);
+    qemu_put_be32(f, tp->rcv_wnd);
+    qemu_put_be32(f, tp->rcv_nxt);
+    qemu_put_be32(f, tp->rcv_up);
+    qemu_put_be32(f, tp->irs);
+    qemu_put_be32(f, tp->rcv_adv);
+    qemu_put_be32(f, tp->snd_max);
+    qemu_put_be32(f, tp->snd_cwnd);
+    qemu_put_be32(f, tp->snd_ssthresh);
+    qemu_put_sbe16(f, tp->t_idle);
+    qemu_put_sbe16(f, tp->t_rtt);
+    qemu_put_be32(f, tp->t_rtseq);
+    qemu_put_sbe16(f, tp->t_srtt);
+    qemu_put_sbe16(f, tp->t_rttvar);
+    qemu_put_be16(f, tp->t_rttmin);
+    qemu_put_be32(f, tp->max_sndwnd);
+    qemu_put_byte(f, tp->t_oobflags);
+    qemu_put_byte(f, tp->t_iobc);
+    qemu_put_sbe16(f, tp->t_softerror);
+    qemu_put_byte(f, tp->snd_scale);
+    qemu_put_byte(f, tp->rcv_scale);
+    qemu_put_byte(f, tp->request_r_scale);
+    qemu_put_byte(f, tp->requested_s_scale);
+    qemu_put_be32(f, tp->ts_recent);
+    qemu_put_be32(f, tp->ts_recent_age);
+    qemu_put_be32(f, tp->last_ack_sent);
+}
+
+static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
+{
+    uint32_t off;
+
+    qemu_put_be32(f, sbuf->sb_cc);
+    qemu_put_be32(f, sbuf->sb_datalen);
+    off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
+    qemu_put_sbe32(f, off);
+    off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
+    qemu_put_sbe32(f, off);
+    qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
+}
+
+static void slirp_socket_save(QEMUFile *f, struct socket *so)
+{
+    qemu_put_be32(f, so->so_urgc);
+    qemu_put_be32(f, so->so_faddr_ip);
+    qemu_put_be32(f, so->so_laddr_ip);
+    qemu_put_be16(f, so->so_faddr_port);
+    qemu_put_be16(f, so->so_laddr_port);
+    qemu_put_byte(f, so->so_iptos);
+    qemu_put_byte(f, so->so_emu);
+    qemu_put_byte(f, so->so_type);
+    qemu_put_be32(f, so->so_state);
+    slirp_sbuf_save(f, &so->so_rcv);
+    slirp_sbuf_save(f, &so->so_snd);
+    slirp_tcp_save(f, so->so_tcpcb);
+}
+
+static void slirp_state_save(QEMUFile *f, void *opaque)
+{
+    struct ex_list *ex_ptr;
+
+    for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+        if (ex_ptr->ex_pty == 3) {
+            struct socket *so;
+            so = slirp_find_ctl_socket(ex_ptr->ex_addr, ntohs(ex_ptr->ex_fport));
+            if (!so)
+                continue;
+
+            qemu_put_byte(f, 42);
+            slirp_socket_save(f, so);
+        }
+    qemu_put_byte(f, 0);
+}
+
+static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
+{
+    int i;
+
+    tp->t_state = qemu_get_sbe16(f);
+    for (i = 0; i < TCPT_NTIMERS; i++)
+        tp->t_timer[i] = qemu_get_sbe16(f);
+    tp->t_rxtshift = qemu_get_sbe16(f);
+    tp->t_rxtcur = qemu_get_sbe16(f);
+    tp->t_dupacks = qemu_get_sbe16(f);
+    tp->t_maxseg = qemu_get_be16(f);
+    tp->t_force = qemu_get_sbyte(f);
+    tp->t_flags = qemu_get_be16(f);
+    tp->snd_una = qemu_get_be32(f);
+    tp->snd_nxt = qemu_get_be32(f);
+    tp->snd_up = qemu_get_be32(f);
+    tp->snd_wl1 = qemu_get_be32(f);
+    tp->snd_wl2 = qemu_get_be32(f);
+    tp->iss = qemu_get_be32(f);
+    tp->snd_wnd = qemu_get_be32(f);
+    tp->rcv_wnd = qemu_get_be32(f);
+    tp->rcv_nxt = qemu_get_be32(f);
+    tp->rcv_up = qemu_get_be32(f);
+    tp->irs = qemu_get_be32(f);
+    tp->rcv_adv = qemu_get_be32(f);
+    tp->snd_max = qemu_get_be32(f);
+    tp->snd_cwnd = qemu_get_be32(f);
+    tp->snd_ssthresh = qemu_get_be32(f);
+    tp->t_idle = qemu_get_sbe16(f);
+    tp->t_rtt = qemu_get_sbe16(f);
+    tp->t_rtseq = qemu_get_be32(f);
+    tp->t_srtt = qemu_get_sbe16(f);
+    tp->t_rttvar = qemu_get_sbe16(f);
+    tp->t_rttmin = qemu_get_be16(f);
+    tp->max_sndwnd = qemu_get_be32(f);
+    tp->t_oobflags = qemu_get_byte(f);
+    tp->t_iobc = qemu_get_byte(f);
+    tp->t_softerror = qemu_get_sbe16(f);
+    tp->snd_scale = qemu_get_byte(f);
+    tp->rcv_scale = qemu_get_byte(f);
+    tp->request_r_scale = qemu_get_byte(f);
+    tp->requested_s_scale = qemu_get_byte(f);
+    tp->ts_recent = qemu_get_be32(f);
+    tp->ts_recent_age = qemu_get_be32(f);
+    tp->last_ack_sent = qemu_get_be32(f);
+    tcp_template(tp);
+}
+
+static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
+{
+    uint32_t off, sb_cc, sb_datalen;
+
+    sb_cc = qemu_get_be32(f);
+    sb_datalen = qemu_get_be32(f);
+
+    sbreserve(sbuf, sb_datalen);
+
+    if (sbuf->sb_datalen != sb_datalen)
+        return -ENOMEM;
+
+    sbuf->sb_cc = sb_cc;
+
+    off = qemu_get_sbe32(f);
+    sbuf->sb_wptr = sbuf->sb_data + off;
+    off = qemu_get_sbe32(f);
+    sbuf->sb_rptr = sbuf->sb_data + off;
+    qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
+
+    return 0;
+}
+
+static int slirp_socket_load(QEMUFile *f, struct socket *so)
+{
+    if (tcp_attach(so) < 0)
+        return -ENOMEM;
+
+    so->so_urgc = qemu_get_be32(f);
+    so->so_faddr_ip = qemu_get_be32(f);
+    so->so_laddr_ip = qemu_get_be32(f);
+    so->so_faddr_port = qemu_get_be16(f);
+    so->so_laddr_port = qemu_get_be16(f);
+    so->so_iptos = qemu_get_byte(f);
+    so->so_emu = qemu_get_byte(f);
+    so->so_type = qemu_get_byte(f);
+    so->so_state = qemu_get_be32(f);
+    if (slirp_sbuf_load(f, &so->so_rcv) < 0)
+        return -ENOMEM;
+    if (slirp_sbuf_load(f, &so->so_snd) < 0)
+        return -ENOMEM;
+    slirp_tcp_load(f, so->so_tcpcb);
+
+    return 0;
+}
+
+static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct ex_list *ex_ptr;
+    int r;
+
+    while ((r = qemu_get_byte(f))) {
+        int ret;
+        struct socket *so = socreate();
+
+        if (!so)
+            return -ENOMEM;
+
+        ret = slirp_socket_load(f, so);
+
+        if (ret < 0)
+            return ret;
+
+        if ((so->so_faddr_ip & 0xffffff00) != special_addr_ip)
+            return -EINVAL;
+
+        for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+            if (ex_ptr->ex_pty == 3 &&
+                    (so->so_faddr_ip & 0xff) == ex_ptr->ex_addr &&
+                    so->so_faddr_port == ex_ptr->ex_fport)
+                break;
+
+        if (!ex_ptr)
+            return -EINVAL;
+
+        so->extra = (void *)ex_ptr->ex_exec;
+    }
+
+    return 0;
+}
diff --git a/slirp2/slirp.h b/slirp-android/slirp.h
similarity index 83%
rename from slirp2/slirp.h
rename to slirp-android/slirp.h
index e69940b..e882a7f 100644
--- a/slirp2/slirp.h
+++ b/slirp-android/slirp.h
@@ -3,12 +3,21 @@
 
 #define CONFIG_QEMU
 
-#define DEBUG 1
+//#define DEBUG 1
+
+// Uncomment the following line to enable SLIRP statistics printing in Qemu
+//#define LOG_ENABLED
+
+#ifdef LOG_ENABLED
+#define STAT(expr) expr
+#else
+#define STAT(expr) do { } while(0)
+#endif
 
 #ifndef CONFIG_QEMU
 #include "version.h"
 #endif
-#include "config.h"
+#include "config-host.h"
 #include "slirp_config.h"
 
 #include <stddef.h>
@@ -85,7 +94,7 @@
 # include <sys/time.h>
 # include <time.h>
 #else
-# if HAVE_SYS_TIME_H
+# ifdef HAVE_SYS_TIME_H
 #  include <sys/time.h>
 # else
 #  include <time.h>
@@ -102,13 +111,12 @@
 #include <sys/uio.h>
 #endif
 
-#ifndef _P
+#undef _P
 #ifndef NO_PROTOTYPES
 #  define   _P(x)   x
 #else
 #  define   _P(x)   ()
 #endif
-#endif
 
 #ifndef _WIN32
 #include <arpa/inet.h>
@@ -209,35 +217,30 @@
 
 void lprint _P((const char *, ...));
 
-extern int do_echo;
 
 #define DEFAULT_BAUD 115200
 
+#define SO_OPTIONS DO_KEEPALIVE
+#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
+
 /* cksum.c */
-int cksum(MBuf m, int len);
+int cksum(struct mbuf *m, int len);
 
 /* if.c */
 void if_init _P((void));
-void if_output _P((struct socket *, MBuf ));
+void if_output _P((struct socket *, struct mbuf *));
 
 /* ip_input.c */
 void ip_init _P((void));
-void ip_input _P((MBuf ));
-struct ip * ip_reass _P((register struct ip*, register struct ipq *));
-void ip_freef _P((struct ipq *));
-void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *));
-void ip_deq _P((register struct ipasfrag *));
+void ip_input _P((struct mbuf *));
 void ip_slowtimo _P((void));
-void ip_stripoptions _P((register MBuf , MBuf ));
+void ip_stripoptions _P((register struct mbuf *, struct mbuf *));
 
 /* ip_output.c */
-int ip_output _P((struct socket *, MBuf ));
+int ip_output _P((struct socket *, struct mbuf *));
 
 /* tcp_input.c */
-int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, MBuf ));
-void tcp_input _P((register MBuf , int, struct socket *));
-void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *));
-void tcp_xmit_timer _P((register struct tcpcb *, int));
+void tcp_input _P((register struct mbuf *, int, struct socket *));
 int tcp_mss _P((register struct tcpcb *, u_int));
 
 /* tcp_output.c */
@@ -247,16 +250,15 @@
 /* tcp_subr.c */
 void tcp_init _P((void));
 void tcp_template _P((struct tcpcb *));
-void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register MBuf , tcp_seq, tcp_seq, int));
+void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int));
 struct tcpcb * tcp_newtcpcb _P((struct socket *));
 struct tcpcb * tcp_close _P((register struct tcpcb *));
-void tcp_drain _P((void));
 void tcp_sockclosed _P((struct tcpcb *));
 int tcp_fconnect _P((struct socket *));
 void tcp_connect _P((struct socket *));
 int tcp_attach _P((struct socket *));
 u_int8_t tcp_tos _P((struct socket *));
-int tcp_emu _P((struct socket *, MBuf ));
+int tcp_emu _P((struct socket *, struct mbuf *));
 int tcp_ctl _P((struct socket *));
 struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
 
diff --git a/slirp2/slirp_config.h b/slirp-android/slirp_config.h
similarity index 96%
rename from slirp2/slirp_config.h
rename to slirp-android/slirp_config.h
index 030d2ff..8e95b7c 100644
--- a/slirp2/slirp_config.h
+++ b/slirp-android/slirp_config.h
@@ -128,10 +128,10 @@
 #undef HAVE_SYS_STROPTS_H
 
 /* Define to whatever your compiler thinks inline should be */
-#define inline inline
+//#define inline inline
 
 /* Define to whatever your compiler thinks const should be */
-#define const const
+//#define const const
 
 /* Define if your compiler doesn't like prototypes */
 #undef NO_PROTOTYPES
@@ -160,6 +160,12 @@
 /* Define if you have srandom() */
 #undef HAVE_SRANDOM
 
+/* Define if you have inet_aton */
+#undef HAVE_INET_ATON
+#ifndef _WIN32
+#define HAVE_INET_ATON
+#endif
+
 /* Define if you have setenv */
 #undef HAVE_SETENV
 
diff --git a/slirp2/socket.c b/slirp-android/socket.c
similarity index 81%
rename from slirp2/socket.c
rename to slirp-android/socket.c
index 05fb4b7..44640a8 100644
--- a/slirp2/socket.c
+++ b/slirp-android/socket.c
@@ -6,6 +6,7 @@
  */
 
 #define WANT_SYS_IOCTL_H
+#include "qemu-common.h"
 #include <slirp.h>
 #include "ip_icmp.h"
 #include "main.h"
@@ -16,20 +17,20 @@
 #include "sockets.h"
 #include "proxy_common.h"
 
-void
+static void sofcantrcvmore(struct socket *so);
+static void sofcantsendmore(struct socket *so);
+
+#if 0
+static void
 so_init()
 {
 	/* Nothing yet */
 }
-
+#endif
 
 struct socket *
-solookup(head, laddr, lport, faddr, fport)
-	struct socket *head;
-	uint32_t laddr;
-	u_int lport;
-	uint32_t faddr;
-	u_int fport;
+solookup(struct socket *head, uint32_t laddr, u_int lport,
+         uint32_t faddr, u_int fport)
 {
 	struct socket *so;
 
@@ -53,7 +54,7 @@
  * insque() it into the correct linked-list
  */
 struct socket *
-socreate()
+socreate(void)
 {
   struct socket *so;
 
@@ -70,13 +71,12 @@
  * remque and free a socket, clobber cache
  */
 void
-sofree(so)
-	struct socket *so;
+sofree(struct socket *so)
 {
   if (so->so_state & SS_PROXIFIED)
     proxy_manager_del(so);
 
-  if (so->extra) {
+  if (so->so_emu==EMU_RSH && so->extra) {
 	sofree(so->extra);
 	so->extra=NULL;
   }
@@ -85,7 +85,7 @@
   else if (so == udp_last_so)
     udp_last_so = &udb;
 
-  mbuf_free(so->so_m);
+  m_free(so->so_m);
 
   if(so->so_next && so->so_prev)
     remque(so);  /* crashes if so is not in a queue */
@@ -93,32 +93,24 @@
   free(so);
 }
 
-/*
- * Read from so's socket into sb_snd, updating all relevant sbuf fields
- * NOTE: This will only be called if it is select()ed for reading, so
- * a read() of 0 (or less) means it's disconnected
- */
-int
-soread(so)
-	struct socket *so;
+size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
 {
-	int n, nn, lss, total;
-	SBuf  sb = &so->so_snd;
-	int   len = sb->sb_datalen - sb->sb_cc;
-	struct iovec iov[2];
+	int n, lss, total;
+	struct sbuf *sb = &so->so_snd;
+	int len = sb->sb_datalen - sb->sb_cc;
 	int mss = so->so_tcpcb->t_maxseg;
 
-	DEBUG_CALL("soread");
+	DEBUG_CALL("sopreprbuf");
 	DEBUG_ARG("so = %lx", (long )so);
 
-	/*
-	 * No need to check if there's enough room to read.
-	 * soread wouldn't have been called if there weren't
-	 */
-
 	len = sb->sb_datalen - sb->sb_cc;
 
+	if (len <= 0)
+		return 0;
+
 	iov[0].iov_base = sb->sb_wptr;
+        iov[1].iov_base = NULL;
+        iov[1].iov_len = 0;
 	if (sb->sb_wptr < sb->sb_rptr) {
 		iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
 		/* Should never succeed, but... */
@@ -156,6 +148,32 @@
 			n = 1;
 		}
 	}
+	if (np)
+		*np = n;
+
+	return iov[0].iov_len + (n - 1) * iov[1].iov_len;
+}
+
+/*
+ * Read from so's socket into sb_snd, updating all relevant sbuf fields
+ * NOTE: This will only be called if it is select()ed for reading, so
+ * a read() of 0 (or less) means it's disconnected
+ */
+int
+soread(struct socket *so)
+{
+	int n, nn;
+	struct sbuf *sb = &so->so_snd;
+	struct iovec iov[2];
+
+	DEBUG_CALL("soread");
+	DEBUG_ARG("so = %lx", (long )so);
+
+	/*
+	 * No need to check if there's enough room to read.
+	 * soread wouldn't have been called if there weren't
+	 */
+	sopreprbuf(so, iov, &n);
 
 #ifdef HAVE_READV
 	nn = readv(so->s, (struct iovec *)iov, n);
@@ -202,6 +220,48 @@
 	return nn;
 }
 
+int soreadbuf(struct socket *so, const char *buf, int size)
+{
+    int n, nn, copy = size;
+	struct sbuf *sb = &so->so_snd;
+	struct iovec iov[2];
+
+	DEBUG_CALL("soreadbuf");
+	DEBUG_ARG("so = %lx", (long )so);
+
+	/*
+	 * No need to check if there's enough room to read.
+	 * soread wouldn't have been called if there weren't
+	 */
+	if (sopreprbuf(so, iov, &n) < size)
+        goto err;
+
+    nn = MIN(iov[0].iov_len, copy);
+    memcpy(iov[0].iov_base, buf, nn);
+
+    copy -= nn;
+    buf += nn;
+
+    if (copy == 0)
+        goto done;
+
+    memcpy(iov[1].iov_base, buf, copy);
+
+done:
+    /* Update fields */
+	sb->sb_cc += size;
+	sb->sb_wptr += size;
+	if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
+		sb->sb_wptr -= sb->sb_datalen;
+    return size;
+err:
+
+    sofcantrcvmore(so);
+    tcp_sockclosed(sototcpcb(so));
+    fprintf(stderr, "soreadbuf buffer to small");
+    return -1;
+}
+
 /*
  * Get urgent data
  *
@@ -210,8 +270,7 @@
  * in the send buffer is sent as urgent data
  */
 void
-sorecvoob(so)
-	struct socket *so;
+sorecvoob(struct socket *so)
 {
 	struct tcpcb *tp = sototcpcb(so);
 
@@ -238,12 +297,12 @@
  * There's a lot duplicated code here, but...
  */
 int
-sosendoob(so)
-	struct socket *so;
+sosendoob(struct socket *so)
 {
-	SBuf  sb = &so->so_rcv;
-	char  buff[2048]; /* XXX Shouldn't be sending more oob data than this */
-	int   n, len;
+	struct sbuf *sb = &so->so_rcv;
+	char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
+
+	int n, len;
 
 	DEBUG_CALL("sosendoob");
 	DEBUG_ARG("so = %lx", (long)so);
@@ -296,12 +355,11 @@
  * updating all sbuf field as necessary
  */
 int
-sowrite(so)
-	struct socket *so;
+sowrite(struct socket *so)
 {
-	int   n,nn;
-	SBuf  sb = &so->so_rcv;
-	int   len = sb->sb_cc;
+	int  n,nn;
+	struct sbuf *sb = &so->so_rcv;
+	int len = sb->sb_cc;
 	struct iovec iov[2];
 
 	DEBUG_CALL("sowrite");
@@ -321,6 +379,8 @@
         len = sb->sb_cc;
 
 	iov[0].iov_base = sb->sb_rptr;
+        iov[1].iov_base = NULL;
+        iov[1].iov_len = 0;
 	if (sb->sb_rptr < sb->sb_wptr) {
 		iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
 		/* Should never succeed, but... */
@@ -389,8 +449,7 @@
  * recvfrom() a UDP socket
  */
 void
-sorecvfrom(so)
-	struct socket *so;
+sorecvfrom(struct socket *so)
 {
         SockAddress  addr;
 
@@ -420,24 +479,25 @@
 	  /* No need for this socket anymore, udp_detach it */
 	  udp_detach(so);
 	} else {                            	/* A "normal" UDP packet */
-	  MBuf m;
-	  int len, n;
+	  struct mbuf *m;
+          int len;
+		  int n;
 
-	  if (!(m = mbuf_alloc())) return;
-	  m->m_data += if_maxlinkhdr;
+	  if (!(m = m_get())) return;
+	  m->m_data += IF_MAXLINKHDR;
 
 	  /*
 	   * XXX Shouldn't FIONREAD packets destined for port 53,
 	   * but I don't know the max packet size for DNS lookups
 	   */
-	  len = mbuf_freeroom(m);
+	  len = M_FREEROOM(m);
 	  /* if (so->so_fport != htons(53)) { */
 	  n = socket_can_read(so->s);
 
 	  if (n > len) {
 	    n = (m->m_data - m->m_dat) + m->m_len + n + 1;
-	    mbuf_ensure(m, n);
-	    len = mbuf_freeroom(m);
+	    m_inc(m, n);
+	    len = M_FREEROOM(m);
 	  }
 	  /* } */
 
@@ -452,7 +512,7 @@
 
 	    DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
 	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,errno_str);
-	    mbuf_free(m);
+	    m_free(m);
 	  } else {
 	  /*
 	   * Hack: domain name lookup will be used the most for UDP,
@@ -468,7 +528,7 @@
 	    }
 
 	    /*		if (m->m_len == len) {
-	     *			mbuf_ensure(m, MINCSIZE);
+	     *			m_inc(m, MINCSIZE);
 	     *			m->m_len = 0;
 	     *		}
 	     */
@@ -486,26 +546,24 @@
  * sendto() a socket
  */
 int
-sosendto(so, m)
-	struct socket *so;
-	MBuf m;
+sosendto(struct socket *so, struct mbuf *m)
 {
-        SockAddress   addr;
-        uint32_t      addr_ip;
-        uint16_t      addr_port;
-        int           ret;
+	int ret;
+    SockAddress   addr;
+    uint32_t      addr_ip;
+    uint16_t      addr_port;
 
 	DEBUG_CALL("sosendto");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m = %lx", (long)m);
 
 	if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) {
-	  /* It's an alias */
-          int  low = so->so_faddr_ip & 0xff;
+        /* It's an alias */
+      	int  low = so->so_faddr_ip & 0xff;
 
-          if ( CTL_IS_DNS(low) )
+        if ( CTL_IS_DNS(low) )
             addr_ip = dns_addr[low - CTL_DNS];
-          else
+        else
             addr_ip = loopback_addr_ip;
 	} else
 	    addr_ip = so->so_faddr_ip;
@@ -535,11 +593,7 @@
  * XXX This should really be tcp_listen
  */
 struct socket *
-solisten(port, laddr, lport, flags)
-	u_int port;
-	u_int32_t laddr;
-	u_int lport;
-	int flags;
+solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
 {
 	SockAddress  addr;
 	uint32_t     addr_ip;
@@ -572,23 +626,23 @@
 
 	so->so_state      = (SS_FACCEPTCONN|flags);
 	so->so_laddr_port = lport; /* Kept in host format */
-        so->so_laddr_ip   = laddr; /* Ditto */
-        so->so_haddr_port = port;
+    so->so_laddr_ip   = laddr; /* Ditto */
+    so->so_haddr_port = port;
 
-        s = socket_loopback_server( port, SOCKET_STREAM );
-        if (s < 0)
-            return NULL;
+    s = socket_loopback_server( port, SOCKET_STREAM );
+    if (s < 0)
+        return NULL;
 
-        socket_get_address(s, &addr);
+    socket_get_address(s, &addr);
 
 	so->so_faddr_port = sock_address_get_port(&addr);
 
-        addr_ip = (uint32_t) sock_address_get_ip(&addr);
+    addr_ip = (uint32_t) sock_address_get_ip(&addr);
 
-        if (addr_ip == 0 || addr_ip == loopback_addr_ip)
-            so->so_faddr_ip = alias_addr_ip;
-        else
-            so->so_faddr_ip = addr_ip;
+    if (addr_ip == 0 || addr_ip == loopback_addr_ip)
+        so->so_faddr_ip = alias_addr_ip;
+    else
+        so->so_faddr_ip = addr_ip;
 
 	so->s = s;
 	return so;
@@ -619,12 +673,13 @@
 }
 
 
+#if 0
 /*
  * Data is available in so_rcv
  * Just write() the data to the socket
  * XXX not yet...
  */
-void
+static void
 sorwakeup(so)
 	struct socket *so;
 {
@@ -637,12 +692,13 @@
  * We have room for a read() if we want to
  * For now, don't read, it'll be done in the main loop
  */
-void
+static void
 sowwakeup(so)
 	struct socket *so;
 {
 	/* Nothing, yet */
 }
+#endif
 
 /*
  * Various session state calls
@@ -651,8 +707,7 @@
  * times each when only 1 was needed
  */
 void
-soisfconnecting(so)
-	register struct socket *so;
+soisfconnecting(struct socket *so)
 {
 	so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
 			  SS_FCANTSENDMORE|SS_FWDRAIN);
@@ -660,16 +715,14 @@
 }
 
 void
-soisfconnected(so)
-        register struct socket *so;
+soisfconnected(struct socket *so)
 {
 	so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
 	so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
 }
 
-void
-sofcantrcvmore(so)
-	struct  socket *so;
+static void
+sofcantrcvmore(struct socket *so)
 {
 	if ((so->so_state & SS_NOFDREF) == 0) {
 		shutdown(so->s,0);
@@ -684,9 +737,8 @@
 	   so->so_state |= SS_FCANTRCVMORE;
 }
 
-void
-sofcantsendmore(so)
-	struct socket *so;
+static void
+sofcantsendmore(struct socket *so)
 {
 	if ((so->so_state & SS_NOFDREF) == 0) {
             shutdown(so->s,1);           /* send FIN to fhost */
@@ -705,8 +757,7 @@
 }
 
 void
-soisfdisconnected(so)
-	struct socket *so;
+soisfdisconnected(struct socket *so)
 {
 /*	so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */
 /*	close(so->s); */
@@ -721,8 +772,7 @@
  * Set CANTSENDMORE once all data has been write()n
  */
 void
-sofwdrain(so)
-	struct socket *so;
+sofwdrain(struct socket *so)
 {
 	if (so->so_rcv.sb_cc)
 		so->so_state |= SS_FWDRAIN;
diff --git a/slirp2/socket.h b/slirp-android/socket.h
similarity index 87%
rename from slirp2/socket.h
rename to slirp-android/socket.h
index 5b71d45..67591cd 100644
--- a/slirp2/socket.h
+++ b/slirp-android/socket.h
@@ -23,7 +23,7 @@
   int s;                           /* The actual socket */
 
 			/* XXX union these with not-yet-used sbuf params */
-  MBuf so_m;	           /* Pointer to the original SYN packet,
+  struct mbuf *so_m;	           /* Pointer to the original SYN packet,
 				    * for non-blocking connect()'s, and
 				    * PING reply's */
   struct tcpiphdr *so_ti;	   /* Pointer to the original ti within
@@ -49,8 +49,8 @@
 				 * Used to determine when to "downgrade" a session
 					 * from fastq to batchq */
 
-  SBufRec so_rcv;		/* Receive buffer */
-  SBufRec so_snd;		/* Send buffer */
+  struct sbuf so_rcv;		/* Receive buffer */
+  struct sbuf so_snd;		/* Send buffer */
   void * extra;			/* Extra pointer */
 };
 
@@ -73,16 +73,9 @@
 #define SS_FACCEPTONCE		0x200	/* If set, the SS_FACCEPTCONN socket will die after one accept */
 #define SS_PROXIFIED            0x400   /* Socket is trying to connect through a proxy, only makes sense
                                            when SS_ISFCONNECTING is also set */
+
 extern struct socket tcb;
 
-
-#if defined(DECLARE_IOVEC) && !defined(HAVE_READV)
-struct iovec {
-	char *iov_base;
-	size_t iov_len;
-};
-#endif
-
 void so_init _P((void));
 struct socket * solookup _P((struct socket *, uint32_t, u_int, uint32_t, u_int));
 struct socket * socreate _P((void));
@@ -92,16 +85,15 @@
 int sosendoob _P((struct socket *));
 int sowrite _P((struct socket *));
 void sorecvfrom _P((struct socket *));
-int sosendto _P((struct socket *, MBuf ));
+int sosendto _P((struct socket *, struct mbuf *));
 struct socket * solisten _P((u_int, u_int32_t, u_int, int));
 int  sounlisten _P((u_int port));
-void sorwakeup _P((struct socket *));
-void sowwakeup _P((struct socket *));
 void soisfconnecting _P((register struct socket *));
 void soisfconnected _P((register struct socket *));
-void sofcantrcvmore _P((struct  socket *));
-void sofcantsendmore _P((struct socket *));
 void soisfdisconnected _P((struct socket *));
 void sofwdrain _P((struct socket *));
+struct iovec; /* For win32 */
+size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
+int soreadbuf(struct socket *so, const char *buf, int size);
 
 #endif /* _SOCKET_H_ */
diff --git a/slirp2/tcp.h b/slirp-android/tcp.h
similarity index 98%
rename from slirp2/tcp.h
rename to slirp-android/tcp.h
index 3cddb77..ee02342 100644
--- a/slirp2/tcp.h
+++ b/slirp-android/tcp.h
@@ -44,8 +44,6 @@
 #define      PR_SLOWHZ       2               /* 2 slow timeouts per second (approx) */
 #define      PR_FASTHZ       5               /* 5 fast timeouts per second (not important) */
 
-extern int tcp_rcvspace;
-extern int tcp_sndspace;
 extern struct socket *tcp_last_so;
 
 #define TCP_SNDSPACE 8192
@@ -170,6 +168,6 @@
 
 extern tcp_seq tcp_iss;                /* tcp initial send seq # */
 
-extern char *tcpstates[];
+extern const char * const tcpstates[];
 
 #endif
diff --git a/slirp2/tcp_input.c b/slirp-android/tcp_input.c
similarity index 87%
copy from slirp2/tcp_input.c
copy to slirp-android/tcp_input.c
index c3196d3..9ecd2eb 100644
--- a/slirp2/tcp_input.c
+++ b/slirp-android/tcp_input.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -47,7 +43,7 @@
 
 struct socket tcb;
 
-int	tcprexmtthresh = 3;
+#define	TCPREXMTTHRESH 3
 struct	socket *tcp_last_so = &tcb;
 
 tcp_seq tcp_iss;                /* tcp initial send seq # */
@@ -79,12 +75,12 @@
                        tp->t_flags |= TF_DELACK; \
                (tp)->rcv_nxt += (ti)->ti_len; \
                flags = (ti)->ti_flags & TH_FIN; \
-               tcpstat.tcps_rcvpack++;\
-               tcpstat.tcps_rcvbyte += (ti)->ti_len;\
+               STAT(tcpstat.tcps_rcvpack++);         \
+               STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len);   \
                if (so->so_emu) { \
-		       if (tcp_emu((so),(m))) sbuf_append((so), (m)); \
+		       if (tcp_emu((so),(m))) sbappend((so), (m)); \
 	       } else \
-	       	       sbuf_append((so), (m)); \
+	       	       sbappend((so), (m)); \
 /*               sorwakeup(so); */ \
 	} else {\
                (flags) = tcp_reass((tp), (ti), (m)); \
@@ -94,17 +90,17 @@
 #else
 #define	TCP_REASS(tp, ti, m, so, flags) { \
 	if ((ti)->ti_seq == (tp)->rcv_nxt && \
-	    tcpfrag_list_empty(tp) && \
+        tcpfrag_list_empty(tp) && \
 	    (tp)->t_state == TCPS_ESTABLISHED) { \
 		tp->t_flags |= TF_DELACK; \
 		(tp)->rcv_nxt += (ti)->ti_len; \
 		flags = (ti)->ti_flags & TH_FIN; \
-		tcpstat.tcps_rcvpack++;\
-		tcpstat.tcps_rcvbyte += (ti)->ti_len;\
+		STAT(tcpstat.tcps_rcvpack++);        \
+		STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len);  \
 		if (so->so_emu) { \
-			if (tcp_emu((so),(m))) sbuf_append(so, (m)); \
+			if (tcp_emu((so),(m))) sbappend(so, (m)); \
 		} else \
-			sbuf_append((so), (m)); \
+			sbappend((so), (m)); \
 /*		sorwakeup(so); */ \
 	} else { \
 		(flags) = tcp_reass((tp), (ti), (m)); \
@@ -112,29 +108,30 @@
 	} \
 }
 #endif
+static void tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt,
+                          struct tcpiphdr *ti);
+static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
 
-int
-tcp_reass(tp, ti, m)
-	register struct tcpcb *tp;
-	register struct tcpiphdr *ti;
-	MBuf m;
+static int
+tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
+          struct mbuf *m)
 {
 	register struct tcpiphdr *q;
 	struct socket *so = tp->t_socket;
 	int flags;
 
 	/*
-	 * Call with ti==0 after become established to
+	 * Call with ti==NULL after become established to
 	 * force pre-ESTABLISHED data up to user socket.
 	 */
-	if (ti == 0)
+        if (ti == NULL)
 		goto present;
 
 	/*
 	 * Find a segment which begins after this one does.
 	 */
 	for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp);
-	     q = tcpiphdr_next(q))
+            q = tcpiphdr_next(q))
 		if (SEQ_GT(q->ti_seq, ti->ti_seq))
 			break;
 
@@ -150,9 +147,9 @@
 		i = q->ti_seq + q->ti_len - ti->ti_seq;
 		if (i > 0) {
 			if (i >= ti->ti_len) {
-				tcpstat.tcps_rcvduppack++;
-				tcpstat.tcps_rcvdupbyte += ti->ti_len;
-				mbuf_free(m);
+				STAT(tcpstat.tcps_rcvduppack++);
+				STAT(tcpstat.tcps_rcvdupbyte += ti->ti_len);
+				m_freem(m);
 				/*
 				 * Try to present any queued data
 				 * at the left window edge to the user.
@@ -161,14 +158,14 @@
 				 */
 				goto present;   /* ??? */
 			}
-			mbuf_trim(m, i);
+			m_adj(m, i);
 			ti->ti_len -= i;
 			ti->ti_seq += i;
 		}
 		q = tcpiphdr_next(q);
 	}
-	tcpstat.tcps_rcvoopack++;
-	tcpstat.tcps_rcvoobyte += ti->ti_len;
+	STAT(tcpstat.tcps_rcvoopack++);
+	STAT(tcpstat.tcps_rcvoobyte += ti->ti_len);
 	ti->ti_mbuf = m;
 
 	/*
@@ -182,13 +179,13 @@
 		if (i < q->ti_len) {
 			q->ti_seq += i;
 			q->ti_len -= i;
-			mbuf_trim(q->ti_mbuf, i);
+			m_adj(q->ti_mbuf, i);
 			break;
 		}
 		q = tcpiphdr_next(q);
 		m = tcpiphdr_prev(q)->ti_mbuf;
 		remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
-		mbuf_free(m);
+		m_freem(m);
 	}
 
 	/*
@@ -203,8 +200,8 @@
 	 */
 	if (!TCPS_HAVEESTABLISHED(tp->t_state))
 		return (0);
-        ti = tcpfrag_list_first(tp);
-        if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt)
+	ti = tcpfrag_list_first(tp);
+	if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt)
 		return (0);
 	if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
 		return (0);
@@ -216,14 +213,14 @@
 		ti = tcpiphdr_next(ti);
 /*		if (so->so_state & SS_FCANTRCVMORE) */
 		if (so->so_state & SS_FCANTSENDMORE)
-			mbuf_free(m);
+			m_freem(m);
 		else {
 			if (so->so_emu) {
-				if (tcp_emu(so,m)) sbuf_append(so, m);
+				if (tcp_emu(so,m)) sbappend(so, m);
 			} else
-				sbuf_append(so, m);
+				sbappend(so, m);
 		}
-	} while (!tcpfrag_list_end(ti, tp) && ti->ti_seq == tp->rcv_nxt);
+	} while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
 /*	sorwakeup(so); */
 	return (flags);
 }
@@ -233,25 +230,23 @@
  * protocol specification dated September, 1981 very closely.
  */
 void
-tcp_input(m, iphlen, inso)
-	register MBuf m;
-	int iphlen;
-	struct socket *inso;
+tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 {
   	struct ip save_ip, *ip;
 	register struct tcpiphdr *ti;
 	caddr_t optp = NULL;
 	int optlen = 0;
 	int len, tlen, off;
-	register struct tcpcb *tp = 0;
+        register struct tcpcb *tp = NULL;
 	register int tiflags;
-	struct socket *so = 0;
+        struct socket *so = NULL;
 	int todrop, acked, ourfinisacked, needoutput = 0;
 /*	int dropsocket = 0; */
 	int iss = 0;
 	u_long tiwin;
 	int ret;
 /*	int ts_present = 0; */
+    struct ex_list *ex_ptr;
 
 	DEBUG_CALL("tcp_input");
 	DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n",
@@ -266,7 +261,7 @@
 		/* Re-set a few variables */
 		tp = sototcpcb(so);
 		m = so->so_m;
-		so->so_m = 0;
+                so->so_m = NULL;
 		ti = so->so_ti;
 		tiwin = ti->ti_win;
 		tiflags = ti->ti_flags;
@@ -275,14 +270,14 @@
 	}
 
 
-	tcpstat.tcps_rcvtotal++;
+	STAT(tcpstat.tcps_rcvtotal++);
 	/*
 	 * Get IP and TCP header together in first mbuf.
 	 * Note: IP leaves IP header in first mbuf.
 	 */
-	ti = MBUF_TO(m, struct tcpiphdr *);
+	ti = mtod(m, struct tcpiphdr *);
 	if (iphlen > sizeof(struct ip )) {
-	  ip_stripoptions(m, (MBuf )0);
+	  ip_stripoptions(m, (struct mbuf *)0);
 	  iphlen=sizeof(struct ip );
 	}
 	/* XXX Check if too short */
@@ -292,7 +287,7 @@
 	 * Save a copy of the IP header in case we want restore it
 	 * for sending an ICMP error message in response.
 	 */
-	ip=MBUF_TO(m, struct ip *);
+	ip=mtod(m, struct ip *);
 	save_ip = *ip;
 	save_ip.ip_len+= iphlen;
 
@@ -300,8 +295,8 @@
 	 * Checksum extended TCP header and data.
 	 */
 	tlen = ((struct ip *)ti)->ip_len;
-	tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = 0;
-	memset(&ti->ti_i.ih_mbuf, 0, sizeof(struct mbuf_ptr));
+        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
 	ti->ti_x1 = 0;
 	ti->ti_len = htons((u_int16_t)tlen);
 	len = sizeof(struct ip ) + tlen;
@@ -309,7 +304,7 @@
 	 * ti->ti_sum = cksum(m, len);
 	 * if (ti->ti_sum) { */
 	if(cksum(m, len)) {
-	  tcpstat.tcps_rcvbadsum++;
+	  STAT(tcpstat.tcps_rcvbadsum++);
 	  goto drop;
 	}
 
@@ -319,14 +314,14 @@
 	 */
 	off = ti->ti_off << 2;
 	if (off < sizeof (struct tcphdr) || off > tlen) {
-	  tcpstat.tcps_rcvbadoff++;
+	  STAT(tcpstat.tcps_rcvbadoff++);
 	  goto drop;
 	}
 	tlen -= off;
 	ti->ti_len = tlen;
 	if (off > sizeof (struct tcphdr)) {
 	  optlen = off - sizeof (struct tcphdr);
-	  optp = MBUF_TO(m, caddr_t) + sizeof (struct tcpiphdr);
+	  optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
 
 		/*
 		 * Do quick retrieval of timestamp options ("options
@@ -363,28 +358,36 @@
 	m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 
+    if (slirp_restrict) {
+        for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+            if (ex_ptr->ex_fport == port_geth(ti->ti_dport) &&
+                    (ip_geth(ti->ti_dst) & 0xff) == ex_ptr->ex_addr)
+                break;
+
+        if (!ex_ptr)
+            goto drop;
+    }
 	/*
 	 * Locate pcb for segment.
 	 */
 findso:
 	so = tcp_last_so;
-        {
-            uint32_t  srcip   = ip_geth(ti->ti_src);
-            uint32_t  dstip   = ip_geth(ti->ti_dst);
-            uint16_t  dstport = port_geth(ti->ti_dport);
-            uint16_t  srcport = port_geth(ti->ti_sport);
- 
-	if (so->so_faddr_port != dstport ||
-	    so->so_laddr_port != srcport ||
-	    so->so_laddr_ip   != srcip ||
-	    so->so_faddr_ip   != dstip) {
-		so = solookup(&tcb, srcip, srcport, dstip, dstport);
-		if (so)
-			tcp_last_so = so;
-		++tcpstat.tcps_socachemiss;
-	}
-        }
+    {
+        uint32_t  srcip   = ip_geth(ti->ti_src);
+        uint32_t  dstip   = ip_geth(ti->ti_dst);
+        uint16_t  dstport = port_geth(ti->ti_dport);
+        uint16_t  srcport = port_geth(ti->ti_sport);
 
+		if (so->so_faddr_port != dstport ||
+			so->so_laddr_port != srcport ||
+			so->so_laddr_ip   != srcip ||
+			so->so_faddr_ip   != dstip) {
+			so = solookup(&tcb, srcip, srcport, dstip, dstport);
+			if (so)
+				tcp_last_so = so;
+			STAT(tcpstat.tcps_socachemiss++);
+		}
+    }
 	/*
 	 * If the state is CLOSED (i.e., TCB does not exist) then
 	 * all data in the incoming segment is discarded.
@@ -398,7 +401,7 @@
 	 * the only flag set, then create a session, mark it
 	 * as if it was LISTENING, and continue...
 	 */
-	if (so == 0) {
+        if (so == NULL) {
 	  if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
 	    goto dropwithreset;
 
@@ -409,8 +412,8 @@
 	    goto dropwithreset;
 	  }
 
-	  sbuf_reserve(&so->so_snd, tcp_sndspace);
-	  sbuf_reserve(&so->so_rcv, tcp_rcvspace);
+	  sbreserve(&so->so_snd, TCP_SNDSPACE);
+	  sbreserve(&so->so_rcv, TCP_RCVSPACE);
 
 	  /*		tcp_last_so = so; */  /* XXX ? */
 	  /*		tp = sototcpcb(so);    */
@@ -438,7 +441,7 @@
 	tp = sototcpcb(so);
 
 	/* XXX Should never fail */
-	if (tp == 0)
+        if (tp == NULL)
 		goto dropwithreset;
 	if (tp->t_state == TCPS_CLOSED)
 		goto drop;
@@ -455,10 +458,10 @@
 	 * Reset idle time and keep-alive timer.
 	 */
 	tp->t_idle = 0;
-	if (so_options)
-	   tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
+	if (SO_OPTIONS)
+	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
 	else
-	   tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
 
 	/*
 	 * Process options if not in LISTEN state,
@@ -510,7 +513,7 @@
 				/*
 				 * this is a pure ack for outstanding data.
 				 */
-				++tcpstat.tcps_predack;
+				STAT(tcpstat.tcps_predack++);
 /*				if (ts_present)
  *					tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
  *				else
@@ -518,11 +521,11 @@
 					    SEQ_GT(ti->ti_ack, tp->t_rtseq))
 					tcp_xmit_timer(tp, tp->t_rtt);
 				acked = ti->ti_ack - tp->snd_una;
-				tcpstat.tcps_rcvackpack++;
-				tcpstat.tcps_rcvackbyte += acked;
-				sbuf_drop(&so->so_snd, acked);
+				STAT(tcpstat.tcps_rcvackpack++);
+				STAT(tcpstat.tcps_rcvackbyte += acked);
+				sbdrop(&so->so_snd, acked);
 				tp->snd_una = ti->ti_ack;
-				mbuf_free(m);
+				m_freem(m);
 
 				/*
 				 * If all outstanding data are acked, stop
@@ -557,23 +560,23 @@
 			}
 		} else if (ti->ti_ack == tp->snd_una &&
 		    tcpfrag_list_empty(tp) &&
-		    ti->ti_len <= sbuf_space(&so->so_rcv)) {
+		    ti->ti_len <= sbspace(&so->so_rcv)) {
 			/*
 			 * this is a pure, in-sequence data packet
 			 * with nothing on the reassembly queue and
 			 * we have enough buffer space to take it.
 			 */
-			++tcpstat.tcps_preddat;
+			STAT(tcpstat.tcps_preddat++);
 			tp->rcv_nxt += ti->ti_len;
-			tcpstat.tcps_rcvpack++;
-			tcpstat.tcps_rcvbyte += ti->ti_len;
+			STAT(tcpstat.tcps_rcvpack++);
+			STAT(tcpstat.tcps_rcvbyte += ti->ti_len);
 			/*
 			 * Add data to socket buffer.
 			 */
 			if (so->so_emu) {
-				if (tcp_emu(so,m)) sbuf_append(so, m);
+				if (tcp_emu(so,m)) sbappend(so, m);
 			} else
-				sbuf_append(so, m);
+				sbappend(so, m);
 
 			/*
 			 * XXX This is called when data arrives.  Later, check
@@ -602,7 +605,7 @@
 	 * but not less than advertised window.
 	 */
 	{ int win;
-          win = sbuf_space(&so->so_rcv);
+          win = sbspace(&so->so_rcv);
 	  if (win < 0)
 	    win = 0;
 	  tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
@@ -642,7 +645,26 @@
 	   * tcp_ctl once connected, otherwise connect
 	   */
 	  if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) {
-	    //int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff;
+	    int lastbyte=so->so_faddr_ip & 0xff;
+	    if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) {
+#if 0
+	      if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) {
+		/* Command or exec adress */
+		so->so_state |= SS_CTL;
+	      } else
+#endif
+              {
+		/* May be an add exec */
+		for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+		  if(ex_ptr->ex_fport == so->so_faddr_port &&
+		     lastbyte == ex_ptr->ex_addr) {
+		    so->so_state |= SS_CTL;
+		    break;
+		  }
+		}
+	      }
+	      if(so->so_state & SS_CTL) goto cont_input;
+	    }
 	    /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
 	  }
 
@@ -671,7 +693,7 @@
 	      icmp_error(m, ICMP_UNREACH,code, 0,errno_str);
 	    }
 	    tp = tcp_close(tp);
-	    mbuf_free(m);
+	    m_free(m);
 	  } else {
 	    /*
 	     * Haven't connected yet, save the current mbuf
@@ -691,7 +713,6 @@
 	   * Check if the connect succeeded
 	   */
 	  if (so->so_state & SS_NOFDREF) {
-            DEBUG_MISC((dfd, " tcp_input closing connecting socket %lx\n", (long)so));
 	    tp = tcp_close(tp);
 	    goto dropwithreset;
 	  }
@@ -714,8 +735,7 @@
 	  tp->t_flags |= TF_ACKNOW;
 	  tp->t_state = TCPS_SYN_RECEIVED;
 	  tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
-	  tcpstat.tcps_accepts++;
-          DEBUG_MISC((dfd, " tcp_input accept connected socket %lx\n", (long)so));
+	  STAT(tcpstat.tcps_accepts++);
 	  goto trimthenstep6;
 	} /* case TCPS_LISTEN */
 
@@ -756,7 +776,7 @@
 		tcp_rcvseqinit(tp);
 		tp->t_flags |= TF_ACKNOW;
 		if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
-			tcpstat.tcps_connects++;
+			STAT(tcpstat.tcps_connects++);
 			soisfconnected(so);
 			tp->t_state = TCPS_ESTABLISHED;
 
@@ -768,7 +788,7 @@
  *			}
  */
 			(void) tcp_reass(tp, (struct tcpiphdr *)0,
-				(MBuf )0);
+				(struct mbuf *)0);
 			/*
 			 * if we didn't have to retransmit the SYN,
 			 * use its rtt as our initial srtt & rtt var.
@@ -787,11 +807,11 @@
 		ti->ti_seq++;
 		if (ti->ti_len > tp->rcv_wnd) {
 			todrop = ti->ti_len - tp->rcv_wnd;
-			mbuf_trim(m, -todrop);
+			m_adj(m, -todrop);
 			ti->ti_len = tp->rcv_wnd;
 			tiflags &= ~TH_FIN;
-			tcpstat.tcps_rcvpackafterwin++;
-			tcpstat.tcps_rcvbyteafterwin += todrop;
+			STAT(tcpstat.tcps_rcvpackafterwin++);
+			STAT(tcpstat.tcps_rcvbyteafterwin += todrop);
 		}
 		tp->snd_wl1 = ti->ti_seq - 1;
 		tp->rcv_up = ti->ti_seq;
@@ -862,13 +882,13 @@
 			 */
 			tp->t_flags |= TF_ACKNOW;
 			todrop = ti->ti_len;
-			tcpstat.tcps_rcvduppack++;
-			tcpstat.tcps_rcvdupbyte += todrop;
+			STAT(tcpstat.tcps_rcvduppack++);
+			STAT(tcpstat.tcps_rcvdupbyte += todrop);
 		} else {
-			tcpstat.tcps_rcvpartduppack++;
-			tcpstat.tcps_rcvpartdupbyte += todrop;
+			STAT(tcpstat.tcps_rcvpartduppack++);
+			STAT(tcpstat.tcps_rcvpartdupbyte += todrop);
 		}
-		mbuf_trim(m, todrop);
+		m_adj(m, todrop);
 		ti->ti_seq += todrop;
 		ti->ti_len -= todrop;
 		if (ti->ti_urp > todrop)
@@ -885,7 +905,7 @@
 	if ((so->so_state & SS_NOFDREF) &&
 	    tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
 		tp = tcp_close(tp);
-		tcpstat.tcps_rcvafterclose++;
+		STAT(tcpstat.tcps_rcvafterclose++);
 		goto dropwithreset;
 	}
 
@@ -895,9 +915,9 @@
 	 */
 	todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
 	if (todrop > 0) {
-		tcpstat.tcps_rcvpackafterwin++;
+		STAT(tcpstat.tcps_rcvpackafterwin++);
 		if (todrop >= ti->ti_len) {
-			tcpstat.tcps_rcvbyteafterwin += ti->ti_len;
+			STAT(tcpstat.tcps_rcvbyteafterwin += ti->ti_len);
 			/*
 			 * If a new connection request is received
 			 * while in TIME_WAIT, drop the old connection
@@ -920,12 +940,12 @@
 			 */
 			if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
 				tp->t_flags |= TF_ACKNOW;
-				tcpstat.tcps_rcvwinprobe++;
+				STAT(tcpstat.tcps_rcvwinprobe++);
 			} else
 				goto dropafterack;
 		} else
-			tcpstat.tcps_rcvbyteafterwin += todrop;
-		mbuf_trim(m, -todrop);
+			STAT(tcpstat.tcps_rcvbyteafterwin += todrop);
+		m_adj(m, -todrop);
 		ti->ti_len -= todrop;
 		tiflags &= ~(TH_PUSH|TH_FIN);
 	}
@@ -965,7 +985,7 @@
 /*		so->so_error = ECONNRESET; */
 	close:
 		tp->t_state = TCPS_CLOSED;
-		tcpstat.tcps_drops++;
+		STAT(tcpstat.tcps_drops++);
 		tp = tcp_close(tp);
 		goto drop;
 
@@ -1004,7 +1024,7 @@
 		if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
 		    SEQ_GT(ti->ti_ack, tp->snd_max))
 			goto dropwithreset;
-		tcpstat.tcps_connects++;
+		STAT(tcpstat.tcps_connects++);
 		tp->t_state = TCPS_ESTABLISHED;
 		/*
 		 * The sent SYN is ack'ed with our sequence number +1
@@ -1037,7 +1057,7 @@
  *			tp->rcv_scale = tp->request_r_scale;
  *		}
  */
-		(void) tcp_reass(tp, (struct tcpiphdr *)0, (MBuf )0);
+		(void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
 		tp->snd_wl1 = ti->ti_seq - 1;
 		/* Avoid ack processing; snd_una==ti_ack  =>  dup ack */
 		goto synrx_to_est;
@@ -1061,7 +1081,7 @@
 
 		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
 			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
-			  tcpstat.tcps_rcvdupack++;
+			  STAT(tcpstat.tcps_rcvdupack++);
 			  DEBUG_MISC((dfd," dup ack  m = %lx  so = %lx \n",
 				      (long )m, (long )so));
 				/*
@@ -1091,7 +1111,7 @@
 				if (tp->t_timer[TCPT_REXMT] == 0 ||
 				    ti->ti_ack != tp->snd_una)
 					tp->t_dupacks = 0;
-				else if (++tp->t_dupacks == tcprexmtthresh) {
+				else if (++tp->t_dupacks == TCPREXMTTHRESH) {
 					tcp_seq onxt = tp->snd_nxt;
 					u_int win =
 					    min(tp->snd_wnd, tp->snd_cwnd) / 2 /
@@ -1110,7 +1130,7 @@
 					if (SEQ_GT(onxt, tp->snd_nxt))
 						tp->snd_nxt = onxt;
 					goto drop;
-				} else if (tp->t_dupacks > tcprexmtthresh) {
+				} else if (tp->t_dupacks > TCPREXMTTHRESH) {
 					tp->snd_cwnd += tp->t_maxseg;
 					(void) tcp_output(tp);
 					goto drop;
@@ -1124,17 +1144,17 @@
 		 * If the congestion window was inflated to account
 		 * for the other side's cached packets, retract it.
 		 */
-		if (tp->t_dupacks > tcprexmtthresh &&
+		if (tp->t_dupacks > TCPREXMTTHRESH &&
 		    tp->snd_cwnd > tp->snd_ssthresh)
 			tp->snd_cwnd = tp->snd_ssthresh;
 		tp->t_dupacks = 0;
 		if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
-			tcpstat.tcps_rcvacktoomuch++;
+			STAT(tcpstat.tcps_rcvacktoomuch++);
 			goto dropafterack;
 		}
 		acked = ti->ti_ack - tp->snd_una;
-		tcpstat.tcps_rcvackpack++;
-		tcpstat.tcps_rcvackbyte += acked;
+		STAT(tcpstat.tcps_rcvackpack++);
+		STAT(tcpstat.tcps_rcvackbyte += acked);
 
 		/*
 		 * If we have a timestamp reply, update smoothed
@@ -1180,10 +1200,10 @@
 		}
 		if (acked > so->so_snd.sb_cc) {
 			tp->snd_wnd -= so->so_snd.sb_cc;
-			sbuf_drop(&so->so_snd, (int )so->so_snd.sb_cc);
+			sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);
 			ourfinisacked = 1;
 		} else {
-			sbuf_drop(&so->so_snd, acked);
+			sbdrop(&so->so_snd, acked);
 			tp->snd_wnd -= acked;
 			ourfinisacked = 0;
 		}
@@ -1216,7 +1236,7 @@
 				 */
 				if (so->so_state & SS_FCANTRCVMORE) {
 					soisfdisconnected(so);
-					tp->t_timer[TCPT_2MSL] = tcp_maxidle;
+					tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;
 				}
 				tp->t_state = TCPS_FIN_WAIT_2;
 			}
@@ -1273,7 +1293,7 @@
 		/* keep track of pure window updates */
 		if (ti->ti_len == 0 &&
 		    tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd)
-			tcpstat.tcps_rcvwinupd++;
+			STAT(tcpstat.tcps_rcvwinupd++);
 		tp->snd_wnd = tiwin;
 		tp->snd_wl1 = ti->ti_seq;
 		tp->snd_wl2 = ti->ti_ack;
@@ -1347,7 +1367,7 @@
 		 */
 		len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt);
 	} else {
-		mbuf_free(m);
+		m_free(m);
 		tiflags &= ~TH_FIN;
 	}
 
@@ -1449,13 +1469,13 @@
 	 */
 	if (tiflags & TH_RST)
 		goto drop;
-	mbuf_free(m);
+	m_freem(m);
 	tp->t_flags |= TF_ACKNOW;
 	(void) tcp_output(tp);
 	return;
 
 dropwithreset:
-	/* reuses m if m!=NULL, mbuf_free() unnecessary */
+	/* reuses m if m!=NULL, m_free() unnecessary */
 	if (tiflags & TH_ACK)
 		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
 	else {
@@ -1470,7 +1490,7 @@
 	/*
 	 * Drop space held by incoming segment and return.
 	 */
-	mbuf_free(m);
+	m_free(m);
 
 	return;
 }
@@ -1479,12 +1499,8 @@
 /*	int *ts_present;
  *	u_int32_t *ts_val, *ts_ecr;
  */
-void
-tcp_dooptions(tp, cp, cnt, ti)
-	struct tcpcb *tp;
-	u_char *cp;
-	int cnt;
-	struct tcpiphdr *ti;
+static void
+tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
 {
 	u_int16_t mss;
 	int opt, optlen;
@@ -1564,13 +1580,13 @@
 tcp_pulloutofband(so, ti, m)
 	struct socket *so;
 	struct tcpiphdr *ti;
-	register MBuf m;
+	register struct mbuf *m;
 {
 	int cnt = ti->ti_urp - 1;
 
 	while (cnt >= 0) {
 		if (m->m_len > cnt) {
-			char *cp = MBUF_TO(m, caddr_t) + cnt;
+			char *cp = mtod(m, caddr_t) + cnt;
 			struct tcpcb *tp = sototcpcb(so);
 
 			tp->t_iobc = *cp;
@@ -1594,10 +1610,8 @@
  * and update averages and current timeout.
  */
 
-void
-tcp_xmit_timer(tp, rtt)
-	register struct tcpcb *tp;
-	int rtt;
+static void
+tcp_xmit_timer(register struct tcpcb *tp, int rtt)
 {
 	register short delta;
 
@@ -1605,7 +1619,7 @@
 	DEBUG_ARG("tp = %lx", (long)tp);
 	DEBUG_ARG("rtt = %d", rtt);
 
-	tcpstat.tcps_rttupdated++;
+	STAT(tcpstat.tcps_rttupdated++);
 	if (tp->t_srtt != 0) {
 		/*
 		 * srtt is stored as fixed point with 3 bits after the
@@ -1685,9 +1699,7 @@
  */
 
 int
-tcp_mss(tp, offer)
-        register struct tcpcb *tp;
-        u_int offer;
+tcp_mss(struct tcpcb *tp, u_int offer)
 {
 	struct socket *so = tp->t_socket;
 	int mss;
@@ -1696,7 +1708,7 @@
 	DEBUG_ARG("tp = %lx", (long)tp);
 	DEBUG_ARG("offer = %d", offer);
 
-	mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr);
+	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr);
 	if (offer)
 		mss = min(mss, offer);
 	mss = max(mss, 32);
@@ -1705,8 +1717,12 @@
 
 	tp->snd_cwnd = mss;
 
-	sbuf_reserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0));
-	sbuf_reserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0));
+	sbreserve(&so->so_snd, TCP_SNDSPACE + ((TCP_SNDSPACE % mss) ?
+                                               (mss - (TCP_SNDSPACE % mss)) :
+                                               0));
+	sbreserve(&so->so_rcv, TCP_RCVSPACE + ((TCP_RCVSPACE % mss) ?
+                                               (mss - (TCP_RCVSPACE % mss)) :
+                                               0));
 
 	DEBUG_MISC((dfd, " returning mss = %d\n", mss));
 
diff --git a/slirp2/tcp_output.c b/slirp-android/tcp_output.c
similarity index 91%
rename from slirp2/tcp_output.c
rename to slirp-android/tcp_output.c
index 95246aa..9ed50f5 100644
--- a/slirp2/tcp_output.c
+++ b/slirp-android/tcp_output.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -37,8 +33,8 @@
 /*
  * Changes and additions relating to SLiRP
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -48,16 +44,16 @@
  * Since this is only used in "stats socket", we give meaning
  * names instead of the REAL names
  */
-char *tcpstates[] = {
+const char * const tcpstates[] = {
 /*	"CLOSED",       "LISTEN",       "SYN_SENT",     "SYN_RCVD", */
 	"REDIRECT",	"LISTEN",	"SYN_SENT",     "SYN_RCVD",
 	"ESTABLISHED",  "CLOSE_WAIT",   "FIN_WAIT_1",   "CLOSING",
 	"LAST_ACK",     "FIN_WAIT_2",   "TIME_WAIT",
 };
 
-u_char  tcp_outflags[TCP_NSTATES] = {
+static const u_char  tcp_outflags[TCP_NSTATES] = {
 	TH_RST|TH_ACK, 0,      TH_SYN,        TH_SYN|TH_ACK,
-	TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, 
+	TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK,
 	TH_FIN|TH_ACK, TH_ACK, TH_ACK,
 };
 
@@ -68,21 +64,20 @@
  * Tcp output routine: figure out what should be sent and send it.
  */
 int
-tcp_output(tp)
-	register struct tcpcb *tp;
+tcp_output(struct tcpcb *tp)
 {
 	register struct socket *so = tp->t_socket;
 	register long len, win;
 	int off, flags, error;
-	register MBuf m;
+	register struct mbuf *m;
 	register struct tcpiphdr *ti;
 	u_char opt[MAX_TCPOPTLEN];
 	unsigned optlen, hdrlen;
 	int idle, sendalot;
-	
+
 	DEBUG_CALL("tcp_output");
 	DEBUG_ARG("tp = %lx", (long )tp);
-	
+
 	/*
 	 * Determine length of data that should be transmitted,
 	 * and flags that will be used.
@@ -103,9 +98,9 @@
 	win = min(tp->snd_wnd, tp->snd_cwnd);
 
 	flags = tcp_outflags[tp->t_state];
-	
+
 	DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags));
-	
+
 	/*
 	 * If in persist timeout with window of 0, send 1 byte.
 	 * Otherwise, if window is small but nonzero
@@ -158,7 +153,7 @@
 			tp->snd_nxt = tp->snd_una;
 		}
 	}
-	
+
 	if (len > tp->t_maxseg) {
 		len = tp->t_maxseg;
 		sendalot = 1;
@@ -166,7 +161,7 @@
 	if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
 		flags &= ~TH_FIN;
 
-	win = sbuf_space(&so->so_rcv);
+	win = sbspace(&so->so_rcv);
 
 	/*
 	 * Sender silly window avoidance.  If connection is idle
@@ -200,7 +195,7 @@
 	 * window, then want to send a window update to peer.
 	 */
 	if (win > 0) {
-		/* 
+		/*
 		 * "adv" is the amount we can increase the window,
 		 * taking into account that we are limited by
 		 * TCP_MAXWIN << tp->rcv_scale.
@@ -263,8 +258,8 @@
 	/*
 	 * No reason to send a segment, just return.
 	 */
-	tcpstat.tcps_didnuttin++;
-	
+	STAT(tcpstat.tcps_didnuttin++);
+
 	return (0);
 
 send:
@@ -302,9 +297,9 @@
  */
 		}
  	}
- 
+
  	/*
-	 * Send a timestamp and echo-reply if this is a SYN and our side 
+	 * Send a timestamp and echo-reply if this is a SYN and our side
 	 * wants to use timestamps (TF_REQ_TSTMP is set) or both our side
 	 * and our peer have sent timestamps in our SYN's.
  	 */
@@ -322,7 +317,7 @@
  *	}
  */
  	hdrlen += optlen;
- 
+
 	/*
 	 * Adjust data length if insertion of options will
 	 * bump the packet length beyond the t_maxseg length.
@@ -339,35 +334,35 @@
 	 */
 	if (len) {
 		if (tp->t_force && len == 1)
-			tcpstat.tcps_sndprobe++;
+			STAT(tcpstat.tcps_sndprobe++);
 		else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
-			tcpstat.tcps_sndrexmitpack++;
-			tcpstat.tcps_sndrexmitbyte += len;
+			STAT(tcpstat.tcps_sndrexmitpack++);
+			STAT(tcpstat.tcps_sndrexmitbyte += len);
 		} else {
-			tcpstat.tcps_sndpack++;
-			tcpstat.tcps_sndbyte += len;
+			STAT(tcpstat.tcps_sndpack++);
+			STAT(tcpstat.tcps_sndbyte += len);
 		}
 
-		m = mbuf_alloc();
+		m = m_get();
 		if (m == NULL) {
 /*			error = ENOBUFS; */
 			error = 1;
 			goto out;
 		}
-		m->m_data += if_maxlinkhdr;
+		m->m_data += IF_MAXLINKHDR;
 		m->m_len = hdrlen;
-		
-		/* 
+
+		/*
 		 * This will always succeed, since we make sure our mbufs
 		 * are big enough to hold one MSS packet + header + ... etc.
 		 */
 /*		if (len <= MHLEN - hdrlen - max_linkhdr) { */
 
-			sbuf_copy(&so->so_snd, off, (int) len, MBUF_TO(m, caddr_t) + hdrlen);
+			sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen);
 			m->m_len += len;
 
 /*		} else {
- *			m->m_next = mbuf_copy(so->so_snd.sb_mb, off, (int) len);
+ *			m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
  *			if (m->m_next == 0)
  *				len = 0;
  *		}
@@ -382,26 +377,26 @@
 			flags |= TH_PUSH;
 	} else {
 		if (tp->t_flags & TF_ACKNOW)
-			tcpstat.tcps_sndacks++;
+			STAT(tcpstat.tcps_sndacks++);
 		else if (flags & (TH_SYN|TH_FIN|TH_RST))
-			tcpstat.tcps_sndctrl++;
+			STAT(tcpstat.tcps_sndctrl++);
 		else if (SEQ_GT(tp->snd_up, tp->snd_una))
-			tcpstat.tcps_sndurg++;
+			STAT(tcpstat.tcps_sndurg++);
 		else
-			tcpstat.tcps_sndwinup++;
+			STAT(tcpstat.tcps_sndwinup++);
 
-		m = mbuf_alloc();
+		m = m_get();
 		if (m == NULL) {
 /*			error = ENOBUFS; */
 			error = 1;
 			goto out;
 		}
-		m->m_data += if_maxlinkhdr;
+		m->m_data += IF_MAXLINKHDR;
 		m->m_len = hdrlen;
 	}
 
-	ti = MBUF_TO(m, struct tcpiphdr *);
-	
+	ti = mtod(m, struct tcpiphdr *);
+
 	memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr));
 
 	/*
@@ -409,7 +404,7 @@
 	 * window for use in delaying messages about window sizes.
 	 * If resending a FIN, be sure not to use a new sequence number.
 	 */
-	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && 
+	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
 	    tp->snd_nxt == tp->snd_max)
 		tp->snd_nxt--;
 	/*
@@ -446,10 +441,10 @@
 	if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
 		win = (long)(tp->rcv_adv - tp->rcv_nxt);
 	ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale));
-	
+
 	if (SEQ_GT(tp->snd_up, tp->snd_una)) {
 		ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq)));
-#ifdef notdef		
+#ifdef notdef
 	if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
 		ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt));
 #endif
@@ -500,7 +495,7 @@
 			if (tp->t_rtt == 0) {
 				tp->t_rtt = 1;
 				tp->t_rtseq = startseq;
-				tcpstat.tcps_segstimed++;
+				STAT(tcpstat.tcps_segstimed++);
 			}
 		}
 
@@ -531,14 +526,14 @@
 	 * the template, but need a way to checksum without them.
 	 */
 	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
-	
+
     {
-	    
+
 	((struct ip *)ti)->ip_len = m->m_len;
 
-	((struct ip *)ti)->ip_ttl = ip_defttl;
+	((struct ip *)ti)->ip_ttl = IPDEFTTL;
 	((struct ip *)ti)->ip_tos = so->so_iptos;
-	    
+
 /* #if BSD >= 43 */
 	/* Don't do IP options... */
 /*	error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
@@ -547,7 +542,7 @@
 	error = ip_output(so, m);
 
 /* #else
- *	error = ip_output(m, (MBuf )0, &tp->t_inpcb->inp_route, 
+ *	error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route,
  *	    so->so_options & SO_DONTROUTE);
  * #endif
  */
@@ -567,7 +562,7 @@
  */
 		return (error);
 	}
-	tcpstat.tcps_sndtotal++;
+	STAT(tcpstat.tcps_sndtotal++);
 
 	/*
 	 * Data sent (as far as we can tell).
@@ -586,8 +581,7 @@
 }
 
 void
-tcp_setpersist(tp)
-	register struct tcpcb *tp;
+tcp_setpersist(struct tcpcb *tp)
 {
     int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
 
diff --git a/slirp2/tcp_subr.c b/slirp-android/tcp_subr.c
similarity index 81%
rename from slirp2/tcp_subr.c
rename to slirp-android/tcp_subr.c
index e453877..b8b680c 100644
--- a/slirp2/tcp_subr.c
+++ b/slirp-android/tcp_subr.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -47,28 +43,17 @@
 #include "proxy_common.h"
 
 /* patchable/settable parameters for tcp */
-int 	tcp_mssdflt = TCP_MSS;
-int 	tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
-int	tcp_do_rfc1323 = 0;	/* Don't do rfc1323 performance enhancements */
-int	tcp_rcvspace;	/* You may want to change this */
-int	tcp_sndspace;	/* Keep small if you have an error prone link */
+/* Don't do rfc1323 performance enhancements */
+#define TCP_DO_RFC1323 0
 
 /*
  * Tcp initialization
  */
 void
-tcp_init()
+tcp_init(void)
 {
 	tcp_iss = 1;		/* wrong */
 	tcb.so_next = tcb.so_prev = &tcb;
-
-	/* tcp_rcvspace = our Window we advertise to the remote */
-	tcp_rcvspace = TCP_RCVSPACE;
-	tcp_sndspace = TCP_SNDSPACE;
-
-	/* Make sure tcp_sndspace is at least 2*MSS */
-	if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)))
-		tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr));
 }
 
 /*
@@ -79,8 +64,7 @@
  */
 /* struct tcpiphdr * */
 void
-tcp_template(tp)
-	struct tcpcb *tp;
+tcp_template(struct tcpcb *tp)
 {
 	struct socket *so = tp->t_socket;
 	register struct tcpiphdr *n = &tp->t_template;
@@ -118,12 +102,8 @@
  * segment are as specified by the parameters.
  */
 void
-tcp_respond(tp, ti, m, ack, seq, flags)
-	struct tcpcb *tp;
-	register struct tcpiphdr *ti;
-	register MBuf m;
-	tcp_seq ack, seq;
-	int flags;
+tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
+            tcp_seq ack, tcp_seq seq, int flags)
 {
 	register int tlen;
 	int win = 0;
@@ -137,18 +117,18 @@
 	DEBUG_ARG("flags = %x", flags);
 
 	if (tp)
-		win = sbuf_space(&tp->t_socket->so_rcv);
-	if (m == 0) {
-		if ((m = mbuf_alloc()) == NULL)
+		win = sbspace(&tp->t_socket->so_rcv);
+        if (m == NULL) {
+		if ((m = m_get()) == NULL)
 			return;
 #ifdef TCP_COMPAT_42
 		tlen = 1;
 #else
 		tlen = 0;
 #endif
-		m->m_data += if_maxlinkhdr;
-		*MBUF_TO(m, struct tcpiphdr *) = *ti;
-		ti = MBUF_TO(m, struct tcpiphdr *);
+		m->m_data += IF_MAXLINKHDR;
+		*mtod(m, struct tcpiphdr *) = *ti;
+		ti = mtod(m, struct tcpiphdr *);
 		flags = TH_ACK;
 	} else {
 		/*
@@ -168,7 +148,7 @@
 	tlen += sizeof (struct tcpiphdr);
 	m->m_len = tlen;
 
-	ti->ti_mbuf = 0;
+        ti->ti_mbuf = NULL;
 	ti->ti_x1 = 0;
 	ti->ti_seq = htonl(seq);
 	ti->ti_ack = htonl(ack);
@@ -187,7 +167,7 @@
 	if(flags & TH_RST)
 	  ((struct ip *)ti)->ip_ttl = MAXTTL;
 	else
-	  ((struct ip *)ti)->ip_ttl = ip_defttl;
+	  ((struct ip *)ti)->ip_ttl = IPDEFTTL;
 
 	(void) ip_output((struct socket *)0, m);
 }
@@ -198,8 +178,7 @@
  * protocol control block.
  */
 struct tcpcb *
-tcp_newtcpcb(so)
-	struct socket *so;
+tcp_newtcpcb(struct socket *so)
 {
 	register struct tcpcb *tp;
 
@@ -209,9 +188,9 @@
 
 	memset((char *) tp, 0, sizeof(struct tcpcb));
 	tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
-	tp->t_maxseg = tcp_mssdflt;
+	tp->t_maxseg = TCP_MSS;
 
-	tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
+	tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
 	tp->t_socket = so;
 
 	/*
@@ -220,7 +199,7 @@
 	 * reasonable initial retransmit time.
 	 */
 	tp->t_srtt = TCPTV_SRTTBASE;
-	tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
+	tp->t_rttvar = TCPTV_SRTTDFLT << 2;
 	tp->t_rttmin = TCPTV_MIN;
 
 	TCPT_RANGESET(tp->t_rxtcur,
@@ -256,9 +235,9 @@
 	if (TCPS_HAVERCVDSYN(tp->t_state)) {
 		tp->t_state = TCPS_CLOSED;
 		(void) tcp_output(tp);
-		tcpstat.tcps_drops++;
+		STAT(tcpstat.tcps_drops++);
 	} else
-		tcpstat.tcps_conndrops++;
+		STAT(tcpstat.tcps_conndrops++);
 /*	if (errno == ETIMEDOUT && tp->t_softerror)
  *		errno = tp->t_softerror;
  */
@@ -273,12 +252,11 @@
  *	wake up any sleepers
  */
 struct tcpcb *
-tcp_close(tp)
-	register struct tcpcb *tp;
+tcp_close(struct tcpcb *tp)
 {
 	register struct tcpiphdr *t;
 	struct socket *so = tp->t_socket;
-	register MBuf m;
+	register struct mbuf *m;
 
 	DEBUG_CALL("tcp_close");
 	DEBUG_ARG("tp = %lx", (long )tp);
@@ -286,30 +264,31 @@
 	/* free the reassembly queue, if any */
 	t = tcpfrag_list_first(tp);
 	while (!tcpfrag_list_end(t, tp)) {
-	    t = tcpiphdr_next(t);
-	    m = tcpiphdr_prev(t)->ti_mbuf;
-	    remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
-            mbuf_free(m);
+		t = tcpiphdr_next(t);
+		m = tcpiphdr_prev(t)->ti_mbuf;
+		remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
+		m_freem(m);
 	}
 	/* It's static */
 /*	if (tp->t_template)
- *		(void) mbuf_free(MBUF_FROM(tp->t_template));
+ *		(void) m_free(dtom(tp->t_template));
  */
 /*	free(tp, M_PCB);  */
 	free(tp);
-	so->so_tcpcb = 0;
+        so->so_tcpcb = NULL;
 	soisfdisconnected(so);
 	/* clobber input socket cache if we're closing the cached connection */
 	if (so == tcp_last_so)
 		tcp_last_so = &tcb;
 	socket_close(so->s);
-	sbuf_free(&so->so_rcv);
-	sbuf_free(&so->so_snd);
+	sbfree(&so->so_rcv);
+	sbfree(&so->so_snd);
 	sofree(so);
-	tcpstat.tcps_closed++;
+	STAT(tcpstat.tcps_closed++);
 	return ((struct tcpcb *)0);
 }
 
+#ifdef notdef
 void
 tcp_drain()
 {
@@ -320,9 +299,6 @@
  * When a source quench is received, close congestion window
  * to one segment.  We will gradually open it again as we proceed.
  */
-
-#ifdef notdef
-
 void
 tcp_quench(i, errno)
 
@@ -351,8 +327,7 @@
  * We can let the user exit from the close as soon as the FIN is acked.
  */
 void
-tcp_sockclosed(tp)
-	struct tcpcb *tp;
+tcp_sockclosed(struct tcpcb *tp)
 {
 
 	DEBUG_CALL("tcp_sockclosed");
@@ -412,10 +387,9 @@
  * nonblocking.  Connect returns after the SYN is sent, and does
  * not wait for ACK+SYN.
  */
-int tcp_fconnect(so)
-     struct socket *so;
+int tcp_fconnect(struct socket *so)
 {
-    int ret=0;
+  int ret=0;
     int try_proxy = 1;
     SockAddress    sockaddr;
     uint32_t       sock_ip;
@@ -486,8 +460,7 @@
  * here and SYN the local-host.
  */
 void
-tcp_connect(inso)
-	struct socket *inso;
+tcp_connect(struct socket *inso)
 {
 	struct socket *so;
 	SockAddress   addr;
@@ -531,7 +504,7 @@
 	socket_set_nodelay(s);
 
 	so->so_faddr_port = sock_address_get_port(&addr);
-	
+
 	addr_ip = sock_address_get_ip(&addr);
 
 	so->so_faddr_ip = addr_ip;
@@ -559,7 +532,7 @@
  */
 
 /*	soisconnecting(so); */ /* NOFDREF used instead */
-	tcpstat.tcps_connattempt++;
+	STAT(tcpstat.tcps_connattempt++);
 
 	tp->t_state = TCPS_SYN_SENT;
 	tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
@@ -573,8 +546,7 @@
  * Attach a TCPCB to a socket.
  */
 int
-tcp_attach(so)
-	struct socket *so;
+tcp_attach(struct socket *so)
 {
 	if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
 	   return -1;
@@ -587,7 +559,7 @@
 /*
  * Set the socket's type of service field
  */
-struct tos_t tcptos[] = {
+static const struct tos_t tcptos[] = {
 	  {0, 20, IPTOS_THROUGHPUT, 0},	/* ftp data */
 	  {21, 21, IPTOS_LOWDELAY,  EMU_FTP},	/* ftp control */
 	  {0, 23, IPTOS_LOWDELAY, 0},	/* telnet */
@@ -603,15 +575,19 @@
 	  {0, 0, 0, 0}
 };
 
+#ifdef CONFIG_QEMU
+static
+#endif
+struct emu_t *tcpemu = NULL;
 
 /*
  * Return TOS according to the above table
  */
 u_int8_t
-tcp_tos(so)
-	struct socket *so;
+tcp_tos(struct socket *so)
 {
 	int i = 0;
+	struct emu_t *emup;
 
 	while(tcptos[i].tos) {
 		if ((tcptos[i].fport && so->so_faddr_port == tcptos[i].fport) ||
@@ -622,10 +598,20 @@
 		i++;
 	}
 
+	/* Nope, lets see if there's a user-added one */
+	for (emup = tcpemu; emup; emup = emup->next) {
+		if ((emup->fport && (so->so_faddr_port == emup->fport)) ||
+		    (emup->lport && (so->so_laddr_port == emup->lport))) {
+			so->so_emu = emup->emu;
+			return emup->tos;
+		}
+	}
 	return 0;
 }
 
+#if 0
 int do_echo = -1;
+#endif
 
 /*
  * Emulate programs that try and connect to us
@@ -647,17 +633,15 @@
  * in the packet before the DCC command.
  *
  * Return 1 if the mbuf m is still valid and should be
- * sbuf_append()ed
+ * sbappend()ed
  *
- * NOTE: if you return 0 you MUST mbuf_free() the mbuf!
+ * NOTE: if you return 0 you MUST m_free() the mbuf!
  */
 int
-tcp_emu(so, m)
-	struct socket *so;
-	MBuf m;
+tcp_emu(struct socket *so, struct mbuf *m)
 {
 	u_int n1, n2, n3, n4, n5, n6;
-	char buff[256];
+        char buff[257];
 	u_int32_t laddr;
 	u_int lport;
 	char *bptr;
@@ -677,14 +661,14 @@
 		{
 			struct socket *tmpso;
 			SockAddress    addr;
-			SBuf  so_rcv = &so->so_rcv;
+			struct sbuf *so_rcv = &so->so_rcv;
 
 			memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
 			so_rcv->sb_wptr += m->m_len;
 			so_rcv->sb_rptr += m->m_len;
 			m->m_data[m->m_len] = 0; /* NULL terminate */
 			if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
-				if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) {
+				if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
 					/* n2 is the one on our host */
 					for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
 						if (tmpso->so_laddr_ip == so->so_laddr_ip &&
@@ -697,21 +681,23 @@
 						}
 					}
 				}
-				so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2);
+                                so_rcv->sb_cc = snprintf(so_rcv->sb_data,
+                                                         so_rcv->sb_datalen,
+                                                         "%d,%d\r\n", n1, n2);
 				so_rcv->sb_rptr = so_rcv->sb_data;
 				so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
 			}
-			mbuf_free(m);
+			m_free(m);
 			return 0;
 		}
 
         case EMU_FTP: /* ftp */
-		*(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */
+                *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */
 		if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
 			/*
 			 * Need to emulate the PORT command
 			 */
-			x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]",
+			x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
 				   &n1, &n2, &n3, &n4, &n5, &n6, buff);
 			if (x < 6)
 			   return 1;
@@ -735,14 +721,15 @@
 			n4 =  (laddr & 0xff);
 
 			m->m_len = bptr - m->m_data; /* Adjust length */
-			m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s",
-					    n1, n2, n3, n4, n5, n6, x==7?buff:"");
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
+                                             "ORT %d,%d,%d,%d,%d,%d\r\n%s",
+                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
 			return 1;
 		} else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
 			/*
 			 * Need to emulate the PASV response
 			 */
-			x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]",
+			x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
 				   &n1, &n2, &n3, &n4, &n5, &n6, buff);
 			if (x < 6)
 			   return 1;
@@ -766,8 +753,9 @@
 			n4 =  (laddr & 0xff);
 
 			m->m_len = bptr - m->m_data; /* Adjust length */
-			m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
-					    n1, n2, n3, n4, n5, n6, x==7?buff:"");
+			m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
+                                             "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
+                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
 
 			return 1;
 		}
@@ -790,7 +778,8 @@
 		}
 		if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
 		    (so = solisten(0, so->so_laddr_ip, lport, SS_FACCEPTONCE)) != NULL)
-			m->m_len = sprintf(m->m_data, "%d", so->so_faddr_port)+1;
+			m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
+                                so->so_faddr_port) + 1;
 		return 1;
 
 	 case EMU_IRC:
@@ -807,7 +796,8 @@
 				return 1;
 
 			m->m_len = bptr - m->m_data; /* Adjust length */
-			m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n",
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC CHAT chat %lu %u%c\n",
 			     (unsigned long) so->so_faddr_ip,
 			     so->so_faddr_port, 1);
 		} else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
@@ -815,16 +805,17 @@
 				return 1;
 
 			m->m_len = bptr - m->m_data; /* Adjust length */
-			m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n",
-			      buff, (unsigned long)so->so_faddr_ip,
-			      so->so_faddr_port, n1, 1);
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC SEND %s %u %u %u%c\n", buff,
+			      so->so_faddr_ip, so->so_faddr_port, n1, 1);
 		} else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
 			if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
 				return 1;
 
 			m->m_len = bptr - m->m_data; /* Adjust length */
-			m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n",
-			      buff, (unsigned long)so->so_faddr_ip,
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC MOVE %s %lu %u %u%c\n", buff,
+			      (unsigned long)so->so_faddr_ip,
 			      so->so_faddr_port, n1, 1);
 		}
 		return 1;
@@ -842,7 +833,7 @@
 		 * A typical packet for player version 1.0 (release version):
 		 *
 		 * 0000:50 4E 41 00 05
-		 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....�..g�l�c..P
+		 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P
 		 * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
 		 * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
 		 * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
@@ -854,8 +845,8 @@
 		 *
 		 * A typical packet for player version 2.0 (beta):
 		 *
-		 * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........�.
-		 * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux�c..Win2.0.0
+		 * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á.
+		 * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0
 		 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
 		 * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
 		 * 0040:65 2E 72 61 79 53 00 00 06 36 42                e.rayS...6B
@@ -934,9 +925,9 @@
 				/* try to get udp port between 6970 - 7170 */
 				for (p = 6970; p < 7071; p++) {
 					if (udp_listen( p,
-						        so->so_laddr_ip,
-						        lport,
-						        SS_FACCEPTONCE)) {
+						       so->so_laddr_ip,
+						       lport,
+						       SS_FACCEPTONCE)) {
 						break;
 					}
 				}
@@ -968,15 +959,12 @@
  * return 2 if this is a command-line connection
  */
 int
-tcp_ctl(so)
-	struct socket *so;
+tcp_ctl(struct socket *so)
 {
-	SBuf  sb = &so->so_snd;
+	struct sbuf *sb = &so->so_snd;
 	int command;
-#if 0	
  	struct ex_list *ex_ptr;
 	int do_pty;
-#endif	
         //	struct socket *tmpso;
 
 	DEBUG_CALL("tcp_ctl");
@@ -995,16 +983,59 @@
 	command = (so->so_faddr_ip & 0xff);
 
 	switch(command) {
-	default:
+	default: /* Check for exec's */
+
+		/*
+		 * Check if it's pty_exec
+		 */
+		for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+			if (ex_ptr->ex_fport == so->so_faddr_port &&
+			    command == ex_ptr->ex_addr) {
+				if (ex_ptr->ex_pty == 3) {
+					so->s = -1;
+					so->extra = (void *)ex_ptr->ex_exec;
+					return 1;
+				}
+				do_pty = ex_ptr->ex_pty;
+				goto do_exec;
+			}
+		}
+
 		/*
 		 * Nothing bound..
 		 */
 		/* tcp_fconnect(so); */
 
+		/* FALLTHROUGH */
 	case CTL_ALIAS:
-	  sb->sb_cc = sprintf(sb->sb_wptr,
-			      "Error: No application configured.\r\n");
+          sb->sb_cc = snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
+                               "Error: No application configured.\r\n");
 	  sb->sb_wptr += sb->sb_cc;
 	  return(0);
+
+	do_exec:
+		DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
+		return(fork_exec(so, ex_ptr->ex_exec, do_pty));
+
+#if 0
+	case CTL_CMD:
+	   for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
+	     if (tmpso->so_emu == EMU_CTL &&
+		 !(tmpso->so_tcpcb?
+		   (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK))
+		   :0)) {
+	       /* Ooops, control connection already active */
+	       sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n");
+	       sb->sb_wptr += sb->sb_cc;
+	       return 0;
+	     }
+	   }
+	   so->so_emu = EMU_CTL;
+	   ctl_password_ok = 0;
+	   sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> ");
+	   sb->sb_wptr += sb->sb_cc;
+	   do_echo=-1;
+	   return(2);
+#endif
 	}
 }
diff --git a/slirp2/tcp_timer.c b/slirp-android/tcp_timer.c
similarity index 86%
rename from slirp2/tcp_timer.c
rename to slirp-android/tcp_timer.c
index ad03098..9215eb2 100644
--- a/slirp2/tcp_timer.c
+++ b/slirp-android/tcp_timer.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -36,25 +32,25 @@
 
 #include <slirp.h>
 
-int	tcp_keepidle = TCPTV_KEEP_IDLE;
-int	tcp_keepintvl = TCPTV_KEEPINTVL;
-int	tcp_maxidle;
-int	so_options = DO_KEEPALIVE;
-
+#ifdef LOG_ENABLED
 struct   tcpstat tcpstat;        /* tcp statistics */
+#endif
+
 u_int32_t        tcp_now;                /* for RFC 1323 timestamps */
 
+static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
+
 /*
  * Fast timeout routine for processing delayed acks
  */
 void
-tcp_fasttimo()
+tcp_fasttimo(void)
 {
 	register struct socket *so;
 	register struct tcpcb *tp;
 
 	DEBUG_CALL("tcp_fasttimo");
-	
+
 	so = tcb.so_next;
 	if (so)
 	for (; so != &tcb; so = so->so_next)
@@ -62,7 +58,7 @@
 		    (tp->t_flags & TF_DELACK)) {
 			tp->t_flags &= ~TF_DELACK;
 			tp->t_flags |= TF_ACKNOW;
-			tcpstat.tcps_delack++;
+			STAT(tcpstat.tcps_delack++);
 			(void) tcp_output(tp);
 		}
 }
@@ -73,15 +69,14 @@
  * causes finite state machine actions if timers expire.
  */
 void
-tcp_slowtimo()
+tcp_slowtimo(void)
 {
 	register struct socket *ip, *ipnxt;
 	register struct tcpcb *tp;
 	register int i;
 
 	DEBUG_CALL("tcp_slowtimo");
-	
-	tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
+
 	/*
 	 * Search through tcb's and update active timers.
 	 */
@@ -118,8 +113,7 @@
  * Cancel all timers for TCP tp.
  */
 void
-tcp_canceltimers(tp)
-	struct tcpcb *tp;
+tcp_canceltimers(struct tcpcb *tp)
 {
 	register int i;
 
@@ -127,21 +121,19 @@
 		tp->t_timer[i] = 0;
 }
 
-int	tcp_backoff[TCP_MAXRXTSHIFT + 1] =
+const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
    { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
 
 /*
  * TCP timer processing.
  */
-struct tcpcb *
-tcp_timers(tp, timer)
-	register struct tcpcb *tp;
-	int timer;
+static struct tcpcb *
+tcp_timers(register struct tcpcb *tp, int timer)
 {
 	register int rexmt;
-	
+
 	DEBUG_CALL("tcp_timers");
-	
+
 	switch (timer) {
 
 	/*
@@ -152,8 +144,8 @@
 	 */
 	case TCPT_2MSL:
 		if (tp->t_state != TCPS_TIME_WAIT &&
-		    tp->t_idle <= tcp_maxidle)
-			tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
+		    tp->t_idle <= TCP_MAXIDLE)
+			tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL;
 		else
 			tp = tcp_close(tp);
 		break;
@@ -164,12 +156,12 @@
 	 * to a longer retransmit interval and retransmit one segment.
 	 */
 	case TCPT_REXMT:
-		
+
 		/*
 		 * XXXXX If a packet has timed out, then remove all the queued
 		 * packets for that session.
 		 */
-		
+
 		if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
 			/*
 			 * This is a hack to suit our terminal server here at the uni of canberra
@@ -178,33 +170,33 @@
 			 * keep retransmitting it, it'll keep eating the zeroes, so we keep
 			 * retransmitting, and eventually the connection dies...
 			 * (this only happens on incoming data)
-			 * 
+			 *
 			 * So, if we were gonna drop the connection from too many retransmits,
 			 * don't... instead halve the t_maxseg, which might break up the NULLs and
 			 * let them through
-			 * 
+			 *
 			 * *sigh*
 			 */
-			
+
 			tp->t_maxseg >>= 1;
 			if (tp->t_maxseg < 32) {
 				/*
 				 * We tried our best, now the connection must die!
 				 */
 				tp->t_rxtshift = TCP_MAXRXTSHIFT;
-				tcpstat.tcps_timeoutdrop++;
+				STAT(tcpstat.tcps_timeoutdrop++);
 				tp = tcp_drop(tp, tp->t_softerror);
 				/* tp->t_softerror : ETIMEDOUT); */ /* XXX */
 				return (tp); /* XXX */
 			}
-			
+
 			/*
 			 * Set rxtshift to 6, which is still at the maximum
 			 * backoff time
 			 */
 			tp->t_rxtshift = 6;
 		}
-		tcpstat.tcps_rexmttimeo++;
+		STAT(tcpstat.tcps_rexmttimeo++);
 		rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
 		TCPT_RANGESET(tp->t_rxtcur, rexmt,
 		    (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
@@ -240,7 +232,7 @@
 		 * size increase exponentially with time.  If the
 		 * window is larger than the path can handle, this
 		 * exponential growth results in dropped packet(s)
-		 * almost immediately.  To get more time between 
+		 * almost immediately.  To get more time between
 		 * drops but still "push" the network to take advantage
 		 * of improving conditions, we switch from exponential
 		 * to linear window opening at some threshold size.
@@ -267,7 +259,7 @@
 	 * Force a byte to be output, if possible.
 	 */
 	case TCPT_PERSIST:
-		tcpstat.tcps_persisttimeo++;
+		STAT(tcpstat.tcps_persisttimeo++);
 		tcp_setpersist(tp);
 		tp->t_force = 1;
 		(void) tcp_output(tp);
@@ -279,13 +271,13 @@
 	 * or drop connection if idle for too long.
 	 */
 	case TCPT_KEEP:
-		tcpstat.tcps_keeptimeo++;
+		STAT(tcpstat.tcps_keeptimeo++);
 		if (tp->t_state < TCPS_ESTABLISHED)
 			goto dropit;
 
 /*		if (tp->t_socket->so_options & SO_KEEPALIVE && */
-		if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) {
-		    	if (tp->t_idle >= tcp_keepidle + tcp_maxidle)
+		if ((SO_OPTIONS) && tp->t_state <= TCPS_CLOSE_WAIT) {
+		    	if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
 				goto dropit;
 			/*
 			 * Send a packet designed to force a response
@@ -299,25 +291,25 @@
 			 * by the protocol spec, this requires the
 			 * correspondent TCP to respond.
 			 */
-			tcpstat.tcps_keepprobe++;
+			STAT(tcpstat.tcps_keepprobe++);
 #ifdef TCP_COMPAT_42
 			/*
 			 * The keepalive packet must have nonzero length
 			 * to get a 4.2 host to respond.
 			 */
-			tcp_respond(tp, &tp->t_template, (MBuf )NULL,
+			tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
 			    tp->rcv_nxt - 1, tp->snd_una - 1, 0);
 #else
-			tcp_respond(tp, &tp->t_template, (MBuf )NULL,
+			tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
 			    tp->rcv_nxt, tp->snd_una - 1, 0);
 #endif
-			tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
+			tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
 		} else
-			tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+			tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
 		break;
 
 	dropit:
-		tcpstat.tcps_keepdrops++;
+		STAT(tcpstat.tcps_keepdrops++);
 		tp = tcp_drop(tp, 0); /* ETIMEDOUT); */
 		break;
 	}
diff --git a/slirp2/tcp_timer.h b/slirp-android/tcp_timer.h
similarity index 89%
rename from slirp2/tcp_timer.h
rename to slirp-android/tcp_timer.h
index 59933bc..791ee49 100644
--- a/slirp2/tcp_timer.h
+++ b/slirp-android/tcp_timer.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -126,17 +122,12 @@
 		(tv) = (tvmax); \
 }
 
-extern int tcp_keepidle;		/* time before keepalive probes begin */
-extern int tcp_keepintvl;		/* time between keepalive probes */
-extern int tcp_maxidle;			/* time to drop after starting probes */
-extern int tcp_ttl;			/* time to live for TCP segs */
-extern int tcp_backoff[];
+extern const int tcp_backoff[];
 
 struct tcpcb;
 
 void tcp_fasttimo _P((void));
 void tcp_slowtimo _P((void));
 void tcp_canceltimers _P((struct tcpcb *));
-struct tcpcb * tcp_timers _P((register struct tcpcb *, int));
 
 #endif
diff --git a/slirp2/tcp_var.h b/slirp-android/tcp_var.h
similarity index 100%
rename from slirp2/tcp_var.h
rename to slirp-android/tcp_var.h
diff --git a/slirp2/tcpip.h b/slirp-android/tcpip.h
similarity index 100%
rename from slirp2/tcpip.h
rename to slirp-android/tcpip.h
diff --git a/slirp2/tftp.c b/slirp-android/tftp.c
similarity index 83%
rename from slirp2/tftp.c
rename to slirp-android/tftp.c
index 37933d9..307610b 100644
--- a/slirp2/tftp.c
+++ b/slirp-android/tftp.c
@@ -23,8 +23,7 @@
  */
 
 #include <slirp.h>
-#include <fcntl.h>
-#include <sys/stat.h>
+#include "qemu-common.h" // for pstrcpy
 
 struct tftp_session {
     int in_use;
@@ -36,7 +35,7 @@
     int timestamp;
 };
 
-struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
+static struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
 
 const char *tftp_prefix;
 
@@ -89,9 +88,9 @@
 
     if (spt->in_use) {
       if (spt->client_ip == ip_geth(tp->ip.ip_src)) {
-	if (spt->client_port == port_geth(tp->udp.uh_sport)) {
-	  return k;
-	}
+		if (spt->client_port == port_geth(tp->udp.uh_sport)) {
+		  return k;
+		}
       }
     }
   }
@@ -108,9 +107,9 @@
   int n;
 
   n = snprintf(buffer, sizeof(buffer), "%s/%s",
-               tftp_prefix, spt->filename);
+	       tftp_prefix, spt->filename);
   if (n >= sizeof(buffer))
-      return -1;
+    return -1;
 
   fd = open(buffer, O_RDONLY | O_BINARY);
 
@@ -134,24 +133,26 @@
                           struct tftp_t *recv_tp)
 {
     SockAddress  saddr, daddr;
-    MBuf m;
+    struct mbuf *m;
     struct tftp_t *tp;
     int n = 0;
 
-    m = mbuf_alloc();
+    m = m_get();
 
     if (!m)
-        return -1;
+	return -1;
 
     memset(m->m_data, 0, m->m_size);
 
-    m->m_data += if_maxlinkhdr;
+    m->m_data += IF_MAXLINKHDR;
     tp = (void *)m->m_data;
     m->m_data += sizeof(struct udpiphdr);
 
     tp->tp_op = htons(TFTP_OACK);
-    n += sprintf((char*)tp->x.tp_buf + n, "%s", key) + 1;
-    n += sprintf((char*)tp->x.tp_buf + n, "%u", value) + 1;
+    n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
+                  key) + 1;
+    n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
+                  value) + 1;
 
     sock_address_init_inet( &saddr,
                             ip_geth(recv_tp->ip.ip_dst),
@@ -162,7 +163,7 @@
                             spt->client_port );
 
     m->m_len = sizeof(struct tftp_t) - 514 + n -
-            sizeof(struct ip) - sizeof(struct udphdr);
+        sizeof(struct ip) - sizeof(struct udphdr);
     udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 
     return 0;
@@ -175,11 +176,11 @@
 			   struct tftp_t *recv_tp)
 {
   SockAddress saddr, daddr;
-  MBuf m;
+  struct mbuf *m;
   struct tftp_t *tp;
   int nobytes;
 
-  m = mbuf_alloc();
+  m = m_get();
 
   if (!m) {
     return -1;
@@ -187,13 +188,13 @@
 
   memset(m->m_data, 0, m->m_size);
 
-  m->m_data += if_maxlinkhdr;
+  m->m_data += IF_MAXLINKHDR;
   tp = (void *)m->m_data;
   m->m_data += sizeof(struct udpiphdr);
 
   tp->tp_op = htons(TFTP_ERROR);
   tp->x.tp_error.tp_error_code = htons(errorcode);
-  strcpy((char*)tp->x.tp_error.tp_msg, msg);
+  pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
 
   sock_address_init_inet( &saddr,
                           ip_geth(recv_tp->ip.ip_dst),
@@ -220,7 +221,7 @@
 			  struct tftp_t *recv_tp)
 {
   SockAddress saddr, daddr;
-  MBuf m;
+  struct mbuf *m;
   struct tftp_t *tp;
   int nobytes;
 
@@ -228,7 +229,7 @@
     return -1;
   }
 
-  m = mbuf_alloc();
+  m = m_get();
 
   if (!m) {
     return -1;
@@ -236,7 +237,7 @@
 
   memset(m->m_data, 0, m->m_size);
 
-  m->m_data += if_maxlinkhdr;
+  m->m_data += IF_MAXLINKHDR;
   tp = (void *)m->m_data;
   m->m_data += sizeof(struct udpiphdr);
 
@@ -254,7 +255,7 @@
   nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
 
   if (nobytes < 0) {
-    mbuf_free(m);
+    m_free(m);
 
     /* send "file not found" error back */
 
@@ -327,13 +328,13 @@
       return;
   }
 
-  k += 6;  /* skipping octet */
+  k += 6; /* skipping octet */
 
   /* do sanity checks on the filename */
 
   if ((spt->filename[0] != '/')
-      || (spt->filename[strlen((const char*)spt->filename) - 1] == '/')
-      ||  strstr((const char*)spt->filename, "/../")) {
+      || (spt->filename[strlen((char *)spt->filename) - 1] == '/')
+      ||  strstr((char *)spt->filename, "/../")) {
       tftp_send_error(spt, 2, "Access violation", tp);
       return;
   }
@@ -360,37 +361,37 @@
   while (k < n) {
       const char *key, *value;
 
-      key = (const char*)src + k;
+      key = (char *)src + k;
       k += strlen(key) + 1;
 
       if (k >= n) {
-          tftp_send_error(spt, 2, "Access violation", tp);
-          return;
+	  tftp_send_error(spt, 2, "Access violation", tp);
+	  return;
       }
 
-      value = (const char*)src + k;
+      value = (char *)src + k;
       k += strlen(value) + 1;
 
       if (strcmp(key, "tsize") == 0) {
-          int tsize = atoi(value);
-          struct stat stat_p;
+	  int tsize = atoi(value);
+	  struct stat stat_p;
 
-          if (tsize == 0 && tftp_prefix) {
-              char buffer[1024];
-              int len;
+	  if (tsize == 0 && tftp_prefix) {
+	      char buffer[1024];
+	      int len;
 
-              len = snprintf(buffer, sizeof(buffer), "%s/%s",
-                             tftp_prefix, spt->filename);
+	      len = snprintf(buffer, sizeof(buffer), "%s/%s",
+			     tftp_prefix, spt->filename);
 
-              if (stat(buffer, &stat_p) == 0)
-                  tsize = stat_p.st_size;
-              else {
-                  tftp_send_error(spt, 1, "File not found", tp);
-                  return;
-              }
-          }
+	      if (stat(buffer, &stat_p) == 0)
+		  tsize = stat_p.st_size;
+	      else {
+		  tftp_send_error(spt, 1, "File not found", tp);
+		  return;
+	      }
+	  }
 
-          tftp_send_oack(spt, "tsize", tsize, tp);
+	  tftp_send_oack(spt, "tsize", tsize, tp);
       }
   }
 
@@ -414,7 +415,7 @@
   }
 }
 
-void tftp_input(MBuf m)
+void tftp_input(struct mbuf *m)
 {
   struct tftp_t *tp = (struct tftp_t *)m->m_data;
 
diff --git a/slirp2/tftp.h b/slirp-android/tftp.h
similarity index 89%
rename from slirp2/tftp.h
rename to slirp-android/tftp.h
index 06018a7..8f2675e 100644
--- a/slirp2/tftp.h
+++ b/slirp-android/tftp.h
@@ -18,11 +18,11 @@
   struct udphdr udp;
   u_int16_t tp_op;
   union {
-    struct { 
+    struct {
       u_int16_t tp_block_nr;
       u_int8_t tp_buf[512];
     } tp_data;
-    struct { 
+    struct {
       u_int16_t tp_error_code;
       u_int8_t tp_msg[512];
     } tp_error;
@@ -30,4 +30,4 @@
   } x;
 };
 
-void tftp_input(MBuf m);
+void tftp_input(struct mbuf *m);
diff --git a/slirp2/udp.c b/slirp-android/udp.c
similarity index 76%
rename from slirp2/udp.c
rename to slirp-android/udp.c
index 9305cfd..9091505 100644
--- a/slirp2/udp.c
+++ b/slirp-android/udp.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -47,24 +43,29 @@
 #define SLIRP_COMPILATION  1
 #include "sockets.h"
 
+#ifdef LOG_ENABLED
 struct udpstat udpstat;
+#endif
 
 struct socket udb;
 
+static u_int8_t udp_tos(struct socket *so);
+static void udp_emu(struct socket *so, struct mbuf *m);
+
 /*
  * UDP protocol implementation.
  * Per RFC 768, August, 1980.
  */
 #ifndef	COMPAT_42
-int	udpcksum = 1;
+#define UDPCKSUM 1
 #else
-int	udpcksum = 0;		/* XXX */
+#define UDPCKSUM 0 /* XXX */
 #endif
 
 struct	socket *udp_last_so = &udb;
 
 void
-udp_init()
+udp_init(void)
 {
 	udb.so_next = udb.so_prev = &udb;
 }
@@ -73,13 +74,11 @@
  * ip->ip_len length data (IPDU)
  */
 void
-udp_input(m, iphlen)
-	register MBuf m;
-	int iphlen;
+udp_input(register struct mbuf *m, int iphlen)
 {
 	register struct ip *ip;
 	register struct udphdr *uh;
-/*	MBuf opts = 0;*/
+/*	struct mbuf *opts = 0;*/
 	int len;
 	struct ip save_ip;
 	struct socket *so;
@@ -88,7 +87,7 @@
 	DEBUG_ARG("m = %lx", (long)m);
 	DEBUG_ARG("iphlen = %d", iphlen);
 
-	udpstat.udps_ipackets++;
+	STAT(udpstat.udps_ipackets++);
 
 	/*
 	 * Strip IP options, if any; should skip this,
@@ -97,14 +96,14 @@
 	 * with options still present.
 	 */
 	if(iphlen > sizeof(struct ip)) {
-		ip_stripoptions(m, (MBuf )0);
+		ip_stripoptions(m, (struct mbuf *)0);
 		iphlen = sizeof(struct ip);
 	}
 
 	/*
 	 * Get IP and UDP header together in first mbuf.
 	 */
-	ip = MBUF_TO(m, struct ip *);
+	ip = mtod(m, struct ip *);
 	uh = (struct udphdr *)((caddr_t)ip + iphlen);
 
 	/*
@@ -115,10 +114,10 @@
 
 	if (ip->ip_len != len) {
 		if (len > ip->ip_len) {
-			udpstat.udps_badlen++;
+			STAT(udpstat.udps_badlen++);
 			goto bad;
 		}
-		mbuf_trim(m, len - ip->ip_len);
+		m_adj(m, len - ip->ip_len);
 		ip->ip_len = len;
 	}
 
@@ -132,8 +131,8 @@
 	/*
 	 * Checksum extended UDP header and data.
 	 */
-	if (udpcksum && uh->uh_sum) {
-	  memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
+	if (UDPCKSUM && uh->uh_sum) {
+      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
 	  ((struct ipovly *)ip)->ih_x1 = 0;
 	  ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
 	  /* keep uh_sum for ICMP reply
@@ -141,7 +140,7 @@
 	   * if (uh->uh_sum) {
 	   */
 	  if(cksum(m, len + sizeof(struct ip))) {
-	    udpstat.udps_badsum++;
+	    STAT(udpstat.udps_badsum++);
 	    goto bad;
 	  }
 	}
@@ -154,6 +153,9 @@
             goto bad;
         }
 
+        if (slirp_restrict)
+            goto bad;
+
         /*
          *  handle TFTP
          */
@@ -182,7 +184,7 @@
 		if (tmp == &udb) {
 		  so = NULL;
 		} else {
-		  udpstat.udpps_pcbcachemiss++;
+		  STAT(udpstat.udpps_pcbcachemiss++);
 		  udp_last_so = so;
 		}
 	}
@@ -219,7 +221,7 @@
         so->so_faddr_ip   = ip_geth(ip->ip_dst); /* XXX */
         so->so_faddr_port = port_geth(uh->uh_dport); /* XXX */
 
-        iphlen += sizeof(struct udphdr);
+	iphlen += sizeof(struct udphdr);
 	m->m_len -= iphlen;
 	m->m_data += iphlen;
 
@@ -237,7 +239,7 @@
 	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,errno_str);
 	}
 
-	mbuf_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
+	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
 
 	/* restore the orig mbuf packet */
 	m->m_len += iphlen;
@@ -247,15 +249,15 @@
 
 	return;
 bad:
-	mbuf_free(m);
-	/* if (opts) mbuf_free(opts); */
+	m_freem(m);
+	/* if (opts) m_freem(opts); */
 	return;
 }
 
-int udp_output2_(struct socket*  so, MBuf  m, 
+int udp_output2_(struct socket *so, struct mbuf *m,
                  const SockAddress*  saddr, 
                  const SockAddress*  daddr,
-                 int  iptos)
+                 int iptos)
 {
     register struct udpiphdr *ui;
     uint32_t  saddr_ip = sock_address_get_ip(saddr);
@@ -265,54 +267,55 @@
     int error = 0;
 
     DEBUG_CALL("udp_output");
-    DEBUG_ARG("so = %lx", (long)so);
-    DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("m = %lx", (long)m);
     DEBUG_ARG("saddr = %lx", (long) saddr_ip);
     DEBUG_ARG("daddr = %lx", (long) daddr_ip);
 
-    /*
-        * Adjust for header
-        */
-    m->m_data -= sizeof(struct udpiphdr);
-    m->m_len  += sizeof(struct udpiphdr);
+	/*
+	 * Adjust for header
+	 */
+	m->m_data -= sizeof(struct udpiphdr);
+	m->m_len += sizeof(struct udpiphdr);
 
-    /*
-        * Fill in mbuf with extended UDP header
-        * and addresses and length put into network format.
-        */
-    ui = MBUF_TO(m, struct udpiphdr *);
+	/*
+	 * Fill in mbuf with extended UDP header
+	 * and addresses and length put into network format.
+	 */
+	ui = mtod(m, struct udpiphdr *);
     memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
-    ui->ui_x1 = 0;
-    ui->ui_pr = IPPROTO_UDP;
-    ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
-    /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
+	ui->ui_x1 = 0;
+	ui->ui_pr = IPPROTO_UDP;
+	ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
+	/* XXXXX Check for from-one-location sockets, or from-any-location sockets */
     ui->ui_src   = ip_seth(saddr_ip);
     ui->ui_dst   = ip_seth(daddr_ip);
     ui->ui_sport = port_seth(saddr_port);
     ui->ui_dport = port_seth(daddr_port);
-    ui->ui_ulen = ui->ui_len;
+	ui->ui_ulen = ui->ui_len;
 
-    /*
-        * Stuff checksum and output datagram.
-        */
-    ui->ui_sum = 0;
-    if (udpcksum) {
-        if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
-            ui->ui_sum = 0xffff;
-    }
-    ((struct ip *)ui)->ip_len = m->m_len;
+	/*
+	 * Stuff checksum and output datagram.
+	 */
+	ui->ui_sum = 0;
+	if (UDPCKSUM) {
+	    if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
+		ui->ui_sum = 0xffff;
+	}
+	((struct ip *)ui)->ip_len = m->m_len;
 
-    ((struct ip *)ui)->ip_ttl = ip_defttl;
-    ((struct ip *)ui)->ip_tos = iptos;
+	((struct ip *)ui)->ip_ttl = IPDEFTTL;
+	((struct ip *)ui)->ip_tos = iptos;
 
-    udpstat.udps_opackets++;
+	STAT(udpstat.udps_opackets++);
 
-    error = ip_output(so, m);
+	error = ip_output(so, m);
 
-    return (error);
+	return (error);
 }
 
-int udp_output_(struct socket *so, MBuf m, SockAddress* from)
+int udp_output_(struct socket *so, struct mbuf *m,
+               SockAddress* from)
 {
     SockAddress  saddr, daddr;
     uint32_t     saddr_ip;
@@ -334,8 +337,7 @@
 }
 
 int
-udp_attach(so)
-     struct socket *so;
+udp_attach(struct socket *so)
 {
   so->s = socket_anyaddr_server( 0, SOCKET_DGRAM );
   if (so->s != -1) {
@@ -347,16 +349,15 @@
 }
 
 void
-udp_detach(so)
-	struct socket *so;
+udp_detach(struct socket *so)
 {
 	socket_close(so->s);
-	/* if (so->so_m) mbuf_free(so->so_m);    done by sofree */
+	/* if (so->so_m) m_free(so->so_m);    done by sofree */
 
 	sofree(so);
 }
 
-struct tos_t udptos[] = {
+static const struct tos_t udptos[] = {
 	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
 	{517, 517, IPTOS_LOWDELAY, EMU_TALK},	/* talk */
 	{518, 518, IPTOS_LOWDELAY, EMU_NTALK},	/* ntalk */
@@ -364,9 +365,8 @@
 	{0, 0, 0, 0}
 };
 
-u_int8_t
-udp_tos(so)
-	struct socket *so;
+static u_int8_t
+udp_tos(struct socket *so)
 {
 	int i = 0;
 
@@ -382,13 +382,12 @@
 	return 0;
 }
 
+
 /*
  * Here, talk/ytalk/ntalk requests must be emulated
  */
-void
-udp_emu(so, m)
-	struct socket *so;
-	MBuf m;
+static void
+udp_emu(struct socket *so, struct mbuf *m)
 {
         SockAddress  sockaddr;
 
@@ -419,7 +418,7 @@
 			if (socket_get_address(so->s, &sockaddr) < 0)
                             return;
 
-			cu_head = MBUF_TO(m, struct cu_header *);
+			cu_head = mtod(m, struct cu_header *);
 			cu_head->s_port  = htons( sock_address_get_port(&sockaddr));
 			cu_head->so_addr = htonl( sock_address_get_ip(&sockaddr));
 		}
@@ -429,11 +428,7 @@
 }
 
 struct socket *
-udp_listen(port, laddr, lport, flags)
-	u_int port;
-	u_int32_t laddr;
-	u_int lport;
-	int flags;
+udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
 {
 	struct socket *so;
 	SockAddress    addr;
@@ -445,7 +440,7 @@
 	}
 	so->s = socket_anyaddr_server( port, SOCKET_DGRAM );
 	so->so_expire = curtime + SO_EXPIRE;
-        so->so_haddr_port = port;
+    so->so_haddr_port = port;
 	insque(so,&udb);
 
 	if (so->s < 0) {
@@ -475,21 +470,5 @@
 
 int udp_unlisten (u_int port)
 {
-    struct socket *so;
-
-    for (so = udb.so_next; so != &udb; so = so->so_next) {
-        if (so->so_haddr_port == port) {
-            break;
-        }
-    }
-
-    if (so == &udb)
-        return -1;
-
-    sofcantrcvmore( so );
-    sofcantsendmore( so );
-    socket_close( so->s );
-    so->s = -1;
-    sofree( so );
-    return 0;
+	return slirp_unredir(1, port);
 }
diff --git a/slirp2/udp.h b/slirp-android/udp.h
similarity index 85%
rename from slirp2/udp.h
rename to slirp-android/udp.h
index cadd17e..4350ec3 100644
--- a/slirp2/udp.h
+++ b/slirp-android/udp.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -73,6 +69,7 @@
 #define ui_ulen         ui_u.uh_ulen
 #define ui_sum          ui_u.uh_sum
 
+#ifdef LOG_ENABLED
 struct udpstat {
 	                                /* input statistics: */
 	        u_long  udps_ipackets;          /* total input packets */
@@ -86,6 +83,7 @@
 	                                /* output statistics: */
 	        u_long  udps_opackets;          /* total output packets */
 };
+#endif
 
 /*
  * Names for UDP sysctl objects
@@ -93,23 +91,22 @@
 #define UDPCTL_CHECKSUM         1       /* checksum UDP packets */
 #define UDPCTL_MAXID            2
 
+#ifdef LOG_ENABLED
 extern struct udpstat udpstat;
+#endif
+
 extern struct socket udb;
 struct mbuf;
 
 void udp_init _P((void));
-void udp_input _P((register MBuf , int));
+void udp_input _P((register struct mbuf *, int));
+int udp_output_ _P((struct socket *, struct mbuf *, SockAddress *));
 int udp_attach _P((struct socket *));
 void udp_detach _P((struct socket *));
-u_int8_t udp_tos _P((struct socket *));
-void udp_emu _P((struct socket *, MBuf ));
 struct socket * udp_listen _P((u_int, u_int32_t, u_int, int));
 int udp_unlisten _P((u_int));
 
-int udp_output_(struct socket *, MBuf, SockAddress*);
-
-int udp_output2_(struct socket*  so, MBuf  m,
-                 const SockAddress*  saddr, const SockAddress*  daddr,
-                 int  iptos);
-
+int udp_output2_(struct socket *so, struct mbuf *m,
+                const SockAddress *saddr, const SockAddress *daddr,
+                int iptos);
 #endif
diff --git a/slirp2/COPYRIGHT b/slirp/COPYRIGHT
similarity index 93%
copy from slirp2/COPYRIGHT
copy to slirp/COPYRIGHT
index 2e86862..1bc83d4 100644
--- a/slirp2/COPYRIGHT
+++ b/slirp/COPYRIGHT
@@ -16,7 +16,7 @@
 ---BEGIN---
 
  Copyright (c) 1995,1996 Danny Gasparovski.  All rights reserved.
- 
+
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:
@@ -25,9 +25,6 @@
  2. Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
- 3. All advertising materials mentioning features or use of this software
-    must display the following acknowledgment:
-      This product includes software developed by Danny Gasparovski.
 
  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
diff --git a/slirp/bootp.c b/slirp/bootp.c
new file mode 100644
index 0000000..4e0082d
--- /dev/null
+++ b/slirp/bootp.c
@@ -0,0 +1,326 @@
+/*
+ * QEMU BOOTP/DHCP server
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <slirp.h>
+
+/* XXX: only DHCP is supported */
+
+#define NB_ADDR 16
+
+#define START_ADDR 15
+
+#define LEASE_TIME (24 * 3600)
+
+typedef struct {
+    uint8_t allocated;
+    uint8_t macaddr[6];
+} BOOTPClient;
+
+static BOOTPClient bootp_clients[NB_ADDR];
+
+const char *bootp_filename;
+
+static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
+
+#ifdef DEBUG
+#define dprintf(fmt, ...) \
+if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ##  __VA_ARGS__); fflush(dfd); }
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static BOOTPClient *get_new_addr(struct in_addr *paddr,
+                                 const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_ADDR; i++) {
+        bc = &bootp_clients[i];
+        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &bootp_clients[i];
+    bc->allocated = 1;
+    paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
+    return bc;
+}
+
+static BOOTPClient *request_addr(const struct in_addr *paddr,
+                                 const uint8_t *macaddr)
+{
+    uint32_t req_addr = ntohl(paddr->s_addr);
+    uint32_t spec_addr = ntohl(special_addr.s_addr);
+    BOOTPClient *bc;
+
+    if (req_addr >= (spec_addr | START_ADDR) &&
+        req_addr < (spec_addr | (NB_ADDR + START_ADDR))) {
+        bc = &bootp_clients[(req_addr & 0xff) - START_ADDR];
+        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
+            bc->allocated = 1;
+            return bc;
+        }
+    }
+    return NULL;
+}
+
+static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
+{
+    BOOTPClient *bc;
+    int i;
+
+    for(i = 0; i < NB_ADDR; i++) {
+        if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
+            goto found;
+    }
+    return NULL;
+ found:
+    bc = &bootp_clients[i];
+    bc->allocated = 1;
+    paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
+    return bc;
+}
+
+static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
+                        const struct in_addr **preq_addr)
+{
+    const uint8_t *p, *p_end;
+    int len, tag;
+
+    *pmsg_type = 0;
+    *preq_addr = NULL;
+
+    p = bp->bp_vend;
+    p_end = p + DHCP_OPT_LEN;
+    if (memcmp(p, rfc1533_cookie, 4) != 0)
+        return;
+    p += 4;
+    while (p < p_end) {
+        tag = p[0];
+        if (tag == RFC1533_PAD) {
+            p++;
+        } else if (tag == RFC1533_END) {
+            break;
+        } else {
+            p++;
+            if (p >= p_end)
+                break;
+            len = *p++;
+            dprintf("dhcp: tag=%d len=%d\n", tag, len);
+
+            switch(tag) {
+            case RFC2132_MSG_TYPE:
+                if (len >= 1)
+                    *pmsg_type = p[0];
+                break;
+            case RFC2132_REQ_ADDR:
+                if (len >= 4)
+                    *preq_addr = (struct in_addr *)p;
+                break;
+            default:
+                break;
+            }
+            p += len;
+        }
+    }
+    if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr.s_addr) {
+        *preq_addr = &bp->bp_ciaddr;
+    }
+}
+
+static void bootp_reply(const struct bootp_t *bp)
+{
+    BOOTPClient *bc = NULL;
+    struct mbuf *m;
+    struct bootp_t *rbp;
+    struct sockaddr_in saddr, daddr;
+    struct in_addr dns_addr;
+    const struct in_addr *preq_addr;
+    int dhcp_msg_type, val;
+    uint8_t *q;
+
+    /* extract exact DHCP msg type */
+    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
+    dprintf("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
+    if (preq_addr)
+        dprintf(" req_addr=%08x\n", ntohl(preq_addr->s_addr));
+    else
+        dprintf("\n");
+
+    if (dhcp_msg_type == 0)
+        dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
+
+    if (dhcp_msg_type != DHCPDISCOVER &&
+        dhcp_msg_type != DHCPREQUEST)
+        return;
+    /* XXX: this is a hack to get the client mac address */
+    memcpy(client_ethaddr, bp->bp_hwaddr, 6);
+
+    if ((m = m_get()) == NULL)
+        return;
+    m->m_data += IF_MAXLINKHDR;
+    rbp = (struct bootp_t *)m->m_data;
+    m->m_data += sizeof(struct udpiphdr);
+    memset(rbp, 0, sizeof(struct bootp_t));
+
+    if (dhcp_msg_type == DHCPDISCOVER) {
+        if (preq_addr) {
+            bc = request_addr(preq_addr, client_ethaddr);
+            if (bc) {
+                daddr.sin_addr = *preq_addr;
+            }
+        }
+        if (!bc) {
+         new_addr:
+            bc = get_new_addr(&daddr.sin_addr, client_ethaddr);
+            if (!bc) {
+                dprintf("no address left\n");
+                return;
+            }
+        }
+        memcpy(bc->macaddr, client_ethaddr, 6);
+    } else if (preq_addr) {
+        bc = request_addr(preq_addr, client_ethaddr);
+        if (bc) {
+            daddr.sin_addr = *preq_addr;
+            memcpy(bc->macaddr, client_ethaddr, 6);
+        } else {
+            daddr.sin_addr.s_addr = 0;
+        }
+    } else {
+        bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
+        if (!bc) {
+            /* if never assigned, behaves as if it was already
+               assigned (windows fix because it remembers its address) */
+            goto new_addr;
+        }
+    }
+
+    saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
+    saddr.sin_port = htons(BOOTP_SERVER);
+
+    daddr.sin_port = htons(BOOTP_CLIENT);
+
+    rbp->bp_op = BOOTP_REPLY;
+    rbp->bp_xid = bp->bp_xid;
+    rbp->bp_htype = 1;
+    rbp->bp_hlen = 6;
+    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
+
+    rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
+    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
+
+    q = rbp->bp_vend;
+    memcpy(q, rfc1533_cookie, 4);
+    q += 4;
+
+    if (bc) {
+        dprintf("%s addr=%08x\n",
+                (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
+                ntohl(daddr.sin_addr.s_addr));
+
+        if (dhcp_msg_type == DHCPDISCOVER) {
+            *q++ = RFC2132_MSG_TYPE;
+            *q++ = 1;
+            *q++ = DHCPOFFER;
+        } else /* DHCPREQUEST */ {
+            *q++ = RFC2132_MSG_TYPE;
+            *q++ = 1;
+            *q++ = DHCPACK;
+        }
+
+        if (bootp_filename)
+            snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
+                     bootp_filename);
+
+        *q++ = RFC2132_SRV_ID;
+        *q++ = 4;
+        memcpy(q, &saddr.sin_addr, 4);
+        q += 4;
+
+        *q++ = RFC1533_NETMASK;
+        *q++ = 4;
+        *q++ = 0xff;
+        *q++ = 0xff;
+        *q++ = 0xff;
+        *q++ = 0x00;
+
+        if (!slirp_restrict) {
+            *q++ = RFC1533_GATEWAY;
+            *q++ = 4;
+            memcpy(q, &saddr.sin_addr, 4);
+            q += 4;
+
+            *q++ = RFC1533_DNS;
+            *q++ = 4;
+            dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
+            memcpy(q, &dns_addr, 4);
+            q += 4;
+        }
+
+        *q++ = RFC2132_LEASE_TIME;
+        *q++ = 4;
+        val = htonl(LEASE_TIME);
+        memcpy(q, &val, 4);
+        q += 4;
+
+        if (*slirp_hostname) {
+            val = strlen(slirp_hostname);
+            *q++ = RFC1533_HOSTNAME;
+            *q++ = val;
+            memcpy(q, slirp_hostname, val);
+            q += val;
+        }
+    } else {
+        static const char nak_msg[] = "requested address not available";
+
+        dprintf("nak'ed addr=%08x\n", ntohl(preq_addr->s_addr));
+
+        *q++ = RFC2132_MSG_TYPE;
+        *q++ = 1;
+        *q++ = DHCPNAK;
+
+        *q++ = RFC2132_MESSAGE;
+        *q++ = sizeof(nak_msg) - 1;
+        memcpy(q, nak_msg, sizeof(nak_msg) - 1);
+        q += sizeof(nak_msg) - 1;
+    }
+    *q++ = RFC1533_END;
+
+    daddr.sin_addr.s_addr = 0xffffffffu;
+
+    m->m_len = sizeof(struct bootp_t) -
+        sizeof(struct ip) - sizeof(struct udphdr);
+    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+}
+
+void bootp_input(struct mbuf *m)
+{
+    struct bootp_t *bp = mtod(m, struct bootp_t *);
+
+    if (bp->bp_op == BOOTP_REQUEST) {
+        bootp_reply(bp);
+    }
+}
diff --git a/slirp2/bootp.h b/slirp/bootp.h
similarity index 93%
copy from slirp2/bootp.h
copy to slirp/bootp.h
index fbc96ac..3d80515 100644
--- a/slirp2/bootp.h
+++ b/slirp/bootp.h
@@ -63,6 +63,7 @@
 #define RFC2132_MSG_TYPE	53
 #define RFC2132_SRV_ID		54
 #define RFC2132_PARAM_LIST	55
+#define RFC2132_MESSAGE		56
 #define RFC2132_MAX_SIZE	57
 #define RFC2132_RENEWAL_TIME    58
 #define RFC2132_REBIND_TIME     59
@@ -71,6 +72,7 @@
 #define DHCPOFFER		2
 #define DHCPREQUEST		3
 #define DHCPACK			5
+#define DHCPNAK			6
 
 #define RFC1533_VENDOR_MAJOR	0
 #define RFC1533_VENDOR_MINOR	0
@@ -100,14 +102,14 @@
     uint32_t bp_xid;
     uint16_t bp_secs;
     uint16_t unused;
-    uint32_t bp_ciaddr;
-    uint32_t bp_yiaddr;
-    uint32_t bp_siaddr;
-    uint32_t bp_giaddr;
+    struct in_addr bp_ciaddr;
+    struct in_addr bp_yiaddr;
+    struct in_addr bp_siaddr;
+    struct in_addr bp_giaddr;
     uint8_t bp_hwaddr[16];
     uint8_t bp_sname[64];
     uint8_t bp_file[128];
     uint8_t bp_vend[DHCP_OPT_LEN];
 };
 
-void bootp_input(MBuf m);
+void bootp_input(struct mbuf *m);
diff --git a/slirp2/cksum.c b/slirp/cksum.c
similarity index 90%
copy from slirp2/cksum.c
copy to slirp/cksum.c
index 9474b9e..34977ff 100644
--- a/slirp2/cksum.c
+++ b/slirp/cksum.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -41,14 +37,14 @@
  *
  * This routine is very heavily used in the network
  * code and should be modified for each CPU to be as fast as possible.
- * 
+ *
  * XXX Since we will never span more than 1 mbuf, we can optimise this
  */
 
 #define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
 #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
 
-int cksum(MBuf m, int len)
+int cksum(struct mbuf *m, int len)
 {
 	register u_int16_t *w;
 	register int sum = 0;
@@ -63,13 +59,13 @@
 		u_int16_t s[2];
 		u_int32_t l;
 	} l_util;
-	
+
 	if (m->m_len == 0)
 	   goto cont;
-	w = MBUF_TO(m, u_int16_t *);
-	
+	w = mtod(m, u_int16_t *);
+
 	mlen = m->m_len;
-	
+
 	if (len < mlen)
 	   mlen = len;
 	len -= mlen;
@@ -107,7 +103,7 @@
 	while ((mlen -= 2) >= 0) {
 		sum += *w++;
 	}
-	
+
 	if (byte_swapped) {
 		REDUCE;
 		sum <<= 8;
@@ -117,11 +113,11 @@
 			sum += s_util.s;
 			mlen = 0;
 		} else
-		   
+
 		   mlen = -1;
 	} else if (mlen == -1)
 	   s_util.c[0] = *(u_int8_t *)w;
-	
+
 cont:
 #ifdef DEBUG
 	if (len) {
diff --git a/slirp/ctl.h b/slirp/ctl.h
new file mode 100644
index 0000000..4a8576d
--- /dev/null
+++ b/slirp/ctl.h
@@ -0,0 +1,7 @@
+#define CTL_CMD		0
+#define CTL_EXEC	1
+#define CTL_ALIAS	2
+#define CTL_DNS		3
+
+#define CTL_SPECIAL	"10.0.2.0"
+#define CTL_LOCAL	"10.0.2.15"
diff --git a/slirp2/debug.c b/slirp/debug.c
similarity index 86%
copy from slirp2/debug.c
copy to slirp/debug.c
index f3a424d..bfef580 100644
--- a/slirp2/debug.c
+++ b/slirp/debug.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
  * Portions copyright (c) 2000 Kelly Price.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -16,10 +16,9 @@
 #endif
 int slirp_debug = 0;
 
-extern char *strerror _P((int));
-
-/* Carry over one item from main.c so that the tty's restored. 
+/* Carry over one item from main.c so that the tty's restored.
  * Only done when the tty being used is /dev/tty --RedWolf */
+#ifndef CONFIG_QEMU
 extern struct termios slirp_tty_settings;
 extern int slirp_tty_restore;
 
@@ -32,7 +31,7 @@
 	/* Close the old debugging file */
 	if (dfd)
 	   fclose(dfd);
-	
+
 	dfd = fopen(file,"w");
 	if (dfd != NULL) {
 #if 0
@@ -42,7 +41,7 @@
 		fflush(dfd);
 		slirp_debug = dbg;
 	} else {
-		fprintf(stderr, "Error: Debugging file \"%s\" could not be opened: %s\r\n",
+		lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n",
 			file, strerror(errno));
 	}
 }
@@ -58,7 +57,7 @@
 {
 	u_char *pptr = (u_char *)dat;
 	int j,k;
-	
+
 	n /= 16;
 	n++;
 	DEBUG_MISC((dfd, "PACKET DUMPED: \n"));
@@ -70,28 +69,30 @@
 	}
 }
 #endif
+#endif
 
+#ifdef LOG_ENABLED
 #if 0
 /*
  * Statistic routines
- * 
+ *
  * These will print statistics to the screen, the debug file (dfd), or
  * a buffer, depending on "type", so that the stats can be sent over
  * the link as well.
  */
 
-void
+static void
 ttystats(ttyp)
 	struct ttys *ttyp;
 {
 	struct slirp_ifstats *is = &ttyp->ifstats;
 	char buff[512];
-	
+
 	lprint(" \r\n");
-	
-	if (if_comp & IF_COMPRESS)
+
+	if (IF_COMP & IF_COMPRESS)
 	   strcpy(buff, "on");
-	else if (if_comp & IF_NOCOMPRESS)
+	else if (IF_COMP & IF_NOCOMPRESS)
 	   strcpy(buff, "off");
 	else
 	   strcpy(buff, "off (for now)");
@@ -119,20 +120,20 @@
 	lprint("  %6d bad input packets\r\n", is->in_mbad);
 }
 
-void
-allttystats()
+static void
+allttystats(void)
 {
 	struct ttys *ttyp;
-	
+
 	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
 	   ttystats(ttyp);
 }
 #endif
 
-void
-ipstats()
+static void
+ipstats(void)
 {
-	lprint(" \r\n");	
+	lprint(" \r\n");
 
 	lprint("IP stats:\r\n");
 	lprint("  %6d total packets received (%d were unaligned)\r\n",
@@ -153,14 +154,14 @@
 	lprint("  %6d total packets delivered\r\n", ipstat.ips_delivered);
 }
 
-#if 0
-void
-vjstats()
+#ifndef CONFIG_QEMU
+static void
+vjstats(void)
 {
 	lprint(" \r\n");
-	
+
 	lprint("VJ compression stats:\r\n");
-	
+
 	lprint("  %6d outbound packets (%d compressed)\r\n",
 	       comp_s.sls_packets, comp_s.sls_compressed);
 	lprint("  %6d searches for connection stats (%d misses)\r\n",
@@ -172,13 +173,13 @@
 }
 #endif
 
-void
-tcpstats()
+static void
+tcpstats(void)
 {
 	lprint(" \r\n");
 
 	lprint("TCP stats:\r\n");
-	
+
 	lprint("  %6d packets sent\r\n", tcpstat.tcps_sndtotal);
 	lprint("          %6d data packets (%d bytes)\r\n",
 			tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte);
@@ -191,8 +192,8 @@
 	lprint("          %6d window update packets\r\n", tcpstat.tcps_sndwinup);
 	lprint("          %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl);
 	lprint("          %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin);
-	
-	lprint("  %6d packets received\r\n", tcpstat.tcps_rcvtotal);       
+
+	lprint("  %6d packets received\r\n", tcpstat.tcps_rcvtotal);
 	lprint("          %6d acks (for %d bytes)\r\n",
 			tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte);
 	lprint("          %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack);
@@ -201,7 +202,7 @@
 			tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte);
         lprint("          %6d completely duplicate packets (%d bytes)\r\n",
 			tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte);
-	
+
 	lprint("          %6d packets with some duplicate data (%d bytes duped)\r\n",
 			tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte);
 	lprint("          %6d out-of-order packets (%d bytes)\r\n",
@@ -214,7 +215,7 @@
 	lprint("          %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum);
 	lprint("          %6d discarded for bad header offset fields\r\n",
 			tcpstat.tcps_rcvbadoff);
-	
+
 	lprint("  %6d connection requests\r\n", tcpstat.tcps_connattempt);
 	lprint("  %6d connection accepts\r\n", tcpstat.tcps_accepts);
 	lprint("  %6d connections established (including accepts)\r\n", tcpstat.tcps_connects);
@@ -233,15 +234,15 @@
 	lprint("  %6d correct ACK header predictions\r\n", tcpstat.tcps_predack);
 	lprint("  %6d correct data packet header predictions\n", tcpstat.tcps_preddat);
 	lprint("  %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss);
-	
-	
+
+
 /*	lprint("    Packets received too short:		%d\r\n", tcpstat.tcps_rcvshort); */
 /*	lprint("    Segments dropped due to PAWS:	%d\r\n", tcpstat.tcps_pawsdrop); */
 
 }
 
-void
-udpstats()
+static void
+udpstats(void)
 {
         lprint(" \r\n");
 
@@ -254,8 +255,8 @@
 	lprint("  %6d datagrams sent\r\n", udpstat.udps_opackets);
 }
 
-void
-icmpstats()
+static void
+icmpstats(void)
 {
 	lprint(" \r\n");
 	lprint("ICMP stats:\r\n");
@@ -267,54 +268,79 @@
 	lprint("  %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect);
 }
 
-void
-sockstats()
+static void
+mbufstats(void)
+{
+	struct mbuf *m;
+	int i;
+
+        lprint(" \r\n");
+
+	lprint("Mbuf stats:\r\n");
+
+	lprint("  %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max);
+
+	i = 0;
+	for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next)
+		i++;
+	lprint("  %6d mbufs on free list\r\n",  i);
+
+	i = 0;
+	for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
+		i++;
+	lprint("  %6d mbufs on used list\r\n",  i);
+        lprint("  %6d mbufs queued as packets\r\n\r\n", if_queued);
+}
+
+static void
+sockstats(void)
 {
 	char buff[256];
 	int n;
 	struct socket *so;
 
         lprint(" \r\n");
-	
+
 	lprint(
 	   "Proto[state]     Sock     Local Address, Port  Remote Address, Port RecvQ SendQ\r\n");
-			
+
 	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
-		
+
 		n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE");
 		while (n < 17)
 		   buff[n++] = ' ';
 		buff[17] = 0;
 		lprint("%s %3d   %15s %5d ",
 				buff, so->s,
-				inet_iptostr(so->so_laddr_ip), so->so_laddr_port);
+				inet_ntoa(so->so_laddr), ntohs(so->so_lport));
 		lprint("%15s %5d %5d %5d\r\n",
-				inet_iptostr(so->so_faddr_ip), so->so_faddr_port,
+				inet_ntoa(so->so_faddr), ntohs(so->so_fport),
 				so->so_rcv.sb_cc, so->so_snd.sb_cc);
 	}
-		   
+
 	for (so = udb.so_next; so != &udb; so = so->so_next) {
-		
+
 		n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000);
 		while (n < 17)
 		   buff[n++] = ' ';
 		buff[17] = 0;
 		lprint("%s %3d  %15s %5d  ",
 				buff, so->s,
-				inet_iptostr(so->so_laddr_ip), so->so_laddr_port);
+				inet_ntoa(so->so_laddr), ntohs(so->so_lport));
 		lprint("%15s %5d %5d %5d\r\n",
-				inet_iptostr(so->so_faddr_ip), so->so_faddr_port,
+				inet_ntoa(so->so_faddr), ntohs(so->so_fport),
 				so->so_rcv.sb_cc, so->so_snd.sb_cc);
 	}
 }
+#endif
 
-#if 0
+#ifndef CONFIG_QEMU
 void
 slirp_exit(exit_status)
 	int exit_status;
 {
 	struct ttys *ttyp;
-	
+
 	DEBUG_CALL("slirp_exit");
 	DEBUG_ARG("exit_status = %d", exit_status);
 
@@ -323,7 +349,7 @@
 		if (!dfd)
 		   debug_init("slirp_stats", 0xf);
 		lprint_arg = (char **)&dfd;
-		
+
 		ipstats();
 		tcpstats();
 		udpstats();
@@ -333,20 +359,35 @@
 		allttystats();
 		vjstats();
 	}
-	
+
 	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
 	   tty_detached(ttyp, 1);
-	
+
 	if (slirp_forked) {
 		/* Menendez time */
 		if (kill(getppid(), SIGQUIT) < 0)
 			lprint("Couldn't kill parent process %ld!\n",
 			    (long) getppid());
     	}
-	
+
 	/* Restore the terminal if we gotta */
 	if(slirp_tty_restore)
 	  tcsetattr(0,TCSANOW, &slirp_tty_settings);  /* NOW DAMMIT! */
 	exit(exit_status);
 }
 #endif
+
+void
+slirp_stats(void)
+{
+#ifdef LOG_ENABLED
+    ipstats();
+    tcpstats();
+    udpstats();
+    icmpstats();
+    mbufstats();
+    sockstats();
+#else
+    lprint("SLIRP statistics code not compiled.\n");
+#endif
+}
diff --git a/slirp2/debug.h b/slirp/debug.h
similarity index 74%
copy from slirp2/debug.h
copy to slirp/debug.h
index 6e8444d..c43eff7 100644
--- a/slirp2/debug.h
+++ b/slirp/debug.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -37,14 +37,3 @@
 #endif
 
 void debug_init _P((char *, int));
-//void ttystats _P((struct ttys *));
-void allttystats _P((void));
-void ipstats _P((void));
-void vjstats _P((void));
-void tcpstats _P((void));
-void udpstats _P((void));
-void icmpstats _P((void));
-void mbufstats _P((void));
-void sockstats _P((void));
-void slirp_exit _P((int));
-
diff --git a/slirp2/icmp_var.h b/slirp/icmp_var.h
similarity index 89%
rename from slirp2/icmp_var.h
rename to slirp/icmp_var.h
index 03fc8c3..99d4c9e 100644
--- a/slirp2/icmp_var.h
+++ b/slirp/icmp_var.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -64,6 +60,8 @@
 	{ "stats", CTLTYPE_STRUCT }, \
 }
 
+#ifdef LOG_ENABLED
 extern struct icmpstat icmpstat;
+#endif
 
 #endif
diff --git a/slirp2/if.c b/slirp/if.c
similarity index 84%
copy from slirp2/if.c
copy to slirp/if.c
index cd96e65..17f8a73 100644
--- a/slirp2/if.c
+++ b/slirp/if.c
@@ -7,12 +7,7 @@
 
 #include <slirp.h>
 
-int if_mtu, if_mru;
-int if_comp;
-int if_maxlinkhdr;
 int     if_queued = 0;                  /* Number of packets queued so far */
-int     if_thresh = 10;                 /* Number of packets queued before we start sending
-					 * (to prevent allocing too many mbufs) */
 
 struct  mbuf if_fastq;                  /* fast queue (for interactive data) */
 struct  mbuf if_batchq;                 /* queue for non-interactive data */
@@ -20,9 +15,8 @@
 
 #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
 
-void
-ifs_insque(ifm, ifmhead)
-	MBuf ifm, ifmhead;
+static void
+ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
 {
 	ifm->ifs_next = ifmhead->ifs_next;
 	ifmhead->ifs_next = ifm;
@@ -30,34 +24,16 @@
 	ifm->ifs_next->ifs_prev = ifm;
 }
 
-void
-ifs_remque(ifm)
-	MBuf ifm;
+static void
+ifs_remque(struct mbuf *ifm)
 {
 	ifm->ifs_prev->ifs_next = ifm->ifs_next;
 	ifm->ifs_next->ifs_prev = ifm->ifs_prev;
 }
 
 void
-if_init()
+if_init(void)
 {
-#if 0
-	/*
-	 * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP,
-	 * and 8 bytes for PPP, but need to have it on an 8byte boundary
-	 */
-#ifdef USE_PPP
-	if_maxlinkhdr = 48;
-#else
-	if_maxlinkhdr = 40;
-#endif
-#else
-        /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
-        if_maxlinkhdr = 2 + 14 + 40;
-#endif
-	if_mtu = 1500;
-	if_mru = 1500;
-	if_comp = IF_AUTOCOMP;
 	if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq;
 	if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq;
         //	sl_compress_init(&comp_s);
@@ -77,16 +53,16 @@
 {
 	int ret;
 	int total;
-	
+
 	/* This should succeed most of the time */
-	ret = socket_send(fd, bptr, n);
+	ret = send(fd, bptr, n,0);
 	if (ret == n || ret <= 0)
 	   return ret;
-	
+
 	/* Didn't write everything, go into the loop */
 	total = ret;
 	while (n > total) {
-		ret = socket_send(fd, bptr+total, n-total);
+		ret = send(fd, bptr+total, n-total,0);
 		if (ret <= 0)
 		   return ret;
 		total += ret;
@@ -97,7 +73,7 @@
 /*
  * if_input - read() the tty, do "top level" processing (ie: check for any escapes),
  * and pass onto (*ttyp->if_input)
- * 
+ *
  * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet.
  */
 #define INBUFF_SIZE 2048 /* XXX */
@@ -107,14 +83,14 @@
 {
 	u_char if_inbuff[INBUFF_SIZE];
 	int if_n;
-	
+
 	DEBUG_CALL("if_input");
 	DEBUG_ARG("ttyp = %lx", (long)ttyp);
-	
-	if_n = socket_recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE);
-	
+
+	if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0);
+
 	DEBUG_MISC((dfd, " read %d bytes\n", if_n));
-	
+
 	if (if_n <= 0) {
 		if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) {
 			if (ttyp->up)
@@ -138,36 +114,34 @@
 		}
 	}
 	ttyp->ones = ttyp->zeros = 0;
-	
+
 	(*ttyp->if_input)(ttyp, if_inbuff, if_n);
 }
-#endif	
-	
+#endif
+
 /*
  * if_output: Queue packet into an output queue.
- * There are 2 output queue's, if_fastq and if_batchq. 
+ * There are 2 output queue's, if_fastq and if_batchq.
  * Each output queue is a doubly linked list of double linked lists
  * of mbufs, each list belonging to one "session" (socket).  This
  * way, we can output packets fairly by sending one packet from each
  * session, instead of all the packets from one session, then all packets
- * from the next session, etc.  Packets on the if_fastq get absolute 
+ * from the next session, etc.  Packets on the if_fastq get absolute
  * priority, but if one session hogs the link, it gets "downgraded"
  * to the batchq until it runs out of packets, then it'll return
  * to the fastq (eg. if the user does an ls -alR in a telnet session,
  * it'll temporarily get downgraded to the batchq)
  */
 void
-if_output(so, ifm)
-	struct socket *so;
-	MBuf ifm;
+if_output(struct socket *so, struct mbuf *ifm)
 {
-	MBuf ifq;
+	struct mbuf *ifq;
 	int on_fastq = 1;
-	
+
 	DEBUG_CALL("if_output");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("ifm = %lx", (long)ifm);
-	
+
 	/*
 	 * First remove the mbuf from m_usedlist,
 	 * since we're gonna use m_next and m_prev ourselves
@@ -177,9 +151,9 @@
 		remque(ifm);
 		ifm->m_flags &= ~M_USEDLIST;
 	}
-	
+
 	/*
-	 * See if there's already a batchq list for this session.  
+	 * See if there's already a batchq list for this session.
 	 * This can include an interactive session, which should go on fastq,
 	 * but gets too greedy... hence it'll be downgraded from fastq to batchq.
 	 * We mustn't put this packet back on the fastq (or we'll send it out of order)
@@ -193,7 +167,7 @@
 			goto diddit;
 		}
 	}
-	
+
 	/* No match, check which queue to put it on */
 	if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
 		ifq = if_fastq.ifq_prev;
@@ -209,15 +183,15 @@
 		}
 	} else
 		ifq = if_batchq.ifq_prev;
-	
+
 	/* Create a new doubly linked list for this session */
 	ifm->ifq_so = so;
 	ifs_init(ifm);
 	insque(ifm, ifq);
-	
+
 diddit:
 	++if_queued;
-	
+
 	if (so) {
 		/* Update *_queued */
 		so->so_queued++;
@@ -229,12 +203,12 @@
 		 * have been sent over the link
 		 * (XXX These are arbitrary numbers, probably not optimal..)
 		 */
-		if (on_fastq && ((so->so_nqueued >= 6) && 
+		if (on_fastq && ((so->so_nqueued >= 6) &&
 				 (so->so_nqueued - so->so_queued) >= 3)) {
-			
+
 			/* Remove from current queue... */
 			remque(ifm->ifs_next);
-			
+
 			/* ...And insert in the new.  That'll teach ya! */
 			insque(ifm->ifs_next, &if_batchq);
 		}
@@ -266,13 +240,13 @@
 void
 if_start(void)
 {
-	MBuf ifm, ifqt;
-	
+	struct mbuf *ifm, *ifqt;
+
 	DEBUG_CALL("if_start");
-	
+
 	if (if_queued == 0)
 	   return; /* Nothing to do */
-	
+
  again:
         /* check if we can really output */
         if (!slirp_can_output())
@@ -290,7 +264,7 @@
 		   ifm = next_m;
 		else
 		   ifm = if_batchq.ifq_next;
-		
+
 		/* Set which packet to send on next iteration */
 		next_m = ifm->ifq_next;
 	}
@@ -298,24 +272,24 @@
 	ifqt = ifm->ifq_prev;
 	remque(ifm);
 	--if_queued;
-	
+
 	/* If there are more packets for this session, re-queue them */
 	if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) {
 		insque(ifm->ifs_next, ifqt);
 		ifs_remque(ifm);
 	}
-	
+
 	/* Update so_queued */
 	if (ifm->ifq_so) {
 		if (--ifm->ifq_so->so_queued == 0)
 		   /* If there's no more queued, reset nqueued */
 		   ifm->ifq_so->so_nqueued = 0;
 	}
-	
-	/* Encapsulate the packet for sending */
-        if_encap(ifm->m_data, ifm->m_len);
 
-        mbuf_free(ifm);
+	/* Encapsulate the packet for sending */
+        if_encap((uint8_t *)ifm->m_data, ifm->m_len);
+
+        m_free(ifm);
 
 	if (if_queued)
 	   goto again;
diff --git a/slirp2/if.h b/slirp/if.h
similarity index 70%
rename from slirp2/if.h
rename to slirp/if.h
index f22f161..bed7152 100644
--- a/slirp2/if.h
+++ b/slirp/if.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -13,22 +13,34 @@
 #define IF_AUTOCOMP	0x04	/* Autodetect (default) */
 #define IF_NOCIDCOMP	0x08	/* CID compression */
 
-/* Needed for FreeBSD */
-#undef if_mtu
-extern int	if_mtu;
-extern int	if_mru;	/* MTU and MRU */
-extern int	if_comp;	/* Flags for compression */
-extern int	if_maxlinkhdr;
+#define IF_MTU 1500
+#define IF_MRU 1500
+#define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
+
+#if 0
+/*
+ * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP,
+ * and 8 bytes for PPP, but need to have it on an 8byte boundary
+ */
+#ifdef USE_PPP
+#define IF_MAXLINKHDR 48
+#else
+#define IF_MAXLINKHDR 40
+#endif
+#else
+        /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
+#define IF_MAXLINKHDR (2 + 14 + 40)
+#endif
+
 extern int	if_queued;	/* Number of packets queued so far */
-extern int	if_thresh;	/* Number of packets queued before we start sending
-				 * (to prevent allocing too many mbufs) */
 
 extern	struct mbuf if_fastq;                  /* fast queue (for interactive data) */
 extern	struct mbuf if_batchq;                 /* queue for non-interactive data */
-extern	MBuf next_m;
+extern	struct mbuf *next_m;
 
 #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
 
+#ifdef LOG_ENABLED
 /* Interface statistics */
 struct slirp_ifstats {
 	u_int out_pkts;		/* Output packets */
@@ -39,12 +51,13 @@
 	u_int in_bytes;		/* Input bytes */
 	u_int in_errpkts;		/* Input Error Packets */
 	u_int in_errbytes;	/* Input Error Bytes */
-	
+
 	u_int bytes_saved;	/* Number of bytes that compression "saved" */
 				/* ie: number of bytes that didn't need to be sent over the link
 				 * because of compression */
-	
+
 	u_int in_mbad;		/* Bad incoming packets */
 };
+#endif
 
 #endif
diff --git a/slirp2/ip.h b/slirp/ip.h
similarity index 84%
copy from slirp2/ip.h
copy to slirp/ip.h
index 8cdb735..7a7a9b9 100644
--- a/slirp2/ip.h
+++ b/slirp/ip.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -37,8 +33,6 @@
 #ifndef _IP_H_
 #define _IP_H_
 
-#include "helper.h"
-
 #ifdef WORDS_BIGENDIAN
 # ifndef NTOHL
 #  define NTOHL(d)
@@ -80,13 +74,13 @@
  */
 struct ip {
 #ifdef WORDS_BIGENDIAN
-	u_int ip_v:4;		/* version */
-	u_int ip_hl:4;		/* header length */
+	u_int ip_v:4,			/* version */
+		ip_hl:4;		/* header length */
 #else
-	u_int ip_hl:4;		/* header length */
-	u_int ip_v:4;		/* version */
+	u_int ip_hl:4,		/* header length */
+		ip_v:4;			/* version */
 #endif
-	u_int8_t  ip_tos;			/* type of service */
+	u_int8_t ip_tos;			/* type of service */
 	u_int16_t	ip_len;			/* total length */
 	u_int16_t	ip_id;			/* identification */
 	u_int16_t	ip_off;			/* fragment offset field */
@@ -96,7 +90,7 @@
 	u_int8_t ip_ttl;			/* time to live */
 	u_int8_t ip_p;			/* protocol */
 	u_int16_t	ip_sum;			/* checksum */
-        ipaddr_t        ip_src, ip_dst; /* source and dest address */
+	struct	in_addr ip_src,ip_dst;	/* source and dest address */
 };
 
 #define	IP_MAXPACKET	65535		/* maximum packet size */
@@ -155,8 +149,8 @@
 	union ipt_timestamp {
 		n_long	ipt_time[1];
 		struct	ipt_ta {
-			ipaddr_t ipt_addr;
-			n_long   ipt_time;
+			struct in_addr ipt_addr;
+			n_long ipt_time;
 		} ipt_ta[1];
 	} ipt_timestamp;
 };
@@ -187,28 +181,28 @@
 
 #if SIZEOF_CHAR_P == 4
 struct mbuf_ptr {
-    struct mbuf *mptr;
-    uint32_t     dummy;
+	struct mbuf *mptr;
+	uint32_t dummy;
 };
 #else
 struct mbuf_ptr {
-    struct mbuf *mptr;
+	struct mbuf *mptr;
 };
 #endif
 struct qlink {
-    void*  next, *prev;
+	void *next, *prev;
 };
 
 /*
  * Overlay for ip header used by other protocols (tcp, udp).
  */
 struct ipovly {
-	struct mbuf_ptr ih_mbuf;      /* backpointer to mbuf */
+	struct mbuf_ptr ih_mbuf;	/* backpointer to mbuf */
 	u_int8_t	ih_x1;			/* (unused) */
 	u_int8_t	ih_pr;			/* protocol */
 	u_int16_t	ih_len;			/* protocol length */
-	ipaddr_t        ih_src;		/* source internet address */
-	ipaddr_t        ih_dst;		/* destination internet address */
+	struct	in_addr ih_src;		/* source internet address */
+	struct	in_addr ih_dst;		/* destination internet address */
 } __attribute__((packed));
 
 /*
@@ -219,29 +213,29 @@
  * size 28 bytes
  */
 struct ipq {
-        struct qlink  frag_link;  /* to ip headers of fragments */
-        struct qlink  ip_link;    /* to other reass headers */
+        struct qlink frag_link;			/* to ip headers of fragments */
+	struct qlink ip_link;				/* to other reass headers */
 	u_int8_t	ipq_ttl;		/* time for reass q to live */
 	u_int8_t	ipq_p;			/* protocol of this fragment */
 	u_int16_t	ipq_id;			/* sequence id for reassembly */
-	ipaddr_t        ipq_src,ipq_dst;
+	struct	in_addr ipq_src,ipq_dst;
 };
 
 /*
  * Ip header, when holding a fragment.
  *
- * Note: ipf_next must be at same offset as frag_link above
+ * Note: ipf_link must be at same offset as frag_link above
  */
 struct	ipasfrag {
-        struct qlink ipf_link;
-        struct ip    ipf_ip;
+	struct qlink ipf_link;
+	struct ip ipf_ip;
 };
 
-#define ipf_off  ipf_ip.ip_off
-#define ipf_tos  ipf_ip.ip_tos
-#define ipf_len  ipf_ip.ip_len
-#define ipf_next ipf_link.next
-#define ipf_prev ipf_link.prev
+#define ipf_off      ipf_ip.ip_off
+#define ipf_tos      ipf_ip.ip_tos
+#define ipf_len      ipf_ip.ip_len
+#define ipf_next     ipf_link.next
+#define ipf_prev     ipf_link.prev 
 
 /*
  * Structure stored in mbuf in inpcb.ip_options
@@ -252,10 +246,11 @@
 #define MAX_IPOPTLEN	40
 
 struct ipoption {
-	u_int32_t ipopt_dst;	/* first-hop dst if source routed */
-	int8_t	  ipopt_list[MAX_IPOPTLEN];	/* options proper */
+	struct	in_addr ipopt_dst;	/* first-hop dst if source routed */
+	int8_t	ipopt_list[MAX_IPOPTLEN];	/* options proper */
 };
 
+#ifdef LOG_ENABLED
 /*
  * Structure attached to inpcb.ip_moptions and
  * passed to ip_output when IP multicast options are in use.
@@ -290,8 +285,9 @@
 };
 
 extern struct	ipstat	ipstat;
+#endif
+
 extern struct	ipq	ipq;			/* ip reass. queue */
 extern u_int16_t	ip_id;				/* ip packet ctr, for ids */
-extern int	ip_defttl;			/* default IP ttl */
 
 #endif
diff --git a/slirp2/ip_icmp.c b/slirp/ip_icmp.c
similarity index 74%
copy from slirp2/ip_icmp.c
copy to slirp/ip_icmp.c
index 6594ec4..61dcaf8 100644
--- a/slirp2/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -36,16 +32,17 @@
 
 #include "slirp.h"
 #include "ip_icmp.h"
-#include "sockets.h"
 
+#ifdef LOG_ENABLED
 struct icmpstat icmpstat;
+#endif
 
 /* The message sent when emulating PING */
-/* Be nice and tell them it's just a psuedo-ping packet */
-char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
+/* Be nice and tell them it's just a pseudo-ping packet */
+static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
 
 /* list of actions for icmp_error() on RX of an icmp message */
-static int icmp_flush[19] = {
+static const int icmp_flush[19] = {
 /*  ECHO REPLY (0)  */   0,
 		         1,
 		         1,
@@ -71,12 +68,10 @@
  * Process a received ICMP message.
  */
 void
-icmp_input(m, hlen)
-     MBuf m;
-     int hlen;
+icmp_input(struct mbuf *m, int hlen)
 {
   register struct icmp *icp;
-  register struct ip *ip=MBUF_TO(m, struct ip *);
+  register struct ip *ip=mtod(m, struct ip *);
   int icmplen=ip->ip_len;
   /* int code; */
 
@@ -84,24 +79,24 @@
   DEBUG_ARG("m = %lx", (long )m);
   DEBUG_ARG("m_len = %d", m->m_len);
 
-  icmpstat.icps_received++;
+  STAT(icmpstat.icps_received++);
 
   /*
    * Locate icmp structure in mbuf, and check
    * that its not corrupted and of at least minimum length.
    */
   if (icmplen < ICMP_MINLEN) {          /* min 8 bytes payload */
-    icmpstat.icps_tooshort++;
+    STAT(icmpstat.icps_tooshort++);
   freeit:
-    mbuf_free(m);
+    m_freem(m);
     goto end_error;
   }
 
   m->m_len -= hlen;
   m->m_data += hlen;
-  icp = MBUF_TO(m, struct icmp *);
+  icp = mtod(m, struct icmp *);
   if (cksum(m, icmplen)) {
-    icmpstat.icps_checksum++;
+    STAT(icmpstat.icps_checksum++);
     goto freeit;
   }
   m->m_len += hlen;
@@ -115,52 +110,51 @@
   case ICMP_ECHO:
     icp->icmp_type = ICMP_ECHOREPLY;
     ip->ip_len += hlen;	             /* since ip_input subtracts this */
-    if (ip_geth(ip->ip_dst) == alias_addr_ip) {
+    if (ip->ip_dst.s_addr == alias_addr.s_addr) {
       icmp_reflect(m);
     } else {
       struct socket *so;
-      SockAddress  addr;
-      uint32_t     addr_ip;
-      uint16_t     addr_port;
-
+      struct sockaddr_in addr;
       if ((so = socreate()) == NULL) goto freeit;
       if(udp_attach(so) == -1) {
 	DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
-		    errno,errno_str));
+		    errno,strerror(errno)));
 	sofree(so);
-	mbuf_free(m);
+	m_free(m);
 	goto end_error;
       }
       so->so_m = m;
-      so->so_faddr_ip   = ip_geth(ip->ip_dst);
-      so->so_faddr_port = 7;
-      so->so_laddr_ip   = ip_geth(ip->ip_src);
-      so->so_laddr_port = 9;
+      so->so_faddr = ip->ip_dst;
+      so->so_fport = htons(7);
+      so->so_laddr = ip->ip_src;
+      so->so_lport = htons(9);
       so->so_iptos = ip->ip_tos;
       so->so_type = IPPROTO_ICMP;
       so->so_state = SS_ISFCONNECTED;
 
       /* Send the packet */
-      if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) {
-        /* It's an alias */
-        int  low = so->so_faddr_ip & 0xff;
-
-        if (low >= CTL_DNS && low < CTL_DNS + dns_addr_count)
-            addr_ip = dns_addr[low - CTL_DNS];
-        else
-            addr_ip = loopback_addr_ip;
+      addr.sin_family = AF_INET;
+      if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
+	/* It's an alias */
+	switch(ntohl(so->so_faddr.s_addr) & 0xff) {
+	case CTL_DNS:
+	  addr.sin_addr = dns_addr;
+	  break;
+	case CTL_ALIAS:
+	default:
+	  addr.sin_addr = loopback_addr;
+	  break;
+	}
       } else {
-            addr_ip = so->so_faddr_ip;
+	addr.sin_addr = so->so_faddr;
       }
-      addr_port = so->so_faddr_port;
-
-      sock_address_init_inet( &addr, addr_ip, addr_port );
-
-      if(socket_sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), &addr) < 0) {
-        DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
-                    errno,errno_str));
-        icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,errno_str);
-        udp_detach(so);
+      addr.sin_port = so->so_fport;
+      if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
+		(struct sockaddr *)&addr, sizeof(addr)) == -1) {
+	DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
+		    errno,strerror(errno)));
+	icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
+	udp_detach(so);
       }
     } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
     break;
@@ -172,17 +166,17 @@
   case ICMP_TSTAMP:
   case ICMP_MASKREQ:
   case ICMP_REDIRECT:
-    icmpstat.icps_notsupp++;
-    mbuf_free(m);
+    STAT(icmpstat.icps_notsupp++);
+    m_freem(m);
     break;
 
   default:
-    icmpstat.icps_badtype++;
-    mbuf_free(m);
+    STAT(icmpstat.icps_badtype++);
+    m_freem(m);
   } /* swith */
 
 end_error:
-  /* m is mbuf_free()'d xor put in a socket xor or given to ip_send */
+  /* m is m_free()'d xor put in a socket xor or given to ip_send */
   return;
 }
 
@@ -198,7 +192,7 @@
  */
 /*
  * Send ICMP_UNREACH back to the source regarding msrc.
- * mbuf *msrc is used as a template, but is NOT mbuf_free()'d.
+ * mbuf *msrc is used as a template, but is NOT m_free()'d.
  * It is reported as the bad ip packet.  The header should
  * be fully correct and in host byte order.
  * ICMP fragmentation is illegal.  All machines must accept 576 bytes in one
@@ -207,17 +201,13 @@
 
 #define ICMP_MAXDATALEN (IP_MSS-28)
 void
-icmp_error(msrc, type, code, minsize, message)
-     MBuf msrc;
-     u_char type;
-     u_char code;
-     int minsize;
-     const char *message;
+icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+           const char *message)
 {
   unsigned hlen, shlen, s_ip_len;
   register struct ip *ip;
   register struct icmp *icp;
-  register MBuf m;
+  register struct mbuf *m;
 
   DEBUG_CALL("icmp_error");
   DEBUG_ARG("msrc = %lx", (long )msrc);
@@ -227,11 +217,11 @@
 
   /* check msrc */
   if(!msrc) goto end_error;
-  ip = MBUF_TO(msrc, struct ip *);
-#if DEBUG
+  ip = mtod(msrc, struct ip *);
+#ifdef DEBUG
   { char bufa[20], bufb[20];
-    strcpy(bufa, inet_iptostr(ip_geth(ip->ip_src)));
-    strcpy(bufb, inet_iptostr(ip_geth(ip->ip_dst)));
+    strcpy(bufa, inet_ntoa(ip->ip_src));
+    strcpy(bufb, inet_ntoa(ip->ip_dst));
     DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
   }
 #endif
@@ -249,23 +239,23 @@
   }
 
   /* make a copy */
-  if(!(m=mbuf_alloc())) goto end_error;               /* get mbuf */
+  if(!(m=m_get())) goto end_error;               /* get mbuf */
   { int new_m_size;
     new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
-    if(new_m_size>m->m_size) mbuf_ensure(m, new_m_size);
+    if(new_m_size>m->m_size) m_inc(m, new_m_size);
   }
   memcpy(m->m_data, msrc->m_data, msrc->m_len);
   m->m_len = msrc->m_len;                        /* copy msrc to m */
 
   /* make the header of the reply packet */
-  ip  = MBUF_TO(m, struct ip *);
+  ip  = mtod(m, struct ip *);
   hlen= sizeof(struct ip );     /* no options in reply */
 
   /* fill in icmp */
   m->m_data += hlen;
   m->m_len -= hlen;
 
-  icp = MBUF_TO(m, struct icmp *);
+  icp = mtod(m, struct icmp *);
 
   if(minsize) s_ip_len=shlen+ICMP_MINLEN;   /* return header+8b only */
   else if(s_ip_len>ICMP_MAXDATALEN)         /* maximum size */
@@ -285,7 +275,7 @@
   HTONS(icp->icmp_ip.ip_id);
   HTONS(icp->icmp_ip.ip_off);
 
-#if DEBUG
+#ifdef DEBUG
   if(message) {           /* DEBUG : append message to ICMP packet */
     int message_len;
     char *cpnt;
@@ -312,11 +302,11 @@
   ip->ip_ttl = MAXTTL;
   ip->ip_p = IPPROTO_ICMP;
   ip->ip_dst = ip->ip_src;    /* ip adresses */
-  ip->ip_src = ip_setn(alias_addr_ip);
+  ip->ip_src = alias_addr;
 
   (void ) ip_output((struct socket *)NULL, m);
 
-  icmpstat.icps_reflect++;
+  STAT(icmpstat.icps_reflect++);
 
 end_error:
   return;
@@ -327,10 +317,9 @@
  * Reflect the ip packet back to the source
  */
 void
-icmp_reflect(m)
-     MBuf m;
+icmp_reflect(struct mbuf *m)
 {
-  register struct ip *ip = MBUF_TO(m, struct ip *);
+  register struct ip *ip = mtod(m, struct ip *);
   int hlen = ip->ip_hl << 2;
   int optlen = hlen - sizeof(struct ip );
   register struct icmp *icp;
@@ -341,7 +330,7 @@
    */
   m->m_data += hlen;
   m->m_len -= hlen;
-  icp = MBUF_TO(m, struct icmp *);
+  icp = mtod(m, struct icmp *);
 
   icp->icmp_cksum = 0;
   icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
@@ -365,13 +354,13 @@
 
   ip->ip_ttl = MAXTTL;
   { /* swap */
-    ipaddr_t icmp_dst;
-    icmp_dst   = ip->ip_dst;
+    struct in_addr icmp_dst;
+    icmp_dst = ip->ip_dst;
     ip->ip_dst = ip->ip_src;
     ip->ip_src = icmp_dst;
   }
 
   (void ) ip_output((struct socket *)NULL, m);
 
-  icmpstat.icps_reflect++;
+  STAT(icmpstat.icps_reflect++);
 }
diff --git a/slirp2/ip_icmp.h b/slirp/ip_icmp.h
similarity index 91%
copy from slirp2/ip_icmp.h
copy to slirp/ip_icmp.h
index bc0be51..0330131 100644
--- a/slirp2/ip_icmp.h
+++ b/slirp/ip_icmp.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -37,8 +33,6 @@
 #ifndef _NETINET_IP_ICMP_H_
 #define _NETINET_IP_ICMP_H_
 
-#include "helper.h"
-
 /*
  * Interface Control Message Protocol Definitions.
  * Per RFC 792, September 1981.
@@ -54,8 +48,8 @@
 	u_char	icmp_code;		/* type sub code */
 	u_short	icmp_cksum;		/* ones complement cksum of struct */
 	union {
-		u_char    ih_pptr;			/* ICMP_PARAMPROB */
-		ipaddr_t  ih_gwaddr;	/* ICMP_REDIRECT */
+		u_char ih_pptr;			/* ICMP_PARAMPROB */
+		struct in_addr ih_gwaddr;	/* ICMP_REDIRECT */
 		struct ih_idseq {
 			u_short	icd_id;
 			u_short	icd_seq;
@@ -159,8 +153,9 @@
 	(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
 	(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
 
-void icmp_input _P((MBuf , int));
-void icmp_error _P((MBuf , u_char, u_char, int, const char *));
-void icmp_reflect _P((MBuf ));
+void icmp_input _P((struct mbuf *, int));
+void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+                const char *message);
+void icmp_reflect _P((struct mbuf *));
 
 #endif
diff --git a/slirp2/ip_input.c b/slirp/ip_input.c
similarity index 77%
copy from slirp2/ip_input.c
copy to slirp/ip_input.c
index fa99a5d..c37412e 100644
--- a/slirp2/ip_input.c
+++ b/slirp/ip_input.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -37,7 +33,7 @@
 /*
  * Changes and additions relating to SLiRP are
  * Copyright (c) 1995 Danny Gasparovski.
- * 
+ *
  * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
@@ -46,22 +42,30 @@
 #include <osdep.h>
 #include "ip_icmp.h"
 
-int ip_defttl;
+#ifdef LOG_ENABLED
 struct ipstat ipstat;
+#endif
+
 struct ipq ipq;
 
+static struct ip *ip_reass(register struct ip *ip,
+                           register struct ipq *fp);
+static void ip_freef(struct ipq *fp);
+static void ip_enq(register struct ipasfrag *p,
+                   register struct ipasfrag *prev);
+static void ip_deq(register struct ipasfrag *p);
+
 /*
  * IP initialization: fill in IP protocol switch table.
  * All protocols not implemented in kernel go to raw IP protocol handler.
  */
 void
-ip_init()
+ip_init(void)
 {
 	ipq.ip_link.next = ipq.ip_link.prev = &ipq.ip_link;
 	ip_id = tt.tv_sec & 0xffff;
 	udp_init();
 	tcp_init();
-	ip_defttl = IPDEFTTL;
 }
 
 /*
@@ -69,42 +73,41 @@
  * try to reassemble.  Process options.  Pass to next level.
  */
 void
-ip_input(m)
-	MBuf m;
+ip_input(struct mbuf *m)
 {
 	register struct ip *ip;
 	int hlen;
-	
+
 	DEBUG_CALL("ip_input");
 	DEBUG_ARG("m = %lx", (long)m);
 	DEBUG_ARG("m_len = %d", m->m_len);
 
-	ipstat.ips_total++;
-	
+	STAT(ipstat.ips_total++);
+
 	if (m->m_len < sizeof (struct ip)) {
-		ipstat.ips_toosmall++;
+		STAT(ipstat.ips_toosmall++);
 		return;
 	}
-	
-	ip = MBUF_TO(m, struct ip *);
-	
+
+	ip = mtod(m, struct ip *);
+
 	if (ip->ip_v != IPVERSION) {
-		ipstat.ips_badvers++;
+		STAT(ipstat.ips_badvers++);
 		goto bad;
 	}
 
 	hlen = ip->ip_hl << 2;
 	if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */
-	  ipstat.ips_badhlen++;                     /* or packet too short */
+	  STAT(ipstat.ips_badhlen++);                     /* or packet too short */
 	  goto bad;
 	}
 
         /* keep ip header intact for ICMP reply
-	 * ip->ip_sum = cksum(m, hlen); 
-	 * if (ip->ip_sum) { 
+	 * ip->ip_sum = cksum(m, hlen);
+	 * if (ip->ip_sum) {
 	 */
 	if(cksum(m,hlen)) {
-	  ipstat.ips_badsum++;
+	  STAT(ipstat.ips_badsum++);
 	  goto bad;
 	}
 
@@ -113,7 +116,7 @@
 	 */
 	NTOHS(ip->ip_len);
 	if (ip->ip_len < hlen) {
-		ipstat.ips_badlen++;
+		STAT(ipstat.ips_badlen++);
 		goto bad;
 	}
 	NTOHS(ip->ip_id);
@@ -126,12 +129,33 @@
 	 * Drop packet if shorter than we expect.
 	 */
 	if (m->m_len < ip->ip_len) {
-		ipstat.ips_tooshort++;
+		STAT(ipstat.ips_tooshort++);
 		goto bad;
 	}
+
+    if (slirp_restrict) {
+        if (memcmp(&ip->ip_dst.s_addr, &special_addr, 3)) {
+            if (ip->ip_dst.s_addr == 0xffffffff && ip->ip_p != IPPROTO_UDP)
+                goto bad;
+        } else {
+            int host = ntohl(ip->ip_dst.s_addr) & 0xff;
+            struct ex_list *ex_ptr;
+
+            if (host == 0xff)
+                goto bad;
+
+            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+                if (ex_ptr->ex_addr == host)
+                    break;
+
+            if (!ex_ptr)
+                goto bad;
+        }
+    }
+
 	/* Should drop packet if mbuf too long? hmmm... */
 	if (m->m_len > ip->ip_len)
-	   mbuf_trim(m, ip->ip_len - m->m_len);
+	   m_adj(m, ip->ip_len - m->m_len);
 
 	/* check ip_ttl for a correct ICMP reply */
 	if(ip->ip_ttl==0 || ip->ip_ttl==1) {
@@ -155,25 +179,25 @@
 	 * (We could look in the reassembly queue to see
 	 * if the packet was previously fragmented,
 	 * but it's not worth the time; just let them time out.)
-	 * 
+	 *
 	 * XXX This should fail, don't fragment yet
 	 */
 	if (ip->ip_off &~ IP_DF) {
 	  register struct ipq *fp;
-	  struct qlink *l;
+      struct qlink *l;
 		/*
 		 * Look for queue of fragments
 		 * of this datagram.
 		 */
 		for (l = ipq.ip_link.next; l != &ipq.ip_link; l = l->next) {
-		  fp = container_of(l, struct ipq, ip_link);
-		  if (ip->ip_id == fp->ipq_id &&
-		      ip_equal(ip->ip_src, fp->ipq_src) &&
-		      ip_equal(ip->ip_dst, fp->ipq_dst) &&
-		      ip->ip_p == fp->ipq_p)
-		  goto found;
-		}
-		fp = NULL;
+            fp = container_of(l, struct ipq, ip_link);
+            if (ip->ip_id == fp->ipq_id &&
+                    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
+                    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
+                    ip->ip_p == fp->ipq_p)
+		    goto found;
+        }
+        fp = NULL;
 	found:
 
 		/*
@@ -184,7 +208,7 @@
 		ip->ip_len -= hlen;
 		if (ip->ip_off & IP_MF)
 		  ip->ip_tos |= 1;
-		else 
+		else
 		  ip->ip_tos &= ~1;
 
 		ip->ip_off <<= 3;
@@ -195,12 +219,12 @@
 		 * attempt reassembly; if it succeeds, proceed.
 		 */
 		if (ip->ip_tos & 1 || ip->ip_off) {
-			ipstat.ips_fragments++;
+			STAT(ipstat.ips_fragments++);
 			ip = ip_reass(ip, fp);
-			if (ip == 0)
+                        if (ip == NULL)
 				return;
-			ipstat.ips_reassembled++;
-			m = MBUF_FROM(ip);
+			STAT(ipstat.ips_reassembled++);
+			m = dtom(ip);
 		} else
 			if (fp)
 		   	   ip_freef(fp);
@@ -211,7 +235,7 @@
 	/*
 	 * Switch out to protocol's input routine.
 	 */
-	ipstat.ips_delivered++;
+	STAT(ipstat.ips_delivered++);
 	switch (ip->ip_p) {
 	 case IPPROTO_TCP:
 		tcp_input(m, hlen, (struct socket *)NULL);
@@ -223,34 +247,31 @@
 		icmp_input(m, hlen);
 		break;
 	 default:
-		ipstat.ips_noproto++;
-		mbuf_free(m);
+		STAT(ipstat.ips_noproto++);
+		m_free(m);
 	}
 	return;
 bad:
-	mbuf_free(m);
+	m_freem(m);
 	return;
 }
 
 #define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink)))
 #define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink)))
-
 /*
  * Take incoming datagram fragment and try to
  * reassemble it into whole datagram.  If a chain for
  * reassembly of this datagram already exists, then it
  * is given as fp; otherwise have to make a chain.
  */
-struct ip *
-ip_reass(ip, fp)
-	register struct ip *ip;
-	register struct ipq *fp;
+static struct ip *
+ip_reass(register struct ip *ip, register struct ipq *fp)
 {
-	register MBuf m = MBUF_FROM(ip);
+	register struct mbuf *m = dtom(ip);
 	register struct ipasfrag *q;
 	int hlen = ip->ip_hl << 2;
 	int i, next;
-	
+
 	DEBUG_CALL("ip_reass");
 	DEBUG_ARG("ip = %lx", (long)ip);
 	DEBUG_ARG("fp = %lx", (long)fp);
@@ -267,40 +288,41 @@
 	/*
 	 * If first fragment to arrive, create a reassembly queue.
 	 */
-	if (fp == 0) {
-	  MBuf t;
-	  if ((t = mbuf_alloc()) == NULL) goto dropfrag;
-	  fp = MBUF_TO(t, struct ipq *);
+        if (fp == NULL) {
+	  struct mbuf *t;
+	  if ((t = m_get()) == NULL) goto dropfrag;
+	  fp = mtod(t, struct ipq *);
 	  insque(&fp->ip_link, &ipq.ip_link);
 	  fp->ipq_ttl = IPFRAGTTL;
 	  fp->ipq_p = ip->ip_p;
 	  fp->ipq_id = ip->ip_id;
 	  fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
 	  fp->ipq_src = ip->ip_src;
-	  fp->ipq_dst = ip->ip_src;
+	  fp->ipq_dst = ip->ip_dst;
 	  q = (struct ipasfrag *)fp;
 	  goto insert;
 	}
-	
+
 	/*
 	 * Find a segment which begins after this one does.
 	 */
-        for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
-             q = q->ipf_next)
-                if (q->ipf_off > ip->ip_off)
-                    break;
+	for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
+            q = q->ipf_next)
+		if (q->ipf_off > ip->ip_off)
+			break;
+
 	/*
 	 * If there is a preceding segment, it may provide some of
 	 * our data already.  If so, drop the data from the incoming
 	 * segment.  If it provides all of our data, drop us.
 	 */
-        if (q->ipf_prev != &fp->frag_link) {
-            struct ipasfrag *pq = q->ipf_prev;
-                i = pq->ipf_off + pq->ipf_len - ip->ip_off;
+	if (q->ipf_prev != &fp->frag_link) {
+        struct ipasfrag *pq = q->ipf_prev;
+		i = pq->ipf_off + pq->ipf_len - ip->ip_off;
 		if (i > 0) {
 			if (i >= ip->ip_len)
 				goto dropfrag;
-			mbuf_trim(MBUF_FROM(ip), i);
+			m_adj(dtom(ip), i);
 			ip->ip_off += i;
 			ip->ip_len -= i;
 		}
@@ -310,17 +332,17 @@
 	 * While we overlap succeeding segments trim them or,
 	 * if they are completely covered, dequeue them.
 	 */
-	while (q != (struct ipasfrag *)&fp->frag_link &&
-	     ip->ip_off + ip->ip_len > q->ipf_off) {
-	       i = (ip->ip_off + ip->ip_len) - q->ipf_off;
-	       if (i < q->ipf_len) {
-	           q->ipf_len -= i;
-	           q->ipf_off += i;
-                   mbuf_trim(MBUF_FROM(q), i);
-                   break;
+	while (q != (struct ipasfrag*)&fp->frag_link &&
+            ip->ip_off + ip->ip_len > q->ipf_off) {
+		i = (ip->ip_off + ip->ip_len) - q->ipf_off;
+		if (i < q->ipf_len) {
+			q->ipf_len -= i;
+			q->ipf_off += i;
+			m_adj(dtom(q), i);
+			break;
 		}
 		q = q->ipf_next;
-		mbuf_free(MBUF_FROM(q->ipf_prev));
+		m_freem(dtom(q->ipf_prev));
 		ip_deq(q->ipf_prev);
 	}
 
@@ -331,28 +353,26 @@
 	 */
 	ip_enq(iptofrag(ip), q->ipf_prev);
 	next = 0;
-	for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
-	     q = q->ipf_next) 
-        {
-            if (q->ipf_off != next)
-                return (0);
-
-            next += q->ipf_len;
+	for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link;
+            q = q->ipf_next) {
+		if (q->ipf_off != next)
+                        return NULL;
+		next += q->ipf_len;
 	}
 	if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
-		return (0);
+                return NULL;
 
 	/*
 	 * Reassembly is complete; concatenate fragments.
 	 */
-	q = fp->frag_link.next;
-	m = MBUF_FROM(q);
+    q = fp->frag_link.next;
+	m = dtom(q);
 
 	q = (struct ipasfrag *) q->ipf_next;
-	while (q != (struct ipasfrag *)&fp->frag_link) {
-	  MBuf t = MBUF_FROM(q);
+	while (q != (struct ipasfrag*)&fp->frag_link) {
+	  struct mbuf *t = dtom(q);
 	  q = (struct ipasfrag *) q->ipf_next;
-	  mbuf_append(m, t);
+	  m_cat(m, t);
 	}
 
 	/*
@@ -361,7 +381,7 @@
 	 * dequeue and discard fragment reassembly header.
 	 * Make header visible.
 	 */
-        q = fp->frag_link.next;
+	q = fp->frag_link.next;
 
 	/*
 	 * If the fragments concatenated to an mbuf that's
@@ -375,57 +395,55 @@
 	  q = (struct ipasfrag *)(m->m_ext + delta);
 	}
 
-	/* DEBUG_ARG("ip = %lx", (long)ip); 
+	/* DEBUG_ARG("ip = %lx", (long)ip);
 	 * ip=(struct ipasfrag *)m->m_data; */
 
-        ip = fragtoip(q);
-	ip->ip_len  = next;
+    ip = fragtoip(q);
+	ip->ip_len = next;
 	ip->ip_tos &= ~1;
-	ip->ip_src  = fp->ipq_src;
-	ip->ip_dst  = fp->ipq_dst;
+	ip->ip_src = fp->ipq_src;
+	ip->ip_dst = fp->ipq_dst;
 	remque(&fp->ip_link);
-	(void) mbuf_free(MBUF_FROM(fp));
+	(void) m_free(dtom(fp));
 	m->m_len += (ip->ip_hl << 2);
 	m->m_data -= (ip->ip_hl << 2);
 
 	return ip;
 
 dropfrag:
-	ipstat.ips_fragdropped++;
-	mbuf_free(m);
-	return (0);
+	STAT(ipstat.ips_fragdropped++);
+	m_freem(m);
+        return NULL;
 }
 
 /*
  * Free a fragment reassembly header and all
  * associated datagrams.
  */
-void
-ip_freef(fp)
-	struct ipq *fp;
+static void
+ip_freef(struct ipq *fp)
 {
 	register struct ipasfrag *q, *p;
 
-	for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; q = p) {
+	for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
 		p = q->ipf_next;
 		ip_deq(q);
-		mbuf_free(MBUF_FROM(q));
+		m_freem(dtom(q));
 	}
 	remque(&fp->ip_link);
-	(void) mbuf_free(MBUF_FROM(fp));
+	(void) m_free(dtom(fp));
 }
 
 /*
  * Put an ip fragment on a reassembly chain.
  * Like insque, but pointers in middle of structure.
  */
-void
-ip_enq(p, prev)
-	register struct ipasfrag *p, *prev;
+static void
+ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
 {
 	DEBUG_CALL("ip_enq");
 	DEBUG_ARG("prev = %lx", (long)prev);
-	p->ipf_prev = prev;
+	p->ipf_prev =  prev;
 	p->ipf_next = prev->ipf_next;
 	((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
 	prev->ipf_next = p;
@@ -434,9 +452,8 @@
 /*
  * To ip_enq as remque is to insque.
  */
-void
-ip_deq(p)
-	register struct ipasfrag *p;
+static void
+ip_deq(register struct ipasfrag *p)
 {
 	((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
 	((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
@@ -448,21 +465,22 @@
  * queue, discard it.
  */
 void
-ip_slowtimo()
+ip_slowtimo(void)
 {
-        struct qlink *l;
-	
+    struct qlink *l;
+
 	DEBUG_CALL("ip_slowtimo");
-	
-	l = ipq.ip_link.next;
-	if (l == 0)
+
+    l = ipq.ip_link.next;
+
+        if (l == NULL)
 	   return;
 
-        while (l != &ipq.ip_link) {
-            struct ipq *fp = container_of(l, struct ipq, ip_link);
-            l = l->next;
-            if (--fp->ipq_ttl == 0) {
-			ipstat.ips_fragtimeout++;
+	while (l != &ipq.ip_link) {
+        struct ipq *fp = container_of(l, struct ipq, ip_link);
+        l = l->next;
+		if (--fp->ipq_ttl == 0) {
+			STAT(ipstat.ips_fragtimeout++);
 			ip_freef(fp);
 		}
 	}
@@ -480,15 +498,15 @@
 
 int
 ip_dooptions(m)
-	MBuf m;
+	struct mbuf *m;
 {
-	register struct ip *ip = MBUF_TO(m, struct ip *);
+	register struct ip *ip = mtod(m, struct ip *);
 	register u_char *cp;
 	register struct ip_timestamp *ipt;
 	register struct in_ifaddr *ia;
 /*	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */
 	int opt, optlen, cnt, off, code, type, forward = 0;
-	ipaddr_t *sin, dst;
+	struct in_addr *sin, dst;
 typedef u_int32_t n_time;
 	n_time ntime;
 
@@ -669,7 +687,7 @@
 /* Not yet */
  	icmp_error(m, type, code, 0, 0);
 
-	ipstat.ips_badoptions++;
+	STAT(ipstat.ips_badoptions++);
 	return (1);
 }
 
@@ -683,12 +701,10 @@
  * (XXX) should be deleted; last arg currently ignored.
  */
 void
-ip_stripoptions(m, mopt)
-	register MBuf m;
-	MBuf mopt;
+ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
 {
 	register int i;
-	struct ip *ip = MBUF_TO(m, struct ip *);
+	struct ip *ip = mtod(m, struct ip *);
 	register caddr_t opts;
 	int olen;
 
@@ -697,6 +713,6 @@
 	i = m->m_len - (sizeof (struct ip) + olen);
 	memcpy(opts, opts  + olen, (unsigned)i);
 	m->m_len -= olen;
-	
+
 	ip->ip_hl = sizeof(struct ip) >> 2;
 }
diff --git a/slirp2/ip_output.c b/slirp/ip_output.c
similarity index 82%
copy from slirp2/ip_output.c
copy to slirp/ip_output.c
index 42d789c..5bce520 100644
--- a/slirp2/ip_output.c
+++ b/slirp/ip_output.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -46,6 +42,10 @@
 
 u_int16_t ip_id;
 
+/* Number of packets queued before we start sending
+ * (to prevent allocing too many mbufs) */
+#define IF_THRESH 10
+
 /*
  * IP output.  The packet in mbuf chain m contains a skeletal IP
  * header (with len, off, ttl, proto, tos, src, dst).
@@ -53,26 +53,24 @@
  * The mbuf opt, if present, will not be freed.
  */
 int
-ip_output(so, m0)
-	struct socket *so;
-	MBuf m0;
+ip_output(struct socket *so, struct mbuf *m0)
 {
 	register struct ip *ip;
-	register MBuf m = m0;
+	register struct mbuf *m = m0;
 	register int hlen = sizeof(struct ip );
 	int len, off, error = 0;
 
 	DEBUG_CALL("ip_output");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m0 = %lx", (long)m0);
-	
+
 	/* We do no options */
 /*	if (opt) {
  *		m = ip_insertoptions(m, opt, &len);
  *		hlen = len;
  *	}
  */
-	ip = MBUF_TO(m, struct ip *);
+	ip = mtod(m, struct ip *);
 	/*
 	 * Fill in IP header.
 	 */
@@ -80,23 +78,23 @@
 	ip->ip_off &= IP_DF;
 	ip->ip_id = htons(ip_id++);
 	ip->ip_hl = hlen >> 2;
-	ipstat.ips_localout++;
+	STAT(ipstat.ips_localout++);
 
 	/*
 	 * Verify that we have any chance at all of being able to queue
 	 *      the packet or packet fragments
 	 */
 	/* XXX Hmmm... */
-/*	if (if_queued > if_thresh && towrite <= 0) {
+/*	if (if_queued > IF_THRESH && towrite <= 0) {
  *		error = ENOBUFS;
  *		goto bad;
  *	}
  */
-	
+
 	/*
 	 * If small enough for interface, can just send directly.
 	 */
-	if ((u_int16_t)ip->ip_len <= if_mtu) {
+	if ((u_int16_t)ip->ip_len <= IF_MTU) {
 		ip->ip_len = htons((u_int16_t)ip->ip_len);
 		ip->ip_off = htons((u_int16_t)ip->ip_off);
 		ip->ip_sum = 0;
@@ -112,11 +110,11 @@
 	 */
 	if (ip->ip_off & IP_DF) {
 		error = -1;
-		ipstat.ips_cantfrag++;
+		STAT(ipstat.ips_cantfrag++);
 		goto bad;
 	}
-	
-	len = (if_mtu - hlen) &~ 7;       /* ip databytes per packet */
+
+	len = (IF_MTU - hlen) &~ 7;       /* ip databytes per packet */
 	if (len < 8) {
 		error = -1;
 		goto bad;
@@ -124,7 +122,7 @@
 
     {
 	int mhlen, firstlen = len;
-	MBuf *mnext = &m->m_nextpkt;
+	struct mbuf **mnext = &m->m_nextpkt;
 
 	/*
 	 * Loop through length of segment after first fragment,
@@ -134,16 +132,16 @@
 	mhlen = sizeof (struct ip);
 	for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) {
 	  register struct ip *mhip;
-	  m = mbuf_alloc();
-	  if (m == 0) {
+	  m = m_get();
+          if (m == NULL) {
 	    error = -1;
-	    ipstat.ips_odropped++;
+	    STAT(ipstat.ips_odropped++);
 	    goto sendorfree;
 	  }
-	  m->m_data += if_maxlinkhdr;
-	  mhip = MBUF_TO(m, struct ip *);
+	  m->m_data += IF_MAXLINKHDR;
+	  mhip = mtod(m, struct ip *);
 	  *mhip = *ip;
-		
+
 		/* No options */
 /*		if (hlen > sizeof (struct ip)) {
  *			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
@@ -156,28 +154,28 @@
 	    mhip->ip_off |= IP_MF;
 	  if (off + len >= (u_int16_t)ip->ip_len)
 	    len = (u_int16_t)ip->ip_len - off;
-	  else 
+	  else
 	    mhip->ip_off |= IP_MF;
 	  mhip->ip_len = htons((u_int16_t)(len + mhlen));
-	  
-	  if (mbuf_copy(m, m0, off, len) < 0) {
+
+	  if (m_copy(m, m0, off, len) < 0) {
 	    error = -1;
 	    goto sendorfree;
 	  }
-	  
+
 	  mhip->ip_off = htons((u_int16_t)mhip->ip_off);
 	  mhip->ip_sum = 0;
 	  mhip->ip_sum = cksum(m, mhlen);
 	  *mnext = m;
 	  mnext = &m->m_nextpkt;
-	  ipstat.ips_ofragments++;
+	  STAT(ipstat.ips_ofragments++);
 	}
 	/*
 	 * Update first fragment by trimming what's been copied out
 	 * and updating header, then send each fragment (in order).
 	 */
 	m = m0;
-	mbuf_trim(m, hlen + firstlen - (u_int16_t)ip->ip_len);
+	m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len);
 	ip->ip_len = htons((u_int16_t)m->m_len);
 	ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF));
 	ip->ip_sum = 0;
@@ -185,21 +183,21 @@
 sendorfree:
 	for (m = m0; m; m = m0) {
 		m0 = m->m_nextpkt;
-		m->m_nextpkt = 0;
+                m->m_nextpkt = NULL;
 		if (error == 0)
 			if_output(so, m);
 		else
-			mbuf_free(m);
+			m_freem(m);
 	}
 
 	if (error == 0)
-		ipstat.ips_fragmented++;
+		STAT(ipstat.ips_fragmented++);
     }
 
 done:
 	return (error);
 
 bad:
-	mbuf_free(m0);
+	m_freem(m0);
 	goto done;
 }
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
new file mode 100644
index 0000000..d0df24b
--- /dev/null
+++ b/slirp/libslirp.h
@@ -0,0 +1,44 @@
+#ifndef _LIBSLIRP_H
+#define _LIBSLIRP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void slirp_init(int restricted, const char *special_ip);
+
+void slirp_select_fill(int *pnfds,
+                       fd_set *readfds, fd_set *writefds, fd_set *xfds);
+
+void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds);
+
+void slirp_input(const uint8_t *pkt, int pkt_len);
+
+/* you must provide the following functions: */
+int slirp_can_output(void);
+void slirp_output(const uint8_t *pkt, int pkt_len);
+
+void slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+                                  struct in_addr *laddr, u_int lport,              
+                                  struct in_addr *faddr, u_int fport),
+                     void *opaque);
+int slirp_redir_rm(int is_udp, int host_port);
+int slirp_redir(int is_udp, int host_port,
+                struct in_addr guest_addr, int guest_port);
+int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
+                   int guest_port);
+
+extern const char *tftp_prefix;
+extern char slirp_hostname[33];
+extern const char *bootp_filename;
+
+void slirp_stats(void);
+void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
+		int size);
+size_t slirp_socket_can_recv(int addr_low_byte, int guest_port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/slirp2/main.h b/slirp/main.h
similarity index 76%
copy from slirp2/main.h
copy to slirp/main.h
index 159e5f4..ed51385 100644
--- a/slirp2/main.h
+++ b/slirp/main.h
@@ -28,26 +28,24 @@
  */
 #define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y)
 
-#define  DNS_ADDR_MAX  4
-
 extern char *slirp_tty;
 extern char *exec_shell;
 extern u_int curtime;
 extern fd_set *global_readfds, *global_writefds, *global_xfds;
-extern uint32_t ctl_addr_ip;
-extern uint32_t special_addr_ip;
-extern uint32_t alias_addr_ip;
-extern uint32_t our_addr_ip;
-extern uint32_t loopback_addr_ip;
-extern uint32_t dns_addr[DNS_ADDR_MAX];
-extern int      dns_addr_count;
+extern struct in_addr ctl_addr;
+extern struct in_addr special_addr;
+extern struct in_addr alias_addr;
+extern struct in_addr our_addr;
+extern struct in_addr loopback_addr;
+extern struct in_addr dns_addr;
 extern char *username;
 extern char *socket_path;
 extern int towrite_max;
 extern int ppp_exit;
-extern int so_options;
 extern int tcp_keepintvl;
 extern uint8_t client_ethaddr[6];
+extern const char *slirp_special_ip;
+extern int slirp_restrict;
 
 #define PROTO_SLIP 0x1
 #ifdef USE_PPP
@@ -55,3 +53,4 @@
 #endif
 
 void if_encap(const uint8_t *ip_data, int ip_data_len);
+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
new file mode 100644
index 0000000..1d30a63
--- /dev/null
+++ b/slirp/mbuf.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+/*
+ * mbuf's in SLiRP are much simpler than the real mbufs in
+ * FreeBSD.  They are fixed size, determined by the MTU,
+ * so that one whole packet can fit.  Mbuf's cannot be
+ * chained together.  If there's more data than the mbuf
+ * could hold, an external malloced buffer is pointed to
+ * by m_ext (and the data pointers) and M_EXT is set in
+ * the flags
+ */
+
+#include <slirp.h>
+
+int mbuf_alloced = 0;
+struct mbuf m_freelist, m_usedlist;
+#define MBUF_THRESH 30
+int mbuf_max = 0;
+
+/*
+ * Find a nice value for msize
+ * XXX if_maxlinkhdr already in mtu
+ */
+#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6)
+
+void
+m_init(void)
+{
+	m_freelist.m_next = m_freelist.m_prev = &m_freelist;
+	m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist;
+}
+
+/*
+ * Get an mbuf from the free list, if there are none
+ * malloc one
+ *
+ * Because fragmentation can occur if we alloc new mbufs and
+ * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
+ * which tells m_free to actually free() it
+ */
+struct mbuf *
+m_get(void)
+{
+	register struct mbuf *m;
+	int flags = 0;
+
+	DEBUG_CALL("m_get");
+
+	if (m_freelist.m_next == &m_freelist) {
+		m = (struct mbuf *)malloc(SLIRP_MSIZE);
+		if (m == NULL) goto end_error;
+		mbuf_alloced++;
+		if (mbuf_alloced > MBUF_THRESH)
+			flags = M_DOFREE;
+		if (mbuf_alloced > mbuf_max)
+			mbuf_max = mbuf_alloced;
+	} else {
+		m = m_freelist.m_next;
+		remque(m);
+	}
+
+	/* Insert it in the used list */
+	insque(m,&m_usedlist);
+	m->m_flags = (flags | M_USEDLIST);
+
+	/* Initialise it */
+	m->m_size = SLIRP_MSIZE - sizeof(struct m_hdr);
+	m->m_data = m->m_dat;
+	m->m_len = 0;
+        m->m_nextpkt = NULL;
+        m->m_prevpkt = NULL;
+end_error:
+	DEBUG_ARG("m = %lx", (long )m);
+	return m;
+}
+
+void
+m_free(struct mbuf *m)
+{
+
+  DEBUG_CALL("m_free");
+  DEBUG_ARG("m = %lx", (long )m);
+
+  if(m) {
+	/* Remove from m_usedlist */
+	if (m->m_flags & M_USEDLIST)
+	   remque(m);
+
+	/* If it's M_EXT, free() it */
+	if (m->m_flags & M_EXT)
+	   free(m->m_ext);
+
+	/*
+	 * Either free() it or put it on the free list
+	 */
+	if (m->m_flags & M_DOFREE) {
+		free(m);
+		mbuf_alloced--;
+	} else if ((m->m_flags & M_FREELIST) == 0) {
+		insque(m,&m_freelist);
+		m->m_flags = M_FREELIST; /* Clobber other flags */
+	}
+  } /* if(m) */
+}
+
+/*
+ * Copy data from one mbuf to the end of
+ * the other.. if result is too big for one mbuf, malloc()
+ * an M_EXT data segment
+ */
+void
+m_cat(struct mbuf *m, struct mbuf *n)
+{
+	/*
+	 * If there's no room, realloc
+	 */
+	if (M_FREEROOM(m) < n->m_len)
+		m_inc(m,m->m_size+MINCSIZE);
+
+	memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
+	m->m_len += n->m_len;
+
+	m_free(n);
+}
+
+
+/* make m size bytes large */
+void
+m_inc(struct mbuf *m, int size)
+{
+	int datasize;
+
+	/* some compiles throw up on gotos.  This one we can fake. */
+        if(m->m_size>size) return;
+
+        if (m->m_flags & M_EXT) {
+	  datasize = m->m_data - m->m_ext;
+	  m->m_ext = (char *)realloc(m->m_ext,size);
+/*		if (m->m_ext == NULL)
+ *			return (struct mbuf *)NULL;
+ */
+	  m->m_data = m->m_ext + datasize;
+        } else {
+	  char *dat;
+	  datasize = m->m_data - m->m_dat;
+	  dat = (char *)malloc(size);
+/*		if (dat == NULL)
+ *			return (struct mbuf *)NULL;
+ */
+	  memcpy(dat, m->m_dat, m->m_size);
+
+	  m->m_ext = dat;
+	  m->m_data = m->m_ext + datasize;
+	  m->m_flags |= M_EXT;
+        }
+
+        m->m_size = size;
+
+}
+
+
+
+void
+m_adj(struct mbuf *m, int len)
+{
+	if (m == NULL)
+		return;
+	if (len >= 0) {
+		/* Trim from head */
+		m->m_data += len;
+		m->m_len -= len;
+	} else {
+		/* Trim from tail */
+		len = -len;
+		m->m_len -= len;
+	}
+}
+
+
+/*
+ * Copy len bytes from m, starting off bytes into n
+ */
+int
+m_copy(struct mbuf *n, struct mbuf *m, int off, int len)
+{
+	if (len > M_FREEROOM(n))
+		return -1;
+
+	memcpy((n->m_data + n->m_len), (m->m_data + off), len);
+	n->m_len += len;
+	return 0;
+}
+
+
+/*
+ * Given a pointer into an mbuf, return the mbuf
+ * XXX This is a kludge, I should eliminate the need for it
+ * Fortunately, it's not used often
+ */
+struct mbuf *
+dtom(void *dat)
+{
+	struct mbuf *m;
+
+	DEBUG_CALL("dtom");
+	DEBUG_ARG("dat = %lx", (long )dat);
+
+	/* bug corrected for M_EXT buffers */
+	for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) {
+	  if (m->m_flags & M_EXT) {
+	    if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) )
+	      return m;
+	  } else {
+	    if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) )
+	      return m;
+	  }
+	}
+
+	DEBUG_ERROR((dfd, "dtom failed"));
+
+	return (struct mbuf *)0;
+}
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
new file mode 100644
index 0000000..5527373
--- /dev/null
+++ b/slirp/mbuf.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)mbuf.h	8.3 (Berkeley) 1/21/94
+ * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
+ */
+
+#ifndef _MBUF_H_
+#define _MBUF_H_
+
+#define m_freem m_free
+
+
+#define MINCSIZE 4096	/* Amount to increase mbuf if too small */
+
+/*
+ * Macros for type conversion
+ * mtod(m,t) -	convert mbuf pointer to data pointer of correct type
+ * dtom(x) -	convert data pointer within mbuf to mbuf pointer (XXX)
+ */
+#define mtod(m,t)	((t)(m)->m_data)
+/* #define	dtom(x)		((struct mbuf *)((int)(x) & ~(M_SIZE-1))) */
+
+/* XXX About mbufs for slirp:
+ * Only one mbuf is ever used in a chain, for each "cell" of data.
+ * m_nextpkt points to the next packet, if fragmented.
+ * If the data is too large, the M_EXT is used, and a larger block
+ * is alloced.  Therefore, m_free[m] must check for M_EXT and if set
+ * free the m_ext.  This is inefficient memory-wise, but who cares.
+ */
+
+/* XXX should union some of these! */
+/* header at beginning of each mbuf: */
+struct m_hdr {
+	struct	mbuf *mh_next;		/* Linked list of mbufs */
+	struct	mbuf *mh_prev;
+	struct	mbuf *mh_nextpkt;	/* Next packet in queue/record */
+	struct	mbuf *mh_prevpkt; /* Flags aren't used in the output queue */
+	int	mh_flags;	  /* Misc flags */
+
+	int	mh_size;		/* Size of data */
+	struct	socket *mh_so;
+
+	caddr_t	mh_data;		/* Location of data */
+	int	mh_len;			/* Amount of data in this mbuf */
+};
+
+/*
+ * How much room is in the mbuf, from m_data to the end of the mbuf
+ */
+#define M_ROOM(m) ((m->m_flags & M_EXT)? \
+			(((m)->m_ext + (m)->m_size) - (m)->m_data) \
+		   : \
+			(((m)->m_dat + (m)->m_size) - (m)->m_data))
+
+/*
+ * How much free room there is
+ */
+#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
+#define M_TRAILINGSPACE M_FREEROOM
+
+struct mbuf {
+	struct	m_hdr m_hdr;
+	union M_dat {
+		char	m_dat_[1]; /* ANSI don't like 0 sized arrays */
+		char	*m_ext_;
+	} M_dat;
+};
+
+#define m_next		m_hdr.mh_next
+#define m_prev		m_hdr.mh_prev
+#define m_nextpkt	m_hdr.mh_nextpkt
+#define m_prevpkt	m_hdr.mh_prevpkt
+#define m_flags		m_hdr.mh_flags
+#define	m_len		m_hdr.mh_len
+#define	m_data		m_hdr.mh_data
+#define m_size		m_hdr.mh_size
+#define m_dat		M_dat.m_dat_
+#define m_ext		M_dat.m_ext_
+#define m_so		m_hdr.mh_so
+
+#define ifq_prev m_prev
+#define ifq_next m_next
+#define ifs_prev m_prevpkt
+#define ifs_next m_nextpkt
+#define ifq_so m_so
+
+#define M_EXT			0x01	/* m_ext points to more (malloced) data */
+#define M_FREELIST		0x02	/* mbuf is on free list */
+#define M_USEDLIST		0x04	/* XXX mbuf is on used list (for dtom()) */
+#define M_DOFREE		0x08	/* when m_free is called on the mbuf, free()
+					 * it rather than putting it on the free list */
+
+/*
+ * Mbuf statistics. XXX
+ */
+
+struct mbstat {
+	int mbs_alloced;		/* Number of mbufs allocated */
+
+};
+
+extern struct	mbstat mbstat;
+extern int mbuf_alloced;
+extern struct mbuf m_freelist, m_usedlist;
+extern int mbuf_max;
+
+void m_init _P((void));
+struct mbuf * m_get _P((void));
+void m_free _P((struct mbuf *));
+void m_cat _P((register struct mbuf *, register struct mbuf *));
+void m_inc _P((struct mbuf *, int));
+void m_adj _P((struct mbuf *, int));
+int m_copy _P((struct mbuf *, struct mbuf *, int, int));
+struct mbuf * dtom _P((void *));
+
+#endif
diff --git a/slirp/misc.c b/slirp/misc.c
new file mode 100644
index 0000000..1391d49
--- /dev/null
+++ b/slirp/misc.c
@@ -0,0 +1,907 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+
+u_int curtime, time_fasttimo, last_slowtimo;
+
+#if 0
+int x_port = -1;
+int x_display = 0;
+int x_screen = 0;
+
+int
+show_x(buff, inso)
+	char *buff;
+	struct socket *inso;
+{
+	if (x_port < 0) {
+		lprint("X Redir: X not being redirected.\r\n");
+	} else {
+		lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n",
+		      inet_ntoa(our_addr), x_port, x_screen);
+		lprint("X Redir: In csh/tcsh/etc. type:    setenv DISPLAY %s:%d.%d\r\n",
+		      inet_ntoa(our_addr), x_port, x_screen);
+		if (x_display)
+		   lprint("X Redir: Redirecting to display %d\r\n", x_display);
+	}
+
+	return CFG_OK;
+}
+
+
+/*
+ * XXX Allow more than one X redirection?
+ */
+void
+redir_x(inaddr, start_port, display, screen)
+	u_int32_t inaddr;
+	int start_port;
+	int display;
+	int screen;
+{
+	int i;
+
+	if (x_port >= 0) {
+		lprint("X Redir: X already being redirected.\r\n");
+		show_x(0, 0);
+	} else {
+		for (i = 6001 + (start_port-1); i <= 6100; i++) {
+			if (solisten(htons(i), inaddr, htons(6000 + display), 0)) {
+				/* Success */
+				x_port = i - 6000;
+				x_display = display;
+				x_screen = screen;
+				show_x(0, 0);
+				return;
+			}
+		}
+		lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n");
+	}
+}
+#endif
+
+/*
+ * Get our IP address and put it in our_addr
+ */
+void
+getouraddr(void)
+{
+	char buff[256];
+	struct hostent *he = NULL;
+
+	if (gethostname(buff,256) == 0)
+            he = gethostbyname(buff);
+        if (he)
+            our_addr = *(struct in_addr *)he->h_addr;
+        if (our_addr.s_addr == 0)
+            our_addr.s_addr = loopback_addr.s_addr;
+}
+
+struct quehead {
+	struct quehead *qh_link;
+	struct quehead *qh_rlink;
+};
+
+inline void
+insque(void *a, void *b)
+{
+	register struct quehead *element = (struct quehead *) a;
+	register struct quehead *head = (struct quehead *) b;
+	element->qh_link = head->qh_link;
+	head->qh_link = (struct quehead *)element;
+	element->qh_rlink = (struct quehead *)head;
+	((struct quehead *)(element->qh_link))->qh_rlink
+	= (struct quehead *)element;
+}
+
+inline void
+remque(void *a)
+{
+  register struct quehead *element = (struct quehead *) a;
+  ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
+  ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
+  element->qh_rlink = NULL;
+  /*  element->qh_link = NULL;  TCP FIN1 crashes if you do this.  Why ? */
+}
+
+/* #endif */
+
+
+int
+add_exec(struct ex_list **ex_ptr, int do_pty, char *exec, int addr, int port)
+{
+	struct ex_list *tmp_ptr;
+
+	/* First, check if the port is "bound" */
+	for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
+		if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr)
+		   return -1;
+	}
+
+	tmp_ptr = *ex_ptr;
+	*ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
+	(*ex_ptr)->ex_fport = port;
+	(*ex_ptr)->ex_addr = addr;
+	(*ex_ptr)->ex_pty = do_pty;
+	(*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec);
+	(*ex_ptr)->ex_next = tmp_ptr;
+	return 0;
+}
+
+#ifndef HAVE_STRERROR
+
+/*
+ * For systems with no strerror
+ */
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(error)
+	int error;
+{
+	if (error < sys_nerr)
+	   return sys_errlist[error];
+	else
+	   return "Unknown error.";
+}
+
+#endif
+
+
+#ifdef _WIN32
+
+int
+fork_exec(struct socket *so, const char *ex, int do_pty)
+{
+    /* not implemented */
+    return 0;
+}
+
+#else
+
+#ifndef CONFIG_QEMU
+int
+slirp_openpty(amaster, aslave)
+     int *amaster, *aslave;
+{
+	register int master, slave;
+
+#ifdef HAVE_GRANTPT
+	char *ptr;
+
+	if ((master = open("/dev/ptmx", O_RDWR)) < 0 ||
+	    grantpt(master) < 0 ||
+	    unlockpt(master) < 0 ||
+	    (ptr = ptsname(master)) == NULL)  {
+		close(master);
+		return -1;
+	}
+
+	if ((slave = open(ptr, O_RDWR)) < 0 ||
+	    ioctl(slave, I_PUSH, "ptem") < 0 ||
+	    ioctl(slave, I_PUSH, "ldterm") < 0 ||
+	    ioctl(slave, I_PUSH, "ttcompat") < 0) {
+		close(master);
+		close(slave);
+		return -1;
+	}
+
+	*amaster = master;
+	*aslave = slave;
+	return 0;
+
+#else
+
+	static char line[] = "/dev/ptyXX";
+	register const char *cp1, *cp2;
+
+	for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
+		line[8] = *cp1;
+		for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
+			line[9] = *cp2;
+			if ((master = open(line, O_RDWR, 0)) == -1) {
+				if (errno == ENOENT)
+				   return (-1);    /* out of ptys */
+			} else {
+				line[5] = 't';
+				/* These will fail */
+				(void) chown(line, getuid(), 0);
+				(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
+#ifdef HAVE_REVOKE
+				(void) revoke(line);
+#endif
+				if ((slave = open(line, O_RDWR, 0)) != -1) {
+					*amaster = master;
+					*aslave = slave;
+					return 0;
+				}
+				(void) close(master);
+				line[5] = 'p';
+			}
+		}
+	}
+	errno = ENOENT; /* out of ptys */
+	return (-1);
+#endif
+}
+#endif
+
+/*
+ * XXX This is ugly
+ * We create and bind a socket, then fork off to another
+ * process, which connects to this socket, after which we
+ * exec the wanted program.  If something (strange) happens,
+ * the accept() call could block us forever.
+ *
+ * do_pty = 0   Fork/exec inetd style
+ * do_pty = 1   Fork/exec using slirp.telnetd
+ * do_ptr = 2   Fork/exec using pty
+ */
+int
+fork_exec(struct socket *so, const char *ex, int do_pty)
+{
+	int s;
+	struct sockaddr_in addr;
+	socklen_t addrlen = sizeof(addr);
+	int opt;
+        int master = -1;
+	const char *argv[256];
+#if 0
+	char buff[256];
+#endif
+	/* don't want to clobber the original */
+	char *bptr;
+	const char *curarg;
+	int c, i, ret;
+
+	DEBUG_CALL("fork_exec");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("ex = %lx", (long)ex);
+	DEBUG_ARG("do_pty = %lx", (long)do_pty);
+
+	if (do_pty == 2) {
+#if 0
+		if (slirp_openpty(&master, &s) == -1) {
+			lprint("Error: openpty failed: %s\n", strerror(errno));
+			return 0;
+		}
+#else
+                return 0;
+#endif
+	} else {
+		addr.sin_family = AF_INET;
+		addr.sin_port = 0;
+		addr.sin_addr.s_addr = INADDR_ANY;
+
+		if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
+		    bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
+		    listen(s, 1) < 0) {
+			lprint("Error: inet socket: %s\n", strerror(errno));
+			closesocket(s);
+
+			return 0;
+		}
+	}
+
+	switch(fork()) {
+	 case -1:
+		lprint("Error: fork failed: %s\n", strerror(errno));
+		close(s);
+		if (do_pty == 2)
+		   close(master);
+		return 0;
+
+	 case 0:
+		/* Set the DISPLAY */
+		if (do_pty == 2) {
+			(void) close(master);
+#ifdef TIOCSCTTY /* XXXXX */
+			(void) setsid();
+			ioctl(s, TIOCSCTTY, (char *)NULL);
+#endif
+		} else {
+			getsockname(s, (struct sockaddr *)&addr, &addrlen);
+			close(s);
+			/*
+			 * Connect to the socket
+			 * XXX If any of these fail, we're in trouble!
+	 		 */
+			s = socket(AF_INET, SOCK_STREAM, 0);
+			addr.sin_addr = loopback_addr;
+                        do {
+                            ret = connect(s, (struct sockaddr *)&addr, addrlen);
+                        } while (ret < 0 && errno == EINTR);
+		}
+
+#if 0
+		if (x_port >= 0) {
+#ifdef HAVE_SETENV
+			sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
+			setenv("DISPLAY", buff, 1);
+#else
+			sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
+			putenv(buff);
+#endif
+		}
+#endif
+		dup2(s, 0);
+		dup2(s, 1);
+		dup2(s, 2);
+		for (s = getdtablesize() - 1; s >= 3; s--)
+		   close(s);
+
+		i = 0;
+		bptr = strdup(ex); /* No need to free() this */
+		if (do_pty == 1) {
+			/* Setup "slirp.telnetd -x" */
+			argv[i++] = "slirp.telnetd";
+			argv[i++] = "-x";
+			argv[i++] = bptr;
+		} else
+		   do {
+			/* Change the string into argv[] */
+			curarg = bptr;
+			while (*bptr != ' ' && *bptr != (char)0)
+			   bptr++;
+			c = *bptr;
+			*bptr++ = (char)0;
+			argv[i++] = strdup(curarg);
+		   } while (c);
+
+                argv[i] = NULL;
+		execvp(argv[0], (char **)argv);
+
+		/* Ooops, failed, let's tell the user why */
+		  {
+			  char buff[256];
+
+			  snprintf(buff, sizeof(buff),
+                                   "Error: execvp of %s failed: %s\n",
+                                   argv[0], strerror(errno));
+			  write(2, buff, strlen(buff)+1);
+		  }
+		close(0); close(1); close(2); /* XXX */
+		exit(1);
+
+	 default:
+		if (do_pty == 2) {
+			close(s);
+			so->s = master;
+		} else {
+			/*
+			 * XXX this could block us...
+			 * XXX Should set a timer here, and if accept() doesn't
+		 	 * return after X seconds, declare it a failure
+		 	 * The only reason this will block forever is if socket()
+		 	 * of connect() fail in the child process
+		 	 */
+                        do {
+                            so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
+                        } while (so->s < 0 && errno == EINTR);
+                        closesocket(s);
+			opt = 1;
+			setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
+			opt = 1;
+			setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
+		}
+		fd_nonblock(so->s);
+
+		/* Append the telnet options now */
+                if (so->so_m != NULL && do_pty == 1)  {
+			sbappend(so, so->so_m);
+                        so->so_m = NULL;
+		}
+
+		return 1;
+	}
+}
+#endif
+
+#ifndef HAVE_STRDUP
+char *
+strdup(str)
+	const char *str;
+{
+	char *bptr;
+
+	bptr = (char *)malloc(strlen(str)+1);
+	strcpy(bptr, str);
+
+	return bptr;
+}
+#endif
+
+#if 0
+void
+snooze_hup(num)
+	int num;
+{
+	int s, ret;
+#ifndef NO_UNIX_SOCKETS
+	struct sockaddr_un sock_un;
+#endif
+	struct sockaddr_in sock_in;
+	char buff[256];
+
+	ret = -1;
+	if (slirp_socket_passwd) {
+		s = socket(AF_INET, SOCK_STREAM, 0);
+		if (s < 0)
+		   slirp_exit(1);
+		sock_in.sin_family = AF_INET;
+		sock_in.sin_addr.s_addr = slirp_socket_addr;
+		sock_in.sin_port = htons(slirp_socket_port);
+		if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0)
+		   slirp_exit(1); /* just exit...*/
+		sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit);
+		write(s, buff, strlen(buff)+1);
+	}
+#ifndef NO_UNIX_SOCKETS
+	  else {
+		s = socket(AF_UNIX, SOCK_STREAM, 0);
+		if (s < 0)
+		   slirp_exit(1);
+		sock_un.sun_family = AF_UNIX;
+		strcpy(sock_un.sun_path, socket_path);
+		if (connect(s, (struct sockaddr *)&sock_un,
+			      sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0)
+		   slirp_exit(1);
+		sprintf(buff, "kill none:%d", slirp_socket_unit);
+		write(s, buff, strlen(buff)+1);
+	}
+#endif
+	slirp_exit(0);
+}
+
+
+void
+snooze()
+{
+	sigset_t s;
+	int i;
+
+	/* Don't need our data anymore */
+	/* XXX This makes SunOS barf */
+/*	brk(0); */
+
+	/* Close all fd's */
+	for (i = 255; i >= 0; i--)
+	   close(i);
+
+	signal(SIGQUIT, slirp_exit);
+	signal(SIGHUP, snooze_hup);
+	sigemptyset(&s);
+
+	/* Wait for any signal */
+	sigsuspend(&s);
+
+	/* Just in case ... */
+	exit(255);
+}
+
+void
+relay(s)
+	int s;
+{
+	char buf[8192];
+	int n;
+	fd_set readfds;
+	struct ttys *ttyp;
+
+	/* Don't need our data anymore */
+	/* XXX This makes SunOS barf */
+/*	brk(0); */
+
+	signal(SIGQUIT, slirp_exit);
+	signal(SIGHUP, slirp_exit);
+        signal(SIGINT, slirp_exit);
+	signal(SIGTERM, slirp_exit);
+
+	/* Fudge to get term_raw and term_restore to work */
+	if (NULL == (ttyp = tty_attach (0, slirp_tty))) {
+         lprint ("Error: tty_attach failed in misc.c:relay()\r\n");
+         slirp_exit (1);
+    }
+	ttyp->fd = 0;
+	ttyp->flags |= TTY_CTTY;
+	term_raw(ttyp);
+
+	while (1) {
+		FD_ZERO(&readfds);
+
+		FD_SET(0, &readfds);
+		FD_SET(s, &readfds);
+
+		n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
+
+		if (n <= 0)
+		   slirp_exit(0);
+
+		if (FD_ISSET(0, &readfds)) {
+			n = read(0, buf, 8192);
+			if (n <= 0)
+			   slirp_exit(0);
+			n = writen(s, buf, n);
+			if (n <= 0)
+			   slirp_exit(0);
+		}
+
+		if (FD_ISSET(s, &readfds)) {
+			n = read(s, buf, 8192);
+			if (n <= 0)
+			   slirp_exit(0);
+			n = writen(0, buf, n);
+			if (n <= 0)
+			   slirp_exit(0);
+		}
+	}
+
+	/* Just in case.... */
+	exit(1);
+}
+#endif
+
+#ifdef CONFIG_QEMU
+#include "monitor.h"
+
+void lprint(const char *format, ...)
+{
+    va_list args;
+
+    va_start(args, format);
+    monitor_vprintf(cur_mon, format, args);
+    va_end(args);
+}
+#else
+int (*lprint_print) _P((void *, const char *, va_list));
+char *lprint_ptr, *lprint_ptr2, **lprint_arg;
+
+void
+#ifdef __STDC__
+lprint(const char *format, ...)
+#else
+lprint(va_alist) va_dcl
+#endif
+{
+	va_list args;
+
+#ifdef __STDC__
+        va_start(args, format);
+#else
+        char *format;
+        va_start(args);
+        format = va_arg(args, char *);
+#endif
+#if 0
+	/* If we're printing to an sbuf, make sure there's enough room */
+	/* XXX +100? */
+	if (lprint_sb) {
+		if ((lprint_ptr - lprint_sb->sb_wptr) >=
+		    (lprint_sb->sb_datalen - (strlen(format) + 100))) {
+			int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data;
+			int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data;
+			int deltap = lprint_ptr -         lprint_sb->sb_data;
+
+			lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data,
+							     lprint_sb->sb_datalen + TCP_SNDSPACE);
+
+			/* Adjust all values */
+			lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw;
+			lprint_sb->sb_rptr = lprint_sb->sb_data + deltar;
+			lprint_ptr =         lprint_sb->sb_data + deltap;
+
+			lprint_sb->sb_datalen += TCP_SNDSPACE;
+		}
+	}
+#endif
+	if (lprint_print)
+	   lprint_ptr += (*lprint_print)(*lprint_arg, format, args);
+
+	/* Check if they want output to be logged to file as well */
+	if (lfd) {
+		/*
+		 * Remove \r's
+		 * otherwise you'll get ^M all over the file
+		 */
+		int len = strlen(format);
+		char *bptr1, *bptr2;
+
+		bptr1 = bptr2 = strdup(format);
+
+		while (len--) {
+			if (*bptr1 == '\r')
+			   memcpy(bptr1, bptr1+1, len+1);
+			else
+			   bptr1++;
+		}
+		vfprintf(lfd, bptr2, args);
+		free(bptr2);
+	}
+	va_end(args);
+}
+
+void
+add_emu(buff)
+	char *buff;
+{
+	u_int lport, fport;
+	u_int8_t tos = 0, emu = 0;
+	char buff1[256], buff2[256], buff4[128];
+	char *buff3 = buff4;
+	struct emu_t *emup;
+	struct socket *so;
+
+	if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) {
+		lprint("Error: Bad arguments\r\n");
+		return;
+	}
+
+	if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) {
+		lport = 0;
+		if (sscanf(buff1, "%d", &fport) != 1) {
+			lprint("Error: Bad first argument\r\n");
+			return;
+		}
+	}
+
+	if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) {
+		buff3 = 0;
+		if (sscanf(buff2, "%256s", buff1) != 1) {
+			lprint("Error: Bad second argument\r\n");
+			return;
+		}
+	}
+
+	if (buff3) {
+		if (strcmp(buff3, "lowdelay") == 0)
+		   tos = IPTOS_LOWDELAY;
+		else if (strcmp(buff3, "throughput") == 0)
+		   tos = IPTOS_THROUGHPUT;
+		else {
+			lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n");
+			return;
+		}
+	}
+
+	if (strcmp(buff1, "ftp") == 0)
+	   emu = EMU_FTP;
+	else if (strcmp(buff1, "irc") == 0)
+	   emu = EMU_IRC;
+	else if (strcmp(buff1, "none") == 0)
+	   emu = EMU_NONE; /* ie: no emulation */
+	else {
+		lprint("Error: Unknown service\r\n");
+		return;
+	}
+
+	/* First, check that it isn't already emulated */
+	for (emup = tcpemu; emup; emup = emup->next) {
+		if (emup->lport == lport && emup->fport == fport) {
+			lprint("Error: port already emulated\r\n");
+			return;
+		}
+	}
+
+	/* link it */
+	emup = (struct emu_t *)malloc(sizeof (struct emu_t));
+	emup->lport = (u_int16_t)lport;
+	emup->fport = (u_int16_t)fport;
+	emup->tos = tos;
+	emup->emu = emu;
+	emup->next = tcpemu;
+	tcpemu = emup;
+
+	/* And finally, mark all current sessions, if any, as being emulated */
+	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
+		if ((lport && lport == ntohs(so->so_lport)) ||
+		    (fport && fport == ntohs(so->so_fport))) {
+			if (emu)
+			   so->so_emu = emu;
+			if (tos)
+			   so->so_iptos = tos;
+		}
+	}
+
+	lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport);
+}
+#endif
+
+#ifdef BAD_SPRINTF
+
+#undef vsprintf
+#undef sprintf
+
+/*
+ * Some BSD-derived systems have a sprintf which returns char *
+ */
+
+int
+vsprintf_len(string, format, args)
+	char *string;
+	const char *format;
+	va_list args;
+{
+	vsprintf(string, format, args);
+	return strlen(string);
+}
+
+int
+#ifdef __STDC__
+sprintf_len(char *string, const char *format, ...)
+#else
+sprintf_len(va_alist) va_dcl
+#endif
+{
+	va_list args;
+#ifdef __STDC__
+	va_start(args, format);
+#else
+	char *string;
+	char *format;
+	va_start(args);
+	string = va_arg(args, char *);
+	format = va_arg(args, char *);
+#endif
+	vsprintf(string, format, args);
+	return strlen(string);
+}
+
+#endif
+
+void
+u_sleep(int usec)
+{
+	struct timeval t;
+	fd_set fdset;
+
+	FD_ZERO(&fdset);
+
+	t.tv_sec = 0;
+	t.tv_usec = usec * 1000;
+
+	select(0, &fdset, &fdset, &fdset, &t);
+}
+
+/*
+ * Set fd blocking and non-blocking
+ */
+
+void
+fd_nonblock(int fd)
+{
+#ifdef FIONBIO
+#ifdef _WIN32
+        unsigned long opt = 1;
+#else
+        int opt = 1;
+#endif
+
+	ioctlsocket(fd, FIONBIO, &opt);
+#else
+	int opt;
+
+	opt = fcntl(fd, F_GETFL, 0);
+	opt |= O_NONBLOCK;
+	fcntl(fd, F_SETFL, opt);
+#endif
+}
+
+void
+fd_block(int fd)
+{
+#ifdef FIONBIO
+#ifdef _WIN32
+        unsigned long opt = 0;
+#else
+	int opt = 0;
+#endif
+
+	ioctlsocket(fd, FIONBIO, &opt);
+#else
+	int opt;
+
+	opt = fcntl(fd, F_GETFL, 0);
+	opt &= ~O_NONBLOCK;
+	fcntl(fd, F_SETFL, opt);
+#endif
+}
+
+
+#if 0
+/*
+ * invoke RSH
+ */
+int
+rsh_exec(so,ns, user, host, args)
+	struct socket *so;
+	struct socket *ns;
+	char *user;
+	char *host;
+	char *args;
+{
+	int fd[2];
+	int fd0[2];
+	int s;
+	char buff[256];
+
+	DEBUG_CALL("rsh_exec");
+	DEBUG_ARG("so = %lx", (long)so);
+
+	if (pipe(fd)<0) {
+          lprint("Error: pipe failed: %s\n", strerror(errno));
+          return 0;
+	}
+/* #ifdef HAVE_SOCKETPAIR */
+#if 1
+        if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) {
+          close(fd[0]);
+          close(fd[1]);
+          lprint("Error: openpty failed: %s\n", strerror(errno));
+          return 0;
+        }
+#else
+        if (slirp_openpty(&fd0[0], &fd0[1]) == -1) {
+          close(fd[0]);
+          close(fd[1]);
+          lprint("Error: openpty failed: %s\n", strerror(errno));
+          return 0;
+        }
+#endif
+
+	switch(fork()) {
+	 case -1:
+           lprint("Error: fork failed: %s\n", strerror(errno));
+           close(fd[0]);
+           close(fd[1]);
+           close(fd0[0]);
+           close(fd0[1]);
+           return 0;
+
+	 case 0:
+           close(fd[0]);
+           close(fd0[0]);
+
+		/* Set the DISPLAY */
+           if (x_port >= 0) {
+#ifdef HAVE_SETENV
+             sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
+             setenv("DISPLAY", buff, 1);
+#else
+             sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
+             putenv(buff);
+#endif
+           }
+
+           dup2(fd0[1], 0);
+           dup2(fd0[1], 1);
+           dup2(fd[1], 2);
+           for (s = 3; s <= 255; s++)
+             close(s);
+
+           execlp("rsh","rsh","-l", user, host, args, NULL);
+
+           /* Ooops, failed, let's tell the user why */
+
+           sprintf(buff, "Error: execlp of %s failed: %s\n",
+                   "rsh", strerror(errno));
+           write(2, buff, strlen(buff)+1);
+           close(0); close(1); close(2); /* XXX */
+           exit(1);
+
+        default:
+          close(fd[1]);
+          close(fd0[1]);
+          ns->s=fd[0];
+          so->s=fd0[0];
+
+          return 1;
+	}
+}
+#endif
diff --git a/slirp/misc.h b/slirp/misc.h
new file mode 100644
index 0000000..ab8e3a7
--- /dev/null
+++ b/slirp/misc.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _MISC_H_
+#define _MISC_H_
+
+struct ex_list {
+	int ex_pty;			/* Do we want a pty? */
+	int ex_addr;			/* The last byte of the address */
+	int ex_fport;                   /* Port to telnet to */
+	const char *ex_exec;            /* Command line of what to exec */
+	struct ex_list *ex_next;
+};
+
+extern struct ex_list *exec_list;
+extern u_int time_fasttimo, last_slowtimo;
+
+extern int (*lprint_print) _P((void *, const char *, va_list));
+extern char *lprint_ptr, *lprint_ptr2, **lprint_arg;
+extern struct sbuf *lprint_sb;
+
+#ifndef HAVE_STRDUP
+char *strdup _P((const char *));
+#endif
+
+void do_wait _P((int));
+
+#define EMU_NONE 0x0
+
+/* TCP emulations */
+#define EMU_CTL 0x1
+#define EMU_FTP 0x2
+#define EMU_KSH 0x3
+#define EMU_IRC 0x4
+#define EMU_REALAUDIO 0x5
+#define EMU_RLOGIN 0x6
+#define EMU_IDENT 0x7
+#define EMU_RSH 0x8
+
+#define EMU_NOCONNECT 0x10	/* Don't connect */
+
+/* UDP emulations */
+#define EMU_TALK	0x1
+#define EMU_NTALK	0x2
+#define EMU_CUSEEME	0x3
+
+struct tos_t {
+	u_int16_t lport;
+	u_int16_t fport;
+	u_int8_t tos;
+	u_int8_t emu;
+};
+
+struct emu_t {
+	u_int16_t lport;
+	u_int16_t fport;
+	u_int8_t tos;
+	u_int8_t emu;
+	struct emu_t *next;
+};
+
+#ifndef CONFIG_QEMU
+extern struct emu_t *tcpemu;
+#endif
+
+extern int x_port, x_server, x_display;
+
+int show_x _P((char *, struct socket *));
+void redir_x _P((u_int32_t, int, int, int));
+void getouraddr _P((void));
+void slirp_insque _P((void *, void *));
+void slirp_remque _P((void *));
+int add_exec _P((struct ex_list **, int, char *, int, int));
+int slirp_openpty _P((int *, int *));
+int fork_exec(struct socket *so, const char *ex, int do_pty);
+void snooze_hup _P((int));
+void snooze _P((void));
+void relay _P((int));
+void add_emu _P((char *));
+void u_sleep _P((int));
+void fd_nonblock _P((int));
+void fd_block _P((int));
+int rsh_exec _P((struct socket *, struct socket *, char *, char *, char *));
+
+#endif
diff --git a/slirp2/sbuf.c b/slirp/sbuf.c
similarity index 69%
copy from slirp2/sbuf.c
copy to slirp/sbuf.c
index abececa..5375414 100644
--- a/slirp2/sbuf.c
+++ b/slirp/sbuf.c
@@ -1,24 +1,34 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
 #include <slirp.h>
 
+static void sbappendsb(struct sbuf *sb, struct mbuf *m);
+
+/* Done as a macro in socket.h */
+/* int
+ * sbspace(struct sockbuff *sb)
+ * {
+ *	return SB_DATALEN - sb->sb_cc;
+ * }
+ */
+
 void
-sbuf_free(SBuf  sb)
+sbfree(struct sbuf *sb)
 {
 	free(sb->sb_data);
 }
 
 void
-sbuf_drop(SBuf  sb, int  num)
+sbdrop(struct sbuf *sb, int num)
 {
-	/* 
+	/*
 	 * We can only drop how much we have
-	 * This should never succeed 
+	 * This should never succeed
 	 */
 	if(num > sb->sb_cc)
 		num = sb->sb_cc;
@@ -26,21 +36,30 @@
 	sb->sb_rptr += num;
 	if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
 		sb->sb_rptr -= sb->sb_datalen;
-   
+
 }
 
 void
-sbuf_reserve(SBuf  sb, int  size)
+sbreserve(struct sbuf *sb, int size)
 {
-    if (sb->sb_datalen == size)
-        return;
-
-    sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
-    sb->sb_cc = 0;
-    if (sb->sb_wptr)
-       sb->sb_datalen = size;
-    else
-       sb->sb_datalen = 0;
+	if (sb->sb_data) {
+		/* Already alloced, realloc if necessary */
+		if (sb->sb_datalen != size) {
+			sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
+			sb->sb_cc = 0;
+			if (sb->sb_wptr)
+			   sb->sb_datalen = size;
+			else
+			   sb->sb_datalen = 0;
+		}
+	} else {
+		sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
+		sb->sb_cc = 0;
+		if (sb->sb_wptr)
+		   sb->sb_datalen = size;
+		else
+		   sb->sb_datalen = 0;
+	}
 }
 
 /*
@@ -50,71 +69,70 @@
  * (the socket is non-blocking, so we won't hang)
  */
 void
-sbuf_append(struct socket *so, MBuf  m)
+sbappend(struct socket *so, struct mbuf *m)
 {
 	int ret = 0;
 
-	DEBUG_CALL("sbuf_append");
+	DEBUG_CALL("sbappend");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m = %lx", (long)m);
 	DEBUG_ARG("m->m_len = %d", m->m_len);
-	
+
 	/* Shouldn't happen, but...  e.g. foreign host closes connection */
 	if (m->m_len <= 0) {
-		mbuf_free(m);
+		m_free(m);
 		return;
 	}
-	
+
 	/*
 	 * If there is urgent data, call sosendoob
 	 * if not all was sent, sowrite will take care of the rest
 	 * (The rest of this function is just an optimisation)
 	 */
 	if (so->so_urgc) {
-		sbuf_appendsb(&so->so_rcv, m);
-		mbuf_free(m);
+		sbappendsb(&so->so_rcv, m);
+		m_free(m);
 		sosendoob(so);
 		return;
 	}
-	
+
 	/*
 	 * We only write if there's nothing in the buffer,
 	 * ottherwise it'll arrive out of order, and hence corrupt
 	 */
-	if (!so->so_rcv.sb_cc) {
-	   ret = socket_send(so->s, m->m_data, m->m_len);
-        }
+	if (!so->so_rcv.sb_cc)
+	   ret = slirp_send(so, m->m_data, m->m_len, 0);
 
 	if (ret <= 0) {
-		/* 
+		/*
 		 * Nothing was written
 		 * It's possible that the socket has closed, but
 		 * we don't need to check because if it has closed,
 		 * it will be detected in the normal way by soread()
 		 */
-		sbuf_appendsb(&so->so_rcv, m);
+		sbappendsb(&so->so_rcv, m);
 	} else if (ret != m->m_len) {
 		/*
 		 * Something was written, but not everything..
-		 * sbuf_appendsb the rest
+		 * sbappendsb the rest
 		 */
 		m->m_len -= ret;
 		m->m_data += ret;
-		sbuf_appendsb(&so->so_rcv, m);
+		sbappendsb(&so->so_rcv, m);
 	} /* else */
 	/* Whatever happened, we free the mbuf */
-	mbuf_free(m);
+	m_free(m);
 }
 
 /*
  * Copy the data from m into sb
  * The caller is responsible to make sure there's enough room
  */
-void
-sbuf_appendsb(SBuf  sb, MBuf  m)
+static void
+sbappendsb(struct sbuf *sb, struct mbuf *m)
 {
 	int len, n,  nn;
-	
+
 	len = m->m_len;
 
 	if (sb->sb_wptr < sb->sb_rptr) {
@@ -136,7 +154,7 @@
 		}
 	}
 
-	sb->sb_cc   += n;
+	sb->sb_cc += n;
 	sb->sb_wptr += n;
 	if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
 		sb->sb_wptr -= sb->sb_datalen;
@@ -148,10 +166,10 @@
  * done in sbdrop when the data is acked
  */
 void
-sbuf_copy(SBuf  sb, int  off, int  len, char*  to)
+sbcopy(struct sbuf *sb, int off, int len, char *to)
 {
 	char *from;
-	
+
 	from = sb->sb_rptr + off;
 	if (from >= sb->sb_data + sb->sb_datalen)
 		from -= sb->sb_datalen;
@@ -169,4 +187,3 @@
 		   memcpy(to+off,sb->sb_data,len);
 	}
 }
-		
diff --git a/slirp/sbuf.h b/slirp/sbuf.h
new file mode 100644
index 0000000..a4f1036
--- /dev/null
+++ b/slirp/sbuf.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _SBUF_H_
+#define _SBUF_H_
+
+#define sbflush(sb) sbdrop((sb),(sb)->sb_cc)
+#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
+
+struct sbuf {
+	u_int	sb_cc;		/* actual chars in buffer */
+	u_int	sb_datalen;	/* Length of data  */
+	char	*sb_wptr;	/* write pointer. points to where the next
+				 * bytes should be written in the sbuf */
+	char	*sb_rptr;	/* read pointer. points to where the next
+				 * byte should be read from the sbuf */
+	char	*sb_data;	/* Actual data */
+};
+
+void sbfree _P((struct sbuf *));
+void sbdrop _P((struct sbuf *, int));
+void sbreserve _P((struct sbuf *, int));
+void sbappend _P((struct socket *, struct mbuf *));
+void sbcopy _P((struct sbuf *, int, int, char *));
+
+#endif
diff --git a/slirp/slirp.c b/slirp/slirp.c
new file mode 100644
index 0000000..30d4ee2
--- /dev/null
+++ b/slirp/slirp.c
@@ -0,0 +1,1086 @@
+/*
+ * libslirp glue
+ *
+ * Copyright (c) 2004-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "qemu-char.h"
+#include "slirp.h"
+#include "hw/hw.h"
+
+/* host address */
+struct in_addr our_addr;
+/* host dns address */
+struct in_addr dns_addr;
+/* host loopback address */
+struct in_addr loopback_addr;
+
+/* address for slirp virtual addresses */
+struct in_addr special_addr;
+/* virtual address alias for host */
+struct in_addr alias_addr;
+
+static const uint8_t special_ethaddr[6] = {
+    0x52, 0x54, 0x00, 0x12, 0x35, 0x00
+};
+
+/* ARP cache for the guest IP addresses (XXX: allow many entries) */
+uint8_t client_ethaddr[6];
+static struct in_addr client_ipaddr;
+
+static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
+
+const char *slirp_special_ip = CTL_SPECIAL;
+int slirp_restrict;
+static int do_slowtimo;
+int link_up;
+struct timeval tt;
+FILE *lfd;
+struct ex_list *exec_list;
+
+/* XXX: suppress those select globals */
+fd_set *global_readfds, *global_writefds, *global_xfds;
+
+char slirp_hostname[33];
+
+#ifdef _WIN32
+
+static int get_dns_addr(struct in_addr *pdns_addr)
+{
+    FIXED_INFO *FixedInfo=NULL;
+    ULONG    BufLen;
+    DWORD    ret;
+    IP_ADDR_STRING *pIPAddr;
+    struct in_addr tmp_addr;
+
+    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
+    BufLen = sizeof(FIXED_INFO);
+
+    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        FixedInfo = GlobalAlloc(GPTR, BufLen);
+    }
+
+    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
+        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        return -1;
+    }
+
+    pIPAddr = &(FixedInfo->DnsServerList);
+    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
+    *pdns_addr = tmp_addr;
+#if 0
+    printf( "DNS Servers:\n" );
+    printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
+
+    pIPAddr = FixedInfo -> DnsServerList.Next;
+    while ( pIPAddr ) {
+            printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
+            pIPAddr = pIPAddr ->Next;
+    }
+#endif
+    if (FixedInfo) {
+        GlobalFree(FixedInfo);
+        FixedInfo = NULL;
+    }
+    return 0;
+}
+
+#else
+
+static int get_dns_addr(struct in_addr *pdns_addr)
+{
+    char buff[512];
+    char buff2[257];
+    FILE *f;
+    int found = 0;
+    struct in_addr tmp_addr;
+
+    f = fopen("/etc/resolv.conf", "r");
+    if (!f)
+        return -1;
+
+#ifdef DEBUG
+    lprint("IP address of your DNS(s): ");
+#endif
+    while (fgets(buff, 512, f) != NULL) {
+        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
+            if (!inet_aton(buff2, &tmp_addr))
+                continue;
+            if (tmp_addr.s_addr == loopback_addr.s_addr)
+                tmp_addr = our_addr;
+            /* If it's the first one, set it to dns_addr */
+            if (!found)
+                *pdns_addr = tmp_addr;
+#ifdef DEBUG
+            else
+                lprint(", ");
+#endif
+            if (++found > 3) {
+#ifdef DEBUG
+                lprint("(more)");
+#endif
+                break;
+            }
+#ifdef DEBUG
+            else
+                lprint("%s", inet_ntoa(tmp_addr));
+#endif
+        }
+    }
+    fclose(f);
+    if (!found)
+        return -1;
+    return 0;
+}
+
+#endif
+
+#ifdef _WIN32
+static void slirp_cleanup(void)
+{
+    WSACleanup();
+}
+#endif
+
+static void slirp_state_save(QEMUFile *f, void *opaque);
+static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
+
+void slirp_init(int restricted, const char *special_ip)
+{
+    //    debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
+
+#ifdef _WIN32
+    {
+        WSADATA Data;
+        WSAStartup(MAKEWORD(2,0), &Data);
+	atexit(slirp_cleanup);
+    }
+#endif
+
+    link_up = 1;
+    slirp_restrict = restricted;
+
+    if_init();
+    ip_init();
+
+    /* Initialise mbufs *after* setting the MTU */
+    m_init();
+
+    /* set default addresses */
+    inet_aton("127.0.0.1", &loopback_addr);
+
+    if (get_dns_addr(&dns_addr) < 0) {
+        dns_addr = loopback_addr;
+        fprintf (stderr, "Warning: No DNS servers found\n");
+    }
+
+    if (special_ip)
+        slirp_special_ip = special_ip;
+
+    inet_aton(slirp_special_ip, &special_addr);
+    alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
+    getouraddr();
+    register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
+}
+
+#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
+#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
+
+/*
+ * curtime kept to an accuracy of 1ms
+ */
+#ifdef _WIN32
+static void updtime(void)
+{
+    struct _timeb tb;
+
+    _ftime(&tb);
+    curtime = (u_int)tb.time * (u_int)1000;
+    curtime += (u_int)tb.millitm;
+}
+#else
+static void updtime(void)
+{
+        gettimeofday(&tt, NULL);
+
+	curtime = (u_int)tt.tv_sec * (u_int)1000;
+	curtime += (u_int)tt.tv_usec / (u_int)1000;
+
+	if ((tt.tv_usec % 1000) >= 500)
+	   curtime++;
+}
+#endif
+
+void slirp_select_fill(int *pnfds,
+                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
+{
+    struct socket *so, *so_next;
+    struct timeval timeout;
+    int nfds;
+    int tmp_time;
+
+    /* fail safe */
+    global_readfds = NULL;
+    global_writefds = NULL;
+    global_xfds = NULL;
+
+    nfds = *pnfds;
+	/*
+	 * First, TCP sockets
+	 */
+	do_slowtimo = 0;
+	if (link_up) {
+		/*
+		 * *_slowtimo needs calling if there are IP fragments
+		 * in the fragment queue, or there are TCP connections active
+		 */
+		do_slowtimo = ((tcb.so_next != &tcb) ||
+                (&ipq.ip_link != ipq.ip_link.next));
+
+		for (so = tcb.so_next; so != &tcb; so = so_next) {
+			so_next = so->so_next;
+
+			/*
+			 * See if we need a tcp_fasttimo
+			 */
+			if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
+			   time_fasttimo = curtime; /* Flag when we want a fasttimo */
+
+			/*
+			 * NOFDREF can include still connecting to local-host,
+			 * newly socreated() sockets etc. Don't want to select these.
+	 		 */
+			if (so->so_state & SS_NOFDREF || so->s == -1)
+			   continue;
+
+			/*
+			 * Set for reading sockets which are accepting
+			 */
+			if (so->so_state & SS_FACCEPTCONN) {
+                                FD_SET(so->s, readfds);
+				UPD_NFDS(so->s);
+				continue;
+			}
+
+			/*
+			 * Set for writing sockets which are connecting
+			 */
+			if (so->so_state & SS_ISFCONNECTING) {
+				FD_SET(so->s, writefds);
+				UPD_NFDS(so->s);
+				continue;
+			}
+
+			/*
+			 * Set for writing if we are connected, can send more, and
+			 * we have something to send
+			 */
+			if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+				FD_SET(so->s, writefds);
+				UPD_NFDS(so->s);
+			}
+
+			/*
+			 * Set for reading (and urgent data) if we are connected, can
+			 * receive more, and we have room for it XXX /2 ?
+			 */
+			if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+				FD_SET(so->s, readfds);
+				FD_SET(so->s, xfds);
+				UPD_NFDS(so->s);
+			}
+		}
+
+		/*
+		 * UDP sockets
+		 */
+		for (so = udb.so_next; so != &udb; so = so_next) {
+			so_next = so->so_next;
+
+			/*
+			 * See if it's timed out
+			 */
+			if (so->so_expire) {
+				if (so->so_expire <= curtime) {
+					udp_detach(so);
+					continue;
+				} else
+					do_slowtimo = 1; /* Let socket expire */
+			}
+
+			/*
+			 * When UDP packets are received from over the
+			 * link, they're sendto()'d straight away, so
+			 * no need for setting for writing
+			 * Limit the number of packets queued by this session
+			 * to 4.  Note that even though we try and limit this
+			 * to 4 packets, the session could have more queued
+			 * if the packets needed to be fragmented
+			 * (XXX <= 4 ?)
+			 */
+			if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
+				FD_SET(so->s, readfds);
+				UPD_NFDS(so->s);
+			}
+		}
+	}
+
+	/*
+	 * Setup timeout to use minimum CPU usage, especially when idle
+	 */
+
+	/*
+	 * First, see the timeout needed by *timo
+	 */
+	timeout.tv_sec = 0;
+	timeout.tv_usec = -1;
+	/*
+	 * If a slowtimo is needed, set timeout to 500ms from the last
+	 * slow timeout. If a fast timeout is needed, set timeout within
+	 * 200ms of when it was requested.
+	 */
+	if (do_slowtimo) {
+		/* XXX + 10000 because some select()'s aren't that accurate */
+		timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
+		if (timeout.tv_usec < 0)
+		   timeout.tv_usec = 0;
+		else if (timeout.tv_usec > 510000)
+		   timeout.tv_usec = 510000;
+
+		/* Can only fasttimo if we also slowtimo */
+		if (time_fasttimo) {
+			tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
+			if (tmp_time < 0)
+			   tmp_time = 0;
+
+			/* Choose the smallest of the 2 */
+			if (tmp_time < timeout.tv_usec)
+			   timeout.tv_usec = (u_int)tmp_time;
+		}
+	}
+        *pnfds = nfds;
+}
+
+void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
+{
+    struct socket *so, *so_next;
+    int ret;
+
+    global_readfds = readfds;
+    global_writefds = writefds;
+    global_xfds = xfds;
+
+	/* Update time */
+	updtime();
+
+	/*
+	 * See if anything has timed out
+	 */
+	if (link_up) {
+		if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
+			tcp_fasttimo();
+			time_fasttimo = 0;
+		}
+		if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
+			ip_slowtimo();
+			tcp_slowtimo();
+			last_slowtimo = curtime;
+		}
+	}
+
+	/*
+	 * Check sockets
+	 */
+	if (link_up) {
+		/*
+		 * Check TCP sockets
+		 */
+		for (so = tcb.so_next; so != &tcb; so = so_next) {
+			so_next = so->so_next;
+
+			/*
+			 * FD_ISSET is meaningless on these sockets
+			 * (and they can crash the program)
+			 */
+			if (so->so_state & SS_NOFDREF || so->s == -1)
+			   continue;
+
+			/*
+			 * Check for URG data
+			 * This will soread as well, so no need to
+			 * test for readfds below if this succeeds
+			 */
+			if (FD_ISSET(so->s, xfds))
+			   sorecvoob(so);
+			/*
+			 * Check sockets for reading
+			 */
+			else if (FD_ISSET(so->s, readfds)) {
+				/*
+				 * Check for incoming connections
+				 */
+				if (so->so_state & SS_FACCEPTCONN) {
+					tcp_connect(so);
+					continue;
+				} /* else */
+				ret = soread(so);
+
+				/* Output it if we read something */
+				if (ret > 0)
+				   tcp_output(sototcpcb(so));
+			}
+
+			/*
+			 * Check sockets for writing
+			 */
+			if (FD_ISSET(so->s, writefds)) {
+			  /*
+			   * Check for non-blocking, still-connecting sockets
+			   */
+			  if (so->so_state & SS_ISFCONNECTING) {
+			    /* Connected */
+			    so->so_state &= ~SS_ISFCONNECTING;
+
+			    ret = send(so->s, (const void *) &ret, 0, 0);
+			    if (ret < 0) {
+			      /* XXXXX Must fix, zero bytes is a NOP */
+			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				  errno == EINPROGRESS || errno == ENOTCONN)
+				continue;
+
+			      /* else failed */
+			      so->so_state = SS_NOFDREF;
+			    }
+			    /* else so->so_state &= ~SS_ISFCONNECTING; */
+
+			    /*
+			     * Continue tcp_input
+			     */
+			    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+			    /* continue; */
+			  } else
+			    ret = sowrite(so);
+			  /*
+			   * XXXXX If we wrote something (a lot), there
+			   * could be a need for a window update.
+			   * In the worst case, the remote will send
+			   * a window probe to get things going again
+			   */
+			}
+
+			/*
+			 * Probe a still-connecting, non-blocking socket
+			 * to check if it's still alive
+	 	 	 */
+#ifdef PROBE_CONN
+			if (so->so_state & SS_ISFCONNECTING) {
+			  ret = recv(so->s, (char *)&ret, 0,0);
+
+			  if (ret < 0) {
+			    /* XXX */
+			    if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				errno == EINPROGRESS || errno == ENOTCONN)
+			      continue; /* Still connecting, continue */
+
+			    /* else failed */
+			    so->so_state = SS_NOFDREF;
+
+			    /* tcp_input will take care of it */
+			  } else {
+			    ret = send(so->s, &ret, 0,0);
+			    if (ret < 0) {
+			      /* XXX */
+			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
+				  errno == EINPROGRESS || errno == ENOTCONN)
+				continue;
+			      /* else failed */
+			      so->so_state = SS_NOFDREF;
+			    } else
+			      so->so_state &= ~SS_ISFCONNECTING;
+
+			  }
+			  tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
+			} /* SS_ISFCONNECTING */
+#endif
+		}
+
+		/*
+		 * Now UDP sockets.
+		 * Incoming packets are sent straight away, they're not buffered.
+		 * Incoming UDP data isn't buffered either.
+		 */
+		for (so = udb.so_next; so != &udb; so = so_next) {
+			so_next = so->so_next;
+
+			if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                            sorecvfrom(so);
+                        }
+		}
+	}
+
+	/*
+	 * See if we can start outputting
+	 */
+	if (if_queued && link_up)
+	   if_start();
+
+	/* clear global file descriptor sets.
+	 * these reside on the stack in vl.c
+	 * so they're unusable if we're not in
+	 * slirp_select_fill or slirp_select_poll.
+	 */
+	 global_readfds = NULL;
+	 global_writefds = NULL;
+	 global_xfds = NULL;
+}
+
+#define ETH_ALEN 6
+#define ETH_HLEN 14
+
+#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
+#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
+
+#define	ARPOP_REQUEST	1		/* ARP request			*/
+#define	ARPOP_REPLY	2		/* ARP reply			*/
+
+struct ethhdr
+{
+	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+	unsigned short	h_proto;		/* packet type ID field	*/
+};
+
+struct arphdr
+{
+	unsigned short	ar_hrd;		/* format of hardware address	*/
+	unsigned short	ar_pro;		/* format of protocol address	*/
+	unsigned char	ar_hln;		/* length of hardware address	*/
+	unsigned char	ar_pln;		/* length of protocol address	*/
+	unsigned short	ar_op;		/* ARP opcode (command)		*/
+
+	 /*
+	  *	 Ethernet looks like this : This bit is variable sized however...
+	  */
+	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
+	unsigned char		ar_sip[4];		/* sender IP address		*/
+	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
+	unsigned char		ar_tip[4];		/* target IP address		*/
+};
+
+static void arp_input(const uint8_t *pkt, int pkt_len)
+{
+    struct ethhdr *eh = (struct ethhdr *)pkt;
+    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
+    uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
+    struct ethhdr *reh = (struct ethhdr *)arp_reply;
+    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
+    int ar_op;
+    struct ex_list *ex_ptr;
+
+    ar_op = ntohs(ah->ar_op);
+    switch(ar_op) {
+    case ARPOP_REQUEST:
+        if (!memcmp(ah->ar_tip, &special_addr, 3)) {
+            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
+                goto arp_ok;
+            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+                if (ex_ptr->ex_addr == ah->ar_tip[3])
+                    goto arp_ok;
+            }
+            return;
+        arp_ok:
+            /* XXX: make an ARP request to have the client address */
+            memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
+
+            /* ARP request for alias/dns mac address */
+            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
+            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
+            reh->h_source[5] = ah->ar_tip[3];
+            reh->h_proto = htons(ETH_P_ARP);
+
+            rah->ar_hrd = htons(1);
+            rah->ar_pro = htons(ETH_P_IP);
+            rah->ar_hln = ETH_ALEN;
+            rah->ar_pln = 4;
+            rah->ar_op = htons(ARPOP_REPLY);
+            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
+            memcpy(rah->ar_sip, ah->ar_tip, 4);
+            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
+            memcpy(rah->ar_tip, ah->ar_sip, 4);
+            slirp_output(arp_reply, sizeof(arp_reply));
+        }
+        break;
+    case ARPOP_REPLY:
+        /* reply to request of client mac address ? */
+        if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
+            !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
+            memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+void slirp_input(const uint8_t *pkt, int pkt_len)
+{
+    struct mbuf *m;
+    int proto;
+
+    if (pkt_len < ETH_HLEN)
+        return;
+
+    proto = ntohs(*(uint16_t *)(pkt + 12));
+    switch(proto) {
+    case ETH_P_ARP:
+        arp_input(pkt, pkt_len);
+        break;
+    case ETH_P_IP:
+        m = m_get();
+        if (!m)
+            return;
+        /* Note: we add to align the IP header */
+        if (M_FREEROOM(m) < pkt_len + 2) {
+            m_inc(m, pkt_len + 2);
+        }
+        m->m_len = pkt_len + 2;
+        memcpy(m->m_data + 2, pkt, pkt_len);
+
+        m->m_data += 2 + ETH_HLEN;
+        m->m_len -= 2 + ETH_HLEN;
+
+        ip_input(m);
+        break;
+    default:
+        break;
+    }
+}
+
+/* output the IP packet to the ethernet device */
+void if_encap(const uint8_t *ip_data, int ip_data_len)
+{
+    uint8_t buf[1600];
+    struct ethhdr *eh = (struct ethhdr *)buf;
+
+    if (ip_data_len + ETH_HLEN > sizeof(buf))
+        return;
+    
+    if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
+        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
+        struct ethhdr *reh = (struct ethhdr *)arp_req;
+        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
+        const struct ip *iph = (const struct ip *)ip_data;
+
+        /* If the client addr is not known, there is no point in
+           sending the packet to it. Normally the sender should have
+           done an ARP request to get its MAC address. Here we do it
+           in place of sending the packet and we hope that the sender
+           will retry sending its packet. */
+        memset(reh->h_dest, 0xff, ETH_ALEN);
+        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
+        reh->h_source[5] = CTL_ALIAS;
+        reh->h_proto = htons(ETH_P_ARP);
+        rah->ar_hrd = htons(1);
+        rah->ar_pro = htons(ETH_P_IP);
+        rah->ar_hln = ETH_ALEN;
+        rah->ar_pln = 4;
+        rah->ar_op = htons(ARPOP_REQUEST);
+        /* source hw addr */
+        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
+        rah->ar_sha[5] = CTL_ALIAS;
+        /* source IP */
+        memcpy(rah->ar_sip, &alias_addr, 4);
+        /* target hw addr (none) */
+        memset(rah->ar_tha, 0, ETH_ALEN);
+        /* target IP */
+        memcpy(rah->ar_tip, &iph->ip_dst, 4);
+        client_ipaddr = iph->ip_dst;
+        slirp_output(arp_req, sizeof(arp_req));
+    } else {
+        memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
+        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
+        /* XXX: not correct */
+        eh->h_source[5] = CTL_ALIAS;
+        eh->h_proto = htons(ETH_P_IP);
+        memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
+        slirp_output(buf, ip_data_len + ETH_HLEN);
+    }
+}
+
+static void _slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+                                           struct in_addr *laddr, u_int lport,
+                                           struct in_addr *faddr, u_int fport),
+                              void *opaque, int is_udp)
+{
+    struct socket *head = (is_udp ? &udb : &tcb);
+    struct socket *so;
+
+    for (so = head->so_next; so != head; so = so->so_next) {
+        func(opaque, is_udp,
+             &so->so_laddr, ntohs(so->so_lport),
+             &so->so_faddr, ntohs(so->so_fport));
+    }
+}
+
+void slirp_redir_loop(void (*func)(void *opaque, int is_udp,
+                                  struct in_addr *laddr, u_int lport,
+                                  struct in_addr *faddr, u_int fport),
+                     void *opaque)
+{
+    _slirp_redir_loop(func, opaque, 0);
+    _slirp_redir_loop(func, opaque, 1);
+}
+
+/* Unlistens a redirection
+ *
+ * Return value: number of redirs removed */
+int slirp_redir_rm(int is_udp, int host_port)
+{
+    struct socket *so;
+    struct socket *head = (is_udp ? &udb : &tcb);
+    int fport = htons(host_port);
+    int n = 0;
+
+ loop_again:
+    for (so = head->so_next; so != head; so = so->so_next) {
+        if (so->so_fport == fport) {
+            close(so->s);
+            sofree(so);
+            n++;
+            goto loop_again;
+        }
+    }
+
+    return n;
+}
+
+int slirp_redir(int is_udp, int host_port,
+                struct in_addr guest_addr, int guest_port)
+{
+    if (is_udp) {
+        if (!udp_listen(htons(host_port), guest_addr.s_addr,
+                        htons(guest_port), 0))
+            return -1;
+    } else {
+        if (!solisten(htons(host_port), guest_addr.s_addr,
+                      htons(guest_port), 0))
+            return -1;
+    }
+    return 0;
+}
+
+int slirp_add_exec(int do_pty, const void *args, int addr_low_byte,
+                  int guest_port)
+{
+    return add_exec(&exec_list, do_pty, (char *)args,
+                    addr_low_byte, htons(guest_port));
+}
+
+ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
+{
+	if (so->s == -1 && so->extra) {
+		qemu_chr_write(so->extra, buf, len);
+		return len;
+	}
+
+	return send(so->s, buf, len, flags);
+}
+
+static struct socket *slirp_find_ctl_socket(int addr_low_byte, int guest_port)
+{
+	struct socket *so;
+
+	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
+		if ((so->so_faddr.s_addr & htonl(0xffffff00)) ==
+				special_addr.s_addr
+				&& (ntohl(so->so_faddr.s_addr) & 0xff) ==
+				addr_low_byte
+				&& htons(so->so_fport) == guest_port)
+			return so;
+	}
+
+	return NULL;
+}
+
+size_t slirp_socket_can_recv(int addr_low_byte, int guest_port)
+{
+	struct iovec iov[2];
+	struct socket *so;
+
+    if (!link_up)
+        return 0;
+
+	so = slirp_find_ctl_socket(addr_low_byte, guest_port);
+
+	if (!so || so->so_state & SS_NOFDREF)
+		return 0;
+
+	if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
+		return 0;
+
+	return sopreprbuf(so, iov, NULL);
+}
+
+void slirp_socket_recv(int addr_low_byte, int guest_port, const uint8_t *buf,
+        int size)
+{
+    int ret;
+    struct socket *so = slirp_find_ctl_socket(addr_low_byte, guest_port);
+   
+    if (!so)
+        return;
+
+    ret = soreadbuf(so, (const char *)buf, size);
+
+    if (ret > 0)
+        tcp_output(sototcpcb(so));
+}
+
+static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
+{
+    int i;
+
+    qemu_put_sbe16(f, tp->t_state);
+    for (i = 0; i < TCPT_NTIMERS; i++)
+        qemu_put_sbe16(f, tp->t_timer[i]);
+    qemu_put_sbe16(f, tp->t_rxtshift);
+    qemu_put_sbe16(f, tp->t_rxtcur);
+    qemu_put_sbe16(f, tp->t_dupacks);
+    qemu_put_be16(f, tp->t_maxseg);
+    qemu_put_sbyte(f, tp->t_force);
+    qemu_put_be16(f, tp->t_flags);
+    qemu_put_be32(f, tp->snd_una);
+    qemu_put_be32(f, tp->snd_nxt);
+    qemu_put_be32(f, tp->snd_up);
+    qemu_put_be32(f, tp->snd_wl1);
+    qemu_put_be32(f, tp->snd_wl2);
+    qemu_put_be32(f, tp->iss);
+    qemu_put_be32(f, tp->snd_wnd);
+    qemu_put_be32(f, tp->rcv_wnd);
+    qemu_put_be32(f, tp->rcv_nxt);
+    qemu_put_be32(f, tp->rcv_up);
+    qemu_put_be32(f, tp->irs);
+    qemu_put_be32(f, tp->rcv_adv);
+    qemu_put_be32(f, tp->snd_max);
+    qemu_put_be32(f, tp->snd_cwnd);
+    qemu_put_be32(f, tp->snd_ssthresh);
+    qemu_put_sbe16(f, tp->t_idle);
+    qemu_put_sbe16(f, tp->t_rtt);
+    qemu_put_be32(f, tp->t_rtseq);
+    qemu_put_sbe16(f, tp->t_srtt);
+    qemu_put_sbe16(f, tp->t_rttvar);
+    qemu_put_be16(f, tp->t_rttmin);
+    qemu_put_be32(f, tp->max_sndwnd);
+    qemu_put_byte(f, tp->t_oobflags);
+    qemu_put_byte(f, tp->t_iobc);
+    qemu_put_sbe16(f, tp->t_softerror);
+    qemu_put_byte(f, tp->snd_scale);
+    qemu_put_byte(f, tp->rcv_scale);
+    qemu_put_byte(f, tp->request_r_scale);
+    qemu_put_byte(f, tp->requested_s_scale);
+    qemu_put_be32(f, tp->ts_recent);
+    qemu_put_be32(f, tp->ts_recent_age);
+    qemu_put_be32(f, tp->last_ack_sent);
+}
+
+static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
+{
+    uint32_t off;
+
+    qemu_put_be32(f, sbuf->sb_cc);
+    qemu_put_be32(f, sbuf->sb_datalen);
+    off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
+    qemu_put_sbe32(f, off);
+    off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
+    qemu_put_sbe32(f, off);
+    qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
+}
+
+static void slirp_socket_save(QEMUFile *f, struct socket *so)
+{
+    qemu_put_be32(f, so->so_urgc);
+    qemu_put_be32(f, so->so_faddr.s_addr);
+    qemu_put_be32(f, so->so_laddr.s_addr);
+    qemu_put_be16(f, so->so_fport);
+    qemu_put_be16(f, so->so_lport);
+    qemu_put_byte(f, so->so_iptos);
+    qemu_put_byte(f, so->so_emu);
+    qemu_put_byte(f, so->so_type);
+    qemu_put_be32(f, so->so_state);
+    slirp_sbuf_save(f, &so->so_rcv);
+    slirp_sbuf_save(f, &so->so_snd);
+    slirp_tcp_save(f, so->so_tcpcb);
+}
+
+static void slirp_state_save(QEMUFile *f, void *opaque)
+{
+    struct ex_list *ex_ptr;
+
+    for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+        if (ex_ptr->ex_pty == 3) {
+            struct socket *so;
+            so = slirp_find_ctl_socket(ex_ptr->ex_addr, ntohs(ex_ptr->ex_fport));
+            if (!so)
+                continue;
+
+            qemu_put_byte(f, 42);
+            slirp_socket_save(f, so);
+        }
+    qemu_put_byte(f, 0);
+}
+
+static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
+{
+    int i;
+
+    tp->t_state = qemu_get_sbe16(f);
+    for (i = 0; i < TCPT_NTIMERS; i++)
+        tp->t_timer[i] = qemu_get_sbe16(f);
+    tp->t_rxtshift = qemu_get_sbe16(f);
+    tp->t_rxtcur = qemu_get_sbe16(f);
+    tp->t_dupacks = qemu_get_sbe16(f);
+    tp->t_maxseg = qemu_get_be16(f);
+    tp->t_force = qemu_get_sbyte(f);
+    tp->t_flags = qemu_get_be16(f);
+    tp->snd_una = qemu_get_be32(f);
+    tp->snd_nxt = qemu_get_be32(f);
+    tp->snd_up = qemu_get_be32(f);
+    tp->snd_wl1 = qemu_get_be32(f);
+    tp->snd_wl2 = qemu_get_be32(f);
+    tp->iss = qemu_get_be32(f);
+    tp->snd_wnd = qemu_get_be32(f);
+    tp->rcv_wnd = qemu_get_be32(f);
+    tp->rcv_nxt = qemu_get_be32(f);
+    tp->rcv_up = qemu_get_be32(f);
+    tp->irs = qemu_get_be32(f);
+    tp->rcv_adv = qemu_get_be32(f);
+    tp->snd_max = qemu_get_be32(f);
+    tp->snd_cwnd = qemu_get_be32(f);
+    tp->snd_ssthresh = qemu_get_be32(f);
+    tp->t_idle = qemu_get_sbe16(f);
+    tp->t_rtt = qemu_get_sbe16(f);
+    tp->t_rtseq = qemu_get_be32(f);
+    tp->t_srtt = qemu_get_sbe16(f);
+    tp->t_rttvar = qemu_get_sbe16(f);
+    tp->t_rttmin = qemu_get_be16(f);
+    tp->max_sndwnd = qemu_get_be32(f);
+    tp->t_oobflags = qemu_get_byte(f);
+    tp->t_iobc = qemu_get_byte(f);
+    tp->t_softerror = qemu_get_sbe16(f);
+    tp->snd_scale = qemu_get_byte(f);
+    tp->rcv_scale = qemu_get_byte(f);
+    tp->request_r_scale = qemu_get_byte(f);
+    tp->requested_s_scale = qemu_get_byte(f);
+    tp->ts_recent = qemu_get_be32(f);
+    tp->ts_recent_age = qemu_get_be32(f);
+    tp->last_ack_sent = qemu_get_be32(f);
+    tcp_template(tp);
+}
+
+static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
+{
+    uint32_t off, sb_cc, sb_datalen;
+
+    sb_cc = qemu_get_be32(f);
+    sb_datalen = qemu_get_be32(f);
+
+    sbreserve(sbuf, sb_datalen);
+
+    if (sbuf->sb_datalen != sb_datalen)
+        return -ENOMEM;
+
+    sbuf->sb_cc = sb_cc;
+
+    off = qemu_get_sbe32(f);
+    sbuf->sb_wptr = sbuf->sb_data + off;
+    off = qemu_get_sbe32(f);
+    sbuf->sb_rptr = sbuf->sb_data + off;
+    qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
+
+    return 0;
+}
+
+static int slirp_socket_load(QEMUFile *f, struct socket *so)
+{
+    if (tcp_attach(so) < 0)
+        return -ENOMEM;
+
+    so->so_urgc = qemu_get_be32(f);
+    so->so_faddr.s_addr = qemu_get_be32(f);
+    so->so_laddr.s_addr = qemu_get_be32(f);
+    so->so_fport = qemu_get_be16(f);
+    so->so_lport = qemu_get_be16(f);
+    so->so_iptos = qemu_get_byte(f);
+    so->so_emu = qemu_get_byte(f);
+    so->so_type = qemu_get_byte(f);
+    so->so_state = qemu_get_be32(f);
+    if (slirp_sbuf_load(f, &so->so_rcv) < 0)
+        return -ENOMEM;
+    if (slirp_sbuf_load(f, &so->so_snd) < 0)
+        return -ENOMEM;
+    slirp_tcp_load(f, so->so_tcpcb);
+
+    return 0;
+}
+
+static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct ex_list *ex_ptr;
+    int r;
+
+    while ((r = qemu_get_byte(f))) {
+        int ret;
+        struct socket *so = socreate();
+
+        if (!so)
+            return -ENOMEM;
+
+        ret = slirp_socket_load(f, so);
+
+        if (ret < 0)
+            return ret;
+
+        if ((so->so_faddr.s_addr & htonl(0xffffff00)) != special_addr.s_addr)
+            return -EINVAL;
+
+        for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+            if (ex_ptr->ex_pty == 3 &&
+                    (ntohl(so->so_faddr.s_addr) & 0xff) == ex_ptr->ex_addr &&
+                    so->so_fport == ex_ptr->ex_fport)
+                break;
+
+        if (!ex_ptr)
+            return -EINVAL;
+
+        so->extra = (void *)ex_ptr->ex_exec;
+    }
+
+    return 0;
+}
diff --git a/slirp2/slirp.h b/slirp/slirp.h
similarity index 72%
copy from slirp2/slirp.h
copy to slirp/slirp.h
index e69940b..8309fe0 100644
--- a/slirp2/slirp.h
+++ b/slirp/slirp.h
@@ -3,17 +3,23 @@
 
 #define CONFIG_QEMU
 
-#define DEBUG 1
+//#define DEBUG 1
+
+// Uncomment the following line to enable SLIRP statistics printing in Qemu
+//#define LOG_ENABLED
+
+#ifdef LOG_ENABLED
+#define STAT(expr) expr
+#else
+#define STAT(expr) do { } while(0)
+#endif
 
 #ifndef CONFIG_QEMU
 #include "version.h"
 #endif
-#include "config.h"
+#include "config-host.h"
 #include "slirp_config.h"
 
-#include <stddef.h>
-#include "sockets.h"
-
 #ifdef _WIN32
 # include <inttypes.h>
 
@@ -24,9 +30,20 @@
 typedef char *caddr_t;
 
 # include <windows.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
 # include <sys/timeb.h>
 # include <iphlpapi.h>
+
+# define EWOULDBLOCK WSAEWOULDBLOCK
+# define EINPROGRESS WSAEINPROGRESS
+# define ENOTCONN WSAENOTCONN
+# define EHOSTUNREACH WSAEHOSTUNREACH
+# define ENETUNREACH WSAENETUNREACH
+# define ECONNREFUSED WSAECONNREFUSED
 #else
+# define ioctlsocket ioctl
+# define closesocket(s) close(s)
 # define O_BINARY 0
 #endif
 
@@ -85,7 +102,7 @@
 # include <sys/time.h>
 # include <time.h>
 #else
-# if HAVE_SYS_TIME_H
+# ifdef HAVE_SYS_TIME_H
 #  include <sys/time.h>
 # else
 #  include <time.h>
@@ -102,15 +119,15 @@
 #include <sys/uio.h>
 #endif
 
-#ifndef _P
+#undef _P
 #ifndef NO_PROTOTYPES
 #  define   _P(x)   x
 #else
 #  define   _P(x)   ()
 #endif
-#endif
 
 #ifndef _WIN32
+#include <netinet/in.h>
 #include <arpa/inet.h>
 #endif
 
@@ -129,12 +146,50 @@
 void free _P((void *ptr));
 #endif
 
+#ifndef HAVE_INET_ATON
+int inet_aton _P((const char *cp, struct in_addr *ia));
+#endif
+
+#include <fcntl.h>
+#ifndef NO_UNIX_SOCKETS
+#include <sys/un.h>
+#endif
+#include <signal.h>
+#ifdef HAVE_SYS_SIGNAL_H
+# include <sys/signal.h>
+#endif
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+
+#if defined(HAVE_SYS_IOCTL_H)
+# include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#ifdef USE_PPP
+#include <ppp/slirppp.h>
+#endif
+
 #ifdef __STDC__
 #include <stdarg.h>
 #else
 #include <varargs.h>
 #endif
 
+#include <sys/stat.h>
+
 /* Avoid conflicting with the libc insque() and remque(), which
    have different prototypes. */
 #define insque slirp_insque
@@ -209,35 +264,33 @@
 
 void lprint _P((const char *, ...));
 
-extern int do_echo;
+#ifndef _WIN32
+#include <netdb.h>
+#endif
 
 #define DEFAULT_BAUD 115200
 
+#define SO_OPTIONS DO_KEEPALIVE
+#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
+
 /* cksum.c */
-int cksum(MBuf m, int len);
+int cksum(struct mbuf *m, int len);
 
 /* if.c */
 void if_init _P((void));
-void if_output _P((struct socket *, MBuf ));
+void if_output _P((struct socket *, struct mbuf *));
 
 /* ip_input.c */
 void ip_init _P((void));
-void ip_input _P((MBuf ));
-struct ip * ip_reass _P((register struct ip*, register struct ipq *));
-void ip_freef _P((struct ipq *));
-void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *));
-void ip_deq _P((register struct ipasfrag *));
+void ip_input _P((struct mbuf *));
 void ip_slowtimo _P((void));
-void ip_stripoptions _P((register MBuf , MBuf ));
+void ip_stripoptions _P((register struct mbuf *, struct mbuf *));
 
 /* ip_output.c */
-int ip_output _P((struct socket *, MBuf ));
+int ip_output _P((struct socket *, struct mbuf *));
 
 /* tcp_input.c */
-int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, MBuf ));
-void tcp_input _P((register MBuf , int, struct socket *));
-void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *));
-void tcp_xmit_timer _P((register struct tcpcb *, int));
+void tcp_input _P((register struct mbuf *, int, struct socket *));
 int tcp_mss _P((register struct tcpcb *, u_int));
 
 /* tcp_output.c */
@@ -247,16 +300,15 @@
 /* tcp_subr.c */
 void tcp_init _P((void));
 void tcp_template _P((struct tcpcb *));
-void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register MBuf , tcp_seq, tcp_seq, int));
+void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int));
 struct tcpcb * tcp_newtcpcb _P((struct socket *));
 struct tcpcb * tcp_close _P((register struct tcpcb *));
-void tcp_drain _P((void));
 void tcp_sockclosed _P((struct tcpcb *));
 int tcp_fconnect _P((struct socket *));
 void tcp_connect _P((struct socket *));
 int tcp_attach _P((struct socket *));
 u_int8_t tcp_tos _P((struct socket *));
-int tcp_emu _P((struct socket *, MBuf ));
+int tcp_emu _P((struct socket *, struct mbuf *));
 int tcp_ctl _P((struct socket *));
 struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
 
@@ -273,4 +325,9 @@
 #define max(x,y) ((x) > (y) ? (x) : (y))
 #endif
 
+#ifdef _WIN32
+#undef errno
+#define errno (WSAGetLastError())
+#endif
+
 #endif
diff --git a/slirp2/slirp_config.h b/slirp/slirp_config.h
similarity index 95%
copy from slirp2/slirp_config.h
copy to slirp/slirp_config.h
index 030d2ff..dbc8dfd 100644
--- a/slirp2/slirp_config.h
+++ b/slirp/slirp_config.h
@@ -128,10 +128,10 @@
 #undef HAVE_SYS_STROPTS_H
 
 /* Define to whatever your compiler thinks inline should be */
-#define inline inline
+//#define inline inline
 
 /* Define to whatever your compiler thinks const should be */
-#define const const
+//#define const const
 
 /* Define if your compiler doesn't like prototypes */
 #undef NO_PROTOTYPES
@@ -160,11 +160,17 @@
 /* Define if you have srandom() */
 #undef HAVE_SRANDOM
 
+/* Define if you have inet_aton */
+#undef HAVE_INET_ATON
+#ifndef _WIN32
+#define HAVE_INET_ATON
+#endif
+
 /* Define if you have setenv */
 #undef HAVE_SETENV
 
 /* Define if you have index() */
-#undef HAVE_INDEX
+#define HAVE_INDEX
 
 /* Define if you have bcmp() */
 #undef HAVE_BCMP
@@ -176,7 +182,7 @@
 #define HAVE_MEMMOVE
 
 /* Define if you have gethostid */
-#undef HAVE_GETHOSTID
+#define HAVE_GETHOSTID
 
 /* Define if you DON'T have unix-domain sockets */
 #undef NO_UNIX_SOCKETS
diff --git a/slirp2/socket.c b/slirp/socket.c
similarity index 69%
copy from slirp2/socket.c
copy to slirp/socket.c
index 05fb4b7..82d026c 100644
--- a/slirp2/socket.c
+++ b/slirp/socket.c
@@ -5,39 +5,35 @@
  * terms and conditions of the copyright.
  */
 
-#define WANT_SYS_IOCTL_H
+#include "qemu-common.h"
 #include <slirp.h>
 #include "ip_icmp.h"
-#include "main.h"
 #ifdef __sun__
 #include <sys/filio.h>
 #endif
-#define  SLIRP_COMPILATION 1
-#include "sockets.h"
-#include "proxy_common.h"
 
-void
+static void sofcantrcvmore(struct socket *so);
+static void sofcantsendmore(struct socket *so);
+
+#if 0
+static void
 so_init()
 {
 	/* Nothing yet */
 }
-
+#endif
 
 struct socket *
-solookup(head, laddr, lport, faddr, fport)
-	struct socket *head;
-	uint32_t laddr;
-	u_int lport;
-	uint32_t faddr;
-	u_int fport;
+solookup(struct socket *head, struct in_addr laddr, u_int lport,
+         struct in_addr faddr, u_int fport)
 {
 	struct socket *so;
 
 	for (so = head->so_next; so != head; so = so->so_next) {
-		if (so->so_laddr_port == lport &&
-		    so->so_laddr_ip   == laddr &&
-		    so->so_faddr_ip   == faddr &&
-		    so->so_faddr_port == fport)
+		if (so->so_lport == lport &&
+		    so->so_laddr.s_addr == laddr.s_addr &&
+		    so->so_faddr.s_addr == faddr.s_addr &&
+		    so->so_fport == fport)
 		   break;
 	}
 
@@ -53,7 +49,7 @@
  * insque() it into the correct linked-list
  */
 struct socket *
-socreate()
+socreate(void)
 {
   struct socket *so;
 
@@ -70,13 +66,9 @@
  * remque and free a socket, clobber cache
  */
 void
-sofree(so)
-	struct socket *so;
+sofree(struct socket *so)
 {
-  if (so->so_state & SS_PROXIFIED)
-    proxy_manager_del(so);
-
-  if (so->extra) {
+  if (so->so_emu==EMU_RSH && so->extra) {
 	sofree(so->extra);
 	so->extra=NULL;
   }
@@ -85,7 +77,7 @@
   else if (so == udp_last_so)
     udp_last_so = &udb;
 
-  mbuf_free(so->so_m);
+  m_free(so->so_m);
 
   if(so->so_next && so->so_prev)
     remque(so);  /* crashes if so is not in a queue */
@@ -93,32 +85,24 @@
   free(so);
 }
 
-/*
- * Read from so's socket into sb_snd, updating all relevant sbuf fields
- * NOTE: This will only be called if it is select()ed for reading, so
- * a read() of 0 (or less) means it's disconnected
- */
-int
-soread(so)
-	struct socket *so;
+size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
 {
-	int n, nn, lss, total;
-	SBuf  sb = &so->so_snd;
-	int   len = sb->sb_datalen - sb->sb_cc;
-	struct iovec iov[2];
+	int n, lss, total;
+	struct sbuf *sb = &so->so_snd;
+	int len = sb->sb_datalen - sb->sb_cc;
 	int mss = so->so_tcpcb->t_maxseg;
 
-	DEBUG_CALL("soread");
+	DEBUG_CALL("sopreprbuf");
 	DEBUG_ARG("so = %lx", (long )so);
 
-	/*
-	 * No need to check if there's enough room to read.
-	 * soread wouldn't have been called if there weren't
-	 */
-
 	len = sb->sb_datalen - sb->sb_cc;
 
+	if (len <= 0)
+		return 0;
+
 	iov[0].iov_base = sb->sb_wptr;
+        iov[1].iov_base = NULL;
+        iov[1].iov_len = 0;
 	if (sb->sb_wptr < sb->sb_rptr) {
 		iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
 		/* Should never succeed, but... */
@@ -156,18 +140,44 @@
 			n = 1;
 		}
 	}
+	if (np)
+		*np = n;
+
+	return iov[0].iov_len + (n - 1) * iov[1].iov_len;
+}
+
+/*
+ * Read from so's socket into sb_snd, updating all relevant sbuf fields
+ * NOTE: This will only be called if it is select()ed for reading, so
+ * a read() of 0 (or less) means it's disconnected
+ */
+int
+soread(struct socket *so)
+{
+	int n, nn;
+	struct sbuf *sb = &so->so_snd;
+	struct iovec iov[2];
+
+	DEBUG_CALL("soread");
+	DEBUG_ARG("so = %lx", (long )so);
+
+	/*
+	 * No need to check if there's enough room to read.
+	 * soread wouldn't have been called if there weren't
+	 */
+	sopreprbuf(so, iov, &n);
 
 #ifdef HAVE_READV
 	nn = readv(so->s, (struct iovec *)iov, n);
 	DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
 #else
-	nn = socket_recv(so->s, iov[0].iov_base, iov[0].iov_len);
+	nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
 #endif
 	if (nn <= 0) {
 		if (nn < 0 && (errno == EINTR || errno == EAGAIN))
 			return 0;
 		else {
-			DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,errno_str));
+			DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
 			sofcantrcvmore(so);
 			tcp_sockclosed(sototcpcb(so));
 			return -1;
@@ -186,7 +196,7 @@
 	 */
 	if (n == 2 && nn == iov[0].iov_len) {
             int ret;
-            ret = socket_recv(so->s, iov[1].iov_base, iov[1].iov_len);
+            ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
             if (ret > 0)
                 nn += ret;
         }
@@ -202,6 +212,48 @@
 	return nn;
 }
 
+int soreadbuf(struct socket *so, const char *buf, int size)
+{
+    int n, nn, copy = size;
+	struct sbuf *sb = &so->so_snd;
+	struct iovec iov[2];
+
+	DEBUG_CALL("soreadbuf");
+	DEBUG_ARG("so = %lx", (long )so);
+
+	/*
+	 * No need to check if there's enough room to read.
+	 * soread wouldn't have been called if there weren't
+	 */
+	if (sopreprbuf(so, iov, &n) < size)
+        goto err;
+
+    nn = MIN(iov[0].iov_len, copy);
+    memcpy(iov[0].iov_base, buf, nn);
+
+    copy -= nn;
+    buf += nn;
+
+    if (copy == 0)
+        goto done;
+
+    memcpy(iov[1].iov_base, buf, copy);
+
+done:
+    /* Update fields */
+	sb->sb_cc += size;
+	sb->sb_wptr += size;
+	if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
+		sb->sb_wptr -= sb->sb_datalen;
+    return size;
+err:
+
+    sofcantrcvmore(so);
+    tcp_sockclosed(sototcpcb(so));
+    fprintf(stderr, "soreadbuf buffer to small");
+    return -1;
+}
+
 /*
  * Get urgent data
  *
@@ -210,8 +262,7 @@
  * in the send buffer is sent as urgent data
  */
 void
-sorecvoob(so)
-	struct socket *so;
+sorecvoob(struct socket *so)
 {
 	struct tcpcb *tp = sototcpcb(so);
 
@@ -238,12 +289,12 @@
  * There's a lot duplicated code here, but...
  */
 int
-sosendoob(so)
-	struct socket *so;
+sosendoob(struct socket *so)
 {
-	SBuf  sb = &so->so_rcv;
-	char  buff[2048]; /* XXX Shouldn't be sending more oob data than this */
-	int   n, len;
+	struct sbuf *sb = &so->so_rcv;
+	char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
+
+	int n, len;
 
 	DEBUG_CALL("sosendoob");
 	DEBUG_ARG("so = %lx", (long)so);
@@ -254,7 +305,7 @@
 
 	if (sb->sb_rptr < sb->sb_wptr) {
 		/* We can send it directly */
-		n = socket_send_oob(so->s, sb->sb_rptr, so->so_urgc); /* |MSG_DONTWAIT)); */
+		n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
 		so->so_urgc -= n;
 
 		DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
@@ -275,7 +326,7 @@
 			so->so_urgc -= n;
 			len += n;
 		}
-		n = socket_send_oob(so->s, buff, len); /* |MSG_DONTWAIT)); */
+		n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
 #ifdef DEBUG
 		if (n != len)
 		   DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
@@ -296,12 +347,11 @@
  * updating all sbuf field as necessary
  */
 int
-sowrite(so)
-	struct socket *so;
+sowrite(struct socket *so)
 {
-	int   n,nn;
-	SBuf  sb = &so->so_rcv;
-	int   len = sb->sb_cc;
+	int  n,nn;
+	struct sbuf *sb = &so->so_rcv;
+	int len = sb->sb_cc;
 	struct iovec iov[2];
 
 	DEBUG_CALL("sowrite");
@@ -321,6 +371,8 @@
         len = sb->sb_cc;
 
 	iov[0].iov_base = sb->sb_rptr;
+        iov[1].iov_base = NULL;
+        iov[1].iov_len = 0;
 	if (sb->sb_rptr < sb->sb_wptr) {
 		iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
 		/* Should never succeed, but... */
@@ -345,7 +397,7 @@
 
 	DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
 #else
-	nn = socket_send(so->s, iov[0].iov_base, iov[0].iov_len);
+	nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
 #endif
 	/* This should never happen, but people tell me it does *shrug* */
 	if (nn < 0 && (errno == EAGAIN || errno == EINTR))
@@ -362,7 +414,7 @@
 #ifndef HAVE_READV
 	if (n == 2 && nn == iov[0].iov_len) {
             int ret;
-            ret = socket_send(so->s, iov[1].iov_base, iov[1].iov_len);
+            ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
             if (ret > 0)
                 nn += ret;
         }
@@ -389,10 +441,10 @@
  * recvfrom() a UDP socket
  */
 void
-sorecvfrom(so)
-	struct socket *so;
+sorecvfrom(struct socket *so)
 {
-        SockAddress  addr;
+	struct sockaddr_in addr;
+	socklen_t addrlen = sizeof(struct sockaddr_in);
 
 	DEBUG_CALL("sorecvfrom");
 	DEBUG_ARG("so = %lx", (long)so);
@@ -401,7 +453,8 @@
 	  char buff[256];
 	  int len;
 
-	  len = socket_recvfrom(so->s, buff, 256, &addr);
+	  len = recvfrom(so->s, buff, 256, 0,
+			 (struct sockaddr *)&addr, &addrlen);
 	  /* XXX Check if reply is "correct"? */
 
 	  if(len == -1 || len == 0) {
@@ -411,39 +464,45 @@
 	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
 
 	    DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
-			errno,errno_str));
-	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,errno_str);
+			errno,strerror(errno)));
+	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
 	  } else {
 	    icmp_reflect(so->so_m);
-	    so->so_m = 0; /* Don't mbuf_free() it again! */
+            so->so_m = NULL; /* Don't m_free() it again! */
 	  }
 	  /* No need for this socket anymore, udp_detach it */
 	  udp_detach(so);
 	} else {                            	/* A "normal" UDP packet */
-	  MBuf m;
-	  int len, n;
+	  struct mbuf *m;
+          int len;
+#ifdef _WIN32
+          unsigned long n;
+#else
+          int n;
+#endif
 
-	  if (!(m = mbuf_alloc())) return;
-	  m->m_data += if_maxlinkhdr;
+	  if (!(m = m_get())) return;
+	  m->m_data += IF_MAXLINKHDR;
 
 	  /*
 	   * XXX Shouldn't FIONREAD packets destined for port 53,
 	   * but I don't know the max packet size for DNS lookups
 	   */
-	  len = mbuf_freeroom(m);
+	  len = M_FREEROOM(m);
 	  /* if (so->so_fport != htons(53)) { */
-	  n = socket_can_read(so->s);
+	  ioctlsocket(so->s, FIONREAD, &n);
 
 	  if (n > len) {
 	    n = (m->m_data - m->m_dat) + m->m_len + n + 1;
-	    mbuf_ensure(m, n);
-	    len = mbuf_freeroom(m);
+	    m_inc(m, n);
+	    len = M_FREEROOM(m);
 	  }
 	  /* } */
 
-	  m->m_len = socket_recvfrom(so->s, m->m_data, len, &addr);
+	  m->m_len = recvfrom(so->s, m->m_data, len, 0,
+			      (struct sockaddr *)&addr, &addrlen);
 	  DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
-		      m->m_len, errno,errno_str));
+		      m->m_len, errno,strerror(errno)));
 	  if(m->m_len<0) {
 	    u_char code=ICMP_UNREACH_PORT;
 
@@ -451,8 +510,8 @@
 	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
 
 	    DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
-	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,errno_str);
-	    mbuf_free(m);
+	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
+	    m_free(m);
 	  } else {
 	  /*
 	   * Hack: domain name lookup will be used the most for UDP,
@@ -461,14 +520,14 @@
 	   * out much quicker (10 seconds  for now...)
 	   */
 	    if (so->so_expire) {
-	      if (so->so_faddr_port == 53)
+	      if (so->so_fport == htons(53))
 		so->so_expire = curtime + SO_EXPIREFAST;
 	      else
 		so->so_expire = curtime + SO_EXPIRE;
 	    }
 
 	    /*		if (m->m_len == len) {
-	     *			mbuf_ensure(m, MINCSIZE);
+	     *			m_inc(m, MINCSIZE);
 	     *			m->m_len = 0;
 	     *		}
 	     */
@@ -477,7 +536,7 @@
 	     * If this packet was destined for CTL_ADDR,
 	     * make it look like that's where it came from, done by udp_output
 	     */
-	    udp_output_(so, m, &addr);
+	    udp_output(so, m, &addr);
 	  } /* rx error */
 	} /* if ping packet */
 }
@@ -486,38 +545,36 @@
  * sendto() a socket
  */
 int
-sosendto(so, m)
-	struct socket *so;
-	MBuf m;
+sosendto(struct socket *so, struct mbuf *m)
 {
-        SockAddress   addr;
-        uint32_t      addr_ip;
-        uint16_t      addr_port;
-        int           ret;
+	int ret;
+	struct sockaddr_in addr;
 
 	DEBUG_CALL("sosendto");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m = %lx", (long)m);
 
-	if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) {
+        addr.sin_family = AF_INET;
+	if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
 	  /* It's an alias */
-          int  low = so->so_faddr_ip & 0xff;
-
-          if ( CTL_IS_DNS(low) )
-            addr_ip = dns_addr[low - CTL_DNS];
-          else
-            addr_ip = loopback_addr_ip;
+	  switch(ntohl(so->so_faddr.s_addr) & 0xff) {
+	  case CTL_DNS:
+	    addr.sin_addr = dns_addr;
+	    break;
+	  case CTL_ALIAS:
+	  default:
+	    addr.sin_addr = loopback_addr;
+	    break;
+	  }
 	} else
-	    addr_ip = so->so_faddr_ip;
+	  addr.sin_addr = so->so_faddr;
+	addr.sin_port = so->so_fport;
 
-	addr_port = so->so_faddr_port;
-
-        sock_address_init_inet(&addr, addr_ip, addr_port);
-
-	DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%08x\n", addr_port, addr_ip));
+	DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
 
 	/* Don't care what port we get */
-	ret = socket_sendto(so->s, m->m_data, m->m_len,&addr);
+	ret = sendto(so->s, m->m_data, m->m_len, 0,
+		     (struct sockaddr *)&addr, sizeof (struct sockaddr));
 	if (ret < 0)
 		return -1;
 
@@ -535,16 +592,12 @@
  * XXX This should really be tcp_listen
  */
 struct socket *
-solisten(port, laddr, lport, flags)
-	u_int port;
-	u_int32_t laddr;
-	u_int lport;
-	int flags;
+solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
 {
-	SockAddress  addr;
-	uint32_t     addr_ip;
+	struct sockaddr_in addr;
 	struct socket *so;
-	int s;
+	int s, opt = 1;
+	socklen_t addrlen = sizeof(addr);
 
 	DEBUG_CALL("solisten");
 	DEBUG_ARG("port = %d", port);
@@ -570,61 +623,50 @@
 	if (flags & SS_FACCEPTONCE)
 	   so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
 
-	so->so_state      = (SS_FACCEPTCONN|flags);
-	so->so_laddr_port = lport; /* Kept in host format */
-        so->so_laddr_ip   = laddr; /* Ditto */
-        so->so_haddr_port = port;
+	so->so_state = (SS_FACCEPTCONN|flags);
+	so->so_lport = lport; /* Kept in network format */
+	so->so_laddr.s_addr = laddr; /* Ditto */
 
-        s = socket_loopback_server( port, SOCKET_STREAM );
-        if (s < 0)
-            return NULL;
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = INADDR_ANY;
+	addr.sin_port = port;
 
-        socket_get_address(s, &addr);
+	if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
+	    (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
+	    (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
+	    (listen(s,1) < 0)) {
+		int tmperrno = errno; /* Don't clobber the real reason we failed */
 
-	so->so_faddr_port = sock_address_get_port(&addr);
+		close(s);
+		sofree(so);
+		/* Restore the real errno */
+#ifdef _WIN32
+		WSASetLastError(tmperrno);
+#else
+		errno = tmperrno;
+#endif
+		return NULL;
+	}
+	setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
 
-        addr_ip = (uint32_t) sock_address_get_ip(&addr);
-
-        if (addr_ip == 0 || addr_ip == loopback_addr_ip)
-            so->so_faddr_ip = alias_addr_ip;
-        else
-            so->so_faddr_ip = addr_ip;
+	getsockname(s,(struct sockaddr *)&addr,&addrlen);
+	so->so_fport = addr.sin_port;
+	if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
+	   so->so_faddr = alias_addr;
+	else
+	   so->so_faddr = addr.sin_addr;
 
 	so->s = s;
 	return so;
 }
 
-
-int
-sounlisten(u_int  port)
-{
-    struct socket *so;
-
-    for (so = tcb.so_next; so != &tcb; so = so->so_next) {
-        if (so->so_haddr_port == port) {
-            break;
-        }
-    }
-
-    if (so == &tcb) {
-        return -1;
-    }
-
-    sofcantrcvmore( so );
-    sofcantsendmore( so );
-    close( so->s );
-    so->s = -1;
-    sofree( so );
-    return 0;
-}
-
-
+#if 0
 /*
  * Data is available in so_rcv
  * Just write() the data to the socket
  * XXX not yet...
  */
-void
+static void
 sorwakeup(so)
 	struct socket *so;
 {
@@ -637,12 +679,13 @@
  * We have room for a read() if we want to
  * For now, don't read, it'll be done in the main loop
  */
-void
+static void
 sowwakeup(so)
 	struct socket *so;
 {
 	/* Nothing, yet */
 }
+#endif
 
 /*
  * Various session state calls
@@ -651,8 +694,7 @@
  * times each when only 1 was needed
  */
 void
-soisfconnecting(so)
-	register struct socket *so;
+soisfconnecting(struct socket *so)
 {
 	so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
 			  SS_FCANTSENDMORE|SS_FWDRAIN);
@@ -660,16 +702,14 @@
 }
 
 void
-soisfconnected(so)
-        register struct socket *so;
+soisfconnected(struct socket *so)
 {
 	so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
 	so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
 }
 
-void
-sofcantrcvmore(so)
-	struct  socket *so;
+static void
+sofcantrcvmore(struct socket *so)
 {
 	if ((so->so_state & SS_NOFDREF) == 0) {
 		shutdown(so->s,0);
@@ -684,9 +724,8 @@
 	   so->so_state |= SS_FCANTRCVMORE;
 }
 
-void
-sofcantsendmore(so)
-	struct socket *so;
+static void
+sofcantsendmore(struct socket *so)
 {
 	if ((so->so_state & SS_NOFDREF) == 0) {
             shutdown(so->s,1);           /* send FIN to fhost */
@@ -705,8 +744,7 @@
 }
 
 void
-soisfdisconnected(so)
-	struct socket *so;
+soisfdisconnected(struct socket *so)
 {
 /*	so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */
 /*	close(so->s); */
@@ -721,12 +759,10 @@
  * Set CANTSENDMORE once all data has been write()n
  */
 void
-sofwdrain(so)
-	struct socket *so;
+sofwdrain(struct socket *so)
 {
 	if (so->so_rcv.sb_cc)
 		so->so_state |= SS_FWDRAIN;
 	else
 		sofcantsendmore(so);
 }
-
diff --git a/slirp2/socket.h b/slirp/socket.h
similarity index 74%
copy from slirp2/socket.h
copy to slirp/socket.h
index 5b71d45..f5adaba 100644
--- a/slirp2/socket.h
+++ b/slirp/socket.h
@@ -23,17 +23,16 @@
   int s;                           /* The actual socket */
 
 			/* XXX union these with not-yet-used sbuf params */
-  MBuf so_m;	           /* Pointer to the original SYN packet,
+  struct mbuf *so_m;	           /* Pointer to the original SYN packet,
 				    * for non-blocking connect()'s, and
 				    * PING reply's */
   struct tcpiphdr *so_ti;	   /* Pointer to the original ti within
 				    * so_mconn, for non-blocking connections */
   int so_urgc;
-  uint32_t   so_faddr_ip;
-  uint32_t   so_laddr_ip;
-  uint16_t   so_faddr_port;
-  uint16_t   so_laddr_port;
-  uint16_t   so_haddr_port;
+  struct in_addr so_faddr;	   /* foreign host table entry */
+  struct in_addr so_laddr;	   /* local host table entry */
+  u_int16_t so_fport;		   /* foreign port */
+  u_int16_t so_lport;		   /* local port */
 
   u_int8_t	so_iptos;	/* Type of service */
   u_int8_t	so_emu;		/* Is the socket emulated? */
@@ -49,8 +48,8 @@
 				 * Used to determine when to "downgrade" a session
 					 * from fastq to batchq */
 
-  SBufRec so_rcv;		/* Receive buffer */
-  SBufRec so_snd;		/* Send buffer */
+  struct sbuf so_rcv;		/* Receive buffer */
+  struct sbuf so_snd;		/* Send buffer */
   void * extra;			/* Extra pointer */
 };
 
@@ -71,20 +70,10 @@
 #define SS_CTL			0x080
 #define SS_FACCEPTCONN		0x100	/* Socket is accepting connections from a host on the internet */
 #define SS_FACCEPTONCE		0x200	/* If set, the SS_FACCEPTCONN socket will die after one accept */
-#define SS_PROXIFIED            0x400   /* Socket is trying to connect through a proxy, only makes sense
-                                           when SS_ISFCONNECTING is also set */
+
 extern struct socket tcb;
 
-
-#if defined(DECLARE_IOVEC) && !defined(HAVE_READV)
-struct iovec {
-	char *iov_base;
-	size_t iov_len;
-};
-#endif
-
-void so_init _P((void));
-struct socket * solookup _P((struct socket *, uint32_t, u_int, uint32_t, u_int));
+struct socket * solookup _P((struct socket *, struct in_addr, u_int, struct in_addr, u_int));
 struct socket * socreate _P((void));
 void sofree _P((struct socket *));
 int soread _P((struct socket *));
@@ -92,16 +81,14 @@
 int sosendoob _P((struct socket *));
 int sowrite _P((struct socket *));
 void sorecvfrom _P((struct socket *));
-int sosendto _P((struct socket *, MBuf ));
+int sosendto _P((struct socket *, struct mbuf *));
 struct socket * solisten _P((u_int, u_int32_t, u_int, int));
-int  sounlisten _P((u_int port));
-void sorwakeup _P((struct socket *));
-void sowwakeup _P((struct socket *));
 void soisfconnecting _P((register struct socket *));
 void soisfconnected _P((register struct socket *));
-void sofcantrcvmore _P((struct  socket *));
-void sofcantsendmore _P((struct socket *));
 void soisfdisconnected _P((struct socket *));
 void sofwdrain _P((struct socket *));
+struct iovec; /* For win32 */
+size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
+int soreadbuf(struct socket *so, const char *buf, int size);
 
 #endif /* _SOCKET_H_ */
diff --git a/slirp2/tcp.h b/slirp/tcp.h
similarity index 91%
copy from slirp2/tcp.h
copy to slirp/tcp.h
index 3cddb77..4057032 100644
--- a/slirp2/tcp.h
+++ b/slirp/tcp.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -37,15 +33,11 @@
 #ifndef _TCP_H_
 #define _TCP_H_
 
-#include "helper.h"
-
 typedef	u_int32_t	tcp_seq;
 
 #define      PR_SLOWHZ       2               /* 2 slow timeouts per second (approx) */
 #define      PR_FASTHZ       5               /* 5 fast timeouts per second (not important) */
 
-extern int tcp_rcvspace;
-extern int tcp_sndspace;
 extern struct socket *tcp_last_so;
 
 #define TCP_SNDSPACE 8192
@@ -56,8 +48,8 @@
  * Per RFC 793, September, 1981.
  */
 struct tcphdr {
-	port_t	th_sport;		/* source port */
-	port_t	th_dport;		/* destination port */
+	u_int16_t	th_sport;		/* source port */
+	u_int16_t	th_dport;		/* destination port */
 	tcp_seq	th_seq;			/* sequence number */
 	tcp_seq	th_ack;			/* acknowledgement number */
 #ifdef WORDS_BIGENDIAN
@@ -113,10 +105,14 @@
 
 /*
  * User-settable options (used with setsockopt).
+ *
+ * We don't use the system headers on unix because we have conflicting
+ * local structures. We can't avoid the system definitions on Windows,
+ * so we undefine them.
  */
-#undef  TCP_NODELAY 
+#undef TCP_NODELAY
 #define	TCP_NODELAY	0x01	/* don't delay send to coalesce packets */
-#undef  TCP_MAXSEG
+#undef TCP_MAXSEG
 /* #define	TCP_MAXSEG	0x02 */	/* set maximum segment size */
 
 /*
@@ -170,6 +166,6 @@
 
 extern tcp_seq tcp_iss;                /* tcp initial send seq # */
 
-extern char *tcpstates[];
+extern const char * const tcpstates[];
 
 #endif
diff --git a/slirp2/tcp_input.c b/slirp/tcp_input.c
similarity index 87%
rename from slirp2/tcp_input.c
rename to slirp/tcp_input.c
index c3196d3..effedfc 100644
--- a/slirp2/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -47,7 +43,7 @@
 
 struct socket tcb;
 
-int	tcprexmtthresh = 3;
+#define	TCPREXMTTHRESH 3
 struct	socket *tcp_last_so = &tcb;
 
 tcp_seq tcp_iss;                /* tcp initial send seq # */
@@ -79,12 +75,12 @@
                        tp->t_flags |= TF_DELACK; \
                (tp)->rcv_nxt += (ti)->ti_len; \
                flags = (ti)->ti_flags & TH_FIN; \
-               tcpstat.tcps_rcvpack++;\
-               tcpstat.tcps_rcvbyte += (ti)->ti_len;\
+               STAT(tcpstat.tcps_rcvpack++);         \
+               STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len);   \
                if (so->so_emu) { \
-		       if (tcp_emu((so),(m))) sbuf_append((so), (m)); \
+		       if (tcp_emu((so),(m))) sbappend((so), (m)); \
 	       } else \
-	       	       sbuf_append((so), (m)); \
+	       	       sbappend((so), (m)); \
 /*               sorwakeup(so); */ \
 	} else {\
                (flags) = tcp_reass((tp), (ti), (m)); \
@@ -94,17 +90,17 @@
 #else
 #define	TCP_REASS(tp, ti, m, so, flags) { \
 	if ((ti)->ti_seq == (tp)->rcv_nxt && \
-	    tcpfrag_list_empty(tp) && \
+        tcpfrag_list_empty(tp) && \
 	    (tp)->t_state == TCPS_ESTABLISHED) { \
 		tp->t_flags |= TF_DELACK; \
 		(tp)->rcv_nxt += (ti)->ti_len; \
 		flags = (ti)->ti_flags & TH_FIN; \
-		tcpstat.tcps_rcvpack++;\
-		tcpstat.tcps_rcvbyte += (ti)->ti_len;\
+		STAT(tcpstat.tcps_rcvpack++);        \
+		STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len);  \
 		if (so->so_emu) { \
-			if (tcp_emu((so),(m))) sbuf_append(so, (m)); \
+			if (tcp_emu((so),(m))) sbappend(so, (m)); \
 		} else \
-			sbuf_append((so), (m)); \
+			sbappend((so), (m)); \
 /*		sorwakeup(so); */ \
 	} else { \
 		(flags) = tcp_reass((tp), (ti), (m)); \
@@ -112,29 +108,30 @@
 	} \
 }
 #endif
+static void tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt,
+                          struct tcpiphdr *ti);
+static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
 
-int
-tcp_reass(tp, ti, m)
-	register struct tcpcb *tp;
-	register struct tcpiphdr *ti;
-	MBuf m;
+static int
+tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
+          struct mbuf *m)
 {
 	register struct tcpiphdr *q;
 	struct socket *so = tp->t_socket;
 	int flags;
 
 	/*
-	 * Call with ti==0 after become established to
+	 * Call with ti==NULL after become established to
 	 * force pre-ESTABLISHED data up to user socket.
 	 */
-	if (ti == 0)
+        if (ti == NULL)
 		goto present;
 
 	/*
 	 * Find a segment which begins after this one does.
 	 */
 	for (q = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp);
-	     q = tcpiphdr_next(q))
+            q = tcpiphdr_next(q))
 		if (SEQ_GT(q->ti_seq, ti->ti_seq))
 			break;
 
@@ -150,9 +147,9 @@
 		i = q->ti_seq + q->ti_len - ti->ti_seq;
 		if (i > 0) {
 			if (i >= ti->ti_len) {
-				tcpstat.tcps_rcvduppack++;
-				tcpstat.tcps_rcvdupbyte += ti->ti_len;
-				mbuf_free(m);
+				STAT(tcpstat.tcps_rcvduppack++);
+				STAT(tcpstat.tcps_rcvdupbyte += ti->ti_len);
+				m_freem(m);
 				/*
 				 * Try to present any queued data
 				 * at the left window edge to the user.
@@ -161,14 +158,14 @@
 				 */
 				goto present;   /* ??? */
 			}
-			mbuf_trim(m, i);
+			m_adj(m, i);
 			ti->ti_len -= i;
 			ti->ti_seq += i;
 		}
 		q = tcpiphdr_next(q);
 	}
-	tcpstat.tcps_rcvoopack++;
-	tcpstat.tcps_rcvoobyte += ti->ti_len;
+	STAT(tcpstat.tcps_rcvoopack++);
+	STAT(tcpstat.tcps_rcvoobyte += ti->ti_len);
 	ti->ti_mbuf = m;
 
 	/*
@@ -182,13 +179,13 @@
 		if (i < q->ti_len) {
 			q->ti_seq += i;
 			q->ti_len -= i;
-			mbuf_trim(q->ti_mbuf, i);
+			m_adj(q->ti_mbuf, i);
 			break;
 		}
 		q = tcpiphdr_next(q);
 		m = tcpiphdr_prev(q)->ti_mbuf;
 		remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
-		mbuf_free(m);
+		m_freem(m);
 	}
 
 	/*
@@ -203,8 +200,8 @@
 	 */
 	if (!TCPS_HAVEESTABLISHED(tp->t_state))
 		return (0);
-        ti = tcpfrag_list_first(tp);
-        if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt)
+	ti = tcpfrag_list_first(tp);
+	if (tcpfrag_list_end(ti, tp) || ti->ti_seq != tp->rcv_nxt)
 		return (0);
 	if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
 		return (0);
@@ -216,14 +213,14 @@
 		ti = tcpiphdr_next(ti);
 /*		if (so->so_state & SS_FCANTRCVMORE) */
 		if (so->so_state & SS_FCANTSENDMORE)
-			mbuf_free(m);
+			m_freem(m);
 		else {
 			if (so->so_emu) {
-				if (tcp_emu(so,m)) sbuf_append(so, m);
+				if (tcp_emu(so,m)) sbappend(so, m);
 			} else
-				sbuf_append(so, m);
+				sbappend(so, m);
 		}
-	} while (!tcpfrag_list_end(ti, tp) && ti->ti_seq == tp->rcv_nxt);
+	} while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
 /*	sorwakeup(so); */
 	return (flags);
 }
@@ -233,25 +230,23 @@
  * protocol specification dated September, 1981 very closely.
  */
 void
-tcp_input(m, iphlen, inso)
-	register MBuf m;
-	int iphlen;
-	struct socket *inso;
+tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 {
   	struct ip save_ip, *ip;
 	register struct tcpiphdr *ti;
 	caddr_t optp = NULL;
 	int optlen = 0;
 	int len, tlen, off;
-	register struct tcpcb *tp = 0;
+        register struct tcpcb *tp = NULL;
 	register int tiflags;
-	struct socket *so = 0;
+        struct socket *so = NULL;
 	int todrop, acked, ourfinisacked, needoutput = 0;
 /*	int dropsocket = 0; */
 	int iss = 0;
 	u_long tiwin;
 	int ret;
 /*	int ts_present = 0; */
+    struct ex_list *ex_ptr;
 
 	DEBUG_CALL("tcp_input");
 	DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n",
@@ -266,7 +261,7 @@
 		/* Re-set a few variables */
 		tp = sototcpcb(so);
 		m = so->so_m;
-		so->so_m = 0;
+                so->so_m = NULL;
 		ti = so->so_ti;
 		tiwin = ti->ti_win;
 		tiflags = ti->ti_flags;
@@ -275,14 +270,14 @@
 	}
 
 
-	tcpstat.tcps_rcvtotal++;
+	STAT(tcpstat.tcps_rcvtotal++);
 	/*
 	 * Get IP and TCP header together in first mbuf.
 	 * Note: IP leaves IP header in first mbuf.
 	 */
-	ti = MBUF_TO(m, struct tcpiphdr *);
+	ti = mtod(m, struct tcpiphdr *);
 	if (iphlen > sizeof(struct ip )) {
-	  ip_stripoptions(m, (MBuf )0);
+	  ip_stripoptions(m, (struct mbuf *)0);
 	  iphlen=sizeof(struct ip );
 	}
 	/* XXX Check if too short */
@@ -292,7 +287,7 @@
 	 * Save a copy of the IP header in case we want restore it
 	 * for sending an ICMP error message in response.
 	 */
-	ip=MBUF_TO(m, struct ip *);
+	ip=mtod(m, struct ip *);
 	save_ip = *ip;
 	save_ip.ip_len+= iphlen;
 
@@ -300,8 +295,8 @@
 	 * Checksum extended TCP header and data.
 	 */
 	tlen = ((struct ip *)ti)->ip_len;
-	tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = 0;
-	memset(&ti->ti_i.ih_mbuf, 0, sizeof(struct mbuf_ptr));
+        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
 	ti->ti_x1 = 0;
 	ti->ti_len = htons((u_int16_t)tlen);
 	len = sizeof(struct ip ) + tlen;
@@ -309,7 +304,7 @@
 	 * ti->ti_sum = cksum(m, len);
 	 * if (ti->ti_sum) { */
 	if(cksum(m, len)) {
-	  tcpstat.tcps_rcvbadsum++;
+	  STAT(tcpstat.tcps_rcvbadsum++);
 	  goto drop;
 	}
 
@@ -319,14 +314,14 @@
 	 */
 	off = ti->ti_off << 2;
 	if (off < sizeof (struct tcphdr) || off > tlen) {
-	  tcpstat.tcps_rcvbadoff++;
+	  STAT(tcpstat.tcps_rcvbadoff++);
 	  goto drop;
 	}
 	tlen -= off;
 	ti->ti_len = tlen;
 	if (off > sizeof (struct tcphdr)) {
 	  optlen = off - sizeof (struct tcphdr);
-	  optp = MBUF_TO(m, caddr_t) + sizeof (struct tcpiphdr);
+	  optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
 
 		/*
 		 * Do quick retrieval of timestamp options ("options
@@ -363,27 +358,30 @@
 	m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 
+    if (slirp_restrict) {
+        for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+            if (ex_ptr->ex_fport == ti->ti_dport &&
+                    (ntohl(ti->ti_dst.s_addr) & 0xff) == ex_ptr->ex_addr)
+                break;
+
+        if (!ex_ptr)
+            goto drop;
+    }
 	/*
 	 * Locate pcb for segment.
 	 */
 findso:
 	so = tcp_last_so;
-        {
-            uint32_t  srcip   = ip_geth(ti->ti_src);
-            uint32_t  dstip   = ip_geth(ti->ti_dst);
-            uint16_t  dstport = port_geth(ti->ti_dport);
-            uint16_t  srcport = port_geth(ti->ti_sport);
- 
-	if (so->so_faddr_port != dstport ||
-	    so->so_laddr_port != srcport ||
-	    so->so_laddr_ip   != srcip ||
-	    so->so_faddr_ip   != dstip) {
-		so = solookup(&tcb, srcip, srcport, dstip, dstport);
+	if (so->so_fport != ti->ti_dport ||
+	    so->so_lport != ti->ti_sport ||
+	    so->so_laddr.s_addr != ti->ti_src.s_addr ||
+	    so->so_faddr.s_addr != ti->ti_dst.s_addr) {
+		so = solookup(&tcb, ti->ti_src, ti->ti_sport,
+			       ti->ti_dst, ti->ti_dport);
 		if (so)
 			tcp_last_so = so;
-		++tcpstat.tcps_socachemiss;
+		STAT(tcpstat.tcps_socachemiss++);
 	}
-        }
 
 	/*
 	 * If the state is CLOSED (i.e., TCB does not exist) then
@@ -398,7 +396,7 @@
 	 * the only flag set, then create a session, mark it
 	 * as if it was LISTENING, and continue...
 	 */
-	if (so == 0) {
+        if (so == NULL) {
 	  if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
 	    goto dropwithreset;
 
@@ -409,16 +407,16 @@
 	    goto dropwithreset;
 	  }
 
-	  sbuf_reserve(&so->so_snd, tcp_sndspace);
-	  sbuf_reserve(&so->so_rcv, tcp_rcvspace);
+	  sbreserve(&so->so_snd, TCP_SNDSPACE);
+	  sbreserve(&so->so_rcv, TCP_RCVSPACE);
 
 	  /*		tcp_last_so = so; */  /* XXX ? */
 	  /*		tp = sototcpcb(so);    */
 
-	  so->so_laddr_ip   = ip_geth(ti->ti_src);
-	  so->so_laddr_port = port_geth(ti->ti_sport);
-	  so->so_faddr_ip   = ip_geth(ti->ti_dst);
-	  so->so_faddr_port = port_geth(ti->ti_dport);
+	  so->so_laddr = ti->ti_src;
+	  so->so_lport = ti->ti_sport;
+	  so->so_faddr = ti->ti_dst;
+	  so->so_fport = ti->ti_dport;
 
 	  if ((so->so_iptos = tcp_tos(so)) == 0)
 	    so->so_iptos = ((struct ip *)ti)->ip_tos;
@@ -438,7 +436,7 @@
 	tp = sototcpcb(so);
 
 	/* XXX Should never fail */
-	if (tp == 0)
+        if (tp == NULL)
 		goto dropwithreset;
 	if (tp->t_state == TCPS_CLOSED)
 		goto drop;
@@ -455,10 +453,10 @@
 	 * Reset idle time and keep-alive timer.
 	 */
 	tp->t_idle = 0;
-	if (so_options)
-	   tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
+	if (SO_OPTIONS)
+	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
 	else
-	   tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
 
 	/*
 	 * Process options if not in LISTEN state,
@@ -510,7 +508,7 @@
 				/*
 				 * this is a pure ack for outstanding data.
 				 */
-				++tcpstat.tcps_predack;
+				STAT(tcpstat.tcps_predack++);
 /*				if (ts_present)
  *					tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
  *				else
@@ -518,11 +516,11 @@
 					    SEQ_GT(ti->ti_ack, tp->t_rtseq))
 					tcp_xmit_timer(tp, tp->t_rtt);
 				acked = ti->ti_ack - tp->snd_una;
-				tcpstat.tcps_rcvackpack++;
-				tcpstat.tcps_rcvackbyte += acked;
-				sbuf_drop(&so->so_snd, acked);
+				STAT(tcpstat.tcps_rcvackpack++);
+				STAT(tcpstat.tcps_rcvackbyte += acked);
+				sbdrop(&so->so_snd, acked);
 				tp->snd_una = ti->ti_ack;
-				mbuf_free(m);
+				m_freem(m);
 
 				/*
 				 * If all outstanding data are acked, stop
@@ -557,23 +555,23 @@
 			}
 		} else if (ti->ti_ack == tp->snd_una &&
 		    tcpfrag_list_empty(tp) &&
-		    ti->ti_len <= sbuf_space(&so->so_rcv)) {
+		    ti->ti_len <= sbspace(&so->so_rcv)) {
 			/*
 			 * this is a pure, in-sequence data packet
 			 * with nothing on the reassembly queue and
 			 * we have enough buffer space to take it.
 			 */
-			++tcpstat.tcps_preddat;
+			STAT(tcpstat.tcps_preddat++);
 			tp->rcv_nxt += ti->ti_len;
-			tcpstat.tcps_rcvpack++;
-			tcpstat.tcps_rcvbyte += ti->ti_len;
+			STAT(tcpstat.tcps_rcvpack++);
+			STAT(tcpstat.tcps_rcvbyte += ti->ti_len);
 			/*
 			 * Add data to socket buffer.
 			 */
 			if (so->so_emu) {
-				if (tcp_emu(so,m)) sbuf_append(so, m);
+				if (tcp_emu(so,m)) sbappend(so, m);
 			} else
-				sbuf_append(so, m);
+				sbappend(so, m);
 
 			/*
 			 * XXX This is called when data arrives.  Later, check
@@ -602,7 +600,7 @@
 	 * but not less than advertised window.
 	 */
 	{ int win;
-          win = sbuf_space(&so->so_rcv);
+          win = sbspace(&so->so_rcv);
 	  if (win < 0)
 	    win = 0;
 	  tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
@@ -641,8 +639,27 @@
 	   * If this is destined for the control address, then flag to
 	   * tcp_ctl once connected, otherwise connect
 	   */
-	  if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) {
-	    //int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff;
+	  if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) {
+	    int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff;
+	    if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) {
+#if 0
+	      if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) {
+		/* Command or exec adress */
+		so->so_state |= SS_CTL;
+	      } else
+#endif
+              {
+		/* May be an add exec */
+		for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+		  if(ex_ptr->ex_fport == so->so_fport &&
+		     lastbyte == ex_ptr->ex_addr) {
+		    so->so_state |= SS_CTL;
+		    break;
+		  }
+		}
+	      }
+	      if(so->so_state & SS_CTL) goto cont_input;
+	    }
 	    /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
 	  }
 
@@ -654,7 +671,7 @@
 	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
 	    u_char code=ICMP_UNREACH_NET;
 	    DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
-			errno,errno_str));
+			errno,strerror(errno)));
 	    if(errno == ECONNREFUSED) {
 	      /* ACK the SYN, send RST to refuse the connection */
 	      tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,
@@ -668,10 +685,10 @@
 	      m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	      *ip=save_ip;
-	      icmp_error(m, ICMP_UNREACH,code, 0,errno_str);
+	      icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));
 	    }
 	    tp = tcp_close(tp);
-	    mbuf_free(m);
+	    m_free(m);
 	  } else {
 	    /*
 	     * Haven't connected yet, save the current mbuf
@@ -691,7 +708,6 @@
 	   * Check if the connect succeeded
 	   */
 	  if (so->so_state & SS_NOFDREF) {
-            DEBUG_MISC((dfd, " tcp_input closing connecting socket %lx\n", (long)so));
 	    tp = tcp_close(tp);
 	    goto dropwithreset;
 	  }
@@ -714,8 +730,7 @@
 	  tp->t_flags |= TF_ACKNOW;
 	  tp->t_state = TCPS_SYN_RECEIVED;
 	  tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
-	  tcpstat.tcps_accepts++;
-          DEBUG_MISC((dfd, " tcp_input accept connected socket %lx\n", (long)so));
+	  STAT(tcpstat.tcps_accepts++);
 	  goto trimthenstep6;
 	} /* case TCPS_LISTEN */
 
@@ -756,7 +771,7 @@
 		tcp_rcvseqinit(tp);
 		tp->t_flags |= TF_ACKNOW;
 		if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
-			tcpstat.tcps_connects++;
+			STAT(tcpstat.tcps_connects++);
 			soisfconnected(so);
 			tp->t_state = TCPS_ESTABLISHED;
 
@@ -768,7 +783,7 @@
  *			}
  */
 			(void) tcp_reass(tp, (struct tcpiphdr *)0,
-				(MBuf )0);
+				(struct mbuf *)0);
 			/*
 			 * if we didn't have to retransmit the SYN,
 			 * use its rtt as our initial srtt & rtt var.
@@ -787,11 +802,11 @@
 		ti->ti_seq++;
 		if (ti->ti_len > tp->rcv_wnd) {
 			todrop = ti->ti_len - tp->rcv_wnd;
-			mbuf_trim(m, -todrop);
+			m_adj(m, -todrop);
 			ti->ti_len = tp->rcv_wnd;
 			tiflags &= ~TH_FIN;
-			tcpstat.tcps_rcvpackafterwin++;
-			tcpstat.tcps_rcvbyteafterwin += todrop;
+			STAT(tcpstat.tcps_rcvpackafterwin++);
+			STAT(tcpstat.tcps_rcvbyteafterwin += todrop);
 		}
 		tp->snd_wl1 = ti->ti_seq - 1;
 		tp->rcv_up = ti->ti_seq;
@@ -862,13 +877,13 @@
 			 */
 			tp->t_flags |= TF_ACKNOW;
 			todrop = ti->ti_len;
-			tcpstat.tcps_rcvduppack++;
-			tcpstat.tcps_rcvdupbyte += todrop;
+			STAT(tcpstat.tcps_rcvduppack++);
+			STAT(tcpstat.tcps_rcvdupbyte += todrop);
 		} else {
-			tcpstat.tcps_rcvpartduppack++;
-			tcpstat.tcps_rcvpartdupbyte += todrop;
+			STAT(tcpstat.tcps_rcvpartduppack++);
+			STAT(tcpstat.tcps_rcvpartdupbyte += todrop);
 		}
-		mbuf_trim(m, todrop);
+		m_adj(m, todrop);
 		ti->ti_seq += todrop;
 		ti->ti_len -= todrop;
 		if (ti->ti_urp > todrop)
@@ -885,7 +900,7 @@
 	if ((so->so_state & SS_NOFDREF) &&
 	    tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
 		tp = tcp_close(tp);
-		tcpstat.tcps_rcvafterclose++;
+		STAT(tcpstat.tcps_rcvafterclose++);
 		goto dropwithreset;
 	}
 
@@ -895,9 +910,9 @@
 	 */
 	todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
 	if (todrop > 0) {
-		tcpstat.tcps_rcvpackafterwin++;
+		STAT(tcpstat.tcps_rcvpackafterwin++);
 		if (todrop >= ti->ti_len) {
-			tcpstat.tcps_rcvbyteafterwin += ti->ti_len;
+			STAT(tcpstat.tcps_rcvbyteafterwin += ti->ti_len);
 			/*
 			 * If a new connection request is received
 			 * while in TIME_WAIT, drop the old connection
@@ -920,12 +935,12 @@
 			 */
 			if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
 				tp->t_flags |= TF_ACKNOW;
-				tcpstat.tcps_rcvwinprobe++;
+				STAT(tcpstat.tcps_rcvwinprobe++);
 			} else
 				goto dropafterack;
 		} else
-			tcpstat.tcps_rcvbyteafterwin += todrop;
-		mbuf_trim(m, -todrop);
+			STAT(tcpstat.tcps_rcvbyteafterwin += todrop);
+		m_adj(m, -todrop);
 		ti->ti_len -= todrop;
 		tiflags &= ~(TH_PUSH|TH_FIN);
 	}
@@ -965,7 +980,7 @@
 /*		so->so_error = ECONNRESET; */
 	close:
 		tp->t_state = TCPS_CLOSED;
-		tcpstat.tcps_drops++;
+		STAT(tcpstat.tcps_drops++);
 		tp = tcp_close(tp);
 		goto drop;
 
@@ -1004,7 +1019,7 @@
 		if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
 		    SEQ_GT(ti->ti_ack, tp->snd_max))
 			goto dropwithreset;
-		tcpstat.tcps_connects++;
+		STAT(tcpstat.tcps_connects++);
 		tp->t_state = TCPS_ESTABLISHED;
 		/*
 		 * The sent SYN is ack'ed with our sequence number +1
@@ -1037,7 +1052,7 @@
  *			tp->rcv_scale = tp->request_r_scale;
  *		}
  */
-		(void) tcp_reass(tp, (struct tcpiphdr *)0, (MBuf )0);
+		(void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
 		tp->snd_wl1 = ti->ti_seq - 1;
 		/* Avoid ack processing; snd_una==ti_ack  =>  dup ack */
 		goto synrx_to_est;
@@ -1061,7 +1076,7 @@
 
 		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
 			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
-			  tcpstat.tcps_rcvdupack++;
+			  STAT(tcpstat.tcps_rcvdupack++);
 			  DEBUG_MISC((dfd," dup ack  m = %lx  so = %lx \n",
 				      (long )m, (long )so));
 				/*
@@ -1091,7 +1106,7 @@
 				if (tp->t_timer[TCPT_REXMT] == 0 ||
 				    ti->ti_ack != tp->snd_una)
 					tp->t_dupacks = 0;
-				else if (++tp->t_dupacks == tcprexmtthresh) {
+				else if (++tp->t_dupacks == TCPREXMTTHRESH) {
 					tcp_seq onxt = tp->snd_nxt;
 					u_int win =
 					    min(tp->snd_wnd, tp->snd_cwnd) / 2 /
@@ -1110,7 +1125,7 @@
 					if (SEQ_GT(onxt, tp->snd_nxt))
 						tp->snd_nxt = onxt;
 					goto drop;
-				} else if (tp->t_dupacks > tcprexmtthresh) {
+				} else if (tp->t_dupacks > TCPREXMTTHRESH) {
 					tp->snd_cwnd += tp->t_maxseg;
 					(void) tcp_output(tp);
 					goto drop;
@@ -1124,17 +1139,17 @@
 		 * If the congestion window was inflated to account
 		 * for the other side's cached packets, retract it.
 		 */
-		if (tp->t_dupacks > tcprexmtthresh &&
+		if (tp->t_dupacks > TCPREXMTTHRESH &&
 		    tp->snd_cwnd > tp->snd_ssthresh)
 			tp->snd_cwnd = tp->snd_ssthresh;
 		tp->t_dupacks = 0;
 		if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
-			tcpstat.tcps_rcvacktoomuch++;
+			STAT(tcpstat.tcps_rcvacktoomuch++);
 			goto dropafterack;
 		}
 		acked = ti->ti_ack - tp->snd_una;
-		tcpstat.tcps_rcvackpack++;
-		tcpstat.tcps_rcvackbyte += acked;
+		STAT(tcpstat.tcps_rcvackpack++);
+		STAT(tcpstat.tcps_rcvackbyte += acked);
 
 		/*
 		 * If we have a timestamp reply, update smoothed
@@ -1180,10 +1195,10 @@
 		}
 		if (acked > so->so_snd.sb_cc) {
 			tp->snd_wnd -= so->so_snd.sb_cc;
-			sbuf_drop(&so->so_snd, (int )so->so_snd.sb_cc);
+			sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);
 			ourfinisacked = 1;
 		} else {
-			sbuf_drop(&so->so_snd, acked);
+			sbdrop(&so->so_snd, acked);
 			tp->snd_wnd -= acked;
 			ourfinisacked = 0;
 		}
@@ -1216,7 +1231,7 @@
 				 */
 				if (so->so_state & SS_FCANTRCVMORE) {
 					soisfdisconnected(so);
-					tp->t_timer[TCPT_2MSL] = tcp_maxidle;
+					tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;
 				}
 				tp->t_state = TCPS_FIN_WAIT_2;
 			}
@@ -1273,7 +1288,7 @@
 		/* keep track of pure window updates */
 		if (ti->ti_len == 0 &&
 		    tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd)
-			tcpstat.tcps_rcvwinupd++;
+			STAT(tcpstat.tcps_rcvwinupd++);
 		tp->snd_wnd = tiwin;
 		tp->snd_wl1 = ti->ti_seq;
 		tp->snd_wl2 = ti->ti_ack;
@@ -1347,7 +1362,7 @@
 		 */
 		len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt);
 	} else {
-		mbuf_free(m);
+		m_free(m);
 		tiflags &= ~TH_FIN;
 	}
 
@@ -1449,13 +1464,13 @@
 	 */
 	if (tiflags & TH_RST)
 		goto drop;
-	mbuf_free(m);
+	m_freem(m);
 	tp->t_flags |= TF_ACKNOW;
 	(void) tcp_output(tp);
 	return;
 
 dropwithreset:
-	/* reuses m if m!=NULL, mbuf_free() unnecessary */
+	/* reuses m if m!=NULL, m_free() unnecessary */
 	if (tiflags & TH_ACK)
 		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
 	else {
@@ -1470,7 +1485,7 @@
 	/*
 	 * Drop space held by incoming segment and return.
 	 */
-	mbuf_free(m);
+	m_free(m);
 
 	return;
 }
@@ -1479,12 +1494,8 @@
 /*	int *ts_present;
  *	u_int32_t *ts_val, *ts_ecr;
  */
-void
-tcp_dooptions(tp, cp, cnt, ti)
-	struct tcpcb *tp;
-	u_char *cp;
-	int cnt;
-	struct tcpiphdr *ti;
+static void
+tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
 {
 	u_int16_t mss;
 	int opt, optlen;
@@ -1564,13 +1575,13 @@
 tcp_pulloutofband(so, ti, m)
 	struct socket *so;
 	struct tcpiphdr *ti;
-	register MBuf m;
+	register struct mbuf *m;
 {
 	int cnt = ti->ti_urp - 1;
 
 	while (cnt >= 0) {
 		if (m->m_len > cnt) {
-			char *cp = MBUF_TO(m, caddr_t) + cnt;
+			char *cp = mtod(m, caddr_t) + cnt;
 			struct tcpcb *tp = sototcpcb(so);
 
 			tp->t_iobc = *cp;
@@ -1594,10 +1605,8 @@
  * and update averages and current timeout.
  */
 
-void
-tcp_xmit_timer(tp, rtt)
-	register struct tcpcb *tp;
-	int rtt;
+static void
+tcp_xmit_timer(register struct tcpcb *tp, int rtt)
 {
 	register short delta;
 
@@ -1605,7 +1614,7 @@
 	DEBUG_ARG("tp = %lx", (long)tp);
 	DEBUG_ARG("rtt = %d", rtt);
 
-	tcpstat.tcps_rttupdated++;
+	STAT(tcpstat.tcps_rttupdated++);
 	if (tp->t_srtt != 0) {
 		/*
 		 * srtt is stored as fixed point with 3 bits after the
@@ -1685,9 +1694,7 @@
  */
 
 int
-tcp_mss(tp, offer)
-        register struct tcpcb *tp;
-        u_int offer;
+tcp_mss(struct tcpcb *tp, u_int offer)
 {
 	struct socket *so = tp->t_socket;
 	int mss;
@@ -1696,7 +1703,7 @@
 	DEBUG_ARG("tp = %lx", (long)tp);
 	DEBUG_ARG("offer = %d", offer);
 
-	mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr);
+	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr);
 	if (offer)
 		mss = min(mss, offer);
 	mss = max(mss, 32);
@@ -1705,8 +1712,12 @@
 
 	tp->snd_cwnd = mss;
 
-	sbuf_reserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0));
-	sbuf_reserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0));
+	sbreserve(&so->so_snd, TCP_SNDSPACE + ((TCP_SNDSPACE % mss) ?
+                                               (mss - (TCP_SNDSPACE % mss)) :
+                                               0));
+	sbreserve(&so->so_rcv, TCP_RCVSPACE + ((TCP_RCVSPACE % mss) ?
+                                               (mss - (TCP_RCVSPACE % mss)) :
+                                               0));
 
 	DEBUG_MISC((dfd, " returning mss = %d\n", mss));
 
diff --git a/slirp2/tcp_output.c b/slirp/tcp_output.c
similarity index 91%
copy from slirp2/tcp_output.c
copy to slirp/tcp_output.c
index 95246aa..9ed50f5 100644
--- a/slirp2/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -37,8 +33,8 @@
 /*
  * Changes and additions relating to SLiRP
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -48,16 +44,16 @@
  * Since this is only used in "stats socket", we give meaning
  * names instead of the REAL names
  */
-char *tcpstates[] = {
+const char * const tcpstates[] = {
 /*	"CLOSED",       "LISTEN",       "SYN_SENT",     "SYN_RCVD", */
 	"REDIRECT",	"LISTEN",	"SYN_SENT",     "SYN_RCVD",
 	"ESTABLISHED",  "CLOSE_WAIT",   "FIN_WAIT_1",   "CLOSING",
 	"LAST_ACK",     "FIN_WAIT_2",   "TIME_WAIT",
 };
 
-u_char  tcp_outflags[TCP_NSTATES] = {
+static const u_char  tcp_outflags[TCP_NSTATES] = {
 	TH_RST|TH_ACK, 0,      TH_SYN,        TH_SYN|TH_ACK,
-	TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, 
+	TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK,
 	TH_FIN|TH_ACK, TH_ACK, TH_ACK,
 };
 
@@ -68,21 +64,20 @@
  * Tcp output routine: figure out what should be sent and send it.
  */
 int
-tcp_output(tp)
-	register struct tcpcb *tp;
+tcp_output(struct tcpcb *tp)
 {
 	register struct socket *so = tp->t_socket;
 	register long len, win;
 	int off, flags, error;
-	register MBuf m;
+	register struct mbuf *m;
 	register struct tcpiphdr *ti;
 	u_char opt[MAX_TCPOPTLEN];
 	unsigned optlen, hdrlen;
 	int idle, sendalot;
-	
+
 	DEBUG_CALL("tcp_output");
 	DEBUG_ARG("tp = %lx", (long )tp);
-	
+
 	/*
 	 * Determine length of data that should be transmitted,
 	 * and flags that will be used.
@@ -103,9 +98,9 @@
 	win = min(tp->snd_wnd, tp->snd_cwnd);
 
 	flags = tcp_outflags[tp->t_state];
-	
+
 	DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags));
-	
+
 	/*
 	 * If in persist timeout with window of 0, send 1 byte.
 	 * Otherwise, if window is small but nonzero
@@ -158,7 +153,7 @@
 			tp->snd_nxt = tp->snd_una;
 		}
 	}
-	
+
 	if (len > tp->t_maxseg) {
 		len = tp->t_maxseg;
 		sendalot = 1;
@@ -166,7 +161,7 @@
 	if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
 		flags &= ~TH_FIN;
 
-	win = sbuf_space(&so->so_rcv);
+	win = sbspace(&so->so_rcv);
 
 	/*
 	 * Sender silly window avoidance.  If connection is idle
@@ -200,7 +195,7 @@
 	 * window, then want to send a window update to peer.
 	 */
 	if (win > 0) {
-		/* 
+		/*
 		 * "adv" is the amount we can increase the window,
 		 * taking into account that we are limited by
 		 * TCP_MAXWIN << tp->rcv_scale.
@@ -263,8 +258,8 @@
 	/*
 	 * No reason to send a segment, just return.
 	 */
-	tcpstat.tcps_didnuttin++;
-	
+	STAT(tcpstat.tcps_didnuttin++);
+
 	return (0);
 
 send:
@@ -302,9 +297,9 @@
  */
 		}
  	}
- 
+
  	/*
-	 * Send a timestamp and echo-reply if this is a SYN and our side 
+	 * Send a timestamp and echo-reply if this is a SYN and our side
 	 * wants to use timestamps (TF_REQ_TSTMP is set) or both our side
 	 * and our peer have sent timestamps in our SYN's.
  	 */
@@ -322,7 +317,7 @@
  *	}
  */
  	hdrlen += optlen;
- 
+
 	/*
 	 * Adjust data length if insertion of options will
 	 * bump the packet length beyond the t_maxseg length.
@@ -339,35 +334,35 @@
 	 */
 	if (len) {
 		if (tp->t_force && len == 1)
-			tcpstat.tcps_sndprobe++;
+			STAT(tcpstat.tcps_sndprobe++);
 		else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
-			tcpstat.tcps_sndrexmitpack++;
-			tcpstat.tcps_sndrexmitbyte += len;
+			STAT(tcpstat.tcps_sndrexmitpack++);
+			STAT(tcpstat.tcps_sndrexmitbyte += len);
 		} else {
-			tcpstat.tcps_sndpack++;
-			tcpstat.tcps_sndbyte += len;
+			STAT(tcpstat.tcps_sndpack++);
+			STAT(tcpstat.tcps_sndbyte += len);
 		}
 
-		m = mbuf_alloc();
+		m = m_get();
 		if (m == NULL) {
 /*			error = ENOBUFS; */
 			error = 1;
 			goto out;
 		}
-		m->m_data += if_maxlinkhdr;
+		m->m_data += IF_MAXLINKHDR;
 		m->m_len = hdrlen;
-		
-		/* 
+
+		/*
 		 * This will always succeed, since we make sure our mbufs
 		 * are big enough to hold one MSS packet + header + ... etc.
 		 */
 /*		if (len <= MHLEN - hdrlen - max_linkhdr) { */
 
-			sbuf_copy(&so->so_snd, off, (int) len, MBUF_TO(m, caddr_t) + hdrlen);
+			sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen);
 			m->m_len += len;
 
 /*		} else {
- *			m->m_next = mbuf_copy(so->so_snd.sb_mb, off, (int) len);
+ *			m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
  *			if (m->m_next == 0)
  *				len = 0;
  *		}
@@ -382,26 +377,26 @@
 			flags |= TH_PUSH;
 	} else {
 		if (tp->t_flags & TF_ACKNOW)
-			tcpstat.tcps_sndacks++;
+			STAT(tcpstat.tcps_sndacks++);
 		else if (flags & (TH_SYN|TH_FIN|TH_RST))
-			tcpstat.tcps_sndctrl++;
+			STAT(tcpstat.tcps_sndctrl++);
 		else if (SEQ_GT(tp->snd_up, tp->snd_una))
-			tcpstat.tcps_sndurg++;
+			STAT(tcpstat.tcps_sndurg++);
 		else
-			tcpstat.tcps_sndwinup++;
+			STAT(tcpstat.tcps_sndwinup++);
 
-		m = mbuf_alloc();
+		m = m_get();
 		if (m == NULL) {
 /*			error = ENOBUFS; */
 			error = 1;
 			goto out;
 		}
-		m->m_data += if_maxlinkhdr;
+		m->m_data += IF_MAXLINKHDR;
 		m->m_len = hdrlen;
 	}
 
-	ti = MBUF_TO(m, struct tcpiphdr *);
-	
+	ti = mtod(m, struct tcpiphdr *);
+
 	memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr));
 
 	/*
@@ -409,7 +404,7 @@
 	 * window for use in delaying messages about window sizes.
 	 * If resending a FIN, be sure not to use a new sequence number.
 	 */
-	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && 
+	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
 	    tp->snd_nxt == tp->snd_max)
 		tp->snd_nxt--;
 	/*
@@ -446,10 +441,10 @@
 	if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
 		win = (long)(tp->rcv_adv - tp->rcv_nxt);
 	ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale));
-	
+
 	if (SEQ_GT(tp->snd_up, tp->snd_una)) {
 		ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq)));
-#ifdef notdef		
+#ifdef notdef
 	if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
 		ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt));
 #endif
@@ -500,7 +495,7 @@
 			if (tp->t_rtt == 0) {
 				tp->t_rtt = 1;
 				tp->t_rtseq = startseq;
-				tcpstat.tcps_segstimed++;
+				STAT(tcpstat.tcps_segstimed++);
 			}
 		}
 
@@ -531,14 +526,14 @@
 	 * the template, but need a way to checksum without them.
 	 */
 	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
-	
+
     {
-	    
+
 	((struct ip *)ti)->ip_len = m->m_len;
 
-	((struct ip *)ti)->ip_ttl = ip_defttl;
+	((struct ip *)ti)->ip_ttl = IPDEFTTL;
 	((struct ip *)ti)->ip_tos = so->so_iptos;
-	    
+
 /* #if BSD >= 43 */
 	/* Don't do IP options... */
 /*	error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
@@ -547,7 +542,7 @@
 	error = ip_output(so, m);
 
 /* #else
- *	error = ip_output(m, (MBuf )0, &tp->t_inpcb->inp_route, 
+ *	error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route,
  *	    so->so_options & SO_DONTROUTE);
  * #endif
  */
@@ -567,7 +562,7 @@
  */
 		return (error);
 	}
-	tcpstat.tcps_sndtotal++;
+	STAT(tcpstat.tcps_sndtotal++);
 
 	/*
 	 * Data sent (as far as we can tell).
@@ -586,8 +581,7 @@
 }
 
 void
-tcp_setpersist(tp)
-	register struct tcpcb *tp;
+tcp_setpersist(struct tcpcb *tp)
 {
     int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;
 
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
new file mode 100644
index 0000000..9d020a6
--- /dev/null
+++ b/slirp/tcp_subr.c
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)tcp_subr.c	8.1 (Berkeley) 6/10/93
+ * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+
+/* patchable/settable parameters for tcp */
+/* Don't do rfc1323 performance enhancements */
+#define TCP_DO_RFC1323 0
+
+/*
+ * Tcp initialization
+ */
+void
+tcp_init(void)
+{
+	tcp_iss = 1;		/* wrong */
+	tcb.so_next = tcb.so_prev = &tcb;
+}
+
+/*
+ * Create template to be used to send tcp packets on a connection.
+ * Call after host entry created, fills
+ * in a skeletal tcp/ip header, minimizing the amount of work
+ * necessary when the connection is used.
+ */
+/* struct tcpiphdr * */
+void
+tcp_template(struct tcpcb *tp)
+{
+	struct socket *so = tp->t_socket;
+	register struct tcpiphdr *n = &tp->t_template;
+
+	n->ti_mbuf = NULL;
+	n->ti_x1 = 0;
+	n->ti_pr = IPPROTO_TCP;
+	n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
+	n->ti_src = so->so_faddr;
+	n->ti_dst = so->so_laddr;
+	n->ti_sport = so->so_fport;
+	n->ti_dport = so->so_lport;
+
+	n->ti_seq = 0;
+	n->ti_ack = 0;
+	n->ti_x2 = 0;
+	n->ti_off = 5;
+	n->ti_flags = 0;
+	n->ti_win = 0;
+	n->ti_sum = 0;
+	n->ti_urp = 0;
+}
+
+/*
+ * Send a single message to the TCP at address specified by
+ * the given TCP/IP header.  If m == 0, then we make a copy
+ * of the tcpiphdr at ti and send directly to the addressed host.
+ * This is used to force keep alive messages out using the TCP
+ * template for a connection tp->t_template.  If flags are given
+ * then we send a message back to the TCP which originated the
+ * segment ti, and discard the mbuf containing it and any other
+ * attached mbufs.
+ *
+ * In any case the ack and sequence number of the transmitted
+ * segment are as specified by the parameters.
+ */
+void
+tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
+            tcp_seq ack, tcp_seq seq, int flags)
+{
+	register int tlen;
+	int win = 0;
+
+	DEBUG_CALL("tcp_respond");
+	DEBUG_ARG("tp = %lx", (long)tp);
+	DEBUG_ARG("ti = %lx", (long)ti);
+	DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("ack = %u", ack);
+	DEBUG_ARG("seq = %u", seq);
+	DEBUG_ARG("flags = %x", flags);
+
+	if (tp)
+		win = sbspace(&tp->t_socket->so_rcv);
+        if (m == NULL) {
+		if ((m = m_get()) == NULL)
+			return;
+#ifdef TCP_COMPAT_42
+		tlen = 1;
+#else
+		tlen = 0;
+#endif
+		m->m_data += IF_MAXLINKHDR;
+		*mtod(m, struct tcpiphdr *) = *ti;
+		ti = mtod(m, struct tcpiphdr *);
+		flags = TH_ACK;
+	} else {
+		/*
+		 * ti points into m so the next line is just making
+		 * the mbuf point to ti
+		 */
+		m->m_data = (caddr_t)ti;
+
+		m->m_len = sizeof (struct tcpiphdr);
+		tlen = 0;
+#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
+		xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t);
+		xchg(ti->ti_dport, ti->ti_sport, u_int16_t);
+#undef xchg
+	}
+	ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
+	tlen += sizeof (struct tcpiphdr);
+	m->m_len = tlen;
+
+        ti->ti_mbuf = NULL;
+	ti->ti_x1 = 0;
+	ti->ti_seq = htonl(seq);
+	ti->ti_ack = htonl(ack);
+	ti->ti_x2 = 0;
+	ti->ti_off = sizeof (struct tcphdr) >> 2;
+	ti->ti_flags = flags;
+	if (tp)
+		ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale));
+	else
+		ti->ti_win = htons((u_int16_t)win);
+	ti->ti_urp = 0;
+	ti->ti_sum = 0;
+	ti->ti_sum = cksum(m, tlen);
+	((struct ip *)ti)->ip_len = tlen;
+
+	if(flags & TH_RST)
+	  ((struct ip *)ti)->ip_ttl = MAXTTL;
+	else
+	  ((struct ip *)ti)->ip_ttl = IPDEFTTL;
+
+	(void) ip_output((struct socket *)0, m);
+}
+
+/*
+ * Create a new TCP control block, making an
+ * empty reassembly queue and hooking it to the argument
+ * protocol control block.
+ */
+struct tcpcb *
+tcp_newtcpcb(struct socket *so)
+{
+	register struct tcpcb *tp;
+
+	tp = (struct tcpcb *)malloc(sizeof(*tp));
+	if (tp == NULL)
+		return ((struct tcpcb *)0);
+
+	memset((char *) tp, 0, sizeof(struct tcpcb));
+	tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
+	tp->t_maxseg = TCP_MSS;
+
+	tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
+	tp->t_socket = so;
+
+	/*
+	 * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
+	 * rtt estimate.  Set rttvar so that srtt + 2 * rttvar gives
+	 * reasonable initial retransmit time.
+	 */
+	tp->t_srtt = TCPTV_SRTTBASE;
+	tp->t_rttvar = TCPTV_SRTTDFLT << 2;
+	tp->t_rttmin = TCPTV_MIN;
+
+	TCPT_RANGESET(tp->t_rxtcur,
+	    ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
+	    TCPTV_MIN, TCPTV_REXMTMAX);
+
+	tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+	tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
+	tp->t_state = TCPS_CLOSED;
+
+	so->so_tcpcb = tp;
+
+	return (tp);
+}
+
+/*
+ * Drop a TCP connection, reporting
+ * the specified error.  If connection is synchronized,
+ * then send a RST to peer.
+ */
+struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
+{
+/* tcp_drop(tp, errno)
+	register struct tcpcb *tp;
+	int errno;
+{
+*/
+
+	DEBUG_CALL("tcp_drop");
+	DEBUG_ARG("tp = %lx", (long)tp);
+	DEBUG_ARG("errno = %d", errno);
+
+	if (TCPS_HAVERCVDSYN(tp->t_state)) {
+		tp->t_state = TCPS_CLOSED;
+		(void) tcp_output(tp);
+		STAT(tcpstat.tcps_drops++);
+	} else
+		STAT(tcpstat.tcps_conndrops++);
+/*	if (errno == ETIMEDOUT && tp->t_softerror)
+ *		errno = tp->t_softerror;
+ */
+/*	so->so_error = errno; */
+	return (tcp_close(tp));
+}
+
+/*
+ * Close a TCP control block:
+ *	discard all space held by the tcp
+ *	discard internet protocol block
+ *	wake up any sleepers
+ */
+struct tcpcb *
+tcp_close(struct tcpcb *tp)
+{
+	register struct tcpiphdr *t;
+	struct socket *so = tp->t_socket;
+	register struct mbuf *m;
+
+	DEBUG_CALL("tcp_close");
+	DEBUG_ARG("tp = %lx", (long )tp);
+
+	/* free the reassembly queue, if any */
+	t = tcpfrag_list_first(tp);
+	while (!tcpfrag_list_end(t, tp)) {
+		t = tcpiphdr_next(t);
+		m = tcpiphdr_prev(t)->ti_mbuf;
+		remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
+		m_freem(m);
+	}
+	/* It's static */
+/*	if (tp->t_template)
+ *		(void) m_free(dtom(tp->t_template));
+ */
+/*	free(tp, M_PCB);  */
+	free(tp);
+        so->so_tcpcb = NULL;
+	soisfdisconnected(so);
+	/* clobber input socket cache if we're closing the cached connection */
+	if (so == tcp_last_so)
+		tcp_last_so = &tcb;
+	closesocket(so->s);
+	sbfree(&so->so_rcv);
+	sbfree(&so->so_snd);
+	sofree(so);
+	STAT(tcpstat.tcps_closed++);
+	return ((struct tcpcb *)0);
+}
+
+#ifdef notdef
+void
+tcp_drain()
+{
+	/* XXX */
+}
+
+/*
+ * When a source quench is received, close congestion window
+ * to one segment.  We will gradually open it again as we proceed.
+ */
+void
+tcp_quench(i, errno)
+
+	int errno;
+{
+	struct tcpcb *tp = intotcpcb(inp);
+
+	if (tp)
+		tp->snd_cwnd = tp->t_maxseg;
+}
+
+#endif /* notdef */
+
+/*
+ * TCP protocol interface to socket abstraction.
+ */
+
+/*
+ * User issued close, and wish to trail through shutdown states:
+ * if never received SYN, just forget it.  If got a SYN from peer,
+ * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
+ * If already got a FIN from peer, then almost done; go to LAST_ACK
+ * state.  In all other cases, have already sent FIN to peer (e.g.
+ * after PRU_SHUTDOWN), and just have to play tedious game waiting
+ * for peer to send FIN or not respond to keep-alives, etc.
+ * We can let the user exit from the close as soon as the FIN is acked.
+ */
+void
+tcp_sockclosed(struct tcpcb *tp)
+{
+
+	DEBUG_CALL("tcp_sockclosed");
+	DEBUG_ARG("tp = %lx", (long)tp);
+
+	switch (tp->t_state) {
+
+	case TCPS_CLOSED:
+	case TCPS_LISTEN:
+	case TCPS_SYN_SENT:
+		tp->t_state = TCPS_CLOSED;
+		tp = tcp_close(tp);
+		break;
+
+	case TCPS_SYN_RECEIVED:
+	case TCPS_ESTABLISHED:
+		tp->t_state = TCPS_FIN_WAIT_1;
+		break;
+
+	case TCPS_CLOSE_WAIT:
+		tp->t_state = TCPS_LAST_ACK;
+		break;
+	}
+/*	soisfdisconnecting(tp->t_socket); */
+	if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
+		soisfdisconnected(tp->t_socket);
+	if (tp)
+		tcp_output(tp);
+}
+
+/*
+ * Connect to a host on the Internet
+ * Called by tcp_input
+ * Only do a connect, the tcp fields will be set in tcp_input
+ * return 0 if there's a result of the connect,
+ * else return -1 means we're still connecting
+ * The return value is almost always -1 since the socket is
+ * nonblocking.  Connect returns after the SYN is sent, and does
+ * not wait for ACK+SYN.
+ */
+int tcp_fconnect(struct socket *so)
+{
+  int ret=0;
+
+  DEBUG_CALL("tcp_fconnect");
+  DEBUG_ARG("so = %lx", (long )so);
+
+  if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) {
+    int opt, s=so->s;
+    struct sockaddr_in addr;
+
+    fd_nonblock(s);
+    opt = 1;
+    setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
+    opt = 1;
+    setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
+
+    addr.sin_family = AF_INET;
+    if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
+      /* It's an alias */
+      switch(ntohl(so->so_faddr.s_addr) & 0xff) {
+      case CTL_DNS:
+	addr.sin_addr = dns_addr;
+	break;
+      case CTL_ALIAS:
+      default:
+	addr.sin_addr = loopback_addr;
+	break;
+      }
+    } else
+      addr.sin_addr = so->so_faddr;
+    addr.sin_port = so->so_fport;
+
+    DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
+		"addr.sin_addr.s_addr=%.16s\n",
+		ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+    /* We don't care what port we get */
+    ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
+
+    /*
+     * If it's not in progress, it failed, so we just return 0,
+     * without clearing SS_NOFDREF
+     */
+    soisfconnecting(so);
+  }
+
+  return(ret);
+}
+
+/*
+ * Accept the socket and connect to the local-host
+ *
+ * We have a problem. The correct thing to do would be
+ * to first connect to the local-host, and only if the
+ * connection is accepted, then do an accept() here.
+ * But, a) we need to know who's trying to connect
+ * to the socket to be able to SYN the local-host, and
+ * b) we are already connected to the foreign host by
+ * the time it gets to accept(), so... We simply accept
+ * here and SYN the local-host.
+ */
+void
+tcp_connect(struct socket *inso)
+{
+	struct socket *so;
+	struct sockaddr_in addr;
+	socklen_t addrlen = sizeof(struct sockaddr_in);
+	struct tcpcb *tp;
+	int s, opt;
+
+	DEBUG_CALL("tcp_connect");
+	DEBUG_ARG("inso = %lx", (long)inso);
+
+	/*
+	 * If it's an SS_ACCEPTONCE socket, no need to socreate()
+	 * another socket, just use the accept() socket.
+	 */
+	if (inso->so_state & SS_FACCEPTONCE) {
+		/* FACCEPTONCE already have a tcpcb */
+		so = inso;
+	} else {
+		if ((so = socreate()) == NULL) {
+			/* If it failed, get rid of the pending connection */
+			closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen));
+			return;
+		}
+		if (tcp_attach(so) < 0) {
+			free(so); /* NOT sofree */
+			return;
+		}
+		so->so_laddr = inso->so_laddr;
+		so->so_lport = inso->so_lport;
+	}
+
+	(void) tcp_mss(sototcpcb(so), 0);
+
+	if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
+		tcp_close(sototcpcb(so)); /* This will sofree() as well */
+		return;
+	}
+	fd_nonblock(s);
+	opt = 1;
+	setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
+	opt = 1;
+	setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
+	opt = 1;
+	setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
+
+	so->so_fport = addr.sin_port;
+	so->so_faddr = addr.sin_addr;
+	/* Translate connections from localhost to the real hostname */
+	if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
+	   so->so_faddr = alias_addr;
+
+	/* Close the accept() socket, set right state */
+	if (inso->so_state & SS_FACCEPTONCE) {
+		closesocket(so->s); /* If we only accept once, close the accept() socket */
+		so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
+					   /* if it's not FACCEPTONCE, it's already NOFDREF */
+	}
+	so->s = s;
+
+	so->so_iptos = tcp_tos(so);
+	tp = sototcpcb(so);
+
+	tcp_template(tp);
+
+	/* Compute window scaling to request.  */
+/*	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
+ *		(TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
+ *		tp->request_r_scale++;
+ */
+
+/*	soisconnecting(so); */ /* NOFDREF used instead */
+	STAT(tcpstat.tcps_connattempt++);
+
+	tp->t_state = TCPS_SYN_SENT;
+	tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+	tp->iss = tcp_iss;
+	tcp_iss += TCP_ISSINCR/2;
+	tcp_sendseqinit(tp);
+	tcp_output(tp);
+}
+
+/*
+ * Attach a TCPCB to a socket.
+ */
+int
+tcp_attach(struct socket *so)
+{
+	if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
+	   return -1;
+
+	insque(so, &tcb);
+
+	return 0;
+}
+
+/*
+ * Set the socket's type of service field
+ */
+static const struct tos_t tcptos[] = {
+	  {0, 20, IPTOS_THROUGHPUT, 0},	/* ftp data */
+	  {21, 21, IPTOS_LOWDELAY,  EMU_FTP},	/* ftp control */
+	  {0, 23, IPTOS_LOWDELAY, 0},	/* telnet */
+	  {0, 80, IPTOS_THROUGHPUT, 0},	/* WWW */
+	  {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT},	/* rlogin */
+	  {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT},	/* shell */
+	  {0, 544, IPTOS_LOWDELAY, EMU_KSH},		/* kshell */
+	  {0, 543, IPTOS_LOWDELAY, 0},	/* klogin */
+	  {0, 6667, IPTOS_THROUGHPUT, EMU_IRC},	/* IRC */
+	  {0, 6668, IPTOS_THROUGHPUT, EMU_IRC},	/* IRC undernet */
+	  {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
+	  {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
+	  {0, 0, 0, 0}
+};
+
+#ifdef CONFIG_QEMU
+static
+#endif
+struct emu_t *tcpemu = NULL;
+
+/*
+ * Return TOS according to the above table
+ */
+u_int8_t
+tcp_tos(struct socket *so)
+{
+	int i = 0;
+	struct emu_t *emup;
+
+	while(tcptos[i].tos) {
+		if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
+		    (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
+			so->so_emu = tcptos[i].emu;
+			return tcptos[i].tos;
+		}
+		i++;
+	}
+
+	/* Nope, lets see if there's a user-added one */
+	for (emup = tcpemu; emup; emup = emup->next) {
+		if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
+		    (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
+			so->so_emu = emup->emu;
+			return emup->tos;
+		}
+	}
+
+	return 0;
+}
+
+#if 0
+int do_echo = -1;
+#endif
+
+/*
+ * Emulate programs that try and connect to us
+ * This includes ftp (the data connection is
+ * initiated by the server) and IRC (DCC CHAT and
+ * DCC SEND) for now
+ *
+ * NOTE: It's possible to crash SLiRP by sending it
+ * unstandard strings to emulate... if this is a problem,
+ * more checks are needed here
+ *
+ * XXX Assumes the whole command came in one packet
+ *
+ * XXX Some ftp clients will have their TOS set to
+ * LOWDELAY and so Nagel will kick in.  Because of this,
+ * we'll get the first letter, followed by the rest, so
+ * we simply scan for ORT instead of PORT...
+ * DCC doesn't have this problem because there's other stuff
+ * in the packet before the DCC command.
+ *
+ * Return 1 if the mbuf m is still valid and should be
+ * sbappend()ed
+ *
+ * NOTE: if you return 0 you MUST m_free() the mbuf!
+ */
+int
+tcp_emu(struct socket *so, struct mbuf *m)
+{
+	u_int n1, n2, n3, n4, n5, n6;
+        char buff[257];
+	u_int32_t laddr;
+	u_int lport;
+	char *bptr;
+
+	DEBUG_CALL("tcp_emu");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("m = %lx", (long)m);
+
+	switch(so->so_emu) {
+		int x, i;
+
+	 case EMU_IDENT:
+		/*
+		 * Identification protocol as per rfc-1413
+		 */
+
+		{
+			struct socket *tmpso;
+			struct sockaddr_in addr;
+			socklen_t addrlen = sizeof(struct sockaddr_in);
+			struct sbuf *so_rcv = &so->so_rcv;
+
+			memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
+			so_rcv->sb_wptr += m->m_len;
+			so_rcv->sb_rptr += m->m_len;
+			m->m_data[m->m_len] = 0; /* NULL terminate */
+			if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
+				if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
+					HTONS(n1);
+					HTONS(n2);
+					/* n2 is the one on our host */
+					for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
+						if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
+						    tmpso->so_lport == n2 &&
+						    tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
+						    tmpso->so_fport == n1) {
+							if (getsockname(tmpso->s,
+								(struct sockaddr *)&addr, &addrlen) == 0)
+							   n2 = ntohs(addr.sin_port);
+							break;
+						}
+					}
+				}
+                                so_rcv->sb_cc = snprintf(so_rcv->sb_data,
+                                                         so_rcv->sb_datalen,
+                                                         "%d,%d\r\n", n1, n2);
+				so_rcv->sb_rptr = so_rcv->sb_data;
+				so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
+			}
+			m_free(m);
+			return 0;
+		}
+
+#if 0
+	 case EMU_RLOGIN:
+		/*
+		 * Rlogin emulation
+		 * First we accumulate all the initial option negotiation,
+		 * then fork_exec() rlogin according to the  options
+		 */
+		{
+			int i, i2, n;
+			char *ptr;
+			char args[100];
+			char term[100];
+			struct sbuf *so_snd = &so->so_snd;
+			struct sbuf *so_rcv = &so->so_rcv;
+
+			/* First check if they have a priveladged port, or too much data has arrived */
+			if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
+			    (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
+				memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
+				so_snd->sb_wptr += 18;
+				so_snd->sb_cc += 18;
+				tcp_sockclosed(sototcpcb(so));
+				m_free(m);
+				return 0;
+			}
+
+			/* Append the current data */
+			memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
+			so_rcv->sb_wptr += m->m_len;
+			so_rcv->sb_rptr += m->m_len;
+			m_free(m);
+
+			/*
+			 * Check if we have all the initial options,
+			 * and build argument list to rlogin while we're here
+			 */
+			n = 0;
+			ptr = so_rcv->sb_data;
+			args[0] = 0;
+			term[0] = 0;
+			while (ptr < so_rcv->sb_wptr) {
+				if (*ptr++ == 0) {
+					n++;
+					if (n == 2) {
+						sprintf(args, "rlogin -l %s %s",
+							ptr, inet_ntoa(so->so_faddr));
+					} else if (n == 3) {
+						i2 = so_rcv->sb_wptr - ptr;
+						for (i = 0; i < i2; i++) {
+							if (ptr[i] == '/') {
+								ptr[i] = 0;
+#ifdef HAVE_SETENV
+								sprintf(term, "%s", ptr);
+#else
+								sprintf(term, "TERM=%s", ptr);
+#endif
+								ptr[i] = '/';
+								break;
+							}
+						}
+					}
+				}
+			}
+
+			if (n != 4)
+			   return 0;
+
+			/* We have it, set our term variable and fork_exec() */
+#ifdef HAVE_SETENV
+			setenv("TERM", term, 1);
+#else
+			putenv(term);
+#endif
+			fork_exec(so, args, 2);
+			term[0] = 0;
+			so->so_emu = 0;
+
+			/* And finally, send the client a 0 character */
+			so_snd->sb_wptr[0] = 0;
+			so_snd->sb_wptr++;
+			so_snd->sb_cc++;
+
+			return 0;
+		}
+
+	 case EMU_RSH:
+		/*
+		 * rsh emulation
+		 * First we accumulate all the initial option negotiation,
+		 * then rsh_exec() rsh according to the  options
+		 */
+		{
+			int  n;
+			char *ptr;
+			char *user;
+			char *args;
+			struct sbuf *so_snd = &so->so_snd;
+			struct sbuf *so_rcv = &so->so_rcv;
+
+			/* First check if they have a priveladged port, or too much data has arrived */
+			if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
+			    (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
+				memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
+				so_snd->sb_wptr += 18;
+				so_snd->sb_cc += 18;
+				tcp_sockclosed(sototcpcb(so));
+				m_free(m);
+				return 0;
+			}
+
+			/* Append the current data */
+			memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
+			so_rcv->sb_wptr += m->m_len;
+			so_rcv->sb_rptr += m->m_len;
+			m_free(m);
+
+			/*
+			 * Check if we have all the initial options,
+			 * and build argument list to rlogin while we're here
+			 */
+			n = 0;
+			ptr = so_rcv->sb_data;
+			user="";
+			args="";
+			if (so->extra==NULL) {
+				struct socket *ns;
+				struct tcpcb* tp;
+				int port=atoi(ptr);
+				if (port <= 0) return 0;
+                if (port > 1023 || port < 512) {
+                  memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
+                  so_snd->sb_wptr += 18;
+                  so_snd->sb_cc += 18;
+                  tcp_sockclosed(sototcpcb(so));
+                  return 0;
+                }
+				if ((ns=socreate()) == NULL)
+                  return 0;
+				if (tcp_attach(ns)<0) {
+                  free(ns);
+                  return 0;
+				}
+
+				ns->so_laddr=so->so_laddr;
+				ns->so_lport=htons(port);
+
+				(void) tcp_mss(sototcpcb(ns), 0);
+
+				ns->so_faddr=so->so_faddr;
+				ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */
+
+				if (ns->so_faddr.s_addr == 0 ||
+					ns->so_faddr.s_addr == loopback_addr.s_addr)
+                  ns->so_faddr = alias_addr;
+
+				ns->so_iptos = tcp_tos(ns);
+				tp = sototcpcb(ns);
+
+				tcp_template(tp);
+
+				/* Compute window scaling to request.  */
+				/*	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
+				 *		(TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
+				 *		tp->request_r_scale++;
+				 */
+
+                /*soisfconnecting(ns);*/
+
+				STAT(tcpstat.tcps_connattempt++);
+
+				tp->t_state = TCPS_SYN_SENT;
+				tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
+				tp->iss = tcp_iss;
+				tcp_iss += TCP_ISSINCR/2;
+				tcp_sendseqinit(tp);
+				tcp_output(tp);
+				so->extra=ns;
+			}
+			while (ptr < so_rcv->sb_wptr) {
+              if (*ptr++ == 0) {
+                n++;
+                if (n == 2) {
+                  user=ptr;
+                } else if (n == 3) {
+                  args=ptr;
+                }
+              }
+			}
+
+			if (n != 4)
+              return 0;
+
+			rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args);
+			so->so_emu = 0;
+			so->extra=NULL;
+
+			/* And finally, send the client a 0 character */
+			so_snd->sb_wptr[0] = 0;
+			so_snd->sb_wptr++;
+			so_snd->sb_cc++;
+
+			return 0;
+		}
+
+	 case EMU_CTL:
+		{
+			int num;
+			struct sbuf *so_snd = &so->so_snd;
+			struct sbuf *so_rcv = &so->so_rcv;
+
+			/*
+			 * If there is binary data here, we save it in so->so_m
+			 */
+			if (!so->so_m) {
+			  int rxlen;
+			  char *rxdata;
+			  rxdata=mtod(m, char *);
+			  for (rxlen=m->m_len; rxlen; rxlen--) {
+			    if (*rxdata++ & 0x80) {
+			      so->so_m = m;
+			      return 0;
+			    }
+			  }
+			} /* if(so->so_m==NULL) */
+
+			/*
+			 * Append the line
+			 */
+			sbappendsb(so_rcv, m);
+
+			/* To avoid going over the edge of the buffer, we reset it */
+			if (so_snd->sb_cc == 0)
+			   so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data;
+
+			/*
+			 * A bit of a hack:
+			 * If the first packet we get here is 1 byte long, then it
+			 * was done in telnet character mode, therefore we must echo
+			 * the characters as they come.  Otherwise, we echo nothing,
+			 * because in linemode, the line is already echoed
+			 * XXX two or more control connections won't work
+			 */
+			if (do_echo == -1) {
+				if (m->m_len == 1) do_echo = 1;
+				else do_echo = 0;
+			}
+			if (do_echo) {
+			  sbappendsb(so_snd, m);
+			  m_free(m);
+			  tcp_output(sototcpcb(so)); /* XXX */
+			} else
+			  m_free(m);
+
+			num = 0;
+			while (num < so->so_rcv.sb_cc) {
+				if (*(so->so_rcv.sb_rptr + num) == '\n' ||
+				    *(so->so_rcv.sb_rptr + num) == '\r') {
+					int n;
+
+					*(so_rcv->sb_rptr + num) = 0;
+					if (ctl_password && !ctl_password_ok) {
+						/* Need a password */
+						if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) {
+							if (strcmp(buff, ctl_password) == 0) {
+								ctl_password_ok = 1;
+								n = sprintf(so_snd->sb_wptr,
+									    "Password OK.\r\n");
+								goto do_prompt;
+							}
+						}
+						n = sprintf(so_snd->sb_wptr,
+					 "Error: Password required, log on with \"pass PASSWORD\"\r\n");
+						goto do_prompt;
+					}
+					cfg_quitting = 0;
+					n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF);
+					if (!cfg_quitting) {
+						/* Register the printed data */
+do_prompt:
+						so_snd->sb_cc += n;
+						so_snd->sb_wptr += n;
+						/* Add prompt */
+						n = sprintf(so_snd->sb_wptr, "Slirp> ");
+						so_snd->sb_cc += n;
+						so_snd->sb_wptr += n;
+					}
+					/* Drop so_rcv data */
+					so_rcv->sb_cc = 0;
+					so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data;
+					tcp_output(sototcpcb(so)); /* Send the reply */
+				}
+				num++;
+			}
+			return 0;
+		}
+#endif
+        case EMU_FTP: /* ftp */
+                *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */
+		if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
+			/*
+			 * Need to emulate the PORT command
+			 */
+			x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
+				   &n1, &n2, &n3, &n4, &n5, &n6, buff);
+			if (x < 6)
+			   return 1;
+
+			laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
+			lport = htons((n5 << 8) | (n6));
+
+			if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
+			   return 1;
+
+			n6 = ntohs(so->so_fport);
+
+			n5 = (n6 >> 8) & 0xff;
+			n6 &= 0xff;
+
+			laddr = ntohl(so->so_faddr.s_addr);
+
+			n1 = ((laddr >> 24) & 0xff);
+			n2 = ((laddr >> 16) & 0xff);
+			n3 = ((laddr >> 8)  & 0xff);
+			n4 =  (laddr & 0xff);
+
+			m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
+                                             "ORT %d,%d,%d,%d,%d,%d\r\n%s",
+                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
+			return 1;
+		} else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
+			/*
+			 * Need to emulate the PASV response
+			 */
+			x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
+				   &n1, &n2, &n3, &n4, &n5, &n6, buff);
+			if (x < 6)
+			   return 1;
+
+			laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
+			lport = htons((n5 << 8) | (n6));
+
+			if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
+			   return 1;
+
+			n6 = ntohs(so->so_fport);
+
+			n5 = (n6 >> 8) & 0xff;
+			n6 &= 0xff;
+
+			laddr = ntohl(so->so_faddr.s_addr);
+
+			n1 = ((laddr >> 24) & 0xff);
+			n2 = ((laddr >> 16) & 0xff);
+			n3 = ((laddr >> 8)  & 0xff);
+			n4 =  (laddr & 0xff);
+
+			m->m_len = bptr - m->m_data; /* Adjust length */
+			m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
+                                             "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
+                                             n1, n2, n3, n4, n5, n6, x==7?buff:"");
+
+			return 1;
+		}
+
+		return 1;
+
+	 case EMU_KSH:
+		/*
+		 * The kshell (Kerberos rsh) and shell services both pass
+		 * a local port port number to carry signals to the server
+		 * and stderr to the client.  It is passed at the beginning
+		 * of the connection as a NUL-terminated decimal ASCII string.
+		 */
+		so->so_emu = 0;
+		for (lport = 0, i = 0; i < m->m_len-1; ++i) {
+			if (m->m_data[i] < '0' || m->m_data[i] > '9')
+				return 1;       /* invalid number */
+			lport *= 10;
+			lport += m->m_data[i] - '0';
+		}
+		if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
+		    (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
+                    m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
+                                        ntohs(so->so_fport)) + 1;
+		return 1;
+
+	 case EMU_IRC:
+		/*
+		 * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
+		 */
+		*(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
+		if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
+			 return 1;
+
+		/* The %256s is for the broken mIRC */
+		if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
+			if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
+				return 1;
+
+			m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC CHAT chat %lu %u%c\n",
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), 1);
+		} else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
+			if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
+				return 1;
+
+			m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC SEND %s %lu %u %u%c\n", buff,
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), n1, 1);
+		} else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
+			if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
+				return 1;
+
+			m->m_len = bptr - m->m_data; /* Adjust length */
+                        m->m_len += snprintf(bptr, m->m_hdr.mh_size,
+                                             "DCC MOVE %s %lu %u %u%c\n", buff,
+                                             (unsigned long)ntohl(so->so_faddr.s_addr),
+                                             ntohs(so->so_fport), n1, 1);
+		}
+		return 1;
+
+	 case EMU_REALAUDIO:
+                /*
+		 * RealAudio emulation - JP. We must try to parse the incoming
+		 * data and try to find the two characters that contain the
+		 * port number. Then we redirect an udp port and replace the
+		 * number with the real port we got.
+		 *
+		 * The 1.0 beta versions of the player are not supported
+		 * any more.
+		 *
+		 * A typical packet for player version 1.0 (release version):
+		 *
+		 * 0000:50 4E 41 00 05
+		 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P
+		 * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
+		 * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
+		 * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
+		 *
+		 * Now the port number 0x1BD7 is found at offset 0x04 of the
+		 * Now the port number 0x1BD7 is found at offset 0x04 of the
+		 * second packet. This time we received five bytes first and
+		 * then the rest. You never know how many bytes you get.
+		 *
+		 * A typical packet for player version 2.0 (beta):
+		 *
+		 * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á.
+		 * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0
+		 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
+		 * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
+		 * 0040:65 2E 72 61 79 53 00 00 06 36 42                e.rayS...6B
+		 *
+		 * Port number 0x1BC1 is found at offset 0x0d.
+		 *
+		 * This is just a horrible switch statement. Variable ra tells
+		 * us where we're going.
+		 */
+
+		bptr = m->m_data;
+		while (bptr < m->m_data + m->m_len) {
+			u_short p;
+			static int ra = 0;
+			char ra_tbl[4];
+
+			ra_tbl[0] = 0x50;
+			ra_tbl[1] = 0x4e;
+			ra_tbl[2] = 0x41;
+			ra_tbl[3] = 0;
+
+			switch (ra) {
+			 case 0:
+			 case 2:
+			 case 3:
+				if (*bptr++ != ra_tbl[ra]) {
+					ra = 0;
+					continue;
+				}
+				break;
+
+			 case 1:
+				/*
+				 * We may get 0x50 several times, ignore them
+				 */
+				if (*bptr == 0x50) {
+					ra = 1;
+					bptr++;
+					continue;
+				} else if (*bptr++ != ra_tbl[ra]) {
+					ra = 0;
+					continue;
+				}
+				break;
+
+			 case 4:
+				/*
+				 * skip version number
+				 */
+				bptr++;
+				break;
+
+			 case 5:
+				/*
+				 * The difference between versions 1.0 and
+				 * 2.0 is here. For future versions of
+				 * the player this may need to be modified.
+				 */
+				if (*(bptr + 1) == 0x02)
+				   bptr += 8;
+				else
+				   bptr += 4;
+				break;
+
+			 case 6:
+				/* This is the field containing the port
+				 * number that RA-player is listening to.
+				 */
+				lport = (((u_char*)bptr)[0] << 8)
+				+ ((u_char *)bptr)[1];
+				if (lport < 6970)
+				   lport += 256;   /* don't know why */
+				if (lport < 6970 || lport > 7170)
+				   return 1;       /* failed */
+
+				/* try to get udp port between 6970 - 7170 */
+				for (p = 6970; p < 7071; p++) {
+					if (udp_listen( htons(p),
+						       so->so_laddr.s_addr,
+						       htons(lport),
+						       SS_FACCEPTONCE)) {
+						break;
+					}
+				}
+				if (p == 7071)
+				   p = 0;
+				*(u_char *)bptr++ = (p >> 8) & 0xff;
+				*(u_char *)bptr++ = p & 0xff;
+				ra = 0;
+				return 1;   /* port redirected, we're done */
+				break;
+
+			 default:
+				ra = 0;
+			}
+			ra++;
+		}
+		return 1;
+
+	 default:
+		/* Ooops, not emulated, won't call tcp_emu again */
+		so->so_emu = 0;
+		return 1;
+	}
+}
+
+/*
+ * Do misc. config of SLiRP while its running.
+ * Return 0 if this connections is to be closed, 1 otherwise,
+ * return 2 if this is a command-line connection
+ */
+int
+tcp_ctl(struct socket *so)
+{
+	struct sbuf *sb = &so->so_snd;
+	int command;
+ 	struct ex_list *ex_ptr;
+	int do_pty;
+        //	struct socket *tmpso;
+
+	DEBUG_CALL("tcp_ctl");
+	DEBUG_ARG("so = %lx", (long )so);
+
+#if 0
+	/*
+	 * Check if they're authorised
+	 */
+	if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) {
+		sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n");
+		sb->sb_wptr += sb->sb_cc;
+		return 0;
+	}
+#endif
+	command = (ntohl(so->so_faddr.s_addr) & 0xff);
+
+	switch(command) {
+	default: /* Check for exec's */
+
+		/*
+		 * Check if it's pty_exec
+		 */
+		for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+			if (ex_ptr->ex_fport == so->so_fport &&
+			    command == ex_ptr->ex_addr) {
+				if (ex_ptr->ex_pty == 3) {
+					so->s = -1;
+					so->extra = (void *)ex_ptr->ex_exec;
+					return 1;
+				}
+				do_pty = ex_ptr->ex_pty;
+				goto do_exec;
+			}
+		}
+
+		/*
+		 * Nothing bound..
+		 */
+		/* tcp_fconnect(so); */
+
+		/* FALLTHROUGH */
+	case CTL_ALIAS:
+          sb->sb_cc = snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
+                               "Error: No application configured.\r\n");
+	  sb->sb_wptr += sb->sb_cc;
+	  return(0);
+
+	do_exec:
+		DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
+		return(fork_exec(so, ex_ptr->ex_exec, do_pty));
+
+#if 0
+	case CTL_CMD:
+	   for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
+	     if (tmpso->so_emu == EMU_CTL &&
+		 !(tmpso->so_tcpcb?
+		   (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK))
+		   :0)) {
+	       /* Ooops, control connection already active */
+	       sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n");
+	       sb->sb_wptr += sb->sb_cc;
+	       return 0;
+	     }
+	   }
+	   so->so_emu = EMU_CTL;
+	   ctl_password_ok = 0;
+	   sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> ");
+	   sb->sb_wptr += sb->sb_cc;
+	   do_echo=-1;
+	   return(2);
+#endif
+	}
+}
diff --git a/slirp2/tcp_timer.c b/slirp/tcp_timer.c
similarity index 86%
copy from slirp2/tcp_timer.c
copy to slirp/tcp_timer.c
index ad03098..9215eb2 100644
--- a/slirp2/tcp_timer.c
+++ b/slirp/tcp_timer.c
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -36,25 +32,25 @@
 
 #include <slirp.h>
 
-int	tcp_keepidle = TCPTV_KEEP_IDLE;
-int	tcp_keepintvl = TCPTV_KEEPINTVL;
-int	tcp_maxidle;
-int	so_options = DO_KEEPALIVE;
-
+#ifdef LOG_ENABLED
 struct   tcpstat tcpstat;        /* tcp statistics */
+#endif
+
 u_int32_t        tcp_now;                /* for RFC 1323 timestamps */
 
+static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
+
 /*
  * Fast timeout routine for processing delayed acks
  */
 void
-tcp_fasttimo()
+tcp_fasttimo(void)
 {
 	register struct socket *so;
 	register struct tcpcb *tp;
 
 	DEBUG_CALL("tcp_fasttimo");
-	
+
 	so = tcb.so_next;
 	if (so)
 	for (; so != &tcb; so = so->so_next)
@@ -62,7 +58,7 @@
 		    (tp->t_flags & TF_DELACK)) {
 			tp->t_flags &= ~TF_DELACK;
 			tp->t_flags |= TF_ACKNOW;
-			tcpstat.tcps_delack++;
+			STAT(tcpstat.tcps_delack++);
 			(void) tcp_output(tp);
 		}
 }
@@ -73,15 +69,14 @@
  * causes finite state machine actions if timers expire.
  */
 void
-tcp_slowtimo()
+tcp_slowtimo(void)
 {
 	register struct socket *ip, *ipnxt;
 	register struct tcpcb *tp;
 	register int i;
 
 	DEBUG_CALL("tcp_slowtimo");
-	
-	tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
+
 	/*
 	 * Search through tcb's and update active timers.
 	 */
@@ -118,8 +113,7 @@
  * Cancel all timers for TCP tp.
  */
 void
-tcp_canceltimers(tp)
-	struct tcpcb *tp;
+tcp_canceltimers(struct tcpcb *tp)
 {
 	register int i;
 
@@ -127,21 +121,19 @@
 		tp->t_timer[i] = 0;
 }
 
-int	tcp_backoff[TCP_MAXRXTSHIFT + 1] =
+const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
    { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
 
 /*
  * TCP timer processing.
  */
-struct tcpcb *
-tcp_timers(tp, timer)
-	register struct tcpcb *tp;
-	int timer;
+static struct tcpcb *
+tcp_timers(register struct tcpcb *tp, int timer)
 {
 	register int rexmt;
-	
+
 	DEBUG_CALL("tcp_timers");
-	
+
 	switch (timer) {
 
 	/*
@@ -152,8 +144,8 @@
 	 */
 	case TCPT_2MSL:
 		if (tp->t_state != TCPS_TIME_WAIT &&
-		    tp->t_idle <= tcp_maxidle)
-			tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
+		    tp->t_idle <= TCP_MAXIDLE)
+			tp->t_timer[TCPT_2MSL] = TCPTV_KEEPINTVL;
 		else
 			tp = tcp_close(tp);
 		break;
@@ -164,12 +156,12 @@
 	 * to a longer retransmit interval and retransmit one segment.
 	 */
 	case TCPT_REXMT:
-		
+
 		/*
 		 * XXXXX If a packet has timed out, then remove all the queued
 		 * packets for that session.
 		 */
-		
+
 		if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
 			/*
 			 * This is a hack to suit our terminal server here at the uni of canberra
@@ -178,33 +170,33 @@
 			 * keep retransmitting it, it'll keep eating the zeroes, so we keep
 			 * retransmitting, and eventually the connection dies...
 			 * (this only happens on incoming data)
-			 * 
+			 *
 			 * So, if we were gonna drop the connection from too many retransmits,
 			 * don't... instead halve the t_maxseg, which might break up the NULLs and
 			 * let them through
-			 * 
+			 *
 			 * *sigh*
 			 */
-			
+
 			tp->t_maxseg >>= 1;
 			if (tp->t_maxseg < 32) {
 				/*
 				 * We tried our best, now the connection must die!
 				 */
 				tp->t_rxtshift = TCP_MAXRXTSHIFT;
-				tcpstat.tcps_timeoutdrop++;
+				STAT(tcpstat.tcps_timeoutdrop++);
 				tp = tcp_drop(tp, tp->t_softerror);
 				/* tp->t_softerror : ETIMEDOUT); */ /* XXX */
 				return (tp); /* XXX */
 			}
-			
+
 			/*
 			 * Set rxtshift to 6, which is still at the maximum
 			 * backoff time
 			 */
 			tp->t_rxtshift = 6;
 		}
-		tcpstat.tcps_rexmttimeo++;
+		STAT(tcpstat.tcps_rexmttimeo++);
 		rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
 		TCPT_RANGESET(tp->t_rxtcur, rexmt,
 		    (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
@@ -240,7 +232,7 @@
 		 * size increase exponentially with time.  If the
 		 * window is larger than the path can handle, this
 		 * exponential growth results in dropped packet(s)
-		 * almost immediately.  To get more time between 
+		 * almost immediately.  To get more time between
 		 * drops but still "push" the network to take advantage
 		 * of improving conditions, we switch from exponential
 		 * to linear window opening at some threshold size.
@@ -267,7 +259,7 @@
 	 * Force a byte to be output, if possible.
 	 */
 	case TCPT_PERSIST:
-		tcpstat.tcps_persisttimeo++;
+		STAT(tcpstat.tcps_persisttimeo++);
 		tcp_setpersist(tp);
 		tp->t_force = 1;
 		(void) tcp_output(tp);
@@ -279,13 +271,13 @@
 	 * or drop connection if idle for too long.
 	 */
 	case TCPT_KEEP:
-		tcpstat.tcps_keeptimeo++;
+		STAT(tcpstat.tcps_keeptimeo++);
 		if (tp->t_state < TCPS_ESTABLISHED)
 			goto dropit;
 
 /*		if (tp->t_socket->so_options & SO_KEEPALIVE && */
-		if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) {
-		    	if (tp->t_idle >= tcp_keepidle + tcp_maxidle)
+		if ((SO_OPTIONS) && tp->t_state <= TCPS_CLOSE_WAIT) {
+		    	if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
 				goto dropit;
 			/*
 			 * Send a packet designed to force a response
@@ -299,25 +291,25 @@
 			 * by the protocol spec, this requires the
 			 * correspondent TCP to respond.
 			 */
-			tcpstat.tcps_keepprobe++;
+			STAT(tcpstat.tcps_keepprobe++);
 #ifdef TCP_COMPAT_42
 			/*
 			 * The keepalive packet must have nonzero length
 			 * to get a 4.2 host to respond.
 			 */
-			tcp_respond(tp, &tp->t_template, (MBuf )NULL,
+			tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
 			    tp->rcv_nxt - 1, tp->snd_una - 1, 0);
 #else
-			tcp_respond(tp, &tp->t_template, (MBuf )NULL,
+			tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
 			    tp->rcv_nxt, tp->snd_una - 1, 0);
 #endif
-			tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
+			tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
 		} else
-			tp->t_timer[TCPT_KEEP] = tcp_keepidle;
+			tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
 		break;
 
 	dropit:
-		tcpstat.tcps_keepdrops++;
+		STAT(tcpstat.tcps_keepdrops++);
 		tp = tcp_drop(tp, 0); /* ETIMEDOUT); */
 		break;
 	}
diff --git a/slirp2/tcp_timer.h b/slirp/tcp_timer.h
similarity index 89%
copy from slirp2/tcp_timer.h
copy to slirp/tcp_timer.h
index 59933bc..791ee49 100644
--- a/slirp2/tcp_timer.h
+++ b/slirp/tcp_timer.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -126,17 +122,12 @@
 		(tv) = (tvmax); \
 }
 
-extern int tcp_keepidle;		/* time before keepalive probes begin */
-extern int tcp_keepintvl;		/* time between keepalive probes */
-extern int tcp_maxidle;			/* time to drop after starting probes */
-extern int tcp_ttl;			/* time to live for TCP segs */
-extern int tcp_backoff[];
+extern const int tcp_backoff[];
 
 struct tcpcb;
 
 void tcp_fasttimo _P((void));
 void tcp_slowtimo _P((void));
 void tcp_canceltimers _P((struct tcpcb *));
-struct tcpcb * tcp_timers _P((register struct tcpcb *, int));
 
 #endif
diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h
new file mode 100644
index 0000000..d4af1c8
--- /dev/null
+++ b/slirp/tcp_var.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1982, 1986, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)tcp_var.h	8.3 (Berkeley) 4/10/94
+ * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp
+ */
+
+#ifndef _TCP_VAR_H_
+#define _TCP_VAR_H_
+
+#include "tcpip.h"
+#include "tcp_timer.h"
+
+/*
+ * Tcp control block, one per tcp; fields:
+ */
+struct tcpcb {
+	struct tcpiphdr *seg_next;	/* sequencing queue */
+	struct tcpiphdr *seg_prev;
+	short	t_state;		/* state of this connection */
+	short	t_timer[TCPT_NTIMERS];	/* tcp timers */
+	short	t_rxtshift;		/* log(2) of rexmt exp. backoff */
+	short	t_rxtcur;		/* current retransmit value */
+	short	t_dupacks;		/* consecutive dup acks recd */
+	u_short	t_maxseg;		/* maximum segment size */
+	char	t_force;		/* 1 if forcing out a byte */
+	u_short	t_flags;
+#define	TF_ACKNOW	0x0001		/* ack peer immediately */
+#define	TF_DELACK	0x0002		/* ack, but try to delay it */
+#define	TF_NODELAY	0x0004		/* don't delay packets to coalesce */
+#define	TF_NOOPT	0x0008		/* don't use tcp options */
+#define	TF_SENTFIN	0x0010		/* have sent FIN */
+#define	TF_REQ_SCALE	0x0020		/* have/will request window scaling */
+#define	TF_RCVD_SCALE	0x0040		/* other side has requested scaling */
+#define	TF_REQ_TSTMP	0x0080		/* have/will request timestamps */
+#define	TF_RCVD_TSTMP	0x0100		/* a timestamp was received in SYN */
+#define	TF_SACK_PERMIT	0x0200		/* other side said I could SACK */
+
+	/* Make it static  for now */
+/*	struct	tcpiphdr *t_template;	/ * skeletal packet for transmit */
+	struct	tcpiphdr t_template;
+
+	struct	socket *t_socket;		/* back pointer to socket */
+/*
+ * The following fields are used as in the protocol specification.
+ * See RFC783, Dec. 1981, page 21.
+ */
+/* send sequence variables */
+	tcp_seq	snd_una;		/* send unacknowledged */
+	tcp_seq	snd_nxt;		/* send next */
+	tcp_seq	snd_up;			/* send urgent pointer */
+	tcp_seq	snd_wl1;		/* window update seg seq number */
+	tcp_seq	snd_wl2;		/* window update seg ack number */
+	tcp_seq	iss;			/* initial send sequence number */
+	u_int32_t snd_wnd;		/* send window */
+/* receive sequence variables */
+	u_int32_t rcv_wnd;		/* receive window */
+	tcp_seq	rcv_nxt;		/* receive next */
+	tcp_seq	rcv_up;			/* receive urgent pointer */
+	tcp_seq	irs;			/* initial receive sequence number */
+/*
+ * Additional variables for this implementation.
+ */
+/* receive variables */
+	tcp_seq	rcv_adv;		/* advertised window */
+/* retransmit variables */
+	tcp_seq	snd_max;		/* highest sequence number sent;
+					 * used to recognize retransmits
+					 */
+/* congestion control (for slow start, source quench, retransmit after loss) */
+	u_int32_t snd_cwnd;		/* congestion-controlled window */
+	u_int32_t snd_ssthresh;		/* snd_cwnd size threshold for
+					 * for slow start exponential to
+					 * linear switch
+					 */
+/*
+ * transmit timing stuff.  See below for scale of srtt and rttvar.
+ * "Variance" is actually smoothed difference.
+ */
+	short	t_idle;			/* inactivity time */
+	short	t_rtt;			/* round trip time */
+	tcp_seq	t_rtseq;		/* sequence number being timed */
+	short	t_srtt;			/* smoothed round-trip time */
+	short	t_rttvar;		/* variance in round-trip time */
+	u_short	t_rttmin;		/* minimum rtt allowed */
+	u_int32_t max_sndwnd;		/* largest window peer has offered */
+
+/* out-of-band data */
+	char	t_oobflags;		/* have some */
+	char	t_iobc;			/* input character */
+#define	TCPOOB_HAVEDATA	0x01
+#define	TCPOOB_HADDATA	0x02
+	short	t_softerror;		/* possible error not yet reported */
+
+/* RFC 1323 variables */
+	u_char	snd_scale;		/* window scaling for send window */
+	u_char	rcv_scale;		/* window scaling for recv window */
+	u_char	request_r_scale;	/* pending window scaling */
+	u_char	requested_s_scale;
+	u_int32_t	ts_recent;		/* timestamp echo data */
+	u_int32_t	ts_recent_age;		/* when last updated */
+	tcp_seq	last_ack_sent;
+
+};
+
+#define	sototcpcb(so)	((so)->so_tcpcb)
+
+/*
+ * The smoothed round-trip time and estimated variance
+ * are stored as fixed point numbers scaled by the values below.
+ * For convenience, these scales are also used in smoothing the average
+ * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed).
+ * With these scales, srtt has 3 bits to the right of the binary point,
+ * and thus an "ALPHA" of 0.875.  rttvar has 2 bits to the right of the
+ * binary point, and is smoothed with an ALPHA of 0.75.
+ */
+#define	TCP_RTT_SCALE		8	/* multiplier for srtt; 3 bits frac. */
+#define	TCP_RTT_SHIFT		3	/* shift for srtt; 3 bits frac. */
+#define	TCP_RTTVAR_SCALE	4	/* multiplier for rttvar; 2 bits */
+#define	TCP_RTTVAR_SHIFT	2	/* multiplier for rttvar; 2 bits */
+
+/*
+ * The initial retransmission should happen at rtt + 4 * rttvar.
+ * Because of the way we do the smoothing, srtt and rttvar
+ * will each average +1/2 tick of bias.  When we compute
+ * the retransmit timer, we want 1/2 tick of rounding and
+ * 1 extra tick because of +-1/2 tick uncertainty in the
+ * firing of the timer.  The bias will give us exactly the
+ * 1.5 tick we need.  But, because the bias is
+ * statistical, we have to test that we don't drop below
+ * the minimum feasible timer (which is 2 ticks).
+ * This macro assumes that the value of TCP_RTTVAR_SCALE
+ * is the same as the multiplier for rttvar.
+ */
+#define	TCP_REXMTVAL(tp) \
+	(((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar)
+
+#ifdef LOG_ENABLED
+/*
+ * TCP statistics.
+ * Many of these should be kept per connection,
+ * but that's inconvenient at the moment.
+ */
+struct tcpstat {
+	u_long	tcps_connattempt;	/* connections initiated */
+	u_long	tcps_accepts;		/* connections accepted */
+	u_long	tcps_connects;		/* connections established */
+	u_long	tcps_drops;		/* connections dropped */
+	u_long	tcps_conndrops;		/* embryonic connections dropped */
+	u_long	tcps_closed;		/* conn. closed (includes drops) */
+	u_long	tcps_segstimed;		/* segs where we tried to get rtt */
+	u_long	tcps_rttupdated;	/* times we succeeded */
+	u_long	tcps_delack;		/* delayed acks sent */
+	u_long	tcps_timeoutdrop;	/* conn. dropped in rxmt timeout */
+	u_long	tcps_rexmttimeo;	/* retransmit timeouts */
+	u_long	tcps_persisttimeo;	/* persist timeouts */
+	u_long	tcps_keeptimeo;		/* keepalive timeouts */
+	u_long	tcps_keepprobe;		/* keepalive probes sent */
+	u_long	tcps_keepdrops;		/* connections dropped in keepalive */
+
+	u_long	tcps_sndtotal;		/* total packets sent */
+	u_long	tcps_sndpack;		/* data packets sent */
+	u_long	tcps_sndbyte;		/* data bytes sent */
+	u_long	tcps_sndrexmitpack;	/* data packets retransmitted */
+	u_long	tcps_sndrexmitbyte;	/* data bytes retransmitted */
+	u_long	tcps_sndacks;		/* ack-only packets sent */
+	u_long	tcps_sndprobe;		/* window probes sent */
+	u_long	tcps_sndurg;		/* packets sent with URG only */
+	u_long	tcps_sndwinup;		/* window update-only packets sent */
+	u_long	tcps_sndctrl;		/* control (SYN|FIN|RST) packets sent */
+
+	u_long	tcps_rcvtotal;		/* total packets received */
+	u_long	tcps_rcvpack;		/* packets received in sequence */
+	u_long	tcps_rcvbyte;		/* bytes received in sequence */
+	u_long	tcps_rcvbadsum;		/* packets received with ccksum errs */
+	u_long	tcps_rcvbadoff;		/* packets received with bad offset */
+/*	u_long	tcps_rcvshort;	*/	/* packets received too short */
+	u_long	tcps_rcvduppack;	/* duplicate-only packets received */
+	u_long	tcps_rcvdupbyte;	/* duplicate-only bytes received */
+	u_long	tcps_rcvpartduppack;	/* packets with some duplicate data */
+	u_long	tcps_rcvpartdupbyte;	/* dup. bytes in part-dup. packets */
+	u_long	tcps_rcvoopack;		/* out-of-order packets received */
+	u_long	tcps_rcvoobyte;		/* out-of-order bytes received */
+	u_long	tcps_rcvpackafterwin;	/* packets with data after window */
+	u_long	tcps_rcvbyteafterwin;	/* bytes rcvd after window */
+	u_long	tcps_rcvafterclose;	/* packets rcvd after "close" */
+	u_long	tcps_rcvwinprobe;	/* rcvd window probe packets */
+	u_long	tcps_rcvdupack;		/* rcvd duplicate acks */
+	u_long	tcps_rcvacktoomuch;	/* rcvd acks for unsent data */
+	u_long	tcps_rcvackpack;	/* rcvd ack packets */
+	u_long	tcps_rcvackbyte;	/* bytes acked by rcvd acks */
+	u_long	tcps_rcvwinupd;		/* rcvd window update packets */
+/*	u_long	tcps_pawsdrop;	*/	/* segments dropped due to PAWS */
+	u_long	tcps_predack;		/* times hdr predict ok for acks */
+	u_long	tcps_preddat;		/* times hdr predict ok for data pkts */
+	u_long	tcps_socachemiss;	/* tcp_last_so misses */
+	u_long	tcps_didnuttin;		/* Times tcp_output didn't do anything XXX */
+};
+
+extern struct	tcpstat tcpstat;	/* tcp statistics */
+#endif
+
+extern u_int32_t	tcp_now;		/* for RFC 1323 timestamps */
+
+#endif
diff --git a/slirp/tcpip.h b/slirp/tcpip.h
new file mode 100644
index 0000000..7974ce3
--- /dev/null
+++ b/slirp/tcpip.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)tcpip.h	8.1 (Berkeley) 6/10/93
+ * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp
+ */
+
+#ifndef _TCPIP_H_
+#define _TCPIP_H_
+
+/*
+ * Tcp+ip header, after ip options removed.
+ */
+struct tcpiphdr {
+	struct 	ipovly ti_i;		/* overlaid ip structure */
+	struct	tcphdr ti_t;		/* tcp header */
+};
+#define	ti_mbuf		ti_i.ih_mbuf.mptr
+#define	ti_x1		ti_i.ih_x1
+#define	ti_pr		ti_i.ih_pr
+#define	ti_len		ti_i.ih_len
+#define	ti_src		ti_i.ih_src
+#define	ti_dst		ti_i.ih_dst
+#define	ti_sport	ti_t.th_sport
+#define	ti_dport	ti_t.th_dport
+#define	ti_seq		ti_t.th_seq
+#define	ti_ack		ti_t.th_ack
+#define	ti_x2		ti_t.th_x2
+#define	ti_off		ti_t.th_off
+#define	ti_flags	ti_t.th_flags
+#define	ti_win		ti_t.th_win
+#define	ti_sum		ti_t.th_sum
+#define	ti_urp		ti_t.th_urp
+
+#define tcpiphdr2qlink(T) ((struct qlink*)(((char*)(T)) - sizeof(struct qlink)))
+#define qlink2tcpiphdr(Q) ((struct tcpiphdr*)(((char*)(Q)) + sizeof(struct qlink)))
+#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next)
+#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev)
+#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next)
+#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T))
+#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T))
+
+/*
+ * Just a clean way to get to the first byte
+ * of the packet
+ */
+struct tcpiphdr_2 {
+	struct tcpiphdr dummy;
+	char first_char;
+};
+
+#endif
diff --git a/slirp2/tftp.c b/slirp/tftp.c
similarity index 69%
copy from slirp2/tftp.c
copy to slirp/tftp.c
index 37933d9..4ad5504 100644
--- a/slirp2/tftp.c
+++ b/slirp/tftp.c
@@ -23,20 +23,19 @@
  */
 
 #include <slirp.h>
-#include <fcntl.h>
-#include <sys/stat.h>
+#include "qemu-common.h" // for pstrcpy
 
 struct tftp_session {
     int in_use;
     unsigned char filename[TFTP_FILENAME_MAX];
 
-    uint32_t client_ip;
-    uint16_t client_port;
+    struct in_addr client_ip;
+    u_int16_t client_port;
 
     int timestamp;
 };
 
-struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
+static struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
 
 const char *tftp_prefix;
 
@@ -71,8 +70,8 @@
 
  found:
   memset(spt, 0, sizeof(*spt));
-  spt->client_ip   = ip_geth(tp->ip.ip_src);
-  spt->client_port = port_geth(tp->udp.uh_sport);
+  memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
+  spt->client_port = tp->udp.uh_sport;
 
   tftp_session_update(spt);
 
@@ -88,8 +87,8 @@
     spt = &tftp_sessions[k];
 
     if (spt->in_use) {
-      if (spt->client_ip == ip_geth(tp->ip.ip_src)) {
-	if (spt->client_port == port_geth(tp->udp.uh_sport)) {
+      if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
+	if (spt->client_port == tp->udp.uh_sport) {
 	  return k;
 	}
       }
@@ -108,9 +107,9 @@
   int n;
 
   n = snprintf(buffer, sizeof(buffer), "%s/%s",
-               tftp_prefix, spt->filename);
+	       tftp_prefix, spt->filename);
   if (n >= sizeof(buffer))
-      return -1;
+    return -1;
 
   fd = open(buffer, O_RDONLY | O_BINARY);
 
@@ -133,37 +132,37 @@
                           const char *key, uint32_t value,
                           struct tftp_t *recv_tp)
 {
-    SockAddress  saddr, daddr;
-    MBuf m;
+    struct sockaddr_in saddr, daddr;
+    struct mbuf *m;
     struct tftp_t *tp;
     int n = 0;
 
-    m = mbuf_alloc();
+    m = m_get();
 
     if (!m)
-        return -1;
+	return -1;
 
     memset(m->m_data, 0, m->m_size);
 
-    m->m_data += if_maxlinkhdr;
+    m->m_data += IF_MAXLINKHDR;
     tp = (void *)m->m_data;
     m->m_data += sizeof(struct udpiphdr);
 
     tp->tp_op = htons(TFTP_OACK);
-    n += sprintf((char*)tp->x.tp_buf + n, "%s", key) + 1;
-    n += sprintf((char*)tp->x.tp_buf + n, "%u", value) + 1;
+    n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
+                  key) + 1;
+    n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
+                  value) + 1;
 
-    sock_address_init_inet( &saddr,
-                            ip_geth(recv_tp->ip.ip_dst),
-                            port_geth(recv_tp->udp.uh_dport) );
+    saddr.sin_addr = recv_tp->ip.ip_dst;
+    saddr.sin_port = recv_tp->udp.uh_dport;
 
-    sock_address_init_inet( &daddr,
-                            spt->client_ip,
-                            spt->client_port );
+    daddr.sin_addr = spt->client_ip;
+    daddr.sin_port = spt->client_port;
 
     m->m_len = sizeof(struct tftp_t) - 514 + n -
-            sizeof(struct ip) - sizeof(struct udphdr);
-    udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+        sizeof(struct ip) - sizeof(struct udphdr);
+    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 
     return 0;
 }
@@ -174,12 +173,12 @@
 			   u_int16_t errorcode, const char *msg,
 			   struct tftp_t *recv_tp)
 {
-  SockAddress saddr, daddr;
-  MBuf m;
+  struct sockaddr_in saddr, daddr;
+  struct mbuf *m;
   struct tftp_t *tp;
   int nobytes;
 
-  m = mbuf_alloc();
+  m = m_get();
 
   if (!m) {
     return -1;
@@ -187,28 +186,26 @@
 
   memset(m->m_data, 0, m->m_size);
 
-  m->m_data += if_maxlinkhdr;
+  m->m_data += IF_MAXLINKHDR;
   tp = (void *)m->m_data;
   m->m_data += sizeof(struct udpiphdr);
 
   tp->tp_op = htons(TFTP_ERROR);
   tp->x.tp_error.tp_error_code = htons(errorcode);
-  strcpy((char*)tp->x.tp_error.tp_msg, msg);
+  pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
 
-  sock_address_init_inet( &saddr,
-                          ip_geth(recv_tp->ip.ip_dst),
-                          port_geth(recv_tp->udp.uh_dport) );
+  saddr.sin_addr = recv_tp->ip.ip_dst;
+  saddr.sin_port = recv_tp->udp.uh_dport;
 
-  sock_address_init_inet( &daddr,
-                          spt->client_ip,
-                          spt->client_port );
+  daddr.sin_addr = spt->client_ip;
+  daddr.sin_port = spt->client_port;
 
   nobytes = 2;
 
   m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
         sizeof(struct ip) - sizeof(struct udphdr);
 
-  udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+  udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 
   tftp_session_terminate(spt);
 
@@ -219,8 +216,8 @@
 			  u_int16_t block_nr,
 			  struct tftp_t *recv_tp)
 {
-  SockAddress saddr, daddr;
-  MBuf m;
+  struct sockaddr_in saddr, daddr;
+  struct mbuf *m;
   struct tftp_t *tp;
   int nobytes;
 
@@ -228,7 +225,7 @@
     return -1;
   }
 
-  m = mbuf_alloc();
+  m = m_get();
 
   if (!m) {
     return -1;
@@ -236,25 +233,23 @@
 
   memset(m->m_data, 0, m->m_size);
 
-  m->m_data += if_maxlinkhdr;
+  m->m_data += IF_MAXLINKHDR;
   tp = (void *)m->m_data;
   m->m_data += sizeof(struct udpiphdr);
 
   tp->tp_op = htons(TFTP_DATA);
   tp->x.tp_data.tp_block_nr = htons(block_nr);
 
-  sock_address_init_inet( &saddr,
-                          ip_geth(recv_tp->ip.ip_dst),
-                          port_geth(recv_tp->udp.uh_dport) );
+  saddr.sin_addr = recv_tp->ip.ip_dst;
+  saddr.sin_port = recv_tp->udp.uh_dport;
 
-  sock_address_init_inet( &daddr,
-                          spt->client_ip,
-                          spt->client_port );
+  daddr.sin_addr = spt->client_ip;
+  daddr.sin_port = spt->client_port;
 
   nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
 
   if (nobytes < 0) {
-    mbuf_free(m);
+    m_free(m);
 
     /* send "file not found" error back */
 
@@ -266,7 +261,7 @@
   m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
         sizeof(struct ip) - sizeof(struct udphdr);
 
-  udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+  udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 
   if (nobytes == 512) {
     tftp_session_update(spt);
@@ -327,13 +322,13 @@
       return;
   }
 
-  k += 6;  /* skipping octet */
+  k += 6; /* skipping octet */
 
   /* do sanity checks on the filename */
 
   if ((spt->filename[0] != '/')
-      || (spt->filename[strlen((const char*)spt->filename) - 1] == '/')
-      ||  strstr((const char*)spt->filename, "/../")) {
+      || (spt->filename[strlen((char *)spt->filename) - 1] == '/')
+      ||  strstr((char *)spt->filename, "/../")) {
       tftp_send_error(spt, 2, "Access violation", tp);
       return;
   }
@@ -360,37 +355,37 @@
   while (k < n) {
       const char *key, *value;
 
-      key = (const char*)src + k;
+      key = (char *)src + k;
       k += strlen(key) + 1;
 
       if (k >= n) {
-          tftp_send_error(spt, 2, "Access violation", tp);
-          return;
+	  tftp_send_error(spt, 2, "Access violation", tp);
+	  return;
       }
 
-      value = (const char*)src + k;
+      value = (char *)src + k;
       k += strlen(value) + 1;
 
       if (strcmp(key, "tsize") == 0) {
-          int tsize = atoi(value);
-          struct stat stat_p;
+	  int tsize = atoi(value);
+	  struct stat stat_p;
 
-          if (tsize == 0 && tftp_prefix) {
-              char buffer[1024];
-              int len;
+	  if (tsize == 0 && tftp_prefix) {
+	      char buffer[1024];
+	      int len;
 
-              len = snprintf(buffer, sizeof(buffer), "%s/%s",
-                             tftp_prefix, spt->filename);
+	      len = snprintf(buffer, sizeof(buffer), "%s/%s",
+			     tftp_prefix, spt->filename);
 
-              if (stat(buffer, &stat_p) == 0)
-                  tsize = stat_p.st_size;
-              else {
-                  tftp_send_error(spt, 1, "File not found", tp);
-                  return;
-              }
-          }
+	      if (stat(buffer, &stat_p) == 0)
+		  tsize = stat_p.st_size;
+	      else {
+		  tftp_send_error(spt, 1, "File not found", tp);
+		  return;
+	      }
+	  }
 
-          tftp_send_oack(spt, "tsize", tsize, tp);
+	  tftp_send_oack(spt, "tsize", tsize, tp);
       }
   }
 
@@ -414,7 +409,7 @@
   }
 }
 
-void tftp_input(MBuf m)
+void tftp_input(struct mbuf *m)
 {
   struct tftp_t *tp = (struct tftp_t *)m->m_data;
 
diff --git a/slirp2/tftp.h b/slirp/tftp.h
similarity index 89%
copy from slirp2/tftp.h
copy to slirp/tftp.h
index 06018a7..8f2675e 100644
--- a/slirp2/tftp.h
+++ b/slirp/tftp.h
@@ -18,11 +18,11 @@
   struct udphdr udp;
   u_int16_t tp_op;
   union {
-    struct { 
+    struct {
       u_int16_t tp_block_nr;
       u_int8_t tp_buf[512];
     } tp_data;
-    struct { 
+    struct {
       u_int16_t tp_error_code;
       u_int8_t tp_msg[512];
     } tp_error;
@@ -30,4 +30,4 @@
   } x;
 };
 
-void tftp_input(MBuf m);
+void tftp_input(struct mbuf *m);
diff --git a/slirp/udp.c b/slirp/udp.c
new file mode 100644
index 0000000..11e78cd
--- /dev/null
+++ b/slirp/udp.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)udp_usrreq.c	8.4 (Berkeley) 1/21/94
+ * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
+ */
+
+/*
+ * Changes and additions relating to SLiRP
+ * Copyright (c) 1995 Danny Gasparovski.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+#include "ip_icmp.h"
+
+#ifdef LOG_ENABLED
+struct udpstat udpstat;
+#endif
+
+struct socket udb;
+
+static u_int8_t udp_tos(struct socket *so);
+static void udp_emu(struct socket *so, struct mbuf *m);
+
+/*
+ * UDP protocol implementation.
+ * Per RFC 768, August, 1980.
+ */
+#ifndef	COMPAT_42
+#define UDPCKSUM 1
+#else
+#define UDPCKSUM 0 /* XXX */
+#endif
+
+struct	socket *udp_last_so = &udb;
+
+void
+udp_init(void)
+{
+	udb.so_next = udb.so_prev = &udb;
+}
+/* m->m_data  points at ip packet header
+ * m->m_len   length ip packet
+ * ip->ip_len length data (IPDU)
+ */
+void
+udp_input(register struct mbuf *m, int iphlen)
+{
+	register struct ip *ip;
+	register struct udphdr *uh;
+/*	struct mbuf *opts = 0;*/
+	int len;
+	struct ip save_ip;
+	struct socket *so;
+
+	DEBUG_CALL("udp_input");
+	DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("iphlen = %d", iphlen);
+
+	STAT(udpstat.udps_ipackets++);
+
+	/*
+	 * Strip IP options, if any; should skip this,
+	 * make available to user, and use on returned packets,
+	 * but we don't yet have a way to check the checksum
+	 * with options still present.
+	 */
+	if(iphlen > sizeof(struct ip)) {
+		ip_stripoptions(m, (struct mbuf *)0);
+		iphlen = sizeof(struct ip);
+	}
+
+	/*
+	 * Get IP and UDP header together in first mbuf.
+	 */
+	ip = mtod(m, struct ip *);
+	uh = (struct udphdr *)((caddr_t)ip + iphlen);
+
+	/*
+	 * Make mbuf data length reflect UDP length.
+	 * If not enough data to reflect UDP length, drop.
+	 */
+	len = ntohs((u_int16_t)uh->uh_ulen);
+
+	if (ip->ip_len != len) {
+		if (len > ip->ip_len) {
+			STAT(udpstat.udps_badlen++);
+			goto bad;
+		}
+		m_adj(m, len - ip->ip_len);
+		ip->ip_len = len;
+	}
+
+	/*
+	 * Save a copy of the IP header in case we want restore it
+	 * for sending an ICMP error message in response.
+	 */
+	save_ip = *ip;
+	save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
+
+	/*
+	 * Checksum extended UDP header and data.
+	 */
+	if (UDPCKSUM && uh->uh_sum) {
+      memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
+	  ((struct ipovly *)ip)->ih_x1 = 0;
+	  ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
+	  /* keep uh_sum for ICMP reply
+	   * uh->uh_sum = cksum(m, len + sizeof (struct ip));
+	   * if (uh->uh_sum) {
+	   */
+	  if(cksum(m, len + sizeof(struct ip))) {
+	    STAT(udpstat.udps_badsum++);
+	    goto bad;
+	  }
+	}
+
+        /*
+         *  handle DHCP/BOOTP
+         */
+        if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
+            bootp_input(m);
+            goto bad;
+        }
+
+        if (slirp_restrict)
+            goto bad;
+
+        /*
+         *  handle TFTP
+         */
+        if (ntohs(uh->uh_dport) == TFTP_SERVER) {
+            tftp_input(m);
+            goto bad;
+        }
+
+	/*
+	 * Locate pcb for datagram.
+	 */
+	so = udp_last_so;
+	if (so->so_lport != uh->uh_sport ||
+	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
+		struct socket *tmp;
+
+		for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
+			if (tmp->so_lport == uh->uh_sport &&
+			    tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
+				tmp->so_faddr.s_addr = ip->ip_dst.s_addr;
+				tmp->so_fport = uh->uh_dport;
+				so = tmp;
+				break;
+			}
+		}
+		if (tmp == &udb) {
+		  so = NULL;
+		} else {
+		  STAT(udpstat.udpps_pcbcachemiss++);
+		  udp_last_so = so;
+		}
+	}
+
+	if (so == NULL) {
+	  /*
+	   * If there's no socket for this packet,
+	   * create one
+	   */
+	  if ((so = socreate()) == NULL) goto bad;
+	  if(udp_attach(so) == -1) {
+	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
+			errno,strerror(errno)));
+	    sofree(so);
+	    goto bad;
+	  }
+
+	  /*
+	   * Setup fields
+	   */
+	  /* udp_last_so = so; */
+	  so->so_laddr = ip->ip_src;
+	  so->so_lport = uh->uh_sport;
+
+	  if ((so->so_iptos = udp_tos(so)) == 0)
+	    so->so_iptos = ip->ip_tos;
+
+	  /*
+	   * XXXXX Here, check if it's in udpexec_list,
+	   * and if it is, do the fork_exec() etc.
+	   */
+	}
+
+        so->so_faddr = ip->ip_dst; /* XXX */
+        so->so_fport = uh->uh_dport; /* XXX */
+
+	iphlen += sizeof(struct udphdr);
+	m->m_len -= iphlen;
+	m->m_data += iphlen;
+
+	/*
+	 * Now we sendto() the packet.
+	 */
+	if (so->so_emu)
+	   udp_emu(so, m);
+
+	if(sosendto(so,m) == -1) {
+	  m->m_len += iphlen;
+	  m->m_data -= iphlen;
+	  *ip=save_ip;
+	  DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
+	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
+	}
+
+	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
+
+	/* restore the orig mbuf packet */
+	m->m_len += iphlen;
+	m->m_data -= iphlen;
+	*ip=save_ip;
+	so->so_m=m;         /* ICMP backup */
+
+	return;
+bad:
+	m_freem(m);
+	/* if (opts) m_freem(opts); */
+	return;
+}
+
+int udp_output2(struct socket *so, struct mbuf *m,
+                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
+                int iptos)
+{
+	register struct udpiphdr *ui;
+	int error = 0;
+
+	DEBUG_CALL("udp_output");
+	DEBUG_ARG("so = %lx", (long)so);
+	DEBUG_ARG("m = %lx", (long)m);
+	DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
+	DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
+
+	/*
+	 * Adjust for header
+	 */
+	m->m_data -= sizeof(struct udpiphdr);
+	m->m_len += sizeof(struct udpiphdr);
+
+	/*
+	 * Fill in mbuf with extended UDP header
+	 * and addresses and length put into network format.
+	 */
+	ui = mtod(m, struct udpiphdr *);
+    memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+	ui->ui_x1 = 0;
+	ui->ui_pr = IPPROTO_UDP;
+	ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
+	/* XXXXX Check for from-one-location sockets, or from-any-location sockets */
+        ui->ui_src = saddr->sin_addr;
+	ui->ui_dst = daddr->sin_addr;
+	ui->ui_sport = saddr->sin_port;
+	ui->ui_dport = daddr->sin_port;
+	ui->ui_ulen = ui->ui_len;
+
+	/*
+	 * Stuff checksum and output datagram.
+	 */
+	ui->ui_sum = 0;
+	if (UDPCKSUM) {
+	    if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
+		ui->ui_sum = 0xffff;
+	}
+	((struct ip *)ui)->ip_len = m->m_len;
+
+	((struct ip *)ui)->ip_ttl = IPDEFTTL;
+	((struct ip *)ui)->ip_tos = iptos;
+
+	STAT(udpstat.udps_opackets++);
+
+	error = ip_output(so, m);
+
+	return (error);
+}
+
+int udp_output(struct socket *so, struct mbuf *m,
+               struct sockaddr_in *addr)
+
+{
+    struct sockaddr_in saddr, daddr;
+
+    saddr = *addr;
+    if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
+        if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff))
+            saddr.sin_addr.s_addr = alias_addr.s_addr;
+        else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
+                 (ntohl(so->so_faddr.s_addr) & 0xff) != CTL_ALIAS)
+            saddr.sin_addr.s_addr = so->so_faddr.s_addr;
+    }
+    daddr.sin_addr = so->so_laddr;
+    daddr.sin_port = so->so_lport;
+
+    return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
+}
+
+int
+udp_attach(struct socket *so)
+{
+  struct sockaddr_in addr;
+
+  if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
+    /*
+     * Here, we bind() the socket.  Although not really needed
+     * (sendto() on an unbound socket will bind it), it's done
+     * here so that emulation of ytalk etc. don't have to do it
+     */
+    addr.sin_family = AF_INET;
+    addr.sin_port = 0;
+    addr.sin_addr.s_addr = INADDR_ANY;
+    if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
+      int lasterrno=errno;
+      closesocket(so->s);
+      so->s=-1;
+#ifdef _WIN32
+      WSASetLastError(lasterrno);
+#else
+      errno=lasterrno;
+#endif
+    } else {
+      /* success, insert in queue */
+      so->so_expire = curtime + SO_EXPIRE;
+      insque(so,&udb);
+    }
+  }
+  return(so->s);
+}
+
+void
+udp_detach(struct socket *so)
+{
+	closesocket(so->s);
+	/* if (so->so_m) m_free(so->so_m);    done by sofree */
+
+	sofree(so);
+}
+
+static const struct tos_t udptos[] = {
+	{0, 53, IPTOS_LOWDELAY, 0},			/* DNS */
+	{517, 517, IPTOS_LOWDELAY, EMU_TALK},	/* talk */
+	{518, 518, IPTOS_LOWDELAY, EMU_NTALK},	/* ntalk */
+	{0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME},	/* Cu-Seeme */
+	{0, 0, 0, 0}
+};
+
+static u_int8_t
+udp_tos(struct socket *so)
+{
+	int i = 0;
+
+	while(udptos[i].tos) {
+		if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
+		    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
+		    	so->so_emu = udptos[i].emu;
+			return udptos[i].tos;
+		}
+		i++;
+	}
+
+	return 0;
+}
+
+#ifdef EMULATE_TALK
+#include "talkd.h"
+#endif
+
+/*
+ * Here, talk/ytalk/ntalk requests must be emulated
+ */
+static void
+udp_emu(struct socket *so, struct mbuf *m)
+{
+	struct sockaddr_in addr;
+	socklen_t addrlen = sizeof(addr);
+#ifdef EMULATE_TALK
+	CTL_MSG_OLD *omsg;
+	CTL_MSG *nmsg;
+	char buff[sizeof(CTL_MSG)];
+	u_char type;
+
+struct talk_request {
+	struct talk_request *next;
+	struct socket *udp_so;
+	struct socket *tcp_so;
+} *req;
+
+	static struct talk_request *req_tbl = 0;
+
+#endif
+
+struct cu_header {
+	uint16_t	d_family;		// destination family
+	uint16_t	d_port;			// destination port
+	uint32_t	d_addr;			// destination address
+	uint16_t	s_family;		// source family
+	uint16_t	s_port;			// source port
+	uint32_t	so_addr;		// source address
+	uint32_t	seqn;			// sequence number
+	uint16_t	message;		// message
+	uint16_t	data_type;		// data type
+	uint16_t	pkt_len;		// packet length
+} *cu_head;
+
+	switch(so->so_emu) {
+
+#ifdef EMULATE_TALK
+	 case EMU_TALK:
+	 case EMU_NTALK:
+		/*
+		 * Talk emulation. We always change the ctl_addr to get
+		 * some answers from the daemon. When an ANNOUNCE comes,
+		 * we send LEAVE_INVITE to the local daemons. Also when a
+		 * DELETE comes, we send copies to the local daemons.
+		 */
+		if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
+			return;
+
+#define	IS_OLD	(so->so_emu == EMU_TALK)
+
+#define COPY_MSG(dest, src) { dest->type = src->type; \
+			      dest->id_num = src->id_num; \
+			      dest->pid = src->pid; \
+			      dest->addr = src->addr; \
+			      dest->ctl_addr = src->ctl_addr; \
+			      memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
+			      memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
+	         	      memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
+
+#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
+/* old_sockaddr to sockaddr_in */
+
+
+		if (IS_OLD) {  		/* old talk */
+			omsg = mtod(m, CTL_MSG_OLD*);
+			nmsg = (CTL_MSG *) buff;
+			type = omsg->type;
+			OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
+			OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
+                        pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin());
+		} else {		/* new talk */
+			omsg = (CTL_MSG_OLD *) buff;
+			nmsg = mtod(m, CTL_MSG *);
+			type = nmsg->type;
+			OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
+			OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
+                        pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin());
+		}
+
+		if (type == LOOK_UP)
+			return;		/* for LOOK_UP this is enough */
+
+		if (IS_OLD) {		/* make a copy of the message */
+			COPY_MSG(nmsg, omsg);
+			nmsg->vers = 1;
+			nmsg->answer = 0;
+		} else
+			COPY_MSG(omsg, nmsg);
+
+		/*
+		 * If if is an ANNOUNCE message, we go through the
+		 * request table to see if a tcp port has already
+		 * been redirected for this socket. If not, we solisten()
+		 * a new socket and add this entry to the table.
+		 * The port number of the tcp socket and our IP
+		 * are put to the addr field of the message structures.
+		 * Then a LEAVE_INVITE is sent to both local daemon
+		 * ports, 517 and 518. This is why we have two copies
+		 * of the message, one in old talk and one in new talk
+		 * format.
+		 */
+
+		if (type == ANNOUNCE) {
+			int s;
+			u_short temp_port;
+
+			for(req = req_tbl; req; req = req->next)
+				if (so == req->udp_so)
+					break;  	/* found it */
+
+			if (!req) {	/* no entry for so, create new */
+				req = (struct talk_request *)
+					malloc(sizeof(struct talk_request));
+				req->udp_so = so;
+				req->tcp_so = solisten(0,
+					OTOSIN(omsg, addr)->sin_addr.s_addr,
+					OTOSIN(omsg, addr)->sin_port,
+					SS_FACCEPTONCE);
+				req->next = req_tbl;
+				req_tbl = req;
+			}
+
+			/* replace port number in addr field */
+			addrlen = sizeof(addr);
+			getsockname(req->tcp_so->s,
+					(struct sockaddr *) &addr,
+					&addrlen);
+			OTOSIN(omsg, addr)->sin_port = addr.sin_port;
+			OTOSIN(omsg, addr)->sin_addr = our_addr;
+			OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
+			OTOSIN(nmsg, addr)->sin_addr = our_addr;
+
+			/* send LEAVE_INVITEs */
+			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
+			OTOSIN(omsg, ctl_addr)->sin_port = 0;
+			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
+			omsg->type = nmsg->type = LEAVE_INVITE;
+
+			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+			addr.sin_addr = our_addr;
+			addr.sin_family = AF_INET;
+			addr.sin_port = htons(517);
+			sendto(s, (char *)omsg, sizeof(*omsg), 0,
+				(struct sockaddr *)&addr, sizeof(addr));
+			addr.sin_port = htons(518);
+			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
+				(struct sockaddr *) &addr, sizeof(addr));
+			closesocket(s) ;
+
+			omsg->type = nmsg->type = ANNOUNCE;
+			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
+			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
+		}
+
+		/*
+		 * If it is a DELETE message, we send a copy to the
+		 * local daemons. Then we delete the entry corresponding
+		 * to our socket from the request table.
+		 */
+
+		if (type == DELETE) {
+			struct talk_request *temp_req, *req_next;
+			int s;
+			u_short temp_port;
+
+			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
+			OTOSIN(omsg, ctl_addr)->sin_port = 0;
+			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
+
+			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+			addr.sin_addr = our_addr;
+			addr.sin_family = AF_INET;
+			addr.sin_port = htons(517);
+			sendto(s, (char *)omsg, sizeof(*omsg), 0,
+				(struct sockaddr *)&addr, sizeof(addr));
+			addr.sin_port = htons(518);
+			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
+				(struct sockaddr *)&addr, sizeof(addr));
+			closesocket(s);
+
+			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
+			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
+
+			/* delete table entry */
+			if (so == req_tbl->udp_so) {
+				temp_req = req_tbl;
+				req_tbl = req_tbl->next;
+				free(temp_req);
+			} else {
+				temp_req = req_tbl;
+				for(req = req_tbl->next; req; req = req_next) {
+					req_next = req->next;
+					if (so == req->udp_so) {
+						temp_req->next = req_next;
+						free(req);
+						break;
+					} else {
+						temp_req = req;
+					}
+				}
+			}
+		}
+
+		return;
+#endif
+
+	case EMU_CUSEEME:
+
+		/*
+		 * Cu-SeeMe emulation.
+		 * Hopefully the packet is more that 16 bytes long. We don't
+		 * do any other tests, just replace the address and port
+		 * fields.
+		 */
+		if (m->m_len >= sizeof (*cu_head)) {
+			if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
+				return;
+			cu_head = mtod(m, struct cu_header *);
+			cu_head->s_port = addr.sin_port;
+			cu_head->so_addr = our_addr.s_addr;
+		}
+
+		return;
+	}
+}
+
+struct socket *
+udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
+{
+	struct sockaddr_in addr;
+	struct socket *so;
+	socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
+
+	if ((so = socreate()) == NULL) {
+		free(so);
+		return NULL;
+	}
+	so->s = socket(AF_INET,SOCK_DGRAM,0);
+	so->so_expire = curtime + SO_EXPIRE;
+	insque(so,&udb);
+
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = INADDR_ANY;
+	addr.sin_port = port;
+
+	if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
+		udp_detach(so);
+		return NULL;
+	}
+	setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
+/*	setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */
+
+	getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
+	so->so_fport = addr.sin_port;
+	if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
+	   so->so_faddr = alias_addr;
+	else
+	   so->so_faddr = addr.sin_addr;
+
+	so->so_lport = lport;
+	so->so_laddr.s_addr = laddr;
+	if (flags != SS_FACCEPTONCE)
+	   so->so_expire = 0;
+
+	so->so_state = SS_ISFCONNECTED;
+
+	return so;
+}
diff --git a/slirp2/udp.h b/slirp/udp.h
similarity index 82%
copy from slirp2/udp.h
copy to slirp/udp.h
index cadd17e..51a07a2 100644
--- a/slirp2/udp.h
+++ b/slirp/udp.h
@@ -10,11 +10,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -37,8 +33,6 @@
 #ifndef _UDP_H_
 #define _UDP_H_
 
-#include "helper.h"
-
 #define UDP_TTL 0x60
 #define UDP_UDPDATALEN 16192
 
@@ -49,8 +43,8 @@
  * Per RFC 768, September, 1981.
  */
 struct udphdr {
-	port_t	uh_sport;		/* source port */
-	port_t	uh_dport;		/* destination port */
+	u_int16_t	uh_sport;		/* source port */
+	u_int16_t	uh_dport;		/* destination port */
 	int16_t	uh_ulen;		/* udp length */
 	u_int16_t	uh_sum;			/* udp checksum */
 };
@@ -73,6 +67,7 @@
 #define ui_ulen         ui_u.uh_ulen
 #define ui_sum          ui_u.uh_sum
 
+#ifdef LOG_ENABLED
 struct udpstat {
 	                                /* input statistics: */
 	        u_long  udps_ipackets;          /* total input packets */
@@ -86,6 +81,7 @@
 	                                /* output statistics: */
 	        u_long  udps_opackets;          /* total output packets */
 };
+#endif
 
 /*
  * Names for UDP sysctl objects
@@ -93,23 +89,20 @@
 #define UDPCTL_CHECKSUM         1       /* checksum UDP packets */
 #define UDPCTL_MAXID            2
 
+#ifdef LOG_ENABLED
 extern struct udpstat udpstat;
+#endif
+
 extern struct socket udb;
 struct mbuf;
 
 void udp_init _P((void));
-void udp_input _P((register MBuf , int));
+void udp_input _P((register struct mbuf *, int));
+int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *));
 int udp_attach _P((struct socket *));
 void udp_detach _P((struct socket *));
-u_int8_t udp_tos _P((struct socket *));
-void udp_emu _P((struct socket *, MBuf ));
 struct socket * udp_listen _P((u_int, u_int32_t, u_int, int));
-int udp_unlisten _P((u_int));
-
-int udp_output_(struct socket *, MBuf, SockAddress*);
-
-int udp_output2_(struct socket*  so, MBuf  m,
-                 const SockAddress*  saddr, const SockAddress*  daddr,
-                 int  iptos);
-
+int udp_output2(struct socket *so, struct mbuf *m,
+                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
+                int iptos);
 #endif
diff --git a/slirp2/bootp.c b/slirp2/bootp.c
deleted file mode 100644
index 9ab4b15..0000000
--- a/slirp2/bootp.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * QEMU BOOTP/DHCP server
- * 
- * Copyright (c) 2004 Fabrice Bellard
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include <slirp.h>
-
-/* XXX: only DHCP is supported */
-
-#define NB_ADDR 16
-
-#define START_ADDR 15
-
-#define LEASE_TIME (24 * 3600)
-
-typedef struct {
-    uint8_t allocated;
-    uint8_t macaddr[6];
-} BOOTPClient;
-
-BOOTPClient bootp_clients[NB_ADDR];
-
-const char *bootp_filename;
-
-static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
-
-#ifdef DEBUG
-#define dprintf(fmt, args...) \
-if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## args); fflush(dfd); }
-#else
-#define dprintf(fmt, args...)
-#endif
-
-static BOOTPClient *get_new_addr(SockAddress*  paddr)
-{
-    BOOTPClient *bc;
-    int i;
-
-    for(i = 0; i < NB_ADDR; i++) {
-        if (!bootp_clients[i].allocated)
-            goto found;
-    }
-    return NULL;
- found:
-    bc = &bootp_clients[i];
-    bc->allocated = 1;
-    sock_address_init_inet( paddr, 
-                            special_addr_ip | (i+START_ADDR),
-                            BOOTP_CLIENT );
-    return bc;
-}
-
-static BOOTPClient *find_addr(SockAddress* paddr, const uint8_t *macaddr)
-{
-    BOOTPClient *bc;
-    int i;
-
-    for(i = 0; i < NB_ADDR; i++) {
-        if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
-            goto found;
-    }
-    return NULL;
- found:
-    bc = &bootp_clients[i];
-    bc->allocated = 1;
-    sock_address_init_inet( paddr,
-                            special_addr_ip | (i + START_ADDR),
-                            BOOTP_CLIENT );
-    return bc;
-}
-
-static void dhcp_decode(const uint8_t *buf, int size,
-                        int *pmsg_type)
-{
-    const uint8_t *p, *p_end;
-    int len, tag;
-
-    *pmsg_type = 0;    
-
-    p = buf;
-    p_end = buf + size;
-    if (size < 5)
-        return;
-    if (memcmp(p, rfc1533_cookie, 4) != 0)
-        return;
-    p += 4;
-    while (p < p_end) {
-        tag = p[0];
-        if (tag == RFC1533_PAD) {
-            p++; 
-        } else if (tag == RFC1533_END) {
-            break;
-        } else {
-            p++;
-            if (p >= p_end)
-                break;
-            len = *p++;
-            dprintf("dhcp: tag=0x%02x len=%d\n", tag, len);
-
-            switch(tag) {
-            case RFC2132_MSG_TYPE:
-                if (len >= 1)
-                    *pmsg_type = p[0];
-                break;
-            default:
-                break;
-            }
-            p += len;
-        }
-    }
-}
-
-static void bootp_reply(struct bootp_t *bp)
-{
-    BOOTPClient *bc;
-    MBuf m;
-    struct bootp_t *rbp;
-    SockAddress  saddr, daddr;
-    uint32_t     dns_addr;
-    int dhcp_msg_type, val;
-    uint8_t *q;
-
-    /* extract exact DHCP msg type */
-    dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);
-    dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type);
-    
-    if (dhcp_msg_type == 0)
-        dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
-        
-    if (dhcp_msg_type != DHCPDISCOVER && 
-        dhcp_msg_type != DHCPREQUEST)
-        return;
-    /* XXX: this is a hack to get the client mac address */
-    memcpy(client_ethaddr, bp->bp_hwaddr, 6);
-    
-    if ((m = mbuf_alloc()) == NULL)
-        return;
-    m->m_data += if_maxlinkhdr;
-    rbp = (struct bootp_t *)m->m_data;
-    m->m_data += sizeof(struct udpiphdr);
-    memset(rbp, 0, sizeof(struct bootp_t));
-
-    if (dhcp_msg_type == DHCPDISCOVER) {
-    new_addr:
-        bc = get_new_addr(&daddr);
-        if (!bc) {
-            dprintf("no address left\n");
-            return;
-        }
-        memcpy(bc->macaddr, client_ethaddr, 6);
-    } else {
-        bc = find_addr(&daddr, bp->bp_hwaddr);
-        if (!bc) {
-            /* if never assigned, behaves as if it was already
-               assigned (windows fix because it remembers its address) */
-            goto new_addr;
-        }
-    }
-    if (bootp_filename)
-        snprintf((char*)rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
-
-    dprintf("offered addr=%s\n", sock_address_to_string(&daddr));
-
-    sock_address_init_inet( &saddr, special_addr_ip | CTL_ALIAS,
-                            BOOTP_SERVER );
-
-    rbp->bp_op = BOOTP_REPLY;
-    rbp->bp_xid = bp->bp_xid;
-    rbp->bp_htype = 1;
-    rbp->bp_hlen = 6;
-    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
-
-    rbp->bp_yiaddr = htonl(sock_address_get_ip(&daddr)); /* Client IP address */
-    rbp->bp_siaddr = htonl(sock_address_get_ip(&saddr)); /* Server IP address */
-
-    q = rbp->bp_vend;
-    memcpy(q, rfc1533_cookie, 4);
-    q += 4;
-
-    if (dhcp_msg_type == DHCPDISCOVER) {
-        *q++ = RFC2132_MSG_TYPE;
-        *q++ = 1;
-        *q++ = DHCPOFFER;
-    } else if (dhcp_msg_type == DHCPREQUEST) {
-        *q++ = RFC2132_MSG_TYPE;
-        *q++ = 1;
-        *q++ = DHCPACK;
-    }
-
-    if (dhcp_msg_type == DHCPDISCOVER ||
-        dhcp_msg_type == DHCPREQUEST) {
-        uint32_t  saddr_ip = htonl(sock_address_get_ip(&saddr));
-        *q++ = RFC2132_SRV_ID;
-        *q++ = 4;
-        memcpy(q, &saddr_ip, 4);
-        q += 4;
-
-        *q++ = RFC1533_NETMASK;
-        *q++ = 4;
-        *q++ = 0xff;
-        *q++ = 0xff;
-        *q++ = 0xff;
-        *q++ = 0x00;
-
-        *q++ = RFC1533_GATEWAY;
-        *q++ = 4;
-        memcpy(q, &saddr_ip, 4);
-        q += 4;
-
-        *q++ = RFC1533_DNS;
-        *q++ = 4;
-        dns_addr = htonl(special_addr_ip | CTL_DNS);
-        memcpy(q, &dns_addr, 4);
-        q += 4;
-
-        *q++ = RFC2132_LEASE_TIME;
-        *q++ = 4;
-        val = htonl(LEASE_TIME);
-        memcpy(q, &val, 4);
-        q += 4;
-
-        if (*slirp_hostname) {
-            val = strlen(slirp_hostname);
-            *q++ = RFC1533_HOSTNAME;
-            *q++ = val;
-            memcpy(q, slirp_hostname, val);
-            q += val;
-        }
-    }
-    *q++ = RFC1533_END;
-    
-    m->m_len = sizeof(struct bootp_t) - 
-        sizeof(struct ip) - sizeof(struct udphdr);
-
-    udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
-}
-
-void bootp_input(MBuf m)
-{
-    struct bootp_t *bp = MBUF_TO(m, struct bootp_t *);
-
-    if (bp->bp_op == BOOTP_REQUEST) {
-        bootp_reply(bp);
-    }
-}
diff --git a/slirp2/mbuf.c b/slirp2/mbuf.c
deleted file mode 100644
index efc8141..0000000
--- a/slirp2/mbuf.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-/*
- * mbuf's in SLiRP are much simpler than the real mbufs in
- * FreeBSD.  They are fixed size, determined by the MTU,
- * so that one whole packet can fit.  Mbuf's cannot be
- * chained together.  If there's more data than the mbuf
- * could hold, an external malloced buffer is pointed to
- * by m_ext (and the data pointers) and M_EXT is set in
- * the flags
- */
-
-#include <slirp.h>
-
-static int      mbuf_alloced = 0;
-static MBufRec  m_freelist, m_usedlist;
-static int      mbuf_thresh = 30;
-static int      mbuf_max = 0;
-static int      msize;
-
-/* 
- * How much room is in the mbuf, from m_data to the end of the mbuf
- */
-#define M_ROOM(m) ((m->m_flags & M_EXT)? \
-			(((m)->m_ext + (m)->m_size) - (m)->m_data) \
-		   : \
-			(((m)->m_dat + (m)->m_size) - (m)->m_data))
-
-/*
- * How much free room there is
- */
-#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
-
-
-void
-mbuf_init()
-{
-	m_freelist.m_next = m_freelist.m_prev = &m_freelist;
-	m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist;
-	msize_init();
-}
-
-void
-msize_init()
-{
-	/*
-	 * Find a nice value for msize
-	 * XXX if_maxlinkhdr already in mtu
-	 */
-	msize = (if_mtu > if_mru ? if_mtu : if_mru) + 
-			if_maxlinkhdr + sizeof(struct m_hdr ) + 6;
-}
-
-static void
-mbuf_insque(MBuf  m, MBuf  head)
-{
-	m->m_next         = head->m_next;
-	m->m_prev         = head;
-	head->m_next      = m;
-	m->m_next->m_prev = m;
-}
-
-static void
-mbuf_remque(MBuf  m)
-{
-	m->m_prev->m_next = m->m_next;
-	m->m_next->m_prev = m->m_prev;
-	m->m_next = m->m_prev = m;
-}
-
-/*
- * Get an mbuf from the free list, if there are none
- * malloc one
- * 
- * Because fragmentation can occur if we alloc new mbufs and
- * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
- * which tells m_free to actually free() it
- */
-MBuf
-mbuf_alloc(void)
-{
-	register MBuf m;
-	int flags = 0;
-	
-	DEBUG_CALL("mbuf_alloc");
-	
-	if (m_freelist.m_next == &m_freelist) {
-		m = (MBuf) malloc(msize);
-		if (m == NULL) goto end_error;
-		mbuf_alloced++;
-		if (mbuf_alloced > mbuf_thresh)
-			flags = M_DOFREE;
-		if (mbuf_alloced > mbuf_max)
-			mbuf_max = mbuf_alloced;
-	} else {
-		m = m_freelist.m_next;
-		mbuf_remque(m);
-	}
-	
-	/* Insert it in the used list */
-	mbuf_insque(m,&m_usedlist);
-	m->m_flags = (flags | M_USEDLIST);
-	
-	/* Initialise it */
-	m->m_size  = msize - sizeof(struct m_hdr);
-	m->m_data  = m->m_dat;
-	m->m_len   = 0;
-	m->m_next2 = NULL;
-	m->m_prev2 = NULL;
-end_error:
-	DEBUG_ARG("m = %lx", (long )m);
-	return m;
-}
-
-void
-mbuf_free(MBuf  m)
-{
-	
-  DEBUG_CALL("mbuf_free");
-  DEBUG_ARG("m = %lx", (long )m);
-	
-  if(m) {
-	/* Remove from m_usedlist */
-	if (m->m_flags & M_USEDLIST)
-	   mbuf_remque(m);
-	
-	/* If it's M_EXT, free() it */
-	if (m->m_flags & M_EXT)
-	   free(m->m_ext);
-
-	/*
-	 * Either free() it or put it on the free list
-	 */
-	if (m->m_flags & M_DOFREE) {
-		free(m);
-		mbuf_alloced--;
-	} else if ((m->m_flags & M_FREELIST) == 0) {
-		mbuf_insque(m,&m_freelist);
-		m->m_flags = M_FREELIST; /* Clobber other flags */
-	}
-  } /* if(m) */
-}
-
-/*
- * Copy data from one mbuf to the end of
- * the other.. if result is too big for one mbuf, malloc()
- * an M_EXT data segment
- */
-void
-mbuf_append(MBuf  m, MBuf  n)
-{
-	/*
-	 * If there's no room, realloc
-	 */
-	if (M_FREEROOM(m) < n->m_len)
-		mbuf_ensure(m, m->m_size+MINCSIZE);
-	
-	memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
-	m->m_len += n->m_len;
-
-	mbuf_free(n);
-}
-
-
-/* make m size bytes large */
-void
-mbuf_ensure(MBuf  m, int  size)
-{
-	int datasize;
-
-	/* some compiles throw up on gotos.  This one we can fake. */
-    if(m->m_size > size) return;
-
-    if (m->m_flags & M_EXT) {
-        datasize = m->m_data - m->m_ext;
-        m->m_ext = (char *)realloc(m->m_ext,size);
-        m->m_data = m->m_ext + datasize;
-    } else {
-        char *dat;
-        datasize = m->m_data - m->m_dat;
-        dat      = (char *)malloc(size);
-        memcpy(dat, m->m_dat, m->m_size);
-
-        m->m_ext    = dat;
-        m->m_data   = m->m_ext + datasize;
-        m->m_flags |= M_EXT;
-    }
- 
-    m->m_size = size;
-}
-
-
-
-void
-mbuf_trim(MBuf  m, int  len)
-{
-	if (m == NULL)
-		return;
-	if (len >= 0) {
-		/* Trim from head */
-		m->m_data += len;
-		m->m_len  -= len;
-	} else {
-		/* Trim from tail */
-		len       = -len;
-		m->m_len -= len;
-	}
-}
-
-
-/*
- * Copy len bytes from m, starting off bytes into n
- */
-int
-mbuf_copy(MBuf  n, MBuf  m, int  off, int  len)
-{
-	if (len > M_FREEROOM(n))
-		return -1;
-
-	memcpy((n->m_data + n->m_len), (m->m_data + off), len);
-	n->m_len += len;
-	return 0;
-}
-
-int
-mbuf_freeroom( MBuf  m )
-{
-	return  M_FREEROOM(m);
-}
-
-/*
- * Given a pointer into an mbuf, return the mbuf
- * XXX This is a kludge, I should eliminate the need for it
- * Fortunately, it's not used often
- */
-MBuf
-mbuf_from(void*  dat)
-{
-	MBuf  m;
-	
-	DEBUG_CALL("mbuf_from");
-	DEBUG_ARG("dat = %lx", (long )dat);
-
-	/* bug corrected for M_EXT buffers */
-	for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) {
-	  if (m->m_flags & M_EXT) {
-	    if( (unsigned)((char*)dat - m->m_ext) < (unsigned)m->m_size )
-			goto Exit;
-	  } else {
-	    if( (unsigned)((char *)dat - m->m_dat) < (unsigned)m->m_size )
-	      goto Exit;
-	  }
-	}
-	m  = NULL;
-	DEBUG_ERROR((dfd, "mbuf_from failed"));
-Exit:	
-	return m;
-}
-
-void
-mbufstats()
-{
-	MBuf m;
-	int i;
-	
-    lprint(" \r\n");
-	
-	lprint("Mbuf stats:\r\n");
-
-	lprint("  %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max);
-	
-	i = 0;
-	for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next)
-		i++;
-	lprint("  %6d mbufs on free list\r\n",  i);
-	
-	i = 0;
-	for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
-		i++;
-	lprint("  %6d mbufs on used list\r\n",  i);
-        lprint("  %6d mbufs queued as packets\r\n\r\n", if_queued);
-}
diff --git a/slirp2/mbuf.h b/slirp2/mbuf.h
deleted file mode 100644
index ed83372..0000000
--- a/slirp2/mbuf.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 1982, 1986, 1988, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)mbuf.h	8.3 (Berkeley) 1/21/94
- * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp
- */
-
-#ifndef _MBUF_H_
-#define _MBUF_H_
-
-#define MINCSIZE 4096	/* Amount to increase mbuf if too small */
-
-/* flags for the mh_flags field */
-#define M_EXT			0x01	/* m_ext points to more (malloced) data */
-#define M_FREELIST		0x02	/* mbuf is on free list */
-#define M_USEDLIST		0x04	/* XXX mbuf is on used list (for dtom()) */
-#define M_DOFREE		0x08	/* when mbuf_free is called on the mbuf, free()
-					                                  * it rather than putting it on the free list */
-
-
-/* XXX About mbufs for slirp:
- * Only one mbuf is ever used in a chain, for each "cell" of data.
- * m_nextpkt points to the next packet, if fragmented.
- * If the data is too large, the M_EXT is used, and a larger block
- * is alloced.  Therefore, mbuf_free[m] must check for M_EXT and if set
- * free the m_ext.  This is inefficient memory-wise, but who cares.
- */
-
-/* XXX should union some of these! */
-/* header at beginning of each mbuf: */
-
-/**
- *  m_next, m_prev   :: used to place the MBuf in free/used linked lists
- *  m_next2, m_prev2 :: used to place the same MBuf in other linked lists
- *  m_flags :: bit flags describing this MBuf
- *  m_size  :: total size of MBuf buffer
- *  m_so    :: socket this MBuf is attached to
- *  m_data  :: pointer to current cursor in MBuf buffer
- *  m_len   :: amount of data recorded in this MBuf
- */
-#define  MBUF_HEADER           \
-	struct mbuf*   m_next;     \
-	struct mbuf*   m_prev;     \
-	struct mbuf*   m_next2;    \
-	struct mbuf*   m_prev2;    \
-	int            m_flags;    \
-	int            m_size;     \
-	struct socket* m_so;       \
-	caddr_t        m_data;     \
-	int            m_len;
-
-struct m_hdr {
-	MBUF_HEADER
-};
-
-typedef struct mbuf {
-	MBUF_HEADER
-	union M_dat {
-		char   m_dat_[1]; /* ANSI doesn't like 0 sized arrays */
-		char*  m_ext_;
-	} M_dat;
-} MBufRec, *MBuf;
-
-#define m_nextpkt	m_next2
-#define m_prevpkt	m_prev2
-#define m_dat		M_dat.m_dat_
-#define m_ext		M_dat.m_ext_
-
-#define ifq_prev m_prev
-#define ifq_next m_next
-
-#define ifs_prev m_prev2
-#define ifs_next m_next2
-
-#define ifq_so m_so
-
-void mbuf_init  (void);
-void msize_init (void);
-MBuf mbuf_alloc (void);
-void mbuf_free  (MBuf  m);
-void mbuf_append(MBuf  m1, MBuf  m2);
-void mbuf_ensure(MBuf  m, int  size);
-void mbuf_trim  (MBuf  m, int  len);
-int  mbuf_copy  (MBuf  m, MBuf  n, int  n_offset, int  n_length);
-
-#define MBUF_TO(m,t)  ((t)(m)->m_data)
-#define MBUF_FROM(d)  mbuf_from(d)
-MBuf  mbuf_from (void *);
-
-int   mbuf_freeroom( MBuf  m );
-
-#endif
diff --git a/slirp2/misc.c b/slirp2/misc.c
deleted file mode 100644
index 9a2699a..0000000
--- a/slirp2/misc.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
- * terms and conditions of the copyright.
- */
-
-#define WANT_SYS_IOCTL_H
-#include <slirp.h>
-
-u_int curtime, time_fasttimo, last_slowtimo, detach_time;
-u_int detach_wait = 600000;	/* 10 minutes */
-struct emu_t *tcpemu;
-
-int
-inet_strtoip(const char*  str, uint32_t  *ip)
-{
-    int  comp[4];
-
-    if (sscanf(str, "%d.%d.%d.%d", &comp[0], &comp[1], &comp[2], &comp[3]) != 4)
-        return -1;
-
-    if ((unsigned)comp[0] >= 256 ||
-        (unsigned)comp[1] >= 256 ||
-        (unsigned)comp[2] >= 256 ||
-        (unsigned)comp[3] >= 256)
-        return -1;
-
-    *ip = (uint32_t)((comp[0] << 24) | (comp[1] << 16) |
-                     (comp[2] << 8)  |  comp[3]);
-    return 0;
-}
-
-char*  inet_iptostr(uint32_t  ip)
-{
-    static char  buff[32];
-
-    snprintf(buff, sizeof(buff), "%d.%d.%d.%d",
-             (ip >> 24) & 255,
-             (ip >> 16) & 255,
-             (ip >> 8) & 255,
-             ip & 255);
-    return buff;
-}
-
-/*
- * Get our IP address and put it in our_addr
- */
-void
-getouraddr()
-{
-    char*        hostname = host_name();
-    SockAddress  hostaddr;
-
-    our_addr_ip = loopback_addr_ip;
-
-    if (sock_address_init_resolve( &hostaddr, hostname, 0, 0 ) < 0)
-        return;
-
-    our_addr_ip = sock_address_get_ip(&hostaddr);
-    if (our_addr_ip == (uint32_t)-1)
-        our_addr_ip = loopback_addr_ip;
-}
-
-struct quehead {
-	struct quehead *qh_link;
-	struct quehead *qh_rlink;
-};
-
-inline void
-insque(void*  a, void*  b)
-{
-	register struct quehead *element = (struct quehead *) a;
-	register struct quehead *head = (struct quehead *) b;
-	element->qh_link = head->qh_link;
-	head->qh_link = (struct quehead *)element;
-	element->qh_rlink = (struct quehead *)head;
-	((struct quehead *)(element->qh_link))->qh_rlink
-	= (struct quehead *)element;
-}
-
-inline void
-remque(void*  a)
-{
-  register struct quehead *element = (struct quehead *) a;
-  ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
-  ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
-  element->qh_rlink = NULL;
-  /*  element->qh_link = NULL;  TCP FIN1 crashes if you do this.  Why ? */
-}
-
-/* #endif */
-
-
-#ifndef HAVE_STRERROR
-
-/*
- * For systems with no strerror
- */
-
-extern int sys_nerr;
-extern char *sys_errlist[];
-
-char *
-strerror(int  error)
-{
-	if (error < sys_nerr)
-	   return sys_errlist[error];
-	else
-	   return "Unknown error.";
-}
-
-#endif
-
-
-
-#ifndef HAVE_STRDUP
-char *
-strdup(const char*  str)
-{
-	char *bptr;
-	int   len = strlen(str);
-
-	bptr = (char *)malloc(len+1);
-	memcpy(bptr, str, len+1);
-
-	return bptr;
-}
-#endif
-
-
-int (*lprint_print) _P((void *, const char *, va_list));
-char *lprint_ptr, *lprint_ptr2, **lprint_arg;
-
-void
-lprint(const char *format, ...)
-{
-	va_list args;
-
-    va_start(args, format);
-	if (lprint_print)
-	   lprint_ptr += (*lprint_print)(*lprint_arg, format, args);
-
-	/* Check if they want output to be logged to file as well */
-	if (lfd) {
-		/*
-		 * Remove \r's
-		 * otherwise you'll get ^M all over the file
-		 */
-		int len = strlen(format);
-		char *bptr1, *bptr2;
-
-		bptr1 = bptr2 = strdup(format);
-
-		while (len--) {
-			if (*bptr1 == '\r')
-			   memcpy(bptr1, bptr1+1, len+1);
-			else
-			   bptr1++;
-		}
-		vfprintf(lfd, bptr2, args);
-		free(bptr2);
-	}
-	va_end(args);
-}
-
-void
-add_emu(char* buff)
-{
-	u_int lport, fport;
-	u_int8_t tos = 0, emu = 0;
-	char buff1[256], buff2[256], buff4[128];
-	char *buff3 = buff4;
-	struct emu_t *emup;
-	struct socket *so;
-
-	if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) {
-		lprint("Error: Bad arguments\r\n");
-		return;
-	}
-
-	if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) {
-		lport = 0;
-		if (sscanf(buff1, "%d", &fport) != 1) {
-			lprint("Error: Bad first argument\r\n");
-			return;
-		}
-	}
-
-	if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) {
-		buff3 = 0;
-		if (sscanf(buff2, "%256s", buff1) != 1) {
-			lprint("Error: Bad second argument\r\n");
-			return;
-		}
-	}
-
-	if (buff3) {
-		if (strcmp(buff3, "lowdelay") == 0)
-		   tos = IPTOS_LOWDELAY;
-		else if (strcmp(buff3, "throughput") == 0)
-		   tos = IPTOS_THROUGHPUT;
-		else {
-			lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n");
-			return;
-		}
-	}
-
-	if (strcmp(buff1, "ftp") == 0)
-	   emu = EMU_FTP;
-	else if (strcmp(buff1, "irc") == 0)
-	   emu = EMU_IRC;
-	else if (strcmp(buff1, "none") == 0)
-	   emu = EMU_NONE; /* ie: no emulation */
-	else {
-		lprint("Error: Unknown service\r\n");
-		return;
-	}
-
-	/* First, check that it isn't already emulated */
-	for (emup = tcpemu; emup; emup = emup->next) {
-		if (emup->lport == lport && emup->fport == fport) {
-			lprint("Error: port already emulated\r\n");
-			return;
-		}
-	}
-
-	/* link it */
-	emup = (struct emu_t *)malloc(sizeof (struct emu_t));
-	emup->lport = (u_int16_t)lport;
-	emup->fport = (u_int16_t)fport;
-	emup->tos = tos;
-	emup->emu = emu;
-	emup->next = tcpemu;
-	tcpemu = emup;
-
-	/* And finally, mark all current sessions, if any, as being emulated */
-	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
-		if ((lport && lport == so->so_laddr_port) ||
-		    (fport && fport == so->so_faddr_port)) {
-			if (emu)
-			   so->so_emu = emu;
-			if (tos)
-			   so->so_iptos = tos;
-		}
-	}
-
-	lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport);
-}
-
-#ifdef BAD_SPRINTF
-
-#undef vsprintf
-#undef sprintf
-
-/*
- * Some BSD-derived systems have a sprintf which returns char *
- */
-
-int
-vsprintf_len(char* string, const char* format, va_list args)
-{
-	vsprintf(string, format, args);
-	return strlen(string);
-}
-
-int
-sprintf_len(char *string, const char *format, ...)
-{
-	va_list args;
-	va_start(args, format);
-	vsprintf(string, format, args);
-	return strlen(string);
-}
-
-#endif
-
diff --git a/slirp2/misc.h b/slirp2/misc.h
deleted file mode 100644
index aa4a0ce..0000000
--- a/slirp2/misc.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
- * terms and conditions of the copyright.
- */
-
-#ifndef _MISC_H_
-#define _MISC_H_
-
-extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait;
-
-extern int (*lprint_print) _P((void *, const char *, va_list));
-extern char *lprint_ptr, *lprint_ptr2, **lprint_arg;
-//extern SBuf lprint_sb;
-
-#ifndef HAVE_STRDUP
-char *strdup _P((const char *));
-#endif
-
-void do_wait _P((int));
-
-#define EMU_NONE 0x0
-
-/* TCP emulations */
-#define EMU_CTL 0x1
-#define EMU_FTP 0x2
-#define EMU_KSH 0x3
-#define EMU_IRC 0x4
-#define EMU_REALAUDIO 0x5
-#define EMU_RLOGIN 0x6
-#define EMU_IDENT 0x7
-#define EMU_RSH 0x8
-
-#define EMU_NOCONNECT 0x10	/* Don't connect */
-
-/* UDP emulations */
-#define EMU_TALK	0x1
-#define EMU_NTALK	0x2
-#define EMU_CUSEEME	0x3
-
-struct tos_t {
-	u_int16_t lport;
-	u_int16_t fport;
-	u_int8_t tos;
-	u_int8_t emu;
-};
-
-struct emu_t {
-	u_int16_t lport;
-	u_int16_t fport;
-	u_int8_t tos;
-	u_int8_t emu;
-	struct emu_t *next;
-};
-
-extern struct emu_t *tcpemu;
-
-void getouraddr _P((void));
-inline  void slirp_insque  _P((void *, void *));
-inline  void slirp_remque  _P((void *));
-void add_emu _P((char *));
-
-#endif
diff --git a/slirp2/sbuf.h b/slirp2/sbuf.h
deleted file mode 100644
index 05fa01a..0000000
--- a/slirp2/sbuf.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
- * terms and conditions of the copyright.
- */
-
-#ifndef _SBUF_H_
-#define _SBUF_H_
-
-#include "mbuf.h"
-#include <stddef.h>
-
-/* a SBuf is a simple circular buffer used to hold RX and TX data in a struct socket
- */
-
-typedef struct sbuf {
-	unsigned  sb_cc;      /* actual chars in buffer */
-	unsigned  sb_datalen; /* Length of data  */
-	char*     sb_wptr;    /* write pointer. points to where the next
-			                                       * bytes should be written in the sbuf */
-	char*     sb_rptr;    /* read pointer. points to where the next
-                                                                       * byte should be read from the sbuf */
-	char*     sb_data;	/* Actual data */
-} SBufRec, *SBuf;
-
-void sbuf_free    (SBuf  sb);
-void sbuf_drop    (SBuf  sb, int  num);
-void sbuf_reserve (SBuf  sb, int  count);
-void sbuf_append  (struct socket *so, MBuf  m);
-void sbuf_appendsb(SBuf  sb, MBuf  m);
-void sbuf_copy    (SBuf  sb, int  offset, int  length, char *to);
-
-#define sbuf_flush(sb) sbuf_drop((sb),(sb)->sb_cc)
-#define sbuf_space(sb) ((sb)->sb_datalen - (sb)->sb_cc)
-
-#endif
diff --git a/slirp2/slirp.c b/slirp2/slirp.c
deleted file mode 100644
index 23a3e3c..0000000
--- a/slirp2/slirp.c
+++ /dev/null
@@ -1,762 +0,0 @@
-#include "slirp.h"
-#include "proxy_common.h"
-#include "android/utils/debug.h"  /* for dprint */
-#include "android/utils/bufprint.h"
-#include "android/android.h"
-#include "sockets.h"
-
-#define  D(...)   VERBOSE_PRINT(slirp,__VA_ARGS__)
-#define  DN(...)  do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0)
-
-/* host address */
-uint32_t our_addr_ip;
-/* host dns address */
-uint32_t dns_addr[DNS_ADDR_MAX];
-int      dns_addr_count;
-
-/* host loopback address */
-uint32_t loopback_addr_ip;
-
-/* address for slirp virtual addresses */
-uint32_t  special_addr_ip;
-
-/* virtual address alias for host */
-uint32_t alias_addr_ip;
-
-const uint8_t special_ethaddr[6] = {
-    0x52, 0x54, 0x00, 0x12, 0x35, 0x00
-};
-
-uint8_t client_ethaddr[6] = {
-    0x52, 0x54, 0x00, 0x12, 0x34, 0x56
-};
-
-int do_slowtimo;
-int link_up;
-struct timeval tt;
-FILE *lfd;
-
-/* XXX: suppress those select globals */
-fd_set *global_readfds, *global_writefds, *global_xfds;
-
-char slirp_hostname[33];
-
-int slirp_add_dns_server(const SockAddress*  new_dns_addr)
-{
-    int   dns_ip;
-
-    if (dns_addr_count >= DNS_ADDR_MAX)
-        return -1;
-
-    dns_ip = sock_address_get_ip(new_dns_addr);
-    if (dns_ip < 0)
-        return -1;
-
-    dns_addr[dns_addr_count++] = dns_ip;
-    return 0;
-}
-
-
-#ifdef _WIN32
-
-int slirp_get_system_dns_servers()
-{
-    FIXED_INFO *FixedInfo=NULL;
-    ULONG    BufLen;
-    DWORD    ret;
-    IP_ADDR_STRING *pIPAddr;
-
-    if (dns_addr_count > 0)
-        return dns_addr_count;
-
-    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
-    BufLen = sizeof(FIXED_INFO);
-
-    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
-        if (FixedInfo) {
-            GlobalFree(FixedInfo);
-            FixedInfo = NULL;
-        }
-        FixedInfo = GlobalAlloc(GPTR, BufLen);
-    }
-
-    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
-        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
-        if (FixedInfo) {
-            GlobalFree(FixedInfo);
-            FixedInfo = NULL;
-        }
-        return -1;
-    }
-
-    D( "DNS Servers:");
-    pIPAddr = &(FixedInfo->DnsServerList);
-    while (pIPAddr && dns_addr_count < DNS_ADDR_MAX) {
-        uint32_t  ip;
-        D( "  %s", pIPAddr->IpAddress.String );
-        if (inet_strtoip(pIPAddr->IpAddress.String, &ip) == 0) {
-            if (ip == loopback_addr_ip)
-                ip = our_addr_ip;
-            if (dns_addr_count < DNS_ADDR_MAX)
-                dns_addr[dns_addr_count++] = ip;
-        }
-        pIPAddr = pIPAddr->Next;
-    }
-
-    if (FixedInfo) {
-        GlobalFree(FixedInfo);
-        FixedInfo = NULL;
-    }
-    if (dns_addr_count <= 0)
-        return -1;
-
-    return dns_addr_count;
-}
-
-#else
-
-int slirp_get_system_dns_servers(void)
-{
-    char buff[512];
-    char buff2[256];
-    FILE *f;
-
-    if (dns_addr_count > 0)
-        return dns_addr_count;
-
-#ifdef CONFIG_DARWIN
-    /* on Darwin /etc/resolv.conf is a symlink to /private/var/run/resolv.conf
-     * in some siutations, the symlink can be destroyed and the system will not
-     * re-create it. Darwin-aware applications will continue to run, but "legacy"
-     * Unix ones will not.
-     */
-     f = fopen("/private/var/run/resolv.conf", "r");
-     if (!f)
-        f = fopen("/etc/resolv.conf", "r");  /* desperate attempt to sanity */
-#else
-    f = fopen("/etc/resolv.conf", "r");
-#endif
-    if (!f)
-        return -1;
-
-    DN("emulator: IP address of your DNS(s): ");
-    while (fgets(buff, 512, f) != NULL) {
-        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
-            uint32_t  tmp_ip;
-
-            if (inet_strtoip(buff2, &tmp_ip) < 0)
-                continue;
-            if (tmp_ip == loopback_addr_ip)
-                tmp_ip = our_addr_ip;
-            if (dns_addr_count < DNS_ADDR_MAX) {
-                dns_addr[dns_addr_count++] = tmp_ip;
-                if (dns_addr_count > 1)
-                    DN(", ");
-                DN("%s", inet_iptostr(tmp_ip));
-            } else {
-                DN("(more)");
-                break;
-            }
-        }
-    }
-    DN("\n");
-    fclose(f);
-
-    if (!dns_addr_count)
-        return -1;
-
-    return dns_addr_count;
-}
-
-#endif
-
-extern void  slirp_init_shapers();
-
-void slirp_init(void)
-{
-#if DEBUG
-    int   slirp_logmask = 0;
-    char  slirp_logfile[512];
-    {
-        const char*  env = getenv( "ANDROID_SLIRP_LOGMASK" );
-        if (env != NULL)
-            slirp_logmask = atoi(env);
-         else if (VERBOSE_CHECK(slirp))
-            slirp_logmask = DEBUG_DEFAULT;
-    }
-
-    {
-        char*  p   = slirp_logfile;
-        char*  end = p + sizeof(slirp_logfile);
-
-        p = bufprint_temp_file( p, end, "slirp.log" );
-        if (p >= end) {
-            dprint( "cannot create slirp log file in temporary directory" );
-            slirp_logmask = 0;
-        }
-    }
-    if (slirp_logmask) {
-        dprint( "sending slirp logs with mask %x to %s", slirp_logmask, slirp_logfile );
-        debug_init( slirp_logfile, slirp_logmask );
-    }
-#endif
-
-    link_up = 1;
-
-    if_init();
-    ip_init();
-
-    /* Initialise mbufs *after* setting the MTU */
-    mbuf_init();
-
-    /* set default addresses */
-    inet_strtoip("127.0.0.1", &loopback_addr_ip);
-
-    if (dns_addr_count == 0) {
-        if (slirp_get_system_dns_servers() < 0) {
-            dns_addr[0]    = loopback_addr_ip;
-            dns_addr_count = 1;
-            fprintf (stderr, "Warning: No DNS servers found\n");
-        }
-    }
-
-    inet_strtoip(CTL_SPECIAL, &special_addr_ip);
-
-    alias_addr_ip = special_addr_ip | CTL_ALIAS;
-    getouraddr();
-
-    slirp_init_shapers();
-}
-
-#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
-
-/*
- * curtime kept to an accuracy of 1ms
- */
-#ifdef _WIN32
-static void updtime(void)
-{
-    struct _timeb tb;
-
-    _ftime(&tb);
-    curtime = (u_int)tb.time * (u_int)1000;
-    curtime += (u_int)tb.millitm;
-}
-#else
-static void updtime(void)
-{
-	gettimeofday(&tt, 0);
-
-	curtime = (u_int)tt.tv_sec * (u_int)1000;
-	curtime += (u_int)tt.tv_usec / (u_int)1000;
-
-	if ((tt.tv_usec % 1000) >= 500)
-	   curtime++;
-}
-#endif
-
-void slirp_select_fill(int *pnfds,
-                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
-{
-    struct socket *so, *so_next;
-    struct timeval timeout;
-    int nfds;
-    int tmp_time;
-
-    /* fail safe */
-    global_readfds = NULL;
-    global_writefds = NULL;
-    global_xfds = NULL;
-
-    nfds = *pnfds;
-    /*
-        * First, TCP sockets
-        */
-    do_slowtimo = 0;
-    if (link_up) {
-        /*
-            * *_slowtimo needs calling if there are IP fragments
-            * in the fragment queue, or there are TCP connections active
-            */
-        do_slowtimo = ((tcb.so_next != &tcb) ||
-                      (&ipq.ip_link != ipq.ip_link.next));
-
-        for (so = tcb.so_next; so != &tcb; so = so_next) {
-            so_next = so->so_next;
-
-               /*
-                * See if we need a tcp_fasttimo
-                */
-            if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
-                time_fasttimo = curtime; /* Flag when we want a fasttimo */
-
-               /*
-                * NOFDREF can include still connecting to local-host,
-                * newly socreated() sockets etc. Don't want to select these.
-                */
-            if (so->so_state & SS_NOFDREF || so->s == -1)
-                continue;
-
-                        /*
-                         * don't register proxified socked connections here
-                         */
-                         if ((so->so_state & SS_PROXIFIED) != 0)
-                            continue;
-
-               /*
-                * Set for reading sockets which are accepting
-                */
-            if (so->so_state & SS_FACCEPTCONN) {
-                                FD_SET(so->s, readfds);
-                UPD_NFDS(so->s);
-                continue;
-            }
-
-               /*
-                * Set for writing sockets which are connecting
-                */
-            if (so->so_state & SS_ISFCONNECTING) {
-                FD_SET(so->s, writefds);
-                UPD_NFDS(so->s);
-                continue;
-            }
-
-               /*
-                * Set for writing if we are connected, can send more, and
-                * we have something to send
-                */
-            if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
-                FD_SET(so->s, writefds);
-                UPD_NFDS(so->s);
-            }
-
-               /*
-                * Set for reading (and urgent data) if we are connected, can
-                * receive more, and we have room for it XXX /2 ?
-                */
-            if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
-                FD_SET(so->s, readfds);
-                FD_SET(so->s, xfds);
-                UPD_NFDS(so->s);
-            }
-        }
-
-        /*
-            * UDP sockets
-            */
-        for (so = udb.so_next; so != &udb; so = so_next) {
-            so_next = so->so_next;
-
-            if ((so->so_state & SS_PROXIFIED) != 0)
-                continue;
-
-               /*
-                * See if it's timed out
-                */
-            if (so->so_expire) {
-                if (so->so_expire <= curtime) {
-                    udp_detach(so);
-                    continue;
-                } else
-                    do_slowtimo = 1; /* Let socket expire */
-            }
-
-               /*
-                * When UDP packets are received from over the
-                * link, they're sendto()'d straight away, so
-                * no need for setting for writing
-                * Limit the number of packets queued by this session
-                * to 4.  Note that even though we try and limit this
-                * to 4 packets, the session could have more queued
-                * if the packets needed to be fragmented
-                * (XXX <= 4 ?)
-                */
-            if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
-                FD_SET(so->s, readfds);
-                UPD_NFDS(so->s);
-            }
-        }
-    }
-
-       /*
-        * Setup timeout to use minimum CPU usage, especially when idle
-        */
-
-       /*
-        * First, see the timeout needed by *timo
-        */
-    timeout.tv_sec = 0;
-    timeout.tv_usec = -1;
-    /*
-        * If a slowtimo is needed, set timeout to 500ms from the last
-        * slow timeout. If a fast timeout is needed, set timeout within
-        * 200ms of when it was requested.
-        */
-    if (do_slowtimo) {
-        /* XXX + 10000 because some select()'s aren't that accurate */
-        timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
-        if (timeout.tv_usec < 0)
-            timeout.tv_usec = 0;
-        else if (timeout.tv_usec > 510000)
-            timeout.tv_usec = 510000;
-
-        /* Can only fasttimo if we also slowtimo */
-        if (time_fasttimo) {
-            tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
-            if (tmp_time < 0)
-                tmp_time = 0;
-
-            /* Choose the smallest of the 2 */
-            if (tmp_time < timeout.tv_usec)
-                timeout.tv_usec = (u_int)tmp_time;
-        }
-    }
-
-        /*
-         * now, the proxified sockets
-         */
-        proxy_manager_select_fill(&nfds, readfds, writefds, xfds);
-
-        *pnfds = nfds;
-}
-
-void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
-{
-    struct socket *so, *so_next;
-    int ret;
-
-    global_readfds = readfds;
-    global_writefds = writefds;
-    global_xfds = xfds;
-
-	/* Update time */
-	updtime();
-
-	/*
-	 * See if anything has timed out
-	 */
-	if (link_up) {
-		if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
-			tcp_fasttimo();
-			time_fasttimo = 0;
-		}
-		if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
-			ip_slowtimo();
-			tcp_slowtimo();
-			last_slowtimo = curtime;
-		}
-	}
-
-	/*
-	 * Check sockets
-	 */
-	if (link_up) {
-		/*
-		 * Check TCP sockets
-		 */
-		for (so = tcb.so_next; so != &tcb; so = so_next) {
-			so_next = so->so_next;
-
-			/*
-			 * FD_ISSET is meaningless on these sockets
-			 * (and they can crash the program)
-			 */
-			if (so->so_state & SS_NOFDREF || so->s == -1)
-			   continue;
-
-                        /*
-                         * proxified sockets are polled later in this
-                         * function.
-                         */
-                        if ((so->so_state & SS_PROXIFIED) != 0)
-                            continue;
-
-			/*
-			 * Check for URG data
-			 * This will soread as well, so no need to
-			 * test for readfds below if this succeeds
-			 */
-			if (FD_ISSET(so->s, xfds))
-			   sorecvoob(so);
-			/*
-			 * Check sockets for reading
-			 */
-			else if (FD_ISSET(so->s, readfds)) {
-				/*
-				 * Check for incoming connections
-				 */
-				if (so->so_state & SS_FACCEPTCONN) {
-					tcp_connect(so);
-					continue;
-				} /* else */
-				ret = soread(so);
-
-				/* Output it if we read something */
-				if (ret > 0)
-				   tcp_output(sototcpcb(so));
-			}
-
-			/*
-			 * Check sockets for writing
-			 */
-			if (FD_ISSET(so->s, writefds)) {
-			  /*
-			   * Check for non-blocking, still-connecting sockets
-			   */
-			  if (so->so_state & SS_ISFCONNECTING) {
-			    /* Connected */
-			    so->so_state &= ~SS_ISFCONNECTING;
-
-			    ret = socket_send(so->s, (char*)&ret, 0);
-			    if (ret < 0) {
-			      /* XXXXX Must fix, zero bytes is a NOP */
-			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
-				  errno == EINPROGRESS || errno == ENOTCONN)
-				continue;
-
-			      /* else failed */
-			      so->so_state = SS_NOFDREF;
-			    }
-			    /* else so->so_state &= ~SS_ISFCONNECTING; */
-
-			    /*
-			     * Continue tcp_input
-			     */
-			    tcp_input((MBuf )NULL, sizeof(struct ip), so);
-			    /* continue; */
-			  } else
-			    ret = sowrite(so);
-			  /*
-			   * XXXXX If we wrote something (a lot), there
-			   * could be a need for a window update.
-			   * In the worst case, the remote will send
-			   * a window probe to get things going again
-			   */
-			}
-
-			/*
-			 * Probe a still-connecting, non-blocking socket
-			 * to check if it's still alive
-	 	 	 */
-#ifdef PROBE_CONN
-			if (so->so_state & SS_ISFCONNECTING) {
-			  ret = socket_recv(so->s, (char *)&ret, 0);
-
-			  if (ret < 0) {
-			    /* XXX */
-			    if (errno == EAGAIN || errno == EWOULDBLOCK ||
-				errno == EINPROGRESS || errno == ENOTCONN)
-			      continue; /* Still connecting, continue */
-
-			    /* else failed */
-			    so->so_state = SS_NOFDREF;
-
-			    /* tcp_input will take care of it */
-			  } else {
-			    ret = socket_send(so->s, &ret, 0,0);
-			    if (ret < 0) {
-			      /* XXX */
-			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
-				  errno == EINPROGRESS || errno == ENOTCONN)
-				continue;
-			      /* else failed */
-			      so->so_state = SS_NOFDREF;
-			    } else
-			      so->so_state &= ~SS_ISFCONNECTING;
-
-			  }
-			  tcp_input((MBuf )NULL, sizeof(struct ip),so);
-			} /* SS_ISFCONNECTING */
-#endif
-		}
-
-		/*
-		 * Now UDP sockets.
-		 * Incoming packets are sent straight away, they're not buffered.
-		 * Incoming UDP data isn't buffered either.
-		 */
-		for (so = udb.so_next; so != &udb; so = so_next) {
-			so_next = so->so_next;
-
-                        if ((so->so_state & SS_PROXIFIED) != 0)
-                            continue;
-
-			if (so->s != -1 && FD_ISSET(so->s, readfds)) {
-                            sorecvfrom(so);
-                        }
-		}
-	}
-
-        /*
-         * Now the proxified sockets
-         */
-        proxy_manager_poll(readfds, writefds, xfds);
-
-	/*
-	 * See if we can start outputting
-	 */
-	if (if_queued && link_up)
-	   if_start();
-
-	/* clear global file descriptor sets.
-	 * these reside on the stack in vl.c
-	 * so they're unusable if we're not in
-	 * slirp_select_fill or slirp_select_poll.
-	 */
-	 global_readfds = NULL;
-	 global_writefds = NULL;
-	 global_xfds = NULL;
-}
-
-#define ETH_ALEN 6
-#define ETH_HLEN 14
-
-#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
-#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
-
-#define	ARPOP_REQUEST	1		/* ARP request			*/
-#define	ARPOP_REPLY	2		/* ARP reply			*/
-
-struct ethhdr
-{
-	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
-	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
-	unsigned short	h_proto;		/* packet type ID field	*/
-};
-
-struct arphdr
-{
-	unsigned short	ar_hrd;		/* format of hardware address	*/
-	unsigned short	ar_pro;		/* format of protocol address	*/
-	unsigned char	ar_hln;		/* length of hardware address	*/
-	unsigned char	ar_pln;		/* length of protocol address	*/
-	unsigned short	ar_op;		/* ARP opcode (command)		*/
-
-	 /*
-	  *	 Ethernet looks like this : This bit is variable sized however...
-	  */
-	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
-	unsigned char		ar_sip[4];		/* sender IP address		*/
-	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
-	unsigned char		ar_tip[4];		/* target IP address		*/
-};
-
-void arp_input(const uint8_t *pkt, int pkt_len)
-{
-    struct ethhdr *eh = (struct ethhdr *)pkt;
-    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
-    uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
-    struct ethhdr *reh = (struct ethhdr *)arp_reply;
-    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
-    int ar_op;
-
-    ar_op = ntohs(ah->ar_op);
-    switch(ar_op) {
-        uint32_t   ar_tip_ip;
-    case ARPOP_REQUEST:
-        ar_tip_ip = (ah->ar_tip[0] << 24) | (ah->ar_tip[1] << 16) | (ah->ar_tip[2] << 8);
-        if (ar_tip_ip == special_addr_ip) {
-            if ( CTL_IS_DNS(ah->ar_tip[3]) || ah->ar_tip[3] == CTL_ALIAS)
-                goto arp_ok;
-            return;
-        arp_ok:
-            /* XXX: make an ARP request to have the client address */
-            memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
-
-            /* ARP request for alias/dns mac address */
-            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
-            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
-            reh->h_source[5] = ah->ar_tip[3];
-            reh->h_proto = htons(ETH_P_ARP);
-
-            rah->ar_hrd = htons(1);
-            rah->ar_pro = htons(ETH_P_IP);
-            rah->ar_hln = ETH_ALEN;
-            rah->ar_pln = 4;
-            rah->ar_op = htons(ARPOP_REPLY);
-            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
-            memcpy(rah->ar_sip, ah->ar_tip, 4);
-            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
-            memcpy(rah->ar_tip, ah->ar_sip, 4);
-            slirp_output(arp_reply, sizeof(arp_reply));
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-void slirp_input(const uint8_t *pkt, int pkt_len)
-{
-    MBuf m;
-    int proto;
-
-    if (pkt_len < ETH_HLEN)
-        return;
-
-    proto = ntohs(*(uint16_t *)(pkt + 12));
-    switch(proto) {
-    case ETH_P_ARP:
-        arp_input(pkt, pkt_len);
-        break;
-    case ETH_P_IP:
-        m = mbuf_alloc();
-        if (!m)
-            return;
-        /* Note: we add to align the IP header */
-        m->m_len = pkt_len + 2;
-        memcpy(m->m_data + 2, pkt, pkt_len);
-
-        m->m_data += 2 + ETH_HLEN;
-        m->m_len -= 2 + ETH_HLEN;
-
-        ip_input(m);
-        break;
-    default:
-        break;
-    }
-}
-
-/* output the IP packet to the ethernet device */
-void if_encap(const uint8_t *ip_data, int ip_data_len)
-{
-    uint8_t buf[1600];
-    struct ethhdr *eh = (struct ethhdr *)buf;
-
-    if (ip_data_len + ETH_HLEN > sizeof(buf))
-        return;
-
-    memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
-    memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
-    /* XXX: not correct */
-    eh->h_source[5] = CTL_ALIAS;
-    eh->h_proto = htons(ETH_P_IP);
-    memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
-    slirp_output(buf, ip_data_len + ETH_HLEN);
-}
-
-int slirp_redir(int is_udp, int host_port,
-                uint32_t  guest_ip, int guest_port)
-{
-    if (is_udp) {
-        if (!udp_listen(host_port,
-                        guest_ip,
-                        guest_port, 0))
-            return -1;
-    } else {
-        if (!solisten(host_port, guest_ip, guest_port, 0))
-            return -1;
-    }
-    return 0;
-}
-
-int  slirp_unredir(int  is_udp, int  host_port)
-{
-    if (is_udp)
-        return udp_unlisten( host_port );
-    else
-        return sounlisten( host_port );
-}
-
diff --git a/sockets.c b/sockets.c
index 338b176..839b94f 100644
--- a/sockets.c
+++ b/sockets.c
@@ -31,7 +31,14 @@
 #  include <sys/socket.h>
 #  include <netinet/in.h>
 #  include <netinet/tcp.h>
-#  include <netdb.h>
+#  ifdef __linux__ /* Recent versions of glibc only define EAI_NODATA, which is an
+                      extension to the POSIX standard, if __USE_GNU is defined. */
+#    define __USE_GNU
+#    include <netdb.h>
+#    undef __USE_GNU
+#  else /* !__linux__ */
+#    include <netdb.h>
+#  endif /* !__linux__ */
 #  if HAVE_UNIX_SOCKETS
 #    include <sys/un.h>
 #    ifndef UNIX_PATH_MAX
@@ -196,7 +203,7 @@
     switch (type) {
         case SOCKET_DGRAM:  return SOCK_DGRAM;
         case SOCKET_STREAM: return SOCK_STREAM;
-        default: return -1;
+        default: return 0;
     }
 }
 
@@ -206,7 +213,7 @@
     switch (type) {
         case SOCK_DGRAM:  return SOCKET_DGRAM;
         case SOCK_STREAM: return SOCKET_STREAM;
-        default:          return (SocketType) -1;
+        default:          return (SocketType) SOCKET_UNSPEC;
     }
 }
 
@@ -718,6 +725,146 @@
     return ret;
 }
 
+/* The Winsock headers for mingw lack some definitions */
+#ifndef AI_ADDRCONFIG
+#  define  AI_ADDRCONFIG  0
+#endif
+
+SockAddress**
+sock_address_list_create( const char*  hostname,
+                          const char*  port,
+                          unsigned     flags )
+{
+    SockAddress**    list = NULL;
+    SockAddress*     addr;
+    int              nn, count, ret;
+    struct addrinfo  ai, *res, *e;
+
+    memset(&ai, 0, sizeof(ai));
+    ai.ai_flags   |= AI_ADDRCONFIG;
+    ai.ai_family   = PF_UNSPEC;
+
+    if (flags & SOCKET_LIST_FORCE_INET)
+        ai.ai_family = PF_INET;
+    else if (flags & SOCKET_LIST_FORCE_IN6)
+        ai.ai_family = PF_INET6;
+
+    if (flags & SOCKET_LIST_PASSIVE)
+        ai.ai_flags |= AI_PASSIVE;
+    else
+        ai.ai_flags |= AI_CANONNAME;
+
+    while (1) {
+        struct addrinfo  hints = ai;
+
+        ret = getaddrinfo(hostname, port, &hints, &res);
+        if (ret == 0)
+            break;
+
+        switch (ret) {
+#ifdef EAI_ADDRFAMILY		
+        case EAI_ADDRFAMILY: 
+#endif		
+        case EAI_NODATA:
+            _set_errno(ENOENT);
+            break;
+        case EAI_FAMILY:
+            _set_errno(EAFNOSUPPORT);
+            break;
+        case EAI_AGAIN:
+            _set_errno(EAGAIN);
+            break;
+#ifdef EAI_SYSTEM			
+        case EAI_SYSTEM:
+            if (errno == EINTR)
+                continue;
+            break;
+#endif			
+        default:
+            _set_errno(EINVAL);
+        }
+        return NULL;
+    }
+
+    /* allocate result list */
+    for (count = 0, e = res; e != NULL; e = e->ai_next)
+        count += 1;
+
+    list = (SockAddress**) qemu_malloc((count+1)*sizeof(SockAddress*));
+    addr = (SockAddress*)  qemu_malloc(count*sizeof(SockAddress));
+
+    for (nn = 0, e = res; e != NULL; e = e->ai_next) {
+
+        ret = sock_address_from_bsd(addr, e->ai_addr, e->ai_addrlen);
+        if (ret < 0)
+            continue;
+
+        list[nn++] = addr++;
+    }
+    list[nn] = NULL;
+    freeaddrinfo(res);
+    return list;
+}
+
+void
+sock_address_list_free( SockAddress**  list )
+{
+    int  nn;
+    SockAddress*  addr;
+
+    if (list == NULL)
+        return;
+
+    addr = list[0];
+    for (nn = 0; list[nn] != NULL; nn++) {
+        sock_address_done(list[nn]);
+        list[nn] = NULL;
+    }
+    qemu_free(addr);
+    qemu_free(list);
+}
+
+int
+sock_address_get_numeric_info( SockAddress*  a,
+                               char*         host,
+                               size_t        hostlen,
+                               char*         serv,
+                               size_t        servlen )
+{
+    struct sockaddr*  saddr;
+    socklen_t         slen;
+    int               ret;
+
+    switch (a->family) {
+    case SOCKET_INET:
+        saddr = (struct sockaddr*) &a->u.inet.address;
+        slen  = sizeof(a->u.inet.address);
+        break;
+
+#if HAVE_IN6_SOCKET
+    case SOCKET_IN6:
+        saddr = (struct sockaddr*) &a->u.in6.address;
+        slen  = sizeof(a->u.in6.address);
+        break;
+#endif
+    default:
+        return _set_errno(EINVAL);
+    }
+
+    ret = getnameinfo( saddr, slen, host, hostlen, serv, servlen,
+                       NI_NUMERICHOST | NI_NUMERICSERV );
+
+    switch (ret) {
+    case 0:
+        break;
+    case EAI_AGAIN:
+        ret = EAGAIN;
+        break;
+    default:
+        ret = EINVAL;
+    }
+    return ret;
+}
 
 int
 socket_create( SocketFamily  family, SocketType  type )
@@ -872,6 +1019,20 @@
 }
 
 int
+socket_get_peer_address( int  fd, SockAddress*  address )
+{
+    struct sockaddr   addr;
+    socklen_t         addrlen = sizeof(addr);
+    int               ret;
+
+    QSOCKET_CALL(ret, getpeername(fd, &addr, &addrlen));
+    if (ret < 0)
+        return _fix_errno();
+
+    return sock_address_from_bsd(address, &addr, addrlen);
+}
+
+int
 socket_listen( int  fd, int  backlog )
 {
     SOCKET_CALL(listen(fd, backlog));
@@ -897,13 +1058,31 @@
     return ret;
 }
 
+static int
+socket_getoption(int  fd, int  domain, int  option, int  defaut)
+{
+    int  ret;
+    while (1) {
+#ifdef _WIN32
+        DWORD opt = (DWORD)-1;
+#else
+        int  opt  = -1;
+#endif
+        size_t  optlen = sizeof(opt);
+        ret = getsockopt(fd, domain, option, (char*)&opt, &optlen);
+        if (ret == 0)
+            return (int)opt;
+        if (errno != EINTR)
+            return defaut;
+    }
+#undef OPT_CAST	
+}
+
+
 SocketType socket_get_type(int fd)
 {
-    int  opt    = -1;
-    int  optlen = sizeof(opt);
-    getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&opt, (void*)&optlen );
-
-    return socket_type_from_bsd(opt);
+    int   so_type = socket_getoption(fd, SOL_SOCKET, SO_TYPE, -1);
+    return socket_type_from_bsd(so_type);
 }
 
 int socket_set_nonblock(int fd)
@@ -939,7 +1118,6 @@
     return setsockopt( fd, domain, option, (const char*)&flag, sizeof(flag) );
 }
 
-
 int socket_set_xreuseaddr(int  fd)
 {
 #ifdef _WIN32
@@ -966,6 +1144,23 @@
     return socket_setoption(fd, IPPROTO_TCP, TCP_NODELAY, 1);
 }
 
+int socket_set_ipv6only(int  fd)
+{
+/* IPV6_ONLY is only supported since Vista on Windows,
+ * and the Mingw headers lack its definition anyway.
+ */
+#if defined(_WIN32) && !defined(IPV6_V6ONLY)
+	return 0;
+#else
+    return socket_setoption(fd, IPPROTO_IPV6, IPV6_V6ONLY, 1);
+#endif	
+}
+
+
+int socket_get_error(int fd)
+{
+    return socket_getoption(fd, SOL_SOCKET, SO_ERROR, -1);
+}
 
 #ifdef _WIN32
 #include <stdlib.h>
diff --git a/sockets.h b/sockets.h
index 0dd06e2..12153e5 100644
--- a/sockets.h
+++ b/sockets.h
@@ -56,6 +56,9 @@
 #  ifndef ENOPROTOOPT
 #    define ENOPROTOOPT  10042
 #  endif
+#  ifndef EAFNOSUPPORT
+#    define EAFNOSUPPORT 10047
+#  endif
 #  ifndef EADDRINUSE
 #    define EADDRINUSE   10048
 #  endif
@@ -212,6 +215,12 @@
 /* return a static string describing the address */
 const char*  sock_address_to_string( const SockAddress*  a );
 
+static __inline__
+SocketFamily  sock_address_get_family( const SockAddress*  a )
+{
+    return a->family;
+}
+
 /* return the port number of a given socket address, or -1 if it's a Unix one */
 int   sock_address_get_port( const SockAddress*  a );
 
@@ -241,6 +250,40 @@
                                  uint16_t      port,
                                  int           preferIn6 );
 
+int  sock_address_get_numeric_info( SockAddress*  a,
+                                    char*         host,
+                                    size_t        hostlen,
+                                    char*         serv,
+                                    size_t        servlen );
+
+/* Support for listing all socket addresses of a given host */
+enum {
+    SOCKET_LIST_PASSIVE    = (1 << 0),
+    SOCKET_LIST_FORCE_INET = (1 << 1),
+    SOCKET_LIST_FORCE_IN6  = (1 << 2)
+};
+
+/* resolve a host and service/port name into a list of SockAddress objects.
+ * returns a NULL-terminated array of SockAddress pointers on success,
+ * or NULL in case of failure, with the value of errno set to one of the
+ * following:
+ *
+ *    EINVAL    : invalid argument
+ *    EHOSTDOWN : could not reach DNS server
+ *    ENOENT    : no host with this name, or host doesn't have IP address
+ *    ENOMEM    : not enough memory to perform request
+ *
+ * other system-level errors can also be set depending on the host sockets
+ * implementation.
+ *
+ * This function loops on EINTR so the caller shouldn't have to check for it.
+ */
+SockAddress**  sock_address_list_create( const char*  hostname,
+                                         const char*  port,
+                                         unsigned     flags );
+
+void sock_address_list_free( SockAddress**  list );
+
 /* create a new socket, return the socket number of -1 on failure */
 int  socket_create( SocketFamily  family, SocketType  type );
 
@@ -281,6 +324,12 @@
 /* send OOB data inline for this socket */
 int  socket_set_oobinline(int  fd);
 
+/* force listening to IPv6 interfaces only */
+int  socket_set_ipv6only(int  fd);
+
+/* retrieve last socket error code */
+int  socket_get_error(int  fd);
+
 /* close an opened socket. Note that this is unlike the Unix 'close' because:
  * - it will properly shutdown the socket in the background
  * - it does not modify errno
@@ -299,6 +348,7 @@
 int   socket_connect( int  fd, const SockAddress*  address );
 int   socket_bind( int  fd, const SockAddress*  address );
 int   socket_get_address( int  fd, SockAddress*  address );
+int   socket_get_peer_address( int  fd, SockAddress*  address );
 int   socket_listen( int  fd, int  backlog );
 int   socket_accept( int  fd, SockAddress*  address );
 
diff --git a/softmmu-semi.h b/softmmu-semi.h
index 8bf96f4..79278cc 100644
--- a/softmmu-semi.h
+++ b/softmmu-semi.h
@@ -37,7 +37,7 @@
 static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
                                int copy)
 {
-    char *p;
+    uint8_t *p;
     /* TODO: Make this something that isn't fixed size.  */
     p = malloc(len);
     if (copy)
diff --git a/softmmu_exec.h b/softmmu_exec.h
index 9cc4535..a43e621 100644
--- a/softmmu_exec.h
+++ b/softmmu_exec.h
@@ -60,6 +60,7 @@
 #include "softmmu_header.h"
 #undef ACCESS_TYPE
 #undef MEMSUFFIX
+#endif /* (NB_MMU_MODES >= 3) */
 
 #if (NB_MMU_MODES >= 4)
 
@@ -78,12 +79,30 @@
 #include "softmmu_header.h"
 #undef ACCESS_TYPE
 #undef MEMSUFFIX
+#endif /* (NB_MMU_MODES >= 4) */
 
-#if (NB_MMU_MODES > 4)
-#error "NB_MMU_MODES > 4 is not supported for now"
-#endif /* (NB_MMU_MODES > 4) */
-#endif /* (NB_MMU_MODES == 4) */
-#endif /* (NB_MMU_MODES >= 3) */
+#if (NB_MMU_MODES >= 5)
+
+#define ACCESS_TYPE 4
+#define MEMSUFFIX MMU_MODE4_SUFFIX
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+#endif /* (NB_MMU_MODES >= 5) */
+
+#if (NB_MMU_MODES > 5)
+#error "NB_MMU_MODES > 5 is not supported for now"
+#endif /* (NB_MMU_MODES > 5) */
 
 /* these access are slower, they must be as rare as possible */
 #define ACCESS_TYPE (NB_MMU_MODES)
diff --git a/softmmu_header.h b/softmmu_header.h
index 9649717..a1b3808 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #if DATA_SIZE == 8
 #define SUFFIX q
diff --git a/softmmu_template.h b/softmmu_template.h
index 98dd378..4b33aef 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #define DATA_SIZE (1 << SHIFT)
 
@@ -64,6 +64,7 @@
         cpu_io_recompile(env, retaddr);
     }
 
+    env->mem_io_vaddr = addr;
 #if SHIFT <= 2
     res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
 #else
@@ -75,7 +76,7 @@
     res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32;
 #endif
 #endif /* SHIFT > 2 */
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     env->last_io_time = cpu_get_time_fast();
 #endif
     return res;
@@ -220,7 +221,7 @@
     io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
 #endif
 #endif /* SHIFT > 2 */
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     env->last_io_time = cpu_get_time_fast();
 #endif
 }
diff --git a/sys-queue.h b/sys-queue.h
new file mode 100644
index 0000000..cb6a4c8
--- /dev/null
+++ b/sys-queue.h
@@ -0,0 +1,343 @@
+/*      $NetBSD: queue.h,v 1.45.14.1 2007/07/18 20:13:24 liamjfoy Exp $ */
+
+/*
+ * Qemu version: Copy from netbsd, removed debug code, removed some of
+ * the implementations.  Left in lists, tail queues and circular queues.
+ */
+
+/*
+ * Copyright (c) 1991, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)queue.h     8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines three types of data structures:
+ * lists, tail queues, and circular queues.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)                                           \
+struct name {                                                           \
+        struct type *lh_first;  /* first element */                     \
+}
+
+#define LIST_HEAD_INITIALIZER(head)                                     \
+        { NULL }
+
+#define LIST_ENTRY(type)                                                \
+struct {                                                                \
+        struct type *le_next;   /* next element */                      \
+        struct type **le_prev;  /* address of previous next element */  \
+}
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do {                                            \
+        (head)->lh_first = NULL;                                        \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {                     \
+        if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
+                (listelm)->field.le_next->field.le_prev =               \
+                    &(elm)->field.le_next;                              \
+        (listelm)->field.le_next = (elm);                               \
+        (elm)->field.le_prev = &(listelm)->field.le_next;               \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do {                    \
+        (elm)->field.le_prev = (listelm)->field.le_prev;                \
+        (elm)->field.le_next = (listelm);                               \
+        *(listelm)->field.le_prev = (elm);                              \
+        (listelm)->field.le_prev = &(elm)->field.le_next;               \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {                         \
+        if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
+                (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+        (head)->lh_first = (elm);                                       \
+        (elm)->field.le_prev = &(head)->lh_first;                       \
+} while (/*CONSTCOND*/0)
+
+#define LIST_REMOVE(elm, field) do {                                    \
+        if ((elm)->field.le_next != NULL)                               \
+                (elm)->field.le_next->field.le_prev =                   \
+                    (elm)->field.le_prev;                               \
+        *(elm)->field.le_prev = (elm)->field.le_next;                   \
+} while (/*CONSTCOND*/0)
+
+#define LIST_FOREACH(var, head, field)                                  \
+        for ((var) = ((head)->lh_first);                                \
+                (var);                                                  \
+                (var) = ((var)->field.le_next))
+
+/*
+ * List access methods.
+ */
+#define LIST_EMPTY(head)                ((head)->lh_first == NULL)
+#define LIST_FIRST(head)                ((head)->lh_first)
+#define LIST_NEXT(elm, field)           ((elm)->field.le_next)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define _TAILQ_HEAD(name, type, qual)                                   \
+struct name {                                                           \
+        qual type *tqh_first;           /* first element */             \
+        qual type *qual *tqh_last;      /* addr of last next element */ \
+}
+#define TAILQ_HEAD(name, type)  _TAILQ_HEAD(name, struct type,)
+
+#define TAILQ_HEAD_INITIALIZER(head)                                    \
+        { NULL, &(head).tqh_first }
+
+#define _TAILQ_ENTRY(type, qual)                                        \
+struct {                                                                \
+        qual type *tqe_next;            /* next element */              \
+        qual type *qual *tqe_prev;      /* address of previous next element */\
+}
+#define TAILQ_ENTRY(type)       _TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do {                                           \
+        (head)->tqh_first = NULL;                                       \
+        (head)->tqh_last = &(head)->tqh_first;                          \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {                        \
+        if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+                (head)->tqh_first->field.tqe_prev =                     \
+                    &(elm)->field.tqe_next;                             \
+        else                                                            \
+                (head)->tqh_last = &(elm)->field.tqe_next;              \
+        (head)->tqh_first = (elm);                                      \
+        (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {                        \
+        (elm)->field.tqe_next = NULL;                                   \
+        (elm)->field.tqe_prev = (head)->tqh_last;                       \
+        *(head)->tqh_last = (elm);                                      \
+        (head)->tqh_last = &(elm)->field.tqe_next;                      \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {              \
+        if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+                (elm)->field.tqe_next->field.tqe_prev =                 \
+                    &(elm)->field.tqe_next;                             \
+        else                                                            \
+                (head)->tqh_last = &(elm)->field.tqe_next;              \
+        (listelm)->field.tqe_next = (elm);                              \
+        (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do {                   \
+        (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
+        (elm)->field.tqe_next = (listelm);                              \
+        *(listelm)->field.tqe_prev = (elm);                             \
+        (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_REMOVE(head, elm, field) do {                             \
+        if (((elm)->field.tqe_next) != NULL)                            \
+                (elm)->field.tqe_next->field.tqe_prev =                 \
+                    (elm)->field.tqe_prev;                              \
+        else                                                            \
+                (head)->tqh_last = (elm)->field.tqe_prev;               \
+        *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_FOREACH(var, head, field)                                 \
+        for ((var) = ((head)->tqh_first);                               \
+                (var);                                                  \
+                (var) = ((var)->field.tqe_next))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, next_var)                  \
+        for ((var) = ((head)->tqh_first);                               \
+                (var) && ((next_var) = ((var)->field.tqe_next), 1);     \
+                (var) = (next_var))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field)               \
+        for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));    \
+                (var);                                                  \
+                (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+
+/*
+ * Tail queue access methods.
+ */
+#define TAILQ_EMPTY(head)               ((head)->tqh_first == NULL)
+#define TAILQ_FIRST(head)               ((head)->tqh_first)
+#define TAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
+
+#define TAILQ_LAST(head, headname) \
+        (*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define TAILQ_PREV(elm, headname, field) \
+        (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)                                        \
+struct name {                                                           \
+        struct type *cqh_first;         /* first element */             \
+        struct type *cqh_last;          /* last element */              \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head)                                  \
+        { (void *)&head, (void *)&head }
+
+#define CIRCLEQ_ENTRY(type)                                             \
+struct {                                                                \
+        struct type *cqe_next;          /* next element */              \
+        struct type *cqe_prev;          /* previous element */          \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do {                                         \
+        (head)->cqh_first = (void *)(head);                             \
+        (head)->cqh_last = (void *)(head);                              \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {            \
+        (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+        (elm)->field.cqe_prev = (listelm);                              \
+        if ((listelm)->field.cqe_next == (void *)(head))                \
+                (head)->cqh_last = (elm);                               \
+        else                                                            \
+                (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+        (listelm)->field.cqe_next = (elm);                              \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {           \
+        (elm)->field.cqe_next = (listelm);                              \
+        (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+        if ((listelm)->field.cqe_prev == (void *)(head))                \
+                (head)->cqh_first = (elm);                              \
+        else                                                            \
+                (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+        (listelm)->field.cqe_prev = (elm);                              \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                      \
+        (elm)->field.cqe_next = (head)->cqh_first;                      \
+        (elm)->field.cqe_prev = (void *)(head);                         \
+        if ((head)->cqh_last == (void *)(head))                         \
+                (head)->cqh_last = (elm);                               \
+        else                                                            \
+                (head)->cqh_first->field.cqe_prev = (elm);              \
+        (head)->cqh_first = (elm);                                      \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                      \
+        (elm)->field.cqe_next = (void *)(head);                         \
+        (elm)->field.cqe_prev = (head)->cqh_last;                       \
+        if ((head)->cqh_first == (void *)(head))                        \
+                (head)->cqh_first = (elm);                              \
+        else                                                            \
+                (head)->cqh_last->field.cqe_next = (elm);               \
+        (head)->cqh_last = (elm);                                       \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do {                           \
+        if ((elm)->field.cqe_next == (void *)(head))                    \
+                (head)->cqh_last = (elm)->field.cqe_prev;               \
+        else                                                            \
+                (elm)->field.cqe_next->field.cqe_prev =                 \
+                    (elm)->field.cqe_prev;                              \
+        if ((elm)->field.cqe_prev == (void *)(head))                    \
+                (head)->cqh_first = (elm)->field.cqe_next;              \
+        else                                                            \
+                (elm)->field.cqe_prev->field.cqe_next =                 \
+                    (elm)->field.cqe_next;                              \
+} while (/*CONSTCOND*/0)
+
+#define CIRCLEQ_FOREACH(var, head, field)                               \
+        for ((var) = ((head)->cqh_first);                               \
+                (var) != (const void *)(head);                          \
+                (var) = ((var)->field.cqe_next))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field)                       \
+        for ((var) = ((head)->cqh_last);                                \
+                (var) != (const void *)(head);                          \
+                (var) = ((var)->field.cqe_prev))
+
+/*
+ * Circular queue access methods.
+ */
+#define CIRCLEQ_EMPTY(head)             ((head)->cqh_first == (void *)(head))
+#define CIRCLEQ_FIRST(head)             ((head)->cqh_first)
+#define CIRCLEQ_LAST(head)              ((head)->cqh_last)
+#define CIRCLEQ_NEXT(elm, field)        ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field)        ((elm)->field.cqe_prev)
+
+#define CIRCLEQ_LOOP_NEXT(head, elm, field)                             \
+        (((elm)->field.cqe_next == (void *)(head))                      \
+            ? ((head)->cqh_first)                                       \
+            : (elm->field.cqe_next))
+#define CIRCLEQ_LOOP_PREV(head, elm, field)                             \
+        (((elm)->field.cqe_prev == (void *)(head))                      \
+            ? ((head)->cqh_last)                                        \
+            : (elm->field.cqe_prev))
+
+#endif  /* !_SYS_QUEUE_H_ */
diff --git a/sysemu.h b/sysemu.h
index eb9ddd3..fe24415 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -2,27 +2,39 @@
 #define SYSEMU_H
 /* Misc. things related to the system emulator.  */
 
+#include "qemu-common.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
 /* vl.c */
 extern const char *bios_name;
-extern const char *bios_dir;
+
+#define QEMU_FILE_TYPE_BIOS   0
+#define QEMU_FILE_TYPE_KEYMAP 1
+char *qemu_find_file(int type, const char *name);
 
 extern int vm_running;
 extern const char *qemu_name;
+extern uint8_t qemu_uuid[];
+int qemu_uuid_parse(const char *str, uint8_t *uuid);
+#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
 
 typedef struct vm_change_state_entry VMChangeStateEntry;
-typedef void VMChangeStateHandler(void *opaque, int running);
-typedef void VMStopHandler(void *opaque, int reason);
+typedef void VMChangeStateHandler(void *opaque, int running, int reason);
 
 VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
                                                      void *opaque);
 void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
 
-int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque);
-void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque);
-
 void vm_start(void);
 void vm_stop(int reason);
 
+uint64_t ram_bytes_remaining(void);
+uint64_t ram_bytes_transferred(void);
+uint64_t ram_bytes_total(void);
+
 int64_t cpu_get_ticks(void);
 void cpu_enable_ticks(void);
 void cpu_disable_ticks(void);
@@ -33,21 +45,32 @@
 int qemu_shutdown_requested(void);
 int qemu_reset_requested(void);
 int qemu_powerdown_requested(void);
+#ifdef NEED_CPU_H
 #if !defined(TARGET_SPARC) && !defined(TARGET_I386)
 // Please implement a power failure function to signal the OS
 #define qemu_system_powerdown() do{}while(0)
 #else
 void qemu_system_powerdown(void);
 #endif
+#endif
 void qemu_system_reset(void);
 
-void do_savevm(const char *name);
-void do_loadvm(const char *name);
-void do_delvm(const char *name);
-void do_info_snapshots(void);
+void do_savevm(Monitor *mon, const char *name);
+void do_loadvm(Monitor *mon, const char *name);
+void do_delvm(Monitor *mon, const char *name);
+void do_info_snapshots(Monitor *mon);
+
+void qemu_announce_self(void);
 
 void main_loop_wait(int timeout);
 
+int qemu_savevm_state_begin(QEMUFile *f);
+int qemu_savevm_state_iterate(QEMUFile *f);
+int qemu_savevm_state_complete(QEMUFile *f);
+int qemu_savevm_state(QEMUFile *f);
+int qemu_loadvm_state(QEMUFile *f);
+
+#ifdef _WIN32
 /* Polling handling */
 
 /* return TRUE if no sleep should be done afterwards */
@@ -56,7 +79,6 @@
 int qemu_add_polling_cb(PollingFunc *func, void *opaque);
 void qemu_del_polling_cb(PollingFunc *func, void *opaque);
 
-#ifdef _WIN32
 /* Wait objects handling */
 typedef void WaitObjectFunc(void *opaque);
 
@@ -65,62 +87,82 @@
 #endif
 
 /* TAP win32 */
-int tap_win32_init(VLANState *vlan, const char *ifname);
+int tap_win32_init(VLANState *vlan, const char *model,
+                   const char *name, const char *ifname);
 
 /* SLIRP */
-void do_info_slirp(void);
+void do_info_slirp(Monitor *mon);
+
+typedef enum DisplayType
+{
+    DT_DEFAULT,
+    DT_CURSES,
+    DT_SDL,
+    DT_VNC,
+    DT_NOGRAPHIC,
+} DisplayType;
 
 extern int bios_size;
 extern int cirrus_vga_enabled;
+extern int std_vga_enabled;
 extern int vmsvga_enabled;
+extern int xenfb_enabled;
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
+extern DisplayType display_type;
 extern const char *keyboard_layout;
 extern int win2k_install_hack;
+extern int rtc_td_hack;
 extern int alt_grab;
 extern int usb_enabled;
+extern int no_virtio_balloon;
 extern int smp_cpus;
 extern int cursor_hide;
 extern int graphic_rotate;
 extern int no_quit;
 extern int semihosting_enabled;
-extern int autostart;
 extern int old_param;
-extern const char *bootp_filename;
 
-
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
 extern int kqemu_allowed;
 #endif
 
+#define MAX_NODES 64
+extern int nb_numa_nodes;
+extern uint64_t node_mem[MAX_NODES];
+
 #define MAX_OPTION_ROMS 16
 extern const char *option_rom[MAX_OPTION_ROMS];
 extern int nb_option_roms;
 
-#ifdef TARGET_SPARC
+#ifdef NEED_CPU_H
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
 #define MAX_PROM_ENVS 128
 extern const char *prom_envs[MAX_PROM_ENVS];
 extern unsigned int nb_prom_envs;
 #endif
-
-#if defined (TARGET_PPC)
-#define BIOS_SIZE (1024 * 1024)
-#elif defined (TARGET_SPARC64)
-#define BIOS_SIZE ((512 + 32) * 1024)
-#elif defined(TARGET_MIPS)
-#define BIOS_SIZE (4 * 1024 * 1024)
 #endif
 
 typedef enum {
-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
+    IF_COUNT
 } BlockInterfaceType;
 
+typedef enum {
+    BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC,
+    BLOCK_ERR_STOP_ANY
+} BlockInterfaceErrorAction;
+
 typedef struct DriveInfo {
     BlockDriverState *bdrv;
     BlockInterfaceType type;
     int bus;
     int unit;
+    int used;
+    int drive_opt_idx;
+    BlockInterfaceErrorAction onerror;
+    char serial[21];
 } DriveInfo;
 
 #define MAX_IDE_DEVS	2
@@ -132,10 +174,47 @@
 
 extern int drive_get_index(BlockInterfaceType type, int bus, int unit);
 extern int drive_get_max_bus(BlockInterfaceType type);
+extern void drive_uninit(BlockDriverState *bdrv);
+extern void drive_remove(int index);
+extern const char *drive_get_serial(BlockDriverState *bdrv);
+extern BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv);
+
+BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type);
+
+struct drive_opt {
+    const char *file;
+    char opt[1024];
+    int used;
+};
+
+extern struct drive_opt drives_opt[MAX_DRIVES];
+extern int nb_drives_opt;
+
+extern int drive_add(const char *file, const char *fmt, ...);
+extern int drive_init(struct drive_opt *arg, int snapshot, void *machine);
+
+/* acpi */
+void qemu_system_hot_add_init(void);
+void qemu_system_device_hot_add(int pcibus, int slot, int state);
+
+/* device-hotplug */
+
+typedef int (dev_match_fn)(void *dev_private, void *arg);
+
+int add_init_drive(const char *opts);
+void destroy_nic(dev_match_fn *match_fn, void *arg);
+void destroy_bdrvs(dev_match_fn *match_fn, void *arg);
+
+/* pci-hotplug */
+void pci_device_hot_add(Monitor *mon, const char *pci_addr, const char *type,
+                        const char *opts);
+void drive_hot_add(Monitor *mon, const char *pci_addr, const char *opts);
+void pci_device_hot_remove(Monitor *mon, const char *pci_addr);
+void pci_device_hot_remove_success(int pcibus, int slot);
 
 /* serial ports */
 
-#define MAX_SERIAL_PORTS 8
+#define MAX_SERIAL_PORTS 4
 
 extern CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 
@@ -145,15 +224,24 @@
 
 extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 
+/* virtio consoles */
+
+#define MAX_VIRTIO_CONSOLES 1
+
+extern CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
+
+#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
+
 #ifdef NEED_CPU_H
 /* loader.c */
 int get_image_size(const char *filename);
 int load_image(const char *filename, uint8_t *addr); /* deprecated */
 int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
-int load_elf(const char *filename, int64_t virt_to_phys_addend,
+int load_elf(const char *filename, int64_t address_offset,
              uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr);
 int load_aout(const char *filename, target_phys_addr_t addr, int max_sz);
-int load_uboot(const char *filename, target_ulong *ep, int *is_linux);
+int load_uimage(const char *filename, target_ulong *ep, target_ulong *loadaddr,
+                int *is_linux);
 
 int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
 int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
@@ -169,16 +257,23 @@
     int enabled;
     int isa;
     union {
-        int (*init_isa) (AudioState *s, qemu_irq *pic);
-        int (*init_pci) (PCIBus *bus, AudioState *s);
+        int (*init_isa) (qemu_irq *pic);
+        int (*init_pci) (PCIBus *bus);
     } init;
 };
 
 extern struct soundhw soundhw[];
 #endif
 
-void do_usb_add(const char *devname);
-void do_usb_del(const char *devname);
-void usb_info(void);
+void do_usb_add(Monitor *mon, const char *devname);
+void do_usb_del(Monitor *mon, const char *devname);
+void usb_info(Monitor *mon);
+
+int get_param_value(char *buf, int buf_size,
+                    const char *tag, const char *str);
+int check_params(char *buf, int buf_size,
+                 const char * const *params, const char *str);
+
+void register_devices(void);
 
 #endif
diff --git a/tap-win32.c b/tap-win32.c
index b4b61d0..ba93355 100644
--- a/tap-win32.c
+++ b/tap-win32.c
@@ -24,10 +24,12 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program (see the file COPYING included with this
  *  distribution); if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
+#include "qemu-common.h"
+#include "net.h"
+#include "sysemu.h"
 #include <stdio.h>
-#include <stdint.h>
 #include <windows.h>
 
 /* NOTE: PCIBus is redefined in winddk.h */
@@ -74,7 +76,7 @@
 // Compile time configuration
 //======================
 
-//#define DEBUG_TAP_WIN32 1
+//#define DEBUG_TAP_WIN32
 
 #define TUN_ASYNCHRONOUS_WRITES 1
 
@@ -97,6 +99,7 @@
     HANDLE write_event;
     HANDLE output_queue_semaphore;
     HANDLE free_list_semaphore;
+    HANDLE tap_semaphore;
     CRITICAL_SECTION output_queue_cs;
     CRITICAL_SECTION free_list_cs;
     OVERLAPPED read_overlapped;
@@ -109,7 +112,7 @@
 
 static tap_win32_overlapped_t tap_overlapped;
 
-static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped) 
+static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped)
 {
     tun_buffer_t* buffer = NULL;
     WaitForSingleObject(overlapped->free_list_semaphore, INFINITE);
@@ -131,18 +134,18 @@
     ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL);
 }
 
-static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block) 
+static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block)
 {
     tun_buffer_t* buffer = NULL;
     DWORD result, timeout = block ? INFINITE : 0L;
 
     // Non-blocking call
-    result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout); 
+    result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout);
 
-    switch (result) 
-    { 
+    switch (result)
+    {
         // The semaphore object was signaled.
-        case WAIT_OBJECT_0: 
+        case WAIT_OBJECT_0:
             EnterCriticalSection(&overlapped->output_queue_cs);
 
             buffer = overlapped->output_queue_front;
@@ -153,18 +156,18 @@
             }
 
             LeaveCriticalSection(&overlapped->output_queue_cs);
-            break; 
+            break;
 
         // Semaphore was nonsignaled, so a time-out occurred.
-        case WAIT_TIMEOUT: 
+        case WAIT_TIMEOUT:
             // Cannot open another window.
-            break; 
+            break;
     }
 
     return buffer;
 }
 
-static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped) 
+static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped)
 {
     return get_buffer_from_output_queue(overlapped, 0);
 }
@@ -251,7 +254,7 @@
                 component_id_string,
                 NULL,
                 &data_type,
-                component_id,
+                (LPBYTE)component_id,
                 &len);
 
             if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
@@ -261,7 +264,7 @@
                     net_cfg_instance_id_string,
                     NULL,
                     &data_type,
-                    net_cfg_instance_id,
+                    (LPBYTE)net_cfg_instance_id,
                     &len);
 
                 if (status == ERROR_SUCCESS && data_type == REG_SZ) {
@@ -331,7 +334,7 @@
             return -1;
         }
 
-        snprintf(connection_string, 
+        snprintf(connection_string,
              sizeof(connection_string),
              "%s\\%s\\Connection",
              NETWORK_CONNECTIONS_KEY, enum_name);
@@ -342,7 +345,7 @@
             0,
             KEY_READ,
             &connection_key);
-        
+
         if (status == ERROR_SUCCESS) {
             len = sizeof (name_data);
             status = RegQueryValueEx(
@@ -350,7 +353,7 @@
                 name_string,
                 NULL,
                 &name_type,
-                name_data,
+                (LPBYTE)name_data,
                 &len);
 
             if (status != ERROR_SUCCESS || name_type != REG_SZ) {
@@ -415,7 +418,7 @@
     InitializeCriticalSection(&overlapped->output_queue_cs);
     InitializeCriticalSection(&overlapped->free_list_cs);
 
-    overlapped->output_queue_semaphore = CreateSemaphore( 
+    overlapped->output_queue_semaphore = CreateSemaphore(
         NULL,   // default security attributes
         0,   // initial count
         TUN_MAX_BUFFER_COUNT,   // maximum count
@@ -425,7 +428,7 @@
         fprintf(stderr, "error creating output queue semaphore!\n");
     }
 
-    overlapped->free_list_semaphore = CreateSemaphore( 
+    overlapped->free_list_semaphore = CreateSemaphore(
         NULL,   // default security attributes
         TUN_MAX_BUFFER_COUNT,   // initial count
         TUN_MAX_BUFFER_COUNT,   // maximum count
@@ -445,9 +448,13 @@
             overlapped->free_list = element;
         }
     }
+    /* To count buffers, initially no-signal. */
+    overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL);
+    if(!overlapped->tap_semaphore)
+        fprintf(stderr, "error creating tap_semaphore.\n");
 }
 
-static int tap_win32_write(tap_win32_overlapped_t *overlapped, 
+static int tap_win32_write(tap_win32_overlapped_t *overlapped,
                            const void *buffer, unsigned long size)
 {
     unsigned long write_size;
@@ -462,18 +469,18 @@
 
     result = WriteFile(overlapped->handle, buffer, size,
                        &write_size, &overlapped->write_overlapped);
-    
-    if (!result) { 
+
+    if (!result) {
         switch (error = GetLastError())
-        { 
-        case ERROR_IO_PENDING: 
+        {
+        case ERROR_IO_PENDING:
 #ifndef TUN_ASYNCHRONOUS_WRITES
             WaitForSingleObject(overlapped->write_event, INFINITE);
 #endif
             break;
         default:
             return -1;
-        } 
+        }
     }
 
     return 0;
@@ -501,7 +508,7 @@
                 result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped,
                                               &read_size, FALSE);
                 if (!result) {
-#if DEBUG_TAP_WIN32
+#ifdef DEBUG_TAP_WIN32
                     LPVOID lpBuffer;
                     dwError = GetLastError();
                     FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
@@ -512,7 +519,7 @@
 #endif
                 }
             } else {
-#if DEBUG_TAP_WIN32
+#ifdef DEBUG_TAP_WIN32
                 LPVOID lpBuffer;
                 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                                NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
@@ -526,6 +533,7 @@
         if(read_size > 0) {
             buffer->read_size = read_size;
             put_buffer_on_output_queue(overlapped, buffer);
+            ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL);
             buffer = get_buffer_from_free_list(overlapped);
         }
     }
@@ -533,7 +541,7 @@
     return 0;
 }
 
-static int tap_win32_read(tap_win32_overlapped_t *overlapped, 
+static int tap_win32_read(tap_win32_overlapped_t *overlapped,
                           uint8_t **pbuf, int max_size)
 {
     int size = 0;
@@ -551,14 +559,14 @@
     return size;
 }
 
-static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, 
-                                  char* pbuf) 
+static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
+                                  uint8_t *pbuf)
 {
     tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
     put_buffer_on_free_list(overlapped, buffer);
 }
 
-static int tap_win32_open(tap_win32_overlapped_t **phandle, 
+static int tap_win32_open(tap_win32_overlapped_t **phandle,
                           const char *prefered_name)
 {
     char device_path[256];
@@ -572,7 +580,7 @@
         unsigned long minor;
         unsigned long debug;
     } version;
-    LONG version_len;
+    DWORD version_len;
     DWORD idThread;
     HANDLE hThread;
 
@@ -620,8 +628,6 @@
 
     hThread = CreateThread(NULL, 0, tap_win32_thread_entry,
                            (LPVOID)&tap_overlapped, 0, &idThread);
-    SetThreadPriority(hThread,THREAD_PRIORITY_TIME_CRITICAL);
-
     return 0;
 }
 
@@ -630,41 +636,46 @@
  typedef struct TAPState {
      VLANClientState *vc;
      tap_win32_overlapped_t *handle;
-     HANDLE tap_event;
  } TAPState;
 
-static TAPState *tap_win32_state = NULL;
-
-void tap_receive(void *opaque, const uint8_t *buf, int size)
+static void tap_cleanup(VLANClientState *vc)
 {
-    TAPState *s = opaque;
+    TAPState *s = vc->opaque;
 
-    tap_win32_write(s->handle, buf, size);
+    qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL);
+
+    /* FIXME: need to kill thread and close file handle:
+       tap_win32_close(s);
+    */
+    qemu_free(s);
 }
 
-/* XXX: horrible, suppress this by using proper thread signaling */
-void tap_win32_poll(void)
+static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
 {
-    TAPState *s = tap_win32_state;
+    TAPState *s = vc->opaque;
+
+    return tap_win32_write(s->handle, buf, size);
+}
+
+static void tap_win32_send(void *opaque)
+{
+    TAPState *s = opaque;
     uint8_t *buf;
     int max_size = 4096;
     int size;
 
-    if (!s)
-        return;
-
     size = tap_win32_read(s->handle, &buf, max_size);
     if (size > 0) {
         qemu_send_packet(s->vc, buf, size);
         tap_win32_free_buffer(s->handle, buf);
-        SetEvent(s->tap_event);
     }
 }
 
-int tap_win32_init(VLANState *vlan, const char *ifname)
+int tap_win32_init(VLANState *vlan, const char *model,
+                   const char *name, const char *ifname)
 {
     TAPState *s;
-    
+
     s = qemu_mallocz(sizeof(TAPState));
     if (!s)
         return -1;
@@ -673,16 +684,12 @@
         return -1;
     }
 
-    s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s);
-    
+    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive,
+                                 NULL, tap_cleanup, s);
+
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "tap: ifname=%s", ifname);
-    tap_win32_state = s;
 
-    s->tap_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (!s->tap_event) {
-        fprintf(stderr, "tap-win32: Failed CreateEvent\n");
-    }
-    qemu_add_wait_object(s->tap_event, NULL, NULL);
+    qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s);
     return 0;
 }
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index ff765f7..f98655f 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #ifndef CPU_ARM_H
 #define CPU_ARM_H
@@ -24,6 +24,8 @@
 
 #define ELF_MACHINE	EM_ARM
 
+#define CPUState struct CPUARMState
+
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -100,6 +102,9 @@
     struct {
         uint32_t c0_cpuid;
         uint32_t c0_cachetype;
+        uint32_t c0_ccsid[16]; /* Cache size.  */
+        uint32_t c0_clid; /* Cache level.  */
+        uint32_t c0_cssel; /* Cache size selection.  */
         uint32_t c0_c1[8]; /* Feature registers.  */
         uint32_t c0_c2[8]; /* Instruction set registers.  */
         uint32_t c1_sys; /* System control register.  */
@@ -107,7 +112,9 @@
         uint32_t c1_xscaleauxcr; /* XScale auxiliary control register.  */
         uint32_t c2_base0; /* MMU translation table base 0.  */
         uint32_t c2_base1; /* MMU translation table base 1.  */
-        uint32_t c2_mask; /* MMU translation table base mask.  */
+        uint32_t c2_control; /* MMU translation table base control.  */
+        uint32_t c2_mask; /* MMU translation table base selection mask.  */
+        uint32_t c2_base_mask; /* MMU translation table base 0 mask. */
         uint32_t c2_data; /* MPU data cachable bits.  */
         uint32_t c2_insn; /* MPU instruction cachable bits.  */
         uint32_t c3; /* MMU domain access control register
@@ -149,6 +156,10 @@
         void *opaque;
     } cp[15];
 
+    /* Thumb-2 EE state.  */
+    uint32_t teecr;
+    uint32_t teehbr;
+
     /* Internal CPU feature flags.  */
     uint32_t features;
 
@@ -208,6 +219,8 @@
    is returned if the signal was handled by the virtual CPU.  */
 int cpu_arm_signal_handler(int host_signum, void *pinfo,
                            void *puc);
+int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
+                              int mmu_idx, int is_softmuu);
 
 void cpu_lock(void);
 void cpu_unlock(void);
@@ -327,7 +340,8 @@
     ARM_FEATURE_NEON,
     ARM_FEATURE_DIV,
     ARM_FEATURE_M, /* Microcontroller profile.  */
-    ARM_FEATURE_OMAPCP  /* OMAP specific CP15 ops handling.  */
+    ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
+    ARM_FEATURE_THUMB2EE
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -386,7 +400,6 @@
 #define TARGET_PAGE_BITS 10
 #endif
 
-#define CPUState CPUARMState
 #define cpu_init cpu_arm_init
 #define cpu_exec cpu_arm_exec
 #define cpu_gen_code cpu_arm_gen_code
@@ -413,8 +426,25 @@
 }
 #endif
 
-#define CPU_PC_FROM_TB(env, tb) env->regs[15] = tb->pc
-
 #include "cpu-all.h"
+#include "exec-all.h"
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->regs[15] = tb->pc;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->regs[15];
+    *cs_base = 0;
+    *flags = env->thumb | (env->vfp.vec_len << 1)
+            | (env->vfp.vec_stride << 4) | (env->condexec_bits << 8);
+    if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
+        *flags |= (1 << 6);
+    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
+        *flags |= (1 << 7);
+}
 
 #endif
diff --git a/target-arm/exec.h b/target-arm/exec.h
index c543cf4..710a2f9 100644
--- a/target-arm/exec.h
+++ b/target-arm/exec.h
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include "config.h"
 #include "dyngen-exec.h"
@@ -37,8 +37,11 @@
 {
 }
 
-int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int mmu_idx, int is_softmmu);
+static inline int cpu_has_work(CPUState *env)
+{
+    return (env->interrupt_request &
+            (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB));
+}
 
 static inline int cpu_halted(CPUState *env) {
     if (!env->halted)
@@ -46,8 +49,7 @@
     /* An interrupt wakes the CPU even if the I and F CPSR bits are
        set.  We use EXITTB to silently wake CPU without causing an
        actual interrupt.  */
-    if (env->interrupt_request &
-        (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) {
+    if (cpu_has_work(env)) {
         env->halted = 0;
         return 0;
     }
@@ -58,6 +60,4 @@
 #include "softmmu_exec.h"
 #endif
 
-void cpu_loop_exit(void);
-
 void raise_exception(int);
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 85753e4..9ac7e25 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -91,12 +91,17 @@
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_VFP3);
         set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
         memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
         memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c0_cachetype = 0x1dd20d2;
+        env->cp15.c0_cachetype = 0x82048004;
+        env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
+        env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
+        env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
+        env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
         break;
     case ARM_CPUID_CORTEXM3:
         set_feature(env, ARM_FEATURE_V6);
@@ -113,6 +118,7 @@
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_VFP3);
         set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
         set_feature(env, ARM_FEATURE_DIV);
         break;
     case ARM_CPUID_TI915T:
@@ -156,6 +162,12 @@
 void cpu_reset(CPUARMState *env)
 {
     uint32_t id;
+
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
     id = env->cp15.c0_cpuid;
     memset(env, 0, offsetof(CPUARMState, breakpoints));
     if (id)
@@ -171,11 +183,64 @@
     if (IS_M(env))
         env->uncached_cpsr &= ~CPSR_I;
     env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+    env->cp15.c2_base_mask = 0xffffc000u;
 #endif
     env->regs[15] = 0;
     tlb_flush(env, 1);
 }
 
+static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg)
+{
+    int nregs;
+
+    /* VFP data registers are always little-endian.  */
+    nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
+    if (reg < nregs) {
+        stfq_le_p(buf, env->vfp.regs[reg]);
+        return 8;
+    }
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        /* Aliases for Q regs.  */
+        nregs += 16;
+        if (reg < nregs) {
+            stfq_le_p(buf, env->vfp.regs[(reg - 32) * 2]);
+            stfq_le_p(buf + 8, env->vfp.regs[(reg - 32) * 2 + 1]);
+            return 16;
+        }
+    }
+    switch (reg - nregs) {
+    case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4;
+    case 1: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSCR]); return 4;
+    case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4;
+    }
+    return 0;
+}
+
+static int vfp_gdb_set_reg(CPUState *env, uint8_t *buf, int reg)
+{
+    int nregs;
+
+    nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
+    if (reg < nregs) {
+        env->vfp.regs[reg] = ldfq_le_p(buf);
+        return 8;
+    }
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        nregs += 16;
+        if (reg < nregs) {
+            env->vfp.regs[(reg - 32) * 2] = ldfq_le_p(buf);
+            env->vfp.regs[(reg - 32) * 2 + 1] = ldfq_le_p(buf + 8);
+            return 16;
+        }
+    }
+    switch (reg - nregs) {
+    case 0: env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); return 4;
+    case 1: env->vfp.xregs[ARM_VFP_FPSCR] = ldl_p(buf); return 4;
+    case 2: env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf); return 4;
+    }
+    return 0;
+}
+
 CPUARMState *cpu_arm_init(const char *cpu_model)
 {
     CPUARMState *env;
@@ -186,8 +251,6 @@
     if (id == 0)
         return NULL;
     env = qemu_mallocz(sizeof(CPUARMState));
-    if (!env)
-        return NULL;
     cpu_exec_init(env);
     if (!inited) {
         inited = 1;
@@ -197,6 +260,17 @@
     env->cpu_model_str = cpu_model;
     env->cp15.c0_cpuid = id;
     cpu_reset(env);
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 51, "arm-neon.xml", 0);
+    } else if (arm_feature(env, ARM_FEATURE_VFP3)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 35, "arm-vfp3.xml", 0);
+    } else if (arm_feature(env, ARM_FEATURE_VFP)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 19, "arm-vfp.xml", 0);
+    }
+    qemu_init_vcpu(env);
     return env;
 }
 
@@ -396,8 +470,6 @@
 static void allocate_mmon_state(CPUState *env)
 {
     env->mmon_entry = malloc(sizeof (mmon_state));
-    if (!env->mmon_entry)
-        abort();
     memset (env->mmon_entry, 0, sizeof (mmon_state));
     env->mmon_entry->cpu_env = env;
     mmon_head = env->mmon_entry;
@@ -622,7 +694,7 @@
        pointer.  */
 }
 
-void do_interrupt_v7m(CPUARMState *env)
+static void do_interrupt_v7m(CPUARMState *env)
 {
     uint32_t xpsr = xpsr_read(env);
     uint32_t lr;
@@ -846,17 +918,34 @@
           return PAGE_READ | PAGE_WRITE;
   case 3:
       return PAGE_READ | PAGE_WRITE;
-  case 4: case 7: /* Reserved.  */
+  case 4: /* Reserved.  */
       return 0;
   case 5:
       return is_user ? 0 : prot_ro;
   case 6:
       return prot_ro;
+  case 7:
+      if (!arm_feature (env, ARM_FEATURE_V7))
+          return 0;
+      return prot_ro;
   default:
       abort();
   }
 }
 
+static uint32_t get_level1_table_address(CPUState *env, uint32_t address)
+{
+    uint32_t table;
+
+    if (address & env->cp15.c2_mask)
+        table = env->cp15.c2_base1 & 0xffffc000;
+    else
+        table = env->cp15.c2_base0 & env->cp15.c2_base_mask;
+
+    table |= (address >> 18) & 0x3ffc;
+    return table;
+}
+
 static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type,
 			    int is_user, uint32_t *phys_ptr, int *prot)
 {
@@ -870,11 +959,7 @@
 
     /* Pagetable walk.  */
     /* Lookup l1 descriptor.  */
-    if (address & env->cp15.c2_mask)
-        table = env->cp15.c2_base1;
-    else
-        table = env->cp15.c2_base0;
-    table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc);
+    table = get_level1_table_address(env, address);
     desc = ldl_phys(table);
     type = (desc & 3);
     domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
@@ -962,11 +1047,7 @@
 
     /* Pagetable walk.  */
     /* Lookup l1 descriptor.  */
-    if (address & env->cp15.c2_mask)
-        table = env->cp15.c2_base1;
-    else
-        table = env->cp15.c2_base0;
-    table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc);
+    table = get_level1_table_address(env, address);
     desc = ldl_phys(table);
     type = (desc & 3);
     if (type == 0) {
@@ -1026,6 +1107,12 @@
     if (xn && access_type == 2)
         goto do_fault;
 
+    /* The simplified model uses AP[0] as an access control bit.  */
+    if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) {
+        /* Access flag fault.  */
+        code = (code == 15) ? 6 : 3;
+        goto do_fault;
+    }
     *prot = check_ap(env, ap, domain, access_type, is_user);
     if (!*prot) {
         /* Access permission fault.  */
@@ -1250,15 +1337,16 @@
     crm = insn & 0xf;
     switch ((insn >> 16) & 0xf) {
     case 0:
-        if (((insn >> 21) & 7) == 2) {
-            /* ??? Select cache level.  Ignore.  */
-            return;
-        }
         /* ID codes.  */
         if (arm_feature(env, ARM_FEATURE_XSCALE))
             break;
         if (arm_feature(env, ARM_FEATURE_OMAPCP))
             break;
+        if (arm_feature(env, ARM_FEATURE_V7)
+                && op1 == 2 && crm == 0 && op2 == 0) {
+            env->cp15.c0_cssel = val & 0xf;
+            break;
+        }
         goto bad_reg;
     case 1: /* System configuration.  */
         if (arm_feature(env, ARM_FEATURE_OMAPCP))
@@ -1281,9 +1369,11 @@
         case 2:
             if (arm_feature(env, ARM_FEATURE_XSCALE))
                 goto bad_reg;
-            env->cp15.c1_coproc = val;
-            /* ??? Is this safe when called from within a TB?  */
-            tb_flush(env);
+            if (env->cp15.c1_coproc != val) {
+                env->cp15.c1_coproc = val;
+                /* ??? Is this safe when called from within a TB?  */
+                tb_flush(env);
+            }
             break;
         default:
             goto bad_reg;
@@ -1310,7 +1400,10 @@
 		env->cp15.c2_base1 = val;
 		break;
 	    case 2:
+                val &= 7;
+                env->cp15.c2_control = val;
 		env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
+                env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val);
 		break;
 	    default:
 		goto bad_reg;
@@ -1572,9 +1665,22 @@
                 goto bad_reg;
             if (crm != 0)
                 goto bad_reg;
-            if (arm_feature(env, ARM_FEATURE_XSCALE))
+            if (!arm_feature(env, ARM_FEATURE_V7))
+                return 0;
+
+            switch (op2) {
+            case 0:
+                return env->cp15.c0_ccsid[env->cp15.c0_cssel];
+            case 1:
+                return env->cp15.c0_clid;
+            case 7:
+                return 0;
+            }
+            goto bad_reg;
+        case 2:
+            if (op2 != 0 || crm != 0)
                 goto bad_reg;
-            return 0;
+            return env->cp15.c0_cssel;
         default:
             goto bad_reg;
         }
@@ -1598,7 +1704,7 @@
             case ARM_CPUID_ARM11MPCORE:
                 return 1;
             case ARM_CPUID_CORTEXA8:
-                return 0;
+                return 2;
             default:
                 goto bad_reg;
             }
@@ -1628,17 +1734,7 @@
 	    case 1:
 		return env->cp15.c2_base1;
 	    case 2:
-		{
-		    int n;
-		    uint32_t mask;
-		    n = 0;
-		    mask = env->cp15.c2_mask;
-		    while (mask) {
-			n++;
-			mask <<= 1;
-		    }
-		    return n;
-		}
+                return env->cp15.c2_control;
 	    default:
 		goto bad_reg;
 	    }
@@ -2250,10 +2346,13 @@
         }
         set_float_rounding_mode(i, &env->vfp.fp_status);
     }
+    if (changed & (1 << 24))
+        set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
+    if (changed & (1 << 25))
+        set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);
 
     i = vfp_exceptbits_to_host((val >> 8) & 0x1f);
     set_float_exception_flags(i, &env->vfp.fp_status);
-    /* XXX: FZ and DN are not implemented.  */
 }
 
 #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
@@ -2458,7 +2557,7 @@
     ftype tmp; \
     tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \
                                   &env->vfp.fp_status); \
-    return ftype##_scalbn(tmp, shift, &env->vfp.fp_status); \
+    return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
 } \
 ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
 { \
@@ -2545,9 +2644,8 @@
 }
 
 #if HOST_LONG_BITS == 32
-void HELPER(traceBB32)(uint32_t  hi, uint32_t  lo, uint32_t  tb)
+void HELPER(traceBB32)(uint64_t  bb_num, uint32_t  tb)
 {
-    uint64_t  bb_num = ((uint64_t)hi << 32) | lo;
     trace_bb_helper(bb_num, (void*)tb);
 }
 #endif
@@ -2560,3 +2658,13 @@
 #endif
 
 #endif /* CONFIG_TRACE */
+
+void HELPER(set_teecr)(CPUState *env, uint32_t val)
+{
+    val &= 1;
+    if (env->teecr != val) {
+        env->teecr = val;
+        tb_flush(env);
+    }
+}
+
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index cef53be..abc54d2 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -1,476 +1,405 @@
-#define DEF_HELPER(name, ret, args) ret glue(helper_,name) args;
+#include "def-helper.h"
 
-#ifdef GEN_HELPER
-#define DEF_HELPER_0_0(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name(void) \
-{ \
-    tcg_gen_helper_0_0(helper_##name); \
-}
-#define DEF_HELPER_0_1(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name(TCGv arg1) \
-{ \
-    tcg_gen_helper_0_1(helper_##name, arg1); \
-}
-#define DEF_HELPER_0_2(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name(TCGv arg1, TCGv arg2) \
-{ \
-    tcg_gen_helper_0_2(helper_##name, arg1, arg2); \
-}
-#define DEF_HELPER_0_3(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name( \
-    TCGv arg1, TCGv arg2, TCGv arg3) \
-{ \
-    tcg_gen_helper_0_3(helper_##name, arg1, arg2, arg3); \
-}
-#define DEF_HELPER_1_0(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name(TCGv ret) \
-{ \
-    tcg_gen_helper_1_0(helper_##name, ret); \
-}
-#define DEF_HELPER_1_1(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name(TCGv ret, TCGv arg1) \
-{ \
-    tcg_gen_helper_1_1(helper_##name, ret, arg1); \
-}
-#define DEF_HELPER_1_2(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name(TCGv ret, TCGv arg1, TCGv arg2) \
-{ \
-    tcg_gen_helper_1_2(helper_##name, ret, arg1, arg2); \
-}
-#define DEF_HELPER_1_3(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name(TCGv ret, \
-    TCGv arg1, TCGv arg2, TCGv arg3) \
-{ \
-    tcg_gen_helper_1_3(helper_##name, ret, arg1, arg2, arg3); \
-}
-#define DEF_HELPER_1_4(name, ret, args) \
-DEF_HELPER(name, ret, args) \
-static inline void gen_helper_##name(TCGv ret, \
-    TCGv arg1, TCGv arg2, TCGv arg3, TCGv arg4) \
-{ \
-    tcg_gen_helper_1_4(helper_##name, ret, arg1, arg2, arg3, arg4); \
-}
-#else /* !GEN_HELPER */
-#define DEF_HELPER_0_0 DEF_HELPER
-#define DEF_HELPER_0_1 DEF_HELPER
-#define DEF_HELPER_0_2 DEF_HELPER
-#define DEF_HELPER_0_3 DEF_HELPER
-#define DEF_HELPER_1_0 DEF_HELPER
-#define DEF_HELPER_1_1 DEF_HELPER
-#define DEF_HELPER_1_2 DEF_HELPER
-#define DEF_HELPER_1_3 DEF_HELPER
-#define DEF_HELPER_1_4 DEF_HELPER
-#define HELPER(x) glue(helper_,x)
-#endif
+DEF_HELPER_1(clz, i32, i32)
+DEF_HELPER_1(sxtb16, i32, i32)
+DEF_HELPER_1(uxtb16, i32, i32)
 
-DEF_HELPER_1_1(clz, uint32_t, (uint32_t))
-DEF_HELPER_1_1(sxtb16, uint32_t, (uint32_t))
-DEF_HELPER_1_1(uxtb16, uint32_t, (uint32_t))
-
-DEF_HELPER_1_2(add_setq, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(add_saturate, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(sub_saturate, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(add_usaturate, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(sub_usaturate, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_1(double_saturate, uint32_t, (int32_t))
-DEF_HELPER_1_2(sdiv, int32_t, (int32_t, int32_t))
-DEF_HELPER_1_2(udiv, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_1(rbit, uint32_t, (uint32_t))
-DEF_HELPER_1_1(abs, uint32_t, (uint32_t))
+DEF_HELPER_2(add_setq, i32, i32, i32)
+DEF_HELPER_2(add_saturate, i32, i32, i32)
+DEF_HELPER_2(sub_saturate, i32, i32, i32)
+DEF_HELPER_2(add_usaturate, i32, i32, i32)
+DEF_HELPER_2(sub_usaturate, i32, i32, i32)
+DEF_HELPER_1(double_saturate, i32, s32)
+DEF_HELPER_2(sdiv, s32, s32, s32)
+DEF_HELPER_2(udiv, i32, i32, i32)
+DEF_HELPER_1(rbit, i32, i32)
+DEF_HELPER_1(abs, i32, i32)
 
 #ifdef CONFIG_TRACE
-DEF_HELPER_0_1(traceTicks,void,(uint32_t))
-DEF_HELPER_0_0(traceInsn,void,(void))
-DEF_HELPER_0_3(traceBB32,void,(uint32_t,uint32_t,uint32_t))
-DEF_HELPER_0_2(traceBB64,void,(uint64_t,uint64_t))
+DEF_HELPER_1(traceTicks, void, i32)
+DEF_HELPER_0(traceInsn, void)
+#if HOST_LONG_BITS == 32
+DEF_HELPER_2(traceBB32, void, i64, i32)
+#endif
+#if HOST_LONG_BITS == 64
+DEF_HELPER_2(traceBB64, void, i64, i64)
+#endif
 #endif
 
 #define PAS_OP(pfx)  \
-    DEF_HELPER_1_3(pfx ## add8, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
-    DEF_HELPER_1_3(pfx ## sub8, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
-    DEF_HELPER_1_3(pfx ## sub16, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
-    DEF_HELPER_1_3(pfx ## add16, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
-    DEF_HELPER_1_3(pfx ## addsubx, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
-    DEF_HELPER_1_3(pfx ## subaddx, uint32_t, (uint32_t, uint32_t, uint32_t *))
+    DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## sub16, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## add16, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## addsubx, i32, i32, i32, ptr) \
+    DEF_HELPER_3(pfx ## subaddx, i32, i32, i32, ptr)
 
 PAS_OP(s)
 PAS_OP(u)
 #undef PAS_OP
 
 #define PAS_OP(pfx)  \
-    DEF_HELPER_1_2(pfx ## add8, uint32_t, (uint32_t, uint32_t)) \
-    DEF_HELPER_1_2(pfx ## sub8, uint32_t, (uint32_t, uint32_t)) \
-    DEF_HELPER_1_2(pfx ## sub16, uint32_t, (uint32_t, uint32_t)) \
-    DEF_HELPER_1_2(pfx ## add16, uint32_t, (uint32_t, uint32_t)) \
-    DEF_HELPER_1_2(pfx ## addsubx, uint32_t, (uint32_t, uint32_t)) \
-    DEF_HELPER_1_2(pfx ## subaddx, uint32_t, (uint32_t, uint32_t))
+    DEF_HELPER_2(pfx ## add8, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## sub8, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## sub16, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## add16, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## addsubx, i32, i32, i32) \
+    DEF_HELPER_2(pfx ## subaddx, i32, i32, i32)
 PAS_OP(q)
 PAS_OP(sh)
 PAS_OP(uq)
 PAS_OP(uh)
 #undef PAS_OP
 
-DEF_HELPER_1_2(ssat, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(usat, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(ssat16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(usat16, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(ssat, i32, i32, i32)
+DEF_HELPER_2(usat, i32, i32, i32)
+DEF_HELPER_2(ssat16, i32, i32, i32)
+DEF_HELPER_2(usat16, i32, i32, i32)
 
-DEF_HELPER_1_2(usad8, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(usad8, i32, i32, i32)
 
-DEF_HELPER_1_1(logicq_cc, uint32_t, (uint64_t))
+DEF_HELPER_1(logicq_cc, i32, i64)
 
-DEF_HELPER_1_3(sel_flags, uint32_t, (uint32_t, uint32_t, uint32_t))
-DEF_HELPER_0_1(exception, void, (uint32_t))
-DEF_HELPER_0_0(wfi, void, (void))
+DEF_HELPER_3(sel_flags, i32, i32, i32, i32)
+DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_0(wfi, void)
 
-DEF_HELPER_0_2(cpsr_write, void, (uint32_t, uint32_t))
-DEF_HELPER_1_0(cpsr_read, uint32_t, (void))
+DEF_HELPER_2(cpsr_write, void, i32, i32)
+DEF_HELPER_0(cpsr_read, i32)
 
-DEF_HELPER_0_3(v7m_msr, void, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_2(v7m_mrs, uint32_t, (CPUState *, uint32_t))
+DEF_HELPER_3(v7m_msr, void, env, i32, i32)
+DEF_HELPER_2(v7m_mrs, i32, env, i32)
 
-DEF_HELPER_0_3(set_cp15, void, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_2(get_cp15, uint32_t, (CPUState *, uint32_t))
+DEF_HELPER_3(set_cp15, void, env, i32, i32)
+DEF_HELPER_2(get_cp15, i32, env, i32)
 
-DEF_HELPER_0_3(set_cp, void, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_2(get_cp, uint32_t, (CPUState *, uint32_t))
+DEF_HELPER_3(set_cp, void, env, i32, i32)
+DEF_HELPER_2(get_cp, i32, env, i32)
 
-DEF_HELPER_1_2(get_r13_banked, uint32_t, (CPUState *, uint32_t))
-DEF_HELPER_0_3(set_r13_banked, void, (CPUState *, uint32_t, uint32_t))
+DEF_HELPER_2(get_r13_banked, i32, env, i32)
+DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
 
-DEF_HELPER_0_2(mark_exclusive, void, (CPUState *, uint32_t))
-DEF_HELPER_1_2(test_exclusive, uint32_t, (CPUState *, uint32_t))
-DEF_HELPER_0_1(clrex, void, (CPUState *))
+DEF_HELPER_2(mark_exclusive, void, env, i32)
+DEF_HELPER_2(test_exclusive, i32, env, i32)
+DEF_HELPER_1(clrex, void, env)
 
-DEF_HELPER_1_1(get_user_reg, uint32_t, (uint32_t))
-DEF_HELPER_0_2(set_user_reg, void, (uint32_t, uint32_t))
+DEF_HELPER_1(get_user_reg, i32, i32)
+DEF_HELPER_2(set_user_reg, void, i32, i32)
 
-DEF_HELPER_1_1(vfp_get_fpscr, uint32_t, (CPUState *))
-DEF_HELPER_0_2(vfp_set_fpscr, void, (CPUState *, uint32_t))
+DEF_HELPER_1(vfp_get_fpscr, i32, env)
+DEF_HELPER_2(vfp_set_fpscr, void, env, i32)
 
-DEF_HELPER_1_3(vfp_adds, float32, (float32, float32, CPUState *))
-DEF_HELPER_1_3(vfp_addd, float64, (float64, float64, CPUState *))
-DEF_HELPER_1_3(vfp_subs, float32, (float32, float32, CPUState *))
-DEF_HELPER_1_3(vfp_subd, float64, (float64, float64, CPUState *))
-DEF_HELPER_1_3(vfp_muls, float32, (float32, float32, CPUState *))
-DEF_HELPER_1_3(vfp_muld, float64, (float64, float64, CPUState *))
-DEF_HELPER_1_3(vfp_divs, float32, (float32, float32, CPUState *))
-DEF_HELPER_1_3(vfp_divd, float64, (float64, float64, CPUState *))
-DEF_HELPER_1_1(vfp_negs, float32, (float32))
-DEF_HELPER_1_1(vfp_negd, float64, (float64))
-DEF_HELPER_1_1(vfp_abss, float32, (float32))
-DEF_HELPER_1_1(vfp_absd, float64, (float64))
-DEF_HELPER_1_2(vfp_sqrts, float32, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_sqrtd, float64, (float64, CPUState *))
-DEF_HELPER_0_3(vfp_cmps, void, (float32, float32, CPUState *))
-DEF_HELPER_0_3(vfp_cmpd, void, (float64, float64, CPUState *))
-DEF_HELPER_0_3(vfp_cmpes, void, (float32, float32, CPUState *))
-DEF_HELPER_0_3(vfp_cmped, void, (float64, float64, CPUState *))
+DEF_HELPER_3(vfp_adds, f32, f32, f32, env)
+DEF_HELPER_3(vfp_addd, f64, f64, f64, env)
+DEF_HELPER_3(vfp_subs, f32, f32, f32, env)
+DEF_HELPER_3(vfp_subd, f64, f64, f64, env)
+DEF_HELPER_3(vfp_muls, f32, f32, f32, env)
+DEF_HELPER_3(vfp_muld, f64, f64, f64, env)
+DEF_HELPER_3(vfp_divs, f32, f32, f32, env)
+DEF_HELPER_3(vfp_divd, f64, f64, f64, env)
+DEF_HELPER_1(vfp_negs, f32, f32)
+DEF_HELPER_1(vfp_negd, f64, f64)
+DEF_HELPER_1(vfp_abss, f32, f32)
+DEF_HELPER_1(vfp_absd, f64, f64)
+DEF_HELPER_2(vfp_sqrts, f32, f32, env)
+DEF_HELPER_2(vfp_sqrtd, f64, f64, env)
+DEF_HELPER_3(vfp_cmps, void, f32, f32, env)
+DEF_HELPER_3(vfp_cmpd, void, f64, f64, env)
+DEF_HELPER_3(vfp_cmpes, void, f32, f32, env)
+DEF_HELPER_3(vfp_cmped, void, f64, f64, env)
 
-DEF_HELPER_1_2(vfp_fcvtds, float64, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_fcvtsd, float32, (float64, CPUState *))
+DEF_HELPER_2(vfp_fcvtds, f64, f32, env)
+DEF_HELPER_2(vfp_fcvtsd, f32, f64, env)
 
-DEF_HELPER_1_2(vfp_uitos, float32, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_uitod, float64, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_sitos, float32, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_sitod, float64, (float32, CPUState *))
+DEF_HELPER_2(vfp_uitos, f32, f32, env)
+DEF_HELPER_2(vfp_uitod, f64, f32, env)
+DEF_HELPER_2(vfp_sitos, f32, f32, env)
+DEF_HELPER_2(vfp_sitod, f64, f32, env)
 
-DEF_HELPER_1_2(vfp_touis, float32, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_touid, float32, (float64, CPUState *))
-DEF_HELPER_1_2(vfp_touizs, float32, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_touizd, float32, (float64, CPUState *))
-DEF_HELPER_1_2(vfp_tosis, float32, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_tosid, float32, (float64, CPUState *))
-DEF_HELPER_1_2(vfp_tosizs, float32, (float32, CPUState *))
-DEF_HELPER_1_2(vfp_tosizd, float32, (float64, CPUState *))
+DEF_HELPER_2(vfp_touis, f32, f32, env)
+DEF_HELPER_2(vfp_touid, f32, f64, env)
+DEF_HELPER_2(vfp_touizs, f32, f32, env)
+DEF_HELPER_2(vfp_touizd, f32, f64, env)
+DEF_HELPER_2(vfp_tosis, f32, f32, env)
+DEF_HELPER_2(vfp_tosid, f32, f64, env)
+DEF_HELPER_2(vfp_tosizs, f32, f32, env)
+DEF_HELPER_2(vfp_tosizd, f32, f64, env)
 
-DEF_HELPER_1_3(vfp_toshs, float32, (float32, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_tosls, float32, (float32, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_touhs, float32, (float32, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_touls, float32, (float32, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_toshd, float64, (float64, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_tosld, float64, (float64, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_touhd, float64, (float64, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_tould, float64, (float64, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_shtos, float32, (float32, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_sltos, float32, (float32, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_uhtos, float32, (float32, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_ultos, float32, (float32, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_shtod, float64, (float64, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_sltod, float64, (float64, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_uhtod, float64, (float64, uint32_t, CPUState *))
-DEF_HELPER_1_3(vfp_ultod, float64, (float64, uint32_t, CPUState *))
+DEF_HELPER_3(vfp_toshs, f32, f32, i32, env)
+DEF_HELPER_3(vfp_tosls, f32, f32, i32, env)
+DEF_HELPER_3(vfp_touhs, f32, f32, i32, env)
+DEF_HELPER_3(vfp_touls, f32, f32, i32, env)
+DEF_HELPER_3(vfp_toshd, f64, f64, i32, env)
+DEF_HELPER_3(vfp_tosld, f64, f64, i32, env)
+DEF_HELPER_3(vfp_touhd, f64, f64, i32, env)
+DEF_HELPER_3(vfp_tould, f64, f64, i32, env)
+DEF_HELPER_3(vfp_shtos, f32, f32, i32, env)
+DEF_HELPER_3(vfp_sltos, f32, f32, i32, env)
+DEF_HELPER_3(vfp_uhtos, f32, f32, i32, env)
+DEF_HELPER_3(vfp_ultos, f32, f32, i32, env)
+DEF_HELPER_3(vfp_shtod, f64, f64, i32, env)
+DEF_HELPER_3(vfp_sltod, f64, f64, i32, env)
+DEF_HELPER_3(vfp_uhtod, f64, f64, i32, env)
+DEF_HELPER_3(vfp_ultod, f64, f64, i32, env)
 
-DEF_HELPER_1_3(recps_f32, float32, (float32, float32, CPUState *))
-DEF_HELPER_1_3(rsqrts_f32, float32, (float32, float32, CPUState *))
-DEF_HELPER_1_2(recpe_f32, float32, (float32, CPUState *))
-DEF_HELPER_1_2(rsqrte_f32, float32, (float32, CPUState *))
-DEF_HELPER_1_2(recpe_u32, uint32_t, (uint32_t, CPUState *))
-DEF_HELPER_1_2(rsqrte_u32, uint32_t, (uint32_t, CPUState *))
-DEF_HELPER_1_4(neon_tbl, uint32_t, (uint32_t, uint32_t, uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_add_saturate_u64, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_add_saturate_s64, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_sub_saturate_u64, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_sub_saturate_s64, uint64_t, (uint64_t, uint64_t))
+DEF_HELPER_3(recps_f32, f32, f32, f32, env)
+DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env)
+DEF_HELPER_2(recpe_f32, f32, f32, env)
+DEF_HELPER_2(rsqrte_f32, f32, f32, env)
+DEF_HELPER_2(recpe_u32, i32, i32, env)
+DEF_HELPER_2(rsqrte_u32, i32, i32, env)
+DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32)
+DEF_HELPER_2(neon_add_saturate_u64, i64, i64, i64)
+DEF_HELPER_2(neon_add_saturate_s64, i64, i64, i64)
+DEF_HELPER_2(neon_sub_saturate_u64, i64, i64, i64)
+DEF_HELPER_2(neon_sub_saturate_s64, i64, i64, i64)
 
-DEF_HELPER_1_2(add_cc, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(adc_cc, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(sub_cc, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(sbc_cc, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(add_cc, i32, i32, i32)
+DEF_HELPER_2(adc_cc, i32, i32, i32)
+DEF_HELPER_2(sub_cc, i32, i32, i32)
+DEF_HELPER_2(sbc_cc, i32, i32, i32)
 
-DEF_HELPER_1_2(shl, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(shr, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(sar, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(ror, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(shl_cc, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(shr_cc, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(sar_cc, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(ror_cc, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(shl, i32, i32, i32)
+DEF_HELPER_2(shr, i32, i32, i32)
+DEF_HELPER_2(sar, i32, i32, i32)
+DEF_HELPER_2(ror, i32, i32, i32)
+DEF_HELPER_2(shl_cc, i32, i32, i32)
+DEF_HELPER_2(shr_cc, i32, i32, i32)
+DEF_HELPER_2(sar_cc, i32, i32, i32)
+DEF_HELPER_2(ror_cc, i32, i32, i32)
 
 /* neon_helper.c */
-DEF_HELPER_1_3(neon_qadd_u8, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qadd_s8, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qadd_u16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qadd_s16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qsub_u8, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qsub_s8, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qsub_u16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qsub_s16, uint32_t, (CPUState *, uint32_t, uint32_t))
+DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qsub_s16, i32, env, i32, i32)
 
-DEF_HELPER_1_2(neon_hadd_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hadd_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hadd_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hadd_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hadd_s32, int32_t, (int32_t, int32_t))
-DEF_HELPER_1_2(neon_hadd_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rhadd_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rhadd_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rhadd_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rhadd_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rhadd_s32, int32_t, (int32_t, int32_t))
-DEF_HELPER_1_2(neon_rhadd_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hsub_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hsub_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hsub_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hsub_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_hsub_s32, int32_t, (int32_t, int32_t))
-DEF_HELPER_1_2(neon_hsub_u32, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(neon_hadd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_hadd_s32, s32, s32, s32)
+DEF_HELPER_2(neon_hadd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_rhadd_s32, s32, s32, s32)
+DEF_HELPER_2(neon_rhadd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s8, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_u8, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s16, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_u16, i32, i32, i32)
+DEF_HELPER_2(neon_hsub_s32, s32, s32, s32)
+DEF_HELPER_2(neon_hsub_u32, i32, i32, i32)
 
-DEF_HELPER_1_2(neon_cgt_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cgt_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cgt_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cgt_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cgt_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cgt_s32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cge_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cge_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cge_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cge_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cge_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cge_s32, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(neon_cgt_u8, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s8, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_u16, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s16, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_u32, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_s32, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u8, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s8, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u16, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s16, i32, i32, i32)
+DEF_HELPER_2(neon_cge_u32, i32, i32, i32)
+DEF_HELPER_2(neon_cge_s32, i32, i32, i32)
 
-DEF_HELPER_1_2(neon_min_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_min_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_min_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_min_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_min_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_min_s32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_max_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_max_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_max_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_max_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_max_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_max_s32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmin_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmin_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmin_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmin_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmin_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmin_s32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmax_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmax_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmax_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmax_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmax_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_pmax_s32, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(neon_min_u8, i32, i32, i32)
+DEF_HELPER_2(neon_min_s8, i32, i32, i32)
+DEF_HELPER_2(neon_min_u16, i32, i32, i32)
+DEF_HELPER_2(neon_min_s16, i32, i32, i32)
+DEF_HELPER_2(neon_min_u32, i32, i32, i32)
+DEF_HELPER_2(neon_min_s32, i32, i32, i32)
+DEF_HELPER_2(neon_max_u8, i32, i32, i32)
+DEF_HELPER_2(neon_max_s8, i32, i32, i32)
+DEF_HELPER_2(neon_max_u16, i32, i32, i32)
+DEF_HELPER_2(neon_max_s16, i32, i32, i32)
+DEF_HELPER_2(neon_max_u32, i32, i32, i32)
+DEF_HELPER_2(neon_max_s32, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_u8, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_s8, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_u16, i32, i32, i32)
+DEF_HELPER_2(neon_pmin_s16, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_u8, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_s8, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_u16, i32, i32, i32)
+DEF_HELPER_2(neon_pmax_s16, i32, i32, i32)
 
-DEF_HELPER_1_2(neon_abd_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abd_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abd_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abd_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abd_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abd_s32, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(neon_abd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s8, i32, i32, i32)
+DEF_HELPER_2(neon_abd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s16, i32, i32, i32)
+DEF_HELPER_2(neon_abd_u32, i32, i32, i32)
+DEF_HELPER_2(neon_abd_s32, i32, i32, i32)
 
-DEF_HELPER_1_2(neon_shl_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_shl_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_shl_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_shl_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_shl_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_shl_s32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_shl_u64, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_shl_s64, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_rshl_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rshl_s8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rshl_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rshl_s16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rshl_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rshl_s32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_rshl_u64, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_rshl_s64, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_3(neon_qshl_u8, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qshl_s8, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qshl_u16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qshl_s16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qshl_u32, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qshl_s32, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qshl_u64, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(neon_qshl_s64, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(neon_qrshl_u8, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qrshl_s8, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qrshl_u16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qrshl_s16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qrshl_u32, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qrshl_s32, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qrshl_u64, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(neon_qrshl_s64, uint64_t, (CPUState *, uint64_t, uint64_t))
+DEF_HELPER_2(neon_shl_u8, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s8, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u16, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s16, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u32, i32, i32, i32)
+DEF_HELPER_2(neon_shl_s32, i32, i32, i32)
+DEF_HELPER_2(neon_shl_u64, i64, i64, i64)
+DEF_HELPER_2(neon_shl_s64, i64, i64, i64)
+DEF_HELPER_2(neon_rshl_u8, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s8, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u16, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s16, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u32, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_s32, i32, i32, i32)
+DEF_HELPER_2(neon_rshl_u64, i64, i64, i64)
+DEF_HELPER_2(neon_rshl_s64, i64, i64, i64)
+DEF_HELPER_3(neon_qshl_u8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_u16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_u32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrshl_u64, i64, env, i64, i64)
+DEF_HELPER_3(neon_qrshl_s64, i64, env, i64, i64)
 
-DEF_HELPER_1_2(neon_add_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_add_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_padd_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_padd_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_sub_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_sub_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_mul_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_mul_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_mul_p8, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(neon_add_u8, i32, i32, i32)
+DEF_HELPER_2(neon_add_u16, i32, i32, i32)
+DEF_HELPER_2(neon_padd_u8, i32, i32, i32)
+DEF_HELPER_2(neon_padd_u16, i32, i32, i32)
+DEF_HELPER_2(neon_sub_u8, i32, i32, i32)
+DEF_HELPER_2(neon_sub_u16, i32, i32, i32)
+DEF_HELPER_2(neon_mul_u8, i32, i32, i32)
+DEF_HELPER_2(neon_mul_u16, i32, i32, i32)
+DEF_HELPER_2(neon_mul_p8, i32, i32, i32)
 
-DEF_HELPER_1_2(neon_tst_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_tst_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_tst_u32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_ceq_u8, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_ceq_u16, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_ceq_u32, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(neon_tst_u8, i32, i32, i32)
+DEF_HELPER_2(neon_tst_u16, i32, i32, i32)
+DEF_HELPER_2(neon_tst_u32, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u8, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u16, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_u32, i32, i32, i32)
 
-DEF_HELPER_1_1(neon_abs_s8, uint32_t, (uint32_t))
-DEF_HELPER_1_1(neon_abs_s16, uint32_t, (uint32_t))
-DEF_HELPER_1_1(neon_clz_u8, uint32_t, (uint32_t))
-DEF_HELPER_1_1(neon_clz_u16, uint32_t, (uint32_t))
-DEF_HELPER_1_1(neon_cls_s8, uint32_t, (uint32_t))
-DEF_HELPER_1_1(neon_cls_s16, uint32_t, (uint32_t))
-DEF_HELPER_1_1(neon_cls_s32, uint32_t, (uint32_t))
-DEF_HELPER_1_1(neon_cnt_u8, uint32_t, (uint32_t))
+DEF_HELPER_1(neon_abs_s8, i32, i32)
+DEF_HELPER_1(neon_abs_s16, i32, i32)
+DEF_HELPER_1(neon_clz_u8, i32, i32)
+DEF_HELPER_1(neon_clz_u16, i32, i32)
+DEF_HELPER_1(neon_cls_s8, i32, i32)
+DEF_HELPER_1(neon_cls_s16, i32, i32)
+DEF_HELPER_1(neon_cls_s32, i32, i32)
+DEF_HELPER_1(neon_cnt_u8, i32, i32)
 
-DEF_HELPER_1_3(neon_qdmulh_s16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qrdmulh_s16, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qdmulh_s32, uint32_t, (CPUState *, uint32_t, uint32_t))
-DEF_HELPER_1_3(neon_qrdmulh_s32, uint32_t, (CPUState *, uint32_t, uint32_t))
+DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32)
+DEF_HELPER_3(neon_qdmulh_s32, i32, env, i32, i32)
+DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32)
 
-DEF_HELPER_1_1(neon_narrow_u8, uint32_t, (uint64_t))
-DEF_HELPER_1_1(neon_narrow_u16, uint32_t, (uint64_t))
-DEF_HELPER_1_2(neon_narrow_sat_u8, uint32_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(neon_narrow_sat_s8, uint32_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(neon_narrow_sat_u16, uint32_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(neon_narrow_sat_s16, uint32_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(neon_narrow_sat_u32, uint32_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(neon_narrow_sat_s32, uint32_t, (CPUState *, uint64_t))
-DEF_HELPER_1_1(neon_narrow_high_u8, uint32_t, (uint64_t))
-DEF_HELPER_1_1(neon_narrow_high_u16, uint32_t, (uint64_t))
-DEF_HELPER_1_1(neon_narrow_round_high_u8, uint32_t, (uint64_t))
-DEF_HELPER_1_1(neon_narrow_round_high_u16, uint32_t, (uint64_t))
-DEF_HELPER_1_1(neon_widen_u8, uint64_t, (uint32_t))
-DEF_HELPER_1_1(neon_widen_s8, uint64_t, (uint32_t))
-DEF_HELPER_1_1(neon_widen_u16, uint64_t, (uint32_t))
-DEF_HELPER_1_1(neon_widen_s16, uint64_t, (uint32_t))
+DEF_HELPER_1(neon_narrow_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_u16, i32, i64)
+DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64)
+DEF_HELPER_1(neon_narrow_high_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_high_u16, i32, i64)
+DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64)
+DEF_HELPER_1(neon_narrow_round_high_u16, i32, i64)
+DEF_HELPER_1(neon_widen_u8, i64, i32)
+DEF_HELPER_1(neon_widen_s8, i64, i32)
+DEF_HELPER_1(neon_widen_u16, i64, i32)
+DEF_HELPER_1(neon_widen_s16, i64, i32)
 
-DEF_HELPER_1_2(neon_addl_u16, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_addl_u32, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_paddl_u16, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_paddl_u32, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_subl_u16, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_subl_u32, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_3(neon_addl_saturate_s32, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(neon_addl_saturate_s64, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_2(neon_abdl_u16, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abdl_s16, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abdl_u32, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abdl_s32, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abdl_u64, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abdl_s64, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_mull_u8, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_mull_s8, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_mull_u16, uint64_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_mull_s16, uint64_t, (uint32_t, uint32_t))
+DEF_HELPER_2(neon_addl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_addl_u32, i64, i64, i64)
+DEF_HELPER_2(neon_paddl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_paddl_u32, i64, i64, i64)
+DEF_HELPER_2(neon_subl_u16, i64, i64, i64)
+DEF_HELPER_2(neon_subl_u32, i64, i64, i64)
+DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64)
+DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64)
+DEF_HELPER_2(neon_abdl_u16, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s16, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_u32, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s32, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_u64, i64, i32, i32)
+DEF_HELPER_2(neon_abdl_s64, i64, i32, i32)
+DEF_HELPER_2(neon_mull_u8, i64, i32, i32)
+DEF_HELPER_2(neon_mull_s8, i64, i32, i32)
+DEF_HELPER_2(neon_mull_u16, i64, i32, i32)
+DEF_HELPER_2(neon_mull_s16, i64, i32, i32)
 
-DEF_HELPER_1_1(neon_negl_u16, uint64_t, (uint64_t))
-DEF_HELPER_1_1(neon_negl_u32, uint64_t, (uint64_t))
-DEF_HELPER_1_1(neon_negl_u64, uint64_t, (uint64_t))
+DEF_HELPER_1(neon_negl_u16, i64, i64)
+DEF_HELPER_1(neon_negl_u32, i64, i64)
+DEF_HELPER_1(neon_negl_u64, i64, i64)
 
-DEF_HELPER_1_2(neon_qabs_s8, uint32_t, (CPUState *, uint32_t))
-DEF_HELPER_1_2(neon_qabs_s16, uint32_t, (CPUState *, uint32_t))
-DEF_HELPER_1_2(neon_qabs_s32, uint32_t, (CPUState *, uint32_t))
-DEF_HELPER_1_2(neon_qneg_s8, uint32_t, (CPUState *, uint32_t))
-DEF_HELPER_1_2(neon_qneg_s16, uint32_t, (CPUState *, uint32_t))
-DEF_HELPER_1_2(neon_qneg_s32, uint32_t, (CPUState *, uint32_t))
+DEF_HELPER_2(neon_qabs_s8, i32, env, i32)
+DEF_HELPER_2(neon_qabs_s16, i32, env, i32)
+DEF_HELPER_2(neon_qabs_s32, i32, env, i32)
+DEF_HELPER_2(neon_qneg_s8, i32, env, i32)
+DEF_HELPER_2(neon_qneg_s16, i32, env, i32)
+DEF_HELPER_2(neon_qneg_s32, i32, env, i32)
 
-DEF_HELPER_0_0(neon_trn_u8, void, (void))
-DEF_HELPER_0_0(neon_trn_u16, void, (void))
-DEF_HELPER_0_0(neon_unzip_u8, void, (void))
-DEF_HELPER_0_0(neon_zip_u8, void, (void))
-DEF_HELPER_0_0(neon_zip_u16, void, (void))
+DEF_HELPER_0(neon_trn_u8, void)
+DEF_HELPER_0(neon_trn_u16, void)
+DEF_HELPER_0(neon_unzip_u8, void)
+DEF_HELPER_0(neon_zip_u8, void)
+DEF_HELPER_0(neon_zip_u16, void)
 
-DEF_HELPER_1_2(neon_min_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_max_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_abd_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_add_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_sub_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_mul_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_ceq_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cge_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_cgt_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_acge_f32, uint32_t, (uint32_t, uint32_t))
-DEF_HELPER_1_2(neon_acgt_f32, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_2(neon_min_f32, i32, i32, i32)
+DEF_HELPER_2(neon_max_f32, i32, i32, i32)
+DEF_HELPER_2(neon_abd_f32, i32, i32, i32)
+DEF_HELPER_2(neon_add_f32, i32, i32, i32)
+DEF_HELPER_2(neon_sub_f32, i32, i32, i32)
+DEF_HELPER_2(neon_mul_f32, i32, i32, i32)
+DEF_HELPER_2(neon_ceq_f32, i32, i32, i32)
+DEF_HELPER_2(neon_cge_f32, i32, i32, i32)
+DEF_HELPER_2(neon_cgt_f32, i32, i32, i32)
+DEF_HELPER_2(neon_acge_f32, i32, i32, i32)
+DEF_HELPER_2(neon_acgt_f32, i32, i32, i32)
 
 /* iwmmxt_helper.c */
-DEF_HELPER_1_2(iwmmxt_maddsq, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_madduq, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_sadb, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_sadw, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_mulslw, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_mulshw, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_mululw, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_muluhw, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_macsw, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_2(iwmmxt_macuw, uint64_t, (uint64_t, uint64_t))
-DEF_HELPER_1_1(iwmmxt_setpsr_nz, uint32_t, (uint64_t))
+DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64)
+DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64)
+DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64)
 
 #define DEF_IWMMXT_HELPER_SIZE_ENV(name) \
-DEF_HELPER_1_3(iwmmxt_##name##b, uint64_t, (CPUState *, uint64_t, uint64_t)) \
-DEF_HELPER_1_3(iwmmxt_##name##w, uint64_t, (CPUState *, uint64_t, uint64_t)) \
-DEF_HELPER_1_3(iwmmxt_##name##l, uint64_t, (CPUState *, uint64_t, uint64_t)) \
+DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \
+DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \
+DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \
 
 DEF_IWMMXT_HELPER_SIZE_ENV(unpackl)
 DEF_IWMMXT_HELPER_SIZE_ENV(unpackh)
 
-DEF_HELPER_1_2(iwmmxt_unpacklub, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpackluw, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpacklul, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpackhub, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpackhuw, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpackhul, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpacklsb, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpacklsw, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpacklsl, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpackhsb, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpackhsw, uint64_t, (CPUState *, uint64_t))
-DEF_HELPER_1_2(iwmmxt_unpackhsl, uint64_t, (CPUState *, uint64_t))
+DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64)
+DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64)
 
 DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq)
 DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu)
@@ -488,61 +417,53 @@
 DEF_IWMMXT_HELPER_SIZE_ENV(subs)
 DEF_IWMMXT_HELPER_SIZE_ENV(adds)
 
-DEF_HELPER_1_3(iwmmxt_avgb0, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(iwmmxt_avgb1, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(iwmmxt_avgw0, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(iwmmxt_avgw1, uint64_t, (CPUState *, uint64_t, uint64_t))
+DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64)
 
-DEF_HELPER_1_2(iwmmxt_msadb, uint64_t, (uint64_t, uint64_t))
+DEF_HELPER_2(iwmmxt_msadb, i64, i64, i64)
 
-DEF_HELPER_1_3(iwmmxt_align, uint64_t, (uint64_t, uint64_t, uint32_t))
-DEF_HELPER_1_4(iwmmxt_insr, uint64_t, (uint64_t, uint32_t, uint32_t, uint32_t))
+DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32)
+DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32)
 
-DEF_HELPER_1_1(iwmmxt_bcstb, uint64_t, (uint32_t))
-DEF_HELPER_1_1(iwmmxt_bcstw, uint64_t, (uint32_t))
-DEF_HELPER_1_1(iwmmxt_bcstl, uint64_t, (uint32_t))
+DEF_HELPER_1(iwmmxt_bcstb, i64, i32)
+DEF_HELPER_1(iwmmxt_bcstw, i64, i32)
+DEF_HELPER_1(iwmmxt_bcstl, i64, i32)
 
-DEF_HELPER_1_1(iwmmxt_addcb, uint64_t, (uint64_t))
-DEF_HELPER_1_1(iwmmxt_addcw, uint64_t, (uint64_t))
-DEF_HELPER_1_1(iwmmxt_addcl, uint64_t, (uint64_t))
+DEF_HELPER_1(iwmmxt_addcb, i64, i64)
+DEF_HELPER_1(iwmmxt_addcw, i64, i64)
+DEF_HELPER_1(iwmmxt_addcl, i64, i64)
 
-DEF_HELPER_1_1(iwmmxt_msbb, uint32_t, (uint64_t))
-DEF_HELPER_1_1(iwmmxt_msbw, uint32_t, (uint64_t))
-DEF_HELPER_1_1(iwmmxt_msbl, uint32_t, (uint64_t))
+DEF_HELPER_1(iwmmxt_msbb, i32, i64)
+DEF_HELPER_1(iwmmxt_msbw, i32, i64)
+DEF_HELPER_1(iwmmxt_msbl, i32, i64)
 
-DEF_HELPER_1_3(iwmmxt_srlw, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_srll, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_srlq, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_sllw, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_slll, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_sllq, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_sraw, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_sral, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_sraq, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_rorw, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_rorl, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_rorq, uint64_t, (CPUState *, uint64_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_shufh, uint64_t, (CPUState *, uint64_t, uint32_t))
+DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32)
+DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32)
 
-DEF_HELPER_1_3(iwmmxt_packuw, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(iwmmxt_packul, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(iwmmxt_packuq, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(iwmmxt_packsw, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(iwmmxt_packsl, uint64_t, (CPUState *, uint64_t, uint64_t))
-DEF_HELPER_1_3(iwmmxt_packsq, uint64_t, (CPUState *, uint64_t, uint64_t))
+DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64)
+DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64)
 
-DEF_HELPER_1_3(iwmmxt_muladdsl, uint64_t, (uint64_t, uint32_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_muladdsw, uint64_t, (uint64_t, uint32_t, uint32_t))
-DEF_HELPER_1_3(iwmmxt_muladdswl, uint64_t, (uint64_t, uint32_t, uint32_t))
+DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32)
+DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32)
+DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32)
 
-#undef DEF_HELPER
-#undef DEF_HELPER_0_0
-#undef DEF_HELPER_0_1
-#undef DEF_HELPER_0_2
-#undef DEF_HELPER_0_3
-#undef DEF_HELPER_1_0
-#undef DEF_HELPER_1_1
-#undef DEF_HELPER_1_2
-#undef DEF_HELPER_1_3
-#undef DEF_HELPER_1_4
-#undef GEN_HELPER
+DEF_HELPER_2(set_teecr, void, env, i32)
+
+#include "def-helper.h"
diff --git a/target-arm/iwmmxt_helper.c b/target-arm/iwmmxt_helper.c
index 6e801c8..2e4193e 100644
--- a/target-arm/iwmmxt_helper.c
+++ b/target-arm/iwmmxt_helper.c
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 
 #include <stdlib.h>
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 3368741..b1deacb 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -1,31 +1,6 @@
 #include "hw/hw.h"
 #include "hw/boards.h"
 
-void register_machines(void)
-{
-#if 0  /* ANDROID */
-    qemu_register_machine(&integratorcp_machine);
-    qemu_register_machine(&versatilepb_machine);
-    qemu_register_machine(&versatileab_machine);
-    qemu_register_machine(&realview_machine);
-    qemu_register_machine(&akitapda_machine);
-    qemu_register_machine(&spitzpda_machine);
-    qemu_register_machine(&borzoipda_machine);
-    qemu_register_machine(&terrierpda_machine);
-    qemu_register_machine(&palmte_machine);
-    qemu_register_machine(&n800_machine);
-    qemu_register_machine(&n810_machine);
-    qemu_register_machine(&lm3s811evb_machine);
-    qemu_register_machine(&lm3s6965evb_machine);
-    qemu_register_machine(&connex_machine);
-    qemu_register_machine(&verdex_machine);
-    qemu_register_machine(&mainstone2_machine);
-    qemu_register_machine(&musicpal_machine);
-    qemu_register_machine(&tosapda_machine);
-#endif
-    qemu_register_machine(&android_arm_machine);
-}
-
 void cpu_save(QEMUFile *f, void *opaque)
 {
     int i;
@@ -214,5 +189,3 @@
 
     return 0;
 }
-
-
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 4ee5658..35fbaf5 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -456,11 +456,11 @@
     if (tmp >= sizeof(src1) * 8) { \
         dest = 0; \
     } else if (tmp < -sizeof(src1) * 8) { \
-        dest >>= sizeof(src1) * 8 - 1; \
+        dest = src1 >> (sizeof(src1) * 8 - 1); \
     } else if (tmp == -sizeof(src1) * 8) { \
         dest = src1 >> (tmp - 1); \
         dest++; \
-        src2 >>= 1; \
+        dest >>= 1; \
     } else if (tmp < 0) { \
         dest = (src1 + (1 << (-1 - tmp))) >> -tmp; \
     } else { \
diff --git a/target-arm/op_addsub.h b/target-arm/op_addsub.h
index 376ee27..29f77ba 100644
--- a/target-arm/op_addsub.h
+++ b/target-arm/op_addsub.h
@@ -8,9 +8,9 @@
  */
 
 #ifdef ARITH_GE
-#define GE_ARG , uint32_t *gep
+#define GE_ARG , void *gep
 #define DECLARE_GE uint32_t ge = 0
-#define SET_GE *gep = ge
+#define SET_GE *(uint32_t *)gep = ge
 #else
 #define GE_ARG
 #define DECLARE_GE do{}while(0)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 36de55b..05eb558 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include "exec.h"
 #include "helpers.h"
@@ -31,7 +31,7 @@
 
 /* thread support */
 
-spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
 
 void cpu_lock(void)
 {
@@ -56,7 +56,7 @@
     for (shift = 0; shift < 32; shift += 8) {
         index = (ireg >> shift) & 0xff;
         if (index < maxindex) {
-            tmp = (table[index >> 3] >> (index & 7)) & 0xff;
+            tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
             val |= tmp << shift;
         } else {
             val |= def & (0xff << shift);
@@ -70,7 +70,7 @@
 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
 
 #define MMUSUFFIX _mmu
-#define ALIGNED_ONLY  1
+//#define ALIGNED_ONLY  1
 
 #define SHIFT 0
 #include "softmmu_template.h"
@@ -129,117 +129,20 @@
     env = saved_env;
 }
 
-#if 1
-#include <string.h>
-/*
- * The following functions are address translation helper functions 
- * for fast memory access in QEMU. 
- */
-static target_phys_addr_t v2p_mmu(target_ulong addr, int mmu_idx)
-{
-    int index;
-    target_ulong tlb_addr;
-    target_phys_addr_t physaddr;
-    void *retaddr;
-
-    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-redo:
-    tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
-    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
-        physaddr = addr + env->tlb_table[mmu_idx][index].addend;
-    } else {
-        /* the page is not in the TLB : fill it */
-        retaddr = GETPC();
-        tlb_fill(addr, 0, mmu_idx, retaddr);
-        goto redo;
-    }
-    return physaddr;
-}
-
-/* 
- * translation from virtual address of simulated OS 
- * to the address of simulation host (not the physical 
- * address of simulated OS.
- */
-target_phys_addr_t v2p(target_ulong ptr, int mmu_idx)
-{
-    CPUState *saved_env;
-    int index;
-    target_ulong addr;
-    target_phys_addr_t physaddr;
-
-    saved_env = env;
-    env = cpu_single_env;
-    addr = ptr;
-    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-    if (__builtin_expect(env->tlb_table[mmu_idx][index].addr_read != 
-                (addr & TARGET_PAGE_MASK), 0)) 
-    {
-        physaddr = v2p_mmu(addr, mmu_idx);
-    } else {
-        physaddr = (target_phys_addr_t)addr + env->tlb_table[mmu_idx][index].addend;
-    }
-    env = saved_env;
-    return physaddr;
-}
-
-#define MINSIZE(x,y)    ((x) < (y) ? (x) : (y))
-/* copy memory from the simulated virtual space to a buffer in QEMU */
-void vmemcpy(target_ulong ptr, char *buf, int size)
-{
-    if (buf == NULL) return;
-    while (size) {
-        int page_remain = TARGET_PAGE_SIZE - (ptr & ~TARGET_PAGE_MASK);
-        int to_copy = MINSIZE(size, page_remain);
-        char *phys = (char *)v2p(ptr, 0);
-        if (phys == NULL) return;
-        memcpy(buf, phys, to_copy);
-        ptr += to_copy;
-        buf += to_copy;
-        size -= to_copy;
-    }
-}
-
-/* copy memory from the QEMU buffer to simulated virtual space */
-void pmemcpy(target_ulong ptr, const char *buf, int size)
-{
-    if (buf == NULL) return;
-    while (size) {
-        int page_remain = TARGET_PAGE_SIZE - (ptr & ~TARGET_PAGE_MASK);
-        int to_copy = MINSIZE(size, page_remain);
-        char *phys = (char *)v2p(ptr, 0);
-        if (phys == NULL) return;
-        memcpy(phys, buf, to_copy);
-        ptr += to_copy;
-        buf += to_copy;
-        size -= to_copy;
-    }
-}
-
 /* copy a string from the simulated virtual space to a buffer in QEMU */
 void vstrcpy(target_ulong ptr, char *buf, int max)
 {
-    char *phys = 0;
-    unsigned long page = 0;
+    int  index;
 
     if (buf == NULL) return;
 
-    while (max) {
-        if ((ptr & TARGET_PAGE_MASK) != page) {
-            phys = (char *)v2p(ptr, 0);
-            page = ptr & TARGET_PAGE_MASK;
-        }
-        *buf = *phys;
-        if (*phys == '\0')
-            return;
-        ptr ++;
-        buf ++;
-        phys ++;
-        max --;
+    for (index = 0; index < max; index += 1) {
+        cpu_physical_memory_read(ptr + index, buf + index, 1);
+        if (buf[index] == 0)
+            break;
     }
 }
 #endif
-#endif
 
 /* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating
    instructions into helper.c  */
@@ -434,7 +337,7 @@
 uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
 {
     uint32_t result;
-    result = T0 + T1;
+    result = a + b;
     env->NF = env->ZF = result;
     env->CF = result < a;
     env->VF = (a ^ b ^ -1) & (a ^ result);
@@ -636,7 +539,6 @@
     rm = ((T1 & 0xff00ff00) >> 8) | (T0 & 0xff00ff00);
     T0 = rd;
     T1 = rm;
-    FORCE_RET();
 }
 
 void HELPER(neon_trn_u16)(void)
@@ -647,7 +549,6 @@
     rm = (T1 >> 16) | (T0 & 0xffff0000);
     T0 = rd;
     T1 = rm;
-    FORCE_RET();
 }
 
 /* Worker routines for zip and unzip.  */
@@ -661,7 +562,6 @@
          | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000);
     T0 = rd;
     T1 = rm;
-    FORCE_RET();
 }
 
 void HELPER(neon_zip_u8)(void)
@@ -674,7 +574,6 @@
          | ((T0 >> 8) & 0xff0000) | (T1 & 0xff000000);
     T0 = rd;
     T1 = rm;
-    FORCE_RET();
 }
 
 void HELPER(neon_zip_u16)(void)
@@ -684,5 +583,4 @@
     tmp = (T0 & 0xffff) | (T1 << 16);
     T1 = (T1 & 0xffff0000) | (T0 >> 16);
     T0 = tmp;
-    FORCE_RET();
 }
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 23db9f7..b6e1a34 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include <stdarg.h>
 #include <stdlib.h>
@@ -35,6 +35,7 @@
 #include "trace.h"
 #endif
 
+#include "helpers.h"
 #define GEN_HELPER 1
 #include "helpers.h"
 
@@ -44,7 +45,7 @@
 #define ENABLE_ARCH_6T2   arm_feature(env, ARM_FEATURE_THUMB2)
 #define ENABLE_ARCH_7     arm_feature(env, ARM_FEATURE_V7)
 
-#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op;
+#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0)
 
 /* internal defines */
 typedef struct DisasContext {
@@ -57,10 +58,10 @@
     /* Thumb-2 condtional execution bits.  */
     int condexec_mask;
     int condexec_cond;
+    int condexec_mask_prev;  /* mask at start of instruction/block */
     struct TranslationBlock *tb;
     int singlestep_enabled;
     int thumb;
-    int is_mem;
 #if !defined(CONFIG_USER_ONLY)
     int user;
 #endif
@@ -74,20 +75,21 @@
 
 #ifdef CONFIG_TRACE
 #include "helpers.h"
-#endif
+#endif /* CONFIG_TRACE */
 
 /* These instructions trap after executing, so defer them until after the
    conditional executions state has been updated.  */
 #define DISAS_WFI 4
 #define DISAS_SWI 5
 
-static TCGv cpu_env;
+static TCGv_ptr cpu_env;
 /* We reuse the same 64-bit temporaries for efficiency.  */
-static TCGv cpu_V0, cpu_V1, cpu_M0;
+static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
 
 /* FIXME:  These should be removed.  */
 static TCGv cpu_T[2];
-static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d;
+static TCGv cpu_F0s, cpu_F1s;
+static TCGv_i64 cpu_F0d, cpu_F1d;
 
 #define ICOUNT_TEMP cpu_T[0]
 #include "gen-icount.h"
@@ -95,10 +97,13 @@
 /* initialize TCG globals.  */
 void arm_translate_init(void)
 {
-    cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
 
-    cpu_T[0] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG1, "T0");
-    cpu_T[1] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG2, "T1");
+    cpu_T[0] = tcg_global_reg_new_i32(TCG_AREG1, "T0");
+    cpu_T[1] = tcg_global_reg_new_i32(TCG_AREG2, "T1");
+
+#define GEN_HELPER 2
+#include "helpers.h"
 }
 
 /* The code generator doesn't like lots of temporaries, so maintain our own
@@ -108,16 +113,16 @@
 static TCGv temps[MAX_TEMPS];
 
 /* Allocate a temporary variable.  */
-static TCGv new_tmp(void)
+static TCGv_i32 new_tmp(void)
 {
     TCGv tmp;
     if (num_temps == MAX_TEMPS)
         abort();
 
-    if (GET_TCGV(temps[num_temps]))
+    if (GET_TCGV_I32(temps[num_temps]))
       return temps[num_temps++];
 
-    tmp = tcg_temp_new(TCG_TYPE_I32);
+    tmp = tcg_temp_new_i32();
     temps[num_temps++] = tmp;
     return tmp;
 }
@@ -128,11 +133,11 @@
     int i;
     num_temps--;
     i = num_temps;
-    if (GET_TCGV(temps[i]) == GET_TCGV(tmp))
+    if (TCGV_EQUAL(temps[i], tmp))
         return;
 
     /* Shuffle this temp to the last slot.  */
-    while (GET_TCGV(temps[i]) != GET_TCGV(tmp))
+    while (!TCGV_EQUAL(temps[i], tmp))
         i--;
     while (i < num_temps) {
         temps[i] = temps[i + 1];
@@ -198,7 +203,6 @@
 
 /* Basic operations.  */
 #define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1])
-#define gen_op_movl_T1_T0() tcg_gen_mov_i32(cpu_T[1], cpu_T[0])
 #define gen_op_movl_T0_im(im) tcg_gen_movi_i32(cpu_T[0], im)
 #define gen_op_movl_T1_im(im) tcg_gen_movi_i32(cpu_T[1], im)
 
@@ -212,7 +216,6 @@
 #define gen_op_subl_T0_T1_cc() gen_helper_sub_cc(cpu_T[0], cpu_T[0], cpu_T[1])
 #define gen_op_sbcl_T0_T1_cc() gen_helper_sbc_cc(cpu_T[0], cpu_T[0], cpu_T[1])
 #define gen_op_rsbl_T0_T1_cc() gen_helper_sub_cc(cpu_T[0], cpu_T[1], cpu_T[0])
-#define gen_op_rscl_T0_T1_cc() gen_helper_sbc_cc(cpu_T[0], cpu_T[1], cpu_T[0])
 
 #define gen_op_andl_T0_T1() tcg_gen_and_i32(cpu_T[0], cpu_T[0], cpu_T[1])
 #define gen_op_xorl_T0_T1() tcg_gen_xor_i32(cpu_T[0], cpu_T[0], cpu_T[1])
@@ -222,11 +225,8 @@
 #define gen_op_logic_T0_cc() gen_logic_CC(cpu_T[0]);
 #define gen_op_logic_T1_cc() gen_logic_CC(cpu_T[1]);
 
-#define gen_op_shll_T0_im(im) tcg_gen_shli_i32(cpu_T[0], cpu_T[0], im)
 #define gen_op_shll_T1_im(im) tcg_gen_shli_i32(cpu_T[1], cpu_T[1], im)
 #define gen_op_shrl_T1_im(im) tcg_gen_shri_i32(cpu_T[1], cpu_T[1], im)
-#define gen_op_sarl_T1_im(im) tcg_gen_sari_i32(cpu_T[1], cpu_T[1], im)
-#define gen_op_rorl_T1_im(im) tcg_gen_rori_i32(cpu_T[1], cpu_T[1], im)
 
 /* Value extensions.  */
 #define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
@@ -243,38 +243,6 @@
 /* Set NZCV flags from the high 4 bits of var.  */
 #define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
 
-#ifdef CONFIG_TRACE
-static void  gen_traceTicks(int  count)
-{
-    TCGv  t0 = new_tmp();
-    tcg_gen_movi_i32(t0, count);
-    gen_helper_traceTicks(t0);
-    dead_tmp(t0);
-}
-
-static void gen_traceBB(uint64_t  bb_num, target_phys_addr_t  tb)
-{
-#if HOST_LONG_BITS ==64
-    TCGv  t0 = tcg_const_i64(bb_num);
-    TCGv  t1 = tcg_const_i64(tb);
-    gen_helper_traceBB64(t0, t1);
-    tcg_temp_free(t1);
-    tcg_temp_free(t0);
-#else
-    TCGv  t0 = new_tmp();
-    TCGv  t1 = new_tmp();
-    TCGv  t2 = new_tmp();
-    tcg_gen_movi_i32(t0, (int32_t)(bb_num >> 32));
-    tcg_gen_movi_i32(t1, (int32_t)(bb_num));
-    tcg_gen_movi_i32(t2, (int32_t)tb);
-    gen_helper_traceBB32(t0, t1, t2);
-    dead_tmp(t2);
-    dead_tmp(t1);
-    dead_tmp(t0);
-#endif
-}
-#endif /* CONFIG_TRACE */
-
 static void gen_exception(int excp)
 {
     TCGv tmp = new_tmp();
@@ -364,10 +332,10 @@
 /* FIXME: Most targets have native widening multiplication.
    It would be good to use that instead of a full wide multiply.  */
 /* 32x32->64 multiply.  Marks inputs as dead.  */
-static TCGv gen_mulu_i64_i32(TCGv a, TCGv b)
+static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
 {
-    TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
-    TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
 
     tcg_gen_extu_i32_i64(tmp1, a);
     dead_tmp(a);
@@ -377,10 +345,10 @@
     return tmp1;
 }
 
-static TCGv gen_muls_i64_i32(TCGv a, TCGv b)
+static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
 {
-    TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
-    TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
 
     tcg_gen_ext_i32_i64(tmp1, a);
     dead_tmp(a);
@@ -393,8 +361,8 @@
 /* Unsigned 32x32->64 multiply.  */
 static void gen_op_mull_T0_T1(void)
 {
-    TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
-    TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
 
     tcg_gen_extu_i32_i64(tmp1, cpu_T[0]);
     tcg_gen_extu_i32_i64(tmp2, cpu_T[1]);
@@ -407,8 +375,8 @@
 /* Signed 32x32->64 multiply.  */
 static void gen_imull(TCGv a, TCGv b)
 {
-    TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
-    TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 tmp1 = tcg_temp_new_i64();
+    TCGv_i64 tmp2 = tcg_temp_new_i64();
 
     tcg_gen_ext_i32_i64(tmp1, a);
     tcg_gen_ext_i32_i64(tmp2, b);
@@ -456,7 +424,7 @@
 {
     TCGv tmp = new_tmp();
     tcg_gen_shri_i32(tmp, var, 31);
-    gen_set_CF(var);
+    gen_set_CF(tmp);
     dead_tmp(tmp);
 }
 
@@ -477,6 +445,16 @@
     dead_tmp(tmp);
 }
 
+/* dest = T0 + T1 + CF. */
+static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
+{
+    TCGv tmp;
+    tcg_gen_add_i32(dest, t0, t1);
+    tmp = load_cpu_field(CF);
+    tcg_gen_add_i32(dest, dest, tmp);
+    dead_tmp(tmp);
+}
+
 /* dest = T0 - T1 + CF - 1.  */
 static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
 {
@@ -531,7 +509,7 @@
         tcg_gen_andi_i32(tmp, var, 1);
     } else {
         tcg_gen_shri_i32(tmp, var, shift);
-        if (shift != 31);
+        if (shift != 31)
             tcg_gen_andi_i32(tmp, tmp, 1);
     }
     gen_set_CF(tmp);
@@ -620,17 +598,17 @@
     }
 static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
 {
-    TCGv tmp;
+    TCGv_ptr tmp;
 
     switch (op1) {
 #define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
     case 1:
-        tmp = tcg_temp_new(TCG_TYPE_PTR);
+        tmp = tcg_temp_new_ptr();
         tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
         PAS_OP(s)
         break;
     case 5:
-        tmp = tcg_temp_new(TCG_TYPE_PTR);
+        tmp = tcg_temp_new_ptr();
         tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
         PAS_OP(u)
         break;
@@ -665,17 +643,17 @@
     }
 static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
 {
-    TCGv tmp;
+    TCGv_ptr tmp;
 
     switch (op1) {
 #define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
     case 0:
-        tmp = tcg_temp_new(TCG_TYPE_PTR);
+        tmp = tcg_temp_new_ptr();
         tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
         PAS_OP(s)
         break;
     case 4:
-        tmp = tcg_temp_new(TCG_TYPE_PTR);
+        tmp = tcg_temp_new_ptr();
         tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
         PAS_OP(u)
         break;
@@ -796,7 +774,7 @@
     dead_tmp(tmp);
 }
 
-const uint8_t table_logic_cc[16] = {
+static const uint8_t table_logic_cc[16] = {
     1, /* and */
     1, /* xor */
     0, /* sub */
@@ -852,17 +830,19 @@
     gen_bx(s, tmp);
 }
 
-#if defined(CONFIG_USER_ONLY)
-#define gen_ldst(name, s) gen_op_##name##_raw()
-#else
-#define gen_ldst(name, s) do { \
-    s->is_mem = 1; \
-    if (IS_USER(s)) \
-        gen_op_##name##_user(); \
-    else \
-        gen_op_##name##_kernel(); \
-    } while (0)
-#endif
+/* Variant of store_reg which uses branch&exchange logic when storing
+   to r15 in ARM architecture v7 and above. The source must be a temporary
+   and will be marked as dead. */
+static inline void store_reg_bx(CPUState *env, DisasContext *s,
+                                int reg, TCGv var)
+{
+    if (reg == 15 && ENABLE_ARCH_7) {
+        gen_bx(s, var);
+    } else {
+        store_reg(s, reg, var);
+    }
+}
+
 static inline TCGv gen_ld8s(TCGv addr, int index)
 {
     TCGv tmp = new_tmp();
@@ -1030,15 +1010,6 @@
         gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \
 }
 
-#define VFP_OP1(name)                               \
-static inline void gen_vfp_##name(int dp, int arg)  \
-{                                                   \
-    if (dp)                                         \
-        gen_op_vfp_##name##d(arg);                  \
-    else                                            \
-        gen_op_vfp_##name##s(arg);                  \
-}
-
 VFP_OP2(add)
 VFP_OP2(sub)
 VFP_OP2(mul)
@@ -1221,12 +1192,12 @@
     dead_tmp(var);
 }
 
-static inline void neon_load_reg64(TCGv var, int reg)
+static inline void neon_load_reg64(TCGv_i64 var, int reg)
 {
     tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
 }
 
-static inline void neon_store_reg64(TCGv var, int reg)
+static inline void neon_store_reg64(TCGv_i64 var, int reg)
 {
     tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
 }
@@ -1262,12 +1233,12 @@
 
 #define ARM_CP_RW_BIT	(1 << 20)
 
-static inline void iwmmxt_load_reg(TCGv var, int reg)
+static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
 {
     tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
 }
 
-static inline void iwmmxt_store_reg(TCGv var, int reg)
+static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
 {
     tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
 }
@@ -1487,10 +1458,7 @@
 
 static void gen_iwmmxt_movl_wRn_T0_T1(int rn)
 {
-    tcg_gen_extu_i32_i64(cpu_V0, cpu_T[0]);
-    tcg_gen_extu_i32_i64(cpu_V1, cpu_T[0]);
-    tcg_gen_shli_i64(cpu_V1, cpu_V1, 32);
-    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
+    tcg_gen_concat_i32_i64(cpu_V0, cpu_T[0], cpu_T[1]);
     iwmmxt_store_reg(cpu_V0, rn);
 }
 
@@ -2847,10 +2815,12 @@
                         } else if (size == 1) {
                             gen_neon_dup_low16(tmp);
                         }
-                        tmp2 = new_tmp();
-                        tcg_gen_mov_i32(tmp2, tmp);
-                        neon_store_reg(rn, 0, tmp2);
-                        neon_store_reg(rn, 0, tmp);
+                        for (n = 0; n <= pass * 2; n++) {
+                            tmp2 = new_tmp();
+                            tcg_gen_mov_i32(tmp2, tmp);
+                            neon_store_reg(rn, n, tmp2);
+                        }
+                        neon_store_reg(rn, n, tmp);
                     } else {
                         /* VMOV */
                         switch (size) {
@@ -3065,6 +3035,10 @@
                 case 21:
                 case 22:
                 case 23:
+                case 28:
+                case 29:
+                case 30:
+                case 31:
                     /* Source and destination the same.  */
                     gen_mov_F0_vreg(dp, rd);
                     break;
@@ -3100,9 +3074,9 @@
                     break;
                 case 3: /* nmsc: -fd - (fn * fm)  */
                     gen_vfp_mul(dp);
-                    gen_mov_F1_vreg(dp, rd);
-                    gen_vfp_add(dp);
                     gen_vfp_neg(dp);
+                    gen_mov_F1_vreg(dp, rd);
+                    gen_vfp_sub(dp);
                     break;
                 case 4: /* mul: fn * fm */
                     gen_vfp_mul(dp);
@@ -3184,22 +3158,22 @@
                     case 20: /* fshto */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_shto(dp, rm);
+                        gen_vfp_shto(dp, 16 - rm);
                         break;
                     case 21: /* fslto */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_slto(dp, rm);
+                        gen_vfp_slto(dp, 32 - rm);
                         break;
                     case 22: /* fuhto */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_uhto(dp, rm);
+                        gen_vfp_uhto(dp, 16 - rm);
                         break;
                     case 23: /* fulto */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_ulto(dp, rm);
+                        gen_vfp_ulto(dp, 32 - rm);
                         break;
                     case 24: /* ftoui */
                         gen_vfp_toui(dp);
@@ -3216,22 +3190,22 @@
                     case 28: /* ftosh */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_tosh(dp, rm);
+                        gen_vfp_tosh(dp, 16 - rm);
                         break;
                     case 29: /* ftosl */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_tosl(dp, rm);
+                        gen_vfp_tosl(dp, 32 - rm);
                         break;
                     case 30: /* ftouh */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_touh(dp, rm);
+                        gen_vfp_touh(dp, 16 - rm);
                         break;
                     case 31: /* ftoul */
                         if (!arm_feature(env, ARM_FEATURE_VFP3))
                           return 1;
-                        gen_vfp_toul(dp, rm);
+                        gen_vfp_toul(dp, 32 - rm);
                         break;
                     default: /* undefined */
                         printf ("rn:%d\n", rn);
@@ -3504,11 +3478,11 @@
     return 0;
 }
 
-/* Generate an old-style exception return.  */
-static void gen_exception_return(DisasContext *s)
+/* Generate an old-style exception return. Marks pc as dead. */
+static void gen_exception_return(DisasContext *s, TCGv pc)
 {
     TCGv tmp;
-    gen_movl_reg_T0(s, 15);
+    store_reg(s, 15, pc);
     tmp = load_cpu_field(spsr);
     gen_set_cpsr(tmp, 0xffffffff);
     dead_tmp(tmp);
@@ -3533,6 +3507,11 @@
         tcg_gen_movi_i32(tmp, val);
         store_cpu_field(tmp, condexec_bits);
     }
+    else if (s->condexec_mask_prev != 0) {
+        TCGv tmp = new_tmp();
+        tcg_gen_movi_i32(tmp, 0);
+        store_cpu_field(tmp, condexec_bits);
+    }
 }
 
 static void gen_nop_hint(DisasContext *s, int val)
@@ -3846,7 +3825,7 @@
                     gen_neon_dup_low16(tmp);
                     break;
                 case 2:
-                    tmp = gen_ld32(cpu_T[0], IS_USER(s));
+                    tmp = gen_ld32(cpu_T[1], IS_USER(s));
                     break;
                 case 3:
                     return 1;
@@ -3857,7 +3836,7 @@
                 tmp2 = new_tmp();
                 tcg_gen_mov_i32(tmp2, tmp);
                 neon_store_reg(rd, 0, tmp2);
-                neon_store_reg(rd, 0, tmp);
+                neon_store_reg(rd, 1, tmp);
                 rd += stride;
             }
             stride = (1 << size) * nregs;
@@ -3950,7 +3929,7 @@
     tcg_gen_or_i32(dest, t, f);
 }
 
-static inline void gen_neon_narrow(int size, TCGv dest, TCGv src)
+static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src)
 {
     switch (size) {
     case 0: gen_helper_neon_narrow_u8(dest, src); break;
@@ -3960,7 +3939,7 @@
     }
 }
 
-static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv src)
+static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
 {
     switch (size) {
     case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
@@ -3970,7 +3949,7 @@
     }
 }
 
-static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv src)
+static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
 {
     switch (size) {
     case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
@@ -4014,7 +3993,7 @@
     }
 }
 
-static inline void gen_neon_widen(TCGv dest, TCGv src, int size, int u)
+static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)
 {
     if (u) {
         switch (size) {
@@ -4054,7 +4033,7 @@
     }
 }
 
-static inline void gen_neon_negl(TCGv var, int size)
+static inline void gen_neon_negl(TCGv_i64 var, int size)
 {
     switch (size) {
     case 0: gen_helper_neon_negl_u16(var, var); break;
@@ -4064,7 +4043,7 @@
     }
 }
 
-static inline void gen_neon_addl_saturate(TCGv op0, TCGv op1, int size)
+static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
 {
     switch (size) {
     case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break;
@@ -4073,9 +4052,9 @@
     }
 }
 
-static inline void gen_neon_mull(TCGv dest, TCGv a, TCGv b, int size, int u)
+static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
 {
-    TCGv tmp;
+    TCGv_i64 tmp;
 
     switch ((size << 1) | u) {
     case 0: gen_helper_neon_mull_s8(dest, a, b); break;
@@ -4119,6 +4098,7 @@
     TCGv tmp;
     TCGv tmp2;
     TCGv tmp3;
+    TCGv_i64 tmp64;
 
     if (!vfp_enabled(env))
       return 1;
@@ -4675,12 +4655,16 @@
                     imm = (uint16_t)shift;
                     imm |= imm << 16;
                     tmp2 = tcg_const_i32(imm);
+                    TCGV_UNUSED_I64(tmp64);
                     break;
                 case 2:
                     imm = (uint32_t)shift;
                     tmp2 = tcg_const_i32(imm);
+                    TCGV_UNUSED_I64(tmp64);
+                    break;
                 case 3:
-                    tmp2 = tcg_const_i64(shift);
+                    tmp64 = tcg_const_i64(shift);
+                    TCGV_UNUSED(tmp2);
                     break;
                 default:
                     abort();
@@ -4691,26 +4675,23 @@
                         neon_load_reg64(cpu_V0, rm + pass);
                         if (q) {
                           if (u)
-                            gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp2);
+                            gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp64);
                           else
-                            gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp2);
+                            gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp64);
                         } else {
                           if (u)
-                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp2);
+                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp64);
                           else
-                            gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp2);
+                            gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp64);
                         }
                     } else {
                         tmp = neon_load_reg(rm + pass, 0);
                         gen_neon_shift_narrow(size, tmp, tmp2, q, u);
-                        tcg_gen_extu_i32_i64(cpu_V0, tmp);
+                        tmp3 = neon_load_reg(rm + pass, 1);
+                        gen_neon_shift_narrow(size, tmp3, tmp2, q, u);
+                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
                         dead_tmp(tmp);
-                        tmp = neon_load_reg(rm + pass, 1);
-                        gen_neon_shift_narrow(size, tmp, tmp2, q, u);
-                        tcg_gen_extu_i32_i64(cpu_V1, tmp);
-                        dead_tmp(tmp);
-                        tcg_gen_shli_i64(cpu_V1, cpu_V1, 32);
-                        tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
+                        dead_tmp(tmp3);
                     }
                     tmp = new_tmp();
                     if (op == 8 && !u) {
@@ -4854,7 +4835,7 @@
                 neon_store_reg(rd, pass, tmp);
             }
         }
-    } else { /* (insn & 0x00800010 == 0x00800010) */
+    } else { /* (insn & 0x00800010 == 0x00800000) */
         if (size != 3) {
             op = (insn >> 8) & 0xf;
             if ((insn & (1 << 6)) == 0) {
@@ -5176,16 +5157,16 @@
                         neon_load_reg64(cpu_V1, rm);
                     }
                 } else if (q) {
-                    tmp = tcg_temp_new(TCG_TYPE_I64);
+                    tmp64 = tcg_temp_new_i64();
                     if (imm < 8) {
                         neon_load_reg64(cpu_V0, rn);
-                        neon_load_reg64(tmp, rn + 1);
+                        neon_load_reg64(tmp64, rn + 1);
                     } else {
                         neon_load_reg64(cpu_V0, rn + 1);
-                        neon_load_reg64(tmp, rm);
+                        neon_load_reg64(tmp64, rm);
                     }
                     tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
-                    tcg_gen_shli_i64(cpu_V1, tmp, 64 - ((imm & 7) * 8));
+                    tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
                     tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                     if (imm < 8) {
                         neon_load_reg64(cpu_V1, rm);
@@ -5194,13 +5175,14 @@
                         imm -= 8;
                     }
                     tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
-                    tcg_gen_shri_i64(tmp, tmp, imm * 8);
-                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp);
+                    tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
+                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
                 } else {
+                    /* BUGFIX */
                     neon_load_reg64(cpu_V0, rn);
-                    tcg_gen_shri_i32(cpu_V0, cpu_V0, imm * 8);
+                    tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
                     neon_load_reg64(cpu_V1, rm);
-                    tcg_gen_shli_i32(cpu_V1, cpu_V1, 64 - (imm * 8));
+                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
                     tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                 }
                 neon_store_reg64(cpu_V0, rd);
@@ -5219,7 +5201,7 @@
                         NEON_GET_REG(T0, rm, pass * 2);
                         NEON_GET_REG(T1, rm, pass * 2 + 1);
                         switch (size) {
-                        case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
+                        case 0: tcg_gen_bswap32_i32(cpu_T[0], cpu_T[0]); break;
                         case 1: gen_swap_half(cpu_T[0]); break;
                         case 2: /* no-op */ break;
                         default: abort();
@@ -5230,7 +5212,7 @@
                         } else {
                             gen_op_movl_T0_T1();
                             switch (size) {
-                            case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
+                            case 0: tcg_gen_bswap32_i32(cpu_T[0], cpu_T[0]); break;
                             case 1: gen_swap_half(cpu_T[0]); break;
                             default: abort();
                             }
@@ -5372,7 +5354,7 @@
                         switch (op) {
                         case 1: /* VREV32 */
                             switch (size) {
-                            case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
+                            case 0: tcg_gen_bswap32_i32(cpu_T[0], cpu_T[0]); break;
                             case 1: gen_swap_half(cpu_T[0]); break;
                             default: return 1;
                             }
@@ -5544,7 +5526,7 @@
                 }
             } else if ((insn & (1 << 10)) == 0) {
                 /* VTBL, VTBX.  */
-                n = (insn >> 5) & 0x18;
+                n = ((insn >> 5) & 0x18) + 8;
                 if (insn & (1 << 6)) {
                     tmp = neon_load_reg(rd, 0);
                 } else {
@@ -5554,6 +5536,7 @@
                 tmp2 = neon_load_reg(rm, 0);
                 gen_helper_neon_tbl(tmp2, tmp2, tmp, tcg_const_i32(rn),
                                     tcg_const_i32(n));
+                dead_tmp(tmp);
                 if (insn & (1 << 6)) {
                     tmp = neon_load_reg(rd, 1);
                 } else {
@@ -5564,7 +5547,8 @@
                 gen_helper_neon_tbl(tmp3, tmp3, tmp, tcg_const_i32(rn),
                                     tcg_const_i32(n));
                 neon_store_reg(rd, 0, tmp2);
-                neon_store_reg(rd, 1, tmp2);
+                neon_store_reg(rd, 1, tmp3);
+                dead_tmp(tmp);
             } else if ((insn & 0x380) == 0) {
                 /* VDUP */
                 if (insn & (1 << 19)) {
@@ -5591,6 +5575,71 @@
     return 0;
 }
 
+static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
+{
+    int crn = (insn >> 16) & 0xf;
+    int crm = insn & 0xf;
+    int op1 = (insn >> 21) & 7;
+    int op2 = (insn >> 5) & 7;
+    int rt = (insn >> 12) & 0xf;
+    TCGv tmp;
+
+    if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
+        if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
+            /* TEECR */
+            if (IS_USER(s))
+                return 1;
+            tmp = load_cpu_field(teecr);
+            store_reg(s, rt, tmp);
+            return 0;
+        }
+        if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
+            /* TEEHBR */
+            if (IS_USER(s) && (env->teecr & 1))
+                return 1;
+            tmp = load_cpu_field(teehbr);
+            store_reg(s, rt, tmp);
+            return 0;
+        }
+    }
+    fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n",
+            op1, crn, crm, op2);
+    return 1;
+}
+
+static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn)
+{
+    int crn = (insn >> 16) & 0xf;
+    int crm = insn & 0xf;
+    int op1 = (insn >> 21) & 7;
+    int op2 = (insn >> 5) & 7;
+    int rt = (insn >> 12) & 0xf;
+    TCGv tmp;
+
+    if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
+        if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
+            /* TEECR */
+            if (IS_USER(s))
+                return 1;
+            tmp = load_reg(s, rt);
+            gen_helper_set_teecr(cpu_env, tmp);
+            dead_tmp(tmp);
+            return 0;
+        }
+        if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
+            /* TEEHBR */
+            if (IS_USER(s) && (env->teecr & 1))
+                return 1;
+            tmp = load_reg(s, rt);
+            store_cpu_field(tmp, teehbr);
+            return 0;
+        }
+    }
+    fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n",
+            op1, crn, crm, op2);
+    return 1;
+}
+
 static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
 {
     int cpnum;
@@ -5612,9 +5661,19 @@
     case 10:
     case 11:
 	return disas_vfp_insn (env, s, insn);
+    case 14:
+        /* Coprocessors 7-15 are architecturally reserved by ARM.
+           Unfortunately Intel decided to ignore this.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE))
+            goto board;
+        if (insn & (1 << 20))
+            return disas_cp14_read(env, s, insn);
+        else
+            return disas_cp14_write(env, s, insn);
     case 15:
 	return disas_cp15_insn (env, s, insn);
     default:
+    board:
 	/* Unknown coprocessor.  See if the board has hooked it.  */
 	return disas_cp_insn (env, s, insn);
     }
@@ -5622,7 +5681,7 @@
 
 
 /* Store a 64-bit value to a register pair.  Clobbers val.  */
-static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv val)
+static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
 {
     TCGv tmp;
     tmp = new_tmp();
@@ -5635,13 +5694,13 @@
 }
 
 /* load a 32-bit value from a register and perform a 64-bit accumulate.  */
-static void gen_addq_lo(DisasContext *s, TCGv val, int rlow)
+static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
 {
-    TCGv tmp;
+    TCGv_i64 tmp;
     TCGv tmp2;
 
-    /* Load 64-bit value rd:rn.  */
-    tmp = tcg_temp_new(TCG_TYPE_I64);
+    /* Load value and extend to 64 bits.  */
+    tmp = tcg_temp_new_i64();
     tmp2 = load_reg(s, rlow);
     tcg_gen_extu_i32_i64(tmp, tmp2);
     dead_tmp(tmp2);
@@ -5649,27 +5708,24 @@
 }
 
 /* load and add a 64-bit value from a register pair.  */
-static void gen_addq(DisasContext *s, TCGv val, int rlow, int rhigh)
+static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
 {
-    TCGv tmp;
-    TCGv tmp2;
+    TCGv_i64 tmp;
+    TCGv tmpl;
+    TCGv tmph;
 
     /* Load 64-bit value rd:rn.  */
-    tmp = tcg_temp_new(TCG_TYPE_I64);
-    tmp2 = load_reg(s, rhigh);
-    tcg_gen_extu_i32_i64(tmp, tmp2);
-    dead_tmp(tmp2);
-    tcg_gen_shli_i64(tmp, tmp, 32);
-    tcg_gen_add_i64(val, val, tmp);
-
-    tmp2 = load_reg(s, rlow);
-    tcg_gen_extu_i32_i64(tmp, tmp2);
-    dead_tmp(tmp2);
+    tmpl = load_reg(s, rlow);
+    tmph = load_reg(s, rhigh);
+    tmp = tcg_temp_new_i64();
+    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
+    dead_tmp(tmpl);
+    dead_tmp(tmph);
     tcg_gen_add_i64(val, val, tmp);
 }
 
 /* Set N and Z flags from a 64-bit value.  */
-static void gen_logicq_cc(TCGv val)
+static void gen_logicq_cc(TCGv_i64 val)
 {
     TCGv tmp = new_tmp();
     gen_helper_logicq_cc(tmp, val);
@@ -5677,23 +5733,63 @@
     dead_tmp(tmp);
 }
 
+
+#ifdef CONFIG_TRACE
+
+#define  gen_traceInsn()   gen_helper_traceInsn()
+
+static void
+gen_traceTicks( int  count )
+{
+    TCGv  tmp = tcg_temp_new_i32();
+    tcg_gen_movi_i32(tmp, count);
+    gen_helper_traceTicks(tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static void
+gen_traceBB( uint64_t  bbNum, target_phys_addr_t  tb )
+{
+#if HOST_LONG_BITS == 32
+    TCGv_i64  tmpNum = tcg_temp_new_i64();
+    TCGv_i32  tmpTb  = tcg_temp_new_i32();
+
+    tcg_gen_movi_i64(tmpNum, (int64_t)bbNum);
+    tcg_gen_movi_i32(tmpTb,  (int32_t)tb);
+    gen_helper_traceBB32(tmpNum, tmpTb);
+    tcg_temp_free_i32(tmpTb);
+    tcg_temp_free_i64(tmpNum);
+#elif HOST_LONG_BITS == 64
+    TCGv_i64  tmpNum = tcg_temp_new_i64();
+    TCGv_i64  tmpTb  = tcg_temp_new_i32();
+
+    tcg_gen_movi_i64(tmpNum, (int64_t)bbNum);
+    tcg_gen_movi_i64(tmpTb,  (int64_t)tb);
+    gen_helper_traceBB32(tmpNum, tmpTb);
+    tcg_temp_free_i64(tmpTb);
+    tcg_temp_free_i64(tmpNum);
+#endif
+}
+#endif /* CONFIG_TRACE */
+
 static void disas_arm_insn(CPUState * env, DisasContext *s)
 {
     unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
+#ifdef CONFIG_TRACE
+    int  ticks;
+#endif
     TCGv tmp;
     TCGv tmp2;
     TCGv tmp3;
     TCGv addr;
-#ifdef CONFIG_TRACE
-    int  ticks = 0;
-#endif
+    TCGv_i64 tmp64;
 
     insn = ldl_code(s->pc);
 #ifdef CONFIG_TRACE
     if (tracing) {
         trace_add_insn(insn, 0);
         ticks = get_insn_ticks_arm(insn);
-        gen_helper_traceInsn();
+        gen_traceInsn();
     }
 #endif
     s->pc += 4;
@@ -6046,10 +6142,10 @@
                     tcg_gen_sari_i32(tmp2, tmp2, 16);
                 else
                     gen_sxth(tmp2);
-                tmp2 = gen_muls_i64_i32(tmp, tmp2);
-                tcg_gen_shri_i64(tmp2, tmp2, 16);
+                tmp64 = gen_muls_i64_i32(tmp, tmp2);
+                tcg_gen_shri_i64(tmp64, tmp64, 16);
                 tmp = new_tmp();
-                tcg_gen_trunc_i64_i32(tmp, tmp2);
+                tcg_gen_trunc_i64_i32(tmp, tmp64);
                 if ((sh & 2) == 0) {
                     tmp2 = load_reg(s, rn);
                     gen_helper_add_setq(tmp, tmp, tmp2);
@@ -6063,11 +6159,11 @@
                 gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
                 dead_tmp(tmp2);
                 if (op1 == 2) {
-                    tmp2 = tcg_temp_new(TCG_TYPE_I64);
-                    tcg_gen_ext_i32_i64(tmp2, tmp);
+                    tmp64 = tcg_temp_new_i64();
+                    tcg_gen_ext_i32_i64(tmp64, tmp);
                     dead_tmp(tmp);
-                    gen_addq(s, tmp2, rn, rd);
-                    gen_storeq_reg(s, rn, rd, tmp2);
+                    gen_addq(s, tmp64, rn, rd);
+                    gen_storeq_reg(s, rn, rd, tmp64);
                 } else {
                     if (op1 == 0) {
                         tmp2 = load_reg(s, rn);
@@ -6095,148 +6191,173 @@
             /* immediate operand */
             val = insn & 0xff;
             shift = ((insn >> 8) & 0xf) * 2;
-            if (shift)
+            if (shift) {
                 val = (val >> shift) | (val << (32 - shift));
-            gen_op_movl_T1_im(val);
-            if (logic_cc && shift)
-                gen_set_CF_bit31(cpu_T[1]);
+            }
+            tmp2 = new_tmp();
+            tcg_gen_movi_i32(tmp2, val);
+            if (logic_cc && shift) {
+                gen_set_CF_bit31(tmp2);
+            }
         } else {
             /* register */
             rm = (insn) & 0xf;
-            gen_movl_T1_reg(s, rm);
+            tmp2 = load_reg(s, rm);
             shiftop = (insn >> 5) & 3;
             if (!(insn & (1 << 4))) {
                 shift = (insn >> 7) & 0x1f;
-                gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
+                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
             } else {
                 rs = (insn >> 8) & 0xf;
                 tmp = load_reg(s, rs);
-                gen_arm_shift_reg(cpu_T[1], shiftop, tmp, logic_cc);
+                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
             }
         }
         if (op1 != 0x0f && op1 != 0x0d) {
             rn = (insn >> 16) & 0xf;
-            gen_movl_T0_reg(s, rn);
+            tmp = load_reg(s, rn);
+        } else {
+            TCGV_UNUSED(tmp);
         }
         rd = (insn >> 12) & 0xf;
         switch(op1) {
         case 0x00:
-            gen_op_andl_T0_T1();
-            gen_movl_reg_T0(s, rd);
-            if (logic_cc)
-                gen_op_logic_T0_cc();
+            tcg_gen_and_i32(tmp, tmp, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 0x01:
-            gen_op_xorl_T0_T1();
-            gen_movl_reg_T0(s, rd);
-            if (logic_cc)
-                gen_op_logic_T0_cc();
+            tcg_gen_xor_i32(tmp, tmp, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 0x02:
             if (set_cc && rd == 15) {
                 /* SUBS r15, ... is used for exception return.  */
-                if (IS_USER(s))
+                if (IS_USER(s)) {
                     goto illegal_op;
-                gen_op_subl_T0_T1_cc();
-                gen_exception_return(s);
+                }
+                gen_helper_sub_cc(tmp, tmp, tmp2);
+                gen_exception_return(s, tmp);
             } else {
-                if (set_cc)
-                    gen_op_subl_T0_T1_cc();
-                else
-                    gen_op_subl_T0_T1();
-                gen_movl_reg_T0(s, rd);
+                if (set_cc) {
+                    gen_helper_sub_cc(tmp, tmp, tmp2);
+                } else {
+                    tcg_gen_sub_i32(tmp, tmp, tmp2);
+                }
+                store_reg_bx(env, s, rd, tmp);
             }
             break;
         case 0x03:
-            if (set_cc)
-                gen_op_rsbl_T0_T1_cc();
-            else
-                gen_op_rsbl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            if (set_cc) {
+                gen_helper_sub_cc(tmp, tmp2, tmp);
+            } else {
+                tcg_gen_sub_i32(tmp, tmp2, tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 0x04:
-            if (set_cc)
-                gen_op_addl_T0_T1_cc();
-            else
-                gen_op_addl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            if (set_cc) {
+                gen_helper_add_cc(tmp, tmp, tmp2);
+            } else {
+                tcg_gen_add_i32(tmp, tmp, tmp2);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 0x05:
-            if (set_cc)
-                gen_op_adcl_T0_T1_cc();
-            else
-                gen_adc_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            if (set_cc) {
+                gen_helper_adc_cc(tmp, tmp, tmp2);
+            } else {
+                gen_add_carry(tmp, tmp, tmp2);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 0x06:
-            if (set_cc)
-                gen_op_sbcl_T0_T1_cc();
-            else
-                gen_sbc_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            if (set_cc) {
+                gen_helper_sbc_cc(tmp, tmp, tmp2);
+            } else {
+                gen_sub_carry(tmp, tmp, tmp2);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 0x07:
-            if (set_cc)
-                gen_op_rscl_T0_T1_cc();
-            else
-                gen_rsc_T0_T1();
-            gen_movl_reg_T0(s, rd);
+            if (set_cc) {
+                gen_helper_sbc_cc(tmp, tmp2, tmp);
+            } else {
+                gen_sub_carry(tmp, tmp2, tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 0x08:
             if (set_cc) {
-                gen_op_andl_T0_T1();
-                gen_op_logic_T0_cc();
+                tcg_gen_and_i32(tmp, tmp, tmp2);
+                gen_logic_CC(tmp);
             }
+            dead_tmp(tmp);
             break;
         case 0x09:
             if (set_cc) {
-                gen_op_xorl_T0_T1();
-                gen_op_logic_T0_cc();
+                tcg_gen_xor_i32(tmp, tmp, tmp2);
+                gen_logic_CC(tmp);
             }
+            dead_tmp(tmp);
             break;
         case 0x0a:
             if (set_cc) {
-                gen_op_subl_T0_T1_cc();
+                gen_helper_sub_cc(tmp, tmp, tmp2);
             }
+            dead_tmp(tmp);
             break;
         case 0x0b:
             if (set_cc) {
-                gen_op_addl_T0_T1_cc();
+                gen_helper_add_cc(tmp, tmp, tmp2);
             }
+            dead_tmp(tmp);
             break;
         case 0x0c:
-            gen_op_orl_T0_T1();
-            gen_movl_reg_T0(s, rd);
-            if (logic_cc)
-                gen_op_logic_T0_cc();
+            tcg_gen_or_i32(tmp, tmp, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 0x0d:
             if (logic_cc && rd == 15) {
                 /* MOVS r15, ... is used for exception return.  */
-                if (IS_USER(s))
+                if (IS_USER(s)) {
                     goto illegal_op;
-                gen_op_movl_T0_T1();
-                gen_exception_return(s);
+                }
+                gen_exception_return(s, tmp2);
             } else {
-                gen_movl_reg_T1(s, rd);
-                if (logic_cc)
-                    gen_op_logic_T1_cc();
+                if (logic_cc) {
+                    gen_logic_CC(tmp2);
+                }
+                store_reg_bx(env, s, rd, tmp2);
             }
             break;
         case 0x0e:
-            gen_op_bicl_T0_T1();
-            gen_movl_reg_T0(s, rd);
-            if (logic_cc)
-                gen_op_logic_T0_cc();
+            tcg_gen_bic_i32(tmp, tmp, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp);
+            }
+            store_reg_bx(env, s, rd, tmp);
             break;
         default:
         case 0x0f:
-            gen_op_notl_T1();
-            gen_movl_reg_T1(s, rd);
-            if (logic_cc)
-                gen_op_logic_T1_cc();
+            tcg_gen_not_i32(tmp2, tmp2);
+            if (logic_cc) {
+                gen_logic_CC(tmp2);
+            }
+            store_reg_bx(env, s, rd, tmp2);
             break;
         }
+        if (op1 != 0x0f && op1 != 0x0d) {
+            dead_tmp(tmp2);
+        }
     } else {
         /* other instructions */
         op1 = (insn >> 24) & 0xf;
@@ -6280,19 +6401,19 @@
                         tmp = load_reg(s, rs);
                         tmp2 = load_reg(s, rm);
                         if (insn & (1 << 22))
-                            tmp = gen_muls_i64_i32(tmp, tmp2);
+                            tmp64 = gen_muls_i64_i32(tmp, tmp2);
                         else
-                            tmp = gen_mulu_i64_i32(tmp, tmp2);
+                            tmp64 = gen_mulu_i64_i32(tmp, tmp2);
                         if (insn & (1 << 21)) /* mult accumulate */
-                            gen_addq(s, tmp, rn, rd);
+                            gen_addq(s, tmp64, rn, rd);
                         if (!(insn & (1 << 23))) { /* double accumulate */
                             ARCH(6);
-                            gen_addq_lo(s, tmp, rn);
-                            gen_addq_lo(s, tmp, rd);
+                            gen_addq_lo(s, tmp64, rn);
+                            gen_addq_lo(s, tmp64, rd);
                         }
                         if (insn & (1 << 20))
-                            gen_logicq_cc(tmp);
-                        gen_storeq_reg(s, rn, rd, tmp);
+                            gen_logicq_cc(tmp64);
+                        gen_storeq_reg(s, rn, rd, tmp64);
                         break;
                     }
                 } else {
@@ -6300,11 +6421,35 @@
                     rd = (insn >> 12) & 0xf;
                     if (insn & (1 << 23)) {
                         /* load/store exclusive */
+                        op1 = (insn >> 21) & 0x3;
+                        if (op1)
+                            ARCH(6K);
+                        else
+                            ARCH(6);
                         gen_movl_T1_reg(s, rn);
                         addr = cpu_T[1];
                         if (insn & (1 << 20)) {
                             gen_helper_mark_exclusive(cpu_env, cpu_T[1]);
-                            tmp = gen_ld32(addr, IS_USER(s));
+                            switch (op1) {
+                            case 0: /* ldrex */
+                                tmp = gen_ld32(addr, IS_USER(s));
+                                break;
+                            case 1: /* ldrexd */
+                                tmp = gen_ld32(addr, IS_USER(s));
+                                store_reg(s, rd, tmp);
+                                tcg_gen_addi_i32(addr, addr, 4);
+                                tmp = gen_ld32(addr, IS_USER(s));
+                                rd++;
+                                break;
+                            case 2: /* ldrexb */
+                                tmp = gen_ld8u(addr, IS_USER(s));
+                                break;
+                            case 3: /* ldrexh */
+                                tmp = gen_ld16u(addr, IS_USER(s));
+                                break;
+                            default:
+                                abort();
+                            }
                             store_reg(s, rd, tmp);
                         } else {
                             int label = gen_new_label();
@@ -6313,7 +6458,25 @@
                             tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0],
                                                 0, label);
                             tmp = load_reg(s,rm);
-                            gen_st32(tmp, cpu_T[1], IS_USER(s));
+                            switch (op1) {
+                            case 0:  /*  strex */
+                                gen_st32(tmp, addr, IS_USER(s));
+                                break;
+                            case 1: /*  strexd */
+                                gen_st32(tmp, addr, IS_USER(s));
+                                tcg_gen_addi_i32(addr, addr, 4);
+                                tmp = load_reg(s, rm + 1);
+                                gen_st32(tmp, addr, IS_USER(s));
+                                break;
+                            case 2: /*  strexb */
+                                gen_st8(tmp, addr, IS_USER(s));
+                                break;
+                            case 3: /* strexh */
+                                gen_st16(tmp, addr, IS_USER(s));
+                                break;
+                            default:
+                                abort();
+                            }
                             gen_set_label(label);
                             gen_movl_reg_T0(s, rd);
                         }
@@ -6536,7 +6699,7 @@
                             if (insn & (1 << 7))
                                 gen_rev16(tmp);
                             else
-                                tcg_gen_bswap_i32(tmp, tmp);
+                                tcg_gen_bswap32_i32(tmp, tmp);
                         }
                         store_reg(s, rd, tmp);
                     } else {
@@ -6548,14 +6711,14 @@
                     tmp2 = load_reg(s, rs);
                     if (insn & (1 << 20)) {
                         /* Signed multiply most significant [accumulate].  */
-                        tmp2 = gen_muls_i64_i32(tmp, tmp2);
+                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
                         if (insn & (1 << 5))
-                            tcg_gen_addi_i64(tmp2, tmp2, 0x80000000u);
-                        tcg_gen_shri_i64(tmp2, tmp2, 32);
+                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
+                        tcg_gen_shri_i64(tmp64, tmp64, 32);
                         tmp = new_tmp();
-                        tcg_gen_trunc_i64_i32(tmp, tmp2);
-                        if (rn != 15) {
-                            tmp2 = load_reg(s, rn);
+                        tcg_gen_trunc_i64_i32(tmp, tmp64);
+                        if (rd != 15) {
+                            tmp2 = load_reg(s, rd);
                             if (insn & (1 << 6)) {
                                 tcg_gen_sub_i32(tmp, tmp, tmp2);
                             } else {
@@ -6563,7 +6726,7 @@
                             }
                             dead_tmp(tmp2);
                         }
-                        store_reg(s, rd, tmp);
+                        store_reg(s, rn, tmp);
                     } else {
                         if (insn & (1 << 5))
                             gen_swap_half(tmp2);
@@ -6577,11 +6740,11 @@
                         dead_tmp(tmp2);
                         if (insn & (1 << 22)) {
                             /* smlald, smlsld */
-                            tmp2 = tcg_temp_new(TCG_TYPE_I64);
-                            tcg_gen_ext_i32_i64(tmp2, tmp);
+                            tmp64 = tcg_temp_new_i64();
+                            tcg_gen_ext_i32_i64(tmp64, tmp);
                             dead_tmp(tmp);
-                            gen_addq(s, tmp2, rd, rn);
-                            gen_storeq_reg(s, rd, rn, tmp2);
+                            gen_addq(s, tmp64, rd, rn);
+                            gen_storeq_reg(s, rd, rn, tmp64);
                         } else {
                             /* smuad, smusd, smlad, smlsd */
                             if (rd != 15)
@@ -6603,12 +6766,12 @@
                         tmp2 = load_reg(s, rs);
                         gen_helper_usad8(tmp, tmp, tmp2);
                         dead_tmp(tmp2);
-                        if (rn != 15) {
-                            tmp2 = load_reg(s, rn);
+                        if (rd != 15) {
+                            tmp2 = load_reg(s, rd);
                             tcg_gen_add_i32(tmp, tmp, tmp2);
                             dead_tmp(tmp2);
                         }
-                        store_reg(s, rd, tmp);
+                        store_reg(s, rn, tmp);
                         break;
                     case 0x20: case 0x24: case 0x28: case 0x2c:
                         /* Bitfield insert/clear.  */
@@ -6631,6 +6794,7 @@
                         break;
                     case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
                     case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
+                        ARCH(6T2);
                         tmp = load_reg(s, rm);
                         shift = (insn >> 7) & 0x1f;
                         i = ((insn >> 16) & 0x1f) + 1;
@@ -6671,7 +6835,6 @@
                 gen_add_data_offset(s, insn, tmp2);
             if (insn & (1 << 20)) {
                 /* load */
-                s->is_mem = 1;
                 if (insn & (1 << 22)) {
                     tmp = gen_ld8u(tmp2, i);
                 } else {
@@ -6950,6 +7113,7 @@
     TCGv tmp2;
     TCGv tmp3;
     TCGv addr;
+    TCGv_i64 tmp64;
     int op;
     int shiftop;
     int conds;
@@ -7002,7 +7166,7 @@
     if (tracing) {
         int  ticks = get_insn_ticks_thumb(insn);
         trace_add_insn( insn_wrap_thumb(insn), 1 );
-        gen_helper_traceInsn();
+        gen_traceInsn();
         gen_traceTicks(ticks);
     }
 #endif
@@ -7298,7 +7462,7 @@
             gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
             if (logic_cc)
                 gen_logic_CC(tmp);
-            store_reg(s, rd, tmp);
+            store_reg_bx(env, s, rd, tmp);
             break;
         case 1: /* Sign/zero extend.  */
             tmp = load_reg(s, rm);
@@ -7359,7 +7523,7 @@
                     gen_helper_rbit(tmp, tmp);
                     break;
                 case 0x08: /* rev */
-                    tcg_gen_bswap_i32(tmp, tmp);
+                    tcg_gen_bswap32_i32(tmp, tmp);
                     break;
                 case 0x09: /* rev16 */
                     gen_rev16(tmp);
@@ -7434,10 +7598,10 @@
                     tcg_gen_sari_i32(tmp2, tmp2, 16);
                 else
                     gen_sxth(tmp2);
-                tmp2 = gen_muls_i64_i32(tmp, tmp2);
-                tcg_gen_shri_i64(tmp2, tmp2, 16);
+                tmp64 = gen_muls_i64_i32(tmp, tmp2);
+                tcg_gen_shri_i64(tmp64, tmp64, 16);
                 tmp = new_tmp();
-                tcg_gen_trunc_i64_i32(tmp, tmp2);
+                tcg_gen_trunc_i64_i32(tmp, tmp64);
                 if (rs != 15)
                   {
                     tmp2 = load_reg(s, rs);
@@ -7501,36 +7665,38 @@
                     tcg_gen_add_i32(tmp, tmp, tmp2);
                 }
                 dead_tmp(tmp2);
-                tmp2 = tcg_temp_new(TCG_TYPE_I64);
-                gen_addq(s, tmp, rs, rd);
-                gen_storeq_reg(s, rs, rd, tmp);
+                /* BUGFIX */
+                tmp64 = tcg_temp_new_i64();
+                tcg_gen_ext_i32_i64(tmp64, tmp);
+                dead_tmp(tmp);
+                gen_addq(s, tmp64, rs, rd);
+                gen_storeq_reg(s, rs, rd, tmp64);
             } else {
                 if (op & 0x20) {
                     /* Unsigned 64-bit multiply  */
-                    tmp = gen_mulu_i64_i32(tmp, tmp2);
+                    tmp64 = gen_mulu_i64_i32(tmp, tmp2);
                 } else {
                     if (op & 8) {
                         /* smlalxy */
                         gen_mulxy(tmp, tmp2, op & 2, op & 1);
                         dead_tmp(tmp2);
-                        tmp2 = tcg_temp_new(TCG_TYPE_I64);
-                        tcg_gen_ext_i32_i64(tmp2, tmp);
+                        tmp64 = tcg_temp_new_i64();
+                        tcg_gen_ext_i32_i64(tmp64, tmp);
                         dead_tmp(tmp);
-                        tmp = tmp2;
                     } else {
                         /* Signed 64-bit multiply  */
-                        tmp = gen_muls_i64_i32(tmp, tmp2);
+                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
                     }
                 }
                 if (op & 4) {
                     /* umaal */
-                    gen_addq_lo(s, tmp, rs);
-                    gen_addq_lo(s, tmp, rd);
+                    gen_addq_lo(s, tmp64, rs);
+                    gen_addq_lo(s, tmp64, rd);
                 } else if (op & 0x40) {
                     /* 64-bit accumulate.  */
-                    gen_addq(s, tmp, rs, rd);
+                    gen_addq(s, tmp64, rs, rd);
                 }
-                gen_storeq_reg(s, rs, rd, tmp);
+                gen_storeq_reg(s, rs, rd, tmp64);
             }
             break;
         }
@@ -7987,7 +8153,7 @@
     if (tracing) {
         int  ticks = get_insn_ticks_thumb(insn);
         trace_add_insn( insn_wrap_thumb(insn), 1 );
-        gen_helper_traceInsn();
+        gen_traceInsn();
         gen_traceTicks(ticks);
     }
 #endif
@@ -8499,7 +8665,7 @@
             rd = insn & 0x7;
             tmp = load_reg(s, rn);
             switch ((insn >> 6) & 3) {
-            case 0: tcg_gen_bswap_i32(tmp, tmp); break;
+            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
             case 1: gen_rev16(tmp); break;
             case 3: gen_revsh(tmp); break;
             default: goto illegal_op;
@@ -8635,6 +8801,7 @@
                                                   int search_pc)
 {
     DisasContext dc1, *dc = &dc1;
+    CPUBreakpoint *bp;
     uint16_t *gen_opc_end;
     int j, lj;
     target_ulong pc_start;
@@ -8658,8 +8825,8 @@
     dc->condjmp = 0;
     dc->thumb = env->thumb;
     dc->condexec_mask = (env->condexec_bits & 0xf) << 1;
+    dc->condexec_mask_prev = dc->condexec_mask;
     dc->condexec_cond = env->condexec_bits >> 4;
-    dc->is_mem = 0;
 #if !defined(CONFIG_USER_ONLY)
     if (IS_M(env)) {
         dc->user = ((env->v7m.exception == 0) && (env->v7m.control & 1));
@@ -8667,14 +8834,14 @@
         dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
     }
 #endif
-    cpu_F0s = tcg_temp_new(TCG_TYPE_I32);
-    cpu_F1s = tcg_temp_new(TCG_TYPE_I32);
-    cpu_F0d = tcg_temp_new(TCG_TYPE_I64);
-    cpu_F1d = tcg_temp_new(TCG_TYPE_I64);
+    cpu_F0s = tcg_temp_new_i32();
+    cpu_F1s = tcg_temp_new_i32();
+    cpu_F0d = tcg_temp_new_i64();
+    cpu_F1d = tcg_temp_new_i64();
     cpu_V0 = cpu_F0d;
     cpu_V1 = cpu_F1d;
     /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
-    cpu_M0 = tcg_temp_new(TCG_TYPE_I64);
+    cpu_M0 = tcg_temp_new_i64();
     next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     lj = -1;
     num_insns = 0;
@@ -8683,14 +8850,6 @@
         max_insns = CF_COUNT_MASK;
 
     gen_icount_start();
-    /* Reset the conditional execution bits immediately. This avoids
-       complications trying to do it at the end of the block.  */
-    if (env->condexec_bits)
-      {
-        TCGv tmp = new_tmp();
-        tcg_gen_movi_i32(tmp, 0);
-        store_cpu_field(tmp, condexec_bits);
-      }
 #ifdef CONFIG_TRACE
     if (tracing) {
         gen_traceBB(trace_static.bb_num, (target_phys_addr_t)tb );
@@ -8718,9 +8877,9 @@
         }
 #endif
 
-        if (env->nb_breakpoints > 0) {
-            for(j = 0; j < env->nb_breakpoints; j++) {
-                if (env->breakpoints[j] == dc->pc) {
+        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
+            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == dc->pc) {
                     gen_set_condexec(dc);
                     gen_set_pc_im(dc->pc);
                     gen_exception(EXCP_DEBUG);
@@ -8750,6 +8909,7 @@
 
         if (env->thumb) {
             disas_thumb_insn(env, dc);
+            dc->condexec_mask_prev = dc->condexec_mask;
             if (dc->condexec_mask) {
                 dc->condexec_cond = (dc->condexec_cond & 0xe)
                                    | ((dc->condexec_mask >> 4) & 1);
@@ -8762,7 +8922,8 @@
             disas_arm_insn(env, dc);
         }
         if (num_temps) {
-            fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
+            fprintf(stderr, "Internal resource leak before %08x (%d temps)\n", dc->pc, num_temps);
+            tcg_dump_ops(&tcg_ctx, stderr);
             num_temps = 0;
         }
 
@@ -8770,19 +8931,14 @@
             gen_set_label(dc->condlabel);
             dc->condjmp = 0;
         }
-        /* Terminate the TB on memory ops if watchpoints are present.  */
-        /* FIXME: This should be replacd by the deterministic execution
-         * IRQ raising bits.  */
-        if (dc->is_mem && env->nb_watchpoints)
-            break;
-
-        /* Translation stops when a conditional branch is enoutered.
+        /* Translation stops when a conditional branch is encountered.
          * Otherwise the subsequent code could get translated several times.
          * Also stop translation when a page boundary is reached.  This
          * ensures prefetch aborts occur at the right place.  */
         num_insns ++;
     } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
              !env->singlestep_enabled &&
+             !singlestep &&
              dc->pc < next_page_start &&
              num_insns < max_insns);
 
@@ -8870,11 +9026,11 @@
     *gen_opc_ptr = INDEX_op_end;
 
 #ifdef DEBUG_DISAS
-    if (loglevel & CPU_LOG_TB_IN_ASM) {
-        fprintf(logfile, "----------------\n");
-        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-        target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
-        fprintf(logfile, "\n");
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("----------------\n");
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, dc->pc - pc_start, env->thumb);
+        qemu_log("\n");
     }
 #endif
     if (search_pc) {
diff --git a/targphys.h b/targphys.h
new file mode 100644
index 0000000..99ab23c
--- /dev/null
+++ b/targphys.h
@@ -0,0 +1,24 @@
+/* Define target_phys_addr_t if it exists.  */
+
+#ifndef TARGPHYS_H
+#define TARGPHYS_H
+
+#ifdef TARGET_PHYS_ADDR_BITS
+/* target_phys_addr_t is the type of a physical address (its size can
+   be different from 'target_ulong'). We have sizeof(target_phys_addr)
+   = max(sizeof(unsigned long),
+   sizeof(size_of_target_physical_address)) because we must pass a
+   host pointer to memory operations in some cases */
+
+#if TARGET_PHYS_ADDR_BITS == 32
+typedef uint32_t target_phys_addr_t;
+#define TARGET_PHYS_ADDR_MAX UINT32_MAX
+#define TARGET_FMT_plx "%08x"
+#elif TARGET_PHYS_ADDR_BITS == 64
+typedef uint64_t target_phys_addr_t;
+#define TARGET_PHYS_ADDR_MAX UINT64_MAX
+#define TARGET_FMT_plx "%016" PRIx64
+#endif
+#endif
+
+#endif
diff --git a/tcg/README b/tcg/README
index b03432e..e672258 100644
--- a/tcg/README
+++ b/tcg/README
@@ -60,9 +60,8 @@
 
 - Basic blocks end after branches (e.g. brcond_i32 instruction),
   goto_tb and exit_tb instructions.
-- Basic blocks end before legacy dyngen operations.
-- Basic blocks start after the end of a previous basic block, at a
-  set_label instruction or after a legacy dyngen operation.
+- Basic blocks start after the end of a previous basic block, or at a
+  set_label instruction.
 
 After the end of a basic block, the content of temporaries is
 destroyed, but local temporaries and globals are preserved.
@@ -205,7 +204,27 @@
 
 t0=~t1
 
-********* Shifts
+* andc_i32/i64 t0, t1, t2
+
+t0=t1&~t2
+
+* eqv_i32/i64 t0, t1, t2
+
+t0=~(t1^t2)
+
+* nand_i32/i64 t0, t1, t2
+
+t0=~(t1&t2)
+
+* nor_i32/i64 t0, t1, t2
+
+t0=~(t1|t2)
+
+* orc_i32/i64 t0, t1, t2
+
+t0=t1|~t2
+
+********* Shifts/Rotates
 
 * shl_i32/i64 t0, t1, t2
 
@@ -219,6 +238,14 @@
 
 t0=t1 >> t2 (signed). Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
 
+* rotl_i32/i64 t0, t1, t2
+
+Rotation of t2 bits to the left. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+
+* rotr_i32/i64 t0, t1, t2
+
+Rotation of t2 bits to the right. Undefined behavior if t2 < 0 or t2 >= 32 (resp 64)
+
 ********* Misc
 
 * mov_i32/i64 t0, t1
@@ -236,16 +263,17 @@
 
 8, 16 or 32 bit sign/zero extension (both operands must have the same type)
 
-* bswap16_i32 t0, t1
+* bswap16_i32/i64 t0, t1
 
-16 bit byte swap on a 32 bit value. The two high order bytes must be set
-to zero.
+16 bit byte swap on a 32/64 bit value. The two/six high order bytes must be
+set to zero.
 
-* bswap_i32 t0, t1
+* bswap32_i32/i64 t0, t1
 
-32 bit byte swap
+32 bit byte swap on a 32/64 bit value. With a 64 bit value, the four high
+order bytes must be set to zero.
 
-* bswap_i64 t0, t1
+* bswap64_i64 t0, t1
 
 64 bit byte swap
 
@@ -265,6 +293,14 @@
 * trunc_i64_i32 t0, t1
 Truncate t1 (64 bit) to t0 (32 bit)
 
+* concat_i32_i64 t0, t1, t2
+Construct t0 (64-bit) taking the low half from t1 (32 bit) and the high half
+from t2 (32 bit).
+
+* concat32_i64 t0, t1, t2
+Construct t0 (64-bit) taking the low half from t1 (64 bit) and the high half
+from t2 (64 bit).
+
 ********* Load/Store
 
 * ld_i32/i64 t0, t1, offset
@@ -299,22 +335,22 @@
 current TB was linked to this TB. Otherwise execute the next
 instructions.
 
-* qemu_ld_i32/i64 t0, t1, flags
-qemu_ld8u_i32/i64 t0, t1, flags
-qemu_ld8s_i32/i64 t0, t1, flags
-qemu_ld16u_i32/i64 t0, t1, flags
-qemu_ld16s_i32/i64 t0, t1, flags
-qemu_ld32u_i64 t0, t1, flags
-qemu_ld32s_i64 t0, t1, flags
+* qemu_ld8u t0, t1, flags
+qemu_ld8s t0, t1, flags
+qemu_ld16u t0, t1, flags
+qemu_ld16s t0, t1, flags
+qemu_ld32u t0, t1, flags
+qemu_ld32s t0, t1, flags
+qemu_ld64 t0, t1, flags
 
 Load data at the QEMU CPU address t1 into t0. t1 has the QEMU CPU
 address type. 'flags' contains the QEMU memory index (selects user or
 kernel access) for example.
 
-* qemu_st_i32/i64 t0, t1, flags
-qemu_st8_i32/i64 t0, t1, flags
-qemu_st16_i32/i64 t0, t1, flags
-qemu_st32_i64 t0, t1, flags
+* qemu_st8 t0, t1, flags
+qemu_st16 t0, t1, flags
+qemu_st32 t0, t1, flags
+qemu_st64 t0, t1, flags
 
 Store the data t0 at the QEMU CPU Address t1. t1 has the QEMU CPU
 address type. 'flags' contains the QEMU memory index (selects user or
@@ -354,6 +390,11 @@
 instruction. Memory constraints are not supported in this
 version. Aliases are specified in the input operands as for GCC.
 
+The same register may be used for both an input and an output, even when
+they are not explicitly aliased.  If an op expands to multiple target
+instructions then care must be taken to avoid clobbering input values.
+GCC style "early clobber" outputs are not currently supported.
+
 A target can define specific register or constant constraints. If an
 operation uses a constant input constraint which does not allow all
 constants, it must also accept registers in order to have a fallback.
@@ -382,18 +423,7 @@
   target, functions must be able to return 2 values in registers for
   64 bit return type.
 
-5) Migration from dyngen to TCG
-
-TCG is backward compatible with QEMU "dyngen" operations. It means
-that TCG instructions can be freely mixed with dyngen operations. It
-is expected that QEMU targets will be progressively fully converted to
-TCG. Once a target is fully converted to TCG, it will be possible
-to apply more optimizations because more registers will be free for
-the generated code.
-
-The exception model is the same as the dyngen one.
-
-6) Recommended coding rules for best performance
+5) Recommended coding rules for best performance
 
 - Use globals to represent the parts of the QEMU CPU state which are
   often modified, e.g. the integer registers and the condition
@@ -401,8 +431,7 @@
 
 - Avoid globals stored in fixed registers. They must be used only to
   store the pointer to the CPU state and possibly to store a pointer
-  to a register window. The other uses are to ensure backward
-  compatibility with dyngen during the porting a new target to TCG.
+  to a register window.
 
 - Use temporaries. Use local temporaries only when really needed,
   e.g. when you need to use a value after a jump. Local temporaries
diff --git a/tcg/TODO b/tcg/TODO
index 5ca35e9..f30cb75 100644
--- a/tcg/TODO
+++ b/tcg/TODO
@@ -1,5 +1,4 @@
-- Add new instructions such as: andnot, ror, rol, setcond, clz, ctz,
-  popcnt.
+- Add new instructions such as: setcond, clz, ctz, popcnt.
 
 - See if it is worth exporting mul2, mulu2, div2, divu2. 
 
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index dee1ebc..8139da1 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -21,7 +21,9 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-const char *tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "%r0",
     "%r1",
     "%r2",
@@ -38,8 +40,9 @@
     "%r13",
     "%r14",
 };
+#endif
 
-int tcg_target_reg_alloc_order[] = {
+static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_R0,
     TCG_REG_R1,
     TCG_REG_R2,
@@ -57,10 +60,10 @@
     TCG_REG_R14,
 };
 
-const int tcg_target_call_iarg_regs[4] = {
+static const int tcg_target_call_iarg_regs[4] = {
     TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3
 };
-const int tcg_target_call_oarg_regs[2] = {
+static const int tcg_target_call_oarg_regs[2] = {
     TCG_REG_R0, TCG_REG_R1
 };
 
@@ -91,7 +94,7 @@
 }
 
 /* parse target specific constraints */
-int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 {
     const char *ct_str;
 
@@ -292,10 +295,19 @@
                 int cond, int opc0, int opc1, int rd0, int rd1,
                 int rn0, int rn1, int rm0, int rm1, int shift)
 {
-    tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
-                    (rn0 << 16) | (rd0 << 12) | shift | rm0);
-    tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
-                    (rn1 << 16) | (rd1 << 12) | shift | rm1);
+    if (rd0 == rn1 || rd0 == rm1) {
+        tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
+                        (rn0 << 16) | (8 << 12) | shift | rm0);
+        tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
+                        (rn1 << 16) | (rd1 << 12) | shift | rm1);
+        tcg_out_dat_reg(s, cond, ARITH_MOV,
+                        rd0, 0, TCG_REG_R8, SHIFT_IMM_LSL(0));
+    } else {
+        tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
+                        (rn0 << 16) | (rd0 << 12) | shift | rm0);
+        tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
+                        (rn1 << 16) | (rd1 << 12) | shift | rm1);
+    }
 }
 
 static inline void tcg_out_dat_imm(TCGContext *s,
@@ -846,10 +858,10 @@
     else
         data_reg2 = 0; /* surpress warning */
     addr_reg = *args++;
-#if TARGET_LONG_BITS == 64
-    addr_reg2 = *args++;
-#endif
 #ifdef CONFIG_SOFTMMU
+# if TARGET_LONG_BITS == 64
+    addr_reg2 = *args++;
+# endif
     mem_index = *args;
     s_bits = opc & 3;
 
@@ -999,8 +1011,13 @@
     case 3:
         /* TODO: use block load -
          * check that data_reg2 > data_reg or the other way */
-        tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
-        tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4);
+        if (data_reg == addr_reg) {
+            tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4);
+            tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
+        } else {
+            tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
+            tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4);
+        }
         break;
     }
 #endif
@@ -1024,10 +1041,10 @@
     else
         data_reg2 = 0; /* surpress warning */
     addr_reg = *args++;
-#if TARGET_LONG_BITS == 64
-    addr_reg2 = *args++;
-#endif
 #ifdef CONFIG_SOFTMMU
+# if TARGET_LONG_BITS == 64
+    addr_reg2 = *args++;
+# endif
     mem_index = *args;
     s_bits = opc & 3;
 
@@ -1229,19 +1246,24 @@
         if (args[0] >> 8)
             tcg_out32(s, args[0]);
 #else
-        if (args[0] >> 8)
-            tcg_out_ld32_12(s, COND_AL, 0, 15, 0);
-        else
-            tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]);
-        tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr);
-        if (args[0] >> 8)
-            tcg_out32(s, args[0]);
+        {
+            uint8_t *ld_ptr = s->code_ptr;
+            if (args[0] >> 8)
+                tcg_out_ld32_12(s, COND_AL, 0, 15, 0);
+            else
+                tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]);
+            tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr);
+            if (args[0] >> 8) {
+                *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8;
+                tcg_out32(s, args[0]);
+            }
+        }
 #endif
         break;
     case INDEX_op_goto_tb:
         if (s->tb_jmp_offset) {
             /* Direct jump method */
-#if 1
+#if defined(USE_DIRECT_JUMP)
             s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
             tcg_out_b(s, COND_AL, 8);
 #else
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 6c180af..8f5016f 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -28,7 +28,7 @@
 #undef TCG_TARGET_WORDS_BIGENDIAN
 #undef TCG_TARGET_HAS_div_i32
 #undef TCG_TARGET_HAS_div_i64
-#undef TCG_TARGET_HAS_bswap_i32
+#undef TCG_TARGET_HAS_bswap32_i32
 #define TCG_TARGET_HAS_ext8s_i32
 #define TCG_TARGET_HAS_ext16s_i32
 #define TCG_TARGET_HAS_neg_i32
@@ -64,13 +64,17 @@
     TCG_AREG0 = TCG_REG_R7,
     TCG_AREG1 = TCG_REG_R4,
     TCG_AREG2 = TCG_REG_R5,
-    TCG_AREG3 = TCG_REG_R6,
 };
 
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
+#if QEMU_GNUC_PREREQ(4, 1)
+    void __clear_cache(char *beg, char *end);
+    __clear_cache((char *) start, (char *) stop);
+#else
     register unsigned long _beg __asm ("a1") = start;
     register unsigned long _end __asm ("a2") = stop;
     register unsigned long _flg __asm ("a3") = 0;
     __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
+#endif
 }
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
index 3affd26..5960c03 100644
--- a/tcg/hppa/tcg-target.c
+++ b/tcg/hppa/tcg-target.c
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 
+#ifndef NDEBUG
 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "%r0",
     "%r1",
@@ -56,6 +57,7 @@
     "%sp",
     "%r31",
 };
+#endif
 
 static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_R4,
@@ -106,7 +108,7 @@
 }
 
 /* parse target specific constraints */
-int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 {
     const char *ct_str;
 
diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h
index 8e2693d..7ab6f0c 100644
--- a/tcg/hppa/tcg-target.h
+++ b/tcg/hppa/tcg-target.h
@@ -78,13 +78,12 @@
 //#define TCG_TARGET_HAS_ext8s_i32
 //#define TCG_TARGET_HAS_ext16s_i32
 //#define TCG_TARGET_HAS_bswap16_i32
-//#define TCG_TARGET_HAS_bswap_i32
+//#define TCG_TARGET_HAS_bswap32_i32
 
 /* Note: must be synced with dyngen-exec.h */
 #define TCG_AREG0 TCG_REG_R17
 #define TCG_AREG1 TCG_REG_R14
 #define TCG_AREG2 TCG_REG_R15
-#define TCG_AREG3 TCG_REG_R16
 
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 08bb783..e748ba2 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -21,7 +21,9 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-const char *tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "%eax",
     "%ecx",
     "%edx",
@@ -31,8 +33,9 @@
     "%esi",
     "%edi",
 };
+#endif
 
-int tcg_target_reg_alloc_order[] = {
+static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_EAX,
     TCG_REG_EDX,
     TCG_REG_ECX,
@@ -42,8 +45,8 @@
     TCG_REG_EBP,
 };
 
-const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX };
-const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
+static const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX };
+static const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
 
 static uint8_t *tb_ret_addr;
 
@@ -80,7 +83,7 @@
 }
 
 /* parse target specific constraints */
-int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
+static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 {
     const char *ct_str;
 
@@ -155,6 +158,8 @@
 #define ARITH_XOR 6
 #define ARITH_CMP 7
 
+#define SHIFT_ROL 0
+#define SHIFT_ROR 1
 #define SHIFT_SHL 4
 #define SHIFT_SHR 5
 #define SHIFT_SAR 7
@@ -271,21 +276,33 @@
     tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2);
 }
 
-static inline void tgen_arithi(TCGContext *s, int c, int r0, int32_t val)
+static inline void tgen_arithi(TCGContext *s, int c, int r0, int32_t val, int cf)
 {
-    if (val == (int8_t)val) {
+    if (!cf && ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1))) {
+        /* inc */
+        tcg_out_opc(s, 0x40 + r0);
+    } else if (!cf && ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1))) {
+        /* dec */
+        tcg_out_opc(s, 0x48 + r0);
+    } else if (val == (int8_t)val) {
         tcg_out_modrm(s, 0x83, c, r0);
         tcg_out8(s, val);
+    } else if (c == ARITH_AND && val == 0xffu && r0 < 4) {
+        /* movzbl */
+        tcg_out_modrm(s, 0xb6 | P_EXT, r0, r0);
+    } else if (c == ARITH_AND && val == 0xffffu) {
+        /* movzwl */
+        tcg_out_modrm(s, 0xb7 | P_EXT, r0, r0);
     } else {
         tcg_out_modrm(s, 0x81, c, r0);
         tcg_out32(s, val);
     }
 }
 
-void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
+static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
 {
     if (val != 0)
-        tgen_arithi(s, ARITH_ADD, reg, val);
+        tgen_arithi(s, ARITH_ADD, reg, val, 0);
 }
 
 static void tcg_out_jxx(TCGContext *s, int opc, int label_index)
@@ -333,7 +350,7 @@
             /* test r, r */
             tcg_out_modrm(s, 0x85, arg1, arg1);
         } else {
-            tgen_arithi(s, ARITH_CMP, arg1, arg2);
+            tgen_arithi(s, ARITH_CMP, arg1, arg2, 0);
         }
     } else {
         tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1);
@@ -522,7 +539,13 @@
         tcg_out_modrm(s, 0xbf | P_EXT, data_reg, TCG_REG_EAX);
         break;
     case 0:
+        /* movzbl */
+        tcg_out_modrm(s, 0xb6 | P_EXT, data_reg, TCG_REG_EAX);
+        break;
     case 1:
+        /* movzwl */
+        tcg_out_modrm(s, 0xb7 | P_EXT, data_reg, TCG_REG_EAX);
+        break;
     case 2:
     default:
         tcg_out_mov(s, data_reg, TCG_REG_EAX);
@@ -940,7 +963,7 @@
         c = ARITH_ADD;
     gen_arith:
         if (const_args[2]) {
-            tgen_arithi(s, c, args[0], args[2]);
+            tgen_arithi(s, c, args[0], args[2], 0);
         } else {
             tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]);
         }
@@ -989,24 +1012,30 @@
     case INDEX_op_sar_i32:
         c = SHIFT_SAR;
         goto gen_shift32;
-        
+    case INDEX_op_rotl_i32:
+        c = SHIFT_ROL;
+        goto gen_shift32;
+    case INDEX_op_rotr_i32:
+        c = SHIFT_ROR;
+        goto gen_shift32;
+
     case INDEX_op_add2_i32:
         if (const_args[4]) 
-            tgen_arithi(s, ARITH_ADD, args[0], args[4]);
+            tgen_arithi(s, ARITH_ADD, args[0], args[4], 1);
         else
             tcg_out_modrm(s, 0x01 | (ARITH_ADD << 3), args[4], args[0]);
         if (const_args[5]) 
-            tgen_arithi(s, ARITH_ADC, args[1], args[5]);
+            tgen_arithi(s, ARITH_ADC, args[1], args[5], 1);
         else
             tcg_out_modrm(s, 0x01 | (ARITH_ADC << 3), args[5], args[1]);
         break;
     case INDEX_op_sub2_i32:
         if (const_args[4]) 
-            tgen_arithi(s, ARITH_SUB, args[0], args[4]);
+            tgen_arithi(s, ARITH_SUB, args[0], args[4], 1);
         else
             tcg_out_modrm(s, 0x01 | (ARITH_SUB << 3), args[4], args[0]);
         if (const_args[5]) 
-            tgen_arithi(s, ARITH_SBB, args[1], args[5]);
+            tgen_arithi(s, ARITH_SBB, args[1], args[5], 1);
         else
             tcg_out_modrm(s, 0x01 | (ARITH_SBB << 3), args[5], args[1]);
         break;
@@ -1017,6 +1046,30 @@
         tcg_out_brcond2(s, args, const_args);
         break;
 
+    case INDEX_op_bswap16_i32:
+        tcg_out8(s, 0x66);
+        tcg_out_modrm(s, 0xc1, SHIFT_ROL, args[0]);
+        tcg_out8(s, 8);
+        break;
+    case INDEX_op_bswap32_i32:
+        tcg_out_opc(s, (0xc8 + args[0]) | P_EXT);
+        break;
+
+    case INDEX_op_neg_i32:
+        tcg_out_modrm(s, 0xf7, 3, args[0]);
+        break;
+
+    case INDEX_op_not_i32:
+        tcg_out_modrm(s, 0xf7, 2, args[0]);
+        break;
+
+    case INDEX_op_ext8s_i32:
+        tcg_out_modrm(s, 0xbe | P_EXT, args[0], args[1]);
+        break;
+    case INDEX_op_ext16s_i32:
+        tcg_out_modrm(s, 0xbf | P_EXT, args[0], args[1]);
+        break;
+
     case INDEX_op_qemu_ld8u:
         tcg_out_qemu_ld(s, args, 0);
         break;
@@ -1084,6 +1137,9 @@
     { INDEX_op_shl_i32, { "r", "0", "ci" } },
     { INDEX_op_shr_i32, { "r", "0", "ci" } },
     { INDEX_op_sar_i32, { "r", "0", "ci" } },
+    { INDEX_op_sar_i32, { "r", "0", "ci" } },
+    { INDEX_op_rotl_i32, { "r", "0", "ci" } },
+    { INDEX_op_rotr_i32, { "r", "0", "ci" } },
 
     { INDEX_op_brcond_i32, { "r", "ri" } },
 
@@ -1091,6 +1147,16 @@
     { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } },
     { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } },
 
+    { INDEX_op_bswap16_i32, { "r", "0" } },
+    { INDEX_op_bswap32_i32, { "r", "0" } },
+
+    { INDEX_op_neg_i32, { "r", "0" } },
+
+    { INDEX_op_not_i32, { "r", "0" } },
+
+    { INDEX_op_ext8s_i32, { "r", "q" } },
+    { INDEX_op_ext16s_i32, { "r", "r" } },
+
 #if TARGET_LONG_BITS == 32
     { INDEX_op_qemu_ld8u, { "r", "L" } },
     { INDEX_op_qemu_ld8s, { "r", "L" } },
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 37fdaa5..301a5bf 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -44,11 +44,19 @@
 #define TCG_TARGET_STACK_ALIGN 16
 #define TCG_TARGET_CALL_STACK_OFFSET 0
 
+/* optional instructions */
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_neg_i32
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_ext8s_i32
+#define TCG_TARGET_HAS_ext16s_i32
+#define TCG_TARGET_HAS_rot_i32
+
 /* Note: must be synced with dyngen-exec.h */
 #define TCG_AREG0 TCG_REG_EBP
 #define TCG_AREG1 TCG_REG_EBX
 #define TCG_AREG2 TCG_REG_ESI
-#define TCG_AREG3 TCG_REG_EDI
 
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index ad17468..e3f4b59 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -26,10 +26,13 @@
 
 #ifdef __APPLE__
 #define LINKAGE_AREA_SIZE 24
-#define BACK_CHAIN_OFFSET 8
+#define LR_OFFSET 8
+#elif defined _AIX
+#define LINKAGE_AREA_SIZE 52
+#define LR_OFFSET 8
 #else
 #define LINKAGE_AREA_SIZE 8
-#define BACK_CHAIN_OFFSET 4
+#define LR_OFFSET 4
 #endif
 
 #define FAST_PATH
@@ -39,6 +42,7 @@
 #define ADDEND_OFFSET 4
 #endif
 
+#ifndef NDEBUG
 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "r0",
     "r1",
@@ -73,6 +77,7 @@
     "r30",
     "r31"
 };
+#endif
 
 static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_R14,
@@ -104,10 +109,9 @@
     TCG_REG_R11,
 #endif
     TCG_REG_R12,
+#ifndef __linux__
     TCG_REG_R13,
-    TCG_REG_R0,
-    TCG_REG_R1,
-    TCG_REG_R2,
+#endif
     TCG_REG_R24,
     TCG_REG_R25,
     TCG_REG_R26,
@@ -135,6 +139,9 @@
     TCG_REG_R11,
     TCG_REG_R13,
 #endif
+#ifdef _AIX
+    TCG_REG_R13,
+#endif
     TCG_REG_R14,
     TCG_REG_R15,
     TCG_REG_R16,
@@ -145,6 +152,11 @@
     TCG_REG_R21,
     TCG_REG_R22,
     TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    /* TCG_REG_R27, */ /* currently used for the global env, so no
+                          need to save */
     TCG_REG_R28,
     TCG_REG_R29,
     TCG_REG_R30,
@@ -204,7 +216,7 @@
 /* maximum number of register used for input function arguments */
 static int tcg_target_get_call_iarg_regs_count(int flags)
 {
-    return sizeof (tcg_target_call_iarg_regs) / sizeof (tcg_target_call_iarg_regs[0]);
+    return ARRAY_SIZE (tcg_target_call_iarg_regs);
 }
 
 /* parse target specific constraints */
@@ -360,9 +372,6 @@
 #define SRW    XO31(536)
 #define SRAW   XO31(792)
 
-#define LMW    OPCD(46)
-#define STMW   OPCD(47)
-
 #define TW     XO31(4)
 #define TRAP   (TW | TO (31))
 
@@ -453,6 +462,24 @@
     }
 }
 
+#ifdef _AIX
+static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg)
+{
+    int reg;
+
+    if (const_arg) {
+        reg = 2;
+        tcg_out_movi (s, TCG_TYPE_I32, reg, arg);
+    }
+    else reg = arg;
+
+    tcg_out32 (s, LWZ | RT (0) | RA (reg));
+    tcg_out32 (s, MTSPR | RA (0) | CTR);
+    tcg_out32 (s, LWZ | RT (2) | RA (reg) | 4);
+    tcg_out32 (s, BCCTR | BO_ALWAYS | LK);
+}
+#endif
+
 #if defined(CONFIG_SOFTMMU)
 
 #include "../../softmmu_defs.h"
@@ -474,9 +501,9 @@
 
 static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
 {
-    int addr_reg, data_reg, data_reg2, r0, mem_index, s_bits, bswap;
+    int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap;
 #ifdef CONFIG_SOFTMMU
-    int r1, r2;
+    int r2;
     void *label1_ptr, *label2_ptr;
 #endif
 #if TARGET_LONG_BITS == 64
@@ -546,7 +573,11 @@
     tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index);
 #endif
 
+#ifdef _AIX
+    tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
+#else
     tcg_out_b (s, LK, (tcg_target_long) qemu_ld_helpers[s_bits]);
+#endif
     switch (opc) {
     case 0|4:
         tcg_out32 (s, EXTSB | RA (data_reg) | RS (3));
@@ -599,6 +630,7 @@
 
 #else  /* !CONFIG_SOFTMMU */
     r0 = addr_reg;
+    r1 = 3;
 #endif
 
 #ifdef TARGET_WORDS_BIGENDIAN
@@ -632,17 +664,9 @@
         break;
     case 3:
         if (bswap) {
-            if (r0 == data_reg) {
-                tcg_out32 (s, LWBRX | RT (0) | RB (r0));
-                tcg_out32 (s, ADDI | RT (r0) | RA (r0) |  4);
-                tcg_out32 (s, LWBRX | RT (data_reg2) | RB (r0));
-                tcg_out_mov (s, data_reg, 0);
-            }
-            else {
-                tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0));
-                tcg_out32 (s, ADDI | RT (r0) | RA (r0) |  4);
-                tcg_out32 (s, LWBRX | RT (data_reg2) | RB (r0));
-            }
+            tcg_out32 (s, ADDI | RT (r1) | RA (r0) |  4);
+            tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0));
+            tcg_out32 (s, LWBRX | RT (data_reg2) | RB (r1));
         }
         else {
             if (r0 == data_reg2) {
@@ -771,7 +795,11 @@
     ir++;
 
     tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index);
+#ifdef _AIX
+    tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1);
+#else
     tcg_out_b (s, LK, (tcg_target_long) qemu_st_helpers[opc]);
+#endif
     label2_ptr = s->code_ptr;
     tcg_out32 (s, B);
 
@@ -841,6 +869,16 @@
         ;
     frame_size = (frame_size + 15) & ~15;
 
+#ifdef _AIX
+    {
+        uint32_t addr;
+
+        /* First emit adhoc function descriptor */
+        addr = (uint32_t) s->code_ptr + 12;
+        tcg_out32 (s, addr);        /* entry point */
+        s->code_ptr += 8;           /* skip TOC and environment pointer */
+    }
+#endif
     tcg_out32 (s, MFSPR | RT (0) | LR);
     tcg_out32 (s, STWU | RS (1) | RA (1) | (-frame_size & 0xffff));
     for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i)
@@ -850,7 +888,7 @@
                        | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE)
                        )
             );
-    tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + BACK_CHAIN_OFFSET));
+    tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + LR_OFFSET));
 
     tcg_out32 (s, MTSPR | RS (3) | CTR);
     tcg_out32 (s, BCCTR | BO_ALWAYS);
@@ -863,7 +901,7 @@
                        | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE)
                        )
             );
-    tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + BACK_CHAIN_OFFSET));
+    tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + LR_OFFSET));
     tcg_out32 (s, MTSPR | RS (0) | LR);
     tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size);
     tcg_out32 (s, BCLR | BO_ALWAYS);
@@ -1111,6 +1149,9 @@
         }
         break;
     case INDEX_op_call:
+#ifdef _AIX
+        tcg_out_call (s, args[0], const_args[0]);
+#else
         if (const_args[0]) {
             tcg_out_b (s, LK, args[0]);
         }
@@ -1118,6 +1159,7 @@
             tcg_out32 (s, MTSPR | RS (args[0]) | LR);
             tcg_out32 (s, BCLR | BO_ALWAYS | LK);
         }
+#endif
         break;
     case INDEX_op_jmp:
         if (const_args[0]) {
@@ -1487,6 +1529,9 @@
 #ifndef __APPLE__
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2);
 #endif
+#ifdef __linux__
+    tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13);
+#endif
 
     tcg_add_target_add_op_defs(ppc_op_defs);
 }
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index d46c19d..5faf730 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -65,11 +65,15 @@
 /* used for function call generation */
 #define TCG_REG_CALL_STACK TCG_REG_R1
 #define TCG_TARGET_STACK_ALIGN 16
-#ifdef __APPLE__
+#if defined __APPLE__
 #define TCG_TARGET_CALL_STACK_OFFSET 24
-#else
+#elif defined _AIX
+#define TCG_TARGET_CALL_STACK_OFFSET 52
+#elif defined __linux__
 #define TCG_TARGET_CALL_ALIGN_ARGS 1
 #define TCG_TARGET_CALL_STACK_OFFSET 8
+#else
+#error Unsupported system
 #endif
 
 /* optional instructions */
@@ -81,25 +85,3 @@
 #define TCG_AREG0 TCG_REG_R27
 #define TCG_AREG1 TCG_REG_R24
 #define TCG_AREG2 TCG_REG_R25
-#define TCG_AREG3 TCG_REG_R26
-
-/* taken directly from tcg-dyngen.c */
-#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
-
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-    unsigned long p;
-
-    start &= ~(MIN_CACHE_LINE_SIZE - 1);
-    stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
-
-    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
-        asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
-    }
-    asm volatile ("sync" : : : "memory");
-    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
-        asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
-    }
-    asm volatile ("sync" : : : "memory");
-    asm volatile ("isync" : : : "memory");
-}
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index 6b16efa..a2f85ff 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -42,6 +42,7 @@
 #define CMP_L (1<<21)
 #endif
 
+#ifndef NDEBUG
 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "r0",
     "r1",
@@ -76,6 +77,7 @@
     "r30",
     "r31"
 };
+#endif
 
 static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_R14,
@@ -102,10 +104,6 @@
     TCG_REG_R10,
     TCG_REG_R11,
     TCG_REG_R12,
-    TCG_REG_R13,
-    TCG_REG_R0,
-    TCG_REG_R1,
-    TCG_REG_R2,
     TCG_REG_R24,
     TCG_REG_R25,
     TCG_REG_R26,
@@ -138,6 +136,11 @@
     TCG_REG_R21,
     TCG_REG_R22,
     TCG_REG_R23,
+    TCG_REG_R24,
+    TCG_REG_R25,
+    TCG_REG_R26,
+    /* TCG_REG_R27, */ /* currently used for the global env, so no
+                          need to save */
     TCG_REG_R28,
     TCG_REG_R29,
     TCG_REG_R30,
@@ -197,7 +200,7 @@
 /* maximum number of register used for input function arguments */
 static int tcg_target_get_call_iarg_regs_count (int flags)
 {
-    return sizeof (tcg_target_call_iarg_regs) / sizeof (tcg_target_call_iarg_regs[0]);
+    return ARRAY_SIZE (tcg_target_call_iarg_regs);
 }
 
 /* parse target specific constraints */
@@ -303,6 +306,7 @@
 
 #define RLDICL XO30(  0)
 #define RLDICR XO30(  1)
+#define RLDIMI XO30(  3)
 
 #define BCLR   XO19( 16)
 #define BCCTR  XO19(528)
@@ -365,9 +369,6 @@
 #define SRAD   XO31(794)
 #define SRADI  XO31(413<<1)
 
-#define LMW    OPCD( 46)
-#define STMW   OPCD( 47)
-
 #define TW     XO31( 4)
 #define TRAP   (TW | TO (31))
 
@@ -494,6 +495,17 @@
     }
 }
 
+static void tcg_out_ldsta (TCGContext *s, int ret, int addr,
+                           int offset, int op1, int op2)
+{
+    if (offset == (int16_t) (offset & ~3))
+        tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff));
+    else {
+        tcg_out_movi (s, TCG_TYPE_I64, 0, offset);
+        tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0));
+    }
+}
+
 static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target)
 {
     tcg_target_long disp;
@@ -691,11 +703,10 @@
         break;
     case 3:
         if (bswap) {
-            tcg_out32 (s, LWBRX | RT (0) | RB (r0));
-            tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4);
-            tcg_out32 (s, LWBRX | RT (data_reg) | RB (r1));
-            tcg_out_rld (s, RLDICR, data_reg, data_reg, 32, 31);
-            tcg_out32 (s, OR | SAB (0, data_reg, data_reg));
+            tcg_out_movi32 (s, 0, 4);
+            tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0));
+            tcg_out32 (s, LWBRX | RT (      r1) | RA (r0));
+            tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0);
         }
         else tcg_out32 (s, LD | RT (data_reg) | RA (r0));
         break;
@@ -858,7 +869,7 @@
     if (type == TCG_TYPE_I32)
         tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX);
     else
-        tcg_out_ldst (s, ret, arg1, arg2, LD, LDX);
+        tcg_out_ldsta (s, ret, arg1, arg2, LD, LDX);
 }
 
 static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1,
@@ -867,7 +878,7 @@
     if (type == TCG_TYPE_I32)
         tcg_out_ldst (s, arg, arg1, arg2, STW, STWX);
     else
-        tcg_out_ldst (s, arg, arg1, arg2, STD, STDX);
+        tcg_out_ldsta (s, arg, arg1, arg2, STD, STDX);
 }
 
 static void ppc_addi32 (TCGContext *s, int rt, int ra, tcg_target_long si)
@@ -888,7 +899,7 @@
 {
     /* XXX: suboptimal */
     if (si == (int16_t) si
-        || (((uint64_t) si >> 31) == 0) && (si & 0x8000) == 0)
+        || ((((uint64_t) si >> 31) == 0) && (si & 0x8000) == 0))
         ppc_addi32 (s, rt, ra, si);
     else {
         tcg_out_movi (s, TCG_TYPE_I64, 0, si);
@@ -1086,10 +1097,10 @@
         tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX);
         break;
     case INDEX_op_ld32s_i64:
-        tcg_out_ldst (s, args[0], args[1], args[2], LWA, LWAX);
+        tcg_out_ldsta (s, args[0], args[1], args[2], LWA, LWAX);
         break;
     case INDEX_op_ld_i64:
-        tcg_out_ldst (s, args[0], args[1], args[2], LD, LDX);
+        tcg_out_ldsta (s, args[0], args[1], args[2], LD, LDX);
         break;
     case INDEX_op_st8_i32:
     case INDEX_op_st8_i64:
@@ -1104,7 +1115,7 @@
         tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX);
         break;
     case INDEX_op_st_i64:
-        tcg_out_ldst (s, args[0], args[1], args[2], STD, STDX);
+        tcg_out_ldsta (s, args[0], args[1], args[2], STD, STDX);
         break;
 
     case INDEX_op_add_i32:
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index 2174db2..452bfda 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -81,25 +81,3 @@
 #define TCG_AREG0 TCG_REG_R27
 #define TCG_AREG1 TCG_REG_R24
 #define TCG_AREG2 TCG_REG_R25
-#define TCG_AREG3 TCG_REG_R26
-
-/* taken directly from tcg-dyngen.c */
-#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
-
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-    unsigned long p;
-
-    start &= ~(MIN_CACHE_LINE_SIZE - 1);
-    stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
-
-    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
-        asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
-    }
-    asm volatile ("sync" : : : "memory");
-    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
-        asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
-    }
-    asm volatile ("sync" : : : "memory");
-    asm volatile ("isync" : : : "memory");
-}
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index f36796d..23cd9cd 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 
+#ifndef NDEBUG
 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "%g0",
     "%g1",
@@ -56,6 +57,7 @@
     "%i6",
     "%i7",
 };
+#endif
 
 static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_L0,
@@ -115,6 +117,13 @@
             tcg_abort();
         *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x3fffff) | value;
         break;
+    case R_SPARC_WDISP19:
+        value -= (long)code_ptr;
+        value >>= 2;
+        if (!check_fit_tl(value, 19))
+            tcg_abort();
+        *(uint32_t *)code_ptr = ((*(uint32_t *)code_ptr) & ~0x7ffff) | value;
+        break;
     default:
         tcg_abort();
     }
@@ -183,6 +192,7 @@
 #define INSN_ASI(x) ((x) << 5)
 
 #define INSN_IMM13(x) ((1 << 13) | ((x) & 0x1fff))
+#define INSN_OFF19(x) (((x) >> 2) & 0x07ffff)
 #define INSN_OFF22(x) (((x) >> 2) & 0x3fffff)
 
 #define INSN_COND(x, a) (((x) << 25) | ((a) << 29))
@@ -419,7 +429,7 @@
     tcg_out_sethi(s, TCG_REG_G0, 0);
 }
 
-static void tcg_out_branch(TCGContext *s, int opc, int label_index)
+static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index)
 {
     int32_t val;
     TCGLabel *l = &s->labels[label_index];
@@ -434,6 +444,25 @@
     }
 }
 
+#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
+static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index)
+{
+    int32_t val;
+    TCGLabel *l = &s->labels[label_index];
+
+    if (l->has_value) {
+        val = l->u.value - (tcg_target_long)s->code_ptr;
+        tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
+                      (0x5 << 19) |
+                      INSN_OFF19(l->u.value - (unsigned long)s->code_ptr)));
+    } else {
+        tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0);
+        tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) |
+                      (0x5 << 19) | 0));
+    }
+}
+#endif
+
 static const uint8_t tcg_cond_to_bcond[10] = {
     [TCG_COND_EQ] = COND_E,
     [TCG_COND_NE] = COND_NE,
@@ -447,9 +476,9 @@
     [TCG_COND_GTU] = COND_GU,
 };
 
-static void tcg_out_brcond(TCGContext *s, int cond,
-                           TCGArg arg1, TCGArg arg2, int const_arg2,
-                           int label_index)
+static void tcg_out_brcond_i32(TCGContext *s, int cond,
+                               TCGArg arg1, TCGArg arg2, int const_arg2,
+                               int label_index)
 {
     if (const_arg2 && arg2 == 0)
         /* orcc %g0, r, %g0 */
@@ -457,10 +486,26 @@
     else
         /* subcc r1, r2, %g0 */
         tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC);
-    tcg_out_branch(s, tcg_cond_to_bcond[cond], label_index);
+    tcg_out_branch_i32(s, tcg_cond_to_bcond[cond], label_index);
     tcg_out_nop(s);
 }
 
+#if defined(__sparc_v9__) && !defined(__sparc_v8plus__)
+static void tcg_out_brcond_i64(TCGContext *s, int cond,
+                               TCGArg arg1, TCGArg arg2, int const_arg2,
+                               int label_index)
+{
+    if (const_arg2 && arg2 == 0)
+        /* orcc %g0, r, %g0 */
+        tcg_out_arith(s, TCG_REG_G0, TCG_REG_G0, arg1, ARITH_ORCC);
+    else
+        /* subcc r1, r2, %g0 */
+        tcg_out_arith(s, TCG_REG_G0, arg1, arg2, ARITH_SUBCC);
+    tcg_out_branch_i64(s, tcg_cond_to_bcond[cond], label_index);
+    tcg_out_nop(s);
+}
+#endif
+
 /* Generate global QEMU prologue and epilogue code */
 void tcg_target_qemu_prologue(TCGContext *s)
 {
@@ -557,7 +602,9 @@
     tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC);
 
     /* will become:
-       be label1 */
+       be label1
+        or
+       be,pt %xcc label1 */
     label1_ptr = (uint32_t *)s->code_ptr;
     tcg_out32(s, 0);
 
@@ -576,9 +623,11 @@
        global registers */
     // delay slot
     tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
-                 TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP);
+                 TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                 sizeof(long), HOST_ST_OP);
     tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
-                 TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP);
+                 TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                 sizeof(long), HOST_LD_OP);
 
     /* data_reg = sign_extend(arg0) */
     switch(opc) {
@@ -623,9 +672,17 @@
     tcg_out_nop(s);
 
     /* label1: */
+#if TARGET_LONG_BITS == 32
+    /* be label1 */
     *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) |
                    INSN_OFF22((unsigned long)s->code_ptr -
                               (unsigned long)label1_ptr));
+#else
+    /* be,pt %xcc label1 */
+    *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) |
+                   (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr -
+                              (unsigned long)label1_ptr));
+#endif
 
     /* ld [arg1 + x], arg1 */
     tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) -
@@ -757,7 +814,9 @@
     tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC);
 
     /* will become:
-       be label1 */
+       be label1
+        or
+       be,pt %xcc label1 */
     label1_ptr = (uint32_t *)s->code_ptr;
     tcg_out32(s, 0);
 
@@ -779,9 +838,11 @@
        global registers */
     // delay slot
     tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
-                 TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP);
+                 TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                 sizeof(long), HOST_ST_OP);
     tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
-                 TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP);
+                 TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                 sizeof(long), HOST_LD_OP);
 
     /* will become:
        ba label2 */
@@ -791,10 +852,17 @@
     /* nop (delay slot) */
     tcg_out_nop(s);
 
-    /* label1: */
+#if TARGET_LONG_BITS == 32
+    /* be label1 */
     *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) |
                    INSN_OFF22((unsigned long)s->code_ptr -
                               (unsigned long)label1_ptr));
+#else
+    /* be,pt %xcc label1 */
+    *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) |
+                   (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr -
+                              (unsigned long)label1_ptr));
+#endif
 
     /* ld [arg1 + x], arg1 */
     tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) -
@@ -903,13 +971,15 @@
            global registers */
         // delay slot
         tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
-                     TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_ST_OP);
+                     TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                     sizeof(long), HOST_ST_OP);
         tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK,
-                     TCG_TARGET_CALL_STACK_OFFSET - sizeof(long), HOST_LD_OP);
+                     TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE -
+                     sizeof(long), HOST_LD_OP);
         break;
     case INDEX_op_jmp:
     case INDEX_op_br:
-        tcg_out_branch(s, COND_A, args[0]);
+        tcg_out_branch_i32(s, COND_A, args[0]);
         tcg_out_nop(s);
         break;
     case INDEX_op_movi_i32:
@@ -1001,8 +1071,8 @@
 #endif
 
     case INDEX_op_brcond_i32:
-        tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
-                       args[3]);
+        tcg_out_brcond_i32(s, args[2], args[0], args[1], const_args[1],
+                           args[3]);
         break;
 
     case INDEX_op_qemu_ld8u:
@@ -1066,8 +1136,8 @@
         goto gen_arith32;
 
     case INDEX_op_brcond_i64:
-        tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
-                       args[3]);
+        tcg_out_brcond_i64(s, args[2], args[0], args[1], const_args[1],
+                           args[3]);
         break;
     case INDEX_op_qemu_ld64:
         tcg_out_qemu_ld(s, args, 3);
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 8dc07d3..97f3533 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -75,19 +75,21 @@
 #define TCG_REG_CALL_STACK TCG_REG_I6
 #ifdef __arch64__
 // Reserve space for AREG0
-#define TCG_TARGET_STACK_MINFRAME (176 + 2 * (int)sizeof(long))
-#define TCG_TARGET_CALL_STACK_OFFSET (2047 + TCG_TARGET_STACK_MINFRAME)
+#define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \
+                                   TCG_STATIC_CALL_ARGS_SIZE)
+#define TCG_TARGET_CALL_STACK_OFFSET (2047 - 16)
 #define TCG_TARGET_STACK_ALIGN 16
 #else
 // AREG0 + one word for alignment
-#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long))
+#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long) + \
+                                   TCG_STATIC_CALL_ARGS_SIZE)
 #define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME
 #define TCG_TARGET_STACK_ALIGN 8
 #endif
 
 /* optional instructions */
-//#define TCG_TARGET_HAS_bswap_i32
-//#define TCG_TARGET_HAS_bswap_i64
+//#define TCG_TARGET_HAS_bswap32_i32
+//#define TCG_TARGET_HAS_bswap64_i64
 //#define TCG_TARGET_HAS_neg_i32
 //#define TCG_TARGET_HAS_neg_i64
 
@@ -97,8 +99,6 @@
 #define TCG_AREG0 TCG_REG_G2
 #define TCG_AREG1 TCG_REG_G3
 #define TCG_AREG2 TCG_REG_G4
-#define TCG_AREG3 TCG_REG_G5
-#define TCG_AREG4 TCG_REG_G6
 #elif defined(__sparc_v9__)
 #define TCG_AREG0 TCG_REG_G5
 #define TCG_AREG1 TCG_REG_G6
@@ -107,7 +107,6 @@
 #define TCG_AREG0 TCG_REG_G6
 #define TCG_AREG1 TCG_REG_G1
 #define TCG_AREG2 TCG_REG_G2
-#define TCG_AREG3 TCG_REG_G3
 #endif
 
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
diff --git a/tcg/tcg-dyngen.c b/tcg/tcg-dyngen.c
deleted file mode 100644
index b4ceb5e..0000000
--- a/tcg/tcg-dyngen.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Tiny Code Generator for QEMU
- *
- * Copyright (c) 2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include <assert.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "config.h"
-#include "osdep.h"
-
-#include "tcg.h"
-
-int __op_param1, __op_param2, __op_param3;
-#if defined(__sparc__) || defined(__arm__)
-  void __op_gen_label1(){}
-  void __op_gen_label2(){}
-  void __op_gen_label3(){}
-#else
-  int __op_gen_label1, __op_gen_label2, __op_gen_label3;
-#endif
-int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
-
-#if 0
-#if defined(__s390__)
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-}
-#elif defined(__ia64__)
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-    while (start < stop) {
-	asm volatile ("fc %0" :: "r"(start));
-	start += 32;
-    }
-    asm volatile (";;sync.i;;srlz.i;;");
-}
-#elif defined(__powerpc__)
-
-#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
-
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-    unsigned long p;
-
-    start &= ~(MIN_CACHE_LINE_SIZE - 1);
-    stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
-
-    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
-        asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
-    }
-    asm volatile ("sync" : : : "memory");
-    for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
-        asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
-    }
-    asm volatile ("sync" : : : "memory");
-    asm volatile ("isync" : : : "memory");
-}
-#elif defined(__alpha__)
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-    asm ("imb");
-}
-#elif defined(__sparc__)
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-	unsigned long p;
-
-	p = start & ~(8UL - 1UL);
-	stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
-
-	for (; p < stop; p += 8)
-		__asm__ __volatile__("flush\t%0" : : "r" (p));
-}
-#elif defined(__arm__)
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-    register unsigned long _beg __asm ("a1") = start;
-    register unsigned long _end __asm ("a2") = stop;
-    register unsigned long _flg __asm ("a3") = 0;
-    __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
-}
-#elif defined(__mc68000)
-
-# include <asm/cachectl.h>
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-    cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
-}
-#elif defined(__mips__)
-
-#include <sys/cachectl.h>
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-    _flush_cache ((void *)start, stop - start, BCACHE);
-}
-#else
-#error unsupported CPU
-#endif
-
-#ifdef __alpha__
-
-register int gp asm("$29");
-
-static inline void immediate_ldah(void *p, int val) {
-    uint32_t *dest = p;
-    long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
-
-    *dest &= ~0xffff;
-    *dest |= high;
-    *dest |= 31 << 16;
-}
-static inline void immediate_lda(void *dest, int val) {
-    *(uint16_t *) dest = val;
-}
-void fix_bsr(void *p, int offset) {
-    uint32_t *dest = p;
-    *dest &= ~((1 << 21) - 1);
-    *dest |= (offset >> 2) & ((1 << 21) - 1);
-}
-
-#endif /* __alpha__ */
-
-#ifdef __ia64
-
-/* Patch instruction with "val" where "mask" has 1 bits. */
-static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
-{
-    uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
-#   define insn_mask ((1UL << 41) - 1)
-    unsigned long shift;
-
-    b0 = b[0]; b1 = b[1];
-    shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */
-    if (shift >= 64) {
-	m1 = mask << (shift - 64);
-	v1 = val << (shift - 64);
-    } else {
-	m0 = mask << shift; m1 = mask >> (64 - shift);
-	v0 = val  << shift; v1 = val >> (64 - shift);
-	b[0] = (b0 & ~m0) | (v0 & m0);
-    }
-    b[1] = (b1 & ~m1) | (v1 & m1);
-}
-
-static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val)
-{
-	ia64_patch(insn_addr,
-		   0x011ffffe000UL,
-		   (  ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
-		    | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */));
-	ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18);
-}
-
-static inline void ia64_imm64 (void *insn, uint64_t val)
-{
-    /* Ignore the slot number of the relocation; GCC and Intel
-       toolchains differed for some time on whether IMM64 relocs are
-       against slot 1 (Intel) or slot 2 (GCC).  */
-    uint64_t insn_addr = (uint64_t) insn & ~3UL;
-
-    ia64_patch(insn_addr + 2,
-	       0x01fffefe000UL,
-	       (  ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */
-		| ((val & 0x0000000000200000UL) <<  0) /* bit 21 -> 21 */
-		| ((val & 0x00000000001f0000UL) <<  6) /* bit 16 -> 22 */
-		| ((val & 0x000000000000ff80UL) << 20) /* bit  7 -> 27 */
-		| ((val & 0x000000000000007fUL) << 13) /* bit  0 -> 13 */)
-	    );
-    ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
-}
-
-static inline void ia64_imm60b (void *insn, uint64_t val)
-{
-    /* Ignore the slot number of the relocation; GCC and Intel
-       toolchains differed for some time on whether IMM64 relocs are
-       against slot 1 (Intel) or slot 2 (GCC).  */
-    uint64_t insn_addr = (uint64_t) insn & ~3UL;
-
-    if (val + ((uint64_t) 1 << 59) >= (1UL << 60))
-	fprintf(stderr, "%s: value %ld out of IMM60 range\n",
-		__FUNCTION__, (int64_t) val);
-    ia64_patch_imm60(insn_addr + 2, val);
-}
-
-static inline void ia64_imm22 (void *insn, uint64_t val)
-{
-    if (val + (1 << 21) >= (1 << 22))
-	fprintf(stderr, "%s: value %li out of IMM22 range\n",
-		__FUNCTION__, (int64_t)val);
-    ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
-	       (  ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
-		| ((val & 0x1f0000UL) <<  6) /* bit 16 -> 22 */
-		| ((val & 0x00ff80UL) << 20) /* bit  7 -> 27 */
-		| ((val & 0x00007fUL) << 13) /* bit  0 -> 13 */));
-}
-
-/* Like ia64_imm22(), but also clear bits 20-21.  For addl, this has
-   the effect of turning "addl rX=imm22,rY" into "addl
-   rX=imm22,r0".  */
-static inline void ia64_imm22_r0 (void *insn, uint64_t val)
-{
-    if (val + (1 << 21) >= (1 << 22))
-	fprintf(stderr, "%s: value %li out of IMM22 range\n",
-		__FUNCTION__, (int64_t)val);
-    ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20),
-	       (  ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
-		| ((val & 0x1f0000UL) <<  6) /* bit 16 -> 22 */
-		| ((val & 0x00ff80UL) << 20) /* bit  7 -> 27 */
-		| ((val & 0x00007fUL) << 13) /* bit  0 -> 13 */));
-}
-
-static inline void ia64_imm21b (void *insn, uint64_t val)
-{
-    if (val + (1 << 20) >= (1 << 21))
-	fprintf(stderr, "%s: value %li out of IMM21b range\n",
-		__FUNCTION__, (int64_t)val);
-    ia64_patch((uint64_t) insn, 0x11ffffe000UL,
-	       (  ((val & 0x100000UL) << 16) /* bit 20 -> 36 */
-		| ((val & 0x0fffffUL) << 13) /* bit  0 -> 13 */));
-}
-
-static inline void ia64_nop_b (void *insn)
-{
-    ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37);
-}
-
-static inline void ia64_ldxmov(void *insn, uint64_t val)
-{
-    if (val + (1 << 21) < (1 << 22))
-	ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37);
-}
-
-static inline int ia64_patch_ltoff(void *insn, uint64_t val,
-				   int relaxable)
-{
-    if (relaxable && (val + (1 << 21) < (1 << 22))) {
-	ia64_imm22_r0(insn, val);
-	return 0;
-    }
-    return 1;
-}
-
-struct ia64_fixup {
-    struct ia64_fixup *next;
-    void *addr;			/* address that needs to be patched */
-    long value;
-};
-
-#define IA64_PLT(insn, plt_index)			\
-do {							\
-    struct ia64_fixup *fixup = alloca(sizeof(*fixup));	\
-    fixup->next = plt_fixes;				\
-    plt_fixes = fixup;					\
-    fixup->addr = (insn);				\
-    fixup->value = (plt_index);				\
-    plt_offset[(plt_index)] = 1;			\
-} while (0)
-
-#define IA64_LTOFF(insn, val, relaxable)			\
-do {								\
-    if (ia64_patch_ltoff(insn, val, relaxable)) {		\
-	struct ia64_fixup *fixup = alloca(sizeof(*fixup));	\
-	fixup->next = ltoff_fixes;				\
-	ltoff_fixes = fixup;					\
-	fixup->addr = (insn);					\
-	fixup->value = (val);					\
-    }								\
-} while (0)
-
-static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
-				     struct ia64_fixup *ltoff_fixes,
-				     uint64_t gp,
-				     struct ia64_fixup *plt_fixes,
-				     int num_plts,
-				     unsigned long *plt_target,
-				     unsigned int *plt_offset)
-{
-    static const uint8_t plt_bundle[] = {
-	0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,	/* nop 0; movl r1=GP */
-	0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60,
-
-	0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,	/* nop 0; brl IP */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0
-    };
-    uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start;
-    uint64_t *vp;
-    struct ia64_fixup *fixup;
-    unsigned int offset = 0;
-    struct fdesc {
-	long ip;
-	long gp;
-    } *fdesc;
-    int i;
-
-    if (plt_fixes) {
-	plt_start = gen_code_ptr;
-
-	for (i = 0; i < num_plts; ++i) {
-	    if (plt_offset[i]) {
-		plt_offset[i] = offset;
-		offset += sizeof(plt_bundle);
-
-		fdesc = (struct fdesc *) plt_target[i];
-		memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
-		ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
-		ia64_imm60b(gen_code_ptr + 0x12,
-			    (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4);
-		gen_code_ptr += sizeof(plt_bundle);
-	    }
-	}
-
-	for (fixup = plt_fixes; fixup; fixup = fixup->next)
-	    ia64_imm21b(fixup->addr,
-			((long) plt_start + plt_offset[fixup->value]
-			 - ((long) fixup->addr & ~0xf)) >> 4);
-    }
-
-    got_start = gen_code_ptr;
-
-    /* First, create the GOT: */
-    for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
-	/* first check if we already have this value in the GOT: */
-	for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp)
-	    if (*vp == fixup->value)
-		break;
-	if (vp == (uint64_t *) gen_code_ptr) {
-	    /* Nope, we need to put the value in the GOT: */
-	    *vp = fixup->value;
-	    gen_code_ptr += 8;
-	}
-	ia64_imm22(fixup->addr, (long) vp - gp);
-    }
-    /* Keep code ptr aligned. */
-    if ((long) gen_code_ptr & 15)
-	gen_code_ptr += 8;
-    *gen_code_pp = gen_code_ptr;
-}
-#endif
-#endif
-
-#ifdef CONFIG_DYNGEN_OP
-
-#if defined __hppa__
-struct hppa_branch_stub {
-    uint32_t *location;
-    long target;
-    struct hppa_branch_stub *next;
-};
-
-#define HPPA_RECORD_BRANCH(LIST, LOC, TARGET) \
-do { \
-    struct hppa_branch_stub *stub = alloca(sizeof(struct hppa_branch_stub)); \
-    stub->location = LOC; \
-    stub->target = TARGET; \
-    stub->next = LIST; \
-    LIST = stub; \
-} while (0)
-
-static inline void hppa_process_stubs(struct hppa_branch_stub *stub,
-                                      uint8_t **gen_code_pp)
-{
-    uint32_t *s = (uint32_t *)*gen_code_pp;
-    uint32_t *p = s + 1;
-
-    if (!stub) return;
-
-    for (; stub != NULL; stub = stub->next) {
-        unsigned long l = (unsigned long)p;
-        /* stub:
-         * ldil L'target, %r1
-         * be,n R'target(%sr4,%r1)
-         */
-        *p++ = 0x20200000 | reassemble_21(lrsel(stub->target, 0));
-        *p++ = 0xe0202002 | (reassemble_17(rrsel(stub->target, 0) >> 2));
-        hppa_patch17f(stub->location, l, 0);
-    }
-    /* b,l,n stub,%r0 */
-    *s = 0xe8000002 | reassemble_17((p - s) - 2);
-    *gen_code_pp = (uint8_t *)p;
-}
-#endif /* __hppa__ */
-
-const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr)
-{
-    uint8_t *gen_code_ptr;
-
-#ifdef __hppa__
-    struct hppa_branch_stub *hppa_stubs = NULL;
-#endif
-
-    gen_code_ptr = s->code_ptr;
-    switch(opc) {
-
-/* op.h is dynamically generated by dyngen.c from op.c */
-#include "op.h"
-
-    default:
-        tcg_abort();
-    }
-
-#ifdef __hppa__
-    hppa_process_stubs(hppa_stubs, &gen_code_ptr);
-#endif
-
-    s->code_ptr = gen_code_ptr;
-    return opparam_ptr;
-}
-#endif
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index bc6be85..7cb6934 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -23,17 +23,18 @@
  */
 #include "tcg.h"
 
-#ifdef CONFIG_DYNGEN_OP
-/* legacy dyngen operations */
-#include "gen-op.h"
-#endif
-
 int gen_new_label(void);
 
-static inline void tcg_gen_op1(int opc, TCGv arg1)
+static inline void tcg_gen_op1_i32(int opc, TCGv_i32 arg1)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+}
+
+static inline void tcg_gen_op1_i64(int opc, TCGv_i64 arg1)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
 }
 
 static inline void tcg_gen_op1i(int opc, TCGArg arg1)
@@ -42,17 +43,31 @@
     *gen_opparam_ptr++ = arg1;
 }
 
-static inline void tcg_gen_op2(int opc, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_op2_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
 }
 
-static inline void tcg_gen_op2i(int opc, TCGv arg1, TCGArg arg2)
+static inline void tcg_gen_op2_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+}
+
+static inline void tcg_gen_op2i_i32(int opc, TCGv_i32 arg1, TCGArg arg2)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = arg2;
+}
+
+static inline void tcg_gen_op2i_i64(int opc, TCGv_i64 arg1, TCGArg arg2)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
     *gen_opparam_ptr++ = arg2;
 }
 
@@ -63,98 +78,230 @@
     *gen_opparam_ptr++ = arg2;
 }
 
-static inline void tcg_gen_op3(int opc, TCGv arg1, TCGv arg2, TCGv arg3)
+static inline void tcg_gen_op3_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                   TCGv_i32 arg3)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
-    *gen_opparam_ptr++ = GET_TCGV(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
 }
 
-static inline void tcg_gen_op3i(int opc, TCGv arg1, TCGv arg2, TCGArg arg3)
+static inline void tcg_gen_op3_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                   TCGv_i64 arg3)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+}
+
+static inline void tcg_gen_op3i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                    TCGArg arg3)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
     *gen_opparam_ptr++ = arg3;
 }
 
-static inline void tcg_gen_op4(int opc, TCGv arg1, TCGv arg2, TCGv arg3, 
-                               TCGv arg4)
+static inline void tcg_gen_op3i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                    TCGArg arg3)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
-    *gen_opparam_ptr++ = GET_TCGV(arg3);
-    *gen_opparam_ptr++ = GET_TCGV(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = arg3;
 }
 
-static inline void tcg_gen_op4i(int opc, TCGv arg1, TCGv arg2, TCGv arg3, 
-                                TCGArg arg4)
+static inline void tcg_gen_ldst_op_i32(int opc, TCGv_i32 val, TCGv_ptr base,
+                                       TCGArg offset)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
-    *gen_opparam_ptr++ = GET_TCGV(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(val);
+    *gen_opparam_ptr++ = GET_TCGV_PTR(base);
+    *gen_opparam_ptr++ = offset;
+}
+
+static inline void tcg_gen_ldst_op_i64(int opc, TCGv_i64 val, TCGv_ptr base,
+                                       TCGArg offset)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(val);
+    *gen_opparam_ptr++ = GET_TCGV_PTR(base);
+    *gen_opparam_ptr++ = offset;
+}
+
+static inline void tcg_gen_qemu_ldst_op_i64_i32(int opc, TCGv_i64 val, TCGv_i32 addr,
+                                                TCGArg mem_index)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(val);
+    *gen_opparam_ptr++ = GET_TCGV_I32(addr);
+    *gen_opparam_ptr++ = mem_index;
+}
+
+static inline void tcg_gen_qemu_ldst_op_i64_i64(int opc, TCGv_i64 val, TCGv_i64 addr,
+                                                TCGArg mem_index)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(val);
+    *gen_opparam_ptr++ = GET_TCGV_I64(addr);
+    *gen_opparam_ptr++ = mem_index;
+}
+
+static inline void tcg_gen_op4_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                   TCGv_i32 arg3, TCGv_i32 arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+}
+
+static inline void tcg_gen_op4_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                   TCGv_i64 arg3, TCGv_i64 arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+}
+
+static inline void tcg_gen_op4i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                    TCGv_i32 arg3, TCGArg arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
     *gen_opparam_ptr++ = arg4;
 }
 
-static inline void tcg_gen_op4ii(int opc, TCGv arg1, TCGv arg2, TCGArg arg3, 
-                                 TCGArg arg4)
+static inline void tcg_gen_op4i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                    TCGv_i64 arg3, TCGArg arg4)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = arg4;
+}
+
+static inline void tcg_gen_op4ii_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                     TCGArg arg3, TCGArg arg4)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
     *gen_opparam_ptr++ = arg3;
     *gen_opparam_ptr++ = arg4;
 }
 
-static inline void tcg_gen_op5(int opc, TCGv arg1, TCGv arg2, 
-                               TCGv arg3, TCGv arg4,
-                               TCGv arg5)
+static inline void tcg_gen_op4ii_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                     TCGArg arg3, TCGArg arg4)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
-    *gen_opparam_ptr++ = GET_TCGV(arg3);
-    *gen_opparam_ptr++ = GET_TCGV(arg4);
-    *gen_opparam_ptr++ = GET_TCGV(arg5);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = arg3;
+    *gen_opparam_ptr++ = arg4;
 }
 
-static inline void tcg_gen_op5i(int opc, TCGv arg1, TCGv arg2, 
-                                TCGv arg3, TCGv arg4,
-                                TCGArg arg5)
+static inline void tcg_gen_op5_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                   TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
-    *gen_opparam_ptr++ = GET_TCGV(arg3);
-    *gen_opparam_ptr++ = GET_TCGV(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg5);
+}
+
+static inline void tcg_gen_op5_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                   TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg5);
+}
+
+static inline void tcg_gen_op5i_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                    TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
     *gen_opparam_ptr++ = arg5;
 }
 
-static inline void tcg_gen_op6(int opc, TCGv arg1, TCGv arg2, 
-                               TCGv arg3, TCGv arg4,
-                               TCGv arg5, TCGv arg6)
+static inline void tcg_gen_op5i_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                    TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
-    *gen_opparam_ptr++ = GET_TCGV(arg3);
-    *gen_opparam_ptr++ = GET_TCGV(arg4);
-    *gen_opparam_ptr++ = GET_TCGV(arg5);
-    *gen_opparam_ptr++ = GET_TCGV(arg6);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+    *gen_opparam_ptr++ = arg5;
 }
 
-static inline void tcg_gen_op6ii(int opc, TCGv arg1, TCGv arg2, 
-                                 TCGv arg3, TCGv arg4,
-                                 TCGArg arg5, TCGArg arg6)
+static inline void tcg_gen_op6_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                   TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5,
+                                   TCGv_i32 arg6)
 {
     *gen_opc_ptr++ = opc;
-    *gen_opparam_ptr++ = GET_TCGV(arg1);
-    *gen_opparam_ptr++ = GET_TCGV(arg2);
-    *gen_opparam_ptr++ = GET_TCGV(arg3);
-    *gen_opparam_ptr++ = GET_TCGV(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg5);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg6);
+}
+
+static inline void tcg_gen_op6_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                   TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5,
+                                   TCGv_i64 arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg5);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg6);
+}
+
+static inline void tcg_gen_op6ii_i32(int opc, TCGv_i32 arg1, TCGv_i32 arg2,
+                                     TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5,
+                                     TCGArg arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I32(arg4);
+    *gen_opparam_ptr++ = arg5;
+    *gen_opparam_ptr++ = arg6;
+}
+
+static inline void tcg_gen_op6ii_i64(int opc, TCGv_i64 arg1, TCGv_i64 arg2,
+                                     TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5,
+                                     TCGArg arg6)
+{
+    *gen_opc_ptr++ = opc;
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg1);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg2);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg3);
+    *gen_opparam_ptr++ = GET_TCGV_I64(arg4);
     *gen_opparam_ptr++ = arg5;
     *gen_opparam_ptr++ = arg6;
 }
@@ -169,232 +316,134 @@
     tcg_gen_op1i(INDEX_op_br, label);
 }
 
-static inline void tcg_gen_mov_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_mov_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-    if (GET_TCGV(ret) != GET_TCGV(arg))
-        tcg_gen_op2(INDEX_op_mov_i32, ret, arg);
+    if (!TCGV_EQUAL_I32(ret, arg))
+        tcg_gen_op2_i32(INDEX_op_mov_i32, ret, arg);
 }
 
-static inline void tcg_gen_movi_i32(TCGv ret, int32_t arg)
+static inline void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg)
 {
-    tcg_gen_op2i(INDEX_op_movi_i32, ret, arg);
+    tcg_gen_op2i_i32(INDEX_op_movi_i32, ret, arg);
 }
 
 /* helper calls */
-#define TCG_HELPER_CALL_FLAGS 0
-
-static inline void tcg_gen_helper_0_0(void *func)
+static inline void tcg_gen_helperN(void *func, int flags, int sizemask,
+                                   TCGArg ret, int nargs, TCGArg *args)
 {
-    TCGv t0;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx, 
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 0, NULL, 0, NULL);
-    tcg_temp_free(t0);
+    TCGv_ptr fn;
+    fn = tcg_const_ptr((tcg_target_long)func);
+    tcg_gen_callN(&tcg_ctx, fn, flags, sizemask, ret,
+                  nargs, args);
+    tcg_temp_free_ptr(fn);
 }
 
-static inline void tcg_gen_helper_0_1(void *func, TCGv arg)
+/* FIXME: Should this be pure?  */
+static inline void tcg_gen_helper64(void *func, TCGv_i64 ret,
+                                    TCGv_i64 a, TCGv_i64 b)
 {
-    TCGv t0;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx,
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 0, NULL, 1, &arg);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_helper_0_2(void *func, TCGv arg1, TCGv arg2)
-{
-    TCGv args[2];
-    TCGv t0;
-    args[0] = arg1;
-    args[1] = arg2;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx, 
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 0, NULL, 2, args);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_helper_0_3(void *func,
-                                      TCGv arg1, TCGv arg2, TCGv arg3)
-{
-    TCGv args[3];
-    TCGv t0;
-    args[0] = arg1;
-    args[1] = arg2;
-    args[2] = arg3;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx,
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 0, NULL, 3, args);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_helper_0_4(void *func, TCGv arg1, TCGv arg2,
-                                      TCGv arg3, TCGv arg4)
-{
-    TCGv args[4];
-    TCGv t0;
-    args[0] = arg1;
-    args[1] = arg2;
-    args[2] = arg3;
-    args[3] = arg4;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx,
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 0, NULL, 4, args);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_helper_1_0(void *func, TCGv ret)
-{
-    TCGv t0;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx,
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 1, &ret, 0, NULL);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_helper_1_1(void *func, TCGv ret, TCGv arg1)
-{
-    TCGv t0;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx,
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 1, &ret, 1, &arg1);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_helper_1_2(void *func, TCGv ret, 
-                                      TCGv arg1, TCGv arg2)
-{
-    TCGv args[2];
-    TCGv t0;
-    args[0] = arg1;
-    args[1] = arg2;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx, 
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 1, &ret, 2, args);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_helper_1_3(void *func, TCGv ret,
-                                      TCGv arg1, TCGv arg2, TCGv arg3)
-{
-    TCGv args[3];
-    TCGv t0;
-    args[0] = arg1;
-    args[1] = arg2;
-    args[2] = arg3;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx,
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 1, &ret, 3, args);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_helper_1_4(void *func, TCGv ret,
-                                      TCGv arg1, TCGv arg2, TCGv arg3,
-                                      TCGv arg4)
-{
-    TCGv args[4];
-    TCGv t0;
-    args[0] = arg1;
-    args[1] = arg2;
-    args[2] = arg3;
-    args[3] = arg4;
-    t0 = tcg_const_ptr((tcg_target_long)func);
-    tcg_gen_call(&tcg_ctx,
-                 t0, TCG_HELPER_CALL_FLAGS,
-                 1, &ret, 4, args);
-    tcg_temp_free(t0);
+    TCGv_ptr fn;
+    TCGArg args[2];
+    fn = tcg_const_ptr((tcg_target_long)func);
+    args[0] = GET_TCGV_I64(a);
+    args[1] = GET_TCGV_I64(b);
+    tcg_gen_callN(&tcg_ctx, fn, 0, 7, GET_TCGV_I64(ret), 2, args);
+    tcg_temp_free_ptr(fn);
 }
 
 /* 32 bit ops */
 
-static inline void tcg_gen_ld8u_i32(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld8u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld8u_i32, ret, arg2, offset);
+    tcg_gen_ldst_op_i32(INDEX_op_ld8u_i32, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld8s_i32(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld8s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld8s_i32, ret, arg2, offset);
+    tcg_gen_ldst_op_i32(INDEX_op_ld8s_i32, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld16u_i32(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld16u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld16u_i32, ret, arg2, offset);
+    tcg_gen_ldst_op_i32(INDEX_op_ld16u_i32, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld16s_i32(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld16s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld16s_i32, ret, arg2, offset);
+    tcg_gen_ldst_op_i32(INDEX_op_ld16s_i32, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld_i32(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld_i32, ret, arg2, offset);
+    tcg_gen_ldst_op_i32(INDEX_op_ld_i32, ret, arg2, offset);
 }
 
-static inline void tcg_gen_st8_i32(TCGv arg1, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_st8_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_st8_i32, arg1, arg2, offset);
+    tcg_gen_ldst_op_i32(INDEX_op_st8_i32, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_st16_i32(TCGv arg1, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_st16_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_st16_i32, arg1, arg2, offset);
+    tcg_gen_ldst_op_i32(INDEX_op_st16_i32, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_st_i32(TCGv arg1, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_st_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_st_i32, arg1, arg2, offset);
+    tcg_gen_ldst_op_i32(INDEX_op_st_i32, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_add_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_add_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_add_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_add_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_addi_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
     /* some cases can be optimized here */
     if (arg2 == 0) {
         tcg_gen_mov_i32(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i32(arg2);
+        TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_add_i32(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i32(t0);
     }
 }
 
-static inline void tcg_gen_sub_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_sub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_sub_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_sub_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_subi_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0 = tcg_const_i32(arg1);
+    tcg_gen_sub_i32(ret, t0, arg2);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
     /* some cases can be optimized here */
     if (arg2 == 0) {
         tcg_gen_mov_i32(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i32(arg2);
+        TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_sub_i32(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i32(t0);
     }
 }
 
-static inline void tcg_gen_and_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_and_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_and_i32, ret, arg1, arg2);
+    if (TCGV_EQUAL_I32(arg1, arg2)) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        tcg_gen_op3_i32(INDEX_op_and_i32, ret, arg1, arg2);
+    }
 }
 
-static inline void tcg_gen_andi_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
     /* some cases can be optimized here */
     if (arg2 == 0) {
@@ -402,18 +451,22 @@
     } else if (arg2 == 0xffffffff) {
         tcg_gen_mov_i32(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i32(arg2);
+        TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_and_i32(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i32(t0);
     }
 }
 
-static inline void tcg_gen_or_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_or_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_or_i32, ret, arg1, arg2);
+    if (TCGV_EQUAL_I32(arg1, arg2)) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        tcg_gen_op3_i32(INDEX_op_or_i32, ret, arg1, arg2);
+    }
 }
 
-static inline void tcg_gen_ori_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
     /* some cases can be optimized here */
     if (arg2 == 0xffffffff) {
@@ -421,688 +474,715 @@
     } else if (arg2 == 0) {
         tcg_gen_mov_i32(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i32(arg2);
+        TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_or_i32(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i32(t0);
     }
 }
 
-static inline void tcg_gen_xor_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_xor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_xor_i32, ret, arg1, arg2);
+    if (TCGV_EQUAL_I32(arg1, arg2)) {
+        tcg_gen_movi_i32(ret, 0);
+    } else {
+        tcg_gen_op3_i32(INDEX_op_xor_i32, ret, arg1, arg2);
+    }
 }
 
-static inline void tcg_gen_xori_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
     /* some cases can be optimized here */
     if (arg2 == 0) {
         tcg_gen_mov_i32(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i32(arg2);
+        TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_xor_i32(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i32(t0);
     }
 }
 
-static inline void tcg_gen_shl_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_shl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_shl_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_shl_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_shli_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
     if (arg2 == 0) {
         tcg_gen_mov_i32(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i32(arg2);
+        TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_shl_i32(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i32(t0);
     }
 }
 
-static inline void tcg_gen_shr_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_shr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_shr_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_shr_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_shri_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
     if (arg2 == 0) {
         tcg_gen_mov_i32(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i32(arg2);
+        TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_shr_i32(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i32(t0);
     }
 }
 
-static inline void tcg_gen_sar_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_sar_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_sar_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_sar_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_sari_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
     if (arg2 == 0) {
         tcg_gen_mov_i32(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i32(arg2);
+        TCGv_i32 t0 = tcg_const_i32(arg2);
         tcg_gen_sar_i32(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i32(t0);
     }
 }
 
-static inline void tcg_gen_brcond_i32(int cond, TCGv arg1, TCGv arg2, 
+static inline void tcg_gen_brcond_i32(int cond, TCGv_i32 arg1, TCGv_i32 arg2,
                                       int label_index)
 {
-    tcg_gen_op4ii(INDEX_op_brcond_i32, arg1, arg2, cond, label_index);
+    tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index);
 }
 
-static inline void tcg_gen_brcondi_i32(int cond, TCGv arg1, int32_t arg2, 
+static inline void tcg_gen_brcondi_i32(int cond, TCGv_i32 arg1, int32_t arg2,
                                        int label_index)
 {
-    TCGv t0 = tcg_const_i32(arg2);
+    TCGv_i32 t0 = tcg_const_i32(arg2);
     tcg_gen_brcond_i32(cond, arg1, t0, label_index);
-    tcg_temp_free(t0);
+    tcg_temp_free_i32(t0);
 }
 
-static inline void tcg_gen_mul_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_mul_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_mul_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_muli_i32(TCGv ret, TCGv arg1, int32_t arg2)
+static inline void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
 {
-    TCGv t0 = tcg_const_i32(arg2);
+    TCGv_i32 t0 = tcg_const_i32(arg2);
     tcg_gen_mul_i32(ret, arg1, t0);
-    tcg_temp_free(t0);
+    tcg_temp_free_i32(t0);
 }
 
 #ifdef TCG_TARGET_HAS_div_i32
-static inline void tcg_gen_div_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_div_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_rem_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_rem_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_divu_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_divu_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_remu_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    tcg_gen_op3(INDEX_op_remu_i32, ret, arg1, arg2);
+    tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2);
 }
 #else
-static inline void tcg_gen_div_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
     tcg_gen_sari_i32(t0, arg1, 31);
-    tcg_gen_op5(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2);
-    tcg_temp_free(t0);
+    tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2);
+    tcg_temp_free_i32(t0);
 }
 
-static inline void tcg_gen_rem_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
     tcg_gen_sari_i32(t0, arg1, 31);
-    tcg_gen_op5(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2);
-    tcg_temp_free(t0);
+    tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2);
+    tcg_temp_free_i32(t0);
 }
 
-static inline void tcg_gen_divu_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
     tcg_gen_movi_i32(t0, 0);
-    tcg_gen_op5(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2);
-    tcg_temp_free(t0);
+    tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2);
+    tcg_temp_free_i32(t0);
 }
 
-static inline void tcg_gen_remu_i32(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
     tcg_gen_movi_i32(t0, 0);
-    tcg_gen_op5(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2);
-    tcg_temp_free(t0);
+    tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2);
+    tcg_temp_free_i32(t0);
 }
 #endif
 
 #if TCG_TARGET_REG_BITS == 32
 
-static inline void tcg_gen_mov_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    if (GET_TCGV(ret) != GET_TCGV(arg)) {
-        tcg_gen_mov_i32(ret, arg);
+    if (!TCGV_EQUAL_I64(ret, arg)) {
+        tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
         tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
     }
 }
 
-static inline void tcg_gen_movi_i64(TCGv ret, int64_t arg)
+static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
 {
-    tcg_gen_movi_i32(ret, arg);
+    tcg_gen_movi_i32(TCGV_LOW(ret), arg);
     tcg_gen_movi_i32(TCGV_HIGH(ret), arg >> 32);
 }
 
-static inline void tcg_gen_ld8u_i64(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                    tcg_target_long offset)
 {
-    tcg_gen_ld8u_i32(ret, arg2, offset);
+    tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset);
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 }
 
-static inline void tcg_gen_ld8s_i64(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                    tcg_target_long offset)
 {
-    tcg_gen_ld8s_i32(ret, arg2, offset);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), 31);
 }
 
-static inline void tcg_gen_ld16u_i64(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
 {
-    tcg_gen_ld16u_i32(ret, arg2, offset);
+    tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset);
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 }
 
-static inline void tcg_gen_ld16s_i64(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
 {
-    tcg_gen_ld16s_i32(ret, arg2, offset);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 }
 
-static inline void tcg_gen_ld32u_i64(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
 {
-    tcg_gen_ld_i32(ret, arg2, offset);
+    tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 }
 
-static inline void tcg_gen_ld32s_i64(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                     tcg_target_long offset)
 {
-    tcg_gen_ld_i32(ret, arg2, offset);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 }
 
-static inline void tcg_gen_ld_i64(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2,
+                                  tcg_target_long offset)
 {
     /* since arg2 and ret have different types, they cannot be the
        same temporary */
 #ifdef TCG_TARGET_WORDS_BIGENDIAN
     tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset);
-    tcg_gen_ld_i32(ret, arg2, offset + 4);
+    tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4);
 #else
-    tcg_gen_ld_i32(ret, arg2, offset);
+    tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset);
     tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset + 4);
 #endif
 }
 
-static inline void tcg_gen_st8_i64(TCGv arg1, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                   tcg_target_long offset)
 {
-    tcg_gen_st8_i32(arg1, arg2, offset);
+    tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset);
 }
 
-static inline void tcg_gen_st16_i64(TCGv arg1, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                    tcg_target_long offset)
 {
-    tcg_gen_st16_i32(arg1, arg2, offset);
+    tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset);
 }
 
-static inline void tcg_gen_st32_i64(TCGv arg1, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                    tcg_target_long offset)
 {
-    tcg_gen_st_i32(arg1, arg2, offset);
+    tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset);
 }
 
-static inline void tcg_gen_st_i64(TCGv arg1, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2,
+                                  tcg_target_long offset)
 {
 #ifdef TCG_TARGET_WORDS_BIGENDIAN
     tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset);
-    tcg_gen_st_i32(arg1, arg2, offset + 4);
+    tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4);
 #else
-    tcg_gen_st_i32(arg1, arg2, offset);
+    tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset);
     tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset + 4);
 #endif
 }
 
-static inline void tcg_gen_add_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op6(INDEX_op_add2_i32, ret, TCGV_HIGH(ret), 
-                arg1, TCGV_HIGH(arg1), arg2, TCGV_HIGH(arg2));
+    tcg_gen_op6_i32(INDEX_op_add2_i32, TCGV_LOW(ret), TCGV_HIGH(ret),
+                    TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+                    TCGV_HIGH(arg2));
 }
 
-static inline void tcg_gen_addi_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    TCGv t0 = tcg_const_i64(arg2);
-    tcg_gen_add_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
+    tcg_gen_op6_i32(INDEX_op_sub2_i32, TCGV_LOW(ret), TCGV_HIGH(ret),
+                    TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+                    TCGV_HIGH(arg2));
 }
 
-static inline void tcg_gen_sub_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op6(INDEX_op_sub2_i32, ret, TCGV_HIGH(ret), 
-                arg1, TCGV_HIGH(arg1), arg2, TCGV_HIGH(arg2));
-}
-
-static inline void tcg_gen_subi_i64(TCGv ret, TCGv arg1, int64_t arg2)
-{
-    TCGv t0 = tcg_const_i64(arg2);
-    tcg_gen_sub_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_and_i64(TCGv ret, TCGv arg1, TCGv arg2)
-{
-    tcg_gen_and_i32(ret, arg1, arg2);
+    tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
     tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
 }
 
-static inline void tcg_gen_andi_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
-    tcg_gen_andi_i32(ret, arg1, arg2);
+    tcg_gen_andi_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
     tcg_gen_andi_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
 }
 
-static inline void tcg_gen_or_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_or_i32(ret, arg1, arg2);
+    tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
     tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
 }
 
-static inline void tcg_gen_ori_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
-    tcg_gen_ori_i32(ret, arg1, arg2);
+    tcg_gen_ori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
     tcg_gen_ori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
 }
 
-static inline void tcg_gen_xor_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_xor_i32(ret, arg1, arg2);
+    tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2));
     tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2));
 }
 
-static inline void tcg_gen_xori_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
-    tcg_gen_xori_i32(ret, arg1, arg2);
+    tcg_gen_xori_i32(TCGV_LOW(ret), TCGV_LOW(arg1), arg2);
     tcg_gen_xori_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), arg2 >> 32);
 }
 
 /* XXX: use generic code when basic block handling is OK or CPU
    specific code (x86) */
-static inline void tcg_gen_shl_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_helper_1_2(tcg_helper_shl_i64, ret, arg1, arg2);
+    tcg_gen_helper64(tcg_helper_shl_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_shli_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
     tcg_gen_shifti_i64(ret, arg1, arg2, 0, 0);
 }
 
-static inline void tcg_gen_shr_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_helper_1_2(tcg_helper_shr_i64, ret, arg1, arg2);
+    tcg_gen_helper64(tcg_helper_shr_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_shri_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
     tcg_gen_shifti_i64(ret, arg1, arg2, 1, 0);
 }
 
-static inline void tcg_gen_sar_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_helper_1_2(tcg_helper_sar_i64, ret, arg1, arg2);
+    tcg_gen_helper64(tcg_helper_sar_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_sari_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
     tcg_gen_shifti_i64(ret, arg1, arg2, 1, 1);
 }
 
-static inline void tcg_gen_brcond_i64(int cond, TCGv arg1, TCGv arg2, 
+static inline void tcg_gen_brcond_i64(int cond, TCGv_i64 arg1, TCGv_i64 arg2,
                                       int label_index)
 {
-    tcg_gen_op6ii(INDEX_op_brcond2_i32, 
-                  arg1, TCGV_HIGH(arg1), arg2, TCGV_HIGH(arg2),
-                  cond, label_index);
+    tcg_gen_op6ii_i32(INDEX_op_brcond2_i32,
+                      TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2),
+                      TCGV_HIGH(arg2), cond, label_index);
 }
 
-static inline void tcg_gen_mul_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    TCGv t0, t1;
-    
-    t0 = tcg_temp_new(TCG_TYPE_I64);
-    t1 = tcg_temp_new(TCG_TYPE_I32);
+    TCGv_i64 t0;
+    TCGv_i32 t1;
 
-    tcg_gen_op4(INDEX_op_mulu2_i32, t0, TCGV_HIGH(t0), arg1, arg2);
-    
-    tcg_gen_mul_i32(t1, arg1, TCGV_HIGH(arg2));
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i32();
+
+    tcg_gen_op4_i32(INDEX_op_mulu2_i32, TCGV_LOW(t0), TCGV_HIGH(t0),
+                    TCGV_LOW(arg1), TCGV_LOW(arg2));
+
+    tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2));
     tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
-    tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), arg2);
+    tcg_gen_mul_i32(t1, TCGV_HIGH(arg1), TCGV_LOW(arg2));
     tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1);
-    
+
     tcg_gen_mov_i64(ret, t0);
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i32(t1);
 }
 
-static inline void tcg_gen_muli_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    TCGv t0 = tcg_const_i64(arg2);
-    tcg_gen_mul_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
+    tcg_gen_helper64(tcg_helper_div_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_div_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_helper_1_2(tcg_helper_div_i64, ret, arg1, arg2);
+    tcg_gen_helper64(tcg_helper_rem_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_rem_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_helper_1_2(tcg_helper_rem_i64, ret, arg1, arg2);
+    tcg_gen_helper64(tcg_helper_divu_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_divu_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_helper_1_2(tcg_helper_divu_i64, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_remu_i64(TCGv ret, TCGv arg1, TCGv arg2)
-{
-    tcg_gen_helper_1_2(tcg_helper_remu_i64, ret, arg1, arg2);
+    tcg_gen_helper64(tcg_helper_remu_i64, ret, arg1, arg2);
 }
 
 #else
 
-static inline void tcg_gen_mov_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    if (GET_TCGV(ret) != GET_TCGV(arg))
-        tcg_gen_op2(INDEX_op_mov_i64, ret, arg);
+    if (!TCGV_EQUAL_I64(ret, arg))
+        tcg_gen_op2_i64(INDEX_op_mov_i64, ret, arg);
 }
 
-static inline void tcg_gen_movi_i64(TCGv ret, int64_t arg)
+static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
 {
-    tcg_gen_op2i(INDEX_op_movi_i64, ret, arg);
+    tcg_gen_op2i_i64(INDEX_op_movi_i64, ret, arg);
 }
 
-static inline void tcg_gen_ld8u_i64(TCGv ret, TCGv arg2,
+static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_i64 arg2,
                                     tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld8u_i64, ret, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_ld8u_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld8s_i64(TCGv ret, TCGv arg2,
+static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_i64 arg2,
                                     tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld8s_i64, ret, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_ld8s_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld16u_i64(TCGv ret, TCGv arg2,
+static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_i64 arg2,
                                      tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld16u_i64, ret, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_ld16u_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld16s_i64(TCGv ret, TCGv arg2,
+static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_i64 arg2,
                                      tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld16s_i64, ret, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_ld16s_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld32u_i64(TCGv ret, TCGv arg2,
+static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_i64 arg2,
                                      tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld32u_i64, ret, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_ld32u_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld32s_i64(TCGv ret, TCGv arg2,
+static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_i64 arg2,
                                      tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld32s_i64, ret, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_ld32s_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_ld_i64(TCGv ret, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_i64 arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_ld_i64, ret, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_ld_i64, ret, arg2, offset);
 }
 
-static inline void tcg_gen_st8_i64(TCGv arg1, TCGv arg2,
+static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_i64 arg2,
                                    tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_st8_i64, arg1, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_st8_i64, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_st16_i64(TCGv arg1, TCGv arg2,
+static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_i64 arg2,
                                     tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_st16_i64, arg1, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_st16_i64, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_st32_i64(TCGv arg1, TCGv arg2,
+static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_i64 arg2,
                                     tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_st32_i64, arg1, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_st32_i64, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_st_i64(TCGv arg1, TCGv arg2, tcg_target_long offset)
+static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_i64 arg2, tcg_target_long offset)
 {
-    tcg_gen_op3i(INDEX_op_st_i64, arg1, arg2, offset);
+    tcg_gen_ldst_op_i64(INDEX_op_st_i64, arg1, arg2, offset);
 }
 
-static inline void tcg_gen_add_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_add_i64, ret, arg1, arg2);
+    tcg_gen_op3_i64(INDEX_op_add_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_addi_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    TCGv t0 = tcg_const_i64(arg2);
-    tcg_gen_add_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
+    tcg_gen_op3_i64(INDEX_op_sub_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_sub_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_sub_i64, ret, arg1, arg2);
+    if (TCGV_EQUAL_I64(arg1, arg2)) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        tcg_gen_op3_i64(INDEX_op_and_i64, ret, arg1, arg2);
+    }
 }
 
-static inline void tcg_gen_subi_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
-    TCGv t0 = tcg_const_i64(arg2);
-    tcg_gen_sub_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
-}
-
-static inline void tcg_gen_and_i64(TCGv ret, TCGv arg1, TCGv arg2)
-{
-    tcg_gen_op3(INDEX_op_and_i64, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_andi_i64(TCGv ret, TCGv arg1, int64_t arg2)
-{
-    TCGv t0 = tcg_const_i64(arg2);
+    TCGv_i64 t0 = tcg_const_i64(arg2);
     tcg_gen_and_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
+    tcg_temp_free_i64(t0);
 }
 
-static inline void tcg_gen_or_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_or_i64, ret, arg1, arg2);
+    if (TCGV_EQUAL_I64(arg1, arg2)) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        tcg_gen_op3_i64(INDEX_op_or_i64, ret, arg1, arg2);
+    }
 }
 
-static inline void tcg_gen_ori_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_ori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
-    TCGv t0 = tcg_const_i64(arg2);
+    TCGv_i64 t0 = tcg_const_i64(arg2);
     tcg_gen_or_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
+    tcg_temp_free_i64(t0);
 }
 
-static inline void tcg_gen_xor_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_xor_i64, ret, arg1, arg2);
+    if (TCGV_EQUAL_I64(arg1, arg2)) {
+        tcg_gen_movi_i64(ret, 0);
+    } else {
+        tcg_gen_op3_i64(INDEX_op_xor_i64, ret, arg1, arg2);
+    }
 }
 
-static inline void tcg_gen_xori_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
-    TCGv t0 = tcg_const_i64(arg2);
+    TCGv_i64 t0 = tcg_const_i64(arg2);
     tcg_gen_xor_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
+    tcg_temp_free_i64(t0);
 }
 
-static inline void tcg_gen_shl_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_shl_i64, ret, arg1, arg2);
+    tcg_gen_op3_i64(INDEX_op_shl_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_shli_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
     if (arg2 == 0) {
         tcg_gen_mov_i64(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i64(arg2);
+        TCGv_i64 t0 = tcg_const_i64(arg2);
         tcg_gen_shl_i64(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i64(t0);
     }
 }
 
-static inline void tcg_gen_shr_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_shr_i64, ret, arg1, arg2);
+    tcg_gen_op3_i64(INDEX_op_shr_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_shri_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
     if (arg2 == 0) {
         tcg_gen_mov_i64(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i64(arg2);
+        TCGv_i64 t0 = tcg_const_i64(arg2);
         tcg_gen_shr_i64(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i64(t0);
     }
 }
 
-static inline void tcg_gen_sar_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_sar_i64, ret, arg1, arg2);
+    tcg_gen_op3_i64(INDEX_op_sar_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_sari_i64(TCGv ret, TCGv arg1, int64_t arg2)
+static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 {
     if (arg2 == 0) {
         tcg_gen_mov_i64(ret, arg1);
     } else {
-        TCGv t0 = tcg_const_i64(arg2);
+        TCGv_i64 t0 = tcg_const_i64(arg2);
         tcg_gen_sar_i64(ret, arg1, t0);
-        tcg_temp_free(t0);
+        tcg_temp_free_i64(t0);
     }
 }
 
-static inline void tcg_gen_brcond_i64(int cond, TCGv arg1, TCGv arg2, 
+static inline void tcg_gen_brcond_i64(int cond, TCGv_i64 arg1, TCGv_i64 arg2,
                                       int label_index)
 {
-    tcg_gen_op4ii(INDEX_op_brcond_i64, arg1, arg2, cond, label_index);
+    tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index);
 }
 
-static inline void tcg_gen_mul_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_mul_i64, ret, arg1, arg2);
-}
-
-static inline void tcg_gen_muli_i64(TCGv ret, TCGv arg1, int64_t arg2)
-{
-    TCGv t0 = tcg_const_i64(arg2);
-    tcg_gen_mul_i64(ret, arg1, t0);
-    tcg_temp_free(t0);
+    tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2);
 }
 
 #ifdef TCG_TARGET_HAS_div_i64
-static inline void tcg_gen_div_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_div_i64, ret, arg1, arg2);
+    tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_rem_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_rem_i64, ret, arg1, arg2);
+    tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_divu_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_divu_i64, ret, arg1, arg2);
+    tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2);
 }
 
-static inline void tcg_gen_remu_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    tcg_gen_op3(INDEX_op_remu_i64, ret, arg1, arg2);
+    tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2);
 }
 #else
-static inline void tcg_gen_div_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
     tcg_gen_sari_i64(t0, arg1, 63);
-    tcg_gen_op5(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
-    tcg_temp_free(t0);
+    tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
+    tcg_temp_free_i64(t0);
 }
 
-static inline void tcg_gen_rem_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
     tcg_gen_sari_i64(t0, arg1, 63);
-    tcg_gen_op5(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
-    tcg_temp_free(t0);
+    tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
+    tcg_temp_free_i64(t0);
 }
 
-static inline void tcg_gen_divu_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
     tcg_gen_movi_i64(t0, 0);
-    tcg_gen_op5(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
-    tcg_temp_free(t0);
+    tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
+    tcg_temp_free_i64(t0);
 }
 
-static inline void tcg_gen_remu_i64(TCGv ret, TCGv arg1, TCGv arg2)
+static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
     tcg_gen_movi_i64(t0, 0);
-    tcg_gen_op5(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
-    tcg_temp_free(t0);
+    tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
+    tcg_temp_free_i64(t0);
 }
 #endif
 
 #endif
 
-static inline void tcg_gen_brcondi_i64(int cond, TCGv arg1, int64_t arg2, 
+static inline void tcg_gen_addi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_add_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+}
+
+static inline void tcg_gen_subfi_i64(TCGv_i64 ret, int64_t arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg1);
+    tcg_gen_sub_i64(ret, t0, arg2);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_sub_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+    }
+}
+static inline void tcg_gen_brcondi_i64(int cond, TCGv_i64 arg1, int64_t arg2,
                                        int label_index)
 {
-    TCGv t0 = tcg_const_i64(arg2);
+    TCGv_i64 t0 = tcg_const_i64(arg2);
     tcg_gen_brcond_i64(cond, arg1, t0, label_index);
-    tcg_temp_free(t0);
+    tcg_temp_free_i64(t0);
 }
 
+static inline void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    TCGv_i64 t0 = tcg_const_i64(arg2);
+    tcg_gen_mul_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+}
+
+
 /***************************************/
 /* optional operations */
 
-static inline void tcg_gen_ext8s_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
 #ifdef TCG_TARGET_HAS_ext8s_i32
-    tcg_gen_op2(INDEX_op_ext8s_i32, ret, arg);
+    tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg);
 #else
     tcg_gen_shli_i32(ret, arg, 24);
     tcg_gen_sari_i32(ret, ret, 24);
 #endif
 }
 
-static inline void tcg_gen_ext16s_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
 #ifdef TCG_TARGET_HAS_ext16s_i32
-    tcg_gen_op2(INDEX_op_ext16s_i32, ret, arg);
+    tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg);
 #else
     tcg_gen_shli_i32(ret, arg, 16);
     tcg_gen_sari_i32(ret, ret, 16);
@@ -1111,43 +1191,40 @@
 
 /* These are currently just for convenience.
    We assume a target will recognise these automatically .  */
-static inline void tcg_gen_ext8u_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
     tcg_gen_andi_i32(ret, arg, 0xffu);
 }
 
-static inline void tcg_gen_ext16u_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
     tcg_gen_andi_i32(ret, arg, 0xffffu);
 }
 
 /* Note: we assume the two high bytes are set to zero */
-static inline void tcg_gen_bswap16_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
 #ifdef TCG_TARGET_HAS_bswap16_i32
-    tcg_gen_op2(INDEX_op_bswap16_i32, ret, arg);
+    tcg_gen_op2_i32(INDEX_op_bswap16_i32, ret, arg);
 #else
-    TCGv t0, t1;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
-    t1 = tcg_temp_new(TCG_TYPE_I32);
+    TCGv_i32 t0 = tcg_temp_new_i32();
     
-    tcg_gen_shri_i32(t0, arg, 8);
-    tcg_gen_andi_i32(t1, arg, 0x000000ff);
-    tcg_gen_shli_i32(t1, t1, 8);
-    tcg_gen_or_i32(ret, t0, t1);
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
+    tcg_gen_ext8u_i32(t0, arg);
+    tcg_gen_shli_i32(t0, t0, 8);
+    tcg_gen_shri_i32(ret, arg, 8);
+    tcg_gen_or_i32(ret, ret, t0);
+    tcg_temp_free_i32(t0);
 #endif
 }
 
-static inline void tcg_gen_bswap_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
-#ifdef TCG_TARGET_HAS_bswap_i32
-    tcg_gen_op2(INDEX_op_bswap_i32, ret, arg);
+#ifdef TCG_TARGET_HAS_bswap32_i32
+    tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
 #else
-    TCGv t0, t1;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
-    t1 = tcg_temp_new(TCG_TYPE_I32);
+    TCGv_i32 t0, t1;
+    t0 = tcg_temp_new_i32();
+    t1 = tcg_temp_new_i32();
     
     tcg_gen_shli_i32(t0, arg, 24);
     
@@ -1161,154 +1238,211 @@
     
     tcg_gen_shri_i32(t1, arg, 24);
     tcg_gen_or_i32(ret, t0, t1);
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
 #endif
 }
 
 #if TCG_TARGET_REG_BITS == 32
-static inline void tcg_gen_ext8s_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    tcg_gen_ext8s_i32(ret, arg);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 }
 
-static inline void tcg_gen_ext16s_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    tcg_gen_ext16s_i32(ret, arg);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 }
 
-static inline void tcg_gen_ext32s_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    tcg_gen_mov_i32(ret, arg);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 }
 
-static inline void tcg_gen_ext8u_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    tcg_gen_ext8u_i32(ret, arg);
+    tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 }
 
-static inline void tcg_gen_ext16u_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    tcg_gen_ext16u_i32(ret, arg);
+    tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg));
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 }
 
-static inline void tcg_gen_ext32u_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    tcg_gen_mov_i32(ret, arg);
+    tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg));
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 }
 
-static inline void tcg_gen_trunc_i64_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
 {
-    tcg_gen_mov_i32(ret, arg);
+    tcg_gen_mov_i32(ret, TCGV_LOW(arg));
 }
 
-static inline void tcg_gen_extu_i32_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
 {
-    tcg_gen_mov_i32(ret, arg);
+    tcg_gen_mov_i32(TCGV_LOW(ret), arg);
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 }
 
-static inline void tcg_gen_ext_i32_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
 {
-    tcg_gen_mov_i32(ret, arg);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_mov_i32(TCGV_LOW(ret), arg);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 }
 
-static inline void tcg_gen_bswap_i64(TCGv ret, TCGv arg)
+/* Note: we assume the six high bytes are set to zero */
+static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-    TCGv t0, t1;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
-    t1 = tcg_temp_new(TCG_TYPE_I32);
+    tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+    tcg_gen_bswap16_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+}
 
-    tcg_gen_bswap_i32(t0, arg);
-    tcg_gen_bswap_i32(t1, TCGV_HIGH(arg));
-    tcg_gen_mov_i32(ret, t1);
+/* Note: we assume the four high bytes are set to zero */
+static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg));
+    tcg_gen_bswap32_i32(TCGV_LOW(ret), TCGV_LOW(arg));
+}
+
+static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+    TCGv_i32 t0, t1;
+    t0 = tcg_temp_new_i32();
+    t1 = tcg_temp_new_i32();
+
+    tcg_gen_bswap32_i32(t0, TCGV_LOW(arg));
+    tcg_gen_bswap32_i32(t1, TCGV_HIGH(arg));
+    tcg_gen_mov_i32(TCGV_LOW(ret), t1);
     tcg_gen_mov_i32(TCGV_HIGH(ret), t0);
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
 }
 #else
 
-static inline void tcg_gen_ext8s_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
 #ifdef TCG_TARGET_HAS_ext8s_i64
-    tcg_gen_op2(INDEX_op_ext8s_i64, ret, arg);
+    tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg);
 #else
     tcg_gen_shli_i64(ret, arg, 56);
     tcg_gen_sari_i64(ret, ret, 56);
 #endif
 }
 
-static inline void tcg_gen_ext16s_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
 #ifdef TCG_TARGET_HAS_ext16s_i64
-    tcg_gen_op2(INDEX_op_ext16s_i64, ret, arg);
+    tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg);
 #else
     tcg_gen_shli_i64(ret, arg, 48);
     tcg_gen_sari_i64(ret, ret, 48);
 #endif
 }
 
-static inline void tcg_gen_ext32s_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
 #ifdef TCG_TARGET_HAS_ext32s_i64
-    tcg_gen_op2(INDEX_op_ext32s_i64, ret, arg);
+    tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg);
 #else
     tcg_gen_shli_i64(ret, arg, 32);
     tcg_gen_sari_i64(ret, ret, 32);
 #endif
 }
 
-static inline void tcg_gen_ext8u_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
     tcg_gen_andi_i64(ret, arg, 0xffu);
 }
 
-static inline void tcg_gen_ext16u_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
     tcg_gen_andi_i64(ret, arg, 0xffffu);
 }
 
-static inline void tcg_gen_ext32u_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
     tcg_gen_andi_i64(ret, arg, 0xffffffffu);
 }
 
 /* Note: we assume the target supports move between 32 and 64 bit
    registers.  This will probably break MIPS64 targets.  */
-static inline void tcg_gen_trunc_i64_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
 {
-    tcg_gen_mov_i32(ret, arg);
+    tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg)));
 }
 
 /* Note: we assume the target supports move between 32 and 64 bit
    registers */
-static inline void tcg_gen_extu_i32_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
 {
-    tcg_gen_andi_i64(ret, arg, 0xffffffffu);
+    tcg_gen_andi_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg)), 0xffffffffu);
 }
 
 /* Note: we assume the target supports move between 32 and 64 bit
    registers */
-static inline void tcg_gen_ext_i32_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_ext_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
 {
-    tcg_gen_ext32s_i64(ret, arg);
+    tcg_gen_ext32s_i64(ret, MAKE_TCGV_I64(GET_TCGV_I32(arg)));
 }
 
-static inline void tcg_gen_bswap_i64(TCGv ret, TCGv arg)
+/* Note: we assume the six high bytes are set to zero */
+static inline void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
-#ifdef TCG_TARGET_HAS_bswap_i64
-    tcg_gen_op2(INDEX_op_bswap_i64, ret, arg);
+#ifdef TCG_TARGET_HAS_bswap16_i64
+    tcg_gen_op2_i64(INDEX_op_bswap16_i64, ret, arg);
 #else
-    TCGv t0, t1;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
-    t1 = tcg_temp_new(TCG_TYPE_I32);
+    TCGv_i64 t0 = tcg_temp_new_i64();
+
+    tcg_gen_ext8u_i64(t0, arg);
+    tcg_gen_shli_i64(t0, t0, 8);
+    tcg_gen_shri_i64(ret, arg, 8);
+    tcg_gen_or_i64(ret, ret, t0);
+    tcg_temp_free_i64(t0);
+#endif
+}
+
+/* Note: we assume the four high bytes are set to zero */
+static inline void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap32_i64
+    tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
+#else
+    TCGv_i64 t0, t1;
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    tcg_gen_shli_i64(t0, arg, 24);
+    tcg_gen_ext32u_i64(t0, t0);
+
+    tcg_gen_andi_i64(t1, arg, 0x0000ff00);
+    tcg_gen_shli_i64(t1, t1, 8);
+    tcg_gen_or_i64(t0, t0, t1);
+
+    tcg_gen_shri_i64(t1, arg, 8);
+    tcg_gen_andi_i64(t1, t1, 0x0000ff00);
+    tcg_gen_or_i64(t0, t0, t1);
+
+    tcg_gen_shri_i64(t1, arg, 24);
+    tcg_gen_or_i64(ret, t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
+{
+#ifdef TCG_TARGET_HAS_bswap64_i64
+    tcg_gen_op2_i64(INDEX_op_bswap64_i64, ret, arg);
+#else
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
     
     tcg_gen_shli_i64(t0, arg, 56);
     
@@ -1338,63 +1472,311 @@
 
     tcg_gen_shri_i64(t1, arg, 56);
     tcg_gen_or_i64(ret, t0, t1);
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
 #endif
 }
 
 #endif
 
-static inline void tcg_gen_neg_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
 #ifdef TCG_TARGET_HAS_neg_i32
-    tcg_gen_op2(INDEX_op_neg_i32, ret, arg);
+    tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg);
 #else
-    TCGv t0 = tcg_const_i32(0);
+    TCGv_i32 t0 = tcg_const_i32(0);
     tcg_gen_sub_i32(ret, t0, arg);
-    tcg_temp_free(t0);
+    tcg_temp_free_i32(t0);
 #endif
 }
 
-static inline void tcg_gen_neg_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_neg_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
 #ifdef TCG_TARGET_HAS_neg_i64
-    tcg_gen_op2(INDEX_op_neg_i64, ret, arg);
+    tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg);
 #else
-    TCGv t0 = tcg_const_i64(0);
+    TCGv_i64 t0 = tcg_const_i64(0);
     tcg_gen_sub_i64(ret, t0, arg);
-    tcg_temp_free(t0);
+    tcg_temp_free_i64(t0);
 #endif
 }
 
-static inline void tcg_gen_not_i32(TCGv ret, TCGv arg)
+static inline void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg)
 {
+#ifdef TCG_TARGET_HAS_not_i32
+    tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg);
+#else
     tcg_gen_xori_i32(ret, arg, -1);
+#endif
 }
 
-static inline void tcg_gen_not_i64(TCGv ret, TCGv arg)
+static inline void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg)
 {
+#ifdef TCG_TARGET_HAS_not_i64
+    tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg);
+#else
     tcg_gen_xori_i64(ret, arg, -1);
+#endif
 }
 
-static inline void tcg_gen_discard_i32(TCGv arg)
+static inline void tcg_gen_discard_i32(TCGv_i32 arg)
 {
-    tcg_gen_op1(INDEX_op_discard, arg);
+    tcg_gen_op1_i32(INDEX_op_discard, arg);
 }
 
 #if TCG_TARGET_REG_BITS == 32
-static inline void tcg_gen_discard_i64(TCGv arg)
+static inline void tcg_gen_discard_i64(TCGv_i64 arg)
 {
-    tcg_gen_discard_i32(arg);
+    tcg_gen_discard_i32(TCGV_LOW(arg));
     tcg_gen_discard_i32(TCGV_HIGH(arg));
 }
 #else
-static inline void tcg_gen_discard_i64(TCGv arg)
+static inline void tcg_gen_discard_i64(TCGv_i64 arg)
 {
-    tcg_gen_op1(INDEX_op_discard, arg);
+    tcg_gen_op1_i64(INDEX_op_discard, arg);
 }
 #endif
 
+static inline void tcg_gen_concat_i32_i64(TCGv_i64 dest, TCGv_i32 low, TCGv_i32 high)
+{
+#if TCG_TARGET_REG_BITS == 32
+    tcg_gen_mov_i32(TCGV_LOW(dest), low);
+    tcg_gen_mov_i32(TCGV_HIGH(dest), high);
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    /* This extension is only needed for type correctness.
+       We may be able to do better given target specific information.  */
+    tcg_gen_extu_i32_i64(tmp, high);
+    tcg_gen_shli_i64(tmp, tmp, 32);
+    tcg_gen_extu_i32_i64(dest, low);
+    tcg_gen_or_i64(dest, dest, tmp);
+    tcg_temp_free_i64(tmp);
+#endif
+}
+
+static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low, TCGv_i64 high)
+{
+#if TCG_TARGET_REG_BITS == 32
+    tcg_gen_concat_i32_i64(dest, TCGV_LOW(low), TCGV_LOW(high));
+#else
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(dest, low);
+    tcg_gen_shli_i64(tmp, high, 32);
+    tcg_gen_or_i64(dest, dest, tmp);
+    tcg_temp_free_i64(tmp);
+#endif
+}
+
+static inline void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_not_i32(t0, arg2);
+    tcg_gen_and_i32(ret, arg1, t0);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_not_i64(t0, arg2);
+    tcg_gen_and_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_xor_i32(ret, arg1, arg2);
+    tcg_gen_not_i32(ret, ret);
+}
+
+static inline void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_xor_i64(ret, arg1, arg2);
+    tcg_gen_not_i64(ret, ret);
+}
+
+static inline void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_and_i32(ret, arg1, arg2);
+    tcg_gen_not_i32(ret, ret);
+}
+
+static inline void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_and_i64(ret, arg1, arg2);
+    tcg_gen_not_i64(ret, ret);
+}
+
+static inline void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_or_i32(ret, arg1, arg2);
+    tcg_gen_not_i32(ret, ret);
+}
+
+static inline void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    tcg_gen_or_i64(ret, arg1, arg2);
+    tcg_gen_not_i64(ret, ret);
+}
+
+static inline void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
+    tcg_gen_not_i32(t0, arg2);
+    tcg_gen_or_i32(ret, arg1, t0);
+    tcg_temp_free_i32(t0);
+}
+
+static inline void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_not_i64(t0, arg2);
+    tcg_gen_or_i64(ret, arg1, t0);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i32
+    tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2);
+#else
+    TCGv_i32 t0, t1;
+
+    t0 = tcg_temp_new_i32();
+    t1 = tcg_temp_new_i32();
+    tcg_gen_shl_i32(t0, arg1, arg2);
+    tcg_gen_subfi_i32(t1, 32, arg2);
+    tcg_gen_shr_i32(t1, arg1, t1);
+    tcg_gen_or_i32(ret, t0, t1);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i64
+    tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2);
+#else
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+    tcg_gen_shl_i64(t0, arg1, arg2);
+    tcg_gen_subfi_i64(t1, 64, arg2);
+    tcg_gen_shr_i64(t1, arg1, t1);
+    tcg_gen_or_i64(ret, t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+#ifdef TCG_TARGET_HAS_rot_i32
+        TCGv_i32 t0 = tcg_const_i32(arg2);
+        tcg_gen_rotl_i32(ret, arg1, t0);
+        tcg_temp_free_i32(t0);
+#else
+        TCGv_i32 t0, t1;
+        t0 = tcg_temp_new_i32();
+        t1 = tcg_temp_new_i32();
+        tcg_gen_shli_i32(t0, arg1, arg2);
+        tcg_gen_shri_i32(t1, arg1, 32 - arg2);
+        tcg_gen_or_i32(ret, t0, t1);
+        tcg_temp_free_i32(t0);
+        tcg_temp_free_i32(t1);
+#endif
+    }
+}
+
+static inline void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+#ifdef TCG_TARGET_HAS_rot_i64
+        TCGv_i64 t0 = tcg_const_i64(arg2);
+        tcg_gen_rotl_i64(ret, arg1, t0);
+        tcg_temp_free_i64(t0);
+#else
+        TCGv_i64 t0, t1;
+        t0 = tcg_temp_new_i64();
+        t1 = tcg_temp_new_i64();
+        tcg_gen_shli_i64(t0, arg1, arg2);
+        tcg_gen_shri_i64(t1, arg1, 64 - arg2);
+        tcg_gen_or_i64(ret, t0, t1);
+        tcg_temp_free_i64(t0);
+        tcg_temp_free_i64(t1);
+#endif
+    }
+}
+
+static inline void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i32
+    tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2);
+#else
+    TCGv_i32 t0, t1;
+
+    t0 = tcg_temp_new_i32();
+    t1 = tcg_temp_new_i32();
+    tcg_gen_shr_i32(t0, arg1, arg2);
+    tcg_gen_subfi_i32(t1, 32, arg2);
+    tcg_gen_shl_i32(t1, arg1, t1);
+    tcg_gen_or_i32(ret, t0, t1);
+    tcg_temp_free_i32(t0);
+    tcg_temp_free_i32(t1);
+#endif
+}
+
+static inline void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifdef TCG_TARGET_HAS_rot_i64
+    tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2);
+#else
+    TCGv_i64 t0, t1;
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+    tcg_gen_shr_i64(t0, arg1, arg2);
+    tcg_gen_subfi_i64(t1, 64, arg2);
+    tcg_gen_shl_i64(t1, arg1, t1);
+    tcg_gen_or_i64(ret, t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+#endif
+}
+
+static inline void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i32(ret, arg1);
+    } else {
+        tcg_gen_rotli_i32(ret, arg1, 32 - arg2);
+    }
+}
+
+static inline void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
+{
+    /* some cases can be optimized here */
+    if (arg2 == 0) {
+        tcg_gen_mov_i64(ret, arg1);
+    } else {
+        tcg_gen_rotli_i64(ret, arg1, 64 - arg2);
+    }
+}
+
 /***************************************/
 /* QEMU specific operations. Their type depend on the QEMU CPU
    type. */
@@ -1402,6 +1784,30 @@
 #error must include QEMU headers
 #endif
 
+#if TARGET_LONG_BITS == 32
+#define TCGv TCGv_i32
+#define tcg_temp_new() tcg_temp_new_i32()
+#define tcg_global_reg_new tcg_global_reg_new_i32
+#define tcg_global_mem_new tcg_global_mem_new_i32
+#define tcg_temp_local_new() tcg_temp_local_new_i32()
+#define tcg_temp_free tcg_temp_free_i32
+#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i32
+#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i32
+#define TCGV_UNUSED(x) TCGV_UNUSED_I32(x)
+#define TCGV_EQUAL(a, b) TCGV_EQUAL_I32(a, b)
+#else
+#define TCGv TCGv_i64
+#define tcg_temp_new() tcg_temp_new_i64()
+#define tcg_global_reg_new tcg_global_reg_new_i64
+#define tcg_global_mem_new tcg_global_mem_new_i64
+#define tcg_temp_local_new() tcg_temp_local_new_i64()
+#define tcg_temp_free tcg_temp_free_i64
+#define tcg_gen_qemu_ldst_op tcg_gen_op3i_i64
+#define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i64
+#define TCGV_UNUSED(x) TCGV_UNUSED_I64(x)
+#define TCGV_EQUAL(a, b) TCGV_EQUAL_I64(a, b)
+#endif
+
 /* debug info: write the PC of the corresponding QEMU CPU instruction */
 static inline void tcg_gen_debug_insn_start(uint64_t pc)
 {
@@ -1428,9 +1834,10 @@
 static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_ld8u, ret, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld8u, ret, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_ld8u, ret, addr, TCGV_HIGH(addr), mem_index);
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld8u, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 #endif
 }
@@ -1438,19 +1845,21 @@
 static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_ld8s, ret, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld8s, ret, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_ld8s, ret, addr, TCGV_HIGH(addr), mem_index);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld8s, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 #endif
 }
 
 static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_ld16u, ret, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld16u, ret, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_ld16u, ret, addr, TCGV_HIGH(addr), mem_index);
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld16u, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 #endif
 }
@@ -1458,19 +1867,21 @@
 static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_ld16s, ret, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld16s, ret, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_ld16s, ret, addr, TCGV_HIGH(addr), mem_index);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld16s, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 #endif
 }
 
 static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_ld32u, ret, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld32u, ret, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_ld32u, ret, addr, TCGV_HIGH(addr), mem_index);
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld32u, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
     tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
 #endif
 }
@@ -1478,57 +1889,62 @@
 static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_ld32u, ret, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_ld32u, ret, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_ld32u, ret, addr, TCGV_HIGH(addr), mem_index);
-    tcg_gen_sari_i32(TCGV_HIGH(ret), ret, 31);
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld32u, TCGV_LOW(ret), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
+    tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31);
 #endif
 }
 
-static inline void tcg_gen_qemu_ld64(TCGv ret, TCGv addr, int mem_index)
+static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op4i(INDEX_op_qemu_ld64, ret, TCGV_HIGH(ret), addr, mem_index);
+    tcg_gen_op4i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret), addr, mem_index);
 #else
-    tcg_gen_op5i(INDEX_op_qemu_ld64, ret, TCGV_HIGH(ret),
-                 addr, TCGV_HIGH(addr), mem_index);
+    tcg_gen_op5i_i32(INDEX_op_qemu_ld64, TCGV_LOW(ret), TCGV_HIGH(ret),
+                     TCGV_LOW(addr), TCGV_HIGH(addr), mem_index);
 #endif
 }
 
 static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_st8, arg, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_st8, arg, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_st8, arg, addr, TCGV_HIGH(addr), mem_index);
+    tcg_gen_op4i_i32(INDEX_op_qemu_st8, TCGV_LOW(arg), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
 #endif
 }
 
 static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_st16, arg, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_st16, arg, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_st16, arg, addr, TCGV_HIGH(addr), mem_index);
+    tcg_gen_op4i_i32(INDEX_op_qemu_st16, TCGV_LOW(arg), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
 #endif
 }
 
 static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op3i(INDEX_op_qemu_st32, arg, addr, mem_index);
+    tcg_gen_op3i_i32(INDEX_op_qemu_st32, arg, addr, mem_index);
 #else
-    tcg_gen_op4i(INDEX_op_qemu_st32, arg, addr, TCGV_HIGH(addr), mem_index);
+    tcg_gen_op4i_i32(INDEX_op_qemu_st32, TCGV_LOW(arg), TCGV_LOW(addr),
+                     TCGV_HIGH(addr), mem_index);
 #endif
 }
 
-static inline void tcg_gen_qemu_st64(TCGv arg, TCGv addr, int mem_index)
+static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
 {
 #if TARGET_LONG_BITS == 32
-    tcg_gen_op4i(INDEX_op_qemu_st64, arg, TCGV_HIGH(arg), addr, mem_index);
+    tcg_gen_op4i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg), addr,
+                     mem_index);
 #else
-    tcg_gen_op5i(INDEX_op_qemu_st64, arg, TCGV_HIGH(arg),
-                 addr, TCGV_HIGH(addr), mem_index);
+    tcg_gen_op5i_i32(INDEX_op_qemu_st64, TCGV_LOW(arg), TCGV_HIGH(arg),
+                     TCGV_LOW(addr), TCGV_HIGH(addr), mem_index);
 #endif
 }
 
@@ -1539,57 +1955,57 @@
 
 static inline void tcg_gen_qemu_ld8u(TCGv ret, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_ld8u, ret, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8u, ret, addr, mem_index);
 }
 
 static inline void tcg_gen_qemu_ld8s(TCGv ret, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_ld8s, ret, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld8s, ret, addr, mem_index);
 }
 
 static inline void tcg_gen_qemu_ld16u(TCGv ret, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_ld16u, ret, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16u, ret, addr, mem_index);
 }
 
 static inline void tcg_gen_qemu_ld16s(TCGv ret, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_ld16s, ret, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld16s, ret, addr, mem_index);
 }
 
 static inline void tcg_gen_qemu_ld32u(TCGv ret, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_ld32u, ret, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32u, ret, addr, mem_index);
 }
 
 static inline void tcg_gen_qemu_ld32s(TCGv ret, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_ld32s, ret, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_ld32s, ret, addr, mem_index);
 }
 
-static inline void tcg_gen_qemu_ld64(TCGv ret, TCGv addr, int mem_index)
+static inline void tcg_gen_qemu_ld64(TCGv_i64 ret, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_ld64, ret, addr, mem_index);
+    tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_ld64, ret, addr, mem_index);
 }
 
 static inline void tcg_gen_qemu_st8(TCGv arg, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_st8, arg, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_st8, arg, addr, mem_index);
 }
 
 static inline void tcg_gen_qemu_st16(TCGv arg, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_st16, arg, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_st16, arg, addr, mem_index);
 }
 
 static inline void tcg_gen_qemu_st32(TCGv arg, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_st32, arg, addr, mem_index);
+    tcg_gen_qemu_ldst_op(INDEX_op_qemu_st32, arg, addr, mem_index);
 }
 
-static inline void tcg_gen_qemu_st64(TCGv arg, TCGv addr, int mem_index)
+static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
 {
-    tcg_gen_op3i(INDEX_op_qemu_st64, arg, addr, mem_index);
+    tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_st64, arg, addr, mem_index);
 }
 
 #define tcg_gen_ld_ptr tcg_gen_ld_i64
@@ -1616,6 +2032,7 @@
 #define tcg_gen_addi_tl tcg_gen_addi_i64
 #define tcg_gen_sub_tl tcg_gen_sub_i64
 #define tcg_gen_neg_tl tcg_gen_neg_i64
+#define tcg_gen_subfi_tl tcg_gen_subfi_i64
 #define tcg_gen_subi_tl tcg_gen_subi_i64
 #define tcg_gen_and_tl tcg_gen_and_i64
 #define tcg_gen_andi_tl tcg_gen_andi_i64
@@ -1634,6 +2051,10 @@
 #define tcg_gen_brcondi_tl tcg_gen_brcondi_i64
 #define tcg_gen_mul_tl tcg_gen_mul_i64
 #define tcg_gen_muli_tl tcg_gen_muli_i64
+#define tcg_gen_div_tl tcg_gen_div_i64
+#define tcg_gen_rem_tl tcg_gen_rem_i64
+#define tcg_gen_divu_tl tcg_gen_divu_i64
+#define tcg_gen_remu_tl tcg_gen_remu_i64
 #define tcg_gen_discard_tl tcg_gen_discard_i64
 #define tcg_gen_trunc_tl_i32 tcg_gen_trunc_i64_i32
 #define tcg_gen_trunc_i64_tl tcg_gen_mov_i64
@@ -1647,7 +2068,21 @@
 #define tcg_gen_ext16s_tl tcg_gen_ext16s_i64
 #define tcg_gen_ext32u_tl tcg_gen_ext32u_i64
 #define tcg_gen_ext32s_tl tcg_gen_ext32s_i64
+#define tcg_gen_bswap16_tl tcg_gen_bswap16_i64
+#define tcg_gen_bswap32_tl tcg_gen_bswap32_i64
+#define tcg_gen_bswap64_tl tcg_gen_bswap64_i64
+#define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64
+#define tcg_gen_andc_tl tcg_gen_andc_i64
+#define tcg_gen_eqv_tl tcg_gen_eqv_i64
+#define tcg_gen_nand_tl tcg_gen_nand_i64
+#define tcg_gen_nor_tl tcg_gen_nor_i64
+#define tcg_gen_orc_tl tcg_gen_orc_i64
+#define tcg_gen_rotl_tl tcg_gen_rotl_i64
+#define tcg_gen_rotli_tl tcg_gen_rotli_i64
+#define tcg_gen_rotr_tl tcg_gen_rotr_i64
+#define tcg_gen_rotri_tl tcg_gen_rotri_i64
 #define tcg_const_tl tcg_const_i64
+#define tcg_const_local_tl tcg_const_local_i64
 #else
 #define TCG_TYPE_TL TCG_TYPE_I32
 #define tcg_gen_movi_tl tcg_gen_movi_i32
@@ -1667,6 +2102,7 @@
 #define tcg_gen_addi_tl tcg_gen_addi_i32
 #define tcg_gen_sub_tl tcg_gen_sub_i32
 #define tcg_gen_neg_tl tcg_gen_neg_i32
+#define tcg_gen_subfi_tl tcg_gen_subfi_i32
 #define tcg_gen_subi_tl tcg_gen_subi_i32
 #define tcg_gen_and_tl tcg_gen_and_i32
 #define tcg_gen_andi_tl tcg_gen_andi_i32
@@ -1685,6 +2121,10 @@
 #define tcg_gen_brcondi_tl tcg_gen_brcondi_i32
 #define tcg_gen_mul_tl tcg_gen_mul_i32
 #define tcg_gen_muli_tl tcg_gen_muli_i32
+#define tcg_gen_div_tl tcg_gen_div_i32
+#define tcg_gen_rem_tl tcg_gen_rem_i32
+#define tcg_gen_divu_tl tcg_gen_divu_i32
+#define tcg_gen_remu_tl tcg_gen_remu_i32
 #define tcg_gen_discard_tl tcg_gen_discard_i32
 #define tcg_gen_trunc_tl_i32 tcg_gen_mov_i32
 #define tcg_gen_trunc_i64_tl tcg_gen_trunc_i64_i32
@@ -1698,7 +2138,20 @@
 #define tcg_gen_ext16s_tl tcg_gen_ext16s_i32
 #define tcg_gen_ext32u_tl tcg_gen_mov_i32
 #define tcg_gen_ext32s_tl tcg_gen_mov_i32
+#define tcg_gen_bswap16_tl tcg_gen_bswap16_i32
+#define tcg_gen_bswap32_tl tcg_gen_bswap32_i32
+#define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64
+#define tcg_gen_andc_tl tcg_gen_andc_i32
+#define tcg_gen_eqv_tl tcg_gen_eqv_i32
+#define tcg_gen_nand_tl tcg_gen_nand_i32
+#define tcg_gen_nor_tl tcg_gen_nor_i32
+#define tcg_gen_orc_tl tcg_gen_orc_i32
+#define tcg_gen_rotl_tl tcg_gen_rotl_i32
+#define tcg_gen_rotli_tl tcg_gen_rotli_i32
+#define tcg_gen_rotr_tl tcg_gen_rotr_i32
+#define tcg_gen_rotri_tl tcg_gen_rotri_i32
 #define tcg_const_tl tcg_const_i32
+#define tcg_const_local_tl tcg_const_local_i32
 #endif
 
 #if TCG_TARGET_REG_BITS == 32
@@ -1710,4 +2163,3 @@
 #define tcg_gen_addi_ptr tcg_gen_addi_i64
 #define tcg_gen_ext_i32_ptr tcg_gen_ext_i32_i64
 #endif /* TCG_TARGET_REG_BITS != 32 */
-
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 31ae550..3a095fc 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -21,10 +21,6 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#ifdef CONFIG_DYNGEN_OP
-#include "dyngen-opc.h"
-#endif
-
 #ifndef DEF2
 #define DEF2(name, oargs, iargs, cargs, flags) DEF(name, oargs + iargs + cargs, 0)
 #endif
@@ -71,10 +67,14 @@
 DEF2(and_i32, 1, 2, 0, 0)
 DEF2(or_i32, 1, 2, 0, 0)
 DEF2(xor_i32, 1, 2, 0, 0)
-/* shifts */
+/* shifts/rotates */
 DEF2(shl_i32, 1, 2, 0, 0)
 DEF2(shr_i32, 1, 2, 0, 0)
 DEF2(sar_i32, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_rot_i32
+DEF2(rotl_i32, 1, 2, 0, 0)
+DEF2(rotr_i32, 1, 2, 0, 0)
+#endif
 
 DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 #if TCG_TARGET_REG_BITS == 32
@@ -89,8 +89,17 @@
 #ifdef TCG_TARGET_HAS_ext16s_i32
 DEF2(ext16s_i32, 1, 1, 0, 0)
 #endif
-#ifdef TCG_TARGET_HAS_bswap_i32
-DEF2(bswap_i32, 1, 1, 0, 0)
+#ifdef TCG_TARGET_HAS_bswap16_i32
+DEF2(bswap16_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_bswap32_i32
+DEF2(bswap32_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_not_i32
+DEF2(not_i32, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_neg_i32
+DEF2(neg_i32, 1, 1, 0, 0)
 #endif
 
 #if TCG_TARGET_REG_BITS == 64
@@ -124,10 +133,14 @@
 DEF2(and_i64, 1, 2, 0, 0)
 DEF2(or_i64, 1, 2, 0, 0)
 DEF2(xor_i64, 1, 2, 0, 0)
-/* shifts */
+/* shifts/rotates */
 DEF2(shl_i64, 1, 2, 0, 0)
 DEF2(shr_i64, 1, 2, 0, 0)
 DEF2(sar_i64, 1, 2, 0, 0)
+#ifdef TCG_TARGET_HAS_rot_i64
+DEF2(rotl_i64, 1, 2, 0, 0)
+DEF2(rotr_i64, 1, 2, 0, 0)
+#endif
 
 DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
 #ifdef TCG_TARGET_HAS_ext8s_i64
@@ -139,16 +152,22 @@
 #ifdef TCG_TARGET_HAS_ext32s_i64
 DEF2(ext32s_i64, 1, 1, 0, 0)
 #endif
-#ifdef TCG_TARGET_HAS_bswap_i64
-DEF2(bswap_i64, 1, 1, 0, 0)
+#ifdef TCG_TARGET_HAS_bswap16_i64
+DEF2(bswap16_i64, 1, 1, 0, 0)
 #endif
+#ifdef TCG_TARGET_HAS_bswap32_i64
+DEF2(bswap32_i64, 1, 1, 0, 0)
 #endif
-#ifdef TCG_TARGET_HAS_neg_i32
-DEF2(neg_i32, 1, 1, 0, 0)
+#ifdef TCG_TARGET_HAS_bswap64_i64
+DEF2(bswap64_i64, 1, 1, 0, 0)
+#endif
+#ifdef TCG_TARGET_HAS_not_i64
+DEF2(not_i64, 1, 1, 0, 0)
 #endif
 #ifdef TCG_TARGET_HAS_neg_i64
 DEF2(neg_i64, 1, 1, 0, 0)
 #endif
+#endif
 
 /* QEMU specific */
 #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
diff --git a/tcg/tcg-runtime.c b/tcg/tcg-runtime.c
index 575da43..1d77c37 100644
--- a/tcg/tcg-runtime.c
+++ b/tcg/tcg-runtime.c
@@ -29,6 +29,7 @@
 
 #include "config.h"
 #include "osdep.h"
+#include "cpu.h" // For TARGET_LONG_BITS
 #include "tcg.h"
 
 int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2)
@@ -65,4 +66,3 @@
 {
     return arg1 % arg2;
 }
-
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 1b7bf5c..5d18842 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -22,13 +22,16 @@
  * THE SOFTWARE.
  */
 
-/* define it to suppress various consistency checks (faster) */
-#define NDEBUG
-
 /* define it to use liveness analysis (better code) */
 #define USE_LIVENESS_ANALYSIS
 
-#include <assert.h>
+#include "config.h"
+
+#ifndef DEBUG_TCG
+/* define it to suppress various consistency checks (faster) */
+#define NDEBUG
+#endif
+
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -37,9 +40,12 @@
 #ifdef _WIN32
 #include <malloc.h>
 #endif
+#ifdef _AIX
+#include <alloca.h>
+#endif
 
-#include "config.h"
 #include "qemu-common.h"
+#include "cache-utils.h"
 
 /* Note: the long term plan is to reduce the dependancies on the QEMU
    CPU definitions. Currently they are used for qemu_ld/st
@@ -51,11 +57,10 @@
 #include "tcg-op.h"
 #include "elf.h"
 
-
 static void patch_reloc(uint8_t *code_ptr, int type, 
                         tcg_target_long value, tcg_target_long addend);
 
-TCGOpDef tcg_op_defs[] = {
+static TCGOpDef tcg_op_defs[] = {
 #define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
 #define DEF2(s, iargs, oargs, cargs, flags) { #s, iargs, oargs, cargs, iargs + oargs + cargs, flags, 0 },
 #include "tcg-opc.h"
@@ -63,8 +68,8 @@
 #undef DEF2
 };
 
-TCGRegSet tcg_target_available_regs[2];
-TCGRegSet tcg_target_call_clobber_regs;
+static TCGRegSet tcg_target_available_regs[2];
+static TCGRegSet tcg_target_call_clobber_regs;
 
 /* XXX: move that inside the context */
 uint16_t *gen_opc_ptr;
@@ -267,7 +272,8 @@
         tcg_abort();
 }
 
-TCGv tcg_global_reg_new(TCGType type, int reg, const char *name)
+static inline int tcg_global_reg_new_internal(TCGType type, int reg,
+                                              const char *name)
 {
     TCGContext *s = &tcg_ctx;
     TCGTemp *ts;
@@ -289,48 +295,28 @@
     ts->name = name;
     s->nb_globals++;
     tcg_regset_set_reg(s->reserved_regs, reg);
-    return MAKE_TCGV(idx);
+    return idx;
 }
 
-#if TCG_TARGET_REG_BITS == 32
-/* temporary hack to avoid register shortage for tcg_qemu_st64() */
-TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, 
-                              const char *name)
+TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name)
 {
-    TCGContext *s = &tcg_ctx;
-    TCGTemp *ts;
     int idx;
-    char buf[64];
 
-    if (type != TCG_TYPE_I64)
-        tcg_abort();
-    idx = s->nb_globals;
-    tcg_temp_alloc(s, s->nb_globals + 2);
-    ts = &s->temps[s->nb_globals];
-    ts->base_type = type;
-    ts->type = TCG_TYPE_I32;
-    ts->fixed_reg = 1;
-    ts->reg = reg1;
-    pstrcpy(buf, sizeof(buf), name);
-    pstrcat(buf, sizeof(buf), "_0");
-    ts->name = strdup(buf);
-
-    ts++;
-    ts->base_type = type;
-    ts->type = TCG_TYPE_I32;
-    ts->fixed_reg = 1;
-    ts->reg = reg2;
-    pstrcpy(buf, sizeof(buf), name);
-    pstrcat(buf, sizeof(buf), "_1");
-    ts->name = strdup(buf);
-
-    s->nb_globals += 2;
-    return MAKE_TCGV(idx);
+    idx = tcg_global_reg_new_internal(TCG_TYPE_I32, reg, name);
+    return MAKE_TCGV_I32(idx);
 }
-#endif
 
-TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset,
-                        const char *name)
+TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name)
+{
+    int idx;
+
+    idx = tcg_global_reg_new_internal(TCG_TYPE_I64, reg, name);
+    return MAKE_TCGV_I64(idx);
+}
+
+static inline int tcg_global_mem_new_internal(TCGType type, int reg,
+                                              tcg_target_long offset,
+                                              const char *name)
 {
     TCGContext *s = &tcg_ctx;
     TCGTemp *ts;
@@ -386,10 +372,28 @@
         ts->name = name;
         s->nb_globals++;
     }
-    return MAKE_TCGV(idx);
+    return idx;
 }
 
-TCGv tcg_temp_new_internal(TCGType type, int temp_local)
+TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
+                                const char *name)
+{
+    int idx;
+
+    idx = tcg_global_mem_new_internal(TCG_TYPE_I32, reg, offset, name);
+    return MAKE_TCGV_I32(idx);
+}
+
+TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
+                                const char *name)
+{
+    int idx;
+
+    idx = tcg_global_mem_new_internal(TCG_TYPE_I64, reg, offset, name);
+    return MAKE_TCGV_I64(idx);
+}
+
+static inline int tcg_temp_new_internal(TCGType type, int temp_local)
 {
     TCGContext *s = &tcg_ctx;
     TCGTemp *ts;
@@ -437,14 +441,29 @@
             s->nb_temps++;
         }
     }
-    return MAKE_TCGV(idx);
+    return idx;
 }
 
-void tcg_temp_free(TCGv arg)
+TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
+{
+    int idx;
+
+    idx = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
+    return MAKE_TCGV_I32(idx);
+}
+
+TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
+{
+    int idx;
+
+    idx = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
+    return MAKE_TCGV_I64(idx);
+}
+
+static inline void tcg_temp_free_internal(int idx)
 {
     TCGContext *s = &tcg_ctx;
     TCGTemp *ts;
-    int idx = GET_TCGV(arg);
     int k;
 
     assert(idx >= s->nb_globals && idx < s->nb_temps);
@@ -458,19 +477,44 @@
     s->first_free_temp[k] = idx;
 }
 
-
-TCGv tcg_const_i32(int32_t val)
+void tcg_temp_free_i32(TCGv_i32 arg)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I32);
+    tcg_temp_free_internal(GET_TCGV_I32(arg));
+}
+
+void tcg_temp_free_i64(TCGv_i64 arg)
+{
+    tcg_temp_free_internal(GET_TCGV_I64(arg));
+}
+
+TCGv_i32 tcg_const_i32(int32_t val)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_new_i32();
     tcg_gen_movi_i32(t0, val);
     return t0;
 }
 
-TCGv tcg_const_i64(int64_t val)
+TCGv_i64 tcg_const_i64(int64_t val)
 {
-    TCGv t0;
-    t0 = tcg_temp_new(TCG_TYPE_I64);
+    TCGv_i64 t0;
+    t0 = tcg_temp_new_i64();
+    tcg_gen_movi_i64(t0, val);
+    return t0;
+}
+
+TCGv_i32 tcg_const_local_i32(int32_t val)
+{
+    TCGv_i32 t0;
+    t0 = tcg_temp_local_new_i32();
+    tcg_gen_movi_i32(t0, val);
+    return t0;
+}
+
+TCGv_i64 tcg_const_local_i64(int64_t val)
+{
+    TCGv_i64 t0;
+    t0 = tcg_temp_local_new_i64();
     tcg_gen_movi_i64(t0, val);
     return t0;
 }
@@ -494,150 +538,129 @@
     s->nb_helpers++;
 }
 
-static inline TCGType tcg_get_base_type(TCGContext *s, TCGv arg)
-{
-    return s->temps[GET_TCGV(arg)].base_type;
-}
-
-static void tcg_gen_call_internal(TCGContext *s, TCGv func, 
-                                  unsigned int flags,
-                                  unsigned int nb_rets, const TCGv *rets,
-                                  unsigned int nb_params, const TCGv *params)
-{
-    int i;
-    *gen_opc_ptr++ = INDEX_op_call;
-    *gen_opparam_ptr++ = (nb_rets << 16) | (nb_params + 1);
-    for(i = 0; i < nb_rets; i++) {
-        *gen_opparam_ptr++ = GET_TCGV(rets[i]);
-    }
-    for(i = 0; i < nb_params; i++) {
-        *gen_opparam_ptr++ = GET_TCGV(params[i]);
-    }
-    *gen_opparam_ptr++ = GET_TCGV(func);
-
-    *gen_opparam_ptr++ = flags;
-    /* total parameters, needed to go backward in the instruction stream */
-    *gen_opparam_ptr++ = 1 + nb_rets + nb_params + 3;
-}
-
-
-#if TCG_TARGET_REG_BITS < 64
 /* Note: we convert the 64 bit args to 32 bit and do some alignment
    and endian swap. Maybe it would be better to do the alignment
    and endian swap in tcg_reg_alloc_call(). */
-void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags,
-                  unsigned int nb_rets, const TCGv *rets,
-                  unsigned int nb_params, const TCGv *args1)
+void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
+                   int sizemask, TCGArg ret, int nargs, TCGArg *args)
 {
-    TCGv ret, *args2, rets_2[2], arg;
-    int j, i, call_type;
-
-    if (nb_rets == 1) {
-        ret = rets[0];
-        if (tcg_get_base_type(s, ret) == TCG_TYPE_I64) {
-            nb_rets = 2;
-#ifdef TCG_TARGET_WORDS_BIGENDIAN
-            rets_2[0] = TCGV_HIGH(ret);
-            rets_2[1] = ret;
-#else
-            rets_2[0] = ret;
-            rets_2[1] = TCGV_HIGH(ret);
-#endif
-            rets = rets_2;
-        }
-    }
-    args2 = alloca((nb_params * 3) * sizeof(TCGv));
-    j = 0;
+    int call_type;
+    int i;
+    int real_args;
+    int nb_rets;
+    TCGArg *nparam;
+    *gen_opc_ptr++ = INDEX_op_call;
+    nparam = gen_opparam_ptr++;
     call_type = (flags & TCG_CALL_TYPE_MASK);
-    for(i = 0; i < nb_params; i++) {
-        arg = args1[i];
-        if (tcg_get_base_type(s, arg) == TCG_TYPE_I64) {
+    if (ret != TCG_CALL_DUMMY_ARG) {
+#if TCG_TARGET_REG_BITS < 64
+        if (sizemask & 1) {
+#ifdef TCG_TARGET_WORDS_BIGENDIAN
+            *gen_opparam_ptr++ = ret + 1;
+            *gen_opparam_ptr++ = ret;
+#else
+            *gen_opparam_ptr++ = ret;
+            *gen_opparam_ptr++ = ret + 1;
+#endif
+            nb_rets = 2;
+        } else
+#endif
+        {
+            *gen_opparam_ptr++ = ret;
+            nb_rets = 1;
+        }
+    } else {
+        nb_rets = 0;
+    }
+    real_args = 0;
+    for (i = 0; i < nargs; i++) {
+#if TCG_TARGET_REG_BITS < 64
+        if (sizemask & (2 << i)) {
 #ifdef TCG_TARGET_I386
             /* REGPARM case: if the third parameter is 64 bit, it is
                allocated on the stack */
-            if (j == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
+            if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) {
                 call_type = TCG_CALL_TYPE_REGPARM_2;
                 flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type;
             }
-            args2[j++] = arg;
-            args2[j++] = TCGV_HIGH(arg);
-#else
+#endif
 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
             /* some targets want aligned 64 bit args */
-            if (j & 1) {
-                args2[j++] = TCG_CALL_DUMMY_ARG;
+            if (real_args & 1) {
+                *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG;
+                real_args++;
             }
 #endif
 #ifdef TCG_TARGET_WORDS_BIGENDIAN
-            args2[j++] = TCGV_HIGH(arg);
-            args2[j++] = arg;
+            *gen_opparam_ptr++ = args[i] + 1;
+            *gen_opparam_ptr++ = args[i];
 #else
-            args2[j++] = arg;
-            args2[j++] = TCGV_HIGH(arg);
+            *gen_opparam_ptr++ = args[i];
+            *gen_opparam_ptr++ = args[i] + 1;
 #endif
+            real_args += 2;
+        } else
 #endif
-        } else {
-            args2[j++] = arg;
+        {
+            *gen_opparam_ptr++ = args[i];
+            real_args++;
         }
     }
-    tcg_gen_call_internal(s, func, flags, 
-                          nb_rets, rets, j, args2);
+    *gen_opparam_ptr++ = GET_TCGV_PTR(func);
+
+    *gen_opparam_ptr++ = flags;
+
+    *nparam = (nb_rets << 16) | (real_args + 1);
+
+    /* total parameters, needed to go backward in the instruction stream */
+    *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
 }
-#else
-void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags,
-                  unsigned int nb_rets, const TCGv *rets,
-                  unsigned int nb_params, const TCGv *args1)
-{
-    tcg_gen_call_internal(s, func, flags, 
-                          nb_rets, rets, nb_params, args1);
-}
-#endif
 
 #if TCG_TARGET_REG_BITS == 32
-void tcg_gen_shifti_i64(TCGv ret, TCGv arg1, 
+void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
                         int c, int right, int arith)
 {
     if (c == 0) {
-        tcg_gen_mov_i32(ret, arg1);
+        tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg1));
         tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1));
     } else if (c >= 32) {
         c -= 32;
         if (right) {
             if (arith) {
-                tcg_gen_sari_i32(ret, TCGV_HIGH(arg1), c);
+                tcg_gen_sari_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
                 tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), 31);
             } else {
-                tcg_gen_shri_i32(ret, TCGV_HIGH(arg1), c);
+                tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_HIGH(arg1), c);
                 tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
             }
         } else {
-            tcg_gen_shli_i32(TCGV_HIGH(ret), arg1, c);
-            tcg_gen_movi_i32(ret, 0);
+            tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), c);
+            tcg_gen_movi_i32(TCGV_LOW(ret), 0);
         }
     } else {
-        TCGv t0, t1;
+        TCGv_i32 t0, t1;
 
-        t0 = tcg_temp_new(TCG_TYPE_I32);
-        t1 = tcg_temp_new(TCG_TYPE_I32);
+        t0 = tcg_temp_new_i32();
+        t1 = tcg_temp_new_i32();
         if (right) {
             tcg_gen_shli_i32(t0, TCGV_HIGH(arg1), 32 - c);
             if (arith)
                 tcg_gen_sari_i32(t1, TCGV_HIGH(arg1), c);
-            else 
+            else
                 tcg_gen_shri_i32(t1, TCGV_HIGH(arg1), c);
-            tcg_gen_shri_i32(ret, arg1, c); 
-            tcg_gen_or_i32(ret, ret, t0);
+            tcg_gen_shri_i32(TCGV_LOW(ret), TCGV_LOW(arg1), c);
+            tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(ret), t0);
             tcg_gen_mov_i32(TCGV_HIGH(ret), t1);
         } else {
-            tcg_gen_shri_i32(t0, arg1, 32 - c);
+            tcg_gen_shri_i32(t0, TCGV_LOW(arg1), 32 - c);
             /* Note: ret can be the same as arg1, so we use t1 */
-            tcg_gen_shli_i32(t1, arg1, c); 
+            tcg_gen_shli_i32(t1, TCGV_LOW(arg1), c);
             tcg_gen_shli_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c);
             tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(ret), t0);
-            tcg_gen_mov_i32(ret, t1);
+            tcg_gen_mov_i32(TCGV_LOW(ret), t1);
         }
-        tcg_temp_free(t0);
-        tcg_temp_free(t1);
+        tcg_temp_free_i32(t0);
+        tcg_temp_free_i32(t1);
     }
 }
 #endif
@@ -682,9 +705,14 @@
     return buf;
 }
 
-char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg)
+char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg)
 {
-    return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV(arg));
+    return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I32(arg));
+}
+
+char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg)
+{
+    return tcg_get_arg_str_idx(s, buf, buf_size, GET_TCGV_I64(arg));
 }
 
 static int helper_cmp(const void *p1, const void *p2)
@@ -822,7 +850,7 @@
             val = args[1];
             th = tcg_find_helper(s, val);
             if (th) {
-                fprintf(outfile, th->name);
+                fprintf(outfile, "%s", th->name);
             } else {
                 if (c == INDEX_op_movi_i32)
                     fprintf(outfile, "0x%x", (uint32_t)val);
@@ -1048,7 +1076,14 @@
     const TCGOpDef *def;
     uint8_t *dead_temps;
     unsigned int dead_iargs;
-    
+
+    /* sanity check */
+    if (gen_opc_ptr - gen_opc_buf > OPC_BUF_SIZE) {
+        fprintf(stderr, "PANIC: too many opcodes generated (%d > %d)\n",
+                gen_opc_ptr - gen_opc_buf, OPC_BUF_SIZE);
+        tcg_abort();
+    }
+
     gen_opc_ptr++; /* skip end */
 
     nb_ops = gen_opc_ptr - gen_opc_buf;
@@ -1095,9 +1130,11 @@
                         dead_temps[arg] = 1;
                     }
                     
-                    /* globals are live (they may be used by the call) */
-                    memset(dead_temps, 0, s->nb_globals);
-                    
+                    if (!(call_flags & TCG_CALL_CONST)) {
+                        /* globals are live (they may be used by the call) */
+                        memset(dead_temps, 0, s->nb_globals);
+                    }
+
                     /* input args are live */
                     dead_iargs = 0;
                     for(i = 0; i < nb_iargs; i++) {
@@ -1135,57 +1172,50 @@
             break;
             /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */
         default:
-            if (op > INDEX_op_end) {
-                args -= def->nb_args;
-                nb_iargs = def->nb_iargs;
-                nb_oargs = def->nb_oargs;
+            args -= def->nb_args;
+            nb_iargs = def->nb_iargs;
+            nb_oargs = def->nb_oargs;
 
-                /* Test if the operation can be removed because all
-                   its outputs are dead. We assume that nb_oargs == 0
-                   implies side effects */
-                if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
-                    for(i = 0; i < nb_oargs; i++) {
-                        arg = args[i];
-                        if (!dead_temps[arg])
-                            goto do_not_remove;
-                    }
-                    tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
-#ifdef CONFIG_PROFILER
-                    s->del_op_count++;
-#endif
-                } else {
-                do_not_remove:
-
-                    /* output args are dead */
-                    for(i = 0; i < nb_oargs; i++) {
-                        arg = args[i];
-                        dead_temps[arg] = 1;
-                    }
-                    
-                    /* if end of basic block, update */
-                    if (def->flags & TCG_OPF_BB_END) {
-                        tcg_la_bb_end(s, dead_temps);
-                    } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
-                        /* globals are live */
-                        memset(dead_temps, 0, s->nb_globals);
-                    }
-                    
-                    /* input args are live */
-                    dead_iargs = 0;
-                    for(i = 0; i < nb_iargs; i++) {
-                        arg = args[i + nb_oargs];
-                        if (dead_temps[arg]) {
-                            dead_iargs |= (1 << i);
-                        }
-                        dead_temps[arg] = 0;
-                    }
-                    s->op_dead_iargs[op_index] = dead_iargs;
+            /* Test if the operation can be removed because all
+               its outputs are dead. We assume that nb_oargs == 0
+               implies side effects */
+            if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) {
+                for(i = 0; i < nb_oargs; i++) {
+                    arg = args[i];
+                    if (!dead_temps[arg])
+                        goto do_not_remove;
                 }
+                tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args);
+#ifdef CONFIG_PROFILER
+                s->del_op_count++;
+#endif
             } else {
-                /* legacy dyngen operations */
-                args -= def->nb_args;
-                /* mark end of basic block */
-                tcg_la_bb_end(s, dead_temps);
+            do_not_remove:
+
+                /* output args are dead */
+                for(i = 0; i < nb_oargs; i++) {
+                    arg = args[i];
+                    dead_temps[arg] = 1;
+                }
+
+                /* if end of basic block, update */
+                if (def->flags & TCG_OPF_BB_END) {
+                    tcg_la_bb_end(s, dead_temps);
+                } else if (def->flags & TCG_OPF_CALL_CLOBBER) {
+                    /* globals are live */
+                    memset(dead_temps, 0, s->nb_globals);
+                }
+
+                /* input args are live */
+                dead_iargs = 0;
+                for(i = 0; i < nb_iargs; i++) {
+                    arg = args[i + nb_oargs];
+                    if (dead_temps[arg]) {
+                        dead_iargs |= (1 << i);
+                    }
+                    dead_temps[arg] = 0;
+                }
+                s->op_dead_iargs[op_index] = dead_iargs;
             }
             break;
         }
@@ -1801,7 +1831,9 @@
     
     /* store globals and free associated registers (we assume the call
        can modify any global. */
-    save_globals(s, allocated_regs);
+    if (!(flags & TCG_CALL_CONST)) {
+        save_globals(s, allocated_regs);
+    }
 
     tcg_out_op(s, opc, &func_arg, &const_func_arg);
     
@@ -1834,20 +1866,15 @@
 
 #ifdef CONFIG_PROFILER
 
-static int64_t dyngen_table_op_count[NB_OPS];
+static int64_t tcg_table_op_count[NB_OPS];
 
 void dump_op_count(void)
 {
     int i;
     FILE *f;
-    f = fopen("/tmp/op1.log", "w");
-    for(i = 0; i < INDEX_op_end; i++) {
-        fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);
-    }
-    fclose(f);
-    f = fopen("/tmp/op2.log", "w");
+    f = fopen("/tmp/op.log", "w");
     for(i = INDEX_op_end; i < NB_OPS; i++) {
-        fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, dyngen_table_op_count[i]);
+        fprintf(f, "%s %" PRId64 "\n", tcg_op_defs[i].name, tcg_table_op_count[i]);
     }
     fclose(f);
 }
@@ -1863,10 +1890,10 @@
     const TCGArg *args;
 
 #ifdef DEBUG_DISAS
-    if (unlikely(loglevel & CPU_LOG_TB_OP)) {
-        fprintf(logfile, "OP:\n");
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+        qemu_log("OP:\n");
         tcg_dump_ops(s, logfile);
-        fprintf(logfile, "\n");
+        qemu_log("\n");
     }
 #endif
 
@@ -1879,10 +1906,10 @@
 #endif
 
 #ifdef DEBUG_DISAS
-    if (unlikely(loglevel & CPU_LOG_TB_OP_OPT)) {
-        fprintf(logfile, "OP after la:\n");
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT))) {
+        qemu_log("OP after la:\n");
         tcg_dump_ops(s, logfile);
-        fprintf(logfile, "\n");
+        qemu_log("\n");
     }
 #endif
 
@@ -1897,7 +1924,7 @@
     for(;;) {
         opc = gen_opc_buf[op_index];
 #ifdef CONFIG_PROFILER
-        dyngen_table_op_count[opc]++;
+        tcg_table_op_count[opc]++;
 #endif
         def = &tcg_op_defs[opc];
 #if 0
@@ -1952,22 +1979,6 @@
             goto next;
         case INDEX_op_end:
             goto the_end;
-
-#ifdef CONFIG_DYNGEN_OP
-        case 0 ... INDEX_op_end - 1:
-            /* legacy dyngen ops */
-#ifdef CONFIG_PROFILER
-            s->old_op_count++;
-#endif
-            tcg_reg_alloc_bb_end(s, s->reserved_regs);
-            if (search_pc >= 0) {
-                s->code_ptr += def->copy_size;
-                args += def->nb_args;
-            } else {
-                args = dyngen_op(s, opc, args);
-            }
-            goto next;
-#endif
         default:
             /* Note: in order to speed up the code, it would be much
                faster to have specialized register allocator functions for
@@ -1990,7 +2001,7 @@
     return -1;
 }
 
-int dyngen_code(TCGContext *s, uint8_t *gen_code_buf)
+int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)
 {
 #ifdef CONFIG_PROFILER
     {
@@ -2006,6 +2017,13 @@
     }
 #endif
 
+    /* sanity check */
+    if (gen_opc_ptr - gen_opc_buf > OPC_BUF_SIZE) {
+        fprintf(stderr, "PANIC: too many opcodes generated (%d > %d)\n",
+                gen_opc_ptr - gen_opc_buf, OPC_BUF_SIZE);
+        tcg_abort();
+    }
+
     tcg_gen_code_common(s, gen_code_buf, -1);
 
     /* flush instruction cache */
@@ -2018,7 +2036,7 @@
    offset bytes from the start of the TB.  The contents of gen_code_buf must
    not be changed, though writing the same values is ok.
    Return -1 if not found. */
-int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
+int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset)
 {
     return tcg_gen_code_common(s, gen_code_buf, offset);
 }
@@ -2039,8 +2057,6 @@
                 s->tb_count1 ? (double)(s->tb_count1 - s->tb_count) / s->tb_count1 * 100.0 : 0);
     cpu_fprintf(f, "avg ops/TB          %0.1f max=%d\n", 
                 s->tb_count ? (double)s->op_count / s->tb_count : 0, s->op_count_max);
-    cpu_fprintf(f, "old ops/total ops   %0.1f%%\n", 
-                s->op_count ? (double)s->old_op_count / s->op_count * 100.0 : 0);
     cpu_fprintf(f, "deleted ops/TB      %0.2f\n",
                 s->tb_count ? 
                 (double)s->del_op_count / s->tb_count : 0);
diff --git a/tcg/tcg.h b/tcg/tcg.h
index bc5b902..ad0bd14 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -21,6 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include "qemu-common.h"
 #include "tcg-target.h"
 
 #if TCG_TARGET_REG_BITS == 32
@@ -114,37 +115,61 @@
    expecially on targets with braindamaged ABIs (e.g. i386).
    We use plain int by default to avoid this runtime overhead.
    Users of tcg_gen_* don't need to know about any of this, and should
-   treat TCGv as an opaque type.  */
+   treat TCGv as an opaque type.
+   In additon we do typechecking for different types of variables.  TCGv_i32
+   and TCGv_i64 are 32/64-bit variables respectively.  TCGv and TCGv_ptr
+   are aliases for target_ulong and host pointer sized values respectively.
+ */
 
-//#define DEBUG_TCGV 1
+#ifdef DEBUG_TCG
+#define DEBUG_TCGV 1
+#endif
 
 #ifdef DEBUG_TCGV
 
 typedef struct
 {
-    int n;
-} TCGv;
+    int i32;
+} TCGv_i32;
 
-#define MAKE_TCGV(i) __extension__ \
-  ({ TCGv make_tcgv_tmp = {i}; make_tcgv_tmp;})
-#define GET_TCGV(t) ((t).n)
+typedef struct
+{
+    int i64;
+} TCGv_i64;
+
+#define MAKE_TCGV_I32(i) __extension__                  \
+    ({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;})
+#define MAKE_TCGV_I64(i) __extension__                  \
+    ({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;})
+#define GET_TCGV_I32(t) ((t).i32)
+#define GET_TCGV_I64(t) ((t).i64)
 #if TCG_TARGET_REG_BITS == 32
-#define TCGV_HIGH(t) MAKE_TCGV(GET_TCGV(t) + 1)
+#define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t))
+#define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1)
 #endif
 
 #else /* !DEBUG_TCGV */
 
-typedef int TCGv;
-#define MAKE_TCGV(x) (x)
-#define GET_TCGV(t) (t)
+typedef int TCGv_i32;
+typedef int TCGv_i64;
+#define MAKE_TCGV_I32(x) (x)
+#define MAKE_TCGV_I64(x) (x)
+#define GET_TCGV_I32(t) (t)
+#define GET_TCGV_I64(t) (t)
+
 #if TCG_TARGET_REG_BITS == 32
+#define TCGV_LOW(t) (t)
 #define TCGV_HIGH(t) ((t) + 1)
 #endif
 
 #endif /* DEBUG_TCGV */
 
+#define TCGV_EQUAL_I32(a, b) (GET_TCGV_I32(a) == GET_TCGV_I32(b))
+#define TCGV_EQUAL_I64(a, b) (GET_TCGV_I64(a) == GET_TCGV_I64(b))
+
 /* Dummy definition to avoid compiler warnings.  */
-#define TCGV_UNUSED(x) x = MAKE_TCGV(-1)
+#define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1)
+#define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1)
 
 /* call flags */
 #define TCG_CALL_TYPE_MASK      0x000f
@@ -152,13 +177,17 @@
 #define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */
 #define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */
 #define TCG_CALL_TYPE_REGPARM   0x0003 /* i386 style regparm call (3 regs) */
-/* A pure function only reads its arguments and globals variables and
-   cannot raise exceptions. Hence a call to a pure function can be
+/* A pure function only reads its arguments and TCG global variables
+   and cannot raise exceptions. Hence a call to a pure function can be
    safely suppressed if the return value is not used. */
 #define TCG_CALL_PURE           0x0010 
+/* A const function only reads its arguments and does not use TCG
+   global variables. Hence a call to such a function does not
+   save TCG global variables back to their canonical location. */
+#define TCG_CALL_CONST          0x0020
 
 /* used to align parameters */
-#define TCG_CALL_DUMMY_TCGV     MAKE_TCGV(-1)
+#define TCG_CALL_DUMMY_TCGV     MAKE_TCGV_I32(-1)
 #define TCG_CALL_DUMMY_ARG      ((TCGArg)(-1))
 
 typedef enum {
@@ -254,7 +283,6 @@
     int op_count_max; /* max insn per TB */
     int64_t temp_count;
     int temp_count_max;
-    int64_t old_op_count;
     int64_t del_op_count;
     int64_t code_in_len;
     int64_t code_out_len;
@@ -296,27 +324,42 @@
 void tcg_context_init(TCGContext *s);
 void tcg_func_start(TCGContext *s);
 
-int dyngen_code(TCGContext *s, uint8_t *gen_code_buf);
-int dyngen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset);
+int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf);
+int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset);
 
 void tcg_set_frame(TCGContext *s, int reg,
                    tcg_target_long start, tcg_target_long size);
-TCGv tcg_global_reg_new(TCGType type, int reg, const char *name);
-TCGv tcg_global_reg2_new_hack(TCGType type, int reg1, int reg2, 
-                              const char *name);
-TCGv tcg_global_mem_new(TCGType type, int reg, tcg_target_long offset,
-                        const char *name);
-TCGv tcg_temp_new_internal(TCGType type, int temp_local);
-static inline TCGv tcg_temp_new(TCGType type)
+
+TCGv_i32 tcg_global_reg_new_i32(int reg, const char *name);
+TCGv_i32 tcg_global_mem_new_i32(int reg, tcg_target_long offset,
+                                const char *name);
+TCGv_i32 tcg_temp_new_internal_i32(int temp_local);
+static inline TCGv_i32 tcg_temp_new_i32(void)
 {
-    return tcg_temp_new_internal(type, 0);
+    return tcg_temp_new_internal_i32(0);
 }
-static inline TCGv tcg_temp_local_new(TCGType type)
+static inline TCGv_i32 tcg_temp_local_new_i32(void)
 {
-    return tcg_temp_new_internal(type, 1);
+    return tcg_temp_new_internal_i32(1);
 }
-void tcg_temp_free(TCGv arg);
-char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGv arg);
+void tcg_temp_free_i32(TCGv_i32 arg);
+char *tcg_get_arg_str_i32(TCGContext *s, char *buf, int buf_size, TCGv_i32 arg);
+
+TCGv_i64 tcg_global_reg_new_i64(int reg, const char *name);
+TCGv_i64 tcg_global_mem_new_i64(int reg, tcg_target_long offset,
+                                const char *name);
+TCGv_i64 tcg_temp_new_internal_i64(int temp_local);
+static inline TCGv_i64 tcg_temp_new_i64(void)
+{
+    return tcg_temp_new_internal_i64(0);
+}
+static inline TCGv_i64 tcg_temp_local_new_i64(void)
+{
+    return tcg_temp_new_internal_i64(1);
+}
+void tcg_temp_free_i64(TCGv_i64 arg);
+char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg);
+
 void tcg_dump_info(FILE *f,
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
 
@@ -357,8 +400,6 @@
     const char *args_ct_str[TCG_MAX_OP_ARGS];
 } TCGTargetOpDef;
 
-extern TCGOpDef tcg_op_defs[];
-
 void tcg_target_init(TCGContext *s);
 void tcg_target_qemu_prologue(TCGContext *s);
 
@@ -370,39 +411,50 @@
 
 void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
 
-void tcg_gen_call(TCGContext *s, TCGv func, unsigned int flags,
-                  unsigned int nb_rets, const TCGv *rets,
-                  unsigned int nb_params, const TCGv *args1);
-void tcg_gen_shifti_i64(TCGv ret, TCGv arg1, 
-                        int c, int right, int arith);
-
-/* only used for debugging purposes */
-void tcg_register_helper(void *func, const char *name);
-#define TCG_HELPER(func) tcg_register_helper(func, #func)
-const char *tcg_helper_get_name(TCGContext *s, void *func);
-void tcg_dump_ops(TCGContext *s, FILE *outfile);
-
-void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf);
-TCGv tcg_const_i32(int32_t val);
-TCGv tcg_const_i64(int64_t val);
-
 #if TCG_TARGET_REG_BITS == 32
 #define tcg_const_ptr tcg_const_i32
 #define tcg_add_ptr tcg_add_i32
 #define tcg_sub_ptr tcg_sub_i32
+#define TCGv_ptr TCGv_i32
+#define GET_TCGV_PTR GET_TCGV_I32
+#define tcg_global_reg_new_ptr tcg_global_reg_new_i32
+#define tcg_global_mem_new_ptr tcg_global_mem_new_i32
+#define tcg_temp_new_ptr tcg_temp_new_i32
+#define tcg_temp_free_ptr tcg_temp_free_i32
 #else
 #define tcg_const_ptr tcg_const_i64
 #define tcg_add_ptr tcg_add_i64
 #define tcg_sub_ptr tcg_sub_i64
+#define TCGv_ptr TCGv_i64
+#define GET_TCGV_PTR GET_TCGV_I64
+#define tcg_global_reg_new_ptr tcg_global_reg_new_i64
+#define tcg_global_mem_new_ptr tcg_global_mem_new_i64
+#define tcg_temp_new_ptr tcg_temp_new_i64
+#define tcg_temp_free_ptr tcg_temp_free_i64
 #endif
 
+void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
+                   int sizemask, TCGArg ret, int nargs, TCGArg *args);
+
+void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
+                        int c, int right, int arith);
+
+/* only used for debugging purposes */
+void tcg_register_helper(void *func, const char *name);
+const char *tcg_helper_get_name(TCGContext *s, void *func);
+void tcg_dump_ops(TCGContext *s, FILE *outfile);
+
+void dump_ops(const uint16_t *opc_buf, const TCGArg *opparam_buf);
+TCGv_i32 tcg_const_i32(int32_t val);
+TCGv_i64 tcg_const_i64(int64_t val);
+TCGv_i32 tcg_const_local_i32(int32_t val);
+TCGv_i64 tcg_const_local_i64(int64_t val);
+
 void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, 
                    int label_index, long addend);
 const TCGArg *tcg_gen_code_op(TCGContext *s, int opc, const TCGArg *args1,
                               unsigned int dead_iargs);
 
-const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr);
-
 /* tcg-runtime.c */
 int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2);
 int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2);
@@ -413,7 +465,7 @@
 uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
 
 extern uint8_t code_gen_prologue[];
-#if defined(__powerpc__) && !defined(__powerpc64__)
+#if defined(_ARCH_PPC) && !defined(_ARCH_PPC64)
 #define tcg_qemu_tb_exec(tb_ptr) \
     ((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr)
 #else
diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c
index 304a0c3..a26e714 100644
--- a/tcg/x86_64/tcg-target.c
+++ b/tcg/x86_64/tcg-target.c
@@ -21,7 +21,9 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-const char *tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+
+#ifndef NDEBUG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "%rax",
     "%rcx",
     "%rdx",
@@ -39,27 +41,27 @@
     "%r14",
     "%r15",
 };
+#endif
 
-int tcg_target_reg_alloc_order[] = {
-    TCG_REG_RDI,
-    TCG_REG_RSI,
-    TCG_REG_RDX,
-    TCG_REG_RCX,
-    TCG_REG_R8,
-    TCG_REG_R9,
-    TCG_REG_RAX,
-    TCG_REG_R10,
-    TCG_REG_R11,
-
+static const int tcg_target_reg_alloc_order[] = {
     TCG_REG_RBP,
     TCG_REG_RBX,
     TCG_REG_R12,
     TCG_REG_R13,
     TCG_REG_R14,
     TCG_REG_R15,
+    TCG_REG_R10,
+    TCG_REG_R11,
+    TCG_REG_R9,
+    TCG_REG_R8,
+    TCG_REG_RCX,
+    TCG_REG_RDX,
+    TCG_REG_RSI,
+    TCG_REG_RDI,
+    TCG_REG_RAX,
 };
 
-const int tcg_target_call_iarg_regs[6] = { 
+static const int tcg_target_call_iarg_regs[6] = {
     TCG_REG_RDI,
     TCG_REG_RSI,
     TCG_REG_RDX,
@@ -68,7 +70,7 @@
     TCG_REG_R9,
 };
 
-const int tcg_target_call_oarg_regs[2] = { 
+static const int tcg_target_call_oarg_regs[2] = {
     TCG_REG_RAX, 
     TCG_REG_RDX 
 };
@@ -191,6 +193,8 @@
 #define ARITH_XOR 6
 #define ARITH_CMP 7
 
+#define SHIFT_ROL 0
+#define SHIFT_ROR 1
 #define SHIFT_SHL 4
 #define SHIFT_SHR 5
 #define SHIFT_SAR 7
@@ -240,7 +244,7 @@
     }
     if (opc & P_EXT)
         tcg_out8(s, 0x0f);
-    tcg_out8(s, opc);
+    tcg_out8(s, opc & 0xff);
 }
 
 static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm)
@@ -359,6 +363,20 @@
     }
 }
 
+static void tcg_out_goto(TCGContext *s, int call, uint8_t *target)
+{
+    int32_t disp;
+
+    disp = target - s->code_ptr - 5;
+    if (disp == (target - s->code_ptr - 5)) {
+        tcg_out8(s, call ? 0xe8 : 0xe9);
+        tcg_out32(s, disp);
+    } else {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, (tcg_target_long) target);
+        tcg_out_modrm(s, 0xff, call ? 2 : 4, TCG_REG_R10);
+    }
+}
+
 static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
                               int arg1, tcg_target_long arg2)
 {
@@ -379,7 +397,13 @@
 
 static inline void tgen_arithi32(TCGContext *s, int c, int r0, int32_t val)
 {
-    if (val == (int8_t)val) {
+    if ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1)) {
+        /* inc */
+        tcg_out_modrm(s, 0xff, 0, r0);
+    } else if ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1)) {
+        /* dec */
+        tcg_out_modrm(s, 0xff, 1, r0);
+    } else if (val == (int8_t)val) {
         tcg_out_modrm(s, 0x83, c, r0);
         tcg_out8(s, val);
     } else if (c == ARITH_AND && val == 0xffu) {
@@ -396,7 +420,13 @@
 
 static inline void tgen_arithi64(TCGContext *s, int c, int r0, int64_t val)
 {
-    if (val == (int8_t)val) {
+    if ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1)) {
+        /* inc */
+        tcg_out_modrm(s, 0xff | P_REXW, 0, r0);
+    } else if ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1)) {
+        /* dec */
+        tcg_out_modrm(s, 0xff | P_REXW, 1, r0);
+    } else if (val == (int8_t)val) {
         tcg_out_modrm(s, 0x83 | P_REXW, c, r0);
         tcg_out8(s, val);
     } else if (c == ARITH_AND && val == 0xffu) {
@@ -504,6 +534,7 @@
                             int opc)
 {
     int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
+    int32_t offset;
 #if defined(CONFIG_SOFTMMU)
     uint8_t *label1_ptr, *label2_ptr;
 #endif
@@ -554,9 +585,7 @@
 
     /* XXX: move that code at the end of the TB */
     tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RSI, mem_index);
-    tcg_out8(s, 0xe8);
-    tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] - 
-              (tcg_target_long)s->code_ptr - 4);
+    tcg_out_goto(s, 1, qemu_ld_helpers[s_bits]);
 
     switch(opc) {
     case 0 | 4:
@@ -572,7 +601,13 @@
         tcg_out_modrm(s, 0x63 | P_REXW, data_reg, TCG_REG_RAX);
         break;
     case 0:
+        /* movzbq */
+        tcg_out_modrm(s, 0xb6 | P_EXT | P_REXW, data_reg, TCG_REG_RAX);
+        break;
     case 1:
+        /* movzwq */
+        tcg_out_modrm(s, 0xb7 | P_EXT | P_REXW, data_reg, TCG_REG_RAX);
+        break;
     case 2:
     default:
         /* movl */
@@ -750,9 +785,7 @@
         break;
     }
     tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
-    tcg_out8(s, 0xe8);
-    tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] - 
-              (tcg_target_long)s->code_ptr - 4);
+    tcg_out_goto(s, 1, qemu_st_helpers[s_bits]);
 
     /* jmp label2 */
     tcg_out8(s, 0xeb);
@@ -829,8 +862,7 @@
     switch(opc) {
     case INDEX_op_exit_tb:
         tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]);
-        tcg_out8(s, 0xe9); /* jmp tb_ret_addr */
-        tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
+        tcg_out_goto(s, 0, tb_ret_addr);
         break;
     case INDEX_op_goto_tb:
         if (s->tb_jmp_offset) {
@@ -849,16 +881,14 @@
         break;
     case INDEX_op_call:
         if (const_args[0]) {
-            tcg_out8(s, 0xe8);
-            tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4);
+            tcg_out_goto(s, 1, (void *) args[0]);
         } else {
             tcg_out_modrm(s, 0xff, 2, args[0]);
         }
         break;
     case INDEX_op_jmp:
         if (const_args[0]) {
-            tcg_out8(s, 0xe9);
-            tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4);
+            tcg_out_goto(s, 0, (void *) args[0]);
         } else {
             tcg_out_modrm(s, 0xff, 4, args[0]);
         }
@@ -1040,7 +1070,13 @@
     case INDEX_op_sar_i32:
         c = SHIFT_SAR;
         goto gen_shift32;
-        
+    case INDEX_op_rotl_i32:
+        c = SHIFT_ROL;
+        goto gen_shift32;
+    case INDEX_op_rotr_i32:
+        c = SHIFT_ROR;
+        goto gen_shift32;
+
     case INDEX_op_shl_i64:
         c = SHIFT_SHL;
     gen_shift64:
@@ -1061,7 +1097,13 @@
     case INDEX_op_sar_i64:
         c = SHIFT_SAR;
         goto gen_shift64;
-        
+    case INDEX_op_rotl_i64:
+        c = SHIFT_ROL;
+        goto gen_shift64;
+    case INDEX_op_rotr_i64:
+        c = SHIFT_ROR;
+        goto gen_shift64;
+
     case INDEX_op_brcond_i32:
         tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], 
                        args[3], 0);
@@ -1071,10 +1113,17 @@
                        args[3], P_REXW);
         break;
 
-    case INDEX_op_bswap_i32:
+    case INDEX_op_bswap16_i32:
+    case INDEX_op_bswap16_i64:
+        tcg_out8(s, 0x66);
+        tcg_out_modrm(s, 0xc1, SHIFT_ROL, args[0]);
+        tcg_out8(s, 8);
+        break;
+    case INDEX_op_bswap32_i32:
+    case INDEX_op_bswap32_i64:
         tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT, 0, args[0], 0);
         break;
-    case INDEX_op_bswap_i64:
+    case INDEX_op_bswap64_i64:
         tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT | P_REXW, 0, args[0], 0);
         break;
 
@@ -1085,6 +1134,13 @@
         tcg_out_modrm(s, 0xf7 | P_REXW, 3, args[0]);
         break;
 
+    case INDEX_op_not_i32:
+        tcg_out_modrm(s, 0xf7, 2, args[0]);
+        break;
+    case INDEX_op_not_i64:
+        tcg_out_modrm(s, 0xf7 | P_REXW, 2, args[0]);
+        break;
+
     case INDEX_op_ext8s_i32:
         tcg_out_modrm(s, 0xbe | P_EXT | P_REXB, args[0], args[1]);
         break;
@@ -1221,6 +1277,8 @@
     { INDEX_op_shl_i32, { "r", "0", "ci" } },
     { INDEX_op_shr_i32, { "r", "0", "ci" } },
     { INDEX_op_sar_i32, { "r", "0", "ci" } },
+    { INDEX_op_rotl_i32, { "r", "0", "ci" } },
+    { INDEX_op_rotr_i32, { "r", "0", "ci" } },
 
     { INDEX_op_brcond_i32, { "r", "ri" } },
 
@@ -1250,15 +1308,23 @@
     { INDEX_op_shl_i64, { "r", "0", "ci" } },
     { INDEX_op_shr_i64, { "r", "0", "ci" } },
     { INDEX_op_sar_i64, { "r", "0", "ci" } },
+    { INDEX_op_rotl_i64, { "r", "0", "ci" } },
+    { INDEX_op_rotr_i64, { "r", "0", "ci" } },
 
     { INDEX_op_brcond_i64, { "r", "re" } },
 
-    { INDEX_op_bswap_i32, { "r", "0" } },
-    { INDEX_op_bswap_i64, { "r", "0" } },
+    { INDEX_op_bswap16_i32, { "r", "0" } },
+    { INDEX_op_bswap16_i64, { "r", "0" } },
+    { INDEX_op_bswap32_i32, { "r", "0" } },
+    { INDEX_op_bswap32_i64, { "r", "0" } },
+    { INDEX_op_bswap64_i64, { "r", "0" } },
 
     { INDEX_op_neg_i32, { "r", "0" } },
     { INDEX_op_neg_i64, { "r", "0" } },
 
+    { INDEX_op_not_i32, { "r", "0" } },
+    { INDEX_op_not_i64, { "r", "0" } },
+
     { INDEX_op_ext8s_i32, { "r", "r"} },
     { INDEX_op_ext16s_i32, { "r", "r"} },
     { INDEX_op_ext8s_i64, { "r", "r"} },
diff --git a/tcg/x86_64/tcg-target.h b/tcg/x86_64/tcg-target.h
index 9a0cca0..8cb05c6 100644
--- a/tcg/x86_64/tcg-target.h
+++ b/tcg/x86_64/tcg-target.h
@@ -56,21 +56,27 @@
 #define TCG_TARGET_CALL_STACK_OFFSET 0
 
 /* optional instructions */
-#define TCG_TARGET_HAS_bswap_i32
-#define TCG_TARGET_HAS_bswap_i64
+#define TCG_TARGET_HAS_bswap16_i32
+#define TCG_TARGET_HAS_bswap16_i64
+#define TCG_TARGET_HAS_bswap32_i32
+#define TCG_TARGET_HAS_bswap32_i64
+#define TCG_TARGET_HAS_bswap64_i64
 #define TCG_TARGET_HAS_neg_i32
 #define TCG_TARGET_HAS_neg_i64
+#define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_not_i64
 #define TCG_TARGET_HAS_ext8s_i32
 #define TCG_TARGET_HAS_ext16s_i32
 #define TCG_TARGET_HAS_ext8s_i64
 #define TCG_TARGET_HAS_ext16s_i64
 #define TCG_TARGET_HAS_ext32s_i64
+#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_rot_i64
 
 /* Note: must be synced with dyngen-exec.h */
 #define TCG_AREG0 TCG_REG_R14
 #define TCG_AREG1 TCG_REG_R15
 #define TCG_AREG2 TCG_REG_R12
-#define TCG_AREG3 TCG_REG_R13
 
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
diff --git a/thunk.c b/thunk.c
index 7331aeb..6813c9f 100644
--- a/thunk.c
+++ b/thunk.c
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include <stdlib.h>
 #include <stdio.h>
@@ -113,7 +113,8 @@
     }
 }
 
-void thunk_register_struct_direct(int id, const char *name, StructEntry *se1)
+void thunk_register_struct_direct(int id, const char *name,
+                                  const StructEntry *se1)
 {
     StructEntry *se;
     se = struct_entries + id;
@@ -248,9 +249,9 @@
  * between X86 and Alpha formats...
  */
 unsigned int target_to_host_bitmask(unsigned int x86_mask,
-                                    bitmask_transtbl * trans_tbl)
+                                    const bitmask_transtbl * trans_tbl)
 {
-    bitmask_transtbl *	btp;
+    const bitmask_transtbl *btp;
     unsigned int	alpha_mask = 0;
 
     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
@@ -262,9 +263,9 @@
 }
 
 unsigned int host_to_target_bitmask(unsigned int alpha_mask,
-                                    bitmask_transtbl * trans_tbl)
+                                    const bitmask_transtbl * trans_tbl)
 {
-    bitmask_transtbl *	btp;
+    const bitmask_transtbl *btp;
     unsigned int	x86_mask = 0;
 
     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
diff --git a/thunk.h b/thunk.h
index d650fa4..597d753 100644
--- a/thunk.h
+++ b/thunk.h
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #ifndef THUNK_H
 #define THUNK_H
@@ -68,7 +68,8 @@
 } bitmask_transtbl;
 
 void thunk_register_struct(int id, const char *name, const argtype *types);
-void thunk_register_struct_direct(int id, const char *name, StructEntry *se1);
+void thunk_register_struct_direct(int id, const char *name,
+                                  const StructEntry *se1);
 const argtype *thunk_convert(void *dst, const void *src,
                              const argtype *type_ptr, int to_host);
 #ifndef NO_THUNK_TYPE_SIZE
@@ -154,8 +155,8 @@
 #endif /* NO_THUNK_TYPE_SIZE */
 
 unsigned int target_to_host_bitmask(unsigned int x86_mask,
-                                    bitmask_transtbl * trans_tbl);
+                                    const bitmask_transtbl * trans_tbl);
 unsigned int host_to_target_bitmask(unsigned int alpha_mask,
-                                    bitmask_transtbl * trans_tbl);
+                                    const bitmask_transtbl * trans_tbl);
 
 #endif
diff --git a/translate-all.c b/translate-all.c
index 1c27fd3..4bdf2c9 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include <stdarg.h>
 #include <stdlib.h>
@@ -118,7 +118,7 @@
     s->interm_time += profile_getclock() - ti;
     s->code_time -= profile_getclock();
 #endif
-    gen_code_size = dyngen_code(s, gen_code_buf);
+    gen_code_size = tcg_gen_code(s, gen_code_buf);
     *gen_code_size_ptr = gen_code_size;
 #ifdef CONFIG_PROFILER
     s->code_time += profile_getclock();
@@ -127,11 +127,11 @@
 #endif
 
 #ifdef DEBUG_DISAS
-    if (loglevel & CPU_LOG_TB_OUT_ASM) {
-        fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
-        disas(logfile, tb->tc_ptr, *gen_code_size_ptr);
-        fprintf(logfile, "\n");
-        fflush(logfile);
+    if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) {
+        qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr);
+        log_disas(tb->tc_ptr, *gen_code_size_ptr);
+        qemu_log("\n");
+        qemu_log_flush();
     }
 #endif
     return 0;
@@ -177,7 +177,7 @@
     s->tb_jmp_offset = NULL;
     s->tb_next = tb->tb_next;
 #endif
-    j = dyngen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr);
+    j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr);
     if (j < 0)
         return -1;
     /* now find start of instruction before */
diff --git a/uboot_image.h b/uboot_image.h
index d5a5b30..b6d49be 100644
--- a/uboot_image.h
+++ b/uboot_image.h
@@ -15,10 +15,9 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  ********************************************************************
  * NOTE: This header file defines an interface to U-Boot. Including
diff --git a/usb-dummy-android.c b/usb-dummy-android.c
new file mode 100755
index 0000000..ed03219
--- /dev/null
+++ b/usb-dummy-android.c
@@ -0,0 +1,43 @@
+/*
+ * Fake Win32 USB redirector
+ *
+ * Copyright (c) 2009 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "monitor.h"
+#include "hw/usb.h"
+
+USBDevice *usb_host_device_open(const char *devname)
+{
+	return NULL;
+}
+
+int usb_host_device_close(const char *devname)
+{
+	return 0;
+}
+ 
+void usb_host_info(Monitor *mon)
+{
+    monitor_printf(mon, "   No devices\n");
+}
diff --git a/usb-linux.c b/usb-linux.c
index 91acccd..67e4acd 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -7,6 +7,10 @@
  *      Support for host device auto connect & disconnect
  *      Major rewrite to support fully async operation
  *
+ * Copyright 2008 TJ <linux@tjworld.net>
+ *      Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
+ *      to the legacy /proc/bus/usb USB device discovery and handling
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -28,9 +32,8 @@
 
 #include "qemu-common.h"
 #include "qemu-timer.h"
-#include "console.h"
+#include "monitor.h"
 
-#if defined(__linux__)
 #include <dirent.h>
 #include <sys/ioctl.h>
 #include <signal.h>
@@ -72,9 +75,22 @@
 #define dprintf(...)
 #endif
 
-#define USBDEVFS_PATH "/proc/bus/usb"
+#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
+
+#define USBPROCBUS_PATH "/proc/bus/usb"
 #define PRODUCT_NAME_SZ 32
 #define MAX_ENDPOINTS 16
+#define USBDEVBUS_PATH "/dev/bus/usb"
+#define USBSYSBUS_PATH "/sys/bus/usb"
+
+static char *usb_host_device_path;
+
+#define USB_FS_NONE 0
+#define USB_FS_PROC 1
+#define USB_FS_DEV 2
+#define USB_FS_SYS 3
+
+static int usb_fs_type;
 
 /* endpoint association data */
 struct endp_data {
@@ -425,10 +441,6 @@
     int ret;
 
     aurb = async_alloc();
-    if (!aurb) {
-        dprintf("husb: async malloc failed\n");
-        return USB_RET_NAK;
-    }
     aurb->hdev   = s;
     aurb->packet = p;
 
@@ -569,10 +581,6 @@
     /* The rest are asynchronous */
 
     aurb = async_alloc();
-    if (!aurb) {
-        dprintf("husb: async malloc failed\n");
-        return USB_RET_NAK;
-    }
     aurb->hdev   = s;
     aurb->packet = p;
 
@@ -771,7 +779,7 @@
 {
     uint8_t *descriptors;
     uint8_t devep, type, configuration, alt_interface;
-    struct usbdevfs_ctrltransfer ct;
+    struct usb_ctrltransfer ct;
     int interface, ret, length, i;
 
     ct.bRequestType = USB_DIR_IN;
@@ -825,8 +833,7 @@
 
         ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
         if (ret < 0) {
-            perror("usb_linux_update_endp_table");
-            return 1;
+            alt_interface = interface;
         }
 
         /* the current interface descriptor is the active interface
@@ -882,21 +889,24 @@
     char buf[1024];
 
     dev = qemu_mallocz(sizeof(USBHostDevice));
-    if (!dev)
-        goto fail;
 
     dev->bus_num = bus_num;
     dev->addr = addr;
 
     printf("husb: open device %d.%d\n", bus_num, addr);
 
-    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
+    if (!usb_host_device_path) {
+        perror("husb: USB Host Device Path not set");
+        goto fail;
+    }
+    snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
              bus_num, addr);
     fd = open(buf, O_RDWR | O_NONBLOCK);
     if (fd < 0) {
         perror(buf);
         goto fail;
     }
+    dprintf("husb: opened %s\n", buf);
 
     /* read the device description */
     dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
@@ -974,6 +984,7 @@
 
 USBDevice *usb_host_device_open(const char *devname)
 {
+    Monitor *mon = cur_mon;
     int bus_num, addr;
     char product_name[PRODUCT_NAME_SZ];
 
@@ -987,7 +998,8 @@
         return NULL;
 
     if (hostdev_find(bus_num, addr)) {
-       term_printf("husb: host usb device %d.%d is already open\n", bus_num, addr);
+       monitor_printf(mon, "husb: host usb device %d.%d is already open\n",
+                      bus_num, addr);
        return NULL;
     }
 
@@ -1026,7 +1038,7 @@
     if (!p)
         return -1;
     p += strlen(tag);
-    while (isspace(*p))
+    while (qemu_isspace(*p))
         p++;
     q = buf;
     while (*p != '\0' && !strchr(stopchars, *p)) {
@@ -1038,23 +1050,33 @@
     return q - buf;
 }
 
-static int usb_host_scan(void *opaque, USBScanFunc *func)
+/*
+ * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
+ * host's USB devices. This is legacy support since many distributions
+ * are moving to /sys/bus/usb
+ */
+static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
 {
-    FILE *f;
+    FILE *f = 0;
     char line[1024];
     char buf[1024];
     int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
-    int ret;
     char product_name[512];
+    int ret = 0;
 
-    f = fopen(USBDEVFS_PATH "/devices", "r");
-    if (!f) {
-        term_printf("husb: could not open %s\n", USBDEVFS_PATH "/devices");
-        return 0;
+    if (!usb_host_device_path) {
+        perror("husb: USB Host Device Path not set");
+        goto the_end;
     }
+    snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
+    f = fopen(line, "r");
+    if (!f) {
+        perror("husb: cannot open devices file");
+        goto the_end;
+    }
+
     device_count = 0;
     bus_num = addr = speed = class_id = product_id = vendor_id = 0;
-    ret = 0;
     for(;;) {
         if (fgets(line, sizeof(line), f) == NULL)
             break;
@@ -1111,7 +1133,191 @@
                    product_id, product_name, speed);
     }
  the_end:
-    fclose(f);
+    if (f)
+        fclose(f);
+    return ret;
+}
+
+/*
+ * Read sys file-system device file
+ *
+ * @line address of buffer to put file contents in
+ * @line_size size of line
+ * @device_file path to device file (printf format string)
+ * @device_name device being opened (inserted into device_file)
+ *
+ * @return 0 failed, 1 succeeded ('line' contains data)
+ */
+static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name)
+{
+    Monitor *mon = cur_mon;
+    FILE *f;
+    int ret = 0;
+    char filename[PATH_MAX];
+
+    snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
+             device_file);
+    f = fopen(filename, "r");
+    if (f) {
+        fgets(line, line_size, f);
+        fclose(f);
+        ret = 1;
+    } else {
+        monitor_printf(mon, "husb: could not open %s\n", filename);
+    }
+
+    return ret;
+}
+
+/*
+ * Use /sys/bus/usb/devices/ directory to determine host's USB
+ * devices.
+ *
+ * This code is based on Robert Schiele's original patches posted to
+ * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
+ */
+static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
+{
+    DIR *dir = 0;
+    char line[1024];
+    int bus_num, addr, speed, class_id, product_id, vendor_id;
+    int ret = 0;
+    char product_name[512];
+    struct dirent *de;
+
+    dir = opendir(USBSYSBUS_PATH "/devices");
+    if (!dir) {
+        perror("husb: cannot open devices directory");
+        goto the_end;
+    }
+
+    while ((de = readdir(dir))) {
+        if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
+            char *tmpstr = de->d_name;
+            if (!strncmp(de->d_name, "usb", 3))
+                tmpstr += 3;
+            bus_num = atoi(tmpstr);
+
+            if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%d", &addr) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
+                                    de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &class_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), "idVendor", de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &vendor_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), "idProduct",
+                                    de->d_name))
+                goto the_end;
+            if (sscanf(line, "%x", &product_id) != 1)
+                goto the_end;
+
+            if (!usb_host_read_file(line, sizeof(line), "product",
+                                    de->d_name)) {
+                *product_name = 0;
+            } else {
+                if (strlen(line) > 0)
+                    line[strlen(line) - 1] = '\0';
+                pstrcpy(product_name, sizeof(product_name), line);
+            }
+
+            if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name))
+                goto the_end;
+            if (!strcmp(line, "480\n"))
+                speed = USB_SPEED_HIGH;
+            else if (!strcmp(line, "1.5\n"))
+                speed = USB_SPEED_LOW;
+            else
+                speed = USB_SPEED_FULL;
+
+            ret = func(opaque, bus_num, addr, class_id, vendor_id,
+                       product_id, product_name, speed);
+            if (ret)
+                goto the_end;
+        }
+    }
+ the_end:
+    if (dir)
+        closedir(dir);
+    return ret;
+}
+
+/*
+ * Determine how to access the host's USB devices and call the
+ * specific support function.
+ */
+static int usb_host_scan(void *opaque, USBScanFunc *func)
+{
+    Monitor *mon = cur_mon;
+    FILE *f = 0;
+    DIR *dir = 0;
+    int ret = 0;
+    const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
+    char devpath[PATH_MAX];
+
+    /* only check the host once */
+    if (!usb_fs_type) {
+        f = fopen(USBPROCBUS_PATH "/devices", "r");
+        if (f) {
+            /* devices found in /proc/bus/usb/ */
+            strcpy(devpath, USBPROCBUS_PATH);
+            usb_fs_type = USB_FS_PROC;
+            fclose(f);
+            dprintf(USBDBG_DEVOPENED, USBPROCBUS_PATH);
+            goto found_devices;
+        }
+        /* try additional methods if an access method hasn't been found yet */
+        f = fopen(USBDEVBUS_PATH "/devices", "r");
+        if (f) {
+            /* devices found in /dev/bus/usb/ */
+            strcpy(devpath, USBDEVBUS_PATH);
+            usb_fs_type = USB_FS_DEV;
+            fclose(f);
+            dprintf(USBDBG_DEVOPENED, USBDEVBUS_PATH);
+            goto found_devices;
+        }
+        dir = opendir(USBSYSBUS_PATH "/devices");
+        if (dir) {
+            /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
+            strcpy(devpath, USBDEVBUS_PATH);
+            usb_fs_type = USB_FS_SYS;
+            closedir(dir);
+            dprintf(USBDBG_DEVOPENED, USBSYSBUS_PATH);
+            goto found_devices;
+        }
+    found_devices:
+        if (!usb_fs_type) {
+            monitor_printf(mon, "husb: unable to access USB devices\n");
+            return -ENOENT;
+        }
+
+        /* the module setting (used later for opening devices) */
+        usb_host_device_path = qemu_mallocz(strlen(devpath)+1);
+        strcpy(usb_host_device_path, devpath);
+        monitor_printf(mon, "husb: using %s file-system with %s\n",
+                       fs_type[usb_fs_type], usb_host_device_path);
+    }
+
+    switch (usb_fs_type) {
+    case USB_FS_PROC:
+    case USB_FS_DEV:
+        ret = usb_host_scan_dev(opaque, func);
+        break;
+    case USB_FS_SYS:
+        ret = usb_host_scan_sys(opaque, func);
+        break;
+    default:
+        ret = -EINVAL;
+        break;
+    }
     return ret;
 }
 
@@ -1237,10 +1443,6 @@
         return -1;
 
     f = qemu_mallocz(sizeof(*f));
-    if (!f) {
-        fprintf(stderr, "husb: failed to allocate auto filter\n");
-        return -1;
-    }
 
     *f = filter; 
 
@@ -1408,6 +1610,7 @@
                             const char *product_name,
                             int speed)
 {
+    Monitor *mon = cur_mon;
     const char *class_str, *speed_str;
 
     switch(speed) {
@@ -1425,17 +1628,17 @@
         break;
     }
 
-    term_printf("  Device %d.%d, speed %s Mb/s\n",
+    monitor_printf(mon, "  Device %d.%d, speed %s Mb/s\n",
                 bus_num, addr, speed_str);
     class_str = usb_class_str(class_id);
     if (class_str)
-        term_printf("    %s:", class_str);
+        monitor_printf(mon, "    %s:", class_str);
     else
-        term_printf("    Class %02x:", class_id);
-    term_printf(" USB device %04x:%04x", vendor_id, product_id);
+        monitor_printf(mon, "    Class %02x:", class_id);
+    monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
     if (product_name[0] != '\0')
-        term_printf(", %s", product_name);
-    term_printf("\n");
+        monitor_printf(mon, ", %s", product_name);
+    monitor_printf(mon, "\n");
 }
 
 static int usb_host_info_device(void *opaque, int bus_num, int addr,
@@ -1449,58 +1652,37 @@
     return 0;
 }
 
-static void dec2str(int val, char *str)
+static void dec2str(int val, char *str, size_t size)
 {
     if (val == -1)
-        strcpy(str, "*");
+        snprintf(str, size, "*");
     else
-        sprintf(str, "%d", val); 
+        snprintf(str, size, "%d", val); 
 }
 
-static void hex2str(int val, char *str)
+static void hex2str(int val, char *str, size_t size)
 {
     if (val == -1)
-        strcpy(str, "*");
+        snprintf(str, size, "*");
     else
-        sprintf(str, "%x", val);
+        snprintf(str, size, "%x", val);
 }
 
-void usb_host_info(void)
+void usb_host_info(Monitor *mon)
 {
     struct USBAutoFilter *f;
 
     usb_host_scan(NULL, usb_host_info_device);
 
     if (usb_auto_filter)
-        term_printf("  Auto filters:\n");
+        monitor_printf(mon, "  Auto filters:\n");
     for (f = usb_auto_filter; f; f = f->next) {
         char bus[10], addr[10], vid[10], pid[10];
-        dec2str(f->bus_num, bus);
-        dec2str(f->addr, addr);
-        hex2str(f->vendor_id, vid);
-        hex2str(f->product_id, pid);
-    	term_printf("    Device %s.%s ID %s:%s\n", bus, addr, vid, pid);
+        dec2str(f->bus_num, bus, sizeof(bus));
+        dec2str(f->addr, addr, sizeof(addr));
+        hex2str(f->vendor_id, vid, sizeof(vid));
+        hex2str(f->product_id, pid, sizeof(pid));
+        monitor_printf(mon, "    Device %s.%s ID %s:%s\n",
+                       bus, addr, vid, pid);
     }
 }
-
-#else
-
-#include "hw/usb.h"
-
-void usb_host_info(void)
-{
-    term_printf("USB host devices not supported\n");
-}
-
-/* XXX: modify configure to compile the right host driver */
-USBDevice *usb_host_device_open(const char *devname)
-{
-    return NULL;
-}
-
-int usb_host_device_close(const char *devname)
-{
-    return 0;
-}
-
-#endif
diff --git a/vl-android.c b/vl-android.c
new file mode 100644
index 0000000..d6feced
--- /dev/null
+++ b/vl-android.c
@@ -0,0 +1,6478 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* the following is needed on Linux to define ptsname() in stdlib.h */
+#if defined(__linux__)
+#define _GNU_SOURCE 1
+#endif
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/usb.h"
+#include "hw/pcmcia.h"
+#include "hw/pc.h"
+#include "hw/audiodev.h"
+#include "hw/isa.h"
+#include "hw/baum.h"
+#include "hw/goldfish_nand.h"
+#include "net.h"
+#include "console.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "block.h"
+#include "audio/audio.h"
+
+#include "qemu_file.h"
+#include "android/android.h"
+#include "charpipe.h"
+#include "shaper.h"
+#include "modem_driver.h"
+#include "android/gps.h"
+#include "android/hw-qemud.h"
+#include "android/hw-kmsg.h"
+#include "tcpdump.h"
+#include "targphys.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <zlib.h>
+
+/* Needed early for HOST_BSD etc. */
+#include "config-host.h"
+
+#ifndef _WIN32
+#include <libgen.h>
+#include <pwd.h>
+#include <sys/times.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#if defined(__NetBSD__)
+#include <net/if_tap.h>
+#endif
+#ifdef __linux__
+#include <linux/if_tun.h>
+#endif
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/select.h>
+#ifdef HOST_BSD
+#include <sys/stat.h>
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <libutil.h>
+#else
+#include <util.h>
+#endif
+#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+#include <freebsd/stdlib.h>
+#else
+#ifdef __linux__
+#include <pty.h>
+#include <malloc.h>
+#include <linux/rtc.h>
+
+/* For the benefit of older linux systems which don't supply it,
+   we use a local copy of hpet.h. */
+/* #include <linux/hpet.h> */
+#include "hpet.h"
+
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+#endif
+#ifdef __sun__
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
+#endif
+#endif
+#endif
+
+#if defined(__OpenBSD__)
+#include <util.h>
+#endif
+
+#if defined(CONFIG_VDE)
+#include <libvdeplug.h>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <malloc.h>
+#include <sys/timeb.h>
+#include <mmsystem.h>
+#define getopt_long_only getopt_long
+#define memalign(align, size) malloc(size)
+#endif
+
+
+#ifdef CONFIG_COCOA
+#undef main
+#define main qemu_main
+#endif /* CONFIG_COCOA */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/usb.h"
+#include "hw/pcmcia.h"
+#include "hw/pc.h"
+#include "hw/audiodev.h"
+#include "hw/isa.h"
+#include "hw/baum.h"
+#include "hw/bt.h"
+#include "hw/watchdog.h"
+#include "hw/smbios.h"
+#include "hw/xen.h"
+#include "bt-host.h"
+#include "net.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "cache-utils.h"
+#include "block.h"
+#include "dma.h"
+#include "audio/audio.h"
+#include "migration.h"
+#include "kvm.h"
+#include "balloon.h"
+
+#ifdef CONFIG_SKINS
+#undef main
+#define main qemu_main
+#endif
+
+#include "disas.h"
+
+#include "exec-all.h"
+
+#ifdef CONFIG_TRACE
+#include "trace.h"
+#include "dcache.h"
+#endif
+
+#include "qemu_socket.h"
+
+#if defined(CONFIG_SLIRP)
+#include "libslirp.h"
+#endif
+
+//#define DEBUG_UNUSED_IOPORT
+//#define DEBUG_IOPORT
+//#define DEBUG_NET
+//#define DEBUG_SLIRP
+
+
+#ifdef DEBUG_IOPORT
+#  define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
+#else
+#  define LOG_IOPORT(...) do { } while (0)
+#endif
+
+#define DEFAULT_RAM_SIZE 128
+
+/* Max number of USB devices that can be specified on the commandline.  */
+#define MAX_USB_CMDLINE 8
+
+/* Max number of bluetooth switches on the commandline.  */
+#define MAX_BT_CMDLINE 10
+
+/* XXX: use a two level table to limit memory usage */
+#define MAX_IOPORTS 65536
+
+static const char *data_dir;
+const char *bios_name = NULL;
+static void *ioport_opaque[MAX_IOPORTS];
+static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
+static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
+/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
+   to store the VM snapshots */
+DriveInfo drives_table[MAX_DRIVES+1];
+int nb_drives;
+enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
+static DisplayState *display_state;
+DisplayType display_type = DT_DEFAULT;
+const char* keyboard_layout = NULL;
+int64_t ticks_per_sec;
+ram_addr_t ram_size;
+int nb_nics;
+NICInfo nd_table[MAX_NICS];
+int vm_running;
+static int autostart;
+static int rtc_utc = 1;
+static int rtc_date_offset = -1; /* -1 means no change */
+int cirrus_vga_enabled = 1;
+int std_vga_enabled = 0;
+int vmsvga_enabled = 0;
+int xenfb_enabled = 0;
+#ifdef TARGET_SPARC
+int graphic_width = 1024;
+int graphic_height = 768;
+int graphic_depth = 8;
+#else
+int graphic_width = 800;
+int graphic_height = 600;
+int graphic_depth = 15;
+#endif
+static int full_screen = 0;
+#ifdef CONFIG_SDL
+static int no_frame = 0;
+#endif
+int no_quit = 0;
+CharDriverState *serial_hds[MAX_SERIAL_PORTS];
+CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
+CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
+#ifdef TARGET_I386
+int win2k_install_hack = 0;
+int rtc_td_hack = 0;
+#endif
+int usb_enabled = 0;
+int singlestep = 0;
+int smp_cpus = 1;
+const char *vnc_display;
+int acpi_enabled = 1;
+int no_hpet = 0;
+int no_virtio_balloon = 0;
+int fd_bootchk = 1;
+int no_reboot = 0;
+int no_shutdown = 0;
+int cursor_hide = 1;
+int graphic_rotate = 0;
+#ifndef _WIN32
+int daemonize = 0;
+#endif
+WatchdogTimerModel *watchdog = NULL;
+int watchdog_action = WDT_RESET;
+const char *option_rom[MAX_OPTION_ROMS];
+int nb_option_roms;
+int semihosting_enabled = 0;
+#ifdef TARGET_ARM
+int old_param = 0;
+#endif
+const char *qemu_name;
+int alt_grab = 0;
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
+unsigned int nb_prom_envs = 0;
+const char *prom_envs[MAX_PROM_ENVS];
+#endif
+int nb_drives_opt;
+struct drive_opt drives_opt[MAX_DRIVES];
+
+int nb_numa_nodes;
+uint64_t node_mem[MAX_NODES];
+uint64_t node_cpumask[MAX_NODES];
+
+static CPUState *cur_cpu;
+static CPUState *next_cpu;
+static int timer_alarm_pending = 1;
+/* Conversion factor from emulated instructions to virtual clock ticks.  */
+static int icount_time_shift;
+/* Arbitrarily pick 1MIPS as the minimum allowable speed.  */
+#define MAX_ICOUNT_SHIFT 10
+/* Compensate for varying guest execution speed.  */
+static int64_t qemu_icount_bias;
+static QEMUTimer *icount_rt_timer;
+static QEMUTimer *icount_vm_timer;
+static QEMUTimer *nographic_timer;
+
+uint8_t qemu_uuid[16];
+
+
+extern int   qemu_cpu_delay;
+extern char* audio_input_source;
+
+extern void  dprint( const char* format, ... );
+
+#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
+
+/***********************************************************/
+/* x86 ISA bus support */
+
+target_phys_addr_t isa_mem_base = 0;
+PicState2 *isa_pic;
+
+static IOPortReadFunc default_ioport_readb, default_ioport_readw, default_ioport_readl;
+static IOPortWriteFunc default_ioport_writeb, default_ioport_writew, default_ioport_writel;
+
+static uint32_t ioport_read(int index, uint32_t address)
+{
+    static IOPortReadFunc *default_func[3] = {
+        default_ioport_readb,
+        default_ioport_readw,
+        default_ioport_readl
+    };
+    IOPortReadFunc *func = ioport_read_table[index][address];
+    if (!func)
+        func = default_func[index];
+    return func(ioport_opaque[address], address);
+}
+
+static void ioport_write(int index, uint32_t address, uint32_t data)
+{
+    static IOPortWriteFunc *default_func[3] = {
+        default_ioport_writeb,
+        default_ioport_writew,
+        default_ioport_writel
+    };
+    IOPortWriteFunc *func = ioport_write_table[index][address];
+    if (!func)
+        func = default_func[index];
+    func(ioport_opaque[address], address, data);
+}
+
+static uint32_t default_ioport_readb(void *opaque, uint32_t address)
+{
+#ifdef DEBUG_UNUSED_IOPORT
+    fprintf(stderr, "unused inb: port=0x%04x\n", address);
+#endif
+    return 0xff;
+}
+
+static void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
+{
+#ifdef DEBUG_UNUSED_IOPORT
+    fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data);
+#endif
+}
+
+/* default is to make two byte accesses */
+static uint32_t default_ioport_readw(void *opaque, uint32_t address)
+{
+    uint32_t data;
+    data = ioport_read(0, address);
+    address = (address + 1) & (MAX_IOPORTS - 1);
+    data |= ioport_read(0, address) << 8;
+    return data;
+}
+
+static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
+{
+    ioport_write(0, address, data & 0xff);
+    address = (address + 1) & (MAX_IOPORTS - 1);
+    ioport_write(0, address, (data >> 8) & 0xff);
+}
+
+static uint32_t default_ioport_readl(void *opaque, uint32_t address)
+{
+#ifdef DEBUG_UNUSED_IOPORT
+    fprintf(stderr, "unused inl: port=0x%04x\n", address);
+#endif
+    return 0xffffffff;
+}
+
+static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
+{
+#ifdef DEBUG_UNUSED_IOPORT
+    fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data);
+#endif
+}
+
+/* size is the word size in byte */
+int register_ioport_read(int start, int length, int size,
+                         IOPortReadFunc *func, void *opaque)
+{
+    int i, bsize;
+
+    if (size == 1) {
+        bsize = 0;
+    } else if (size == 2) {
+        bsize = 1;
+    } else if (size == 4) {
+        bsize = 2;
+    } else {
+        hw_error("register_ioport_read: invalid size");
+        return -1;
+    }
+    for(i = start; i < start + length; i += size) {
+        ioport_read_table[bsize][i] = func;
+        if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
+            hw_error("register_ioport_read: invalid opaque");
+        ioport_opaque[i] = opaque;
+    }
+    return 0;
+}
+
+/* size is the word size in byte */
+int register_ioport_write(int start, int length, int size,
+                          IOPortWriteFunc *func, void *opaque)
+{
+    int i, bsize;
+
+    if (size == 1) {
+        bsize = 0;
+    } else if (size == 2) {
+        bsize = 1;
+    } else if (size == 4) {
+        bsize = 2;
+    } else {
+        hw_error("register_ioport_write: invalid size");
+        return -1;
+    }
+    for(i = start; i < start + length; i += size) {
+        ioport_write_table[bsize][i] = func;
+        if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
+            hw_error("register_ioport_write: invalid opaque");
+        ioport_opaque[i] = opaque;
+    }
+    return 0;
+}
+
+void isa_unassign_ioport(int start, int length)
+{
+    int i;
+
+    for(i = start; i < start + length; i++) {
+        ioport_read_table[0][i] = default_ioport_readb;
+        ioport_read_table[1][i] = default_ioport_readw;
+        ioport_read_table[2][i] = default_ioport_readl;
+
+        ioport_write_table[0][i] = default_ioport_writeb;
+        ioport_write_table[1][i] = default_ioport_writew;
+        ioport_write_table[2][i] = default_ioport_writel;
+
+        ioport_opaque[i] = NULL;
+    }
+}
+
+/***********************************************************/
+
+void cpu_outb(CPUState *env, int addr, int val)
+{
+    LOG_IOPORT("outb: %04x %02x\n", addr, val);
+    ioport_write(0, addr, val);
+#ifdef CONFIG_KQEMU
+    if (env)
+        env->last_io_time = cpu_get_time_fast();
+#endif
+}
+
+void cpu_outw(CPUState *env, int addr, int val)
+{
+    LOG_IOPORT("outw: %04x %04x\n", addr, val);
+    ioport_write(1, addr, val);
+#ifdef CONFIG_KQEMU
+    if (env)
+        env->last_io_time = cpu_get_time_fast();
+#endif
+}
+
+void cpu_outl(CPUState *env, int addr, int val)
+{
+    LOG_IOPORT("outl: %04x %08x\n", addr, val);
+    ioport_write(2, addr, val);
+#ifdef CONFIG_KQEMU
+    if (env)
+        env->last_io_time = cpu_get_time_fast();
+#endif
+}
+
+int cpu_inb(CPUState *env, int addr)
+{
+    int val;
+    val = ioport_read(0, addr);
+    LOG_IOPORT("inb : %04x %02x\n", addr, val);
+#ifdef CONFIG_KQEMU
+    if (env)
+        env->last_io_time = cpu_get_time_fast();
+#endif
+    return val;
+}
+
+int cpu_inw(CPUState *env, int addr)
+{
+    int val;
+    val = ioport_read(1, addr);
+    LOG_IOPORT("inw : %04x %04x\n", addr, val);
+#ifdef CONFIG_KQEMU
+    if (env)
+        env->last_io_time = cpu_get_time_fast();
+#endif
+    return val;
+}
+
+int cpu_inl(CPUState *env, int addr)
+{
+    int val;
+    val = ioport_read(2, addr);
+    LOG_IOPORT("inl : %04x %08x\n", addr, val);
+#ifdef CONFIG_KQEMU
+    if (env)
+        env->last_io_time = cpu_get_time_fast();
+#endif
+    return val;
+}
+
+/***********************************************************/
+void hw_error(const char *fmt, ...)
+{
+    va_list ap;
+    CPUState *env;
+
+    va_start(ap, fmt);
+    fprintf(stderr, "qemu: hardware error: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        fprintf(stderr, "CPU #%d:\n", env->cpu_index);
+#ifdef TARGET_I386
+        cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
+#else
+        cpu_dump_state(env, stderr, fprintf, 0);
+#endif
+    }
+    va_end(ap);
+    abort();
+}
+ 
+/***************/
+/* ballooning */
+
+static QEMUBalloonEvent *qemu_balloon_event;
+void *qemu_balloon_event_opaque;
+
+void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
+{
+    qemu_balloon_event = func;
+    qemu_balloon_event_opaque = opaque;
+}
+
+void qemu_balloon(ram_addr_t target)
+{
+    if (qemu_balloon_event)
+        qemu_balloon_event(qemu_balloon_event_opaque, target);
+}
+
+ram_addr_t qemu_balloon_status(void)
+{
+    if (qemu_balloon_event)
+        return qemu_balloon_event(qemu_balloon_event_opaque, 0);
+    return 0;
+}
+
+/***********************************************************/
+/* keyboard/mouse */
+
+static QEMUPutKBDEvent*  qemu_put_kbd_event;
+static void*             qemu_put_kbd_event_opaque;
+
+static QEMUPutKBDEventN*  qemu_put_kbd_event_n;
+static void*              qemu_put_kbd_event_n_opaque;
+
+
+static QEMUPutGenericEvent*  qemu_put_generic_event;
+static void*                 qemu_put_generic_event_opaque;
+
+static QEMUPutMouseEntry *qemu_put_mouse_event_head;
+static QEMUPutMouseEntry *qemu_put_mouse_event_current;
+
+void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
+{
+    qemu_put_kbd_event_opaque = opaque;
+    qemu_put_kbd_event = func;
+}
+
+void qemu_add_kbd_event_n_handler(QEMUPutKBDEventN *func, void *opaque)
+{
+    qemu_put_kbd_event_n_opaque = opaque;
+    qemu_put_kbd_event_n = func;
+}
+
+#if 0
+void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute)
+{
+    qemu_put_mouse_event_opaque = opaque;
+    qemu_put_mouse_event = func;
+    qemu_put_mouse_event_absolute = absolute;
+}
+#else
+QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
+                                                void *opaque, int absolute,
+                                                const char *name)
+{
+    QEMUPutMouseEntry *s, *cursor;
+
+    s = qemu_mallocz(sizeof(QEMUPutMouseEntry));
+    if (!s)
+        return NULL;
+
+    s->qemu_put_mouse_event = func;
+    s->qemu_put_mouse_event_opaque = opaque;
+    s->qemu_put_mouse_event_absolute = absolute;
+    s->qemu_put_mouse_event_name = qemu_strdup(name);
+    s->next = NULL;
+
+    if (!qemu_put_mouse_event_head) {
+        qemu_put_mouse_event_head = qemu_put_mouse_event_current = s;
+        return s;
+    }
+
+    cursor = qemu_put_mouse_event_head;
+    while (cursor->next != NULL)
+        cursor = cursor->next;
+
+    cursor->next = s;
+    qemu_put_mouse_event_current = s;
+
+    return s;
+}
+
+void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
+{
+    QEMUPutMouseEntry *prev = NULL, *cursor;
+
+    if (!qemu_put_mouse_event_head || entry == NULL)
+        return;
+
+    cursor = qemu_put_mouse_event_head;
+    while (cursor != NULL && cursor != entry) {
+        prev = cursor;
+        cursor = cursor->next;
+    }
+
+    if (cursor == NULL) // does not exist or list empty
+        return;
+    else if (prev == NULL) { // entry is head
+        qemu_put_mouse_event_head = cursor->next;
+        if (qemu_put_mouse_event_current == entry)
+            qemu_put_mouse_event_current = cursor->next;
+        qemu_free(entry->qemu_put_mouse_event_name);
+        qemu_free(entry);
+        return;
+    }
+
+    prev->next = entry->next;
+
+    if (qemu_put_mouse_event_current == entry)
+        qemu_put_mouse_event_current = prev;
+
+    qemu_free(entry->qemu_put_mouse_event_name);
+    qemu_free(entry);
+}
+#endif
+
+void qemu_add_generic_event_handler(QEMUPutGenericEvent *func, void*  opaque)
+{
+    qemu_put_generic_event = func;
+    qemu_put_generic_event_opaque = opaque;
+}
+
+void kbd_put_keycode(int keycode)
+{
+    if (qemu_put_kbd_event) {
+        qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);
+    }
+}
+
+void kbd_put_keycodes(int*  keycodes, int  count)
+{
+    if (qemu_put_kbd_event_n)
+    {
+        qemu_put_kbd_event_n(qemu_put_kbd_event_n_opaque, keycodes, count);
+    }
+    else if (qemu_put_kbd_event)
+    {
+        int  nn;
+
+        for (nn = 0; nn < count; nn++)
+            qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycodes[nn]);
+    }
+}
+
+
+void  kbd_generic_event(int  type, int code, int  value)
+{
+    if (qemu_put_generic_event)
+        qemu_put_generic_event(qemu_put_generic_event_opaque, type, code, value);
+}
+
+
+void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
+{
+    QEMUPutMouseEvent *mouse_event;
+    void *mouse_event_opaque;
+    int width;
+
+    if (!qemu_put_mouse_event_current) {
+        return;
+    }
+
+    mouse_event =
+        qemu_put_mouse_event_current->qemu_put_mouse_event;
+    mouse_event_opaque =
+        qemu_put_mouse_event_current->qemu_put_mouse_event_opaque;
+
+    if (mouse_event) {
+        if (graphic_rotate) {
+            if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute)
+                width = 0x7fff;
+            else
+                width = graphic_width - 1;
+            mouse_event(mouse_event_opaque,
+                                 width - dy, dx, dz, buttons_state);
+        } else
+            mouse_event(mouse_event_opaque,
+                                 dx, dy, dz, buttons_state);
+    }
+}
+
+int kbd_mouse_is_absolute(void)
+{
+    if (!qemu_put_mouse_event_current)
+        return 0;
+
+    return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute;
+}
+
+void do_info_mice(Monitor *mon)
+{
+    QEMUPutMouseEntry *cursor;
+    int index = 0;
+
+    if (!qemu_put_mouse_event_head) {
+        monitor_printf(mon, "No mouse devices connected\n");
+        return;
+    }
+
+    monitor_printf(mon, "Mouse devices available:\n");
+    cursor = qemu_put_mouse_event_head;
+    while (cursor != NULL) {
+        monitor_printf(mon, "%c Mouse #%d: %s\n",
+                       (cursor == qemu_put_mouse_event_current ? '*' : ' '),
+                       index, cursor->qemu_put_mouse_event_name);
+        index++;
+        cursor = cursor->next;
+    }
+}
+
+void do_mouse_set(Monitor *mon, int index)
+{
+    QEMUPutMouseEntry *cursor;
+    int i = 0;
+
+    if (!qemu_put_mouse_event_head) {
+        monitor_printf(mon, "No mouse devices connected\n");
+        return;
+    }
+
+    cursor = qemu_put_mouse_event_head;
+    while (cursor != NULL && index != i) {
+        i++;
+        cursor = cursor->next;
+    }
+
+    if (cursor != NULL)
+        qemu_put_mouse_event_current = cursor;
+    else
+        monitor_printf(mon, "Mouse at given index not found\n");
+}
+
+/* compute with 96 bit intermediate result: (a*b)/c */
+uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+    union {
+        uint64_t ll;
+        struct {
+#ifdef WORDS_BIGENDIAN
+            uint32_t high, low;
+#else
+            uint32_t low, high;
+#endif
+        } l;
+    } u, res;
+    uint64_t rl, rh;
+
+    u.ll = a;
+    rl = (uint64_t)u.l.low * (uint64_t)b;
+    rh = (uint64_t)u.l.high * (uint64_t)b;
+    rh += (rl >> 32);
+    res.l.high = rh / c;
+    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+    return res.ll;
+}
+
+/***********************************************************/
+/* real time host monotonic timer */
+
+#define QEMU_TIMER_BASE 1000000000LL
+
+#ifdef WIN32
+
+static int64_t clock_freq;
+
+static void init_get_clock(void)
+{
+    LARGE_INTEGER freq;
+    int ret;
+    ret = QueryPerformanceFrequency(&freq);
+    if (ret == 0) {
+        fprintf(stderr, "Could not calibrate ticks\n");
+        exit(1);
+    }
+    clock_freq = freq.QuadPart;
+}
+
+static int64_t get_clock(void)
+{
+    LARGE_INTEGER ti;
+    QueryPerformanceCounter(&ti);
+    return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq);
+}
+
+#else
+
+static int use_rt_clock;
+
+static void init_get_clock(void)
+{
+    use_rt_clock = 0;
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
+    || defined(__DragonFly__)
+    {
+        struct timespec ts;
+        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+            use_rt_clock = 1;
+        }
+    }
+#endif
+}
+
+static int64_t get_clock(void)
+{
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
+	|| defined(__DragonFly__)
+    if (use_rt_clock) {
+        struct timespec ts;
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+    } else
+#endif
+    {
+        /* XXX: using gettimeofday leads to problems if the date
+           changes, so it should be avoided. */
+        struct timeval tv;
+        gettimeofday(&tv, NULL);
+        return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
+    }
+}
+#endif
+
+/* Return the virtual CPU time, based on the instruction counter.  */
+static int64_t cpu_get_icount(void)
+{
+    int64_t icount;
+    CPUState *env = cpu_single_env;;
+    icount = qemu_icount;
+    if (env) {
+        if (!can_do_io(env))
+            fprintf(stderr, "Bad clock read\n");
+        icount -= (env->icount_decr.u16.low + env->icount_extra);
+    }
+    return qemu_icount_bias + (icount << icount_time_shift);
+}
+
+/***********************************************************/
+/* guest cycle counter */
+
+static int64_t cpu_ticks_prev;
+static int64_t cpu_ticks_offset;
+static int64_t cpu_clock_offset;
+static int cpu_ticks_enabled;
+
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
+{
+    if (use_icount) {
+        return cpu_get_icount();
+    }
+    if (!cpu_ticks_enabled) {
+        return cpu_ticks_offset;
+    } else {
+        int64_t ticks;
+        ticks = cpu_get_real_ticks();
+        if (cpu_ticks_prev > ticks) {
+            /* Note: non increasing ticks may happen if the host uses
+               software suspend */
+            cpu_ticks_offset += cpu_ticks_prev - ticks;
+        }
+        cpu_ticks_prev = ticks;
+        return ticks + cpu_ticks_offset;
+    }
+}
+
+/* return the host CPU monotonic timer and handle stop/restart */
+static int64_t cpu_get_clock(void)
+{
+    int64_t ti;
+    if (!cpu_ticks_enabled) {
+        return cpu_clock_offset;
+    } else {
+        ti = get_clock();
+        return ti + cpu_clock_offset;
+    }
+}
+
+/* enable cpu_get_ticks() */
+void cpu_enable_ticks(void)
+{
+    if (!cpu_ticks_enabled) {
+        cpu_ticks_offset -= cpu_get_real_ticks();
+        cpu_clock_offset -= get_clock();
+        cpu_ticks_enabled = 1;
+    }
+}
+
+/* disable cpu_get_ticks() : the clock is stopped. You must not call
+   cpu_get_ticks() after that.  */
+void cpu_disable_ticks(void)
+{
+    if (cpu_ticks_enabled) {
+        cpu_ticks_offset = cpu_get_ticks();
+        cpu_clock_offset = cpu_get_clock();
+        cpu_ticks_enabled = 0;
+    }
+}
+
+/***********************************************************/
+/* timers */
+
+#define QEMU_TIMER_REALTIME 0
+#define QEMU_TIMER_VIRTUAL  1
+
+struct QEMUClock {
+    int type;
+    /* XXX: add frequency */
+};
+
+struct QEMUTimer {
+    QEMUClock *clock;
+    int64_t expire_time;
+    QEMUTimerCB *cb;
+    void *opaque;
+    struct QEMUTimer *next;
+};
+
+struct qemu_alarm_timer {
+    char const *name;
+    unsigned int flags;
+
+    int (*start)(struct qemu_alarm_timer *t);
+    void (*stop)(struct qemu_alarm_timer *t);
+    void (*rearm)(struct qemu_alarm_timer *t);
+    void *priv;
+};
+
+#define ALARM_FLAG_DYNTICKS  0x1
+#define ALARM_FLAG_EXPIRED   0x2
+
+static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
+{
+    return t && (t->flags & ALARM_FLAG_DYNTICKS);
+}
+
+static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
+{
+    if (!alarm_has_dynticks(t))
+        return;
+
+    t->rearm(t);
+}
+
+/* TODO: MIN_TIMER_REARM_US should be optimized */
+#define MIN_TIMER_REARM_US 250
+
+static struct qemu_alarm_timer *alarm_timer;
+
+#ifdef _WIN32
+
+struct qemu_alarm_win32 {
+    MMRESULT timerId;
+    unsigned int period;
+} alarm_win32_data = {0, -1};
+
+static int win32_start_timer(struct qemu_alarm_timer *t);
+static void win32_stop_timer(struct qemu_alarm_timer *t);
+static void win32_rearm_timer(struct qemu_alarm_timer *t);
+
+#else
+
+static int unix_start_timer(struct qemu_alarm_timer *t);
+static void unix_stop_timer(struct qemu_alarm_timer *t);
+
+#ifdef __linux__
+
+static int dynticks_start_timer(struct qemu_alarm_timer *t);
+static void dynticks_stop_timer(struct qemu_alarm_timer *t);
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
+
+static int hpet_start_timer(struct qemu_alarm_timer *t);
+static void hpet_stop_timer(struct qemu_alarm_timer *t);
+
+static int rtc_start_timer(struct qemu_alarm_timer *t);
+static void rtc_stop_timer(struct qemu_alarm_timer *t);
+
+#endif /* __linux__ */
+
+#endif /* _WIN32 */
+
+/* Correlation between real and virtual time is always going to be
+   fairly approximate, so ignore small variation.
+   When the guest is idle real and virtual time will be aligned in
+   the IO wait loop.  */
+#define ICOUNT_WOBBLE (QEMU_TIMER_BASE / 10)
+
+static void icount_adjust(void)
+{
+    int64_t cur_time;
+    int64_t cur_icount;
+    int64_t delta;
+    static int64_t last_delta;
+    /* If the VM is not running, then do nothing.  */
+    if (!vm_running)
+        return;
+
+    cur_time = cpu_get_clock();
+    cur_icount = qemu_get_clock(vm_clock);
+    delta = cur_icount - cur_time;
+    /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */
+    if (delta > 0
+        && last_delta + ICOUNT_WOBBLE < delta * 2
+        && icount_time_shift > 0) {
+        /* The guest is getting too far ahead.  Slow time down.  */
+        icount_time_shift--;
+    }
+    if (delta < 0
+        && last_delta - ICOUNT_WOBBLE > delta * 2
+        && icount_time_shift < MAX_ICOUNT_SHIFT) {
+        /* The guest is getting too far behind.  Speed time up.  */
+        icount_time_shift++;
+    }
+    last_delta = delta;
+    qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
+}
+
+static void icount_adjust_rt(void * opaque)
+{
+    qemu_mod_timer(icount_rt_timer,
+                   qemu_get_clock(rt_clock) + 1000);
+    icount_adjust();
+}
+
+static void icount_adjust_vm(void * opaque)
+{
+    qemu_mod_timer(icount_vm_timer,
+                   qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
+    icount_adjust();
+}
+
+static void init_icount_adjust(void)
+{
+    /* Have both realtime and virtual time triggers for speed adjustment.
+       The realtime trigger catches emulated time passing too slowly,
+       the virtual time trigger catches emulated time passing too fast.
+       Realtime triggers occur even when idle, so use them less frequently
+       than VM triggers.  */
+    icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL);
+    qemu_mod_timer(icount_rt_timer,
+                   qemu_get_clock(rt_clock) + 1000);
+    icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL);
+    qemu_mod_timer(icount_vm_timer,
+                   qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
+}
+
+static struct qemu_alarm_timer alarm_timers[] = {
+#ifndef _WIN32
+#ifdef __linux__
+    {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer,
+     dynticks_stop_timer, dynticks_rearm_timer, NULL},
+    /* HPET - if available - is preferred */
+    {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL},
+    /* ...otherwise try RTC */
+    {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL},
+#endif
+    {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL},
+#else
+    {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer,
+     win32_stop_timer, win32_rearm_timer, &alarm_win32_data},
+    {"win32", 0, win32_start_timer,
+     win32_stop_timer, NULL, &alarm_win32_data},
+#endif
+    {NULL, 0, NULL, NULL, NULL, NULL}
+};
+
+static void show_available_alarms(void)
+{
+    int i;
+
+    printf("Available alarm timers, in order of precedence:\n");
+    for (i = 0; alarm_timers[i].name; i++)
+        printf("%s\n", alarm_timers[i].name);
+}
+
+static void configure_alarms(char const *opt)
+{
+    int i;
+    int cur = 0;
+    int count = ARRAY_SIZE(alarm_timers) - 1;
+    char *arg;
+    char *name;
+    struct qemu_alarm_timer tmp;
+
+    if (!strcmp(opt, "?")) {
+        show_available_alarms();
+        exit(0);
+    }
+
+    arg = strdup(opt);
+
+    /* Reorder the array */
+    name = strtok(arg, ",");
+    while (name) {
+        for (i = 0; i < count && alarm_timers[i].name; i++) {
+            if (!strcmp(alarm_timers[i].name, name))
+                break;
+        }
+
+        if (i == count) {
+            fprintf(stderr, "Unknown clock %s\n", name);
+            goto next;
+        }
+
+        if (i < cur)
+            /* Ignore */
+            goto next;
+
+	/* Swap */
+        tmp = alarm_timers[i];
+        alarm_timers[i] = alarm_timers[cur];
+        alarm_timers[cur] = tmp;
+
+        cur++;
+next:
+        name = strtok(NULL, ",");
+    }
+
+    free(arg);
+
+    if (cur) {
+        /* Disable remaining timers */
+        for (i = cur; i < count; i++)
+            alarm_timers[i].name = NULL;
+    } else {
+        show_available_alarms();
+        exit(1);
+    }
+}
+
+QEMUClock *rt_clock;
+QEMUClock *vm_clock;
+
+static QEMUTimer *active_timers[2];
+
+static QEMUClock *qemu_new_clock(int type)
+{
+    QEMUClock *clock;
+    clock = qemu_mallocz(sizeof(QEMUClock));
+    clock->type = type;
+    return clock;
+}
+
+QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque)
+{
+    QEMUTimer *ts;
+
+    ts = qemu_mallocz(sizeof(QEMUTimer));
+    ts->clock = clock;
+    ts->cb = cb;
+    ts->opaque = opaque;
+    return ts;
+}
+
+void qemu_free_timer(QEMUTimer *ts)
+{
+    qemu_free(ts);
+}
+
+/* stop a timer, but do not dealloc it */
+void qemu_del_timer(QEMUTimer *ts)
+{
+    QEMUTimer **pt, *t;
+
+    /* NOTE: this code must be signal safe because
+       qemu_timer_expired() can be called from a signal. */
+    pt = &active_timers[ts->clock->type];
+    for(;;) {
+        t = *pt;
+        if (!t)
+            break;
+        if (t == ts) {
+            *pt = t->next;
+            break;
+        }
+        pt = &t->next;
+    }
+}
+
+/* modify the current timer so that it will be fired when current_time
+   >= expire_time. The corresponding callback will be called. */
+void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
+{
+    QEMUTimer **pt, *t;
+
+    qemu_del_timer(ts);
+
+    /* add the timer in the sorted list */
+    /* NOTE: this code must be signal safe because
+       qemu_timer_expired() can be called from a signal. */
+    pt = &active_timers[ts->clock->type];
+    for(;;) {
+        t = *pt;
+        if (!t)
+            break;
+        if (t->expire_time > expire_time)
+            break;
+        pt = &t->next;
+    }
+    ts->expire_time = expire_time;
+    ts->next = *pt;
+    *pt = ts;
+
+    /* Rearm if necessary  */
+    if (pt == &active_timers[ts->clock->type]) {
+        if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0) {
+            qemu_rearm_alarm_timer(alarm_timer);
+        }
+        /* Interrupt execution to force deadline recalculation.  */
+        if (use_icount)
+            qemu_notify_event();
+    }
+}
+
+int qemu_timer_pending(QEMUTimer *ts)
+{
+    QEMUTimer *t;
+    for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
+        if (t == ts)
+            return 1;
+    }
+    return 0;
+}
+
+static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
+{
+    if (!timer_head)
+        return 0;
+    return (timer_head->expire_time <= current_time);
+}
+
+static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time)
+{
+    QEMUTimer *ts;
+
+    for(;;) {
+        ts = *ptimer_head;
+        if (!ts || ts->expire_time > current_time)
+            break;
+        /* remove timer from the list before calling the callback */
+        *ptimer_head = ts->next;
+        ts->next = NULL;
+
+        /* run the callback (the timer list can be modified) */
+        ts->cb(ts->opaque);
+    }
+}
+
+int64_t qemu_get_clock(QEMUClock *clock)
+{
+    switch(clock->type) {
+    case QEMU_TIMER_REALTIME:
+        return get_clock() / 1000000;
+    default:
+    case QEMU_TIMER_VIRTUAL:
+        if (use_icount) {
+            return cpu_get_icount();
+        } else {
+            return cpu_get_clock();
+        }
+    }
+}
+
+static void init_timers(void)
+{
+    init_get_clock();
+    ticks_per_sec = QEMU_TIMER_BASE;
+    rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
+    vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
+}
+
+/* save a timer */
+void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+{
+    uint64_t expire_time;
+
+    if (qemu_timer_pending(ts)) {
+        expire_time = ts->expire_time;
+    } else {
+        expire_time = -1;
+    }
+    qemu_put_be64(f, expire_time);
+}
+
+void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
+{
+    uint64_t expire_time;
+
+    expire_time = qemu_get_be64(f);
+    if (expire_time != -1) {
+        qemu_mod_timer(ts, expire_time);
+    } else {
+        qemu_del_timer(ts);
+    }
+}
+
+static void timer_save(QEMUFile *f, void *opaque)
+{
+    if (cpu_ticks_enabled) {
+        hw_error("cannot save state if virtual timers are running");
+    }
+    qemu_put_be64(f, cpu_ticks_offset);
+    qemu_put_be64(f, ticks_per_sec);
+    qemu_put_be64(f, cpu_clock_offset);
+}
+
+static int timer_load(QEMUFile *f, void *opaque, int version_id)
+{
+    if (version_id != 1 && version_id != 2)
+        return -EINVAL;
+    if (cpu_ticks_enabled) {
+        return -EINVAL;
+    }
+    cpu_ticks_offset=qemu_get_be64(f);
+    ticks_per_sec=qemu_get_be64(f);
+    if (version_id == 2) {
+        cpu_clock_offset=qemu_get_be64(f);
+    }
+    return 0;
+}
+
+static void qemu_event_increment(void);
+
+#ifdef _WIN32
+static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
+                                        DWORD_PTR dwUser, DWORD_PTR dw1,
+                                        DWORD_PTR dw2)
+#else
+static void host_alarm_handler(int host_signum)
+#endif
+{
+#if 0
+#define DISP_FREQ 1000
+    {
+        static int64_t delta_min = INT64_MAX;
+        static int64_t delta_max, delta_cum, last_clock, delta, ti;
+        static int count;
+        ti = qemu_get_clock(vm_clock);
+        if (last_clock != 0) {
+            delta = ti - last_clock;
+            if (delta < delta_min)
+                delta_min = delta;
+            if (delta > delta_max)
+                delta_max = delta;
+            delta_cum += delta;
+            if (++count == DISP_FREQ) {
+                printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
+                       muldiv64(delta_min, 1000000, ticks_per_sec),
+                       muldiv64(delta_max, 1000000, ticks_per_sec),
+                       muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec),
+                       (double)ticks_per_sec / ((double)delta_cum / DISP_FREQ));
+                count = 0;
+                delta_min = INT64_MAX;
+                delta_max = 0;
+                delta_cum = 0;
+            }
+        }
+        last_clock = ti;
+    }
+#endif
+    if (alarm_has_dynticks(alarm_timer) ||
+        (!use_icount &&
+            qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
+                               qemu_get_clock(vm_clock))) ||
+        qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
+                           qemu_get_clock(rt_clock))) {
+        qemu_event_increment();
+        if (alarm_timer) alarm_timer->flags |= ALARM_FLAG_EXPIRED;
+
+#ifndef CONFIG_IOTHREAD
+        if (next_cpu) {
+            /* stop the currently executing cpu because a timer occured */
+            cpu_exit(next_cpu);
+#ifdef CONFIG_KQEMU
+            if (next_cpu->kqemu_enabled) {
+                kqemu_cpu_interrupt(next_cpu);
+            }
+#endif
+        }
+#endif
+        timer_alarm_pending = 1;
+        qemu_notify_event();
+    }
+}
+
+static int64_t qemu_next_deadline(void)
+{
+    int64_t delta;
+
+    if (active_timers[QEMU_TIMER_VIRTUAL]) {
+        delta = active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
+                     qemu_get_clock(vm_clock);
+    } else {
+        /* To avoid problems with overflow limit this to 2^32.  */
+        delta = INT32_MAX;
+    }
+
+    if (delta < 0)
+        delta = 0;
+
+    return delta;
+}
+
+#if defined(__linux__) || defined(_WIN32)
+static uint64_t qemu_next_deadline_dyntick(void)
+{
+    int64_t delta;
+    int64_t rtdelta;
+
+    if (use_icount)
+        delta = INT32_MAX;
+    else
+        delta = (qemu_next_deadline() + 999) / 1000;
+
+    if (active_timers[QEMU_TIMER_REALTIME]) {
+        rtdelta = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
+                 qemu_get_clock(rt_clock))*1000;
+        if (rtdelta < delta)
+            delta = rtdelta;
+    }
+
+    if (delta < MIN_TIMER_REARM_US)
+        delta = MIN_TIMER_REARM_US;
+
+    return delta;
+}
+#endif
+
+#ifndef _WIN32
+
+/* Sets a specific flag */
+static int fcntl_setfl(int fd, int flag)
+{
+    int flags;
+
+    flags = fcntl(fd, F_GETFL);
+    if (flags == -1)
+        return -errno;
+
+    if (fcntl(fd, F_SETFL, flags | flag) == -1)
+        return -errno;
+
+    return 0;
+}
+
+#if defined(__linux__)
+
+#define RTC_FREQ 1024
+
+static void enable_sigio_timer(int fd)
+{
+    struct sigaction act;
+
+    /* timer signal */
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+    act.sa_handler = host_alarm_handler;
+
+    sigaction(SIGIO, &act, NULL);
+    fcntl_setfl(fd, O_ASYNC);
+    fcntl(fd, F_SETOWN, getpid());
+}
+
+static int hpet_start_timer(struct qemu_alarm_timer *t)
+{
+    struct hpet_info info;
+    int r, fd;
+
+    fd = open("/dev/hpet", O_RDONLY);
+    if (fd < 0)
+        return -1;
+
+    /* Set frequency */
+    r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
+    if (r < 0) {
+        fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
+                "error, but for better emulation accuracy type:\n"
+                "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
+        goto fail;
+    }
+
+    /* Check capabilities */
+    r = ioctl(fd, HPET_INFO, &info);
+    if (r < 0)
+        goto fail;
+
+    /* Enable periodic mode */
+    r = ioctl(fd, HPET_EPI, 0);
+    if (info.hi_flags && (r < 0))
+        goto fail;
+
+    /* Enable interrupt */
+    r = ioctl(fd, HPET_IE_ON, 0);
+    if (r < 0)
+        goto fail;
+
+    enable_sigio_timer(fd);
+    t->priv = (void *)(long)fd;
+
+    return 0;
+fail:
+    close(fd);
+    return -1;
+}
+
+static void hpet_stop_timer(struct qemu_alarm_timer *t)
+{
+    int fd = (long)t->priv;
+
+    close(fd);
+}
+
+static int rtc_start_timer(struct qemu_alarm_timer *t)
+{
+    int rtc_fd;
+    unsigned long current_rtc_freq = 0;
+
+    TFR(rtc_fd = open("/dev/rtc", O_RDONLY));
+    if (rtc_fd < 0)
+        return -1;
+    ioctl(rtc_fd, RTC_IRQP_READ, &current_rtc_freq);
+    if (current_rtc_freq != RTC_FREQ &&
+        ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
+        fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
+                "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
+                "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
+        goto fail;
+    }
+    if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
+    fail:
+        close(rtc_fd);
+        return -1;
+    }
+
+    enable_sigio_timer(rtc_fd);
+
+    t->priv = (void *)(long)rtc_fd;
+
+    return 0;
+}
+
+static void rtc_stop_timer(struct qemu_alarm_timer *t)
+{
+    int rtc_fd = (long)t->priv;
+
+    close(rtc_fd);
+}
+
+static int dynticks_start_timer(struct qemu_alarm_timer *t)
+{
+    struct sigevent ev;
+    timer_t host_timer;
+    struct sigaction act;
+
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+    act.sa_handler = host_alarm_handler;
+
+    sigaction(SIGALRM, &act, NULL);
+
+    /* 
+     * Initialize ev struct to 0 to avoid valgrind complaining
+     * about uninitialized data in timer_create call
+     */
+    memset(&ev, 0, sizeof(ev));
+    ev.sigev_value.sival_int = 0;
+    ev.sigev_notify = SIGEV_SIGNAL;
+    ev.sigev_signo = SIGALRM;
+
+    if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
+        perror("timer_create");
+
+        /* disable dynticks */
+        fprintf(stderr, "Dynamic Ticks disabled\n");
+
+        return -1;
+    }
+
+    t->priv = (void *)(long)host_timer;
+
+    return 0;
+}
+
+static void dynticks_stop_timer(struct qemu_alarm_timer *t)
+{
+    timer_t host_timer = (timer_t)(long)t->priv;
+
+    timer_delete(host_timer);
+}
+
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
+{
+    timer_t host_timer = (timer_t)(long)t->priv;
+    struct itimerspec timeout;
+    int64_t nearest_delta_us = INT64_MAX;
+    int64_t current_us;
+
+    if (!active_timers[QEMU_TIMER_REALTIME] &&
+                !active_timers[QEMU_TIMER_VIRTUAL])
+        return;
+
+    nearest_delta_us = qemu_next_deadline_dyntick();
+
+    /* check whether a timer is already running */
+    if (timer_gettime(host_timer, &timeout)) {
+        perror("gettime");
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
+    current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
+    if (current_us && current_us <= nearest_delta_us)
+        return;
+
+    timeout.it_interval.tv_sec = 0;
+    timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
+    timeout.it_value.tv_sec =  nearest_delta_us / 1000000;
+    timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000;
+    if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
+        perror("settime");
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
+}
+
+#endif /* defined(__linux__) */
+
+static int unix_start_timer(struct qemu_alarm_timer *t)
+{
+    struct sigaction act;
+    struct itimerval itv;
+    int err;
+
+    /* timer signal */
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+    act.sa_handler = host_alarm_handler;
+
+    sigaction(SIGALRM, &act, NULL);
+
+    itv.it_interval.tv_sec = 0;
+    /* for i386 kernel 2.6 to get 1 ms */
+    itv.it_interval.tv_usec = 999;
+    itv.it_value.tv_sec = 0;
+    itv.it_value.tv_usec = 10 * 1000;
+
+    err = setitimer(ITIMER_REAL, &itv, NULL);
+    if (err)
+        return -1;
+
+    return 0;
+}
+
+static void unix_stop_timer(struct qemu_alarm_timer *t)
+{
+    struct itimerval itv;
+
+    memset(&itv, 0, sizeof(itv));
+    setitimer(ITIMER_REAL, &itv, NULL);
+}
+
+#endif /* !defined(_WIN32) */
+
+
+#ifdef _WIN32
+
+static int win32_start_timer(struct qemu_alarm_timer *t)
+{
+    TIMECAPS tc;
+    struct qemu_alarm_win32 *data = t->priv;
+    UINT flags;
+
+    memset(&tc, 0, sizeof(tc));
+    timeGetDevCaps(&tc, sizeof(tc));
+
+    if (data->period < tc.wPeriodMin)
+        data->period = tc.wPeriodMin;
+
+    timeBeginPeriod(data->period);
+
+    flags = TIME_CALLBACK_FUNCTION;
+    if (alarm_has_dynticks(t))
+        flags |= TIME_ONESHOT;
+    else
+        flags |= TIME_PERIODIC;
+
+    data->timerId = timeSetEvent(1,         // interval (ms)
+                        data->period,       // resolution
+                        host_alarm_handler, // function
+                        (DWORD)t,           // parameter
+                        flags);
+
+    if (!data->timerId) {
+        perror("Failed to initialize win32 alarm timer");
+        timeEndPeriod(data->period);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void win32_stop_timer(struct qemu_alarm_timer *t)
+{
+    struct qemu_alarm_win32 *data = t->priv;
+
+    timeKillEvent(data->timerId);
+    timeEndPeriod(data->period);
+}
+
+static void win32_rearm_timer(struct qemu_alarm_timer *t)
+{
+    struct qemu_alarm_win32 *data = t->priv;
+    uint64_t nearest_delta_us;
+
+    if (!active_timers[QEMU_TIMER_REALTIME] &&
+                !active_timers[QEMU_TIMER_VIRTUAL])
+        return;
+
+    nearest_delta_us = qemu_next_deadline_dyntick();
+    nearest_delta_us /= 1000;
+
+    timeKillEvent(data->timerId);
+
+    data->timerId = timeSetEvent(1,
+                        data->period,
+                        host_alarm_handler,
+                        (DWORD)t,
+                        TIME_ONESHOT | TIME_PERIODIC);
+
+    if (!data->timerId) {
+        perror("Failed to re-arm win32 alarm timer");
+
+        timeEndPeriod(data->period);
+        exit(1);
+    }
+}
+
+#endif /* _WIN32 */
+
+static int init_timer_alarm(void)
+{
+    struct qemu_alarm_timer *t = NULL;
+    int i, err = -1;
+
+    for (i = 0; alarm_timers[i].name; i++) {
+        t = &alarm_timers[i];
+
+        err = t->start(t);
+        if (!err)
+            break;
+    }
+
+    if (err) {
+        err = -ENOENT;
+        goto fail;
+    }
+
+    alarm_timer = t;
+
+    return 0;
+
+fail:
+    return err;
+}
+
+static void quit_timers(void)
+{
+    alarm_timer->stop(alarm_timer);
+    alarm_timer = NULL;
+}
+
+/***********************************************************/
+/* host time/date access */
+void qemu_get_timedate(struct tm *tm, int offset)
+{
+    time_t ti;
+    struct tm *ret;
+
+    time(&ti);
+    ti += offset;
+    if (rtc_date_offset == -1) {
+        if (rtc_utc)
+            ret = gmtime(&ti);
+        else
+            ret = localtime(&ti);
+    } else {
+        ti -= rtc_date_offset;
+        ret = gmtime(&ti);
+    }
+
+    memcpy(tm, ret, sizeof(struct tm));
+}
+
+int qemu_timedate_diff(struct tm *tm)
+{
+    time_t seconds;
+
+    if (rtc_date_offset == -1)
+        if (rtc_utc)
+            seconds = mktimegm(tm);
+        else
+            seconds = mktime(tm);
+    else
+        seconds = mktimegm(tm) + rtc_date_offset;
+
+    return seconds - time(NULL);
+}
+
+
+#ifdef CONFIG_TRACE
+static int tbflush_requested;
+static int exit_requested;
+
+void start_tracing()
+{
+  if (trace_filename == NULL)
+    return;
+  if (!tracing) {
+    fprintf(stderr,"-- start tracing --\n");
+    start_time = Now();
+  }
+  tracing = 1;
+  tbflush_requested = 1;
+  qemu_notify_event();
+}
+
+void stop_tracing()
+{
+  if (trace_filename == NULL)
+    return;
+  if (tracing) {
+    end_time = Now();
+    elapsed_usecs += end_time - start_time;
+    fprintf(stderr,"-- stop tracing --\n");
+  }
+  tracing = 0;
+  tbflush_requested = 1;
+  qemu_notify_event();
+}
+
+#ifndef _WIN32
+/* This is the handler for the SIGUSR1 and SIGUSR2 signals.
+ * SIGUSR1 turns tracing on.  SIGUSR2 turns tracing off.
+ */
+void sigusr_handler(int sig)
+{
+  if (sig == SIGUSR1)
+    start_tracing();
+  else
+    stop_tracing();
+}
+#endif
+
+/* This is the handler to catch control-C so that we can exit cleanly.
+ * This is needed when tracing to flush the buffers to disk.
+ */
+void sigint_handler(int sig)
+{
+  exit_requested = 1;
+  qemu_notify_event();
+}
+#endif /* CONFIG_TRACE */
+
+
+int get_param_value(char *buf, int buf_size,
+                    const char *tag, const char *str)
+{
+    const char *p;
+    char option[128];
+
+    p = str;
+    for(;;) {
+        p = get_opt_name(option, sizeof(option), p, '=');
+        if (*p != '=')
+            break;
+        p++;
+        if (!strcmp(tag, option)) {
+            (void)get_opt_value(buf, buf_size, p);
+            return strlen(buf);
+        } else {
+            p = get_opt_value(NULL, 0, p);
+        }
+        if (*p != ',')
+            break;
+        p++;
+    }
+    return 0;
+}
+
+int check_params(char *buf, int buf_size,
+                 const char * const *params, const char *str)
+{
+    const char *p;
+    int i;
+
+    p = str;
+    while (*p != '\0') {
+        p = get_opt_name(buf, buf_size, p, '=');
+        if (*p != '=') {
+            return -1;
+        }
+        p++;
+        for (i = 0; params[i] != NULL; i++) {
+            if (!strcmp(params[i], buf)) {
+                break;
+            }
+        }
+        if (params[i] == NULL) {
+            return -1;
+        }
+        p = get_opt_value(NULL, 0, p);
+        if (*p != ',') {
+            break;
+        }
+        p++;
+    }
+    return 0;
+}
+
+/***********************************************************/
+/* Bluetooth support */
+static int nb_hcis;
+static int cur_hci;
+static struct HCIInfo *hci_table[MAX_NICS];
+
+static struct bt_vlan_s {
+    struct bt_scatternet_s net;
+    int id;
+    struct bt_vlan_s *next;
+} *first_bt_vlan;
+
+/* find or alloc a new bluetooth "VLAN" */
+static struct bt_scatternet_s *qemu_find_bt_vlan(int id)
+{
+    struct bt_vlan_s **pvlan, *vlan;
+    for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->id == id)
+            return &vlan->net;
+    }
+    vlan = qemu_mallocz(sizeof(struct bt_vlan_s));
+    vlan->id = id;
+    pvlan = &first_bt_vlan;
+    while (*pvlan != NULL)
+        pvlan = &(*pvlan)->next;
+    *pvlan = vlan;
+    return &vlan->net;
+}
+
+static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
+{
+}
+
+static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
+{
+    return -ENOTSUP;
+}
+
+static struct HCIInfo null_hci = {
+    .cmd_send = null_hci_send,
+    .sco_send = null_hci_send,
+    .acl_send = null_hci_send,
+    .bdaddr_set = null_hci_addr_set,
+};
+
+struct HCIInfo *qemu_next_hci(void)
+{
+    if (cur_hci == nb_hcis)
+        return &null_hci;
+
+    return hci_table[cur_hci++];
+}
+
+static struct HCIInfo *hci_init(const char *str)
+{
+    char *endp;
+    struct bt_scatternet_s *vlan = 0;
+
+    if (!strcmp(str, "null"))
+        /* null */
+        return &null_hci;
+    else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':'))
+        /* host[:hciN] */
+        return bt_host_hci(str[4] ? str + 5 : "hci0");
+    else if (!strncmp(str, "hci", 3)) {
+        /* hci[,vlan=n] */
+        if (str[3]) {
+            if (!strncmp(str + 3, ",vlan=", 6)) {
+                vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0));
+                if (*endp)
+                    vlan = 0;
+            }
+        } else
+            vlan = qemu_find_bt_vlan(0);
+        if (vlan)
+           return bt_new_hci(vlan);
+    }
+
+    fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str);
+
+    return 0;
+}
+
+static int bt_hci_parse(const char *str)
+{
+    struct HCIInfo *hci;
+    bdaddr_t bdaddr;
+
+    if (nb_hcis >= MAX_NICS) {
+        fprintf(stderr, "qemu: Too many bluetooth HCIs (max %i).\n", MAX_NICS);
+        return -1;
+    }
+
+    hci = hci_init(str);
+    if (!hci)
+        return -1;
+
+    bdaddr.b[0] = 0x52;
+    bdaddr.b[1] = 0x54;
+    bdaddr.b[2] = 0x00;
+    bdaddr.b[3] = 0x12;
+    bdaddr.b[4] = 0x34;
+    bdaddr.b[5] = 0x56 + nb_hcis;
+    hci->bdaddr_set(hci, bdaddr.b);
+
+    hci_table[nb_hcis++] = hci;
+
+    return 0;
+}
+
+static void bt_vhci_add(int vlan_id)
+{
+    struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id);
+
+    if (!vlan->slave)
+        fprintf(stderr, "qemu: warning: adding a VHCI to "
+                        "an empty scatternet %i\n", vlan_id);
+
+    bt_vhci_init(bt_new_hci(vlan));
+}
+
+static struct bt_device_s *bt_device_add(const char *opt)
+{
+    struct bt_scatternet_s *vlan;
+    int vlan_id = 0;
+    char *endp = strstr(opt, ",vlan=");
+    int len = (endp ? endp - opt : strlen(opt)) + 1;
+    char devname[10];
+
+    pstrcpy(devname, MIN(sizeof(devname), len), opt);
+
+    if (endp) {
+        vlan_id = strtol(endp + 6, &endp, 0);
+        if (*endp) {
+            fprintf(stderr, "qemu: unrecognised bluetooth vlan Id\n");
+            return 0;
+        }
+    }
+
+    vlan = qemu_find_bt_vlan(vlan_id);
+
+    if (!vlan->slave)
+        fprintf(stderr, "qemu: warning: adding a slave device to "
+                        "an empty scatternet %i\n", vlan_id);
+
+    if (!strcmp(devname, "keyboard"))
+        return bt_keyboard_init(vlan);
+
+    fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname);
+    return 0;
+}
+
+static int bt_parse(const char *opt)
+{
+    const char *endp, *p;
+    int vlan;
+
+    if (strstart(opt, "hci", &endp)) {
+        if (!*endp || *endp == ',') {
+            if (*endp)
+                if (!strstart(endp, ",vlan=", 0))
+                    opt = endp + 1;
+
+            return bt_hci_parse(opt);
+       }
+    } else if (strstart(opt, "vhci", &endp)) {
+        if (!*endp || *endp == ',') {
+            if (*endp) {
+                if (strstart(endp, ",vlan=", &p)) {
+                    vlan = strtol(p, (char **) &endp, 0);
+                    if (*endp) {
+                        fprintf(stderr, "qemu: bad scatternet '%s'\n", p);
+                        return 1;
+                    }
+                } else {
+                    fprintf(stderr, "qemu: bad parameter '%s'\n", endp + 1);
+                    return 1;
+                }
+            } else
+                vlan = 0;
+
+            bt_vhci_add(vlan);
+            return 0;
+        }
+    } else if (strstart(opt, "device:", &endp))
+        return !bt_device_add(endp);
+
+    fprintf(stderr, "qemu: bad bluetooth parameter '%s'\n", opt);
+    return 1;
+}
+
+/***********************************************************/
+/* QEMU Block devices */
+
+#define HD_ALIAS "index=%d,media=disk"
+#define CDROM_ALIAS "index=2,media=cdrom"
+#define FD_ALIAS "index=%d,if=floppy"
+#define PFLASH_ALIAS "if=pflash"
+#define MTD_ALIAS "if=mtd"
+#define SD_ALIAS "index=0,if=sd"
+
+static int drive_opt_get_free_idx(void)
+{
+    int index;
+
+    for (index = 0; index < MAX_DRIVES; index++)
+        if (!drives_opt[index].used) {
+            drives_opt[index].used = 1;
+            return index;
+        }
+
+    return -1;
+}
+
+static int drive_get_free_idx(void)
+{
+    int index;
+
+    for (index = 0; index < MAX_DRIVES; index++)
+        if (!drives_table[index].used) {
+            drives_table[index].used = 1;
+            return index;
+        }
+
+    return -1;
+}
+
+int drive_add(const char *file, const char *fmt, ...)
+{
+    va_list ap;
+    int index = drive_opt_get_free_idx();
+
+    if (nb_drives_opt >= MAX_DRIVES || index == -1) {
+        fprintf(stderr, "qemu: too many drives\n");
+        return -1;
+    }
+
+    drives_opt[index].file = file;
+    va_start(ap, fmt);
+    vsnprintf(drives_opt[index].opt,
+              sizeof(drives_opt[0].opt), fmt, ap);
+    va_end(ap);
+
+    nb_drives_opt++;
+    return index;
+}
+
+void drive_remove(int index)
+{
+    drives_opt[index].used = 0;
+    nb_drives_opt--;
+}
+
+int drive_get_index(BlockInterfaceType type, int bus, int unit)
+{
+    int index;
+
+    /* seek interface, bus and unit */
+
+    for (index = 0; index < MAX_DRIVES; index++)
+        if (drives_table[index].type == type &&
+	    drives_table[index].bus == bus &&
+	    drives_table[index].unit == unit &&
+	    drives_table[index].used)
+        return index;
+
+    return -1;
+}
+
+int drive_get_max_bus(BlockInterfaceType type)
+{
+    int max_bus;
+    int index;
+
+    max_bus = -1;
+    for (index = 0; index < nb_drives; index++) {
+        if(drives_table[index].type == type &&
+           drives_table[index].bus > max_bus)
+            max_bus = drives_table[index].bus;
+    }
+    return max_bus;
+}
+
+const char *drive_get_serial(BlockDriverState *bdrv)
+{
+    int index;
+
+    for (index = 0; index < nb_drives; index++)
+        if (drives_table[index].bdrv == bdrv)
+            return drives_table[index].serial;
+
+    return "\0";
+}
+
+BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv)
+{
+    int index;
+
+    for (index = 0; index < nb_drives; index++)
+        if (drives_table[index].bdrv == bdrv)
+            return drives_table[index].onerror;
+
+    return BLOCK_ERR_STOP_ENOSPC;
+}
+
+static void bdrv_format_print(void *opaque, const char *name)
+{
+    fprintf(stderr, " %s", name);
+}
+
+void drive_uninit(BlockDriverState *bdrv)
+{
+    int i;
+
+    for (i = 0; i < MAX_DRIVES; i++)
+        if (drives_table[i].bdrv == bdrv) {
+            drives_table[i].bdrv = NULL;
+            drives_table[i].used = 0;
+            drive_remove(drives_table[i].drive_opt_idx);
+            nb_drives--;
+            break;
+        }
+}
+
+int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
+{
+    char buf[128];
+    char file[1024];
+    char devname[128];
+    char serial[21];
+    const char *mediastr = "";
+    BlockInterfaceType type;
+    enum { MEDIA_DISK, MEDIA_CDROM } media;
+    int bus_id, unit_id;
+    int cyls, heads, secs, translation;
+    BlockDriverState *bdrv;
+    BlockDriver *drv = NULL;
+    QEMUMachine *machine = opaque;
+    int max_devs;
+    int index;
+    int cache;
+    int bdrv_flags, onerror;
+    int drives_table_idx;
+    char *str = arg->opt;
+    static const char * const params[] = { "bus", "unit", "if", "index",
+                                           "cyls", "heads", "secs", "trans",
+                                           "media", "snapshot", "file",
+                                           "cache", "format", "serial", "werror",
+                                           NULL };
+
+    if (check_params(buf, sizeof(buf), params, str) < 0) {
+         fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
+                         buf, str);
+         return -1;
+    }
+
+    file[0] = 0;
+    cyls = heads = secs = 0;
+    bus_id = 0;
+    unit_id = -1;
+    translation = BIOS_ATA_TRANSLATION_AUTO;
+    index = -1;
+    cache = 3;
+
+    if (machine->use_scsi) {
+        type = IF_SCSI;
+        max_devs = MAX_SCSI_DEVS;
+        pstrcpy(devname, sizeof(devname), "scsi");
+    } else {
+        type = IF_IDE;
+        max_devs = MAX_IDE_DEVS;
+        pstrcpy(devname, sizeof(devname), "ide");
+    }
+    media = MEDIA_DISK;
+
+    /* extract parameters */
+
+    if (get_param_value(buf, sizeof(buf), "bus", str)) {
+        bus_id = strtol(buf, NULL, 0);
+	if (bus_id < 0) {
+	    fprintf(stderr, "qemu: '%s' invalid bus id\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "unit", str)) {
+        unit_id = strtol(buf, NULL, 0);
+	if (unit_id < 0) {
+	    fprintf(stderr, "qemu: '%s' invalid unit id\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "if", str)) {
+        pstrcpy(devname, sizeof(devname), buf);
+        if (!strcmp(buf, "ide")) {
+	    type = IF_IDE;
+            max_devs = MAX_IDE_DEVS;
+        } else if (!strcmp(buf, "scsi")) {
+	    type = IF_SCSI;
+            max_devs = MAX_SCSI_DEVS;
+        } else if (!strcmp(buf, "floppy")) {
+	    type = IF_FLOPPY;
+            max_devs = 0;
+        } else if (!strcmp(buf, "pflash")) {
+	    type = IF_PFLASH;
+            max_devs = 0;
+	} else if (!strcmp(buf, "mtd")) {
+	    type = IF_MTD;
+            max_devs = 0;
+	} else if (!strcmp(buf, "sd")) {
+	    type = IF_SD;
+            max_devs = 0;
+        } else if (!strcmp(buf, "virtio")) {
+            type = IF_VIRTIO;
+            max_devs = 0;
+	} else if (!strcmp(buf, "xen")) {
+	    type = IF_XEN;
+            max_devs = 0;
+	} else {
+            fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
+            return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "index", str)) {
+        index = strtol(buf, NULL, 0);
+	if (index < 0) {
+	    fprintf(stderr, "qemu: '%s' invalid index\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "cyls", str)) {
+        cyls = strtol(buf, NULL, 0);
+    }
+
+    if (get_param_value(buf, sizeof(buf), "heads", str)) {
+        heads = strtol(buf, NULL, 0);
+    }
+
+    if (get_param_value(buf, sizeof(buf), "secs", str)) {
+        secs = strtol(buf, NULL, 0);
+    }
+
+    if (cyls || heads || secs) {
+        if (cyls < 1 || cyls > 16383) {
+            fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str);
+	    return -1;
+	}
+        if (heads < 1 || heads > 16) {
+            fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str);
+	    return -1;
+	}
+        if (secs < 1 || secs > 63) {
+            fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "trans", str)) {
+        if (!cyls) {
+            fprintf(stderr,
+                    "qemu: '%s' trans must be used with cyls,heads and secs\n",
+                    str);
+            return -1;
+        }
+        if (!strcmp(buf, "none"))
+            translation = BIOS_ATA_TRANSLATION_NONE;
+        else if (!strcmp(buf, "lba"))
+            translation = BIOS_ATA_TRANSLATION_LBA;
+        else if (!strcmp(buf, "auto"))
+            translation = BIOS_ATA_TRANSLATION_AUTO;
+	else {
+            fprintf(stderr, "qemu: '%s' invalid translation type\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "media", str)) {
+        if (!strcmp(buf, "disk")) {
+	    media = MEDIA_DISK;
+	} else if (!strcmp(buf, "cdrom")) {
+            if (cyls || secs || heads) {
+                fprintf(stderr,
+                        "qemu: '%s' invalid physical CHS format\n", str);
+	        return -1;
+            }
+	    media = MEDIA_CDROM;
+	} else {
+	    fprintf(stderr, "qemu: '%s' invalid media\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "snapshot", str)) {
+        if (!strcmp(buf, "on"))
+	    snapshot = 1;
+        else if (!strcmp(buf, "off"))
+	    snapshot = 0;
+	else {
+	    fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "cache", str)) {
+        if (!strcmp(buf, "off") || !strcmp(buf, "none"))
+            cache = 0;
+        else if (!strcmp(buf, "writethrough"))
+            cache = 1;
+        else if (!strcmp(buf, "writeback"))
+            cache = 2;
+        else {
+           fprintf(stderr, "qemu: invalid cache option\n");
+           return -1;
+        }
+    }
+
+    if (get_param_value(buf, sizeof(buf), "format", str)) {
+       if (strcmp(buf, "?") == 0) {
+            fprintf(stderr, "qemu: Supported formats:");
+            bdrv_iterate_format(bdrv_format_print, NULL);
+            fprintf(stderr, "\n");
+	    return -1;
+        }
+        drv = bdrv_find_format(buf);
+        if (!drv) {
+            fprintf(stderr, "qemu: '%s' invalid format\n", buf);
+            return -1;
+        }
+    }
+
+    if (arg->file == NULL)
+        get_param_value(file, sizeof(file), "file", str);
+    else
+        pstrcpy(file, sizeof(file), arg->file);
+
+    if (!get_param_value(serial, sizeof(serial), "serial", str))
+	    memset(serial, 0,  sizeof(serial));
+
+    onerror = BLOCK_ERR_STOP_ENOSPC;
+    if (get_param_value(buf, sizeof(serial), "werror", str)) {
+        if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO) {
+            fprintf(stderr, "werror is no supported by this format\n");
+            return -1;
+        }
+        if (!strcmp(buf, "ignore"))
+            onerror = BLOCK_ERR_IGNORE;
+        else if (!strcmp(buf, "enospc"))
+            onerror = BLOCK_ERR_STOP_ENOSPC;
+        else if (!strcmp(buf, "stop"))
+            onerror = BLOCK_ERR_STOP_ANY;
+        else if (!strcmp(buf, "report"))
+            onerror = BLOCK_ERR_REPORT;
+        else {
+            fprintf(stderr, "qemu: '%s' invalid write error action\n", buf);
+            return -1;
+        }
+    }
+
+    /* compute bus and unit according index */
+
+    if (index != -1) {
+        if (bus_id != 0 || unit_id != -1) {
+            fprintf(stderr,
+                    "qemu: '%s' index cannot be used with bus and unit\n", str);
+            return -1;
+        }
+        if (max_devs == 0)
+        {
+            unit_id = index;
+            bus_id = 0;
+        } else {
+            unit_id = index % max_devs;
+            bus_id = index / max_devs;
+        }
+    }
+
+    /* if user doesn't specify a unit_id,
+     * try to find the first free
+     */
+
+    if (unit_id == -1) {
+       unit_id = 0;
+       while (drive_get_index(type, bus_id, unit_id) != -1) {
+           unit_id++;
+           if (max_devs && unit_id >= max_devs) {
+               unit_id -= max_devs;
+               bus_id++;
+           }
+       }
+    }
+
+    /* check unit id */
+
+    if (max_devs && unit_id >= max_devs) {
+        fprintf(stderr, "qemu: '%s' unit %d too big (max is %d)\n",
+                        str, unit_id, max_devs - 1);
+        return -1;
+    }
+
+    /*
+     * ignore multiple definitions
+     */
+
+    if (drive_get_index(type, bus_id, unit_id) != -1)
+        return -2;
+
+    /* init */
+
+    if (type == IF_IDE || type == IF_SCSI)
+        mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
+    if (max_devs)
+        snprintf(buf, sizeof(buf), "%s%i%s%i",
+                 devname, bus_id, mediastr, unit_id);
+    else
+        snprintf(buf, sizeof(buf), "%s%s%i",
+                 devname, mediastr, unit_id);
+    bdrv = bdrv_new(buf);
+    drives_table_idx = drive_get_free_idx();
+    drives_table[drives_table_idx].bdrv = bdrv;
+    drives_table[drives_table_idx].type = type;
+    drives_table[drives_table_idx].bus = bus_id;
+    drives_table[drives_table_idx].unit = unit_id;
+    drives_table[drives_table_idx].onerror = onerror;
+    drives_table[drives_table_idx].drive_opt_idx = arg - drives_opt;
+    strncpy(drives_table[drives_table_idx].serial, serial, sizeof(serial));
+    nb_drives++;
+
+    switch(type) {
+    case IF_IDE:
+    case IF_SCSI:
+    case IF_XEN:
+        switch(media) {
+	case MEDIA_DISK:
+            if (cyls != 0) {
+                bdrv_set_geometry_hint(bdrv, cyls, heads, secs);
+                bdrv_set_translation_hint(bdrv, translation);
+            }
+	    break;
+	case MEDIA_CDROM:
+            bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
+	    break;
+	}
+        break;
+    case IF_SD:
+        /* FIXME: This isn't really a floppy, but it's a reasonable
+           approximation.  */
+    case IF_FLOPPY:
+        bdrv_set_type_hint(bdrv, BDRV_TYPE_FLOPPY);
+        break;
+    case IF_PFLASH:
+    case IF_MTD:
+    case IF_VIRTIO:
+        break;
+    case IF_COUNT:
+        abort();
+    }
+    if (!file[0])
+        return -2;
+    bdrv_flags = 0;
+    if (snapshot) {
+        bdrv_flags |= BDRV_O_SNAPSHOT;
+        cache = 2; /* always use write-back with snapshot */
+    }
+    if (cache == 0) /* no caching */
+        bdrv_flags |= BDRV_O_NOCACHE;
+    else if (cache == 2) /* write-back */
+        bdrv_flags |= BDRV_O_CACHE_WB;
+    else if (cache == 3) /* not specified */
+        bdrv_flags |= BDRV_O_CACHE_DEF;
+    if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0) {
+        fprintf(stderr, "qemu: could not open disk image %s\n",
+                        file);
+        return -1;
+    }
+    if (bdrv_key_required(bdrv))
+        autostart = 0;
+    return drives_table_idx;
+}
+
+static void numa_add(const char *optarg)
+{
+    char option[128];
+    char *endptr;
+    unsigned long long value, endvalue;
+    int nodenr;
+
+    optarg = get_opt_name(option, 128, optarg, ',') + 1;
+    if (!strcmp(option, "node")) {
+        if (get_param_value(option, 128, "nodeid", optarg) == 0) {
+            nodenr = nb_numa_nodes;
+        } else {
+            nodenr = strtoull(option, NULL, 10);
+        }
+
+        if (get_param_value(option, 128, "mem", optarg) == 0) {
+            node_mem[nodenr] = 0;
+        } else {
+            value = strtoull(option, &endptr, 0);
+            switch (*endptr) {
+            case 0: case 'M': case 'm':
+                value <<= 20;
+                break;
+            case 'G': case 'g':
+                value <<= 30;
+                break;
+            }
+            node_mem[nodenr] = value;
+        }
+        if (get_param_value(option, 128, "cpus", optarg) == 0) {
+            node_cpumask[nodenr] = 0;
+        } else {
+            value = strtoull(option, &endptr, 10);
+            if (value >= 64) {
+                value = 63;
+                fprintf(stderr, "only 64 CPUs in NUMA mode supported.\n");
+            } else {
+                if (*endptr == '-') {
+                    endvalue = strtoull(endptr+1, &endptr, 10);
+                    if (endvalue >= 63) {
+                        endvalue = 62;
+                        fprintf(stderr,
+                            "only 63 CPUs in NUMA mode supported.\n");
+                    }
+                    value = (1 << (endvalue + 1)) - (1 << value);
+                } else {
+                    value = 1 << value;
+                }
+            }
+            node_cpumask[nodenr] = value;
+        }
+        nb_numa_nodes++;
+    }
+    return;
+}
+
+/***********************************************************/
+/* USB devices */
+
+static USBPort *used_usb_ports;
+static USBPort *free_usb_ports;
+
+/* ??? Maybe change this to register a hub to keep track of the topology.  */
+void qemu_register_usb_port(USBPort *port, void *opaque, int index,
+                            usb_attachfn attach)
+{
+    port->opaque = opaque;
+    port->index = index;
+    port->attach = attach;
+    port->next = free_usb_ports;
+    free_usb_ports = port;
+}
+
+int usb_device_add_dev(USBDevice *dev)
+{
+    USBPort *port;
+
+    /* Find a USB port to add the device to.  */
+    port = free_usb_ports;
+    if (!port->next) {
+        USBDevice *hub;
+
+        /* Create a new hub and chain it on.  */
+        free_usb_ports = NULL;
+        port->next = used_usb_ports;
+        used_usb_ports = port;
+
+        hub = usb_hub_init(VM_USB_HUB_SIZE);
+        usb_attach(port, hub);
+        port = free_usb_ports;
+    }
+
+    free_usb_ports = port->next;
+    port->next = used_usb_ports;
+    used_usb_ports = port;
+    usb_attach(port, dev);
+    return 0;
+}
+
+static void usb_msd_password_cb(void *opaque, int err)
+{
+    USBDevice *dev = opaque;
+
+    if (!err)
+        usb_device_add_dev(dev);
+    else
+        dev->handle_destroy(dev);
+}
+
+static int usb_device_add(const char *devname, int is_hotplug)
+{
+    const char *p;
+    USBDevice *dev;
+
+    if (!free_usb_ports)
+        return -1;
+
+    if (strstart(devname, "host:", &p)) {
+        dev = usb_host_device_open(p);
+    } else if (!strcmp(devname, "mouse")) {
+        dev = usb_mouse_init();
+    } else if (!strcmp(devname, "tablet")) {
+        dev = usb_tablet_init();
+    } else if (!strcmp(devname, "keyboard")) {
+        dev = usb_keyboard_init();
+    } else if (strstart(devname, "disk:", &p)) {
+#if 0
+        BlockDriverState *bs;
+#endif
+        dev = usb_msd_init(p);
+        if (!dev)
+            return -1;
+#if 0
+        bs = usb_msd_get_bdrv(dev);
+        if (bdrv_key_required(bs)) {
+            autostart = 0;
+            if (is_hotplug) {
+                monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb,
+                                            dev);
+                return 0;
+            }
+        }
+    } else if (!strcmp(devname, "wacom-tablet")) {
+        dev = usb_wacom_init();
+    } else if (strstart(devname, "serial:", &p)) {
+        dev = usb_serial_init(p);
+#ifdef CONFIG_BRLAPI
+    } else if (!strcmp(devname, "braille")) {
+        dev = usb_baum_init();
+#endif
+    } else if (strstart(devname, "net:", &p)) {
+        int nic = nb_nics;
+
+        if (net_client_init("nic", p) < 0)
+            return -1;
+        nd_table[nic].model = "usb";
+        dev = usb_net_init(&nd_table[nic]);
+    } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
+        dev = usb_bt_init(devname[2] ? hci_init(p) :
+                        bt_new_hci(qemu_find_bt_vlan(0)));
+#endif
+    } else {
+        return -1;
+    }
+    if (!dev)
+        return -1;
+
+    return usb_device_add_dev(dev);
+}
+
+int usb_device_del_addr(int bus_num, int addr)
+{
+    USBPort *port;
+    USBPort **lastp;
+    USBDevice *dev;
+
+    if (!used_usb_ports)
+        return -1;
+
+    if (bus_num != 0)
+        return -1;
+
+    lastp = &used_usb_ports;
+    port = used_usb_ports;
+    while (port && port->dev->addr != addr) {
+        lastp = &port->next;
+        port = port->next;
+    }
+
+    if (!port)
+        return -1;
+
+    dev = port->dev;
+    *lastp = port->next;
+    usb_attach(port, NULL);
+    dev->handle_destroy(dev);
+    port->next = free_usb_ports;
+    free_usb_ports = port;
+    return 0;
+}
+
+static int usb_device_del(const char *devname)
+{
+    int bus_num, addr;
+    const char *p;
+
+    if (strstart(devname, "host:", &p))
+        return usb_host_device_close(p);
+
+    if (!used_usb_ports)
+        return -1;
+
+    p = strchr(devname, '.');
+    if (!p)
+        return -1;
+    bus_num = strtoul(devname, NULL, 0);
+    addr = strtoul(p + 1, NULL, 0);
+
+    return usb_device_del_addr(bus_num, addr);
+}
+
+void do_usb_add(Monitor *mon, const char *devname)
+{
+    usb_device_add(devname, 1);
+}
+
+void do_usb_del(Monitor *mon, const char *devname)
+{
+    usb_device_del(devname);
+}
+
+void usb_info(Monitor *mon)
+{
+    USBDevice *dev;
+    USBPort *port;
+    const char *speed_str;
+
+    if (!usb_enabled) {
+        monitor_printf(mon, "USB support not enabled\n");
+        return;
+    }
+
+    for (port = used_usb_ports; port; port = port->next) {
+        dev = port->dev;
+        if (!dev)
+            continue;
+        switch(dev->speed) {
+        case USB_SPEED_LOW:
+            speed_str = "1.5";
+            break;
+        case USB_SPEED_FULL:
+            speed_str = "12";
+            break;
+        case USB_SPEED_HIGH:
+            speed_str = "480";
+            break;
+        default:
+            speed_str = "?";
+            break;
+        }
+        monitor_printf(mon, "  Device %d.%d, Speed %s Mb/s, Product %s\n",
+                       0, dev->addr, speed_str, dev->devname);
+    }
+}
+
+/***********************************************************/
+/* PCMCIA/Cardbus */
+
+static struct pcmcia_socket_entry_s {
+    PCMCIASocket *socket;
+    struct pcmcia_socket_entry_s *next;
+} *pcmcia_sockets = 0;
+
+void pcmcia_socket_register(PCMCIASocket *socket)
+{
+    struct pcmcia_socket_entry_s *entry;
+
+    entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s));
+    entry->socket = socket;
+    entry->next = pcmcia_sockets;
+    pcmcia_sockets = entry;
+}
+
+void pcmcia_socket_unregister(PCMCIASocket *socket)
+{
+    struct pcmcia_socket_entry_s *entry, **ptr;
+
+    ptr = &pcmcia_sockets;
+    for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr)
+        if (entry->socket == socket) {
+            *ptr = entry->next;
+            qemu_free(entry);
+        }
+}
+
+void pcmcia_info(Monitor *mon)
+{
+    struct pcmcia_socket_entry_s *iter;
+
+    if (!pcmcia_sockets)
+        monitor_printf(mon, "No PCMCIA sockets\n");
+
+    for (iter = pcmcia_sockets; iter; iter = iter->next)
+        monitor_printf(mon, "%s: %s\n", iter->socket->slot_string,
+                       iter->socket->attached ? iter->socket->card_string :
+                       "Empty");
+}
+
+/***********************************************************/
+/* register display */
+
+struct DisplayAllocator default_allocator = {
+    defaultallocator_create_displaysurface,
+    defaultallocator_resize_displaysurface,
+    defaultallocator_free_displaysurface
+};
+
+void register_displaystate(DisplayState *ds)
+{
+    DisplayState **s;
+    s = &display_state;
+    while (*s != NULL)
+        s = &(*s)->next;
+    ds->next = NULL;
+    *s = ds;
+}
+
+DisplayState *get_displaystate(void)
+{
+    return display_state;
+}
+
+DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
+{
+    if(ds->allocator ==  &default_allocator) ds->allocator = da;
+    return ds->allocator;
+}
+
+/* dumb display */
+
+static void dumb_display_init(void)
+{
+    DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
+    ds->allocator = &default_allocator;
+    ds->surface = qemu_create_displaysurface(ds, 640, 480);
+    register_displaystate(ds);
+}
+
+/***********************************************************/
+/* I/O handling */
+
+typedef struct IOHandlerRecord {
+    int fd;
+    IOCanRWHandler *fd_read_poll;
+    IOHandler *fd_read;
+    IOHandler *fd_write;
+    int deleted;
+    void *opaque;
+    /* temporary data */
+    struct pollfd *ufd;
+    struct IOHandlerRecord *next;
+} IOHandlerRecord;
+
+static IOHandlerRecord *first_io_handler;
+
+/* XXX: fd_read_poll should be suppressed, but an API change is
+   necessary in the character devices to suppress fd_can_read(). */
+int qemu_set_fd_handler2(int fd,
+                         IOCanRWHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
+                         void *opaque)
+{
+    IOHandlerRecord **pioh, *ioh;
+
+    if (!fd_read && !fd_write) {
+        pioh = &first_io_handler;
+        for(;;) {
+            ioh = *pioh;
+            if (ioh == NULL)
+                break;
+            if (ioh->fd == fd) {
+                ioh->deleted = 1;
+                break;
+            }
+            pioh = &ioh->next;
+        }
+    } else {
+        for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
+            if (ioh->fd == fd)
+                goto found;
+        }
+        ioh = qemu_mallocz(sizeof(IOHandlerRecord));
+        ioh->next = first_io_handler;
+        first_io_handler = ioh;
+    found:
+        ioh->fd = fd;
+        ioh->fd_read_poll = fd_read_poll;
+        ioh->fd_read = fd_read;
+        ioh->fd_write = fd_write;
+        ioh->opaque = opaque;
+        ioh->deleted = 0;
+    }
+    return 0;
+}
+
+int qemu_set_fd_handler(int fd,
+                        IOHandler *fd_read,
+                        IOHandler *fd_write,
+                        void *opaque)
+{
+    return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
+}
+
+#ifdef _WIN32
+/***********************************************************/
+/* Polling handling */
+
+typedef struct PollingEntry {
+    PollingFunc *func;
+    void *opaque;
+    struct PollingEntry *next;
+} PollingEntry;
+
+static PollingEntry *first_polling_entry;
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    pe = qemu_mallocz(sizeof(PollingEntry));
+    pe->func = func;
+    pe->opaque = opaque;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
+    *ppe = pe;
+    return 0;
+}
+
+void qemu_del_polling_cb(PollingFunc *func, void *opaque)
+{
+    PollingEntry **ppe, *pe;
+    for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
+        pe = *ppe;
+        if (pe->func == func && pe->opaque == opaque) {
+            *ppe = pe->next;
+            qemu_free(pe);
+            break;
+        }
+    }
+}
+
+/***********************************************************/
+/* Wait objects support */
+typedef struct WaitObjects {
+    int num;
+    HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
+    WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
+    void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
+} WaitObjects;
+
+static WaitObjects wait_objects = {0};
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+    WaitObjects *w = &wait_objects;
+
+    if (w->num >= MAXIMUM_WAIT_OBJECTS)
+        return -1;
+    w->events[w->num] = handle;
+    w->func[w->num] = func;
+    w->opaque[w->num] = opaque;
+    w->num++;
+    return 0;
+}
+
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+    int i, found;
+    WaitObjects *w = &wait_objects;
+
+    found = 0;
+    for (i = 0; i < w->num; i++) {
+        if (w->events[i] == handle)
+            found = 1;
+        if (found) {
+            w->events[i] = w->events[i + 1];
+            w->func[i] = w->func[i + 1];
+            w->opaque[i] = w->opaque[i + 1];
+        }
+    }
+    if (found)
+        w->num--;
+}
+#endif
+
+/***********************************************************/
+/* ram save/restore */
+
+static int ram_get_page(QEMUFile *f, uint8_t *buf, int len)
+{
+    int v;
+
+    v = qemu_get_byte(f);
+    switch(v) {
+    case 0:
+        if (qemu_get_buffer(f, buf, len) != len)
+            return -EIO;
+        break;
+    case 1:
+        v = qemu_get_byte(f);
+        memset(buf, v, len);
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    if (qemu_file_has_error(f))
+        return -EIO;
+
+    return 0;
+}
+
+static int ram_load_v1(QEMUFile *f, void *opaque)
+{
+    int ret;
+    ram_addr_t i;
+
+    if (qemu_get_be32(f) != last_ram_offset)
+        return -EINVAL;
+    for(i = 0; i < last_ram_offset; i+= TARGET_PAGE_SIZE) {
+        ret = ram_get_page(f, qemu_get_ram_ptr(i), TARGET_PAGE_SIZE);
+        if (ret)
+            return ret;
+    }
+    return 0;
+}
+
+#define BDRV_HASH_BLOCK_SIZE 1024
+#define IOBUF_SIZE 4096
+#define RAM_CBLOCK_MAGIC 0xfabe
+
+typedef struct RamDecompressState {
+    z_stream zstream;
+    QEMUFile *f;
+    uint8_t buf[IOBUF_SIZE];
+} RamDecompressState;
+
+static int ram_decompress_open(RamDecompressState *s, QEMUFile *f)
+{
+    int ret;
+    memset(s, 0, sizeof(*s));
+    s->f = f;
+    ret = inflateInit(&s->zstream);
+    if (ret != Z_OK)
+        return -1;
+    return 0;
+}
+
+static int ram_decompress_buf(RamDecompressState *s, uint8_t *buf, int len)
+{
+    int ret, clen;
+
+    s->zstream.avail_out = len;
+    s->zstream.next_out = buf;
+    while (s->zstream.avail_out > 0) {
+        if (s->zstream.avail_in == 0) {
+            if (qemu_get_be16(s->f) != RAM_CBLOCK_MAGIC)
+                return -1;
+            clen = qemu_get_be16(s->f);
+            if (clen > IOBUF_SIZE)
+                return -1;
+            qemu_get_buffer(s->f, s->buf, clen);
+            s->zstream.avail_in = clen;
+            s->zstream.next_in = s->buf;
+        }
+        ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
+        if (ret != Z_OK && ret != Z_STREAM_END) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static void ram_decompress_close(RamDecompressState *s)
+{
+    inflateEnd(&s->zstream);
+}
+
+#define RAM_SAVE_FLAG_FULL	0x01
+#define RAM_SAVE_FLAG_COMPRESS	0x02
+#define RAM_SAVE_FLAG_MEM_SIZE	0x04
+#define RAM_SAVE_FLAG_PAGE	0x08
+#define RAM_SAVE_FLAG_EOS	0x10
+
+static int is_dup_page(uint8_t *page, uint8_t ch)
+{
+    uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch;
+    uint32_t *array = (uint32_t *)page;
+    int i;
+
+    for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) {
+        if (array[i] != val)
+            return 0;
+    }
+
+    return 1;
+}
+
+static int ram_save_block(QEMUFile *f)
+{
+    static ram_addr_t current_addr = 0;
+    ram_addr_t saved_addr = current_addr;
+    ram_addr_t addr = 0;
+    int found = 0;
+
+    while (addr < last_ram_offset) {
+        if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
+            uint8_t *p;
+
+            cpu_physical_memory_reset_dirty(current_addr,
+                                            current_addr + TARGET_PAGE_SIZE,
+                                            MIGRATION_DIRTY_FLAG);
+
+            p = qemu_get_ram_ptr(current_addr);
+
+            if (is_dup_page(p, *p)) {
+                qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_COMPRESS);
+                qemu_put_byte(f, *p);
+            } else {
+                qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_PAGE);
+                qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
+            }
+
+            found = 1;
+            break;
+        }
+        addr += TARGET_PAGE_SIZE;
+        current_addr = (saved_addr + addr) % last_ram_offset;
+    }
+
+    return found;
+}
+
+static uint64_t bytes_transferred = 0;
+
+static ram_addr_t ram_save_remaining(void)
+{
+    ram_addr_t addr;
+    ram_addr_t count = 0;
+
+    for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) {
+        if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
+            count++;
+    }
+
+    return count;
+}
+
+uint64_t ram_bytes_remaining(void)
+{
+    return ram_save_remaining() * TARGET_PAGE_SIZE;
+}
+
+uint64_t ram_bytes_transferred(void)
+{
+    return bytes_transferred;
+}
+
+uint64_t ram_bytes_total(void)
+{
+    return last_ram_offset;
+}
+
+static int ram_save_live(QEMUFile *f, int stage, void *opaque)
+{
+    ram_addr_t addr;
+    uint64_t bytes_transferred_last;
+    double bwidth = 0;
+    uint64_t expected_time = 0;
+
+    cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX);
+
+    if (stage == 1) {
+        /* Make sure all dirty bits are set */
+        for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) {
+            if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
+                cpu_physical_memory_set_dirty(addr);
+        }
+
+        /* Enable dirty memory tracking */
+        cpu_physical_memory_set_dirty_tracking(1);
+
+        qemu_put_be64(f, last_ram_offset | RAM_SAVE_FLAG_MEM_SIZE);
+    }
+
+    bytes_transferred_last = bytes_transferred;
+    bwidth = get_clock();
+
+    while (!qemu_file_rate_limit(f)) {
+        int ret;
+
+        ret = ram_save_block(f);
+        bytes_transferred += ret * TARGET_PAGE_SIZE;
+        if (ret == 0) /* no more blocks */
+            break;
+    }
+
+    bwidth = get_clock() - bwidth;
+    bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
+
+    /* if we haven't transferred anything this round, force expected_time to a
+     * a very high value, but without crashing */
+    if (bwidth == 0)
+        bwidth = 0.000001;
+
+    /* try transferring iterative blocks of memory */
+
+    if (stage == 3) {
+
+        /* flush all remaining blocks regardless of rate limiting */
+        while (ram_save_block(f) != 0) {
+            bytes_transferred += TARGET_PAGE_SIZE;
+        }
+        cpu_physical_memory_set_dirty_tracking(0);
+    }
+
+    qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
+
+    expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
+
+    return (stage == 2) && (expected_time <= migrate_max_downtime());
+}
+
+static int ram_load_dead(QEMUFile *f, void *opaque)
+{
+    RamDecompressState s1, *s = &s1;
+    uint8_t buf[10];
+    ram_addr_t i;
+
+    if (ram_decompress_open(s, f) < 0)
+        return -EINVAL;
+    for(i = 0; i < last_ram_offset; i+= BDRV_HASH_BLOCK_SIZE) {
+        if (ram_decompress_buf(s, buf, 1) < 0) {
+            fprintf(stderr, "Error while reading ram block header\n");
+            goto error;
+        }
+        if (buf[0] == 0) {
+            if (ram_decompress_buf(s, qemu_get_ram_ptr(i),
+                                   BDRV_HASH_BLOCK_SIZE) < 0) {
+                fprintf(stderr, "Error while reading ram block address=0x%08" PRIx64, (uint64_t)i);
+                goto error;
+            }
+        } else {
+        error:
+            printf("Error block header\n");
+            return -EINVAL;
+        }
+    }
+    ram_decompress_close(s);
+
+    return 0;
+}
+
+static int ram_load(QEMUFile *f, void *opaque, int version_id)
+{
+    ram_addr_t addr;
+    int flags;
+
+    if (version_id == 1)
+        return ram_load_v1(f, opaque);
+
+    if (version_id == 2) {
+        if (qemu_get_be32(f) != last_ram_offset)
+            return -EINVAL;
+        return ram_load_dead(f, opaque);
+    }
+
+    if (version_id != 3)
+        return -EINVAL;
+
+    do {
+        addr = qemu_get_be64(f);
+
+        flags = addr & ~TARGET_PAGE_MASK;
+        addr &= TARGET_PAGE_MASK;
+
+        if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
+            if (addr != last_ram_offset)
+                return -EINVAL;
+        }
+
+        if (flags & RAM_SAVE_FLAG_FULL) {
+            if (ram_load_dead(f, opaque) < 0)
+                return -EINVAL;
+        }
+        
+        if (flags & RAM_SAVE_FLAG_COMPRESS) {
+            uint8_t ch = qemu_get_byte(f);
+            memset(qemu_get_ram_ptr(addr), ch, TARGET_PAGE_SIZE);
+        } else if (flags & RAM_SAVE_FLAG_PAGE)
+            qemu_get_buffer(f, qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE);
+    } while (!(flags & RAM_SAVE_FLAG_EOS));
+
+    return 0;
+}
+
+void qemu_service_io(void)
+{
+    qemu_notify_event();
+}
+
+/***********************************************************/
+/* bottom halves (can be seen as timers which expire ASAP) */
+
+struct QEMUBH {
+    QEMUBHFunc *cb;
+    void *opaque;
+    int scheduled;
+    int idle;
+    int deleted;
+    QEMUBH *next;
+};
+
+static QEMUBH *first_bh = NULL;
+
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+{
+    QEMUBH *bh;
+    bh = qemu_mallocz(sizeof(QEMUBH));
+    bh->cb = cb;
+    bh->opaque = opaque;
+    bh->next = first_bh;
+    first_bh = bh;
+    return bh;
+}
+
+int qemu_bh_poll(void)
+{
+    QEMUBH *bh, **bhp;
+    int ret;
+
+    ret = 0;
+    for (bh = first_bh; bh; bh = bh->next) {
+        if (!bh->deleted && bh->scheduled) {
+            bh->scheduled = 0;
+            if (!bh->idle)
+                ret = 1;
+            bh->idle = 0;
+            bh->cb(bh->opaque);
+        }
+    }
+
+    /* remove deleted bhs */
+    bhp = &first_bh;
+    while (*bhp) {
+        bh = *bhp;
+        if (bh->deleted) {
+            *bhp = bh->next;
+            qemu_free(bh);
+        } else
+            bhp = &bh->next;
+    }
+
+    return ret;
+}
+
+void qemu_bh_schedule_idle(QEMUBH *bh)
+{
+    if (bh->scheduled)
+        return;
+    bh->scheduled = 1;
+    bh->idle = 1;
+}
+
+void qemu_bh_schedule(QEMUBH *bh)
+{
+    if (bh->scheduled)
+        return;
+    bh->scheduled = 1;
+    bh->idle = 0;
+    /* stop the currently executing CPU to execute the BH ASAP */
+    qemu_notify_event();
+}
+
+void qemu_bh_cancel(QEMUBH *bh)
+{
+    bh->scheduled = 0;
+}
+
+void qemu_bh_delete(QEMUBH *bh)
+{
+    bh->scheduled = 0;
+    bh->deleted = 1;
+}
+
+static void qemu_bh_update_timeout(int *timeout)
+{
+    QEMUBH *bh;
+
+    for (bh = first_bh; bh; bh = bh->next) {
+        if (!bh->deleted && bh->scheduled) {
+            if (bh->idle) {
+                /* idle bottom halves will be polled at least
+                 * every 10ms */
+                *timeout = MIN(10, *timeout);
+            } else {
+                /* non-idle bottom halves will be executed
+                 * immediately */
+                *timeout = 0;
+                break;
+            }
+        }
+    }
+}
+
+/***********************************************************/
+/* machine registration */
+
+static QEMUMachine *first_machine = NULL;
+QEMUMachine *current_machine = NULL;
+
+int qemu_register_machine(QEMUMachine *m)
+{
+    QEMUMachine **pm;
+    pm = &first_machine;
+    while (*pm != NULL)
+        pm = &(*pm)->next;
+    m->next = NULL;
+    *pm = m;
+    return 0;
+}
+
+static QEMUMachine *find_machine(const char *name)
+{
+    QEMUMachine *m;
+
+    for(m = first_machine; m != NULL; m = m->next) {
+        if (!strcmp(m->name, name))
+            return m;
+    }
+    return NULL;
+}
+
+static QEMUMachine *find_default_machine(void)
+{
+    QEMUMachine *m;
+
+    for(m = first_machine; m != NULL; m = m->next) {
+        if (m->is_default) {
+            return m;
+        }
+    }
+    return NULL;
+}
+
+/***********************************************************/
+/* main execution loop */
+
+static void gui_update(void *opaque)
+{
+    uint64_t interval = GUI_REFRESH_INTERVAL;
+    DisplayState *ds = opaque;
+    DisplayChangeListener *dcl = ds->listeners;
+
+    dpy_refresh(ds);
+
+    while (dcl != NULL) {
+        if (dcl->gui_timer_interval &&
+            dcl->gui_timer_interval < interval)
+            interval = dcl->gui_timer_interval;
+        dcl = dcl->next;
+    }
+    qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock));
+}
+
+static void nographic_update(void *opaque)
+{
+    uint64_t interval = GUI_REFRESH_INTERVAL;
+
+    qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
+}
+
+struct vm_change_state_entry {
+    VMChangeStateHandler *cb;
+    void *opaque;
+    LIST_ENTRY (vm_change_state_entry) entries;
+};
+
+static LIST_HEAD(vm_change_state_head, vm_change_state_entry) vm_change_state_head;
+
+VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
+                                                     void *opaque)
+{
+    VMChangeStateEntry *e;
+
+    e = qemu_mallocz(sizeof (*e));
+
+    e->cb = cb;
+    e->opaque = opaque;
+    LIST_INSERT_HEAD(&vm_change_state_head, e, entries);
+    return e;
+}
+
+void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
+{
+    LIST_REMOVE (e, entries);
+    qemu_free (e);
+}
+
+static void vm_state_notify(int running, int reason)
+{
+    VMChangeStateEntry *e;
+
+    for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
+        e->cb(e->opaque, running, reason);
+    }
+}
+
+static void resume_all_vcpus(void);
+static void pause_all_vcpus(void);
+
+void vm_start(void)
+{
+    if (!vm_running) {
+        cpu_enable_ticks();
+        vm_running = 1;
+        vm_state_notify(1, 0);
+        qemu_rearm_alarm_timer(alarm_timer);
+        resume_all_vcpus();
+    }
+}
+
+/* reset/shutdown handler */
+
+typedef struct QEMUResetEntry {
+    QEMUResetHandler *func;
+    void *opaque;
+    int order;
+    struct QEMUResetEntry *next;
+} QEMUResetEntry;
+
+static QEMUResetEntry *first_reset_entry;
+static int reset_requested;
+static int shutdown_requested;
+static int powerdown_requested;
+static int debug_requested;
+static int vmstop_requested;
+
+int qemu_shutdown_requested(void)
+{
+    int r = shutdown_requested;
+    shutdown_requested = 0;
+    return r;
+}
+
+int qemu_reset_requested(void)
+{
+    int r = reset_requested;
+    reset_requested = 0;
+    return r;
+}
+
+int qemu_powerdown_requested(void)
+{
+    int r = powerdown_requested;
+    powerdown_requested = 0;
+    return r;
+}
+
+static int qemu_debug_requested(void)
+{
+    int r = debug_requested;
+    debug_requested = 0;
+    return r;
+}
+
+static int qemu_vmstop_requested(void)
+{
+    int r = vmstop_requested;
+    vmstop_requested = 0;
+    return r;
+}
+
+static void do_vm_stop(int reason)
+{
+    if (vm_running) {
+        cpu_disable_ticks();
+        vm_running = 0;
+        pause_all_vcpus();
+        vm_state_notify(0, reason);
+    }
+}
+
+void qemu_register_reset(QEMUResetHandler *func, int order, void *opaque)
+{
+    QEMUResetEntry **pre, *re;
+
+    pre = &first_reset_entry;
+    while (*pre != NULL && (*pre)->order >= order) {
+        pre = &(*pre)->next;
+    }
+    re = qemu_mallocz(sizeof(QEMUResetEntry));
+    re->func = func;
+    re->opaque = opaque;
+    re->order = order;
+    re->next = NULL;
+    *pre = re;
+}
+
+void qemu_system_reset(void)
+{
+    QEMUResetEntry *re;
+
+    /* reset all devices */
+    for(re = first_reset_entry; re != NULL; re = re->next) {
+        re->func(re->opaque);
+    }
+}
+
+void qemu_system_reset_request(void)
+{
+    if (no_reboot) {
+        shutdown_requested = 1;
+    } else {
+        reset_requested = 1;
+    }
+    qemu_notify_event();
+}
+
+void qemu_system_shutdown_request(void)
+{
+    shutdown_requested = 1;
+    qemu_notify_event();
+}
+
+void qemu_system_powerdown_request(void)
+{
+    powerdown_requested = 1;
+    qemu_notify_event();
+}
+
+#ifdef CONFIG_IOTHREAD
+static void qemu_system_vmstop_request(int reason)
+{
+    vmstop_requested = reason;
+    qemu_notify_event();
+}
+#endif
+
+#ifndef _WIN32
+static int io_thread_fd = -1;
+
+static void qemu_event_increment(void)
+{
+    static const char byte = 0;
+
+    if (io_thread_fd == -1)
+        return;
+
+    write(io_thread_fd, &byte, sizeof(byte));
+}
+
+static void qemu_event_read(void *opaque)
+{
+    int fd = (unsigned long)opaque;
+    ssize_t len;
+
+    /* Drain the notify pipe */
+    do {
+        char buffer[512];
+        len = read(fd, buffer, sizeof(buffer));
+    } while ((len == -1 && errno == EINTR) || len > 0);
+}
+
+static int qemu_event_init(void)
+{
+    int err;
+    int fds[2];
+
+    err = pipe(fds);
+    if (err == -1)
+        return -errno;
+
+    err = fcntl_setfl(fds[0], O_NONBLOCK);
+    if (err < 0)
+        goto fail;
+
+    err = fcntl_setfl(fds[1], O_NONBLOCK);
+    if (err < 0)
+        goto fail;
+
+    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+                         (void *)(unsigned long)fds[0]);
+
+    io_thread_fd = fds[1];
+    return 0;
+
+fail:
+    close(fds[0]);
+    close(fds[1]);
+    return err;
+}
+#else
+HANDLE qemu_event_handle;
+
+static void dummy_event_handler(void *opaque)
+{
+}
+
+static int qemu_event_init(void)
+{
+    qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!qemu_event_handle) {
+        perror("Failed CreateEvent");
+        return -1;
+    }
+    qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+    return 0;
+}
+
+static void qemu_event_increment(void)
+{
+    SetEvent(qemu_event_handle);
+}
+#endif
+
+static int cpu_can_run(CPUState *env)
+{
+    if (env->stop)
+        return 0;
+    if (env->stopped)
+        return 0;
+    return 1;
+}
+
+#ifndef CONFIG_IOTHREAD
+static int qemu_init_main_loop(void)
+{
+    return qemu_event_init();
+}
+
+void qemu_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+
+    if (kvm_enabled())
+        kvm_init_vcpu(env);
+    return;
+}
+
+int qemu_cpu_self(void *env)
+{
+    return 1;
+}
+
+static void resume_all_vcpus(void)
+{
+}
+
+static void pause_all_vcpus(void)
+{
+}
+
+void qemu_cpu_kick(void *env)
+{
+    return;
+}
+
+void qemu_notify_event(void)
+{
+    CPUState *env = cpu_single_env;
+
+    if (env) {
+        cpu_exit(env);
+#ifdef USE_KQEMU
+        if (env->kqemu_enabled)
+            kqemu_cpu_interrupt(env);
+#endif
+     }
+}
+
+#define qemu_mutex_lock_iothread() do { } while (0)
+#define qemu_mutex_unlock_iothread() do { } while (0)
+
+void vm_stop(int reason)
+{
+    do_vm_stop(reason);
+}
+
+#else /* CONFIG_IOTHREAD */
+
+#include "qemu-thread.h"
+
+QemuMutex qemu_global_mutex;
+static QemuMutex qemu_fair_mutex;
+
+static QemuThread io_thread;
+
+static QemuThread *tcg_cpu_thread;
+static QemuCond *tcg_halt_cond;
+
+static int qemu_system_ready;
+/* cpu creation */
+static QemuCond qemu_cpu_cond;
+/* system init */
+static QemuCond qemu_system_cond;
+static QemuCond qemu_pause_cond;
+
+static void block_io_signals(void);
+static void unblock_io_signals(void);
+static int tcg_has_work(void);
+
+static int qemu_init_main_loop(void)
+{
+    int ret;
+
+    ret = qemu_event_init();
+    if (ret)
+        return ret;
+
+    qemu_cond_init(&qemu_pause_cond);
+    qemu_mutex_init(&qemu_fair_mutex);
+    qemu_mutex_init(&qemu_global_mutex);
+    qemu_mutex_lock(&qemu_global_mutex);
+
+    unblock_io_signals();
+    qemu_thread_self(&io_thread);
+
+    return 0;
+}
+
+static void qemu_wait_io_event(CPUState *env)
+{
+    while (!tcg_has_work())
+        qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
+
+    qemu_mutex_unlock(&qemu_global_mutex);
+
+    /*
+     * Users of qemu_global_mutex can be starved, having no chance
+     * to acquire it since this path will get to it first.
+     * So use another lock to provide fairness.
+     */
+    qemu_mutex_lock(&qemu_fair_mutex);
+    qemu_mutex_unlock(&qemu_fair_mutex);
+
+    qemu_mutex_lock(&qemu_global_mutex);
+    if (env->stop) {
+        env->stop = 0;
+        env->stopped = 1;
+        qemu_cond_signal(&qemu_pause_cond);
+    }
+}
+
+static int qemu_cpu_exec(CPUState *env);
+
+static void *kvm_cpu_thread_fn(void *arg)
+{
+    CPUState *env = arg;
+
+    block_io_signals();
+    qemu_thread_self(env->thread);
+
+    /* signal CPU creation */
+    qemu_mutex_lock(&qemu_global_mutex);
+    env->created = 1;
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    /* and wait for machine initialization */
+    while (!qemu_system_ready)
+        qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+
+    while (1) {
+        if (cpu_can_run(env))
+            qemu_cpu_exec(env);
+        qemu_wait_io_event(env);
+    }
+
+    return NULL;
+}
+
+static void tcg_cpu_exec(void);
+
+static void *tcg_cpu_thread_fn(void *arg)
+{
+    CPUState *env = arg;
+
+    block_io_signals();
+    qemu_thread_self(env->thread);
+
+    /* signal CPU creation */
+    qemu_mutex_lock(&qemu_global_mutex);
+    for (env = first_cpu; env != NULL; env = env->next_cpu)
+        env->created = 1;
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    /* and wait for machine initialization */
+    while (!qemu_system_ready)
+        qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+
+    while (1) {
+        tcg_cpu_exec();
+        qemu_wait_io_event(cur_cpu);
+    }
+
+    return NULL;
+}
+
+void qemu_cpu_kick(void *_env)
+{
+    CPUState *env = _env;
+    qemu_cond_broadcast(env->halt_cond);
+    if (kvm_enabled())
+        qemu_thread_signal(env->thread, SIGUSR1);
+}
+
+int qemu_cpu_self(void *env)
+{
+    return (cpu_single_env != NULL);
+}
+
+static void cpu_signal(int sig)
+{
+    if (cpu_single_env)
+        cpu_exit(cpu_single_env);
+}
+
+static void block_io_signals(void)
+{
+    sigset_t set;
+    struct sigaction sigact;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR2);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR1);
+    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+    memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_handler = cpu_signal;
+    sigaction(SIGUSR1, &sigact, NULL);
+}
+
+static void unblock_io_signals(void)
+{
+    sigset_t set;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR2);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR1);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+}
+
+static void qemu_signal_lock(unsigned int msecs)
+{
+    qemu_mutex_lock(&qemu_fair_mutex);
+
+    while (qemu_mutex_trylock(&qemu_global_mutex)) {
+        qemu_thread_signal(tcg_cpu_thread, SIGUSR1);
+        if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
+            break;
+    }
+    qemu_mutex_unlock(&qemu_fair_mutex);
+}
+
+static void qemu_mutex_lock_iothread(void)
+{
+    if (kvm_enabled()) {
+        qemu_mutex_lock(&qemu_fair_mutex);
+        qemu_mutex_lock(&qemu_global_mutex);
+        qemu_mutex_unlock(&qemu_fair_mutex);
+    } else
+        qemu_signal_lock(100);
+}
+
+static void qemu_mutex_unlock_iothread(void)
+{
+    qemu_mutex_unlock(&qemu_global_mutex);
+}
+
+static int all_vcpus_paused(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        if (!penv->stopped)
+            return 0;
+        penv = (CPUState *)penv->next_cpu;
+    }
+
+    return 1;
+}
+
+static void pause_all_vcpus(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        penv->stop = 1;
+        qemu_thread_signal(penv->thread, SIGUSR1);
+        qemu_cpu_kick(penv);
+        penv = (CPUState *)penv->next_cpu;
+    }
+
+    while (!all_vcpus_paused()) {
+        qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
+        penv = first_cpu;
+        while (penv) {
+            qemu_thread_signal(penv->thread, SIGUSR1);
+            penv = (CPUState *)penv->next_cpu;
+        }
+    }
+}
+
+static void resume_all_vcpus(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        penv->stop = 0;
+        penv->stopped = 0;
+        qemu_thread_signal(penv->thread, SIGUSR1);
+        qemu_cpu_kick(penv);
+        penv = (CPUState *)penv->next_cpu;
+    }
+}
+
+static void tcg_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+    /* share a single thread for all cpus with TCG */
+    if (!tcg_cpu_thread) {
+        env->thread = qemu_mallocz(sizeof(QemuThread));
+        env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+        qemu_cond_init(env->halt_cond);
+        qemu_thread_create(env->thread, tcg_cpu_thread_fn, env);
+        while (env->created == 0)
+            qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+        tcg_cpu_thread = env->thread;
+        tcg_halt_cond = env->halt_cond;
+    } else {
+        env->thread = tcg_cpu_thread;
+        env->halt_cond = tcg_halt_cond;
+    }
+}
+
+static void kvm_start_vcpu(CPUState *env)
+{
+#if 0
+    kvm_init_vcpu(env);
+    env->thread = qemu_mallocz(sizeof(QemuThread));
+    env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+    qemu_cond_init(env->halt_cond);
+    qemu_thread_create(env->thread, kvm_cpu_thread_fn, env);
+    while (env->created == 0)
+        qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+#endif
+}
+
+void qemu_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+
+    if (kvm_enabled())
+        kvm_start_vcpu(env);
+    else
+        tcg_init_vcpu(env);
+}
+
+void qemu_notify_event(void)
+{
+    qemu_event_increment();
+}
+
+void vm_stop(int reason)
+{
+    QemuThread me;
+    qemu_thread_self(&me);
+
+    if (!qemu_thread_equal(&me, &io_thread)) {
+        qemu_system_vmstop_request(reason);
+        /*
+         * FIXME: should not return to device code in case
+         * vm_stop() has been requested.
+         */
+        if (cpu_single_env) {
+            cpu_exit(cpu_single_env);
+            cpu_single_env->stop = 1;
+        }
+        return;
+    }
+    do_vm_stop(reason);
+}
+
+#endif
+
+
+#ifdef _WIN32
+static void host_main_loop_wait(int *timeout)
+{
+    int ret, ret2, i;
+    PollingEntry *pe;
+
+
+    /* XXX: need to suppress polling by better using win32 events */
+    ret = 0;
+    for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
+        ret |= pe->func(pe->opaque);
+    }
+    if (ret == 0) {
+        int err;
+        WaitObjects *w = &wait_objects;
+
+        ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
+        if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+            if (w->func[ret - WAIT_OBJECT_0])
+                w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+
+            /* Check for additional signaled events */
+            for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+
+                /* Check if event is signaled */
+                ret2 = WaitForSingleObject(w->events[i], 0);
+                if(ret2 == WAIT_OBJECT_0) {
+                    if (w->func[i])
+                        w->func[i](w->opaque[i]);
+                } else if (ret2 == WAIT_TIMEOUT) {
+                } else {
+                    err = GetLastError();
+                    fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+                }
+            }
+        } else if (ret == WAIT_TIMEOUT) {
+        } else {
+            err = GetLastError();
+            fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
+        }
+    }
+
+    *timeout = 0;
+}
+#else
+static void host_main_loop_wait(int *timeout)
+{
+}
+#endif
+
+void main_loop_wait(int timeout)
+{
+    IOHandlerRecord *ioh;
+    fd_set rfds, wfds, xfds;
+    int ret, nfds;
+    struct timeval tv;
+
+    qemu_bh_update_timeout(&timeout);
+
+    host_main_loop_wait(&timeout);
+
+    /* poll any events */
+    /* XXX: separate device handlers from system ones */
+    nfds = -1;
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+    for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
+        if (ioh->deleted)
+            continue;
+        if (ioh->fd_read &&
+            (!ioh->fd_read_poll ||
+             ioh->fd_read_poll(ioh->opaque) != 0)) {
+            FD_SET(ioh->fd, &rfds);
+            if (ioh->fd > nfds)
+                nfds = ioh->fd;
+        }
+        if (ioh->fd_write) {
+            FD_SET(ioh->fd, &wfds);
+            if (ioh->fd > nfds)
+                nfds = ioh->fd;
+        }
+    }
+
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+
+#if defined(CONFIG_SLIRP)
+    if (slirp_is_inited()) {
+        slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+    }
+#endif
+    qemu_mutex_unlock_iothread();
+    ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+    qemu_mutex_lock_iothread();
+    if (ret > 0) {
+        IOHandlerRecord **pioh;
+
+        for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
+            if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
+                ioh->fd_read(ioh->opaque);
+            }
+            if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
+                ioh->fd_write(ioh->opaque);
+            }
+        }
+
+	/* remove deleted IO handlers */
+	pioh = &first_io_handler;
+	while (*pioh) {
+            ioh = *pioh;
+            if (ioh->deleted) {
+                *pioh = ioh->next;
+                qemu_free(ioh);
+            } else
+                pioh = &ioh->next;
+        }
+    }
+#if defined(CONFIG_SLIRP)
+    if (slirp_is_inited()) {
+        if (ret < 0) {
+            FD_ZERO(&rfds);
+            FD_ZERO(&wfds);
+            FD_ZERO(&xfds);
+        }
+        slirp_select_poll(&rfds, &wfds, &xfds);
+    }
+#endif
+    charpipe_poll();
+
+    /* rearm timer, if not periodic */
+    if (alarm_timer->flags & ALARM_FLAG_EXPIRED) {
+        alarm_timer->flags &= ~ALARM_FLAG_EXPIRED;
+        qemu_rearm_alarm_timer(alarm_timer);
+    }
+
+    /* vm time timers */
+    if (vm_running) {
+        if (!cur_cpu || likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER)))
+            qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
+                qemu_get_clock(vm_clock));
+    }
+
+    /* real time timers */
+    qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
+                    qemu_get_clock(rt_clock));
+
+    /* Check bottom-halves last in case any of the earlier events triggered
+       them.  */
+    qemu_bh_poll();
+
+}
+
+static int qemu_cpu_exec(CPUState *env)
+{
+    int ret;
+#ifdef CONFIG_PROFILER
+    int64_t ti;
+#endif
+
+#ifdef CONFIG_PROFILER
+    ti = profile_getclock();
+#endif
+    if (use_icount) {
+        int64_t count;
+        int decr;
+        qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
+        env->icount_decr.u16.low = 0;
+        env->icount_extra = 0;
+        count = qemu_next_deadline();
+        count = (count + (1 << icount_time_shift) - 1)
+                >> icount_time_shift;
+        qemu_icount += count;
+        decr = (count > 0xffff) ? 0xffff : count;
+        count -= decr;
+        env->icount_decr.u16.low = decr;
+        env->icount_extra = count;
+    }
+#ifdef CONFIG_TRACE
+    if (tbflush_requested) {
+        tbflush_requested = 0;
+        tb_flush(env);
+        return EXCP_INTERRUPT;
+    }
+#endif
+
+
+    ret = cpu_exec(env);
+#ifdef CONFIG_PROFILER
+    qemu_time += profile_getclock() - ti;
+#endif
+    if (use_icount) {
+        /* Fold pending instructions back into the
+           instruction counter, and clear the interrupt flag.  */
+        qemu_icount -= (env->icount_decr.u16.low
+                        + env->icount_extra);
+        env->icount_decr.u32 = 0;
+        env->icount_extra = 0;
+    }
+    return ret;
+}
+
+static void tcg_cpu_exec(void)
+{
+    int ret = 0;
+
+    if (next_cpu == NULL)
+        next_cpu = first_cpu;
+    for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) {
+        CPUState *env = cur_cpu = next_cpu;
+
+        if (!vm_running)
+            break;
+        if (timer_alarm_pending) {
+            timer_alarm_pending = 0;
+            break;
+        }
+        if (cpu_can_run(env))
+            ret = qemu_cpu_exec(env);
+        if (ret == EXCP_DEBUG) {
+            gdb_set_stop_cpu(env);
+            debug_requested = 1;
+            break;
+        }
+    }
+}
+
+static int cpu_has_work(CPUState *env)
+{
+    if (env->stop)
+        return 1;
+    if (env->stopped)
+        return 0;
+    if (!env->halted)
+        return 1;
+    if (qemu_cpu_has_work(env))
+        return 1;
+    return 0;
+}
+
+static int tcg_has_work(void)
+{
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu)
+        if (cpu_has_work(env))
+            return 1;
+    return 0;
+}
+
+static int qemu_calculate_timeout(void)
+{
+#ifndef CONFIG_IOTHREAD
+    int timeout;
+
+    if (!vm_running)
+        timeout = 5000;
+    else if (tcg_has_work())
+        timeout = 0;
+    else if (!use_icount)
+        timeout = 5000;
+    else {
+     /* XXX: use timeout computed from timers */
+        int64_t add;
+        int64_t delta;
+        /* Advance virtual time to the next event.  */
+        if (use_icount == 1) {
+            /* When not using an adaptive execution frequency
+               we tend to get badly out of sync with real time,
+               so just delay for a reasonable amount of time.  */
+            delta = 0;
+        } else {
+            delta = cpu_get_icount() - cpu_get_clock();
+        }
+        if (delta > 0) {
+            /* If virtual time is ahead of real time then just
+               wait for IO.  */
+            timeout = (delta / 1000000) + 1;
+        } else {
+            /* Wait for either IO to occur or the next
+               timer event.  */
+            add = qemu_next_deadline();
+            /* We advance the timer before checking for IO.
+               Limit the amount we advance so that early IO
+               activity won't get the guest too far ahead.  */
+            if (add > 10000000)
+                add = 10000000;
+            delta += add;
+            add = (add + (1 << icount_time_shift) - 1)
+                  >> icount_time_shift;
+            qemu_icount += add;
+            timeout = delta / 1000000;
+            if (timeout < 0)
+                timeout = 0;
+        }
+    }
+
+    return timeout;
+#else /* CONFIG_IOTHREAD */
+    return 1000;
+#endif
+}
+
+static int vm_can_run(void)
+{
+    if (powerdown_requested)
+        return 0;
+    if (reset_requested)
+        return 0;
+    if (shutdown_requested)
+        return 0;
+    if (debug_requested)
+        return 0;
+    return 1;
+}
+
+static void main_loop(void)
+{
+    int r;
+
+#ifdef CONFIG_IOTHREAD
+    qemu_system_ready = 1;
+    qemu_cond_broadcast(&qemu_system_cond);
+#endif
+
+    for (;;) {
+        do {
+#ifdef CONFIG_PROFILER
+            int64_t ti;
+#endif
+#ifndef CONFIG_IOTHREAD
+            tcg_cpu_exec();
+#endif
+#ifdef CONFIG_PROFILER
+            ti = profile_getclock();
+#endif
+            main_loop_wait(qemu_calculate_timeout());
+#ifdef CONFIG_PROFILER
+            dev_time += profile_getclock() - ti;
+#endif
+        } while (vm_can_run());
+
+        if (qemu_debug_requested())
+            vm_stop(EXCP_DEBUG);
+        if (qemu_shutdown_requested()) {
+            if (no_shutdown) {
+                vm_stop(0);
+                no_shutdown = 0;
+            } else
+                break;
+        }
+        if (qemu_reset_requested()) {
+            pause_all_vcpus();
+            qemu_system_reset();
+            resume_all_vcpus();
+        }
+        if (qemu_powerdown_requested())
+            qemu_system_powerdown();
+        if ((r = qemu_vmstop_requested()))
+            vm_stop(r);
+    }
+    pause_all_vcpus();
+}
+
+static void version(void)
+{
+    printf("QEMU PC emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+}
+
+void qemu_help(int exitcode)
+{
+    version();
+    printf("usage: %s [options] [disk_image]\n"
+           "\n"
+           "'disk_image' is a raw hard image image for IDE hard disk 0\n"
+           "\n"
+#define DEF(option, opt_arg, opt_enum, opt_help)        \
+           opt_help
+#define DEFHEADING(text) stringify(text) "\n"
+#include "qemu-options.h"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
+           "\n"
+           "During emulation, the following keys are useful:\n"
+           "ctrl-alt-f      toggle full screen\n"
+           "ctrl-alt-n      switch to virtual console 'n'\n"
+           "ctrl-alt        toggle mouse and keyboard grab\n"
+           "\n"
+           "When using -nographic, press 'ctrl-a h' to get some help.\n"
+           ,
+           "qemu",
+           DEFAULT_RAM_SIZE,
+#ifndef _WIN32
+           DEFAULT_NETWORK_SCRIPT,
+           DEFAULT_NETWORK_DOWN_SCRIPT,
+#endif
+           DEFAULT_GDBSTUB_PORT,
+           "/tmp/qemu.log");
+    exit(exitcode);
+}
+
+#define HAS_ARG 0x0001
+
+enum {
+#define DEF(option, opt_arg, opt_enum, opt_help)        \
+    opt_enum,
+#define DEFHEADING(text)
+#include "qemu-options.h"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
+};
+
+typedef struct QEMUOption {
+    const char *name;
+    int flags;
+    int index;
+} QEMUOption;
+
+static const QEMUOption qemu_options[] = {
+    { "h", 0, QEMU_OPTION_h },
+#define DEF(option, opt_arg, opt_enum, opt_help)        \
+    { option, opt_arg, opt_enum },
+#define DEFHEADING(text)
+#include "qemu-options.h"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
+    { NULL, 0, 0 },
+};
+
+#ifdef HAS_AUDIO
+struct soundhw soundhw[] = {
+#ifdef HAS_AUDIO_CHOICE
+#if defined(TARGET_I386) || defined(TARGET_MIPS)
+    {
+        "pcspk",
+        "PC speaker",
+        0,
+        1,
+        { .init_isa = pcspk_audio_init }
+    },
+#endif
+
+#ifdef CONFIG_SB16
+    {
+        "sb16",
+        "Creative Sound Blaster 16",
+        0,
+        1,
+        { .init_isa = SB16_init }
+    },
+#endif
+
+#ifdef CONFIG_CS4231A
+    {
+        "cs4231a",
+        "CS4231A",
+        0,
+        1,
+        { .init_isa = cs4231a_init }
+    },
+#endif
+
+#ifdef CONFIG_ADLIB
+    {
+        "adlib",
+#ifdef HAS_YMF262
+        "Yamaha YMF262 (OPL3)",
+#else
+        "Yamaha YM3812 (OPL2)",
+#endif
+        0,
+        1,
+        { .init_isa = Adlib_init }
+    },
+#endif
+
+#ifdef CONFIG_GUS
+    {
+        "gus",
+        "Gravis Ultrasound GF1",
+        0,
+        1,
+        { .init_isa = GUS_init }
+    },
+#endif
+
+#ifdef CONFIG_AC97
+    {
+        "ac97",
+        "Intel 82801AA AC97 Audio",
+        0,
+        0,
+        { .init_pci = ac97_init }
+    },
+#endif
+
+#ifdef CONFIG_ES1370
+    {
+        "es1370",
+        "ENSONIQ AudioPCI ES1370",
+        0,
+        0,
+        { .init_pci = es1370_init }
+    },
+#endif
+
+#endif /* HAS_AUDIO_CHOICE */
+
+    { NULL, NULL, 0, 0, { NULL } }
+};
+
+static void select_soundhw (const char *optarg)
+{
+    struct soundhw *c;
+
+    if (*optarg == '?') {
+    show_valid_cards:
+
+        printf ("Valid sound card names (comma separated):\n");
+        for (c = soundhw; c->name; ++c) {
+            printf ("%-11s %s\n", c->name, c->descr);
+        }
+        printf ("\n-soundhw all will enable all of the above\n");
+        exit (*optarg != '?');
+    }
+    else {
+        size_t l;
+        const char *p;
+        char *e;
+        int bad_card = 0;
+
+        if (!strcmp (optarg, "all")) {
+            for (c = soundhw; c->name; ++c) {
+                c->enabled = 1;
+            }
+            return;
+        }
+
+        p = optarg;
+        while (*p) {
+            e = strchr (p, ',');
+            l = !e ? strlen (p) : (size_t) (e - p);
+
+            for (c = soundhw; c->name; ++c) {
+                if (!strncmp (c->name, p, l)) {
+                    c->enabled = 1;
+                    break;
+                }
+            }
+
+            if (!c->name) {
+                if (l > 80) {
+                    fprintf (stderr,
+                             "Unknown sound card name (too big to show)\n");
+                }
+                else {
+                    fprintf (stderr, "Unknown sound card name `%.*s'\n",
+                             (int) l, p);
+                }
+                bad_card = 1;
+            }
+            p += l + (e != NULL);
+        }
+
+        if (bad_card)
+            goto show_valid_cards;
+    }
+}
+#endif
+
+static void select_vgahw (const char *p)
+{
+    const char *opts;
+
+    cirrus_vga_enabled = 0;
+    std_vga_enabled = 0;
+    vmsvga_enabled = 0;
+    xenfb_enabled = 0;
+    if (strstart(p, "std", &opts)) {
+        std_vga_enabled = 1;
+    } else if (strstart(p, "cirrus", &opts)) {
+        cirrus_vga_enabled = 1;
+    } else if (strstart(p, "vmware", &opts)) {
+        vmsvga_enabled = 1;
+    } else if (strstart(p, "xenfb", &opts)) {
+        xenfb_enabled = 1;
+    } else if (!strstart(p, "none", &opts)) {
+    invalid_vga:
+        fprintf(stderr, "Unknown vga type: %s\n", p);
+        exit(1);
+    }
+    while (*opts) {
+        const char *nextopt;
+
+        if (strstart(opts, ",retrace=", &nextopt)) {
+            opts = nextopt;
+            if (strstart(opts, "dumb", &nextopt))
+                vga_retrace_method = VGA_RETRACE_DUMB;
+            else if (strstart(opts, "precise", &nextopt))
+                vga_retrace_method = VGA_RETRACE_PRECISE;
+            else goto invalid_vga;
+        } else goto invalid_vga;
+        opts = nextopt;
+    }
+}
+
+#ifdef _WIN32
+static BOOL WINAPI qemu_ctrl_handler(DWORD type)
+{
+    exit(STATUS_CONTROL_C_EXIT);
+    return TRUE;
+}
+#endif
+
+int qemu_uuid_parse(const char *str, uint8_t *uuid)
+{
+    int ret;
+
+    if(strlen(str) != 36)
+        return -1;
+
+    ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3],
+            &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9],
+            &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14], &uuid[15]);
+
+    if(ret != 16)
+        return -1;
+
+#ifdef TARGET_I386
+    smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid);
+#endif
+
+    return 0;
+}
+
+#define MAX_NET_CLIENTS 32
+
+#ifndef _WIN32
+
+static void termsig_handler(int signal)
+{
+    qemu_system_shutdown_request();
+}
+
+static void sigchld_handler(int signal)
+{
+    waitpid(-1, NULL, WNOHANG);
+}
+
+static void sighandler_setup(void)
+{
+    struct sigaction act;
+
+    memset(&act, 0, sizeof(act));
+    act.sa_handler = termsig_handler;
+    sigaction(SIGINT,  &act, NULL);
+    sigaction(SIGHUP,  &act, NULL);
+    sigaction(SIGTERM, &act, NULL);
+
+    act.sa_handler = sigchld_handler;
+    act.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGCHLD, &act, NULL);
+}
+
+#endif
+
+#ifdef _WIN32
+/* Look for support files in the same directory as the executable.  */
+static char *find_datadir(const char *argv0)
+{
+    char *p;
+    char buf[MAX_PATH];
+    DWORD len;
+
+    len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
+    if (len == 0) {
+        return NULL;
+    }
+
+    buf[len] = 0;
+    p = buf + len - 1;
+    while (p != buf && *p != '\\')
+        p--;
+    *p = 0;
+    if (access(buf, R_OK) == 0) {
+        return qemu_strdup(buf);
+    }
+    return NULL;
+}
+#else /* !_WIN32 */
+
+/* Find a likely location for support files using the location of the binary.
+   For installed binaries this will be "$bindir/../share/qemu".  When
+   running from the build tree this will be "$bindir/../pc-bios".  */
+#define SHARE_SUFFIX "/share/qemu"
+#define BUILD_SUFFIX "/pc-bios"
+static char *find_datadir(const char *argv0)
+{
+    char *dir;
+    char *p = NULL;
+    char *res;
+#ifdef PATH_MAX
+    char buf[PATH_MAX];
+#endif
+    size_t max_len;
+
+#if defined(__linux__)
+    {
+        int len;
+        len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
+        if (len > 0) {
+            buf[len] = 0;
+            p = buf;
+        }
+    }
+#elif defined(__FreeBSD__)
+    {
+        int len;
+        len = readlink("/proc/curproc/file", buf, sizeof(buf) - 1);
+        if (len > 0) {
+            buf[len] = 0;
+            p = buf;
+        }
+    }
+#endif
+    /* If we don't have any way of figuring out the actual executable
+       location then try argv[0].  */
+    if (!p) {
+#ifdef PATH_MAX
+        p = buf;
+#endif
+        p = realpath(argv0, p);
+        if (!p) {
+            return NULL;
+        }
+    }
+    dir = dirname(p);
+    dir = dirname(dir);
+
+    max_len = strlen(dir) +
+        MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
+    res = qemu_mallocz(max_len);
+    snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
+    if (access(res, R_OK)) {
+        snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
+        if (access(res, R_OK)) {
+            qemu_free(res);
+            res = NULL;
+        }
+    }
+#ifndef PATH_MAX
+    free(p);
+#endif
+    return res;
+}
+#undef SHARE_SUFFIX
+#undef BUILD_SUFFIX
+#endif
+
+char *qemu_find_file(int type, const char *name)
+{
+    int len;
+    const char *subdir;
+    char *buf;
+
+    /* If name contains path separators then try it as a straight path.  */
+    if ((strchr(name, '/') || strchr(name, '\\'))
+        && access(name, R_OK) == 0) {
+        return strdup(name);
+    }
+    switch (type) {
+    case QEMU_FILE_TYPE_BIOS:
+        subdir = "";
+        break;
+    case QEMU_FILE_TYPE_KEYMAP:
+        subdir = "keymaps/";
+        break;
+    default:
+        abort();
+    }
+    len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2;
+    buf = qemu_mallocz(len);
+    snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
+    if (access(buf, R_OK)) {
+        qemu_free(buf);
+        return NULL;
+    }
+    return buf;
+}
+
+int main(int argc, char **argv, char **envp)
+{
+    const char *gdbstub_dev = NULL;
+    uint32_t boot_devices_bitmap = 0;
+    int i;
+    int snapshot, linux_boot, net_boot;
+    const char *initrd_filename;
+    const char *kernel_filename, *kernel_cmdline;
+    const char *boot_devices = "";
+    DisplayState *ds;
+    DisplayChangeListener *dcl;
+    int cyls, heads, secs, translation;
+    const char *net_clients[MAX_NET_CLIENTS];
+    int nb_net_clients;
+    const char *bt_opts[MAX_BT_CMDLINE];
+    int nb_bt_opts;
+    int hda_index;
+    int optind;
+    const char *r, *optarg;
+    CharDriverState *monitor_hd = NULL;
+    const char *monitor_device;
+    const char *serial_devices[MAX_SERIAL_PORTS];
+    int serial_device_index;
+    const char *parallel_devices[MAX_PARALLEL_PORTS];
+    int parallel_device_index;
+    const char *virtio_consoles[MAX_VIRTIO_CONSOLES];
+    int virtio_console_index;
+    const char *loadvm = NULL;
+    QEMUMachine *machine;
+    const char *cpu_model;
+    const char *usb_devices[MAX_USB_CMDLINE];
+    int usb_devices_index;
+#ifndef _WIN32
+    int fds[2];
+#endif
+    int tb_size;
+    const char *pid_file = NULL;
+    const char *incoming = NULL;
+#ifndef _WIN32
+    int fd = 0;
+    struct passwd *pwd = NULL;
+    const char *chroot_dir = NULL;
+    const char *run_as = NULL;
+#endif
+    CPUState *env;
+    int show_vnc_port = 0;
+
+    qemu_cache_utils_init(envp);
+
+    LIST_INIT (&vm_change_state_head);
+#ifndef _WIN32
+    {
+        struct sigaction act;
+        sigfillset(&act.sa_mask);
+        act.sa_flags = 0;
+        act.sa_handler = SIG_IGN;
+        sigaction(SIGPIPE, &act, NULL);
+    }
+#else
+    SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
+    /* Note: cpu_interrupt() is currently not SMP safe, so we force
+       QEMU to run on a single CPU */
+    {
+        HANDLE h;
+        DWORD mask, smask;
+        int i;
+        h = GetCurrentProcess();
+        if (GetProcessAffinityMask(h, &mask, &smask)) {
+            for(i = 0; i < 32; i++) {
+                if (mask & (1 << i))
+                    break;
+            }
+            if (i != 32) {
+                mask = 1 << i;
+                SetProcessAffinityMask(h, mask);
+            }
+        }
+    }
+#endif
+
+    module_call_init(MODULE_INIT_MACHINE);
+    machine = find_default_machine();
+    cpu_model = NULL;
+    initrd_filename = NULL;
+    ram_size = 0;
+    snapshot = 0;
+    kernel_filename = NULL;
+    kernel_cmdline = "";
+    cyls = heads = secs = 0;
+    translation = BIOS_ATA_TRANSLATION_AUTO;
+    monitor_device = "vc:80Cx24C";
+
+    serial_devices[0] = "vc:80Cx24C";
+    for(i = 1; i < MAX_SERIAL_PORTS; i++)
+        serial_devices[i] = NULL;
+    serial_device_index = 0;
+
+    parallel_devices[0] = "vc:80Cx24C";
+    for(i = 1; i < MAX_PARALLEL_PORTS; i++)
+        parallel_devices[i] = NULL;
+    parallel_device_index = 0;
+
+    for(i = 0; i < MAX_VIRTIO_CONSOLES; i++)
+        virtio_consoles[i] = NULL;
+    virtio_console_index = 0;
+
+    for (i = 0; i < MAX_NODES; i++) {
+        node_mem[i] = 0;
+        node_cpumask[i] = 0;
+    }
+
+    usb_devices_index = 0;
+
+    nb_net_clients = 0;
+    nb_bt_opts = 0;
+    nb_drives = 0;
+    nb_drives_opt = 0;
+    nb_numa_nodes = 0;
+    hda_index = -1;
+
+    nb_nics = 0;
+
+    tb_size = 0;
+    autostart= 1;
+
+    register_watchdogs();
+
+    optind = 1;
+    for(;;) {
+        if (optind >= argc)
+            break;
+        r = argv[optind];
+        if (r[0] != '-') {
+	    hda_index = drive_add(argv[optind++], HD_ALIAS, 0);
+        } else {
+            const QEMUOption *popt;
+
+            optind++;
+            /* Treat --foo the same as -foo.  */
+            if (r[1] == '-')
+                r++;
+            popt = qemu_options;
+            for(;;) {
+                if (!popt->name) {
+                    fprintf(stderr, "%s: invalid option -- '%s'\n",
+                            argv[0], r);
+                    exit(1);
+                }
+                if (!strcmp(popt->name, r + 1))
+                    break;
+                popt++;
+            }
+            if (popt->flags & HAS_ARG) {
+                if (optind >= argc) {
+                    fprintf(stderr, "%s: option '%s' requires an argument\n",
+                            argv[0], r);
+                    exit(1);
+                }
+                optarg = argv[optind++];
+            } else {
+                optarg = NULL;
+            }
+
+            switch(popt->index) {
+            case QEMU_OPTION_M:
+                machine = find_machine(optarg);
+                if (!machine) {
+                    QEMUMachine *m;
+                    printf("Supported machines are:\n");
+                    for(m = first_machine; m != NULL; m = m->next) {
+                        printf("%-10s %s%s\n",
+                               m->name, m->desc,
+                               m->is_default ? " (default)" : "");
+                    }
+                    exit(*optarg != '?');
+                }
+                break;
+            case QEMU_OPTION_cpu:
+                /* hw initialization will check this */
+                if (*optarg == '?') {
+/* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list)
+                    cpu_list(stdout, &fprintf);
+#endif
+                    exit(0);
+                } else {
+                    cpu_model = optarg;
+                }
+                break;
+            case QEMU_OPTION_initrd:
+                initrd_filename = optarg;
+                break;
+            case QEMU_OPTION_hda:
+                if (cyls == 0)
+                    hda_index = drive_add(optarg, HD_ALIAS, 0);
+                else
+                    hda_index = drive_add(optarg, HD_ALIAS
+			     ",cyls=%d,heads=%d,secs=%d%s",
+                             0, cyls, heads, secs,
+                             translation == BIOS_ATA_TRANSLATION_LBA ?
+                                 ",trans=lba" :
+                             translation == BIOS_ATA_TRANSLATION_NONE ?
+                                 ",trans=none" : "");
+                 break;
+            case QEMU_OPTION_hdb:
+            case QEMU_OPTION_hdc:
+            case QEMU_OPTION_hdd:
+                drive_add(optarg, HD_ALIAS, popt->index - QEMU_OPTION_hda);
+                break;
+            case QEMU_OPTION_drive:
+                drive_add(NULL, "%s", optarg);
+	        break;
+            case QEMU_OPTION_mtdblock:
+                drive_add(optarg, MTD_ALIAS);
+                break;
+            case QEMU_OPTION_sd:
+                drive_add(optarg, SD_ALIAS);
+                break;
+            case QEMU_OPTION_pflash:
+                drive_add(optarg, PFLASH_ALIAS);
+                break;
+            case QEMU_OPTION_snapshot:
+                snapshot = 1;
+                break;
+            case QEMU_OPTION_hdachs:
+                {
+                    const char *p;
+                    p = optarg;
+                    cyls = strtol(p, (char **)&p, 0);
+                    if (cyls < 1 || cyls > 16383)
+                        goto chs_fail;
+                    if (*p != ',')
+                        goto chs_fail;
+                    p++;
+                    heads = strtol(p, (char **)&p, 0);
+                    if (heads < 1 || heads > 16)
+                        goto chs_fail;
+                    if (*p != ',')
+                        goto chs_fail;
+                    p++;
+                    secs = strtol(p, (char **)&p, 0);
+                    if (secs < 1 || secs > 63)
+                        goto chs_fail;
+                    if (*p == ',') {
+                        p++;
+                        if (!strcmp(p, "none"))
+                            translation = BIOS_ATA_TRANSLATION_NONE;
+                        else if (!strcmp(p, "lba"))
+                            translation = BIOS_ATA_TRANSLATION_LBA;
+                        else if (!strcmp(p, "auto"))
+                            translation = BIOS_ATA_TRANSLATION_AUTO;
+                        else
+                            goto chs_fail;
+                    } else if (*p != '\0') {
+                    chs_fail:
+                        fprintf(stderr, "qemu: invalid physical CHS format\n");
+                        exit(1);
+                    }
+		    if (hda_index != -1)
+                        snprintf(drives_opt[hda_index].opt,
+                                 sizeof(drives_opt[hda_index].opt),
+                                 HD_ALIAS ",cyls=%d,heads=%d,secs=%d%s",
+                                 0, cyls, heads, secs,
+			         translation == BIOS_ATA_TRANSLATION_LBA ?
+			     	    ",trans=lba" :
+			         translation == BIOS_ATA_TRANSLATION_NONE ?
+			             ",trans=none" : "");
+                }
+                break;
+            case QEMU_OPTION_numa:
+                if (nb_numa_nodes >= MAX_NODES) {
+                    fprintf(stderr, "qemu: too many NUMA nodes\n");
+                    exit(1);
+                }
+                numa_add(optarg);
+                break;
+            case QEMU_OPTION_nographic:
+                display_type = DT_NOGRAPHIC;
+                break;
+#ifdef CONFIG_CURSES
+            case QEMU_OPTION_curses:
+                display_type = DT_CURSES;
+                break;
+#endif
+            case QEMU_OPTION_portrait:
+                graphic_rotate = 1;
+                break;
+            case QEMU_OPTION_kernel:
+                kernel_filename = optarg;
+                break;
+            case QEMU_OPTION_append:
+                kernel_cmdline = optarg;
+                break;
+            case QEMU_OPTION_cdrom:
+                drive_add(optarg, CDROM_ALIAS);
+                break;
+            case QEMU_OPTION_boot:
+                boot_devices = optarg;
+                /* We just do some generic consistency checks */
+                {
+                    /* Could easily be extended to 64 devices if needed */
+                    const char *p;
+                    
+                    boot_devices_bitmap = 0;
+                    for (p = boot_devices; *p != '\0'; p++) {
+                        /* Allowed boot devices are:
+                         * a b     : floppy disk drives
+                         * c ... f : IDE disk drives
+                         * g ... m : machine implementation dependant drives
+                         * n ... p : network devices
+                         * It's up to each machine implementation to check
+                         * if the given boot devices match the actual hardware
+                         * implementation and firmware features.
+                         */
+                        if (*p < 'a' || *p > 'q') {
+                            fprintf(stderr, "Invalid boot device '%c'\n", *p);
+                            exit(1);
+                        }
+                        if (boot_devices_bitmap & (1 << (*p - 'a'))) {
+                            fprintf(stderr,
+                                    "Boot device '%c' was given twice\n",*p);
+                            exit(1);
+                        }
+                        boot_devices_bitmap |= 1 << (*p - 'a');
+                    }
+                }
+                break;
+            case QEMU_OPTION_fda:
+            case QEMU_OPTION_fdb:
+                drive_add(optarg, FD_ALIAS, popt->index - QEMU_OPTION_fda);
+                break;
+#ifdef TARGET_I386
+            case QEMU_OPTION_no_fd_bootchk:
+                fd_bootchk = 0;
+                break;
+#endif
+            case QEMU_OPTION_net:
+                if (nb_net_clients >= MAX_NET_CLIENTS) {
+                    fprintf(stderr, "qemu: too many network clients\n");
+                    exit(1);
+                }
+                net_clients[nb_net_clients] = optarg;
+                nb_net_clients++;
+                break;
+#ifdef CONFIG_SLIRP
+            case QEMU_OPTION_tftp:
+		tftp_prefix = optarg;
+                break;
+            case QEMU_OPTION_bootp:
+                bootp_filename = optarg;
+                break;
+#if 0  /* ANDROID disabled */
+#ifndef _WIN32
+            case QEMU_OPTION_smb:
+		net_slirp_smb(optarg);
+                break;
+#endif
+#endif /* ANDROID */
+            case QEMU_OPTION_redir:
+                net_slirp_redir(NULL, optarg, NULL);
+                break;
+#endif
+            case QEMU_OPTION_bt:
+                if (nb_bt_opts >= MAX_BT_CMDLINE) {
+                    fprintf(stderr, "qemu: too many bluetooth options\n");
+                    exit(1);
+                }
+                bt_opts[nb_bt_opts++] = optarg;
+                break;
+#ifdef HAS_AUDIO
+            case QEMU_OPTION_audio_help:
+                AUD_help ();
+                exit (0);
+                break;
+            case QEMU_OPTION_soundhw:
+                select_soundhw (optarg);
+                break;
+#endif
+            case QEMU_OPTION_h:
+                qemu_help(0);
+                break;
+            case QEMU_OPTION_version:
+                version();
+                exit(0);
+                break;
+            case QEMU_OPTION_m: {
+                uint64_t value;
+                char *ptr;
+
+                value = strtoul(optarg, &ptr, 10);
+                switch (*ptr) {
+                case 0: case 'M': case 'm':
+                    value <<= 20;
+                    break;
+                case 'G': case 'g':
+                    value <<= 30;
+                    break;
+                default:
+                    fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
+                    exit(1);
+                }
+
+                /* On 32-bit hosts, QEMU is limited by virtual address space */
+                if (value > (2047 << 20)
+#ifndef CONFIG_KQEMU
+                    && HOST_LONG_BITS == 32
+#endif
+                    ) {
+                    fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n");
+                    exit(1);
+                }
+                if (value != (uint64_t)(ram_addr_t)value) {
+                    fprintf(stderr, "qemu: ram size too large\n");
+                    exit(1);
+                }
+                ram_size = value;
+                break;
+            }
+            case QEMU_OPTION_d:
+                {
+                    int mask;
+                    const CPULogItem *item;
+
+                    mask = cpu_str_to_log_mask(optarg);
+                    if (!mask) {
+                        printf("Log items (comma separated):\n");
+                    for(item = cpu_log_items; item->mask != 0; item++) {
+                        printf("%-10s %s\n", item->name, item->help);
+                    }
+                    exit(1);
+                    }
+                    cpu_set_log(mask);
+                }
+                break;
+            case QEMU_OPTION_s:
+                gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
+                break;
+            case QEMU_OPTION_gdb:
+                gdbstub_dev = optarg;
+                break;
+            case QEMU_OPTION_L:
+                data_dir = optarg;
+                break;
+            case QEMU_OPTION_bios:
+                bios_name = optarg;
+                break;
+            case QEMU_OPTION_singlestep:
+                singlestep = 1;
+                break;
+            case QEMU_OPTION_S:
+#if 0  /* ANDROID */
+                fprintf(stderr, "Sorry, stopped launch is not supported in the Android emulator\n" );
+                exit(1);
+#endif
+                autostart = 0;
+                break;
+#ifndef _WIN32
+	    case QEMU_OPTION_k:
+		keyboard_layout = optarg;
+		break;
+#endif
+            case QEMU_OPTION_localtime:
+                rtc_utc = 0;
+                break;
+            case QEMU_OPTION_vga:
+                select_vgahw (optarg);
+                break;
+#if defined(TARGET_PPC) || defined(TARGET_SPARC)
+            case QEMU_OPTION_g:
+                {
+                    const char *p;
+                    int w, h, depth;
+                    p = optarg;
+                    w = strtol(p, (char **)&p, 10);
+                    if (w <= 0) {
+                    graphic_error:
+                        fprintf(stderr, "qemu: invalid resolution or depth\n");
+                        exit(1);
+                    }
+                    if (*p != 'x')
+                        goto graphic_error;
+                    p++;
+                    h = strtol(p, (char **)&p, 10);
+                    if (h <= 0)
+                        goto graphic_error;
+                    if (*p == 'x') {
+                        p++;
+                        depth = strtol(p, (char **)&p, 10);
+                        if (depth != 8 && depth != 15 && depth != 16 &&
+                            depth != 24 && depth != 32)
+                            goto graphic_error;
+                    } else if (*p == '\0') {
+                        depth = graphic_depth;
+                    } else {
+                        goto graphic_error;
+                    }
+
+                    graphic_width = w;
+                    graphic_height = h;
+                    graphic_depth = depth;
+                }
+                break;
+#endif
+            case QEMU_OPTION_echr:
+                {
+                    char *r;
+                    term_escape_char = strtol(optarg, &r, 0);
+                    if (r == optarg)
+                        printf("Bad argument to echr\n");
+                    break;
+                }
+            case QEMU_OPTION_monitor:
+                monitor_device = optarg;
+                break;
+            case QEMU_OPTION_serial:
+                if (serial_device_index >= MAX_SERIAL_PORTS) {
+                    fprintf(stderr, "qemu: too many serial ports\n");
+                    exit(1);
+                }
+                serial_devices[serial_device_index] = optarg;
+                serial_device_index++;
+                break;
+            case QEMU_OPTION_watchdog:
+                i = select_watchdog(optarg);
+                if (i > 0)
+                    exit (i == 1 ? 1 : 0);
+                break;
+            case QEMU_OPTION_watchdog_action:
+                if (select_watchdog_action(optarg) == -1) {
+                    fprintf(stderr, "Unknown -watchdog-action parameter\n");
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_virtiocon:
+                if (virtio_console_index >= MAX_VIRTIO_CONSOLES) {
+                    fprintf(stderr, "qemu: too many virtio consoles\n");
+                    exit(1);
+                }
+                virtio_consoles[virtio_console_index] = optarg;
+                virtio_console_index++;
+                break;
+            case QEMU_OPTION_parallel:
+                if (parallel_device_index >= MAX_PARALLEL_PORTS) {
+                    fprintf(stderr, "qemu: too many parallel ports\n");
+                    exit(1);
+                }
+                parallel_devices[parallel_device_index] = optarg;
+                parallel_device_index++;
+                break;
+	    case QEMU_OPTION_loadvm:
+		loadvm = optarg;
+		break;
+            case QEMU_OPTION_full_screen:
+                full_screen = 1;
+                break;
+#ifdef CONFIG_SDL
+            case QEMU_OPTION_no_frame:
+                no_frame = 1;
+                break;
+            case QEMU_OPTION_alt_grab:
+                alt_grab = 1;
+                break;
+            case QEMU_OPTION_no_quit:
+                no_quit = 1;
+                break;
+            case QEMU_OPTION_sdl:
+                display_type = DT_SDL;
+                break;
+#endif
+            case QEMU_OPTION_pidfile:
+                pid_file = optarg;
+                break;
+#ifdef TARGET_I386
+            case QEMU_OPTION_win2k_hack:
+                win2k_install_hack = 1;
+                break;
+            case QEMU_OPTION_rtc_td_hack:
+                rtc_td_hack = 1;
+                break;
+            case QEMU_OPTION_acpitable:
+                if(acpi_table_add(optarg) < 0) {
+                    fprintf(stderr, "Wrong acpi table provided\n");
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_smbios:
+                if(smbios_entry_add(optarg) < 0) {
+                    fprintf(stderr, "Wrong smbios provided\n");
+                    exit(1);
+                }
+                break;
+#endif
+#ifdef CONFIG_KQEMU
+            case QEMU_OPTION_no_kqemu:
+                kqemu_allowed = 0;
+                break;
+            case QEMU_OPTION_kernel_kqemu:
+                kqemu_allowed = 2;
+                break;
+#endif
+#ifdef CONFIG_KVM
+            case QEMU_OPTION_enable_kvm:
+                kvm_allowed = 1;
+#ifdef CONFIG_KQEMU
+                kqemu_allowed = 0;
+#endif
+                break;
+#endif
+            case QEMU_OPTION_usb:
+                usb_enabled = 1;
+                break;
+            case QEMU_OPTION_usbdevice:
+                usb_enabled = 1;
+                if (usb_devices_index >= MAX_USB_CMDLINE) {
+                    fprintf(stderr, "Too many USB devices\n");
+                    exit(1);
+                }
+                usb_devices[usb_devices_index] = optarg;
+                usb_devices_index++;
+                break;
+            case QEMU_OPTION_smp:
+                smp_cpus = atoi(optarg);
+                if (smp_cpus < 1) {
+                    fprintf(stderr, "Invalid number of CPUs\n");
+                    exit(1);
+                }
+                break;
+	    case QEMU_OPTION_vnc:
+                display_type = DT_VNC;
+		vnc_display = optarg;
+		break;
+#ifdef TARGET_I386
+            case QEMU_OPTION_no_acpi:
+                acpi_enabled = 0;
+                break;
+            case QEMU_OPTION_no_hpet:
+                no_hpet = 1;
+                break;
+            case QEMU_OPTION_no_virtio_balloon:
+                no_virtio_balloon = 1;
+                break;
+#endif
+            case QEMU_OPTION_no_reboot:
+                no_reboot = 1;
+                break;
+            case QEMU_OPTION_no_shutdown:
+                no_shutdown = 1;
+                break;
+            case QEMU_OPTION_show_cursor:
+                cursor_hide = 0;
+                break;
+            case QEMU_OPTION_uuid:
+                if(qemu_uuid_parse(optarg, qemu_uuid) < 0) {
+                    fprintf(stderr, "Fail to parse UUID string."
+                            " Wrong format.\n");
+                    exit(1);
+                }
+                break;
+#ifndef _WIN32
+	    case QEMU_OPTION_daemonize:
+		daemonize = 1;
+		break;
+#endif
+	    case QEMU_OPTION_option_rom:
+		if (nb_option_roms >= MAX_OPTION_ROMS) {
+		    fprintf(stderr, "Too many option ROMs\n");
+		    exit(1);
+		}
+		option_rom[nb_option_roms] = optarg;
+		nb_option_roms++;
+		break;
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
+            case QEMU_OPTION_semihosting:
+                semihosting_enabled = 1;
+                break;
+#endif
+            case QEMU_OPTION_name:
+                qemu_name = optarg;
+                break;
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
+            case QEMU_OPTION_prom_env:
+                if (nb_prom_envs >= MAX_PROM_ENVS) {
+                    fprintf(stderr, "Too many prom variables\n");
+                    exit(1);
+                }
+                prom_envs[nb_prom_envs] = optarg;
+                nb_prom_envs++;
+                break;
+#endif
+#ifdef TARGET_ARM
+            case QEMU_OPTION_old_param:
+                old_param = 1;
+                break;
+#endif
+            case QEMU_OPTION_clock:
+                configure_alarms(optarg);
+                break;
+            case QEMU_OPTION_startdate:
+                {
+                    struct tm tm;
+                    time_t rtc_start_date;
+                    if (!strcmp(optarg, "now")) {
+                        rtc_date_offset = -1;
+                    } else {
+                        if (sscanf(optarg, "%d-%d-%dT%d:%d:%d",
+                               &tm.tm_year,
+                               &tm.tm_mon,
+                               &tm.tm_mday,
+                               &tm.tm_hour,
+                               &tm.tm_min,
+                               &tm.tm_sec) == 6) {
+                            /* OK */
+                        } else if (sscanf(optarg, "%d-%d-%d",
+                                          &tm.tm_year,
+                                          &tm.tm_mon,
+                                          &tm.tm_mday) == 3) {
+                            tm.tm_hour = 0;
+                            tm.tm_min = 0;
+                            tm.tm_sec = 0;
+                        } else {
+                            goto date_fail;
+                        }
+                        tm.tm_year -= 1900;
+                        tm.tm_mon--;
+                        rtc_start_date = mktimegm(&tm);
+                        if (rtc_start_date == -1) {
+                        date_fail:
+                            fprintf(stderr, "Invalid date format. Valid format are:\n"
+                                    "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n");
+                            exit(1);
+                        }
+                        rtc_date_offset = time(NULL) - rtc_start_date;
+                    }
+                }
+                break;
+            case QEMU_OPTION_tb_size:
+                tb_size = strtol(optarg, NULL, 0);
+                if (tb_size < 0)
+                    tb_size = 0;
+                break;
+            case QEMU_OPTION_icount:
+                use_icount = 1;
+                if (strcmp(optarg, "auto") == 0) {
+                    icount_time_shift = -1;
+                } else {
+                    icount_time_shift = strtol(optarg, NULL, 0);
+                }
+                break;
+            case QEMU_OPTION_incoming:
+                incoming = optarg;
+                break;
+#ifndef _WIN32
+            case QEMU_OPTION_chroot:
+                chroot_dir = optarg;
+                break;
+            case QEMU_OPTION_runas:
+                run_as = optarg;
+                break;
+#endif
+#ifdef CONFIG_XEN
+            case QEMU_OPTION_xen_domid:
+                xen_domid = atoi(optarg);
+                break;
+            case QEMU_OPTION_xen_create:
+                xen_mode = XEN_CREATE;
+                break;
+            case QEMU_OPTION_xen_attach:
+                xen_mode = XEN_ATTACH;
+                break;
+#endif
+
+
+            case QEMU_OPTION_mic:
+                audio_input_source = (char*)optarg;
+                break;
+#ifdef CONFIG_TRACE
+            case QEMU_OPTION_trace:
+                trace_filename = optarg;
+                tracing = 1;
+                break;
+#if 0
+            case QEMU_OPTION_trace_miss:
+                trace_cache_miss = 1;
+                break;
+            case QEMU_OPTION_trace_addr:
+                trace_all_addr = 1;
+                break;
+#endif
+            case QEMU_OPTION_tracing:
+                if (strcmp(optarg, "off") == 0)
+                    tracing = 0;
+                else if (strcmp(optarg, "on") == 0 && trace_filename)
+                    tracing = 1;
+                else {
+                    fprintf(stderr, "Unexpected option to -tracing ('%s')\n",
+                            optarg);
+                    exit(1);
+                }
+                break;
+#if 0
+            case QEMU_OPTION_dcache_load_miss:
+                dcache_load_miss_penalty = atoi(optarg);
+                break;
+            case QEMU_OPTION_dcache_store_miss:
+                dcache_store_miss_penalty = atoi(optarg);
+                break;
+#endif
+#endif
+#ifdef CONFIG_NAND
+            case QEMU_OPTION_nand:
+                nand_add_dev(optarg);
+                break;
+#endif
+            }
+        }
+    }
+
+    /* If no data_dir is specified then try to find it relative to the
+       executable path.  */
+    if (!data_dir) {
+        data_dir = find_datadir(argv[0]);
+    }
+    /* If all else fails use the install patch specified when building.  */
+    if (!data_dir) {
+        data_dir = CONFIG_QEMU_SHAREDIR;
+    }
+
+#if defined(CONFIG_KVM) && defined(CONFIG_KQEMU)
+    if (kvm_allowed && kqemu_allowed) {
+        fprintf(stderr,
+                "You can not enable both KVM and kqemu at the same time\n");
+        exit(1);
+    }
+#endif
+
+    machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
+    if (smp_cpus > machine->max_cpus) {
+        fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus "
+                "supported by machine `%s' (%d)\n", smp_cpus,  machine->name,
+                machine->max_cpus);
+        exit(1);
+    }
+
+    if (display_type == DT_NOGRAPHIC) {
+       if (serial_device_index == 0)
+           serial_devices[0] = "stdio";
+       if (parallel_device_index == 0)
+           parallel_devices[0] = "null";
+       if (strncmp(monitor_device, "vc", 2) == 0)
+           monitor_device = "stdio";
+    }
+
+#ifndef _WIN32
+    if (daemonize) {
+	pid_t pid;
+
+	if (pipe(fds) == -1)
+	    exit(1);
+
+	pid = fork();
+	if (pid > 0) {
+	    uint8_t status;
+	    ssize_t len;
+
+	    close(fds[1]);
+
+	again:
+            len = read(fds[0], &status, 1);
+            if (len == -1 && (errno == EINTR))
+                goto again;
+
+            if (len != 1)
+                exit(1);
+            else if (status == 1) {
+                fprintf(stderr, "Could not acquire pidfile\n");
+                exit(1);
+            } else
+                exit(0);
+	} else if (pid < 0)
+            exit(1);
+
+	setsid();
+
+	pid = fork();
+	if (pid > 0)
+	    exit(0);
+	else if (pid < 0)
+	    exit(1);
+
+	umask(027);
+
+        signal(SIGTSTP, SIG_IGN);
+        signal(SIGTTOU, SIG_IGN);
+        signal(SIGTTIN, SIG_IGN);
+    }
+
+    if (pid_file && qemu_create_pidfile(pid_file) != 0) {
+        if (daemonize) {
+            uint8_t status = 1;
+            write(fds[1], &status, 1);
+        } else
+            fprintf(stderr, "Could not acquire pid file\n");
+        exit(1);
+    }
+#endif
+
+#ifdef CONFIG_KQEMU
+    if (smp_cpus > 1)
+        kqemu_allowed = 0;
+#endif
+    if (qemu_init_main_loop()) {
+        fprintf(stderr, "qemu_init_main_loop failed\n");
+        exit(1);
+    }
+    linux_boot = (kernel_filename != NULL);
+    net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
+
+    if (!linux_boot && *kernel_cmdline != '\0') {
+        fprintf(stderr, "-append only allowed with -kernel option\n");
+        exit(1);
+    }
+
+    if (!linux_boot && initrd_filename != NULL) {
+        fprintf(stderr, "-initrd only allowed with -kernel option\n");
+        exit(1);
+    }
+
+    /* boot to floppy or the default cd if no hard disk defined yet */
+    if (!boot_devices[0]) {
+        boot_devices = "cad";
+    }
+    setvbuf(stdout, NULL, _IOLBF, 0);
+
+    init_timers();
+    if (init_timer_alarm() < 0) {
+        fprintf(stderr, "could not initialize alarm timer\n");
+        exit(1);
+    }
+    if (use_icount && icount_time_shift < 0) {
+        use_icount = 2;
+        /* 125MIPS seems a reasonable initial guess at the guest speed.
+           It will be corrected fairly quickly anyway.  */
+        icount_time_shift = 3;
+        init_icount_adjust();
+    }
+
+#ifdef _WIN32
+    socket_init();
+#endif
+
+    /* init network clients */
+    if (nb_net_clients == 0) {
+        /* if no clients, we use a default config */
+        net_clients[nb_net_clients++] = "nic";
+#ifdef CONFIG_SLIRP
+        net_clients[nb_net_clients++] = "user";
+#endif
+    }
+
+    for(i = 0;i < nb_net_clients; i++) {
+        if (net_client_parse(net_clients[i]) < 0)
+            exit(1);
+    }
+    net_client_check();
+
+#ifdef TARGET_I386
+    /* XXX: this should be moved in the PC machine instantiation code */
+    if (net_boot != 0) {
+        int netroms = 0;
+	for (i = 0; i < nb_nics && i < 4; i++) {
+	    const char *model = nd_table[i].model;
+	    char buf[1024];
+            char *filename;
+            if (net_boot & (1 << i)) {
+                if (model == NULL)
+                    model = "ne2k_pci";
+                snprintf(buf, sizeof(buf), "pxe-%s.bin", model);
+                filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, buf);
+                if (filename && get_image_size(filename) > 0) {
+                    if (nb_option_roms >= MAX_OPTION_ROMS) {
+                        fprintf(stderr, "Too many option ROMs\n");
+                        exit(1);
+                    }
+                    option_rom[nb_option_roms] = qemu_strdup(buf);
+                    nb_option_roms++;
+                    netroms++;
+                }
+                if (filename) {
+                    qemu_free(filename);
+                }
+            }
+	}
+	if (netroms == 0) {
+	    fprintf(stderr, "No valid PXE rom found for network device\n");
+	    exit(1);
+	}
+    }
+#endif
+
+    /* init the bluetooth world */
+    for (i = 0; i < nb_bt_opts; i++)
+        if (bt_parse(bt_opts[i]))
+            exit(1);
+
+    /* init the memory */
+    if (ram_size == 0)
+        ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
+
+#ifdef CONFIG_KQEMU
+    /* FIXME: This is a nasty hack because kqemu can't cope with dynamic
+       guest ram allocation.  It needs to go away.  */
+    if (kqemu_allowed) {
+        kqemu_phys_ram_size = ram_size + 8 * 1024 * 1024 + 4 * 1024 * 1024;
+        kqemu_phys_ram_base = qemu_vmalloc(kqemu_phys_ram_size);
+        if (!kqemu_phys_ram_base) {
+            fprintf(stderr, "Could not allocate physical memory\n");
+            exit(1);
+        }
+    }
+#endif
+
+    /* init the dynamic translator */
+    cpu_exec_init_all(tb_size * 1024 * 1024);
+
+    bdrv_init();
+
+    /* we always create the cdrom drive, even if no disk is there */
+
+    if (nb_drives_opt < MAX_DRIVES)
+        drive_add(NULL, CDROM_ALIAS);
+
+    /* we always create at least one floppy */
+
+    if (nb_drives_opt < MAX_DRIVES)
+        drive_add(NULL, FD_ALIAS, 0);
+
+    /* we always create one sd slot, even if no card is in it */
+
+    if (nb_drives_opt < MAX_DRIVES)
+        drive_add(NULL, SD_ALIAS);
+
+    /* open the virtual block devices */
+
+    for(i = 0; i < nb_drives_opt; i++)
+        if (drive_init(&drives_opt[i], snapshot, machine) == -1)
+	    exit(1);
+
+    register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
+    register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL);
+
+#ifndef _WIN32
+    /* must be after terminal init, SDL library changes signal handlers */
+    sighandler_setup();
+#endif
+
+    /* Maintain compatibility with multiple stdio monitors */
+    if (!strcmp(monitor_device,"stdio")) {
+        for (i = 0; i < MAX_SERIAL_PORTS; i++) {
+            const char *devname = serial_devices[i];
+            if (devname && !strcmp(devname,"mon:stdio")) {
+                monitor_device = NULL;
+                break;
+            } else if (devname && !strcmp(devname,"stdio")) {
+                monitor_device = NULL;
+                serial_devices[i] = "mon:stdio";
+                break;
+            }
+        }
+    }
+
+    if (nb_numa_nodes > 0) {
+        int i;
+
+        if (nb_numa_nodes > smp_cpus) {
+            nb_numa_nodes = smp_cpus;
+        }
+
+        /* If no memory size if given for any node, assume the default case
+         * and distribute the available memory equally across all nodes
+         */
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_mem[i] != 0)
+                break;
+        }
+        if (i == nb_numa_nodes) {
+            uint64_t usedmem = 0;
+
+            /* On Linux, the each node's border has to be 8MB aligned,
+             * the final node gets the rest.
+             */
+            for (i = 0; i < nb_numa_nodes - 1; i++) {
+                node_mem[i] = (ram_size / nb_numa_nodes) & ~((1 << 23UL) - 1);
+                usedmem += node_mem[i];
+            }
+            node_mem[i] = ram_size - usedmem;
+        }
+
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_cpumask[i] != 0)
+                break;
+        }
+        /* assigning the VCPUs round-robin is easier to implement, guest OSes
+         * must cope with this anyway, because there are BIOSes out there in
+         * real machines which also use this scheme.
+         */
+        if (i == nb_numa_nodes) {
+            for (i = 0; i < smp_cpus; i++) {
+                node_cpumask[i % nb_numa_nodes] |= 1 << i;
+            }
+        }
+    }
+
+    if (kvm_enabled()) {
+        int ret;
+
+        ret = kvm_init(smp_cpus);
+        if (ret < 0) {
+            fprintf(stderr, "failed to initialize KVM\n");
+            exit(1);
+        }
+    }
+
+    if (monitor_device) {
+        monitor_hd = qemu_chr_open("monitor", monitor_device, NULL);
+        if (!monitor_hd) {
+            fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
+            exit(1);
+        }
+    }
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        const char *devname = serial_devices[i];
+        if (devname && strcmp(devname, "none")) {
+            char label[32];
+            snprintf(label, sizeof(label), "serial%d", i);
+            serial_hds[i] = qemu_chr_open(label, devname, NULL);
+            if (!serial_hds[i]) {
+                fprintf(stderr, "qemu: could not open serial device '%s'\n",
+                        devname);
+                exit(1);
+            }
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        const char *devname = parallel_devices[i];
+        if (devname && strcmp(devname, "none")) {
+            char label[32];
+            snprintf(label, sizeof(label), "parallel%d", i);
+            parallel_hds[i] = qemu_chr_open(label, devname, NULL);
+            if (!parallel_hds[i]) {
+                fprintf(stderr, "qemu: could not open parallel device '%s'\n",
+                        devname);
+                exit(1);
+            }
+        }
+    }
+
+    for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+        const char *devname = virtio_consoles[i];
+        if (devname && strcmp(devname, "none")) {
+            char label[32];
+            snprintf(label, sizeof(label), "virtcon%d", i);
+            virtcon_hds[i] = qemu_chr_open(label, devname, NULL);
+            if (!virtcon_hds[i]) {
+                fprintf(stderr, "qemu: could not open virtio console '%s'\n",
+                        devname);
+                exit(1);
+            }
+        }
+    }
+
+    module_call_init(MODULE_INIT_DEVICE);
+
+
+#ifdef CONFIG_TRACE
+    if (trace_filename) {
+        trace_init(trace_filename);
+#if 0
+        // We don't need the dcache code until we can get load and store tracing
+        // working again.
+        dcache_init(dcache_size, dcache_ways, dcache_line_size,
+                    dcache_replace_policy, dcache_load_miss_penalty,
+                    dcache_store_miss_penalty);
+#endif
+        fprintf(stderr, "-- When done tracing, exit the emulator. --\n");
+    }
+#endif
+
+    machine->init(ram_size, boot_devices,
+                  kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
+
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_cpumask[i] & (1 << env->cpu_index)) {
+                env->numa_node = i;
+            }
+        }
+    }
+
+    current_machine = machine;
+
+    /* Set KVM's vcpu state to qemu's initial CPUState. */
+    if (kvm_enabled()) {
+        int ret;
+
+        ret = kvm_sync_vcpus();
+        if (ret < 0) {
+            fprintf(stderr, "failed to initialize vcpus\n");
+            exit(1);
+        }
+    }
+
+    /* init USB devices */
+    if (usb_enabled) {
+        for(i = 0; i < usb_devices_index; i++) {
+            if (usb_device_add(usb_devices[i], 0) < 0) {
+                fprintf(stderr, "Warning: could not add USB device %s\n",
+                        usb_devices[i]);
+            }
+        }
+    }
+
+    if (!display_state)
+        dumb_display_init();
+    /* just use the first displaystate for the moment */
+    ds = display_state;
+
+    if (display_type == DT_DEFAULT) {
+#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+        display_type = DT_SDL;
+#else
+        display_type = DT_VNC;
+        vnc_display = "localhost:0,to=99";
+        show_vnc_port = 1;
+#endif
+    }
+        
+
+    switch (display_type) {
+    case DT_NOGRAPHIC:
+        break;
+#if defined(CONFIG_CURSES)
+    case DT_CURSES:
+        curses_display_init(ds, full_screen);
+        break;
+#endif
+#if defined(CONFIG_SDL)
+    case DT_SDL:
+        sdl_display_init(ds, full_screen, no_frame);
+        break;
+#elif defined(CONFIG_COCOA)
+    case DT_SDL:
+        cocoa_display_init(ds, full_screen);
+        break;
+#endif
+    case DT_VNC:
+        vnc_display_init(ds);
+        if (vnc_display_open(ds, vnc_display) < 0)
+            exit(1);
+
+        if (show_vnc_port) {
+            printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
+        }
+        break;
+    default:
+        break;
+    }
+    dpy_resize(ds);
+
+    dcl = ds->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_refresh != NULL) {
+            ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
+            qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
+        }
+        dcl = dcl->next;
+    }
+
+    if (display_type == DT_NOGRAPHIC || display_type == DT_VNC) {
+        nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL);
+        qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
+    }
+
+    text_consoles_set_display(display_state);
+    qemu_chr_initial_reset();
+
+    if (monitor_device && monitor_hd)
+        monitor_init(monitor_hd, MONITOR_USE_READLINE | MONITOR_IS_DEFAULT);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        const char *devname = serial_devices[i];
+        if (devname && strcmp(devname, "none")) {
+            if (strstart(devname, "vc", 0))
+                qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i);
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        const char *devname = parallel_devices[i];
+        if (devname && strcmp(devname, "none")) {
+            if (strstart(devname, "vc", 0))
+                qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i);
+        }
+    }
+
+    for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+        const char *devname = virtio_consoles[i];
+        if (virtcon_hds[i] && devname) {
+            if (strstart(devname, "vc", 0))
+                qemu_chr_printf(virtcon_hds[i], "virtio console%d\r\n", i);
+        }
+    }
+
+    if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
+        fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
+                gdbstub_dev);
+        exit(1);
+    }
+
+    if (loadvm)
+        do_loadvm(cur_mon, loadvm);
+
+    /* call android-specific setup function */
+    android_emulation_setup();
+
+    if (incoming) {
+        autostart = 0; /* fixme how to deal with -daemonize */
+        qemu_start_incoming_migration(incoming);
+    }
+
+    if (autostart)
+        vm_start();
+
+#ifndef _WIN32
+    if (daemonize) {
+	uint8_t status = 0;
+	ssize_t len;
+
+    again1:
+	len = write(fds[1], &status, 1);
+	if (len == -1 && (errno == EINTR))
+	    goto again1;
+
+	if (len != 1)
+	    exit(1);
+
+	chdir("/");
+	TFR(fd = open("/dev/null", O_RDWR));
+	if (fd == -1)
+	    exit(1);
+    }
+
+    if (run_as) {
+        pwd = getpwnam(run_as);
+        if (!pwd) {
+            fprintf(stderr, "User \"%s\" doesn't exist\n", run_as);
+            exit(1);
+        }
+    }
+
+    if (chroot_dir) {
+        if (chroot(chroot_dir) < 0) {
+            fprintf(stderr, "chroot failed\n");
+            exit(1);
+        }
+        chdir("/");
+    }
+
+    if (run_as) {
+        if (setgid(pwd->pw_gid) < 0) {
+            fprintf(stderr, "Failed to setgid(%d)\n", pwd->pw_gid);
+            exit(1);
+        }
+        if (setuid(pwd->pw_uid) < 0) {
+            fprintf(stderr, "Failed to setuid(%d)\n", pwd->pw_uid);
+            exit(1);
+        }
+        if (setuid(0) != -1) {
+            fprintf(stderr, "Dropping privileges failed\n");
+            exit(1);
+        }
+    }
+
+    if (daemonize) {
+        dup2(fd, 0);
+        dup2(fd, 1);
+        dup2(fd, 2);
+
+        close(fd);
+    }
+#endif
+
+    main_loop();
+    quit_timers();
+    net_cleanup();
+    android_emulation_teardown();
+    return 0;
+}
diff --git a/vl.c b/vl.c
index e6a0305..3242c23 100644
--- a/vl.c
+++ b/vl.c
@@ -21,40 +21,6 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-
-/* the following is needed on Linux to define ptsname() in stdlib.h */
-#if defined(__linux__)
-#define _GNU_SOURCE 1
-#endif
-
-#include "qemu-common.h"
-#include "hw/hw.h"
-#include "hw/boards.h"
-#include "hw/usb.h"
-#include "hw/pcmcia.h"
-#include "hw/pc.h"
-#include "hw/audiodev.h"
-#include "hw/isa.h"
-#include "hw/baum.h"
-#include "net.h"
-#include "console.h"
-#include "sysemu.h"
-#include "gdbstub.h"
-#include "qemu-timer.h"
-#include "qemu-char.h"
-#include "block.h"
-#include "audio/audio.h"
-
-#include "qemu_file.h"
-#include "android/android.h"
-#include "charpipe.h"
-#include "shaper.h"
-#include "modem_driver.h"
-#include "android/gps.h"
-#include "android/hw-qemud.h"
-#include "android/hw-kmsg.h"
-#include "tcpdump.h"
-
 #include <unistd.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -63,33 +29,42 @@
 #include <sys/time.h>
 #include <zlib.h>
 
+/* Needed early for HOST_BSD etc. */
+#include "config-host.h"
+
 #ifndef _WIN32
+#include <libgen.h>
+#include <pwd.h>
 #include <sys/times.h>
 #include <sys/wait.h>
 #include <termios.h>
-#include <sys/poll.h>
 #include <sys/mman.h>
 #include <sys/ioctl.h>
+#include <sys/resource.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <net/if.h>
+#if defined(__NetBSD__)
+#include <net/if_tap.h>
+#endif
+#ifdef __linux__
+#include <linux/if_tun.h>
+#endif
+#include <arpa/inet.h>
 #include <dirent.h>
 #include <netdb.h>
 #include <sys/select.h>
-#include <arpa/inet.h>
-#ifdef _BSD
+#ifdef HOST_BSD
 #include <sys/stat.h>
-#if !defined(__APPLE__) && !defined(__OpenBSD__)
+#if defined(__FreeBSD__) || defined(__DragonFly__)
 #include <libutil.h>
-#endif
-#ifdef __OpenBSD__
-#include <net/if.h>
+#else
+#include <util.h>
 #endif
 #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
 #include <freebsd/stdlib.h>
 #else
-#ifndef __sun__
-#include <linux/if.h>
-#include <linux/if_tun.h>
+#ifdef __linux__
 #include <pty.h>
 #include <malloc.h>
 #include <linux/rtc.h>
@@ -101,7 +76,8 @@
 
 #include <linux/ppdev.h>
 #include <linux/parport.h>
-#else
+#endif
+#ifdef __sun__
 #include <sys/stat.h>
 #include <sys/ethernet.h>
 #include <sys/sockio.h>
@@ -119,12 +95,6 @@
 #endif
 #endif
 
-#include "qemu_socket.h"
-
-#if defined(CONFIG_SLIRP)
-#include "libslirp.h"
-#endif
-
 #if defined(__OpenBSD__)
 #include <util.h>
 #endif
@@ -134,6 +104,7 @@
 #endif
 
 #ifdef _WIN32
+#include <windows.h>
 #include <malloc.h>
 #include <sys/timeb.h>
 #include <mmsystem.h>
@@ -141,79 +112,111 @@
 #define memalign(align, size) malloc(size)
 #endif
 
+#ifdef CONFIG_SDL
+#ifdef __APPLE__
+#include <SDL.h>
+int qemu_main(int argc, char **argv, char **envp);
+int main(int argc, char **argv)
+{
+    qemu_main(argc, argv, NULL);
+}
+#undef main
+#define main qemu_main
+#endif
+#endif /* CONFIG_SDL */
 
 #ifdef CONFIG_COCOA
 #undef main
 #define main qemu_main
 #endif /* CONFIG_COCOA */
 
-#ifdef CONFIG_SKINS
-#undef main
-#define main qemu_main
-#endif
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/usb.h"
+#include "hw/pcmcia.h"
+#include "hw/pc.h"
+#include "hw/audiodev.h"
+#include "hw/isa.h"
+#include "hw/baum.h"
+#include "hw/bt.h"
+#include "hw/watchdog.h"
+#include "hw/smbios.h"
+#include "hw/xen.h"
+#include "bt-host.h"
+#include "net.h"
+#include "monitor.h"
+#include "console.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "cache-utils.h"
+#include "block.h"
+#include "dma.h"
+#include "audio/audio.h"
+#include "migration.h"
+#include "kvm.h"
+#include "balloon.h"
+#include "qemu-option.h"
 
 #include "disas.h"
 
 #include "exec-all.h"
 
-#ifdef CONFIG_TRACE
-#include "trace.h"
-#include "dcache.h"
-#endif
+#include "qemu_socket.h"
 
-#ifdef CONFIG_NAND
-#include "hw/goldfish_nand.h"
-#endif
-
-#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
-#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
-#ifdef __sun__
-#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
-#else
-#define SMBD_COMMAND "/usr/sbin/smbd"
+#if defined(CONFIG_SLIRP)
+#include "libslirp.h"
 #endif
 
 //#define DEBUG_UNUSED_IOPORT
 //#define DEBUG_IOPORT
+//#define DEBUG_NET
+//#define DEBUG_SLIRP
 
-#ifdef TARGET_PPC
-#define DEFAULT_RAM_SIZE 144
+
+#ifdef DEBUG_IOPORT
+#  define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
 #else
-#define DEFAULT_RAM_SIZE 128
+#  define LOG_IOPORT(...) do { } while (0)
 #endif
 
+#define DEFAULT_RAM_SIZE 128
+
 /* Max number of USB devices that can be specified on the commandline.  */
 #define MAX_USB_CMDLINE 8
 
+/* Max number of bluetooth switches on the commandline.  */
+#define MAX_BT_CMDLINE 10
+
 /* XXX: use a two level table to limit memory usage */
 #define MAX_IOPORTS 65536
 
-const char *bios_dir = CONFIG_QEMU_SHAREDIR;
+static const char *data_dir;
 const char *bios_name = NULL;
-void *ioport_opaque[MAX_IOPORTS];
-IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
-IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
+static void *ioport_opaque[MAX_IOPORTS];
+static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
+static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
 /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
    to store the VM snapshots */
 DriveInfo drives_table[MAX_DRIVES+1];
 int nb_drives;
-/* point to the block driver where the snapshots are managed */
-BlockDriverState *bs_snapshots;
-int vga_ram_size;
-static DisplayState display_state;
-int nographic;
-int curses;
+enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
+static DisplayState *display_state;
+DisplayType display_type = DT_DEFAULT;
 const char* keyboard_layout = NULL;
 int64_t ticks_per_sec;
 ram_addr_t ram_size;
-int pit_min_timer_count = 0;
 int nb_nics;
 NICInfo nd_table[MAX_NICS];
 int vm_running;
+static int autostart;
 static int rtc_utc = 1;
 static int rtc_date_offset = -1; /* -1 means no change */
 int cirrus_vga_enabled = 1;
+int std_vga_enabled = 0;
 int vmsvga_enabled = 0;
+int xenfb_enabled = 0;
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
 int graphic_height = 768;
@@ -223,70 +226,68 @@
 int graphic_height = 600;
 int graphic_depth = 15;
 #endif
-int full_screen = 0;
-int no_frame = 0;
+static int full_screen = 0;
+#ifdef CONFIG_SDL
+static int no_frame = 0;
+#endif
 int no_quit = 0;
 CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
+CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
 #ifdef TARGET_I386
 int win2k_install_hack = 0;
+int rtc_td_hack = 0;
 #endif
 int usb_enabled = 0;
-static VLANState *first_vlan;
+int singlestep = 0;
 int smp_cpus = 1;
 const char *vnc_display;
-#if defined(TARGET_SPARC)
-#define MAX_CPUS 16
-#elif defined(TARGET_I386)
-#define MAX_CPUS 255
-#else
-#define MAX_CPUS 1
-#endif
 int acpi_enabled = 1;
+int no_hpet = 0;
+int no_virtio_balloon = 0;
 int fd_bootchk = 1;
 int no_reboot = 0;
 int no_shutdown = 0;
 int cursor_hide = 1;
 int graphic_rotate = 0;
+#ifndef _WIN32
 int daemonize = 0;
+#endif
+WatchdogTimerModel *watchdog = NULL;
+int watchdog_action = WDT_RESET;
 const char *option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;
 int semihosting_enabled = 0;
-int autostart = 1;
 #ifdef TARGET_ARM
 int old_param = 0;
 #endif
 const char *qemu_name;
 int alt_grab = 0;
-#ifdef TARGET_SPARC
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
 unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];
 #endif
 int nb_drives_opt;
-struct drive_opt {
-    const char *file;
-    char opt[1024];
-} drives_opt[MAX_DRIVES];
+struct drive_opt drives_opt[MAX_DRIVES];
+
+int nb_numa_nodes;
+uint64_t node_mem[MAX_NODES];
+uint64_t node_cpumask[MAX_NODES];
 
 static CPUState *cur_cpu;
 static CPUState *next_cpu;
-static int event_pending = 1;
+static int timer_alarm_pending = 1;
 /* Conversion factor from emulated instructions to virtual clock ticks.  */
 static int icount_time_shift;
 /* Arbitrarily pick 1MIPS as the minimum allowable speed.  */
 #define MAX_ICOUNT_SHIFT 10
 /* Compensate for varying guest execution speed.  */
 static int64_t qemu_icount_bias;
-QEMUTimer *icount_rt_timer;
-QEMUTimer *icount_vm_timer;
+static QEMUTimer *icount_rt_timer;
+static QEMUTimer *icount_vm_timer;
+static QEMUTimer *nographic_timer;
 
-
-extern int   qemu_cpu_delay;
-extern char* audio_input_source;
-
-extern void  dprint( const char* format, ... );
-
-#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
+uint8_t qemu_uuid[16];
 
 /***********************************************************/
 /* x86 ISA bus support */
@@ -432,6 +433,8 @@
         ioport_write_table[0][i] = default_ioport_writeb;
         ioport_write_table[1][i] = default_ioport_writew;
         ioport_write_table[2][i] = default_ioport_writel;
+
+        ioport_opaque[i] = NULL;
     }
 }
 
@@ -439,12 +442,9 @@
 
 void cpu_outb(CPUState *env, int addr, int val)
 {
-#ifdef DEBUG_IOPORT
-    if (loglevel & CPU_LOG_IOPORT)
-        fprintf(logfile, "outb: %04x %02x\n", addr, val);
-#endif
+    LOG_IOPORT("outb: %04x %02x\n", addr, val);
     ioport_write(0, addr, val);
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     if (env)
         env->last_io_time = cpu_get_time_fast();
 #endif
@@ -452,12 +452,9 @@
 
 void cpu_outw(CPUState *env, int addr, int val)
 {
-#ifdef DEBUG_IOPORT
-    if (loglevel & CPU_LOG_IOPORT)
-        fprintf(logfile, "outw: %04x %04x\n", addr, val);
-#endif
+    LOG_IOPORT("outw: %04x %04x\n", addr, val);
     ioport_write(1, addr, val);
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     if (env)
         env->last_io_time = cpu_get_time_fast();
 #endif
@@ -465,12 +462,9 @@
 
 void cpu_outl(CPUState *env, int addr, int val)
 {
-#ifdef DEBUG_IOPORT
-    if (loglevel & CPU_LOG_IOPORT)
-        fprintf(logfile, "outl: %04x %08x\n", addr, val);
-#endif
+    LOG_IOPORT("outl: %04x %08x\n", addr, val);
     ioport_write(2, addr, val);
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     if (env)
         env->last_io_time = cpu_get_time_fast();
 #endif
@@ -480,11 +474,8 @@
 {
     int val;
     val = ioport_read(0, addr);
-#ifdef DEBUG_IOPORT
-    if (loglevel & CPU_LOG_IOPORT)
-        fprintf(logfile, "inb : %04x %02x\n", addr, val);
-#endif
-#ifdef USE_KQEMU
+    LOG_IOPORT("inb : %04x %02x\n", addr, val);
+#ifdef CONFIG_KQEMU
     if (env)
         env->last_io_time = cpu_get_time_fast();
 #endif
@@ -495,11 +486,8 @@
 {
     int val;
     val = ioport_read(1, addr);
-#ifdef DEBUG_IOPORT
-    if (loglevel & CPU_LOG_IOPORT)
-        fprintf(logfile, "inw : %04x %04x\n", addr, val);
-#endif
-#ifdef USE_KQEMU
+    LOG_IOPORT("inw : %04x %04x\n", addr, val);
+#ifdef CONFIG_KQEMU
     if (env)
         env->last_io_time = cpu_get_time_fast();
 #endif
@@ -510,11 +498,8 @@
 {
     int val;
     val = ioport_read(2, addr);
-#ifdef DEBUG_IOPORT
-    if (loglevel & CPU_LOG_IOPORT)
-        fprintf(logfile, "inl : %04x %08x\n", addr, val);
-#endif
-#ifdef USE_KQEMU
+    LOG_IOPORT("inl : %04x %08x\n", addr, val);
+#ifdef CONFIG_KQEMU
     if (env)
         env->last_io_time = cpu_get_time_fast();
 #endif
@@ -542,20 +527,37 @@
     va_end(ap);
     abort();
 }
+ 
+/***************/
+/* ballooning */
+
+static QEMUBalloonEvent *qemu_balloon_event;
+void *qemu_balloon_event_opaque;
+
+void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
+{
+    qemu_balloon_event = func;
+    qemu_balloon_event_opaque = opaque;
+}
+
+void qemu_balloon(ram_addr_t target)
+{
+    if (qemu_balloon_event)
+        qemu_balloon_event(qemu_balloon_event_opaque, target);
+}
+
+ram_addr_t qemu_balloon_status(void)
+{
+    if (qemu_balloon_event)
+        return qemu_balloon_event(qemu_balloon_event_opaque, 0);
+    return 0;
+}
 
 /***********************************************************/
 /* keyboard/mouse */
 
-static QEMUPutKBDEvent*  qemu_put_kbd_event;
-static void*             qemu_put_kbd_event_opaque;
-
-static QEMUPutKBDEventN*  qemu_put_kbd_event_n;
-static void*              qemu_put_kbd_event_n_opaque;
-
-
-static QEMUPutGenericEvent*  qemu_put_generic_event;
-static void*                 qemu_put_generic_event_opaque;
-
+static QEMUPutKBDEvent *qemu_put_kbd_event;
+static void *qemu_put_kbd_event_opaque;
 static QEMUPutMouseEntry *qemu_put_mouse_event_head;
 static QEMUPutMouseEntry *qemu_put_mouse_event_current;
 
@@ -565,20 +567,6 @@
     qemu_put_kbd_event = func;
 }
 
-void qemu_add_kbd_event_n_handler(QEMUPutKBDEventN *func, void *opaque)
-{
-    qemu_put_kbd_event_n_opaque = opaque;
-    qemu_put_kbd_event_n = func;
-}
-
-#if 0
-void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute)
-{
-    qemu_put_mouse_event_opaque = opaque;
-    qemu_put_mouse_event = func;
-    qemu_put_mouse_event_absolute = absolute;
-}
-#else
 QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
                                                 void *opaque, int absolute,
                                                 const char *name)
@@ -586,8 +574,6 @@
     QEMUPutMouseEntry *s, *cursor;
 
     s = qemu_mallocz(sizeof(QEMUPutMouseEntry));
-    if (!s)
-        return NULL;
 
     s->qemu_put_mouse_event = func;
     s->qemu_put_mouse_event_opaque = opaque;
@@ -642,13 +628,6 @@
     qemu_free(entry->qemu_put_mouse_event_name);
     qemu_free(entry);
 }
-#endif
-
-void qemu_add_generic_event_handler(QEMUPutGenericEvent *func, void*  opaque)
-{
-    qemu_put_generic_event = func;
-    qemu_put_generic_event_opaque = opaque;
-}
 
 void kbd_put_keycode(int keycode)
 {
@@ -657,29 +636,6 @@
     }
 }
 
-void kbd_put_keycodes(int*  keycodes, int  count)
-{
-    if (qemu_put_kbd_event_n)
-    {
-        qemu_put_kbd_event_n(qemu_put_kbd_event_n_opaque, keycodes, count);
-    }
-    else if (qemu_put_kbd_event)
-    {
-        int  nn;
-
-        for (nn = 0; nn < count; nn++)
-            qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycodes[nn]);
-    }
-}
-
-
-void  kbd_generic_event(int  type, int code, int  value)
-{
-    if (qemu_put_generic_event)
-        qemu_put_generic_event(qemu_put_generic_event_opaque, type, code, value);
-}
-
-
 void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
 {
     QEMUPutMouseEvent *mouse_event;
@@ -717,34 +673,34 @@
     return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute;
 }
 
-void do_info_mice(void)
+void do_info_mice(Monitor *mon)
 {
     QEMUPutMouseEntry *cursor;
     int index = 0;
 
     if (!qemu_put_mouse_event_head) {
-        term_printf("No mouse devices connected\n");
+        monitor_printf(mon, "No mouse devices connected\n");
         return;
     }
 
-    term_printf("Mouse devices available:\n");
+    monitor_printf(mon, "Mouse devices available:\n");
     cursor = qemu_put_mouse_event_head;
     while (cursor != NULL) {
-        term_printf("%c Mouse #%d: %s\n",
-                    (cursor == qemu_put_mouse_event_current ? '*' : ' '),
-                    index, cursor->qemu_put_mouse_event_name);
+        monitor_printf(mon, "%c Mouse #%d: %s\n",
+                       (cursor == qemu_put_mouse_event_current ? '*' : ' '),
+                       index, cursor->qemu_put_mouse_event_name);
         index++;
         cursor = cursor->next;
     }
 }
 
-void do_mouse_set(int index)
+void do_mouse_set(Monitor *mon, int index)
 {
     QEMUPutMouseEntry *cursor;
     int i = 0;
 
     if (!qemu_put_mouse_event_head) {
-        term_printf("No mouse devices connected\n");
+        monitor_printf(mon, "No mouse devices connected\n");
         return;
     }
 
@@ -757,7 +713,7 @@
     if (cursor != NULL)
         qemu_put_mouse_event_current = cursor;
     else
-        term_printf("Mouse at given index not found\n");
+        monitor_printf(mon, "Mouse at given index not found\n");
 }
 
 /* compute with 96 bit intermediate result: (a*b)/c */
@@ -819,7 +775,8 @@
 static void init_get_clock(void)
 {
     use_rt_clock = 0;
-#if defined(__linux__)
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
+    || defined(__DragonFly__)
     {
         struct timespec ts;
         if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
@@ -831,7 +788,8 @@
 
 static int64_t get_clock(void)
 {
-#if defined(__linux__)
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
+	|| defined(__DragonFly__)
     if (use_rt_clock) {
         struct timespec ts;
         clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -958,7 +916,7 @@
 
 static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
 {
-    return t->flags & ALARM_FLAG_DYNTICKS;
+    return t && (t->flags & ALARM_FLAG_DYNTICKS);
 }
 
 static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
@@ -978,9 +936,8 @@
 
 struct qemu_alarm_win32 {
     MMRESULT timerId;
-    HANDLE host_alarm;
     unsigned int period;
-} alarm_win32_data = {0, NULL, -1};
+} alarm_win32_data = {0, -1};
 
 static int win32_start_timer(struct qemu_alarm_timer *t);
 static void win32_stop_timer(struct qemu_alarm_timer *t);
@@ -1089,7 +1046,7 @@
     {"win32", 0, win32_start_timer,
      win32_stop_timer, NULL, &alarm_win32_data},
 #endif
-    {NULL, 0, NULL, NULL, NULL, NULL}
+    {NULL, }
 };
 
 static void show_available_alarms(void)
@@ -1105,7 +1062,7 @@
 {
     int i;
     int cur = 0;
-    int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;
+    int count = ARRAY_SIZE(alarm_timers) - 1;
     char *arg;
     char *name;
     struct qemu_alarm_timer tmp;
@@ -1165,8 +1122,6 @@
 {
     QEMUClock *clock;
     clock = qemu_mallocz(sizeof(QEMUClock));
-    if (!clock)
-        return NULL;
     clock->type = type;
     return clock;
 }
@@ -1237,9 +1192,8 @@
             qemu_rearm_alarm_timer(alarm_timer);
         }
         /* Interrupt execution to force deadline recalculation.  */
-        if (use_icount && cpu_single_env) {
-            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
-        }
+        if (use_icount)
+            qemu_notify_event();
     }
 }
 
@@ -1350,9 +1304,12 @@
     return 0;
 }
 
+static void qemu_event_increment(void);
+
 #ifdef _WIN32
-void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
-                                 DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
+static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
+                                        DWORD_PTR dwUser, DWORD_PTR dw1,
+                                        DWORD_PTR dw2)
 #else
 static void host_alarm_handler(int host_signum)
 #endif
@@ -1392,24 +1349,22 @@
                                qemu_get_clock(vm_clock))) ||
         qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
                            qemu_get_clock(rt_clock))) {
-#ifdef _WIN32
-        struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
-        SetEvent(data->host_alarm);
-#endif
-        CPUState *env = next_cpu;
+        qemu_event_increment();
+        if (alarm_timer) alarm_timer->flags |= ALARM_FLAG_EXPIRED;
 
-        alarm_timer->flags |= ALARM_FLAG_EXPIRED;
-
-        if (env) {
+#ifndef CONFIG_IOTHREAD
+        if (next_cpu) {
             /* stop the currently executing cpu because a timer occured */
-            cpu_interrupt(env, CPU_INTERRUPT_EXIT);
-#ifdef USE_KQEMU
-            if (env->kqemu_enabled) {
-                kqemu_cpu_interrupt(env);
+            cpu_exit(next_cpu);
+#ifdef CONFIG_KQEMU
+            if (next_cpu->kqemu_enabled) {
+                kqemu_cpu_interrupt(next_cpu);
             }
 #endif
         }
-        event_pending = 1;
+#endif
+        timer_alarm_pending = 1;
+        qemu_notify_event();
     }
 }
 
@@ -1458,6 +1413,21 @@
 
 #ifndef _WIN32
 
+/* Sets a specific flag */
+static int fcntl_setfl(int fd, int flag)
+{
+    int flags;
+
+    flags = fcntl(fd, F_GETFL);
+    if (flags == -1)
+        return -errno;
+
+    if (fcntl(fd, F_SETFL, flags | flag) == -1)
+        return -errno;
+
+    return 0;
+}
+
 #if defined(__linux__)
 
 #define RTC_FREQ 1024
@@ -1472,7 +1442,7 @@
     act.sa_handler = host_alarm_handler;
 
     sigaction(SIGIO, &act, NULL);
-    fcntl(fd, F_SETFL, O_ASYNC);
+    fcntl_setfl(fd, O_ASYNC);
     fcntl(fd, F_SETOWN, getpid());
 }
 
@@ -1573,6 +1543,11 @@
 
     sigaction(SIGALRM, &act, NULL);
 
+    /* 
+     * Initialize ev struct to 0 to avoid valgrind complaining
+     * about uninitialized data in timer_create call
+     */
+    memset(&ev, 0, sizeof(ev));
     ev.sigev_value.sival_int = 0;
     ev.sigev_notify = SIGEV_SIGNAL;
     ev.sigev_signo = SIGALRM;
@@ -1586,21 +1561,21 @@
         return -1;
     }
 
-    t->priv = (void *)host_timer;
+    t->priv = (void *)(long)host_timer;
 
     return 0;
 }
 
 static void dynticks_stop_timer(struct qemu_alarm_timer *t)
 {
-    timer_t host_timer = (timer_t)t->priv;
+    timer_t host_timer = (timer_t)(long)t->priv;
 
     timer_delete(host_timer);
 }
 
 static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
 {
-    timer_t host_timer = (timer_t)t->priv;
+    timer_t host_timer = (timer_t)(long)t->priv;
     struct itimerspec timeout;
     int64_t nearest_delta_us = INT64_MAX;
     int64_t current_us;
@@ -1670,6 +1645,7 @@
 
 #endif /* !defined(_WIN32) */
 
+
 #ifdef _WIN32
 
 static int win32_start_timer(struct qemu_alarm_timer *t)
@@ -1678,12 +1654,6 @@
     struct qemu_alarm_win32 *data = t->priv;
     UINT flags;
 
-    data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (!data->host_alarm) {
-        perror("Failed CreateEvent");
-        return -1;
-    }
-
     memset(&tc, 0, sizeof(tc));
     timeGetDevCaps(&tc, sizeof(tc));
 
@@ -1706,14 +1676,10 @@
 
     if (!data->timerId) {
         perror("Failed to initialize win32 alarm timer");
-
         timeEndPeriod(data->period);
-        CloseHandle(data->host_alarm);
         return -1;
     }
 
-    qemu_add_wait_object(data->host_alarm, NULL, NULL);
-
     return 0;
 }
 
@@ -1723,8 +1689,6 @@
 
     timeKillEvent(data->timerId);
     timeEndPeriod(data->period);
-
-    CloseHandle(data->host_alarm);
 }
 
 static void win32_rearm_timer(struct qemu_alarm_timer *t)
@@ -1751,16 +1715,15 @@
         perror("Failed to re-arm win32 alarm timer");
 
         timeEndPeriod(data->period);
-        CloseHandle(data->host_alarm);
         exit(1);
     }
 }
 
 #endif /* _WIN32 */
 
-static void init_timer_alarm(void)
+static int init_timer_alarm(void)
 {
-    struct qemu_alarm_timer *t;
+    struct qemu_alarm_timer *t = NULL;
     int i, err = -1;
 
     for (i = 0; alarm_timers[i].name; i++) {
@@ -1772,12 +1735,16 @@
     }
 
     if (err) {
-        fprintf(stderr, "Unable to find any suitable alarm timer.\n");
-        fprintf(stderr, "Terminating\n");
-        exit(1);
+        err = -ENOENT;
+        goto fail;
     }
 
     alarm_timer = t;
+
+    return 0;
+
+fail:
+    return err;
 }
 
 static void quit_timers(void)
@@ -1823,3552 +1790,37 @@
     return seconds - time(NULL);
 }
 
-
-#ifdef CONFIG_TRACE
-static int tbflush_requested;
-static int exit_requested;
-
-void start_tracing()
-{
-  if (trace_filename == NULL)
-    return;
-  if (!tracing) {
-    fprintf(stderr,"-- start tracing --\n");
-    start_time = Now();
-  }
-  tracing = 1;
-  tbflush_requested = 1;
-  if (cpu_single_env)
-    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
-}
-
-void stop_tracing()
-{
-  if (trace_filename == NULL)
-    return;
-  if (tracing) {
-    end_time = Now();
-    elapsed_usecs += end_time - start_time;
-    fprintf(stderr,"-- stop tracing --\n");
-  }
-  tracing = 0;
-  tbflush_requested = 1;
-  if (cpu_single_env)
-    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
-}
-
-#ifndef _WIN32
-/* This is the handler for the SIGUSR1 and SIGUSR2 signals.
- * SIGUSR1 turns tracing on.  SIGUSR2 turns tracing off.
- */
-void sigusr_handler(int sig)
-{
-  if (sig == SIGUSR1)
-    start_tracing();
-  else
-    stop_tracing();
-}
-#endif
-
-/* This is the handler to catch control-C so that we can exit cleanly.
- * This is needed when tracing to flush the buffers to disk.
- */
-void sigint_handler(int sig)
-{
-  exit_requested = 1;
-  if (cpu_single_env)
-    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
-}
-#endif /* CONFIG_TRACE */
-
-
-/***********************************************************/
-/* character device */
-
-static void qemu_chr_event(CharDriverState *s, int event)
-{
-    if (!s->chr_event)
-        return;
-    s->chr_event(s->handler_opaque, event);
-}
-
-static void qemu_chr_reset_bh(void *opaque)
-{
-    CharDriverState *s = opaque;
-    qemu_chr_event(s, CHR_EVENT_RESET);
-    qemu_bh_delete(s->bh);
-    s->bh = NULL;
-}
-
-void qemu_chr_reset(CharDriverState *s)
-{
-    if (s->bh == NULL) {
-	s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
-	qemu_bh_schedule(s->bh);
-    }
-}
-
-int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
-{
-    return s->chr_write(s, buf, len);
-}
-
-int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
-{
-    if (!s->chr_ioctl)
-        return -ENOTSUP;
-    return s->chr_ioctl(s, cmd, arg);
-}
-
-int qemu_chr_can_read(CharDriverState *s)
-{
-    if (!s->chr_can_read)
-        return 0;
-    return s->chr_can_read(s->handler_opaque);
-}
-
-void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
-{
-    s->chr_read(s->handler_opaque, buf, len);
-}
-
-void qemu_chr_accept_input(CharDriverState *s)
-{
-    if (s->chr_accept_input)
-        s->chr_accept_input(s);
-}
-
-void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
-{
-    char buf[4096];
-    va_list ap;
-    va_start(ap, fmt);
-    vsnprintf(buf, sizeof(buf), fmt, ap);
-    qemu_chr_write(s, (uint8_t *)buf, strlen(buf));
-    va_end(ap);
-}
-
-void qemu_chr_send_event(CharDriverState *s, int event)
-{
-    if (s->chr_send_event)
-        s->chr_send_event(s, event);
-}
-
-void qemu_chr_add_handlers(CharDriverState *s,
-                           IOCanRWHandler *fd_can_read,
-                           IOReadHandler *fd_read,
-                           IOEventHandler *fd_event,
-                           void *opaque)
-{
-    s->chr_can_read = fd_can_read;
-    s->chr_read = fd_read;
-    s->chr_event = fd_event;
-    s->handler_opaque = opaque;
-    if (s->chr_update_read_handler)
-        s->chr_update_read_handler(s);
-}
-
-static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    return len;
-}
-
-static CharDriverState *qemu_chr_open_null(void)
-{
-    CharDriverState *chr;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
-    chr->chr_write = null_chr_write;
-    return chr;
-}
-
-/* MUX driver for serial I/O splitting */
-static int term_timestamps;
-static int64_t term_timestamps_start;
-#define MAX_MUX 4
-#define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
-#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
-typedef struct {
-    IOCanRWHandler *chr_can_read[MAX_MUX];
-    IOReadHandler *chr_read[MAX_MUX];
-    IOEventHandler *chr_event[MAX_MUX];
-    void *ext_opaque[MAX_MUX];
-    CharDriverState *drv;
-    unsigned char buffer[MUX_BUFFER_SIZE];
-    int prod;
-    int cons;
-    int mux_cnt;
-    int term_got_escape;
-    int max_size;
-} MuxDriver;
-
-
-static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    MuxDriver *d = chr->opaque;
-    int ret;
-    if (!term_timestamps) {
-        ret = d->drv->chr_write(d->drv, buf, len);
-    } else {
-        int i;
-
-        ret = 0;
-        for(i = 0; i < len; i++) {
-            ret += d->drv->chr_write(d->drv, buf+i, 1);
-            if (buf[i] == '\n') {
-                char buf1[64];
-                int64_t ti;
-                int secs;
-
-                ti = get_clock();
-                if (term_timestamps_start == -1)
-                    term_timestamps_start = ti;
-                ti -= term_timestamps_start;
-                secs = ti / 1000000000;
-                snprintf(buf1, sizeof(buf1),
-                         "[%02d:%02d:%02d.%03d] ",
-                         secs / 3600,
-                         (secs / 60) % 60,
-                         secs % 60,
-                         (int)((ti / 1000000) % 1000));
-                d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
-            }
-        }
-    }
-    return ret;
-}
-
-static const char * const mux_help[] = {
-    "% h    print this help\n\r",
-    "% x    exit emulator\n\r",
-    "% s    save disk data back to file (if -snapshot)\n\r",
-    "% t    toggle console timestamps\n\r"
-    "% b    send break (magic sysrq)\n\r",
-    "% c    switch between console and monitor\n\r",
-    "% %  sends %\n\r",
-    NULL
-};
-
-static int term_escape_char = 0x01; /* ctrl-a is used for escape */
-static void mux_print_help(CharDriverState *chr)
-{
-    int i, j;
-    char ebuf[15] = "Escape-Char";
-    char cbuf[50] = "\n\r";
-
-    if (term_escape_char > 0 && term_escape_char < 26) {
-        snprintf(cbuf, sizeof(cbuf), "\n\r");
-        snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
-    } else {
-        snprintf(cbuf, sizeof(cbuf),
-                 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
-                 term_escape_char);
-    }
-    chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf));
-    for (i = 0; mux_help[i] != NULL; i++) {
-        for (j=0; mux_help[i][j] != '\0'; j++) {
-            if (mux_help[i][j] == '%')
-                chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf));
-            else
-                chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);
-        }
-    }
-}
-
-static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
-{
-    if (d->term_got_escape) {
-        d->term_got_escape = 0;
-        if (ch == term_escape_char)
-            goto send_char;
-        switch(ch) {
-        case '?':
-        case 'h':
-            mux_print_help(chr);
-            break;
-        case 'x':
-            {
-                 const char *term =  "QEMU: Terminated\n\r";
-                 chr->chr_write(chr,(uint8_t *)term,strlen(term));
-                 exit(0);
-                 break;
-            }
-        case 's':
-            {
-                int i;
-                for (i = 0; i < nb_drives; i++) {
-                        bdrv_commit(drives_table[i].bdrv);
-                }
-            }
-            break;
-        case 'b':
-            qemu_chr_event(chr, CHR_EVENT_BREAK);
-            break;
-        case 'c':
-            /* Switch to the next registered device */
-            chr->focus++;
-            if (chr->focus >= d->mux_cnt)
-                chr->focus = 0;
-            break;
-       case 't':
-           term_timestamps = !term_timestamps;
-           term_timestamps_start = -1;
-           break;
-        }
-    } else if (ch == term_escape_char) {
-        d->term_got_escape = 1;
-    } else {
-    send_char:
-        return 1;
-    }
-    return 0;
-}
-
-static void mux_chr_accept_input(CharDriverState *chr)
-{
-    int m = chr->focus;
-    MuxDriver *d = chr->opaque;
-
-    while (d->prod != d->cons &&
-           d->chr_can_read[m] &&
-           d->chr_can_read[m](d->ext_opaque[m])) {
-        d->chr_read[m](d->ext_opaque[m],
-                       &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1);
-    }
-}
-
-static int mux_chr_can_read(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
-
-    if ((d->prod - d->cons) < MUX_BUFFER_SIZE)
-        return 1;
-    if (d->chr_can_read[chr->focus])
-        return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
-    return 0;
-}
-
-static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
-{
-    CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
-    int m = chr->focus;
-    int i;
-
-    mux_chr_accept_input (opaque);
-
-    for(i = 0; i < size; i++)
-        if (mux_proc_byte(chr, d, buf[i])) {
-            if (d->prod == d->cons &&
-                d->chr_can_read[m] &&
-                d->chr_can_read[m](d->ext_opaque[m]))
-                d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
-            else
-                d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i];
-        }
-}
-
-static void mux_chr_event(void *opaque, int event)
-{
-    CharDriverState *chr = opaque;
-    MuxDriver *d = chr->opaque;
-    int i;
-
-    /* Send the event to all registered listeners */
-    for (i = 0; i < d->mux_cnt; i++)
-        if (d->chr_event[i])
-            d->chr_event[i](d->ext_opaque[i], event);
-}
-
-static void mux_chr_update_read_handler(CharDriverState *chr)
-{
-    MuxDriver *d = chr->opaque;
-
-    if (d->mux_cnt >= MAX_MUX) {
-        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
-        return;
-    }
-    d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
-    d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
-    d->chr_read[d->mux_cnt] = chr->chr_read;
-    d->chr_event[d->mux_cnt] = chr->chr_event;
-    /* Fix up the real driver with mux routines */
-    if (d->mux_cnt == 0) {
-        qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
-                              mux_chr_event, chr);
-    }
-    chr->focus = d->mux_cnt;
-    d->mux_cnt++;
-}
-
-static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
-{
-    CharDriverState *chr;
-    MuxDriver *d;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
-    d = qemu_mallocz(sizeof(MuxDriver));
-    if (!d) {
-        free(chr);
-        return NULL;
-    }
-
-    chr->opaque = d;
-    d->drv = drv;
-    chr->focus = -1;
-    chr->chr_write = mux_chr_write;
-    chr->chr_update_read_handler = mux_chr_update_read_handler;
-    chr->chr_accept_input = mux_chr_accept_input;
-    return chr;
-}
-
-
 #ifdef _WIN32
-
-static int send_all(int fd, const uint8_t *buf, int len1)
+static void socket_cleanup(void)
 {
-    int ret, len;
-
-    len = len1;
-    while (len > 0) {
-        ret = socket_send(fd, buf, len);
-        if (ret < 0) {
-            if (errno != EWOULDBLOCK) {
-                return -1;
-            }
-        } else if (ret == 0) {
-            break;
-        } else {
-            buf += ret;
-            len -= ret;
-        }
-    }
-    return len1 - len;
+    WSACleanup();
 }
 
-#else
-
-static int unix_write(int fd, const uint8_t *buf, int len1)
+static int socket_init(void)
 {
-    int ret, len;
-
-    len = len1;
-    while (len > 0) {
-        ret = write(fd, buf, len);
-        if (ret < 0) {
-            if (errno != EINTR && errno != EAGAIN)
-                return -1;
-        } else if (ret == 0) {
-            break;
-        } else {
-            buf += ret;
-            len -= ret;
-        }
-    }
-    return len1 - len;
-}
-
-static inline int send_all(int fd, const uint8_t *buf, int len1)
-{
-    return unix_write(fd, buf, len1);
-}
-#endif /* !_WIN32 */
-
-#ifndef _WIN32
-
-typedef struct {
-    int fd_in, fd_out;
-    int max_size;
-} FDCharDriver;
-
-#define STDIO_MAX_CLIENTS 1
-static int stdio_nb_clients = 0;
-
-static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    FDCharDriver *s = chr->opaque;
-    return unix_write(s->fd_out, buf, len);
-}
-
-static int fd_chr_read_poll(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    FDCharDriver *s = chr->opaque;
-
-    s->max_size = qemu_chr_can_read(chr);
-    return s->max_size;
-}
-
-static void fd_chr_read(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    FDCharDriver *s = chr->opaque;
-    int size, len;
-    uint8_t buf[1024];
-
-    len = sizeof(buf);
-    if (len > s->max_size)
-        len = s->max_size;
-    if (len == 0)
-        return;
-    size = read(s->fd_in, buf, len);
-    if (size == 0) {
-        /* FD has been closed. Remove it from the active list.  */
-        qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
-        return;
-    }
-    if (size > 0) {
-        qemu_chr_read(chr, buf, size);
-    }
-}
-
-static void fd_chr_update_read_handler(CharDriverState *chr)
-{
-    FDCharDriver *s = chr->opaque;
-
-    if (s->fd_in >= 0) {
-        if (nographic && s->fd_in == 0) {
-        } else {
-            qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
-                                 fd_chr_read, NULL, chr);
-        }
-    }
-}
-
-static void fd_chr_close(struct CharDriverState *chr)
-{
-    FDCharDriver *s = chr->opaque;
-
-    if (s->fd_in >= 0) {
-        if (nographic && s->fd_in == 0) {
-        } else {
-            qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
-        }
-    }
-
-    qemu_free(s);
-}
-
-/* open a character device to a unix fd */
-static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
-{
-    CharDriverState *chr;
-    FDCharDriver *s;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
-    s = qemu_mallocz(sizeof(FDCharDriver));
-    if (!s) {
-        free(chr);
-        return NULL;
-    }
-    s->fd_in = fd_in;
-    s->fd_out = fd_out;
-    chr->opaque = s;
-    chr->chr_write = fd_chr_write;
-    chr->chr_update_read_handler = fd_chr_update_read_handler;
-    chr->chr_close = fd_chr_close;
-
-    qemu_chr_reset(chr);
-
-    return chr;
-}
-
-static CharDriverState *qemu_chr_open_file_out(const char *file_out)
-{
-    int fd_out;
-
-    TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
-    if (fd_out < 0)
-        return NULL;
-    return qemu_chr_open_fd(-1, fd_out);
-}
-
-static CharDriverState *qemu_chr_open_pipe(const char *filename)
-{
-    int fd_in, fd_out;
-    char filename_in[256], filename_out[256];
-
-    snprintf(filename_in, 256, "%s.in", filename);
-    snprintf(filename_out, 256, "%s.out", filename);
-    TFR(fd_in = open(filename_in, O_RDWR | O_BINARY));
-    TFR(fd_out = open(filename_out, O_RDWR | O_BINARY));
-    if (fd_in < 0 || fd_out < 0) {
-	if (fd_in >= 0)
-	    close(fd_in);
-	if (fd_out >= 0)
-	    close(fd_out);
-        TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
-        if (fd_in < 0)
-            return NULL;
-    }
-    return qemu_chr_open_fd(fd_in, fd_out);
-}
-
-CharDriverState *qemu_chr_open_fdpair(const char *fd_pair)
-{
-    int fd_in, fd_out;
-    char *endptr;
-
-    /* fd_pair should contain two decimal fd values, separated by
-     * a colon. */
-    endptr = NULL;
-    fd_in = strtol(fd_pair, &endptr, 10);
-    if (endptr == NULL || endptr == fd_pair || *endptr != ':')
-        return NULL;
-    endptr++;   // skip colon
-    fd_pair = endptr;
-    endptr = NULL;
-    fd_out = strtol(fd_pair, &endptr, 10);
-    if (endptr == NULL || endptr == fd_pair || *endptr != '\0')
-        return NULL;
-
-    return qemu_chr_open_fd(fd_in, fd_out);
-}
-
-
-/* for STDIO, we handle the case where several clients use it
-   (nographic mode) */
-
-#define TERM_FIFO_MAX_SIZE 1
-
-static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
-static int term_fifo_size;
-
-static int stdio_read_poll(void *opaque)
-{
-    CharDriverState *chr = opaque;
-
-    /* try to flush the queue if needed */
-    if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
-        qemu_chr_read(chr, term_fifo, 1);
-        term_fifo_size = 0;
-    }
-    /* see if we can absorb more chars */
-    if (term_fifo_size == 0)
-        return 1;
-    else
-        return 0;
-}
-
-static void stdio_read(void *opaque)
-{
-    int size;
-    uint8_t buf[1];
-    CharDriverState *chr = opaque;
-
-    size = read(0, buf, 1);
-    if (size == 0) {
-        /* stdin has been closed. Remove it from the active list.  */
-        qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
-        return;
-    }
-    if (size > 0) {
-        if (qemu_chr_can_read(chr) > 0) {
-            qemu_chr_read(chr, buf, 1);
-        } else if (term_fifo_size == 0) {
-            term_fifo[term_fifo_size++] = buf[0];
-        }
-    }
-}
-
-/* init terminal so that we can grab keys */
-static struct termios oldtty;
-static int old_fd0_flags;
-static int term_atexit_done;
-
-static void term_exit(void)
-{
-    tcsetattr (0, TCSANOW, &oldtty);
-    fcntl(0, F_SETFL, old_fd0_flags);
-}
-
-static void term_init(void)
-{
-    struct termios tty;
-
-    tcgetattr (0, &tty);
-    oldtty = tty;
-    old_fd0_flags = fcntl(0, F_GETFL);
-
-    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
-                          |INLCR|IGNCR|ICRNL|IXON);
-    tty.c_oflag |= OPOST;
-    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
-    /* if graphical mode, we allow Ctrl-C handling */
-    if (nographic)
-        tty.c_lflag &= ~ISIG;
-    tty.c_cflag &= ~(CSIZE|PARENB);
-    tty.c_cflag |= CS8;
-    tty.c_cc[VMIN] = 1;
-    tty.c_cc[VTIME] = 0;
-
-    tcsetattr (0, TCSANOW, &tty);
-
-    if (!term_atexit_done++)
-        atexit(term_exit);
-
-    fcntl(0, F_SETFL, O_NONBLOCK);
-}
-
-static void qemu_chr_close_stdio(struct CharDriverState *chr)
-{
-    term_exit();
-    stdio_nb_clients--;
-    qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
-    fd_chr_close(chr);
-}
-
-static CharDriverState *qemu_chr_open_stdio(void)
-{
-    CharDriverState *chr;
-
-    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
-        return NULL;
-    chr = qemu_chr_open_fd(0, 1);
-    chr->chr_close = qemu_chr_close_stdio;
-    qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
-    stdio_nb_clients++;
-    term_init();
-
-    return chr;
-}
-
-#ifdef __sun__
-/* Once Solaris has openpty(), this is going to be removed. */
-int openpty(int *amaster, int *aslave, char *name,
-            struct termios *termp, struct winsize *winp)
-{
-        const char *slave;
-        int mfd = -1, sfd = -1;
-
-        *amaster = *aslave = -1;
-
-        mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
-        if (mfd < 0)
-                goto err;
-
-        if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
-                goto err;
-
-        if ((slave = ptsname(mfd)) == NULL)
-                goto err;
-
-        if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
-                goto err;
-
-        if (ioctl(sfd, I_PUSH, "ptem") == -1 ||
-            (termp != NULL && tcgetattr(sfd, termp) < 0))
-                goto err;
-
-        if (amaster)
-                *amaster = mfd;
-        if (aslave)
-                *aslave = sfd;
-        if (winp)
-                ioctl(sfd, TIOCSWINSZ, winp);
-
-        return 0;
-
-err:
-        if (sfd != -1)
-                close(sfd);
-        close(mfd);
-        return -1;
-}
-
-void cfmakeraw (struct termios *termios_p)
-{
-        termios_p->c_iflag &=
-                ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
-        termios_p->c_oflag &= ~OPOST;
-        termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
-        termios_p->c_cflag &= ~(CSIZE|PARENB);
-        termios_p->c_cflag |= CS8;
-
-        termios_p->c_cc[VMIN] = 0;
-        termios_p->c_cc[VTIME] = 0;
-}
-#endif  /* __sun__ */
-
-#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
-
-typedef struct {
-    int fd;
-    int connected;
-    int polling;
-    int read_bytes;
-    QEMUTimer *timer;
-} PtyCharDriver;
-
-static void pty_chr_update_read_handler(CharDriverState *chr);
-static void pty_chr_state(CharDriverState *chr, int connected);
-
-static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    PtyCharDriver *s = chr->opaque;
-
-    if (!s->connected) {
-        /* guest sends data, check for (re-)connect */
-        pty_chr_update_read_handler(chr);
-        return 0;
-    }
-    return unix_write(s->fd, buf, len);
-}
-
-static int pty_chr_read_poll(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
-
-    s->read_bytes = qemu_chr_can_read(chr);
-    return s->read_bytes;
-}
-
-static void pty_chr_read(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
-    int size, len;
-    uint8_t buf[1024];
-
-    len = sizeof(buf);
-    if (len > s->read_bytes)
-        len = s->read_bytes;
-    if (len == 0)
-        return;
-    size = read(s->fd, buf, len);
-    if ((size == -1 && errno == EIO) ||
-        (size == 0)) {
-        pty_chr_state(chr, 0);
-        return;
-    }
-    if (size > 0) {
-        pty_chr_state(chr, 1);
-        qemu_chr_read(chr, buf, size);
-    }
-}
-
-static void pty_chr_update_read_handler(CharDriverState *chr)
-{
-    PtyCharDriver *s = chr->opaque;
-
-    qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
-                         pty_chr_read, NULL, chr);
-    s->polling = 1;
-    /*
-     * Short timeout here: just need wait long enougth that qemu makes
-     * it through the poll loop once.  When reconnected we want a
-     * short timeout so we notice it almost instantly.  Otherwise
-     * read() gives us -EIO instantly, making pty_chr_state() reset the
-     * timeout to the normal (much longer) poll interval before the
-     * timer triggers.
-     */
-    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
-}
-
-static void pty_chr_state(CharDriverState *chr, int connected)
-{
-    PtyCharDriver *s = chr->opaque;
-
-    if (!connected) {
-        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
-        s->connected = 0;
-        s->polling = 0;
-        /* (re-)connect poll interval for idle guests: once per second.
-         * We check more frequently in case the guests sends data to
-         * the virtual device linked to our pty. */
-        qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
-    } else {
-        if (!s->connected)
-            qemu_chr_reset(chr);
-        s->connected = 1;
-    }
-}
-
-static void pty_chr_timer(void *opaque)
-{
-    struct CharDriverState *chr = opaque;
-    PtyCharDriver *s = chr->opaque;
-
-    if (s->connected)
-        return;
-    if (s->polling) {
-        /* If we arrive here without polling being cleared due
-         * read returning -EIO, then we are (re-)connected */
-        pty_chr_state(chr, 1);
-        return;
-    }
-
-    /* Next poll ... */
-    pty_chr_update_read_handler(chr);
-}
-
-static void pty_chr_close(struct CharDriverState *chr)
-{
-    PtyCharDriver *s = chr->opaque;
-
-    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
-    close(s->fd);
-    qemu_free(s);
-}
-
-static CharDriverState *qemu_chr_open_pty(void)
-{
-    CharDriverState *chr;
-    PtyCharDriver *s;
-    struct termios tty;
-    int slave_fd;
-#if defined(__OpenBSD__)
-    char pty_name[PATH_MAX];
-#define q_ptsname(x) pty_name
-#else
-    char *pty_name = NULL;
-#define q_ptsname(x) ptsname(x)
-#endif
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
-    s = qemu_mallocz(sizeof(PtyCharDriver));
-    if (!s) {
-        qemu_free(chr);
-        return NULL;
-    }
-
-    if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
-        return NULL;
-    }
-
-    /* Set raw attributes on the pty. */
-    cfmakeraw(&tty);
-    tcsetattr(slave_fd, TCSAFLUSH, &tty);
-    close(slave_fd);
-
-    fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
-
-    chr->opaque = s;
-    chr->chr_write = pty_chr_write;
-    chr->chr_update_read_handler = pty_chr_update_read_handler;
-    chr->chr_close = pty_chr_close;
-
-    s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
-
-    return chr;
-}
-#endif /* __linux__ || __sun__ || __xxxBSD__ */
-
-static void tty_serial_init(int fd, int speed,
-                            int parity, int data_bits, int stop_bits)
-{
-    struct termios tty;
-    speed_t spd;
-
-#if 0
-    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
-           speed, parity, data_bits, stop_bits);
-#endif
-    tcgetattr (fd, &tty);
-
-#define MARGIN 1.1
-    if (speed <= 50 * MARGIN)
-        spd = B50;
-    else if (speed <= 75 * MARGIN)
-        spd = B75;
-    else if (speed <= 300 * MARGIN)
-        spd = B300;
-    else if (speed <= 600 * MARGIN)
-        spd = B600;
-    else if (speed <= 1200 * MARGIN)
-        spd = B1200;
-    else if (speed <= 2400 * MARGIN)
-        spd = B2400;
-    else if (speed <= 4800 * MARGIN)
-        spd = B4800;
-    else if (speed <= 9600 * MARGIN)
-        spd = B9600;
-    else if (speed <= 19200 * MARGIN)
-        spd = B19200;
-    else if (speed <= 38400 * MARGIN)
-        spd = B38400;
-    else if (speed <= 57600 * MARGIN)
-        spd = B57600;
-    else if (speed <= 115200 * MARGIN)
-        spd = B115200;
-    else
-        spd = B115200;
-
-    cfsetispeed(&tty, spd);
-    cfsetospeed(&tty, spd);
-
-    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
-                          |INLCR|IGNCR|ICRNL|IXON);
-    tty.c_oflag |= OPOST;
-    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
-    tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
-    switch(data_bits) {
-    default:
-    case 8:
-        tty.c_cflag |= CS8;
-        break;
-    case 7:
-        tty.c_cflag |= CS7;
-        break;
-    case 6:
-        tty.c_cflag |= CS6;
-        break;
-    case 5:
-        tty.c_cflag |= CS5;
-        break;
-    }
-    switch(parity) {
-    default:
-    case 'N':
-        break;
-    case 'E':
-        tty.c_cflag |= PARENB;
-        break;
-    case 'O':
-        tty.c_cflag |= PARENB | PARODD;
-        break;
-    }
-    if (stop_bits == 2)
-        tty.c_cflag |= CSTOPB;
-
-    tcsetattr (fd, TCSANOW, &tty);
-}
-
-static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
-{
-    FDCharDriver *s = chr->opaque;
-
-    switch(cmd) {
-    case CHR_IOCTL_SERIAL_SET_PARAMS:
-        {
-            QEMUSerialSetParams *ssp = arg;
-            tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
-                            ssp->data_bits, ssp->stop_bits);
-        }
-        break;
-    case CHR_IOCTL_SERIAL_SET_BREAK:
-        {
-            int enable = *(int *)arg;
-            if (enable)
-                tcsendbreak(s->fd_in, 1);
-        }
-        break;
-    case CHR_IOCTL_SERIAL_GET_TIOCM:
-        {
-            int sarg = 0;
-            int *targ = (int *)arg;
-            ioctl(s->fd_in, TIOCMGET, &sarg);
-            *targ = 0;
-            if (sarg | TIOCM_CTS)
-                *targ |= CHR_TIOCM_CTS;
-            if (sarg | TIOCM_CAR)
-                *targ |= CHR_TIOCM_CAR;
-            if (sarg | TIOCM_DSR)
-                *targ |= CHR_TIOCM_DSR;
-            if (sarg | TIOCM_RI)
-                *targ |= CHR_TIOCM_RI;
-            if (sarg | TIOCM_DTR)
-                *targ |= CHR_TIOCM_DTR;
-            if (sarg | TIOCM_RTS)
-                *targ |= CHR_TIOCM_RTS;
-        }
-        break;
-    case CHR_IOCTL_SERIAL_SET_TIOCM:
-        {
-            int sarg = *(int *)arg;
-            int targ = 0;
-            if (sarg | CHR_TIOCM_DTR)
-                targ |= TIOCM_DTR;
-            if (sarg | CHR_TIOCM_RTS)
-                targ |= TIOCM_RTS;
-            ioctl(s->fd_in, TIOCMSET, &targ);
-        }
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static CharDriverState *qemu_chr_open_tty(const char *filename)
-{
-    CharDriverState *chr;
-    int fd;
-
-    TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
-    tty_serial_init(fd, 115200, 'N', 8, 1);
-    chr = qemu_chr_open_fd(fd, fd);
-    if (!chr) {
-        close(fd);
-        return NULL;
-    }
-    chr->chr_ioctl = tty_serial_ioctl;
-    qemu_chr_reset(chr);
-    return chr;
-}
-
-#if defined(__linux__)
-typedef struct {
-    int fd;
-    int mode;
-} ParallelCharDriver;
-
-static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
-{
-    if (s->mode != mode) {
-	int m = mode;
-        if (ioctl(s->fd, PPSETMODE, &m) < 0)
-            return 0;
-	s->mode = mode;
-    }
-    return 1;
-}
-
-static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
-{
-    ParallelCharDriver *drv = chr->opaque;
-    int fd = drv->fd;
-    uint8_t b;
-
-    switch(cmd) {
-    case CHR_IOCTL_PP_READ_DATA:
-        if (ioctl(fd, PPRDATA, &b) < 0)
-            return -ENOTSUP;
-        *(uint8_t *)arg = b;
-        break;
-    case CHR_IOCTL_PP_WRITE_DATA:
-        b = *(uint8_t *)arg;
-        if (ioctl(fd, PPWDATA, &b) < 0)
-            return -ENOTSUP;
-        break;
-    case CHR_IOCTL_PP_READ_CONTROL:
-        if (ioctl(fd, PPRCONTROL, &b) < 0)
-            return -ENOTSUP;
-	/* Linux gives only the lowest bits, and no way to know data
-	   direction! For better compatibility set the fixed upper
-	   bits. */
-        *(uint8_t *)arg = b | 0xc0;
-        break;
-    case CHR_IOCTL_PP_WRITE_CONTROL:
-        b = *(uint8_t *)arg;
-        if (ioctl(fd, PPWCONTROL, &b) < 0)
-            return -ENOTSUP;
-        break;
-    case CHR_IOCTL_PP_READ_STATUS:
-        if (ioctl(fd, PPRSTATUS, &b) < 0)
-            return -ENOTSUP;
-        *(uint8_t *)arg = b;
-        break;
-    case CHR_IOCTL_PP_DATA_DIR:
-        if (ioctl(fd, PPDATADIR, (int *)arg) < 0)
-            return -ENOTSUP;
-        break;
-    case CHR_IOCTL_PP_EPP_READ_ADDR:
-	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
-	    struct ParallelIOArg *parg = arg;
-	    int n = read(fd, parg->buffer, parg->count);
-	    if (n != parg->count) {
-		return -EIO;
-	    }
-	}
-        break;
-    case CHR_IOCTL_PP_EPP_READ:
-	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
-	    struct ParallelIOArg *parg = arg;
-	    int n = read(fd, parg->buffer, parg->count);
-	    if (n != parg->count) {
-		return -EIO;
-	    }
-	}
-        break;
-    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
-	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
-	    struct ParallelIOArg *parg = arg;
-	    int n = write(fd, parg->buffer, parg->count);
-	    if (n != parg->count) {
-		return -EIO;
-	    }
-	}
-        break;
-    case CHR_IOCTL_PP_EPP_WRITE:
-	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
-	    struct ParallelIOArg *parg = arg;
-	    int n = write(fd, parg->buffer, parg->count);
-	    if (n != parg->count) {
-		return -EIO;
-	    }
-	}
-        break;
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static void pp_close(CharDriverState *chr)
-{
-    ParallelCharDriver *drv = chr->opaque;
-    int fd = drv->fd;
-
-    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
-    ioctl(fd, PPRELEASE);
-    close(fd);
-    qemu_free(drv);
-}
-
-static CharDriverState *qemu_chr_open_pp(const char *filename)
-{
-    CharDriverState *chr;
-    ParallelCharDriver *drv;
-    int fd;
-
-    TFR(fd = open(filename, O_RDWR));
-    if (fd < 0)
-        return NULL;
-
-    if (ioctl(fd, PPCLAIM) < 0) {
-        close(fd);
-        return NULL;
-    }
-
-    drv = qemu_mallocz(sizeof(ParallelCharDriver));
-    if (!drv) {
-        close(fd);
-        return NULL;
-    }
-    drv->fd = fd;
-    drv->mode = IEEE1284_MODE_COMPAT;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr) {
-	qemu_free(drv);
-        close(fd);
-        return NULL;
-    }
-    chr->chr_write = null_chr_write;
-    chr->chr_ioctl = pp_ioctl;
-    chr->chr_close = pp_close;
-    chr->opaque = drv;
-
-    qemu_chr_reset(chr);
-
-    return chr;
-}
-#endif /* __linux__ */
-
-#else /* _WIN32 */
-
-typedef struct {
-    int max_size;
-    HANDLE hcom, hrecv, hsend;
-    OVERLAPPED orecv, osend;
-    BOOL fpipe;
-    DWORD len;
-} WinCharState;
-
-#define NSENDBUF 2048
-#define NRECVBUF 2048
-#define MAXCONNECT 1
-#define NTIMEOUT 5000
-
-static int win_chr_poll(void *opaque);
-static int win_chr_pipe_poll(void *opaque);
-
-static void win_chr_close(CharDriverState *chr)
-{
-    WinCharState *s = chr->opaque;
-
-    if (s->hsend) {
-        CloseHandle(s->hsend);
-        s->hsend = NULL;
-    }
-    if (s->hrecv) {
-        CloseHandle(s->hrecv);
-        s->hrecv = NULL;
-    }
-    if (s->hcom) {
-        CloseHandle(s->hcom);
-        s->hcom = NULL;
-    }
-    if (s->fpipe)
-        qemu_del_polling_cb(win_chr_pipe_poll, chr);
-    else
-        qemu_del_polling_cb(win_chr_poll, chr);
-}
-
-static int win_chr_init(CharDriverState *chr, const char *filename)
-{
-    WinCharState *s = chr->opaque;
-    COMMCONFIG comcfg;
-    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
-    COMSTAT comstat;
-    DWORD size;
-    DWORD err;
-
-    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!s->hsend) {
-        fprintf(stderr, "Failed CreateEvent\n");
-        goto fail;
-    }
-    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!s->hrecv) {
-        fprintf(stderr, "Failed CreateEvent\n");
-        goto fail;
-    }
-
-    s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
-                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
-    if (s->hcom == INVALID_HANDLE_VALUE) {
-        fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
-        s->hcom = NULL;
-        goto fail;
-    }
-
-    if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
-        fprintf(stderr, "Failed SetupComm\n");
-        goto fail;
-    }
-
-    ZeroMemory(&comcfg, sizeof(COMMCONFIG));
-    size = sizeof(COMMCONFIG);
-    GetDefaultCommConfig(filename, &comcfg, &size);
-    comcfg.dcb.DCBlength = sizeof(DCB);
-    CommConfigDialog(filename, NULL, &comcfg);
-
-    if (!SetCommState(s->hcom, &comcfg.dcb)) {
-        fprintf(stderr, "Failed SetCommState\n");
-        goto fail;
-    }
-
-    if (!SetCommMask(s->hcom, EV_ERR)) {
-        fprintf(stderr, "Failed SetCommMask\n");
-        goto fail;
-    }
-
-    cto.ReadIntervalTimeout = MAXDWORD;
-    if (!SetCommTimeouts(s->hcom, &cto)) {
-        fprintf(stderr, "Failed SetCommTimeouts\n");
-        goto fail;
-    }
-
-    if (!ClearCommError(s->hcom, &err, &comstat)) {
-        fprintf(stderr, "Failed ClearCommError\n");
-        goto fail;
-    }
-    qemu_add_polling_cb(win_chr_poll, chr);
-    return 0;
-
- fail:
-    win_chr_close(chr);
-    return -1;
-}
-
-static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
-{
-    WinCharState *s = chr->opaque;
-    DWORD len, ret, size, err;
-
-    len = len1;
-    ZeroMemory(&s->osend, sizeof(s->osend));
-    s->osend.hEvent = s->hsend;
-    while (len > 0) {
-        if (s->hsend)
-            ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
-        else
-            ret = WriteFile(s->hcom, buf, len, &size, NULL);
-        if (!ret) {
-            err = GetLastError();
-            if (err == ERROR_IO_PENDING) {
-                ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
-                if (ret) {
-                    buf += size;
-                    len -= size;
-                } else {
-                    break;
-                }
-            } else {
-                break;
-            }
-        } else {
-            buf += size;
-            len -= size;
-        }
-    }
-    return len1 - len;
-}
-
-static int win_chr_read_poll(CharDriverState *chr)
-{
-    WinCharState *s = chr->opaque;
-
-    s->max_size = qemu_chr_can_read(chr);
-    return s->max_size;
-}
-
-static void win_chr_readfile(CharDriverState *chr)
-{
-    WinCharState *s = chr->opaque;
+    WSADATA Data;
     int ret, err;
-    uint8_t buf[1024];
-    DWORD size;
 
-    ZeroMemory(&s->orecv, sizeof(s->orecv));
-    s->orecv.hEvent = s->hrecv;
-    ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
-    if (!ret) {
-        err = GetLastError();
-        if (err == ERROR_IO_PENDING) {
-            ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
-        }
-    }
-
-    if (size > 0) {
-        qemu_chr_read(chr, buf, size);
-    }
-}
-
-static void win_chr_read(CharDriverState *chr)
-{
-    WinCharState *s = chr->opaque;
-
-    if (s->len > s->max_size)
-        s->len = s->max_size;
-    if (s->len == 0)
-        return;
-
-    win_chr_readfile(chr);
-}
-
-static int win_chr_poll(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    WinCharState *s = chr->opaque;
-    COMSTAT status;
-    DWORD comerr;
-
-    ClearCommError(s->hcom, &comerr, &status);
-    if (status.cbInQue > 0) {
-        s->len = status.cbInQue;
-        win_chr_read_poll(chr);
-        win_chr_read(chr);
-        return 1;
-    }
-    return 0;
-}
-
-static CharDriverState *qemu_chr_open_win(const char *filename)
-{
-    CharDriverState *chr;
-    WinCharState *s;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
-    s = qemu_mallocz(sizeof(WinCharState));
-    if (!s) {
-        free(chr);
-        return NULL;
-    }
-    chr->opaque = s;
-    chr->chr_write = win_chr_write;
-    chr->chr_close = win_chr_close;
-
-    if (win_chr_init(chr, filename) < 0) {
-        free(s);
-        free(chr);
-        return NULL;
-    }
-    qemu_chr_reset(chr);
-    return chr;
-}
-
-static int win_chr_pipe_poll(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    WinCharState *s = chr->opaque;
-    DWORD size;
-
-    PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
-    if (size > 0) {
-        s->len = size;
-        win_chr_read_poll(chr);
-        win_chr_read(chr);
-        return 1;
-    }
-    return 0;
-}
-
-static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
-{
-    WinCharState *s = chr->opaque;
-    OVERLAPPED ov;
-    int ret;
-    DWORD size;
-    char openname[256];
-
-    s->fpipe = TRUE;
-
-    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!s->hsend) {
-        fprintf(stderr, "Failed CreateEvent\n");
-        goto fail;
-    }
-    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!s->hrecv) {
-        fprintf(stderr, "Failed CreateEvent\n");
-        goto fail;
-    }
-
-    snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
-    s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
-                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
-                              PIPE_WAIT,
-                              MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
-    if (s->hcom == INVALID_HANDLE_VALUE) {
-        fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());
-        s->hcom = NULL;
-        goto fail;
-    }
-
-    ZeroMemory(&ov, sizeof(ov));
-    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-    ret = ConnectNamedPipe(s->hcom, &ov);
-    if (ret) {
-        fprintf(stderr, "Failed ConnectNamedPipe\n");
-        goto fail;
-    }
-
-    ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
-    if (!ret) {
-        fprintf(stderr, "Failed GetOverlappedResult\n");
-        if (ov.hEvent) {
-            CloseHandle(ov.hEvent);
-            ov.hEvent = NULL;
-        }
-        goto fail;
-    }
-
-    if (ov.hEvent) {
-        CloseHandle(ov.hEvent);
-        ov.hEvent = NULL;
-    }
-    qemu_add_polling_cb(win_chr_pipe_poll, chr);
-    return 0;
-
- fail:
-    win_chr_close(chr);
-    return -1;
-}
-
-
-static CharDriverState *qemu_chr_open_win_pipe(const char *filename)
-{
-    CharDriverState *chr;
-    WinCharState *s;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
-    s = qemu_mallocz(sizeof(WinCharState));
-    if (!s) {
-        free(chr);
-        return NULL;
-    }
-    chr->opaque = s;
-    chr->chr_write = win_chr_write;
-    chr->chr_close = win_chr_close;
-
-    if (win_chr_pipe_init(chr, filename) < 0) {
-        free(s);
-        free(chr);
-        return NULL;
-    }
-    qemu_chr_reset(chr);
-    return chr;
-}
-
-static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
-{
-    CharDriverState *chr;
-    WinCharState *s;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        return NULL;
-    s = qemu_mallocz(sizeof(WinCharState));
-    if (!s) {
-        free(chr);
-        return NULL;
-    }
-    s->hcom = fd_out;
-    chr->opaque = s;
-    chr->chr_write = win_chr_write;
-    qemu_chr_reset(chr);
-    return chr;
-}
-
-static CharDriverState *qemu_chr_open_win_con(const char *filename)
-{
-    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
-}
-
-static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
-{
-    HANDLE fd_out;
-
-    fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
-                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (fd_out == INVALID_HANDLE_VALUE)
-        return NULL;
-
-    return qemu_chr_open_win_file(fd_out);
-}
-#endif /* !_WIN32 */
-
-/***********************************************************/
-/* UDP Net console */
-
-typedef struct {
-    int fd;
-    SockAddress daddr;
-    uint8_t buf[1024];
-    int bufcnt;
-    int bufptr;
-    int max_size;
-} NetCharDriver;
-
-static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    NetCharDriver *s = chr->opaque;
-
-    return socket_sendto(s->fd, buf, len, &s->daddr);
-}
-
-static int udp_chr_read_poll(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    NetCharDriver *s = chr->opaque;
-
-    s->max_size = qemu_chr_can_read(chr);
-
-    /* If there were any stray characters in the queue process them
-     * first
-     */
-    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
-        s->bufptr++;
-        s->max_size = qemu_chr_can_read(chr);
-    }
-    return s->max_size;
-}
-
-static void udp_chr_read(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    NetCharDriver *s = chr->opaque;
-
-    if (s->max_size == 0)
-        return;
-    s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0);
-    s->bufptr = s->bufcnt;
-    if (s->bufcnt <= 0)
-        return;
-
-    s->bufptr = 0;
-    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
-        s->bufptr++;
-        s->max_size = qemu_chr_can_read(chr);
-    }
-}
-
-static void udp_chr_update_read_handler(CharDriverState *chr)
-{
-    NetCharDriver *s = chr->opaque;
-
-    if (s->fd >= 0) {
-        qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
-                             udp_chr_read, NULL, chr);
-    }
-}
-
-int parse_host_port(SockAddress *saddr, const char *str);
-int parse_host_src_port(SockAddress *haddr,
-                        SockAddress *saddr,
-                        const char *str);
-#ifndef _WIN32
-static int parse_unix_path(SockAddress  *uaddr, const char*  str);
-#endif
-
-static CharDriverState *qemu_chr_open_udp(const char *def)
-{
-    CharDriverState *chr = NULL;
-    NetCharDriver *s = NULL;
-    int fd = -1;
-    SockAddress saddr;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        goto return_err;
-    s = qemu_mallocz(sizeof(NetCharDriver));
-    if (!s)
-        goto return_err;
-
-    fd = socket(PF_INET, SOCK_DGRAM, 0);
-    if (fd < 0) {
-        perror("socket(PF_INET, SOCK_DGRAM)");
-        goto return_err;
-    }
-
-    if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
-        printf("Could not parse: %s\n", def);
-        goto return_err;
-    }
-
-    if (socket_bind(fd, &saddr) < 0)
-    {
-        perror("bind");
-        goto return_err;
-    }
-
-    s->fd = fd;
-    s->bufcnt = 0;
-    s->bufptr = 0;
-    chr->opaque = s;
-    chr->chr_write = udp_chr_write;
-    chr->chr_update_read_handler = udp_chr_update_read_handler;
-    return chr;
-
-return_err:
-    if (chr)
-        free(chr);
-    if (s)
-        free(s);
-    if (fd >= 0)
-        closesocket(fd);
-    return NULL;
-}
-
-/***********************************************************/
-/* TCP Net console */
-
-typedef struct {
-    int fd, listen_fd;
-    int connected;
-    int max_size;
-    int do_telnetopt;
-    int do_nodelay;
-    int is_unix;
-} TCPCharDriver;
-
-static void tcp_chr_accept(void *opaque);
-
-static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    TCPCharDriver *s = chr->opaque;
-    if (s->connected) {
-        return send_all(s->fd, buf, len);
-    } else {
-        /* XXX: indicate an error ? */
-        return len;
-    }
-}
-
-static int tcp_chr_read_poll(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
-    if (!s->connected)
-        return 0;
-    s->max_size = qemu_chr_can_read(chr);
-    return s->max_size;
-}
-
-#define IAC 255
-#define IAC_BREAK 243
-static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
-                                      TCPCharDriver *s,
-                                      uint8_t *buf, int *size)
-{
-    /* Handle any telnet client's basic IAC options to satisfy char by
-     * char mode with no echo.  All IAC options will be removed from
-     * the buf and the do_telnetopt variable will be used to track the
-     * state of the width of the IAC information.
-     *
-     * IAC commands come in sets of 3 bytes with the exception of the
-     * "IAC BREAK" command and the double IAC.
-     */
-
-    int i;
-    int j = 0;
-
-    for (i = 0; i < *size; i++) {
-        if (s->do_telnetopt > 1) {
-            if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
-                /* Double IAC means send an IAC */
-                if (j != i)
-                    buf[j] = buf[i];
-                j++;
-                s->do_telnetopt = 1;
-            } else {
-                if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
-                    /* Handle IAC break commands by sending a serial break */
-                    qemu_chr_event(chr, CHR_EVENT_BREAK);
-                    s->do_telnetopt++;
-                }
-                s->do_telnetopt++;
-            }
-            if (s->do_telnetopt >= 4) {
-                s->do_telnetopt = 1;
-            }
-        } else {
-            if ((unsigned char)buf[i] == IAC) {
-                s->do_telnetopt = 2;
-            } else {
-                if (j != i)
-                    buf[j] = buf[i];
-                j++;
-            }
-        }
-    }
-    *size = j;
-}
-
-static void tcp_chr_read(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
-    uint8_t buf[1024];
-    int len, size;
-
-    if (!s->connected || s->max_size <= 0)
-        return;
-    len = sizeof(buf);
-    if (len > s->max_size)
-        len = s->max_size;
-    size = socket_recv(s->fd, buf, len);
-    if (size == 0) {
-        /* connection closed */
-        s->connected = 0;
-        if (s->listen_fd >= 0) {
-            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
-        }
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
-        socket_close(s->fd);
-        s->fd = -1;
-    } else if (size > 0) {
-        if (s->do_telnetopt)
-            tcp_chr_process_IAC_bytes(chr, s, buf, &size);
-        if (size > 0)
-            qemu_chr_read(chr, buf, size);
-    }
-}
-
-static void tcp_chr_connect(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
-
-    s->connected = 1;
-    qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
-                         tcp_chr_read, NULL, chr);
-    qemu_chr_reset(chr);
-}
-
-#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
-static void tcp_chr_telnet_init(int fd)
-{
-    char buf[3];
-    /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
-    IACSET(buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
-    socket_send(fd, (char *)buf, 3);
-    IACSET(buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
-    socket_send(fd, (char *)buf, 3);
-    IACSET(buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
-    socket_send(fd, (char *)buf, 3);
-    IACSET(buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
-    socket_send(fd, (char *)buf, 3);
-}
-
-static void tcp_chr_accept(void *opaque)
-{
-    CharDriverState *chr = opaque;
-    TCPCharDriver *s = chr->opaque;
-    int fd;
-
-    for(;;) {
-        fd = socket_accept(s->listen_fd, NULL);
-        if (fd < 0) {
-            return;
-        } else if (fd >= 0) {
-            if (s->do_telnetopt)
-                tcp_chr_telnet_init(fd);
-            break;
-        }
-    }
-    socket_set_nonblock(fd);
-    if (s->do_nodelay)
-        socket_set_nodelay(fd);
-    s->fd = fd;
-    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
-    tcp_chr_connect(chr);
-}
-
-static void tcp_chr_close(CharDriverState *chr)
-{
-    TCPCharDriver *s = chr->opaque;
-    if (s->fd >= 0)
-        closesocket(s->fd);
-    if (s->listen_fd >= 0)
-        closesocket(s->listen_fd);
-    qemu_free(s);
-}
-
-static CharDriverState *qemu_chr_open_tcp(const char *host_str,
-                                          int is_telnet,
-					  int is_unix)
-{
-    CharDriverState *chr = NULL;
-    TCPCharDriver *s = NULL;
-    int fd = -1, ret, err;
-    int is_listen = 0;
-    int is_waitconnect = 1;
-    int do_nodelay = 0;
-    const char *ptr;
-    SockAddress saddr;
-
-#ifndef _WIN32
-    if (is_unix) {
-	if (parse_unix_path(&saddr, host_str) < 0)
-	    goto fail;
-    } else
-#endif
-    {
-	if (parse_host_port(&saddr, host_str) < 0)
-	    goto fail;
-    }
-
-    ptr = host_str;
-    while((ptr = strchr(ptr,','))) {
-        ptr++;
-        if (!strncmp(ptr,"server",6)) {
-            is_listen = 1;
-        } else if (!strncmp(ptr,"nowait",6)) {
-            is_waitconnect = 0;
-        } else if (!strncmp(ptr,"nodelay",6)) {
-            do_nodelay = 1;
-        } else {
-            printf("Unknown option: %s\n", ptr);
-            goto fail;
-        }
-    }
-    if (!is_listen)
-        is_waitconnect = 0;
-
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr)
-        goto fail;
-    s = qemu_mallocz(sizeof(TCPCharDriver));
-    if (!s)
-        goto fail;
-
-#ifndef _WIN32
-    if (is_unix)
-        fd = socket_create( SOCKET_UNIX, SOCKET_STREAM );
-    else
-#endif
-        fd = socket_create_inet( SOCKET_STREAM );
-
-    if (fd < 0)
-        goto fail;
-
-    if (!is_waitconnect)
-        socket_set_nonblock(fd);
-
-    s->connected = 0;
-    s->fd = -1;
-    s->listen_fd = -1;
-    s->is_unix = is_unix;
-    s->do_nodelay = do_nodelay && !is_unix;
-
-    chr->opaque = s;
-    chr->chr_write = tcp_chr_write;
-    chr->chr_close = tcp_chr_close;
-
-    if (is_listen) {
-        /* allow fast reuse */
-#ifndef _WIN32
-    if (is_unix) {
-        unlink( sock_address_get_path(&saddr) );
-    } else
-#endif
-        socket_set_xreuseaddr(fd);
-
-        if (socket_bind(fd, &saddr) < 0 ||
-            socket_listen(fd, 0) < 0)
-            goto fail;
-
-        s->listen_fd = fd;
-        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
-        if (is_telnet)
-            s->do_telnetopt = 1;
-    } else {
-        for(;;) {
-            ret = socket_connect(fd, &saddr);
-            if (ret < 0) {
-                err = errno;
-                if (err == EINTR || err == EWOULDBLOCK) {
-                } else if (err == EINPROGRESS) {
-                    break;
-#ifdef _WIN32
-                } else if (err == EALREADY) {
-                    break;
-#endif
-                } else {
-                    goto fail;
-                }
-            } else {
-                s->connected = 1;
-                break;
-            }
-        }
-        s->fd = fd;
-        socket_set_nodelay(fd);
-        if (s->connected)
-            tcp_chr_connect(chr);
-        else
-            qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
-    }
-
-    if (is_listen && is_waitconnect) {
-        printf("QEMU waiting for connection on: %s\n", host_str);
-        tcp_chr_accept(chr);
-        socket_set_nonblock(s->listen_fd);
-    }
-
-    return chr;
- fail:
-    if (fd >= 0)
-        socket_close(fd);
-    qemu_free(s);
-    qemu_free(chr);
-    return NULL;
-}
-
-CharDriverState *qemu_chr_open(const char *filename)
-{
-    const char *p;
-
-    if (!strcmp(filename, "vc")) {
-        return text_console_init(&display_state, 0);
-    } else if (strstart(filename, "vc:", &p)) {
-        return text_console_init(&display_state, p);
-    } else if (!strcmp(filename, "null")) {
-        return qemu_chr_open_null();
-    } else
-    if (strstart(filename, "tcp:", &p)) {
-        return qemu_chr_open_tcp(p, 0, 0);
-    } else
-    if (strstart(filename, "telnet:", &p)) {
-        return qemu_chr_open_tcp(p, 1, 0);
-    } else
-    if (strstart(filename, "udp:", &p)) {
-        return qemu_chr_open_udp(p);
-    } else
-    if (strstart(filename, "mon:", &p)) {
-        CharDriverState *drv = qemu_chr_open(p);
-        if (drv) {
-            drv = qemu_chr_open_mux(drv);
-            monitor_init(drv, !nographic);
-            return drv;
-        }
-        printf("Unable to open driver: %s\n", p);
-        return 0;
-    } else
-#ifndef _WIN32
-    if (strstart(filename, "unix:", &p)) {
-	return qemu_chr_open_tcp(p, 0, 1);
-    } else if (strstart(filename, "file:", &p)) {
-        return qemu_chr_open_file_out(p);
-    } else if (strstart(filename, "pipe:", &p)) {
-        return qemu_chr_open_pipe(p);
-    } else if (!strcmp(filename, "pty")) {
-        return qemu_chr_open_pty();
-    } else if (!strcmp(filename, "stdio")) {
-        return qemu_chr_open_stdio();
-    } else if (strstart(filename, "fdpair:", &p)) {
-        return qemu_chr_open_fdpair(p);
-    } else
-#endif
-#if defined(__linux__)
-    if (strstart(filename, "/dev/parport", NULL)) {
-        return qemu_chr_open_pp(filename);
-    } else
-#endif
-#ifndef _WIN32
-    if (strstart(filename, "/dev/", NULL)) {
-        return qemu_chr_open_tty(filename);
-    } else
-#endif
-    if (!strcmp(filename, "android-modem")) {
-        CharDriverState*  cs;
-        qemu_chr_open_charpipe( &cs, &android_modem_cs );
-        return cs;
-    } else if (!strcmp(filename, "android-gps")) {
-        CharDriverState*  cs;
-        qemu_chr_open_charpipe( &cs, &android_gps_cs );
-        return cs;
-    } else if (!strcmp(filename, "android-kmsg")) {
-        return android_kmsg_get_cs();
-    } else if (!strcmp(filename, "android-qemud")) {
-        return android_qemud_get_cs();
-    } else
-#if defined(__linux__)
-    if (strstart(filename, "/dev/parport", NULL)) {
-        return qemu_chr_open_pp(filename);
-    } else
-#endif
-#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__)
-    if (strstart(filename, "/dev/", NULL)) {
-        return qemu_chr_open_tty(filename);
-    } else
-#endif
-#ifdef _WIN32
-    if (strstart(filename, "COM", NULL)) {
-        return qemu_chr_open_win(filename);
-    } else
-    if (strstart(filename, "pipe:", &p)) {
-        return qemu_chr_open_win_pipe(p);
-    } else
-    if (strstart(filename, "con:", NULL)) {
-        return qemu_chr_open_win_con(filename);
-    } else
-    if (strstart(filename, "file:", &p)) {
-        return qemu_chr_open_win_file_out(p);
-    } else
-#endif
-#ifdef CONFIG_BRLAPI
-    if (!strcmp(filename, "braille")) {
-        return chr_baum_init();
-    } else
-#endif
-    {
-        return NULL;
-    }
-}
-
-void qemu_chr_close(CharDriverState *chr)
-{
-    if (chr->chr_close)
-        chr->chr_close(chr);
-    qemu_free(chr);
-}
-
-/***********************************************************/
-/* network device redirectors */
-
-__attribute__ (( unused ))
-static void hex_dump(FILE *f, const uint8_t *buf, int size)
-{
-    int len, i, j, c;
-
-    for(i=0;i<size;i+=16) {
-        len = size - i;
-        if (len > 16)
-            len = 16;
-        fprintf(f, "%08x ", i);
-        for(j=0;j<16;j++) {
-            if (j < len)
-                fprintf(f, " %02x", buf[i+j]);
-            else
-                fprintf(f, "   ");
-        }
-        fprintf(f, " ");
-        for(j=0;j<len;j++) {
-            c = buf[i+j];
-            if (c < ' ' || c > '~')
-                c = '.';
-            fprintf(f, "%c", c);
-        }
-        fprintf(f, "\n");
-    }
-}
-
-static int parse_macaddr(uint8_t *macaddr, const char *p)
-{
-    int i;
-    char *last_char;
-    long int offset;
-
-    errno = 0;
-    offset = strtol(p, &last_char, 0);    
-    if (0 == errno && '\0' == *last_char &&
-            offset >= 0 && offset <= 0xFFFFFF) {
-        macaddr[3] = (offset & 0xFF0000) >> 16;
-        macaddr[4] = (offset & 0xFF00) >> 8;
-        macaddr[5] = offset & 0xFF;
-        return 0;
-    } else {
-        for(i = 0; i < 6; i++) {
-            macaddr[i] = strtol(p, (char **)&p, 16);
-            if (i == 5) {
-                if (*p != '\0')
-                    return -1;
-            } else {
-                if (*p != ':' && *p != '-')
-                    return -1;
-                p++;
-            }
-        }
-        return 0;    
-    }
-
-    return -1;
-}
-
-static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
-{
-    const char *p, *p1;
-    int len;
-    p = *pp;
-    p1 = strchr(p, sep);
-    if (!p1)
-        return -1;
-    len = p1 - p;
-    p1++;
-    if (buf_size > 0) {
-        if (len > buf_size - 1)
-            len = buf_size - 1;
-        memcpy(buf, p, len);
-        buf[len] = '\0';
-    }
-    *pp = p1;
-    return 0;
-}
-
-int parse_host_src_port(SockAddress *haddr,
-                        SockAddress *saddr,
-                        const char *input_str)
-{
-    char *str = strdup(input_str);
-    char *host_str = str;
-    char *src_str;
-    const char *src_str2;
-    char *ptr;
-
-    /*
-     * Chop off any extra arguments at the end of the string which
-     * would start with a comma, then fill in the src port information
-     * if it was provided else use the "any address" and "any port".
-     */
-    if ((ptr = strchr(str,',')))
-        *ptr = '\0';
-
-    if ((src_str = strchr(input_str,'@'))) {
-        *src_str = '\0';
-        src_str++;
-    }
-
-    if (parse_host_port(haddr, host_str) < 0)
-        goto fail;
-
-    src_str2 = src_str;
-    if (!src_str || *src_str == '\0')
-        src_str2 = ":0";
-
-    if (parse_host_port(saddr, src_str2) < 0)
-        goto fail;
-
-    free(str);
-    return(0);
-
-fail:
-    free(str);
-    return -1;
-}
-
-int parse_host_port(SockAddress  *saddr, const char *str)
-{
-    char buf[512];
-    const char *p, *r;
-    uint16_t  port;
-
-    p = str;
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
-        return -1;
-
-    port = strtol(p, (char **)&r, 0);
-    if (r == p)
-        return -1;
-
-    if (buf[0] == '\0') {
-        sock_address_init_inet( saddr, SOCK_ADDRESS_INET_ANY, port );
-    } else {
-        if (sock_address_init_resolve( saddr, buf, port, 0 ) < 0)
-            return -1;
-    }
-    return 0;
-}
-
-#ifndef _WIN32
-static int
-parse_unix_path(SockAddress*  uaddr, const char *str)
-{
-    char  temp[109];
-    const char *p;
-    int len;
-
-    len = MIN(108, strlen(str));
-    p = strchr(str, ',');
-    if (p)
-        len = MIN(len, p - str);
-
-    memcpy(temp, str, len);
-    temp[len] = 0;
-
-    sock_address_init_unix( uaddr, temp );
-    return 0;
-}
-#endif
-
-/* find or alloc a new VLAN */
-VLANState *qemu_find_vlan(int id)
-{
-    VLANState **pvlan, *vlan;
-    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
-        if (vlan->id == id)
-            return vlan;
-    }
-    vlan = qemu_mallocz(sizeof(VLANState));
-    if (!vlan)
-        return NULL;
-    vlan->id = id;
-    vlan->next = NULL;
-    pvlan = &first_vlan;
-    while (*pvlan != NULL)
-        pvlan = &(*pvlan)->next;
-    *pvlan = vlan;
-    return vlan;
-}
-
-VLANClientState *qemu_new_vlan_client(VLANState *vlan,
-                                      IOReadHandler *fd_read,
-                                      IOCanRWHandler *fd_can_read,
-                                      void *opaque)
-{
-    VLANClientState *vc, **pvc;
-    vc = qemu_mallocz(sizeof(VLANClientState));
-    if (!vc)
-        return NULL;
-    vc->fd_read = fd_read;
-    vc->fd_can_read = fd_can_read;
-    vc->opaque = opaque;
-    vc->vlan = vlan;
-
-    vc->next = NULL;
-    pvc = &vlan->first_client;
-    while (*pvc != NULL)
-        pvc = &(*pvc)->next;
-    *pvc = vc;
-    return vc;
-}
-
-void qemu_del_vlan_client(VLANClientState *vc)
-{
-    VLANClientState **pvc = &vc->vlan->first_client;
-
-    while (*pvc != NULL)
-        if (*pvc == vc) {
-            *pvc = vc->next;
-            free(vc);
-            break;
-        } else
-            pvc = &(*pvc)->next;
-}
-
-int qemu_can_send_packet(VLANClientState *vc1)
-{
-    VLANState *vlan = vc1->vlan;
-    VLANClientState *vc;
-
-    for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
-        if (vc != vc1) {
-            if (vc->fd_can_read && vc->fd_can_read(vc->opaque))
-                return 1;
-        }
-    }
-    return 0;
-}
-
-void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
-{
-    VLANState *vlan = vc1->vlan;
-    VLANClientState *vc;
-
-#if 0
-    printf("vlan %d send:\n", vlan->id);
-    hex_dump(stdout, buf, size);
-#endif
-    for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
-        if (vc != vc1) {
-            vc->fd_read(vc->opaque, buf, size);
-        }
-    }
-}
-
-#if defined(CONFIG_SLIRP)
-
-/* slirp network adapter */
-
-int slirp_inited;
-static VLANClientState *slirp_vc;
-
-double   qemu_net_upload_speed   = 0.;
-double   qemu_net_download_speed = 0.;
-int      qemu_net_min_latency = 0;
-int      qemu_net_max_latency = 0;
-int      qemu_net_disable = 0;
-
-int
-ip_packet_is_internal( const uint8_t*  data, size_t  size )
-{
-    const uint8_t*  end = data + size;
-
-    /* must have room for Mac + IP header */
-    if (data + 40 > end)
-        return 0;
-
-    if (data[12] != 0x08 || data[13] != 0x00 )
-        return 0;
-
-    /* must have valid IP header */
-    data += 14;
-    if ((data[0] >> 4) != 4 || (data[0] & 15) < 5)
-        return 0;
-
-    /* internal if both source and dest addresses are in 10.x.x.x */
-    return ( data[12] == 10 && data[16] == 10);
-}
-
-#ifdef CONFIG_SHAPER
-
-/* see http://en.wikipedia.org/wiki/List_of_device_bandwidths or a complete list */
-const NetworkSpeed  android_netspeeds[] = {
-    { "gsm", "GSM/CSD", 14400, 14400 },
-    { "hscsd", "HSCSD", 14400, 43200 },
-    { "gprs", "GPRS", 40000, 80000 },
-    { "edge", "EDGE/EGPRS", 118400, 236800 },
-    { "umts", "UMTS/3G", 128000, 1920000 },
-    { "hsdpa", "HSDPA", 348000, 14400000 },
-    { "full", "no limit", 0, 0 },
-    { NULL, NULL, 0, 0 }
-};
-
-const NetworkLatency  android_netdelays[] = {
-    /* FIXME: these numbers are totally imaginary */
-    { "gprs", "GPRS", 150, 550 },
-    { "edge", "EDGE/EGPRS", 80, 400 },
-    { "umts", "UMTS/3G", 35, 200 },
-    { "none", "no latency", 0, 0 },
-    { NULL, NULL, 0, 0 }
-};
-
-
-NetShaper  slirp_shaper_in;
-NetShaper  slirp_shaper_out;
-NetDelay   slirp_delay_in;
-
-static void
-slirp_delay_in_cb( void*   data,
-                   size_t  size,
-                   void*   opaque )
-{
-    slirp_input( (const uint8_t*)data, (int)size );
-    opaque = opaque;
-}
-
-static void
-slirp_shaper_in_cb( void*   data,
-                    size_t  size,
-                    void*   opaque )
-{
-    netdelay_send_aux( slirp_delay_in, data, size, opaque );
-}
-
-static void
-slirp_shaper_out_cb( void*   data,
-                     size_t  size,
-                     void*   opaque )
-{
-    qemu_send_packet( slirp_vc, (const uint8_t*)data, (int)size );
-}
-
-void
-slirp_init_shapers( void )
-{
-    slirp_delay_in   = netdelay_create( slirp_delay_in_cb );
-    slirp_shaper_in  = netshaper_create( 1, slirp_shaper_in_cb );
-    slirp_shaper_out = netshaper_create( 1, slirp_shaper_out_cb );
-
-    netdelay_set_latency( slirp_delay_in, qemu_net_min_latency, qemu_net_max_latency );
-    netshaper_set_rate( slirp_shaper_out, qemu_net_download_speed );
-    netshaper_set_rate( slirp_shaper_in,  qemu_net_upload_speed  );
-}
-
-#endif /* CONFIG_SHAPER */
-
-int slirp_can_output(void)
-{
-#ifdef CONFIG_SHAPER
-    return !slirp_vc                                ||
-           ( netshaper_can_send( slirp_shaper_out ) &&
-             qemu_can_send_packet(slirp_vc) );
-#else
-    return !slirp_vc || qemu_can_send_packet(slirp_vc);
-#endif
-}
-
-
-
-void slirp_output(const uint8_t *pkt, int pkt_len)
-{
-#if 0
-    printf("slirp output:\n");
-    hex_dump(stdout, pkt, pkt_len);
-#endif
-    if (!slirp_vc)
-        return;
-
-    if (qemu_tcpdump_active)
-        qemu_tcpdump_packet(pkt, pkt_len);
-
-    /* always send internal packets */
-    if ( ip_packet_is_internal( pkt, pkt_len ) ) {
-        qemu_send_packet( slirp_vc, pkt, pkt_len );
-        return;
-    }
-
-    if ( qemu_net_disable )
-        return;
-
-#ifdef CONFIG_SHAPER
-    netshaper_send( slirp_shaper_out, (void*)pkt, pkt_len );
-#else
-    qemu_send_packet(slirp_vc, pkt, pkt_len);
-#endif
-}
-
-static void slirp_receive(void *opaque, const uint8_t *buf, int size)
-{
-#if 0
-    printf("slirp input:\n");
-    hex_dump(stdout, buf, size);
-#endif
-    if (qemu_tcpdump_active)
-        qemu_tcpdump_packet(buf, size);
-
-    if ( ip_packet_is_internal( buf, size ) ) {
-        slirp_input(buf, size);
-        return;
-    }
-
-    if (qemu_net_disable)
-        return;
-
-#ifdef CONFIG_SHAPER
-    netshaper_send( slirp_shaper_in, (char*)buf, size );
-#else
-    slirp_input(buf, size);
-#endif
-}
-
-static int net_slirp_init(VLANState *vlan)
-{
-    if (!slirp_inited) {
-        slirp_inited = 1;
-        slirp_init();
-    }
-    slirp_vc = qemu_new_vlan_client(vlan,
-                                    slirp_receive, NULL, NULL);
-    snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector");
-    return 0;
-}
-
-static void net_slirp_redir(const char *redir_str)
-{
-    int is_udp;
-    char buf[256], *r;
-    const char *p;
-    uint32_t  guest_ip;
-    int host_port, guest_port;
-
-    if (!slirp_inited) {
-        slirp_inited = 1;
-        slirp_init();
-    }
-
-    p = redir_str;
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
-        goto fail;
-    if (!strcmp(buf, "tcp")) {
-        is_udp = 0;
-    } else if (!strcmp(buf, "udp")) {
-        is_udp = 1;
-    } else {
-        goto fail;
-    }
-
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
-        goto fail;
-    host_port = strtol(buf, &r, 0);
-    if (r == buf)
-        goto fail;
-
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
-        goto fail;
-    if (buf[0] == '\0') {
-        pstrcpy(buf, sizeof(buf), "10.0.2.15");
-    }
-    if (inet_strtoip(buf, &guest_ip) < 0)
-        goto fail;
-
-    guest_port = strtol(p, &r, 0);
-    if (r == p)
-        goto fail;
-
-    if (slirp_redir(is_udp, host_port, guest_ip, guest_port) < 0) {
-        fprintf(stderr, "qemu: could not set up redirection\n");
-        exit(1);
-    }
-    return;
- fail:
-    fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n");
-    exit(1);
-}
-
-#if 0  /* ANDROID disabled */
-
-char smb_dir[1024];
-
-static void erase_dir(char *dir_name)
-{
-    DIR *d;
-    struct dirent *de;
-    char filename[1024];
-
-    /* erase all the files in the directory */
-    if ((d = opendir(dir_name)) != 0) {
-        for(;;) {
-            de = readdir(d);
-            if (!de)
-                break;
-            if (strcmp(de->d_name, ".") != 0 &&
-                strcmp(de->d_name, "..") != 0) {
-                snprintf(filename, sizeof(filename), "%s/%s",
-                         smb_dir, de->d_name);
-                if (unlink(filename) != 0)  /* is it a directory? */
-                    erase_dir(filename);
-            }
-        }
-        closedir(d);
-        rmdir(dir_name);
-    }
-}
-
-/* automatic user mode samba server configuration */
-static void smb_exit(void)
-{
-    erase_dir(smb_dir);
-}
-
-/* automatic user mode samba server configuration */
-static void net_slirp_smb(const char *exported_dir)
-{
-    char smb_conf[1024];
-    char smb_cmdline[1024];
-    FILE *f;
-
-    if (!slirp_inited) {
-        slirp_inited = 1;
-        slirp_init();
-    }
-
-    /* XXX: better tmp dir construction */
-    snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%d", getpid());
-    if (mkdir(smb_dir, 0700) < 0) {
-        fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir);
-        exit(1);
-    }
-    snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf");
-
-    f = fopen(smb_conf, "w");
-    if (!f) {
-        fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf);
-        exit(1);
-    }
-    fprintf(f,
-            "[global]\n"
-            "private dir=%s\n"
-            "smb ports=0\n"
-            "socket address=127.0.0.1\n"
-            "pid directory=%s\n"
-            "lock directory=%s\n"
-            "log file=%s/log.smbd\n"
-            "smb passwd file=%s/smbpasswd\n"
-            "security = share\n"
-            "[qemu]\n"
-            "path=%s\n"
-            "read only=no\n"
-            "guest ok=yes\n",
-            smb_dir,
-            smb_dir,
-            smb_dir,
-            smb_dir,
-            smb_dir,
-            exported_dir
-            );
-    fclose(f);
-    atexit(smb_exit);
-
-    snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
-             SMBD_COMMAND, smb_conf);
-
-    slirp_add_exec(0, smb_cmdline, 4, 139);
-}
-
-#endif /* !defined(_WIN32) */
-
-#endif /* CONFIG_SLIRP */
-
-#if !defined(_WIN32)
-
-typedef struct TAPState {
-    VLANClientState *vc;
-    int fd;
-    char down_script[1024];
-} TAPState;
-
-static void tap_receive(void *opaque, const uint8_t *buf, int size)
-{
-    TAPState *s = opaque;
-    int ret;
-    for(;;) {
-        ret = write(s->fd, buf, size);
-        if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
-        } else {
-            break;
-        }
-    }
-}
-
-static void tap_send(void *opaque)
-{
-    TAPState *s = opaque;
-    uint8_t buf[4096];
-    int size;
-
-#ifdef __sun__
-    struct strbuf sbuf;
-    int f = 0;
-    sbuf.maxlen = sizeof(buf);
-    sbuf.buf = buf;
-    size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
-#else
-    size = read(s->fd, buf, sizeof(buf));
-#endif
-    if (size > 0) {
-        qemu_send_packet(s->vc, buf, size);
-    }
-}
-
-/* fd support */
-
-static TAPState *net_tap_fd_init(VLANState *vlan, int fd)
-{
-    TAPState *s;
-
-    s = qemu_mallocz(sizeof(TAPState));
-    if (!s)
-        return NULL;
-    s->fd = fd;
-    s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s);
-    qemu_set_fd_handler(s->fd, tap_send, NULL, s);
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd);
-    return s;
-}
-
-#if defined (_BSD) || defined (__FreeBSD_kernel__)
-static int tap_open(char *ifname, int ifname_size)
-{
-    int fd;
-    char *dev;
-    struct stat s;
-
-    TFR(fd = open("/dev/tap", O_RDWR));
-    if (fd < 0) {
-        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
-        return -1;
-    }
-
-    fstat(fd, &s);
-    dev = devname(s.st_rdev, S_IFCHR);
-    pstrcpy(ifname, ifname_size, dev);
-
-    fcntl(fd, F_SETFL, O_NONBLOCK);
-    return fd;
-}
-#elif defined(__sun__)
-#define TUNNEWPPA       (('T'<<16) | 0x0001)
-/*
- * Allocate TAP device, returns opened fd.
- * Stores dev name in the first arg(must be large enough).
- */
-int tap_alloc(char *dev, size_t dev_size)
-{
-    int tap_fd, if_fd, ppa = -1;
-    static int ip_fd = 0;
-    char *ptr;
-
-    static int arp_fd = 0;
-    int ip_muxid, arp_muxid;
-    struct strioctl  strioc_if, strioc_ppa;
-    int link_type = I_PLINK;;
-    struct lifreq ifr;
-    char actual_name[32] = "";
-
-    memset(&ifr, 0x0, sizeof(ifr));
-
-    if( *dev ){
-       ptr = dev;
-       while( *ptr && !isdigit((int)*ptr) ) ptr++;
-       ppa = atoi(ptr);
-    }
-
-    /* Check if IP device was opened */
-    if( ip_fd )
-       close(ip_fd);
-
-    TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
-    if (ip_fd < 0) {
-       syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
-       return -1;
-    }
-
-    TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
-    if (tap_fd < 0) {
-       syslog(LOG_ERR, "Can't open /dev/tap");
-       return -1;
-    }
-
-    /* Assign a new PPA and get its unit number. */
-    strioc_ppa.ic_cmd = TUNNEWPPA;
-    strioc_ppa.ic_timout = 0;
-    strioc_ppa.ic_len = sizeof(ppa);
-    strioc_ppa.ic_dp = (char *)&ppa;
-    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
-       syslog (LOG_ERR, "Can't assign new interface");
-
-    TFR(if_fd = open("/dev/tap", O_RDWR, 0));
-    if (if_fd < 0) {
-       syslog(LOG_ERR, "Can't open /dev/tap (2)");
-       return -1;
-    }
-    if(ioctl(if_fd, I_PUSH, "ip") < 0){
-       syslog(LOG_ERR, "Can't push IP module");
-       return -1;
-    }
-
-    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
-	syslog(LOG_ERR, "Can't get flags\n");
-
-    snprintf (actual_name, 32, "tap%d", ppa);
-    strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));
-
-    ifr.lifr_ppa = ppa;
-    /* Assign ppa according to the unit number returned by tun device */
-
-    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
-        syslog (LOG_ERR, "Can't set PPA %d", ppa);
-    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
-        syslog (LOG_ERR, "Can't get flags\n");
-    /* Push arp module to if_fd */
-    if (ioctl (if_fd, I_PUSH, "arp") < 0)
-        syslog (LOG_ERR, "Can't push ARP module (2)");
-
-    /* Push arp module to ip_fd */
-    if (ioctl (ip_fd, I_POP, NULL) < 0)
-        syslog (LOG_ERR, "I_POP failed\n");
-    if (ioctl (ip_fd, I_PUSH, "arp") < 0)
-        syslog (LOG_ERR, "Can't push ARP module (3)\n");
-    /* Open arp_fd */
-    TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
-    if (arp_fd < 0)
-       syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
-
-    /* Set ifname to arp */
-    strioc_if.ic_cmd = SIOCSLIFNAME;
-    strioc_if.ic_timout = 0;
-    strioc_if.ic_len = sizeof(ifr);
-    strioc_if.ic_dp = (char *)&ifr;
-    if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
-        syslog (LOG_ERR, "Can't set ifname to arp\n");
-    }
-
-    if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
-       syslog(LOG_ERR, "Can't link TAP device to IP");
-       return -1;
-    }
-
-    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
-        syslog (LOG_ERR, "Can't link TAP device to ARP");
-
-    close (if_fd);
-
-    memset(&ifr, 0x0, sizeof(ifr));
-    strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));
-    ifr.lifr_ip_muxid  = ip_muxid;
-    ifr.lifr_arp_muxid = arp_muxid;
-
-    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
-    {
-      ioctl (ip_fd, I_PUNLINK , arp_muxid);
-      ioctl (ip_fd, I_PUNLINK, ip_muxid);
-      syslog (LOG_ERR, "Can't set multiplexor id");
-    }
-
-    snprintf(dev, dev_size, "tap%d", ppa);
-    return tap_fd;
-}
-
-static int tap_open(char *ifname, int ifname_size)
-{
-    char  dev[10]="";
-    int fd;
-    if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){
-       fprintf(stderr, "Cannot allocate TAP device\n");
-       return -1;
-    }
-    pstrcpy(ifname, ifname_size, dev);
-    fcntl(fd, F_SETFL, O_NONBLOCK);
-    return fd;
-}
-#else
-static int tap_open(char *ifname, int ifname_size)
-{
-    struct ifreq ifr;
-    int fd, ret;
-
-    TFR(fd = open("/dev/net/tun", O_RDWR));
-    if (fd < 0) {
-        fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
-        return -1;
-    }
-    memset(&ifr, 0, sizeof(ifr));
-    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
-    if (ifname[0] != '\0')
-        pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
-    else
-        pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
-    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+    ret = WSAStartup(MAKEWORD(2,2), &Data);
     if (ret != 0) {
-        fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
-        close(fd);
+        err = WSAGetLastError();
+        fprintf(stderr, "WSAStartup: %d\n", err);
         return -1;
     }
-    pstrcpy(ifname, ifname_size, ifr.ifr_name);
-    fcntl(fd, F_SETFL, O_NONBLOCK);
-    return fd;
-}
-#endif
-
-static int launch_script(const char *setup_script, const char *ifname, int fd)
-{
-    int pid, status;
-    char *args[3];
-    char **parg;
-
-        /* try to launch network script */
-        pid = fork();
-        if (pid >= 0) {
-            if (pid == 0) {
-                int open_max = sysconf (_SC_OPEN_MAX), i;
-                for (i = 0; i < open_max; i++)
-                    if (i != STDIN_FILENO &&
-                        i != STDOUT_FILENO &&
-                        i != STDERR_FILENO &&
-                        i != fd)
-                        close(i);
-
-                parg = args;
-                *parg++ = (char *)setup_script;
-                *parg++ = (char *)ifname;
-                *parg++ = NULL;
-                execv(setup_script, args);
-                _exit(1);
-            }
-            while (waitpid(pid, &status, 0) != pid);
-            if (!WIFEXITED(status) ||
-                WEXITSTATUS(status) != 0) {
-                fprintf(stderr, "%s: could not launch network script\n",
-                        setup_script);
-                return -1;
-            }
-        }
-    return 0;
-}
-
-static int net_tap_init(VLANState *vlan, const char *ifname1,
-                        const char *setup_script, const char *down_script)
-{
-    TAPState *s;
-    int fd;
-    char ifname[128];
-
-    if (ifname1 != NULL)
-        pstrcpy(ifname, sizeof(ifname), ifname1);
-    else
-        ifname[0] = '\0';
-    TFR(fd = tap_open(ifname, sizeof(ifname)));
-    if (fd < 0)
-        return -1;
-
-    if (!setup_script || !strcmp(setup_script, "no"))
-        setup_script = "";
-    if (setup_script[0] != '\0') {
-	if (launch_script(setup_script, ifname, fd))
-	    return -1;
-    }
-    s = net_tap_fd_init(vlan, fd);
-    if (!s)
-        return -1;
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-             "tap: ifname=%s setup_script=%s", ifname, setup_script);
-    if (down_script && strcmp(down_script, "no"))
-        snprintf(s->down_script, sizeof(s->down_script), "%s", down_script);
-    return 0;
-}
-
-#endif /* !_WIN32 */
-
-#if defined(CONFIG_VDE)
-typedef struct VDEState {
-    VLANClientState *vc;
-    VDECONN *vde;
-} VDEState;
-
-static void vde_to_qemu(void *opaque)
-{
-    VDEState *s = opaque;
-    uint8_t buf[4096];
-    int size;
-
-    size = vde_recv(s->vde, buf, sizeof(buf), 0);
-    if (size > 0) {
-        qemu_send_packet(s->vc, buf, size);
-    }
-}
-
-static void vde_from_qemu(void *opaque, const uint8_t *buf, int size)
-{
-    VDEState *s = opaque;
-    int ret;
-    for(;;) {
-        ret = vde_send(s->vde, buf, size, 0);
-        if (ret < 0 && errno == EINTR) {
-        } else {
-            break;
-        }
-    }
-}
-
-static int net_vde_init(VLANState *vlan, const char *sock, int port,
-                        const char *group, int mode)
-{
-    VDEState *s;
-    char *init_group = strlen(group) ? (char *)group : NULL;
-    char *init_sock = strlen(sock) ? (char *)sock : NULL;
-
-    struct vde_open_args args = {
-        .port = port,
-        .group = init_group,
-        .mode = mode,
-    };
-
-    s = qemu_mallocz(sizeof(VDEState));
-    if (!s)
-        return -1;
-    s->vde = vde_open(init_sock, "QEMU", &args);
-    if (!s->vde){
-        free(s);
-        return -1;
-    }
-    s->vc = qemu_new_vlan_client(vlan, vde_from_qemu, NULL, s);
-    qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "vde: sock=%s fd=%d",
-             sock, vde_datafd(s->vde));
+    atexit(socket_cleanup);
     return 0;
 }
 #endif
 
-/* network connection */
-typedef struct NetSocketState {
-    VLANClientState *vc;
-    int fd;
-    int state; /* 0 = getting length, 1 = getting data */
-    int index;
-    int packet_len;
-    uint8_t buf[4096];
-    SockAddress dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
-} NetSocketState;
-
-typedef struct NetSocketListenState {
-    VLANState *vlan;
-    int fd;
-} NetSocketListenState;
-
-/* XXX: we consider we can send the whole packet without blocking */
-static void net_socket_receive(void *opaque, const uint8_t *buf, int size)
-{
-    NetSocketState *s = opaque;
-    uint32_t len;
-    len = htonl(size);
-
-    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
-    send_all(s->fd, buf, size);
-}
-
-static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
-{
-    NetSocketState *s = opaque;
-    socket_sendto(s->fd, buf, size, &s->dgram_dst);
-}
-
-static void net_socket_send(void *opaque)
-{
-    NetSocketState *s = opaque;
-    int l, size, err;
-    uint8_t buf1[4096];
-    const uint8_t *buf;
-
-    size = socket_recv(s->fd, buf1, sizeof(buf1));
-    if (size < 0) {
-        err = errno;
-        if (err != EWOULDBLOCK)
-            goto eoc;
-    } else if (size == 0) {
-        /* end of connection */
-    eoc:
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
-        socket_close(s->fd);
-        return;
-    }
-    buf = buf1;
-    while (size > 0) {
-        /* reassemble a packet from the network */
-        switch(s->state) {
-        case 0:
-            l = 4 - s->index;
-            if (l > size)
-                l = size;
-            memcpy(s->buf + s->index, buf, l);
-            buf += l;
-            size -= l;
-            s->index += l;
-            if (s->index == 4) {
-                /* got length */
-                s->packet_len = ntohl(*(uint32_t *)s->buf);
-                s->index = 0;
-                s->state = 1;
-            }
-            break;
-        case 1:
-            l = s->packet_len - s->index;
-            if (l > size)
-                l = size;
-            memcpy(s->buf + s->index, buf, l);
-            s->index += l;
-            buf += l;
-            size -= l;
-            if (s->index >= s->packet_len) {
-                qemu_send_packet(s->vc, s->buf, s->packet_len);
-                s->index = 0;
-                s->state = 0;
-            }
-            break;
-        }
-    }
-}
-
-static void net_socket_send_dgram(void *opaque)
-{
-    NetSocketState *s = opaque;
-    int size;
-
-    size = socket_recv(s->fd, s->buf, sizeof(s->buf));
-    if (size < 0)
-        return;
-    if (size == 0) {
-        /* end of connection */
-        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
-        return;
-    }
-    qemu_send_packet(s->vc, s->buf, size);
-}
-
-static int net_socket_mcast_create(SockAddress*  mcastaddr)
-{
-    uint32_t   mcast_ip = (uint32_t) sock_address_get_ip(mcastaddr);
-
-    int fd, ret;
-
-    if (!IN_MULTICAST(mcast_ip)) {
-        fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" does not contain a multicast address\n",
-                sock_address_to_string(mcastaddr));
-        return -1;
-
-    }
-    fd = socket_create_inet( SOCKET_DGRAM );
-    if (fd < 0) {
-        perror("socket(PF_INET, SOCK_DGRAM)");
-        return -1;
-    }
-
-#if 0
-    val = 1;
-    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
-                   (const char *)&val, sizeof(val));
-#else
-    ret=socket_set_xreuseaddr(fd);
-#endif
-    if (ret < 0) {
-	perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
-	goto fail;
-    }
-
-    if (socket_bind(fd, mcastaddr) < 0) {
-        perror("bind");
-        goto fail;
-    }
-
-    /* Add host to multicast group */
-    if (socket_mcast_inet_add_membership(fd, mcast_ip) < 0) {
-        perror("setsockopt(IP_ADD_MEMBERSHIP)");
-        goto fail;
-    }
-
-    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
-    if (socket_mcast_inet_set_loop(fd, 1) < 0) {
-        perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
-        goto fail;
-    }
-
-    socket_set_nonblock(fd);
-    return fd;
-fail:
-    if (fd >= 0)
-        closesocket(fd);
-    return -1;
-}
-
-static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
-                                          int is_connected)
-{
-    SockAddress  saddr;
-    int newfd;
-    NetSocketState *s;
-
-    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
-     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
-     * by ONLY ONE process: we must "clone" this dgram socket --jjo
-     */
-
-    if (is_connected) {
-	if (socket_get_address(fd, &saddr) == 0) {
-	    /* must be bound */
-	    if (sock_address_get_ip(&saddr) == 0) {
-		fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
-			fd);
-		return NULL;
-	    }
-	    /* clone dgram socket */
-	    newfd = net_socket_mcast_create(&saddr);
-	    if (newfd < 0) {
-		/* error already reported by net_socket_mcast_create() */
-		close(fd);
-		return NULL;
-	    }
-	    /* clone newfd to fd, close newfd */
-	    dup2(newfd, fd);
-	    close(newfd);
-
-	} else {
-	    fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
-		    fd, errno_str);
-	    return NULL;
-	}
-    }
-
-    s = qemu_mallocz(sizeof(NetSocketState));
-    if (!s)
-        return NULL;
-    s->fd = fd;
-
-    s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, NULL, s);
-    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
-
-    /* mcast: save bound address as dst */
-    if (is_connected) s->dgram_dst=saddr;
-
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-	    "socket: fd=%d (%s mcast=%s)",
-	    fd, is_connected? "cloned" : "",
-	    sock_address_to_string(&saddr));
-    return s;
-}
-
-static void net_socket_connect(void *opaque)
-{
-    NetSocketState *s = opaque;
-    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
-}
-
-static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
-                                          int is_connected)
-{
-    NetSocketState *s;
-    s = qemu_mallocz(sizeof(NetSocketState));
-    if (!s)
-        return NULL;
-    s->fd = fd;
-    s->vc = qemu_new_vlan_client(vlan,
-                                 net_socket_receive, NULL, s);
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-             "socket: fd=%d", fd);
-    if (is_connected) {
-        net_socket_connect(s);
-    } else {
-        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
-    }
-    return s;
-}
-
-static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
-                                          int is_connected)
-{
-    SocketType  so_type;
-
-    so_type = socket_get_type(fd);
-    switch(so_type) {
-    case SOCKET_DGRAM:
-        return net_socket_fd_init_dgram(vlan, fd, is_connected);
-    case SOCKET_STREAM:
-        return net_socket_fd_init_stream(vlan, fd, is_connected);
-    default:
-        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
-        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
-        return net_socket_fd_init_stream(vlan, fd, is_connected);
-    }
-    return NULL;
-}
-
-static void net_socket_accept(void *opaque)
-{
-    NetSocketListenState *s = opaque;
-    NetSocketState *s1;
-    SockAddress   saddr;
-    int fd;
-
-    fd = socket_accept(s->fd, &saddr);
-    if (fd < 0)
-        return;
-
-    s1 = net_socket_fd_init(s->vlan, fd, 1);
-    if (!s1) {
-        closesocket(fd);
-    } else {
-        snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
-                 "socket: connection from %s",
-                 sock_address_to_string(&saddr));
-    }
-    sock_address_done(&saddr);
-}
-
-static int net_socket_listen_init(VLANState *vlan, const char *host_str)
-{
-    NetSocketListenState *s;
-    int fd, ret;
-    SockAddress saddr;
-
-    if (parse_host_port(&saddr, host_str) < 0)
-        return -1;
-
-    s = qemu_mallocz(sizeof(NetSocketListenState));
-    if (!s)
-        return -1;
-
-    fd = socket_create_inet( SOCKET_STREAM );
-    if (fd < 0) {
-        perror("socket");
-        return -1;
-    }
-    socket_set_nonblock(fd);
-#if 0
-    /* allow fast reuse */
-    val = 1;
-    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
-#else
-    socket_set_xreuseaddr(fd);
-#endif
-
-    ret = socket_bind(fd, &saddr);
-    if (ret < 0) {
-        perror("bind");
-        socket_close(fd);
-        return -1;
-    }
-    ret = socket_listen(fd, 0);
-    if (ret < 0) {
-        perror("listen");
-        socket_close(fd);
-        return -1;
-    }
-    s->vlan = vlan;
-    s->fd   = fd;
-    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
-    return 0;
-}
-
-static int net_socket_connect_init(VLANState *vlan, const char *host_str)
-{
-    NetSocketState *s;
-    int fd, connected, ret, err;
-    SockAddress  saddr;
-
-    if (parse_host_port(&saddr, host_str) < 0)
-        return -1;
-
-    fd = socket_create_inet( SOCKET_STREAM );
-    if (fd < 0) {
-        perror("socket");
-        return -1;
-    }
-    socket_set_nonblock(fd);
-
-    connected = 0;
-    for(;;) {
-        ret = socket_connect(fd, &saddr);
-        if (ret < 0) {
-            err = errno;
-            if (err == EINTR || err == EWOULDBLOCK) {
-            } else if (err == EINPROGRESS) {
-                break;
-#ifdef _WIN32
-            } else if (err == EALREADY) {
-                break;
-#endif
-            } else {
-                perror("connect");
-                socket_close(fd);
-                return -1;
-            }
-        } else {
-            connected = 1;
-            break;
-        }
-    }
-    s = net_socket_fd_init(vlan, fd, connected);
-    if (!s)
-        return -1;
-
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-             "socket: connect to %s", sock_address_to_string(&saddr));
-    return 0;
-}
-
-static int net_socket_mcast_init(VLANState *vlan, const char *host_str)
-{
-    NetSocketState *s;
-    int fd;
-    SockAddress  saddr;
-
-    if (parse_host_port(&saddr, host_str) < 0)
-        return -1;
-
-
-    fd = net_socket_mcast_create(&saddr);
-    if (fd < 0)
-	return -1;
-
-    s = net_socket_fd_init(vlan, fd, 0);
-    if (!s)
-        return -1;
-
-    s->dgram_dst = saddr;
-
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-             "socket: mcast=%s", sock_address_to_string(&saddr));
-    return 0;
-
-}
-
-static const char *get_opt_name(char *buf, int buf_size, const char *p)
-{
-    char *q;
-
-    q = buf;
-    while (*p != '\0' && *p != '=') {
-        if (q && (q - buf) < buf_size - 1)
-            *q++ = *p;
-        p++;
-    }
-    if (q)
-        *q = '\0';
-
-    return p;
-}
-
-static const char *get_opt_value(char *buf, int buf_size, const char *p)
-{
-    char *q;
-
-    q = buf;
-    while (*p != '\0') {
-        if (*p == ',') {
-            if (*(p + 1) != ',')
-                break;
-            p++;
-        }
-        if (q && (q - buf) < buf_size - 1)
-            *q++ = *p;
-        p++;
-    }
-    if (q)
-        *q = '\0';
-
-    return p;
-}
-
-static int get_param_value(char *buf, int buf_size,
-                           const char *tag, const char *str)
+int get_param_value(char *buf, int buf_size,
+                    const char *tag, const char *str)
 {
     const char *p;
     char option[128];
 
     p = str;
     for(;;) {
-        p = get_opt_name(option, sizeof(option), p);
+        p = get_opt_name(option, sizeof(option), p, '=');
         if (*p != '=')
             break;
         p++;
@@ -5385,247 +1837,287 @@
     return 0;
 }
 
-static int check_params(char *buf, int buf_size,
-                        const char * const *params, const char *str)
+int check_params(char *buf, int buf_size,
+                 const char * const *params, const char *str)
 {
     const char *p;
     int i;
 
     p = str;
-    for(;;) {
-        p = get_opt_name(buf, buf_size, p);
-        if (*p != '=')
+    while (*p != '\0') {
+        p = get_opt_name(buf, buf_size, p, '=');
+        if (*p != '=') {
             return -1;
+        }
         p++;
-        for(i = 0; params[i] != NULL; i++)
-            if (!strcmp(params[i], buf))
+        for (i = 0; params[i] != NULL; i++) {
+            if (!strcmp(params[i], buf)) {
                 break;
-        if (params[i] == NULL)
+            }
+        }
+        if (params[i] == NULL) {
             return -1;
+        }
         p = get_opt_value(NULL, 0, p);
-        if (*p != ',')
+        if (*p != ',') {
             break;
+        }
         p++;
     }
     return 0;
 }
 
-static int net_client_init(const char *device, const char *p)
+/***********************************************************/
+/* Bluetooth support */
+static int nb_hcis;
+static int cur_hci;
+static struct HCIInfo *hci_table[MAX_NICS];
+
+static struct bt_vlan_s {
+    struct bt_scatternet_s net;
+    int id;
+    struct bt_vlan_s *next;
+} *first_bt_vlan;
+
+/* find or alloc a new bluetooth "VLAN" */
+static struct bt_scatternet_s *qemu_find_bt_vlan(int id)
 {
-    char buf[1024];
-    int vlan_id, ret;
-    VLANState *vlan;
-
-    vlan_id = 0;
-    if (get_param_value(buf, sizeof(buf), "vlan", p)) {
-        vlan_id = strtol(buf, NULL, 0);
+    struct bt_vlan_s **pvlan, *vlan;
+    for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->id == id)
+            return &vlan->net;
     }
-    vlan = qemu_find_vlan(vlan_id);
-    if (!vlan) {
-        fprintf(stderr, "Could not create vlan %d\n", vlan_id);
-        return -1;
-    }
-    if (!strcmp(device, "nic")) {
-        NICInfo *nd;
-        uint8_t *macaddr;
-
-        if (nb_nics >= MAX_NICS) {
-            fprintf(stderr, "Too Many NICs\n");
-            return -1;
-        }
-        nd = &nd_table[nb_nics];
-        macaddr = nd->macaddr;
-        macaddr[0] = 0x52;
-        macaddr[1] = 0x54;
-        macaddr[2] = 0x00;
-        macaddr[3] = 0x12;
-        macaddr[4] = 0x34;
-        macaddr[5] = 0x56 + nb_nics;
-
-        if (get_param_value(buf, sizeof(buf), "macaddr", p)) {
-            if (parse_macaddr(macaddr, buf) < 0) {
-                fprintf(stderr, "invalid syntax for ethernet address\n");
-                return -1;
-            }
-        }
-        if (get_param_value(buf, sizeof(buf), "model", p)) {
-            nd->model = strdup(buf);
-        }
-        nd->vlan = vlan;
-        nb_nics++;
-        vlan->nb_guest_devs++;
-        ret = 0;
-    } else
-    if (!strcmp(device, "none")) {
-        /* does nothing. It is needed to signal that no network cards
-           are wanted */
-#if 1 /* ANDROID */
-        fprintf(stderr, "sorry, you need to enable the network to use the Android emulator\n");
-        return -1;
-#else
-        ret = 0;
-#endif
-    } else
-#ifdef CONFIG_SLIRP
-    if (!strcmp(device, "user")) {
-        if (get_param_value(buf, sizeof(buf), "hostname", p)) {
-            pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf);
-        }
-        vlan->nb_host_devs++;
-        ret = net_slirp_init(vlan);
-    } else
-#endif
-#ifdef _WIN32
-#if 0
-    if (!strcmp(device, "tap")) {
-        char ifname[64];
-        if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
-            fprintf(stderr, "tap: no interface name\n");
-            return -1;
-        }
-        vlan->nb_host_devs++;
-        ret = tap_win32_init(vlan, ifname);
-    } else
-#endif
-#else
-    if (!strcmp(device, "tap")) {
-        char ifname[64];
-        char setup_script[1024], down_script[1024];
-        int fd;
-        vlan->nb_host_devs++;
-        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
-            fd = strtol(buf, NULL, 0);
-            socket_set_nonblock(fd);
-            ret = -1;
-            if (net_tap_fd_init(vlan, fd))
-                ret = 0;
-        } else {
-            if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
-                ifname[0] = '\0';
-            }
-            if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
-                pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
-            }
-            if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) {
-                pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT);
-            }
-            ret = net_tap_init(vlan, ifname, setup_script, down_script);
-        }
-    } else
-#endif
-    if (!strcmp(device, "socket")) {
-        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
-            int fd;
-            fd = strtol(buf, NULL, 0);
-            ret = -1;
-            if (net_socket_fd_init(vlan, fd, 1))
-                ret = 0;
-        } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) {
-            ret = net_socket_listen_init(vlan, buf);
-        } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
-            ret = net_socket_connect_init(vlan, buf);
-        } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
-            ret = net_socket_mcast_init(vlan, buf);
-        } else {
-            fprintf(stderr, "Unknown socket options: %s\n", p);
-            return -1;
-        }
-        vlan->nb_host_devs++;
-    } else
-#ifdef CONFIG_VDE
-    if (!strcmp(device, "vde")) {
-        char vde_sock[1024], vde_group[512];
-	int vde_port, vde_mode;
-        vlan->nb_host_devs++;
-        if (get_param_value(vde_sock, sizeof(vde_sock), "sock", p) <= 0) {
-	    vde_sock[0] = '\0';
-	}
-	if (get_param_value(buf, sizeof(buf), "port", p) > 0) {
-	    vde_port = strtol(buf, NULL, 10);
-	} else {
-	    vde_port = 0;
-	}
-	if (get_param_value(vde_group, sizeof(vde_group), "group", p) <= 0) {
-	    vde_group[0] = '\0';
-	}
-	if (get_param_value(buf, sizeof(buf), "mode", p) > 0) {
-	    vde_mode = strtol(buf, NULL, 8);
-	} else {
-	    vde_mode = 0700;
-	}
-	ret = net_vde_init(vlan, vde_sock, vde_port, vde_group, vde_mode);
-    } else
-#endif
-    {
-        fprintf(stderr, "Unknown network device: %s\n", device);
-        return -1;
-    }
-    if (ret < 0) {
-        fprintf(stderr, "Could not initialize device '%s'\n", device);
-    }
-
-    return ret;
+    vlan = qemu_mallocz(sizeof(struct bt_vlan_s));
+    vlan->id = id;
+    pvlan = &first_bt_vlan;
+    while (*pvlan != NULL)
+        pvlan = &(*pvlan)->next;
+    *pvlan = vlan;
+    return &vlan->net;
 }
 
-static int net_client_parse(const char *str)
+static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
 {
-    const char *p;
-    char *q;
-    char device[64];
-
-    p = str;
-    q = device;
-    while (*p != '\0' && *p != ',') {
-        if ((q - device) < sizeof(device) - 1)
-            *q++ = *p;
-        p++;
-    }
-    *q = '\0';
-    if (*p == ',')
-        p++;
-
-    return net_client_init(device, p);
 }
 
-void do_info_network(void)
+static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
 {
-    VLANState *vlan;
-    VLANClientState *vc;
-
-    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
-        term_printf("VLAN %d devices:\n", vlan->id);
-        for(vc = vlan->first_client; vc != NULL; vc = vc->next)
-            term_printf("  %s\n", vc->info_str);
-    }
+    return -ENOTSUP;
 }
 
+static struct HCIInfo null_hci = {
+    .cmd_send = null_hci_send,
+    .sco_send = null_hci_send,
+    .acl_send = null_hci_send,
+    .bdaddr_set = null_hci_addr_set,
+};
+
+struct HCIInfo *qemu_next_hci(void)
+{
+    if (cur_hci == nb_hcis)
+        return &null_hci;
+
+    return hci_table[cur_hci++];
+}
+
+static struct HCIInfo *hci_init(const char *str)
+{
+    char *endp;
+    struct bt_scatternet_s *vlan = 0;
+
+    if (!strcmp(str, "null"))
+        /* null */
+        return &null_hci;
+    else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':'))
+        /* host[:hciN] */
+        return bt_host_hci(str[4] ? str + 5 : "hci0");
+    else if (!strncmp(str, "hci", 3)) {
+        /* hci[,vlan=n] */
+        if (str[3]) {
+            if (!strncmp(str + 3, ",vlan=", 6)) {
+                vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0));
+                if (*endp)
+                    vlan = 0;
+            }
+        } else
+            vlan = qemu_find_bt_vlan(0);
+        if (vlan)
+           return bt_new_hci(vlan);
+    }
+
+    fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str);
+
+    return 0;
+}
+
+static int bt_hci_parse(const char *str)
+{
+    struct HCIInfo *hci;
+    bdaddr_t bdaddr;
+
+    if (nb_hcis >= MAX_NICS) {
+        fprintf(stderr, "qemu: Too many bluetooth HCIs (max %i).\n", MAX_NICS);
+        return -1;
+    }
+
+    hci = hci_init(str);
+    if (!hci)
+        return -1;
+
+    bdaddr.b[0] = 0x52;
+    bdaddr.b[1] = 0x54;
+    bdaddr.b[2] = 0x00;
+    bdaddr.b[3] = 0x12;
+    bdaddr.b[4] = 0x34;
+    bdaddr.b[5] = 0x56 + nb_hcis;
+    hci->bdaddr_set(hci, bdaddr.b);
+
+    hci_table[nb_hcis++] = hci;
+
+    return 0;
+}
+
+static void bt_vhci_add(int vlan_id)
+{
+    struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id);
+
+    if (!vlan->slave)
+        fprintf(stderr, "qemu: warning: adding a VHCI to "
+                        "an empty scatternet %i\n", vlan_id);
+
+    bt_vhci_init(bt_new_hci(vlan));
+}
+
+static struct bt_device_s *bt_device_add(const char *opt)
+{
+    struct bt_scatternet_s *vlan;
+    int vlan_id = 0;
+    char *endp = strstr(opt, ",vlan=");
+    int len = (endp ? endp - opt : strlen(opt)) + 1;
+    char devname[10];
+
+    pstrcpy(devname, MIN(sizeof(devname), len), opt);
+
+    if (endp) {
+        vlan_id = strtol(endp + 6, &endp, 0);
+        if (*endp) {
+            fprintf(stderr, "qemu: unrecognised bluetooth vlan Id\n");
+            return 0;
+        }
+    }
+
+    vlan = qemu_find_bt_vlan(vlan_id);
+
+    if (!vlan->slave)
+        fprintf(stderr, "qemu: warning: adding a slave device to "
+                        "an empty scatternet %i\n", vlan_id);
+
+    if (!strcmp(devname, "keyboard"))
+        return bt_keyboard_init(vlan);
+
+    fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname);
+    return 0;
+}
+
+static int bt_parse(const char *opt)
+{
+    const char *endp, *p;
+    int vlan;
+
+    if (strstart(opt, "hci", &endp)) {
+        if (!*endp || *endp == ',') {
+            if (*endp)
+                if (!strstart(endp, ",vlan=", 0))
+                    opt = endp + 1;
+
+            return bt_hci_parse(opt);
+       }
+    } else if (strstart(opt, "vhci", &endp)) {
+        if (!*endp || *endp == ',') {
+            if (*endp) {
+                if (strstart(endp, ",vlan=", &p)) {
+                    vlan = strtol(p, (char **) &endp, 0);
+                    if (*endp) {
+                        fprintf(stderr, "qemu: bad scatternet '%s'\n", p);
+                        return 1;
+                    }
+                } else {
+                    fprintf(stderr, "qemu: bad parameter '%s'\n", endp + 1);
+                    return 1;
+                }
+            } else
+                vlan = 0;
+
+            bt_vhci_add(vlan);
+            return 0;
+        }
+    } else if (strstart(opt, "device:", &endp))
+        return !bt_device_add(endp);
+
+    fprintf(stderr, "qemu: bad bluetooth parameter '%s'\n", opt);
+    return 1;
+}
+
+/***********************************************************/
+/* QEMU Block devices */
+
 #define HD_ALIAS "index=%d,media=disk"
-#ifdef TARGET_PPC
-#define CDROM_ALIAS "index=1,media=cdrom"
-#else
 #define CDROM_ALIAS "index=2,media=cdrom"
-#endif
 #define FD_ALIAS "index=%d,if=floppy"
 #define PFLASH_ALIAS "if=pflash"
 #define MTD_ALIAS "if=mtd"
 #define SD_ALIAS "index=0,if=sd"
 
-static int drive_add(const char *file, const char *fmt, ...)
+static int drive_opt_get_free_idx(void)
+{
+    int index;
+
+    for (index = 0; index < MAX_DRIVES; index++)
+        if (!drives_opt[index].used) {
+            drives_opt[index].used = 1;
+            return index;
+        }
+
+    return -1;
+}
+
+static int drive_get_free_idx(void)
+{
+    int index;
+
+    for (index = 0; index < MAX_DRIVES; index++)
+        if (!drives_table[index].used) {
+            drives_table[index].used = 1;
+            return index;
+        }
+
+    return -1;
+}
+
+int drive_add(const char *file, const char *fmt, ...)
 {
     va_list ap;
+    int index = drive_opt_get_free_idx();
 
-    if (nb_drives_opt >= MAX_DRIVES) {
+    if (nb_drives_opt >= MAX_DRIVES || index == -1) {
         fprintf(stderr, "qemu: too many drives\n");
-        exit(1);
+        return -1;
     }
 
-    drives_opt[nb_drives_opt].file = file;
+    drives_opt[index].file = file;
     va_start(ap, fmt);
-    vsnprintf(drives_opt[nb_drives_opt].opt,
+    vsnprintf(drives_opt[index].opt,
               sizeof(drives_opt[0].opt), fmt, ap);
     va_end(ap);
 
-    return nb_drives_opt++;
+    nb_drives_opt++;
+    return index;
+}
+
+void drive_remove(int index)
+{
+    drives_opt[index].used = 0;
+    nb_drives_opt--;
 }
 
 int drive_get_index(BlockInterfaceType type, int bus, int unit)
@@ -5634,10 +2126,11 @@
 
     /* seek interface, bus and unit */
 
-    for (index = 0; index < nb_drives; index++)
+    for (index = 0; index < MAX_DRIVES; index++)
         if (drives_table[index].type == type &&
 	    drives_table[index].bus == bus &&
-	    drives_table[index].unit == unit)
+	    drives_table[index].unit == unit &&
+	    drives_table[index].used)
         return index;
 
     return -1;
@@ -5657,17 +2150,53 @@
     return max_bus;
 }
 
+const char *drive_get_serial(BlockDriverState *bdrv)
+{
+    int index;
+
+    for (index = 0; index < nb_drives; index++)
+        if (drives_table[index].bdrv == bdrv)
+            return drives_table[index].serial;
+
+    return "\0";
+}
+
+BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv)
+{
+    int index;
+
+    for (index = 0; index < nb_drives; index++)
+        if (drives_table[index].bdrv == bdrv)
+            return drives_table[index].onerror;
+
+    return BLOCK_ERR_STOP_ENOSPC;
+}
+
 static void bdrv_format_print(void *opaque, const char *name)
 {
     fprintf(stderr, " %s", name);
 }
 
-static int drive_init(struct drive_opt *arg, int snapshot,
-                      QEMUMachine *machine)
+void drive_uninit(BlockDriverState *bdrv)
+{
+    int i;
+
+    for (i = 0; i < MAX_DRIVES; i++)
+        if (drives_table[i].bdrv == bdrv) {
+            drives_table[i].bdrv = NULL;
+            drives_table[i].used = 0;
+            drive_remove(drives_table[i].drive_opt_idx);
+            nb_drives--;
+            break;
+        }
+}
+
+int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
 {
     char buf[128];
     char file[1024];
     char devname[128];
+    char serial[21];
     const char *mediastr = "";
     BlockInterfaceType type;
     enum { MEDIA_DISK, MEDIA_CDROM } media;
@@ -5675,15 +2204,18 @@
     int cyls, heads, secs, translation;
     BlockDriverState *bdrv;
     BlockDriver *drv = NULL;
+    QEMUMachine *machine = opaque;
     int max_devs;
     int index;
     int cache;
-    int bdrv_flags;
+    int bdrv_flags, onerror;
+    int drives_table_idx;
     char *str = arg->opt;
     static const char * const params[] = { "bus", "unit", "if", "index",
                                            "cyls", "heads", "secs", "trans",
                                            "media", "snapshot", "file",
-                                           "cache", "format", NULL };
+                                           "cache", "format", "serial", "werror",
+                                           NULL };
 
     if (check_params(buf, sizeof(buf), params, str) < 0) {
          fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
@@ -5697,14 +2229,9 @@
     unit_id = -1;
     translation = BIOS_ATA_TRANSLATION_AUTO;
     index = -1;
-    cache = 1;
+    cache = 3;
 
-    if (!strcmp(machine->name, "realview") ||
-        !strcmp(machine->name, "SS-5") ||
-        !strcmp(machine->name, "SS-10") ||
-        !strcmp(machine->name, "SS-600MP") ||
-        !strcmp(machine->name, "versatilepb") ||
-        !strcmp(machine->name, "versatileab")) {
+    if (machine->use_scsi) {
         type = IF_SCSI;
         max_devs = MAX_SCSI_DEVS;
         pstrcpy(devname, sizeof(devname), "scsi");
@@ -5753,6 +2280,12 @@
 	} else if (!strcmp(buf, "sd")) {
 	    type = IF_SD;
             max_devs = 0;
+        } else if (!strcmp(buf, "virtio")) {
+            type = IF_VIRTIO;
+            max_devs = 0;
+	} else if (!strcmp(buf, "xen")) {
+	    type = IF_XEN;
+            max_devs = 0;
 	} else {
             fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
             return -1;
@@ -5841,10 +2374,12 @@
     }
 
     if (get_param_value(buf, sizeof(buf), "cache", str)) {
-        if (!strcmp(buf, "off"))
+        if (!strcmp(buf, "off") || !strcmp(buf, "none"))
             cache = 0;
-        else if (!strcmp(buf, "on"))
+        else if (!strcmp(buf, "writethrough"))
             cache = 1;
+        else if (!strcmp(buf, "writeback"))
+            cache = 2;
         else {
            fprintf(stderr, "qemu: invalid cache option\n");
            return -1;
@@ -5870,6 +2405,29 @@
     else
         pstrcpy(file, sizeof(file), arg->file);
 
+    if (!get_param_value(serial, sizeof(serial), "serial", str))
+	    memset(serial, 0,  sizeof(serial));
+
+    onerror = BLOCK_ERR_STOP_ENOSPC;
+    if (get_param_value(buf, sizeof(serial), "werror", str)) {
+        if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO) {
+            fprintf(stderr, "werror is no supported by this format\n");
+            return -1;
+        }
+        if (!strcmp(buf, "ignore"))
+            onerror = BLOCK_ERR_IGNORE;
+        else if (!strcmp(buf, "enospc"))
+            onerror = BLOCK_ERR_STOP_ENOSPC;
+        else if (!strcmp(buf, "stop"))
+            onerror = BLOCK_ERR_STOP_ANY;
+        else if (!strcmp(buf, "report"))
+            onerror = BLOCK_ERR_REPORT;
+        else {
+            fprintf(stderr, "qemu: '%s' invalid write error action\n", buf);
+            return -1;
+        }
+    }
+
     /* compute bus and unit according index */
 
     if (index != -1) {
@@ -5916,7 +2474,7 @@
      */
 
     if (drive_get_index(type, bus_id, unit_id) != -1)
-        return 0;
+        return -2;
 
     /* init */
 
@@ -5929,15 +2487,20 @@
         snprintf(buf, sizeof(buf), "%s%s%i",
                  devname, mediastr, unit_id);
     bdrv = bdrv_new(buf);
-    drives_table[nb_drives].bdrv = bdrv;
-    drives_table[nb_drives].type = type;
-    drives_table[nb_drives].bus = bus_id;
-    drives_table[nb_drives].unit = unit_id;
+    drives_table_idx = drive_get_free_idx();
+    drives_table[drives_table_idx].bdrv = bdrv;
+    drives_table[drives_table_idx].type = type;
+    drives_table[drives_table_idx].bus = bus_id;
+    drives_table[drives_table_idx].unit = unit_id;
+    drives_table[drives_table_idx].onerror = onerror;
+    drives_table[drives_table_idx].drive_opt_idx = arg - drives_opt;
+    strncpy(drives_table[drives_table_idx].serial, serial, sizeof(serial));
     nb_drives++;
 
     switch(type) {
     case IF_IDE:
     case IF_SCSI:
+    case IF_XEN:
         switch(media) {
 	case MEDIA_DISK:
             if (cyls != 0) {
@@ -5958,21 +2521,88 @@
         break;
     case IF_PFLASH:
     case IF_MTD:
+    case IF_VIRTIO:
         break;
+    case IF_COUNT:
+        abort();
     }
     if (!file[0])
-        return 0;
+        return -2;
     bdrv_flags = 0;
-    if (snapshot)
+    if (snapshot) {
         bdrv_flags |= BDRV_O_SNAPSHOT;
-    if (!cache)
-        bdrv_flags |= BDRV_O_DIRECT;
-    if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0 || qemu_key_check(bdrv, file)) {
+        cache = 2; /* always use write-back with snapshot */
+    }
+    if (cache == 0) /* no caching */
+        bdrv_flags |= BDRV_O_NOCACHE;
+    else if (cache == 2) /* write-back */
+        bdrv_flags |= BDRV_O_CACHE_WB;
+    else if (cache == 3) /* not specified */
+        bdrv_flags |= BDRV_O_CACHE_DEF;
+    if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0) {
         fprintf(stderr, "qemu: could not open disk image %s\n",
                         file);
         return -1;
     }
-    return 0;
+    if (bdrv_key_required(bdrv))
+        autostart = 0;
+    return drives_table_idx;
+}
+
+static void numa_add(const char *optarg)
+{
+    char option[128];
+    char *endptr;
+    unsigned long long value, endvalue;
+    int nodenr;
+
+    optarg = get_opt_name(option, 128, optarg, ',') + 1;
+    if (!strcmp(option, "node")) {
+        if (get_param_value(option, 128, "nodeid", optarg) == 0) {
+            nodenr = nb_numa_nodes;
+        } else {
+            nodenr = strtoull(option, NULL, 10);
+        }
+
+        if (get_param_value(option, 128, "mem", optarg) == 0) {
+            node_mem[nodenr] = 0;
+        } else {
+            value = strtoull(option, &endptr, 0);
+            switch (*endptr) {
+            case 0: case 'M': case 'm':
+                value <<= 20;
+                break;
+            case 'G': case 'g':
+                value <<= 30;
+                break;
+            }
+            node_mem[nodenr] = value;
+        }
+        if (get_param_value(option, 128, "cpus", optarg) == 0) {
+            node_cpumask[nodenr] = 0;
+        } else {
+            value = strtoull(option, &endptr, 10);
+            if (value >= 64) {
+                value = 63;
+                fprintf(stderr, "only 64 CPUs in NUMA mode supported.\n");
+            } else {
+                if (*endptr == '-') {
+                    endvalue = strtoull(endptr+1, &endptr, 10);
+                    if (endvalue >= 63) {
+                        endvalue = 62;
+                        fprintf(stderr,
+                            "only 63 CPUs in NUMA mode supported.\n");
+                    }
+                    value = (1 << (endvalue + 1)) - (1 << value);
+                } else {
+                    value = 1 << value;
+                }
+            }
+            node_cpumask[nodenr] = value;
+        }
+        nb_numa_nodes++;
+    }
+    return;
 }
 
 /***********************************************************/
@@ -6018,7 +2648,17 @@
     return 0;
 }
 
-static int usb_device_add(const char *devname)
+static void usb_msd_password_cb(void *opaque, int err)
+{
+    USBDevice *dev = opaque;
+
+    if (!err)
+        usb_device_add_dev(dev);
+    else
+        dev->handle_destroy(dev);
+}
+
+static int usb_device_add(const char *devname, int is_hotplug)
 {
     const char *p;
     USBDevice *dev;
@@ -6035,8 +2675,20 @@
     } else if (!strcmp(devname, "keyboard")) {
         dev = usb_keyboard_init();
     } else if (strstart(devname, "disk:", &p)) {
+        BlockDriverState *bs;
+
         dev = usb_msd_init(p);
-#if 0
+        if (!dev)
+            return -1;
+        bs = usb_msd_get_bdrv(dev);
+        if (bdrv_key_required(bs)) {
+            autostart = 0;
+            if (is_hotplug) {
+                monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb,
+                                            dev);
+                return 0;
+            }
+        }
     } else if (!strcmp(devname, "wacom-tablet")) {
         dev = usb_wacom_init();
     } else if (strstart(devname, "serial:", &p)) {
@@ -6048,11 +2700,13 @@
     } else if (strstart(devname, "net:", &p)) {
         int nic = nb_nics;
 
-        if (net_client_init("nic", p) < 0)
+        if (net_client_init(NULL, "nic", p) < 0)
             return -1;
         nd_table[nic].model = "usb";
         dev = usb_net_init(&nd_table[nic]);
-#endif
+    } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
+        dev = usb_bt_init(devname[2] ? hci_init(p) :
+                        bt_new_hci(qemu_find_bt_vlan(0)));
     } else {
         return -1;
     }
@@ -6113,24 +2767,24 @@
     return usb_device_del_addr(bus_num, addr);
 }
 
-void do_usb_add(const char *devname)
+void do_usb_add(Monitor *mon, const char *devname)
 {
-    usb_device_add(devname);
+    usb_device_add(devname, 1);
 }
 
-void do_usb_del(const char *devname)
+void do_usb_del(Monitor *mon, const char *devname)
 {
     usb_device_del(devname);
 }
 
-void usb_info(void)
+void usb_info(Monitor *mon)
 {
     USBDevice *dev;
     USBPort *port;
     const char *speed_str;
 
     if (!usb_enabled) {
-        term_printf("USB support not enabled\n");
+        monitor_printf(mon, "USB support not enabled\n");
         return;
     }
 
@@ -6152,86 +2806,97 @@
             speed_str = "?";
             break;
         }
-        term_printf("  Device %d.%d, Speed %s Mb/s, Product %s\n",
-                    0, dev->addr, speed_str, dev->devname);
+        monitor_printf(mon, "  Device %d.%d, Speed %s Mb/s, Product %s\n",
+                       0, dev->addr, speed_str, dev->devname);
     }
 }
 
 /***********************************************************/
-/* pid file */
+/* PCMCIA/Cardbus */
 
-static char *pid_filename;
+static struct pcmcia_socket_entry_s {
+    PCMCIASocket *socket;
+    struct pcmcia_socket_entry_s *next;
+} *pcmcia_sockets = 0;
 
-/* Remove PID file. Called on normal exit */
-
-static void remove_pidfile(void)
+void pcmcia_socket_register(PCMCIASocket *socket)
 {
-    unlink (pid_filename);
+    struct pcmcia_socket_entry_s *entry;
+
+    entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s));
+    entry->socket = socket;
+    entry->next = pcmcia_sockets;
+    pcmcia_sockets = entry;
 }
 
-static void create_pidfile(const char *filename)
+void pcmcia_socket_unregister(PCMCIASocket *socket)
 {
-    struct stat pidstat;
-    FILE *f;
+    struct pcmcia_socket_entry_s *entry, **ptr;
 
-    /* Try to write our PID to the named file */
-    if (stat(filename, &pidstat) < 0) {
-        if (errno == ENOENT) {
-            if ((f = fopen (filename, "w")) == NULL) {
-                perror("Opening pidfile");
-                exit(1);
-            }
-            fprintf(f, "%d\n", getpid());
-            fclose(f);
-            pid_filename = qemu_strdup(filename);
-            if (!pid_filename) {
-                fprintf(stderr, "Could not save PID filename");
-                exit(1);
-            }
-            atexit(remove_pidfile);
+    ptr = &pcmcia_sockets;
+    for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr)
+        if (entry->socket == socket) {
+            *ptr = entry->next;
+            qemu_free(entry);
         }
-    } else {
-        fprintf(stderr, "%s already exists. Remove it and try again.\n",
-                filename);
-        exit(1);
-    }
+}
+
+void pcmcia_info(Monitor *mon)
+{
+    struct pcmcia_socket_entry_s *iter;
+
+    if (!pcmcia_sockets)
+        monitor_printf(mon, "No PCMCIA sockets\n");
+
+    for (iter = pcmcia_sockets; iter; iter = iter->next)
+        monitor_printf(mon, "%s: %s\n", iter->socket->slot_string,
+                       iter->socket->attached ? iter->socket->card_string :
+                       "Empty");
 }
 
 /***********************************************************/
+/* register display */
+
+struct DisplayAllocator default_allocator = {
+    defaultallocator_create_displaysurface,
+    defaultallocator_resize_displaysurface,
+    defaultallocator_free_displaysurface
+};
+
+void register_displaystate(DisplayState *ds)
+{
+    DisplayState **s;
+    s = &display_state;
+    while (*s != NULL)
+        s = &(*s)->next;
+    ds->next = NULL;
+    *s = ds;
+}
+
+DisplayState *get_displaystate(void)
+{
+    return display_state;
+}
+
+DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
+{
+    if(ds->allocator ==  &default_allocator) ds->allocator = da;
+    return ds->allocator;
+}
+
 /* dumb display */
 
-static void dumb_update(DisplayState *ds, int x, int y, int w, int h)
+static void dumb_display_init(void)
 {
-}
-
-static void dumb_resize(DisplayState *ds, int w, int h)
-{
-}
-
-static void dumb_refresh(DisplayState *ds)
-{
-#if defined(CONFIG_SDL)
-    vga_hw_update();
-#endif
-}
-
-static void dumb_display_init(DisplayState *ds)
-{
-    ds->data = NULL;
-    ds->linesize = 0;
-    ds->depth = 0;
-    ds->dpy_update = dumb_update;
-    ds->dpy_resize = dumb_resize;
-    ds->dpy_refresh = dumb_refresh;
-    ds->gui_timer_interval = 500;
-    ds->idle = 1;
+    DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
+    ds->allocator = &default_allocator;
+    ds->surface = qemu_create_displaysurface(ds, 640, 480);
+    register_displaystate(ds);
 }
 
 /***********************************************************/
 /* I/O handling */
 
-#define MAX_IO_HANDLERS 64
-
 typedef struct IOHandlerRecord {
     int fd;
     IOCanRWHandler *fd_read_poll;
@@ -6274,8 +2939,6 @@
                 goto found;
         }
         ioh = qemu_mallocz(sizeof(IOHandlerRecord));
-        if (!ioh)
-            return -1;
         ioh->next = first_io_handler;
         first_io_handler = ioh;
     found:
@@ -6297,6 +2960,7 @@
     return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
 }
 
+#ifdef _WIN32
 /***********************************************************/
 /* Polling handling */
 
@@ -6312,8 +2976,6 @@
 {
     PollingEntry **ppe, *pe;
     pe = qemu_mallocz(sizeof(PollingEntry));
-    if (!pe)
-        return -1;
     pe->func = func;
     pe->opaque = opaque;
     for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
@@ -6334,7 +2996,6 @@
     }
 }
 
-#ifdef _WIN32
 /***********************************************************/
 /* Wait objects support */
 typedef struct WaitObjects {
@@ -6380,805 +3041,7 @@
 #endif
 
 /***********************************************************/
-/* savevm/loadvm support */
-
-#define IO_BUF_SIZE 32768
-
-struct QEMUFile {
-    FILE *outfile;
-    BlockDriverState *bs;
-    int is_file;
-    int is_writable;
-    int64_t base_offset;
-    int64_t buf_offset; /* start of buffer when writing, end of buffer
-                           when reading */
-    int buf_index;
-    int buf_size; /* 0 when writing */
-    uint8_t buf[IO_BUF_SIZE];
-};
-
-QEMUFile *qemu_fopen(const char *filename, const char *mode)
-{
-    QEMUFile *f;
-
-    f = qemu_mallocz(sizeof(QEMUFile));
-    if (!f)
-        return NULL;
-    if (!strcmp(mode, "wb")) {
-        f->is_writable = 1;
-    } else if (!strcmp(mode, "rb")) {
-        f->is_writable = 0;
-    } else {
-        goto fail;
-    }
-    f->outfile = fopen(filename, mode);
-    if (!f->outfile)
-        goto fail;
-    f->is_file = 1;
-    return f;
- fail:
-    if (f->outfile)
-        fclose(f->outfile);
-    qemu_free(f);
-    return NULL;
-}
-
-static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
-{
-    QEMUFile *f;
-
-    f = qemu_mallocz(sizeof(QEMUFile));
-    if (!f)
-        return NULL;
-    f->is_file = 0;
-    f->bs = bs;
-    f->is_writable = is_writable;
-    f->base_offset = offset;
-    return f;
-}
-
-void qemu_fflush(QEMUFile *f)
-{
-    if (!f->is_writable)
-        return;
-    if (f->buf_index > 0) {
-        if (f->is_file) {
-            fseek(f->outfile, f->buf_offset, SEEK_SET);
-            fwrite(f->buf, 1, f->buf_index, f->outfile);
-        } else {
-            bdrv_pwrite(f->bs, f->base_offset + f->buf_offset,
-                        f->buf, f->buf_index);
-        }
-        f->buf_offset += f->buf_index;
-        f->buf_index = 0;
-    }
-}
-
-static void qemu_fill_buffer(QEMUFile *f)
-{
-    int len;
-
-    if (f->is_writable)
-        return;
-    if (f->is_file) {
-        fseek(f->outfile, f->buf_offset, SEEK_SET);
-        len = fread(f->buf, 1, IO_BUF_SIZE, f->outfile);
-        if (len < 0)
-            len = 0;
-    } else {
-        len = bdrv_pread(f->bs, f->base_offset + f->buf_offset,
-                         f->buf, IO_BUF_SIZE);
-        if (len < 0)
-            len = 0;
-    }
-    f->buf_index = 0;
-    f->buf_size = len;
-    f->buf_offset += len;
-}
-
-void qemu_fclose(QEMUFile *f)
-{
-    if (f->is_writable)
-        qemu_fflush(f);
-    if (f->is_file) {
-        fclose(f->outfile);
-    }
-    qemu_free(f);
-}
-
-void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
-{
-    int l;
-    while (size > 0) {
-        l = IO_BUF_SIZE - f->buf_index;
-        if (l > size)
-            l = size;
-        memcpy(f->buf + f->buf_index, buf, l);
-        f->buf_index += l;
-        buf += l;
-        size -= l;
-        if (f->buf_index >= IO_BUF_SIZE)
-            qemu_fflush(f);
-    }
-}
-
-void qemu_put_byte(QEMUFile *f, int v)
-{
-    f->buf[f->buf_index++] = v;
-    if (f->buf_index >= IO_BUF_SIZE)
-        qemu_fflush(f);
-}
-
-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
-{
-    int size, l;
-
-    size = size1;
-    while (size > 0) {
-        l = f->buf_size - f->buf_index;
-        if (l == 0) {
-            qemu_fill_buffer(f);
-            l = f->buf_size - f->buf_index;
-            if (l == 0)
-                break;
-        }
-        if (l > size)
-            l = size;
-        memcpy(buf, f->buf + f->buf_index, l);
-        f->buf_index += l;
-        buf += l;
-        size -= l;
-    }
-    return size1 - size;
-}
-
-int qemu_get_byte(QEMUFile *f)
-{
-    if (f->buf_index >= f->buf_size) {
-        qemu_fill_buffer(f);
-        if (f->buf_index >= f->buf_size)
-            return 0;
-    }
-    return f->buf[f->buf_index++];
-}
-
-int64_t qemu_ftell(QEMUFile *f)
-{
-    return f->buf_offset - f->buf_size + f->buf_index;
-}
-
-int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
-{
-    if (whence == SEEK_SET) {
-        /* nothing to do */
-    } else if (whence == SEEK_CUR) {
-        pos += qemu_ftell(f);
-    } else {
-        /* SEEK_END not supported */
-        return -1;
-    }
-    if (f->is_writable) {
-        qemu_fflush(f);
-        f->buf_offset = pos;
-    } else {
-        f->buf_offset = pos;
-        f->buf_index = 0;
-        f->buf_size = 0;
-    }
-    return pos;
-}
-
-void qemu_put_be16(QEMUFile *f, unsigned int v)
-{
-    qemu_put_byte(f, v >> 8);
-    qemu_put_byte(f, v);
-}
-
-void qemu_put_be32(QEMUFile *f, unsigned int v)
-{
-    qemu_put_byte(f, v >> 24);
-    qemu_put_byte(f, v >> 16);
-    qemu_put_byte(f, v >> 8);
-    qemu_put_byte(f, v);
-}
-
-void qemu_put_be64(QEMUFile *f, uint64_t v)
-{
-    qemu_put_be32(f, v >> 32);
-    qemu_put_be32(f, v);
-}
-
-unsigned int qemu_get_be16(QEMUFile *f)
-{
-    unsigned int v;
-    v = qemu_get_byte(f) << 8;
-    v |= qemu_get_byte(f);
-    return v;
-}
-
-unsigned int qemu_get_be32(QEMUFile *f)
-{
-    unsigned int v;
-    v = qemu_get_byte(f) << 24;
-    v |= qemu_get_byte(f) << 16;
-    v |= qemu_get_byte(f) << 8;
-    v |= qemu_get_byte(f);
-    return v;
-}
-
-uint64_t qemu_get_be64(QEMUFile *f)
-{
-    uint64_t v;
-    v = (uint64_t)qemu_get_be32(f) << 32;
-    v |= qemu_get_be32(f);
-    return v;
-}
-
-void  qemu_put_struct(QEMUFile*  f, const QField*  fields, const void*  s)
-{
-    const QField*  qf = fields;
-
-    for (;;) {
-        uint8_t*  p = (uint8_t*)s + qf->offset;
-
-        switch (qf->type) {
-            case Q_FIELD_END:
-                break;
-            case Q_FIELD_BYTE:
-                qemu_put_byte(f, p[0]);
-                break;
-            case Q_FIELD_INT16:
-                qemu_put_be16(f, ((uint16_t*)p)[0]);
-                break;
-            case Q_FIELD_INT32:
-                qemu_put_be32(f, ((uint32_t*)p)[0]);
-                break;
-            case Q_FIELD_INT64:
-                qemu_put_be64(f, ((uint64_t*)p)[0]);
-                break;
-            case Q_FIELD_BUFFER:
-                if (fields[1].type != Q_FIELD_BUFFER_SIZE ||
-                    fields[2].type != Q_FIELD_BUFFER_SIZE)
-                {
-                    fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n",
-                            __FUNCTION__ );
-                    exit(1);
-                }
-                else
-                {
-                    uint32_t  size = ((uint32_t)fields[1].offset << 16) | (uint32_t)fields[2].offset;
-
-                    qemu_put_buffer(f, p, size);
-                    qf += 2;
-                }
-                break;
-            default:
-                fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
-                exit(1);
-        }
-        qf++;
-    }
-}
-
-int   qemu_get_struct(QEMUFile*  f, const QField*  fields, void*  s)
-{
-    const QField*  qf = fields;
-
-    for (;;) {
-        uint8_t*  p = (uint8_t*)s + qf->offset;
-
-        switch (qf->type) {
-            case Q_FIELD_END:
-                break;
-            case Q_FIELD_BYTE:
-                p[0] = qemu_get_byte(f);
-                break;
-            case Q_FIELD_INT16:
-                ((uint16_t*)p)[0] = qemu_get_be16(f);
-                break;
-            case Q_FIELD_INT32:
-                ((uint32_t*)p)[0] = qemu_get_be32(f);
-                break;
-            case Q_FIELD_INT64:
-                ((uint64_t*)p)[0] = qemu_get_be64(f);
-                break;
-            case Q_FIELD_BUFFER:
-                if (fields[1].type != Q_FIELD_BUFFER_SIZE ||
-                    fields[2].type != Q_FIELD_BUFFER_SIZE)
-                {
-                    fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n",
-                            __FUNCTION__ );
-                    return -1;
-                }
-                else
-                {
-                    uint32_t  size = ((uint32_t)fields[1].offset << 16) | (uint32_t)fields[2].offset;
-                    int       ret  = qemu_get_buffer(f, p, size);
-
-                    if (ret != size) {
-                        fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__);
-                        return -1;
-                    }
-                    qf += 2;
-                }
-                break;
-            default:
-                fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
-                exit(1);
-        }
-        qf++;
-    }
-    return 0;
-}
-
-typedef struct SaveStateEntry {
-    char idstr[256];
-    int instance_id;
-    int version_id;
-    SaveStateHandler *save_state;
-    LoadStateHandler *load_state;
-    void *opaque;
-    struct SaveStateEntry *next;
-} SaveStateEntry;
-
-static SaveStateEntry *first_se;
-
-/* TODO: Individual devices generally have very little idea about the rest
-   of the system, so instance_id should be removed/replaced.
-   Meanwhile pass -1 as instance_id if you do not already have a clearly
-   distinguishing id for all instances of your device class. */
-int register_savevm(const char *idstr,
-                    int instance_id,
-                    int version_id,
-                    SaveStateHandler *save_state,
-                    LoadStateHandler *load_state,
-                    void *opaque)
-{
-    SaveStateEntry *se, **pse;
-
-    se = qemu_malloc(sizeof(SaveStateEntry));
-    if (!se)
-        return -1;
-    pstrcpy(se->idstr, sizeof(se->idstr), idstr);
-    se->instance_id = (instance_id == -1) ? 0 : instance_id;
-    se->version_id = version_id;
-    se->save_state = save_state;
-    se->load_state = load_state;
-    se->opaque = opaque;
-    se->next = NULL;
-
-    /* add at the end of list */
-    pse = &first_se;
-    while (*pse != NULL) {
-        if (instance_id == -1
-                && strcmp(se->idstr, (*pse)->idstr) == 0
-                && se->instance_id <= (*pse)->instance_id)
-            se->instance_id = (*pse)->instance_id + 1;
-        pse = &(*pse)->next;
-    }
-    *pse = se;
-    return 0;
-}
-
-#define QEMU_VM_FILE_MAGIC   0x5145564d
-#define QEMU_VM_FILE_VERSION 0x00000002
-
-static int qemu_savevm_state(QEMUFile *f)
-{
-    SaveStateEntry *se;
-    int len, ret;
-    int64_t cur_pos, len_pos, total_len_pos;
-
-    qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
-    qemu_put_be32(f, QEMU_VM_FILE_VERSION);
-    total_len_pos = qemu_ftell(f);
-    qemu_put_be64(f, 0); /* total size */
-
-    for(se = first_se; se != NULL; se = se->next) {
-	if (se->save_state == NULL)
-	    /* this one has a loader only, for backwards compatibility */
-	    continue;
-
-        /* ID string */
-        len = strlen(se->idstr);
-        qemu_put_byte(f, len);
-        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
-
-        qemu_put_be32(f, se->instance_id);
-        qemu_put_be32(f, se->version_id);
-
-        /* record size: filled later */
-        len_pos = qemu_ftell(f);
-        qemu_put_be32(f, 0);
-        se->save_state(f, se->opaque);
-
-        /* fill record size */
-        cur_pos = qemu_ftell(f);
-        len = cur_pos - len_pos - 4;
-        qemu_fseek(f, len_pos, SEEK_SET);
-        qemu_put_be32(f, len);
-        qemu_fseek(f, cur_pos, SEEK_SET);
-    }
-    cur_pos = qemu_ftell(f);
-    qemu_fseek(f, total_len_pos, SEEK_SET);
-    qemu_put_be64(f, cur_pos - total_len_pos - 8);
-    qemu_fseek(f, cur_pos, SEEK_SET);
-
-    ret = 0;
-    return ret;
-}
-
-static SaveStateEntry *find_se(const char *idstr, int instance_id)
-{
-    SaveStateEntry *se;
-
-    for(se = first_se; se != NULL; se = se->next) {
-        if (!strcmp(se->idstr, idstr) &&
-            instance_id == se->instance_id)
-            return se;
-    }
-    return NULL;
-}
-
-static int qemu_loadvm_state(QEMUFile *f)
-{
-    SaveStateEntry *se;
-    int len, ret, instance_id, record_len, version_id;
-    int64_t total_len, end_pos, cur_pos;
-    unsigned int v;
-    char idstr[256];
-
-    v = qemu_get_be32(f);
-    if (v != QEMU_VM_FILE_MAGIC)
-        goto fail;
-    v = qemu_get_be32(f);
-    if (v != QEMU_VM_FILE_VERSION) {
-    fail:
-        ret = -1;
-        goto the_end;
-    }
-    total_len = qemu_get_be64(f);
-    end_pos = total_len + qemu_ftell(f);
-    for(;;) {
-        if (qemu_ftell(f) >= end_pos)
-            break;
-        len = qemu_get_byte(f);
-        qemu_get_buffer(f, (uint8_t *)idstr, len);
-        idstr[len] = '\0';
-        instance_id = qemu_get_be32(f);
-        version_id = qemu_get_be32(f);
-        record_len = qemu_get_be32(f);
-#if 0
-        printf("idstr=%s instance=0x%x version=%d len=%d\n",
-               idstr, instance_id, version_id, record_len);
-#endif
-        cur_pos = qemu_ftell(f);
-        se = find_se(idstr, instance_id);
-        if (!se) {
-            fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
-                    instance_id, idstr);
-        } else {
-            ret = se->load_state(f, se->opaque, version_id);
-            if (ret < 0) {
-                fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
-                        instance_id, idstr);
-            }
-        }
-        /* always seek to exact end of record */
-        qemu_fseek(f, cur_pos + record_len, SEEK_SET);
-    }
-    ret = 0;
- the_end:
-    return ret;
-}
-
-/* device can contain snapshots */
-static int bdrv_can_snapshot(BlockDriverState *bs)
-{
-    return (bs &&
-            !bdrv_is_removable(bs) &&
-            !bdrv_is_read_only(bs));
-}
-
-/* device must be snapshots in order to have a reliable snapshot */
-static int bdrv_has_snapshot(BlockDriverState *bs)
-{
-    return (bs &&
-            !bdrv_is_removable(bs) &&
-            !bdrv_is_read_only(bs));
-}
-
-static BlockDriverState *get_bs_snapshots(void)
-{
-    BlockDriverState *bs;
-    int i;
-
-    if (bs_snapshots)
-        return bs_snapshots;
-    for(i = 0; i <= nb_drives; i++) {
-        bs = drives_table[i].bdrv;
-        if (bdrv_can_snapshot(bs))
-            goto ok;
-    }
-    return NULL;
- ok:
-    bs_snapshots = bs;
-    return bs;
-}
-
-static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
-                              const char *name)
-{
-    QEMUSnapshotInfo *sn_tab, *sn;
-    int nb_sns, i, ret;
-
-    ret = -ENOENT;
-    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
-    if (nb_sns < 0)
-        return ret;
-    for(i = 0; i < nb_sns; i++) {
-        sn = &sn_tab[i];
-        if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
-            *sn_info = *sn;
-            ret = 0;
-            break;
-        }
-    }
-    qemu_free(sn_tab);
-    return ret;
-}
-
-void do_savevm(const char *name)
-{
-    BlockDriverState *bs, *bs1;
-    QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
-    int must_delete, ret, i;
-    BlockDriverInfo bdi1, *bdi = &bdi1;
-    QEMUFile *f;
-    int saved_vm_running;
-#ifdef _WIN32
-    struct _timeb tb;
-#else
-    struct timeval tv;
-#endif
-
-    bs = get_bs_snapshots();
-    if (!bs) {
-        term_printf("No block device can accept snapshots\n");
-        return;
-    }
-
-    /* ??? Should this occur after vm_stop?  */
-    qemu_aio_flush();
-
-    saved_vm_running = vm_running;
-    vm_stop(0);
-
-    must_delete = 0;
-    if (name) {
-        ret = bdrv_snapshot_find(bs, old_sn, name);
-        if (ret >= 0) {
-            must_delete = 1;
-        }
-    }
-    memset(sn, 0, sizeof(*sn));
-    if (must_delete) {
-        pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
-        pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
-    } else {
-        if (name)
-            pstrcpy(sn->name, sizeof(sn->name), name);
-    }
-
-    /* fill auxiliary fields */
-#ifdef _WIN32
-    _ftime(&tb);
-    sn->date_sec = tb.time;
-    sn->date_nsec = tb.millitm * 1000000;
-#else
-    gettimeofday(&tv, NULL);
-    sn->date_sec = tv.tv_sec;
-    sn->date_nsec = tv.tv_usec * 1000;
-#endif
-    sn->vm_clock_nsec = qemu_get_clock(vm_clock);
-
-    if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
-        term_printf("Device %s does not support VM state snapshots\n",
-                    bdrv_get_device_name(bs));
-        goto the_end;
-    }
-
-    /* save the VM state */
-    f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1);
-    if (!f) {
-        term_printf("Could not open VM state file\n");
-        goto the_end;
-    }
-    ret = qemu_savevm_state(f);
-    sn->vm_state_size = qemu_ftell(f);
-    qemu_fclose(f);
-    if (ret < 0) {
-        term_printf("Error %d while writing VM\n", ret);
-        goto the_end;
-    }
-
-    /* create the snapshots */
-
-    for(i = 0; i < nb_drives; i++) {
-        bs1 = drives_table[i].bdrv;
-        if (bdrv_has_snapshot(bs1)) {
-            if (must_delete) {
-                ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
-                if (ret < 0) {
-                    term_printf("Error while deleting snapshot on '%s'\n",
-                                bdrv_get_device_name(bs1));
-                }
-            }
-            ret = bdrv_snapshot_create(bs1, sn);
-            if (ret < 0) {
-                term_printf("Error while creating snapshot on '%s'\n",
-                            bdrv_get_device_name(bs1));
-            }
-        }
-    }
-
- the_end:
-    if (saved_vm_running)
-        vm_start();
-}
-
-void do_loadvm(const char *name)
-{
-    BlockDriverState *bs, *bs1;
-    BlockDriverInfo bdi1, *bdi = &bdi1;
-    QEMUFile *f;
-    int i, ret;
-    int saved_vm_running;
-
-    bs = get_bs_snapshots();
-    if (!bs) {
-        term_printf("No block device supports snapshots\n");
-        return;
-    }
-
-    /* Flush all IO requests so they don't interfere with the new state.  */
-    qemu_aio_flush();
-
-    saved_vm_running = vm_running;
-    vm_stop(0);
-
-    for(i = 0; i <= nb_drives; i++) {
-        bs1 = drives_table[i].bdrv;
-        if (bdrv_has_snapshot(bs1)) {
-            ret = bdrv_snapshot_goto(bs1, name);
-            if (ret < 0) {
-                if (bs != bs1)
-                    term_printf("Warning: ");
-                switch(ret) {
-                case -ENOTSUP:
-                    term_printf("Snapshots not supported on device '%s'\n",
-                                bdrv_get_device_name(bs1));
-                    break;
-                case -ENOENT:
-                    term_printf("Could not find snapshot '%s' on device '%s'\n",
-                                name, bdrv_get_device_name(bs1));
-                    break;
-                default:
-                    term_printf("Error %d while activating snapshot on '%s'\n",
-                                ret, bdrv_get_device_name(bs1));
-                    break;
-                }
-                /* fatal on snapshot block device */
-                if (bs == bs1)
-                    goto the_end;
-            }
-        }
-    }
-
-    if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
-        term_printf("Device %s does not support VM state snapshots\n",
-                    bdrv_get_device_name(bs));
-        return;
-    }
-
-    /* restore the VM state */
-    f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);
-    if (!f) {
-        term_printf("Could not open VM state file\n");
-        goto the_end;
-    }
-    ret = qemu_loadvm_state(f);
-    qemu_fclose(f);
-    if (ret < 0) {
-        term_printf("Error %d while loading VM state\n", ret);
-    }
- the_end:
-    if (saved_vm_running)
-        vm_start();
-}
-
-void do_delvm(const char *name)
-{
-    BlockDriverState *bs, *bs1;
-    int i, ret;
-
-    bs = get_bs_snapshots();
-    if (!bs) {
-        term_printf("No block device supports snapshots\n");
-        return;
-    }
-
-    for(i = 0; i <= nb_drives; i++) {
-        bs1 = drives_table[i].bdrv;
-        if (bdrv_has_snapshot(bs1)) {
-            ret = bdrv_snapshot_delete(bs1, name);
-            if (ret < 0) {
-                if (ret == -ENOTSUP)
-                    term_printf("Snapshots not supported on device '%s'\n",
-                                bdrv_get_device_name(bs1));
-                else
-                    term_printf("Error %d while deleting snapshot on '%s'\n",
-                                ret, bdrv_get_device_name(bs1));
-            }
-        }
-    }
-}
-
-void do_info_snapshots(void)
-{
-    BlockDriverState *bs, *bs1;
-    QEMUSnapshotInfo *sn_tab, *sn;
-    int nb_sns, i;
-    char buf[256];
-
-    bs = get_bs_snapshots();
-    if (!bs) {
-        term_printf("No available block device supports snapshots\n");
-        return;
-    }
-    term_printf("Snapshot devices:");
-    for(i = 0; i <= nb_drives; i++) {
-        bs1 = drives_table[i].bdrv;
-        if (bdrv_has_snapshot(bs1)) {
-            if (bs == bs1)
-                term_printf(" %s", bdrv_get_device_name(bs1));
-        }
-    }
-    term_printf("\n");
-
-    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
-    if (nb_sns < 0) {
-        term_printf("bdrv_snapshot_list: error %d\n", nb_sns);
-        return;
-    }
-    term_printf("Snapshot list (from %s):\n", bdrv_get_device_name(bs));
-    term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
-    for(i = 0; i < nb_sns; i++) {
-        sn = &sn_tab[i];
-        term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
-    }
-    qemu_free(sn_tab);
-}
-
-/***********************************************************/
 /* ram save/restore */
-/* we just avoid storing empty pages */
-static void ram_put_page(QEMUFile *f, const uint8_t *buf, int len)
-{
-    int i, v;
-
-    v = buf[0];
-    for(i = 1; i < len; i++) {
-        if (buf[i] != v)
-            goto normal_save;
-    }
-    qemu_put_byte(f, 1);
-    qemu_put_byte(f, v);
-    return;
- normal_save:
-    qemu_put_byte(f, 0);
-    qemu_put_buffer(f, buf, len);
-}
 
 static int ram_get_page(QEMUFile *f, uint8_t *buf, int len)
 {
@@ -7197,6 +3060,10 @@
     default:
         return -EINVAL;
     }
+
+    if (qemu_file_has_error(f))
+        return -EIO;
+
     return 0;
 }
 
@@ -7205,10 +3072,10 @@
     int ret;
     ram_addr_t i;
 
-    if (qemu_get_be32(f) != phys_ram_size)
+    if (qemu_get_be32(f) != last_ram_offset)
         return -EINVAL;
-    for(i = 0; i < phys_ram_size; i+= TARGET_PAGE_SIZE) {
-        ret = ram_get_page(f, phys_ram_base + i, TARGET_PAGE_SIZE);
+    for(i = 0; i < last_ram_offset; i+= TARGET_PAGE_SIZE) {
+        ret = ram_get_page(f, qemu_get_ram_ptr(i), TARGET_PAGE_SIZE);
         if (ret)
             return ret;
     }
@@ -7219,77 +3086,6 @@
 #define IOBUF_SIZE 4096
 #define RAM_CBLOCK_MAGIC 0xfabe
 
-typedef struct RamCompressState {
-    z_stream zstream;
-    QEMUFile *f;
-    uint8_t buf[IOBUF_SIZE];
-} RamCompressState;
-
-static int ram_compress_open(RamCompressState *s, QEMUFile *f)
-{
-    int ret;
-    memset(s, 0, sizeof(*s));
-    s->f = f;
-    ret = deflateInit2(&s->zstream, 1,
-                       Z_DEFLATED, 15,
-                       9, Z_DEFAULT_STRATEGY);
-    if (ret != Z_OK)
-        return -1;
-    s->zstream.avail_out = IOBUF_SIZE;
-    s->zstream.next_out = s->buf;
-    return 0;
-}
-
-static void ram_put_cblock(RamCompressState *s, const uint8_t *buf, int len)
-{
-    qemu_put_be16(s->f, RAM_CBLOCK_MAGIC);
-    qemu_put_be16(s->f, len);
-    qemu_put_buffer(s->f, buf, len);
-}
-
-static int ram_compress_buf(RamCompressState *s, const uint8_t *buf, int len)
-{
-    int ret;
-
-    s->zstream.avail_in = len;
-    s->zstream.next_in = (uint8_t *)buf;
-    while (s->zstream.avail_in > 0) {
-        ret = deflate(&s->zstream, Z_NO_FLUSH);
-        if (ret != Z_OK)
-            return -1;
-        if (s->zstream.avail_out == 0) {
-            ram_put_cblock(s, s->buf, IOBUF_SIZE);
-            s->zstream.avail_out = IOBUF_SIZE;
-            s->zstream.next_out = s->buf;
-        }
-    }
-    return 0;
-}
-
-static void ram_compress_close(RamCompressState *s)
-{
-    int len, ret;
-
-    /* compress last bytes */
-    for(;;) {
-        ret = deflate(&s->zstream, Z_FINISH);
-        if (ret == Z_OK || ret == Z_STREAM_END) {
-            len = IOBUF_SIZE - s->zstream.avail_out;
-            if (len > 0) {
-                ram_put_cblock(s, s->buf, len);
-            }
-            s->zstream.avail_out = IOBUF_SIZE;
-            s->zstream.next_out = s->buf;
-            if (ret == Z_STREAM_END)
-                break;
-        } else {
-            goto fail;
-        }
-    }
-fail:
-    deflateEnd(&s->zstream);
-}
-
 typedef struct RamDecompressState {
     z_stream zstream;
     QEMUFile *f;
@@ -7337,105 +3133,232 @@
     inflateEnd(&s->zstream);
 }
 
-static void ram_save(QEMUFile *f, void *opaque)
+#define RAM_SAVE_FLAG_FULL	0x01
+#define RAM_SAVE_FLAG_COMPRESS	0x02
+#define RAM_SAVE_FLAG_MEM_SIZE	0x04
+#define RAM_SAVE_FLAG_PAGE	0x08
+#define RAM_SAVE_FLAG_EOS	0x10
+
+static int is_dup_page(uint8_t *page, uint8_t ch)
 {
-    ram_addr_t i;
-    RamCompressState s1, *s = &s1;
-    uint8_t buf[10];
+    uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch;
+    uint32_t *array = (uint32_t *)page;
+    int i;
 
-    qemu_put_be32(f, phys_ram_size);
-    if (ram_compress_open(s, f) < 0)
-        return;
-    for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) {
-#if 0
-        if (tight_savevm_enabled) {
-            int64_t sector_num;
-            int j;
-
-            /* find if the memory block is available on a virtual
-               block device */
-            sector_num = -1;
-            for(j = 0; j < nb_drives; j++) {
-                sector_num = bdrv_hash_find(drives_table[j].bdrv,
-                                            phys_ram_base + i,
-					    BDRV_HASH_BLOCK_SIZE);
-                if (sector_num >= 0)
-                    break;
-            }
-            if (j == nb_drives)
-                goto normal_compress;
-            buf[0] = 1;
-            buf[1] = j;
-            cpu_to_be64wu((uint64_t *)(buf + 2), sector_num);
-            ram_compress_buf(s, buf, 10);
-        } else
-#endif
-        {
-            //        normal_compress:
-            buf[0] = 0;
-            ram_compress_buf(s, buf, 1);
-            ram_compress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE);
-        }
+    for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) {
+        if (array[i] != val)
+            return 0;
     }
-    ram_compress_close(s);
+
+    return 1;
 }
 
-static int ram_load(QEMUFile *f, void *opaque, int version_id)
+static int ram_save_block(QEMUFile *f)
+{
+    static ram_addr_t current_addr = 0;
+    ram_addr_t saved_addr = current_addr;
+    ram_addr_t addr = 0;
+    int found = 0;
+
+    while (addr < last_ram_offset) {
+        if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
+            uint8_t *p;
+
+            cpu_physical_memory_reset_dirty(current_addr,
+                                            current_addr + TARGET_PAGE_SIZE,
+                                            MIGRATION_DIRTY_FLAG);
+
+            p = qemu_get_ram_ptr(current_addr);
+
+            if (is_dup_page(p, *p)) {
+                qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_COMPRESS);
+                qemu_put_byte(f, *p);
+            } else {
+                qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_PAGE);
+                qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
+            }
+
+            found = 1;
+            break;
+        }
+        addr += TARGET_PAGE_SIZE;
+        current_addr = (saved_addr + addr) % last_ram_offset;
+    }
+
+    return found;
+}
+
+static uint64_t bytes_transferred = 0;
+
+static ram_addr_t ram_save_remaining(void)
+{
+    ram_addr_t addr;
+    ram_addr_t count = 0;
+
+    for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) {
+        if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
+            count++;
+    }
+
+    return count;
+}
+
+uint64_t ram_bytes_remaining(void)
+{
+    return ram_save_remaining() * TARGET_PAGE_SIZE;
+}
+
+uint64_t ram_bytes_transferred(void)
+{
+    return bytes_transferred;
+}
+
+uint64_t ram_bytes_total(void)
+{
+    return last_ram_offset;
+}
+
+static int ram_save_live(QEMUFile *f, int stage, void *opaque)
+{
+    ram_addr_t addr;
+    uint64_t bytes_transferred_last;
+    double bwidth = 0;
+    uint64_t expected_time = 0;
+
+    if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
+        qemu_file_set_error(f);
+        return 0;
+    }
+
+    if (stage == 1) {
+        /* Make sure all dirty bits are set */
+        for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) {
+            if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
+                cpu_physical_memory_set_dirty(addr);
+        }
+
+        /* Enable dirty memory tracking */
+        cpu_physical_memory_set_dirty_tracking(1);
+
+        qemu_put_be64(f, last_ram_offset | RAM_SAVE_FLAG_MEM_SIZE);
+    }
+
+    bytes_transferred_last = bytes_transferred;
+    bwidth = get_clock();
+
+    while (!qemu_file_rate_limit(f)) {
+        int ret;
+
+        ret = ram_save_block(f);
+        bytes_transferred += ret * TARGET_PAGE_SIZE;
+        if (ret == 0) /* no more blocks */
+            break;
+    }
+
+    bwidth = get_clock() - bwidth;
+    bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
+
+    /* if we haven't transferred anything this round, force expected_time to a
+     * a very high value, but without crashing */
+    if (bwidth == 0)
+        bwidth = 0.000001;
+
+    /* try transferring iterative blocks of memory */
+
+    if (stage == 3) {
+
+        /* flush all remaining blocks regardless of rate limiting */
+        while (ram_save_block(f) != 0) {
+            bytes_transferred += TARGET_PAGE_SIZE;
+        }
+        cpu_physical_memory_set_dirty_tracking(0);
+    }
+
+    qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
+
+    expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
+
+    return (stage == 2) && (expected_time <= migrate_max_downtime());
+}
+
+static int ram_load_dead(QEMUFile *f, void *opaque)
 {
     RamDecompressState s1, *s = &s1;
     uint8_t buf[10];
     ram_addr_t i;
 
-    if (version_id == 1)
-        return ram_load_v1(f, opaque);
-    if (version_id != 2)
-        return -EINVAL;
-    if (qemu_get_be32(f) != phys_ram_size)
-        return -EINVAL;
     if (ram_decompress_open(s, f) < 0)
         return -EINVAL;
-    for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) {
+    for(i = 0; i < last_ram_offset; i+= BDRV_HASH_BLOCK_SIZE) {
         if (ram_decompress_buf(s, buf, 1) < 0) {
             fprintf(stderr, "Error while reading ram block header\n");
             goto error;
         }
         if (buf[0] == 0) {
-            if (ram_decompress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE) < 0) {
+            if (ram_decompress_buf(s, qemu_get_ram_ptr(i),
+                                   BDRV_HASH_BLOCK_SIZE) < 0) {
                 fprintf(stderr, "Error while reading ram block address=0x%08" PRIx64, (uint64_t)i);
                 goto error;
             }
-        } else
-#if 0
-        if (buf[0] == 1) {
-            int bs_index;
-            int64_t sector_num;
-
-            ram_decompress_buf(s, buf + 1, 9);
-            bs_index = buf[1];
-            sector_num = be64_to_cpupu((const uint64_t *)(buf + 2));
-            if (bs_index >= nb_drives) {
-                fprintf(stderr, "Invalid block device index %d\n", bs_index);
-                goto error;
-            }
-            if (bdrv_read(drives_table[bs_index].bdrv, sector_num,
-	                  phys_ram_base + i,
-                          BDRV_HASH_BLOCK_SIZE / 512) < 0) {
-                fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n",
-                        bs_index, sector_num);
-                goto error;
-            }
-        } else
-#endif
-        {
+        } else {
         error:
             printf("Error block header\n");
             return -EINVAL;
         }
     }
     ram_decompress_close(s);
+
     return 0;
 }
 
+static int ram_load(QEMUFile *f, void *opaque, int version_id)
+{
+    ram_addr_t addr;
+    int flags;
+
+    if (version_id == 1)
+        return ram_load_v1(f, opaque);
+
+    if (version_id == 2) {
+        if (qemu_get_be32(f) != last_ram_offset)
+            return -EINVAL;
+        return ram_load_dead(f, opaque);
+    }
+
+    if (version_id != 3)
+        return -EINVAL;
+
+    do {
+        addr = qemu_get_be64(f);
+
+        flags = addr & ~TARGET_PAGE_MASK;
+        addr &= TARGET_PAGE_MASK;
+
+        if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
+            if (addr != last_ram_offset)
+                return -EINVAL;
+        }
+
+        if (flags & RAM_SAVE_FLAG_FULL) {
+            if (ram_load_dead(f, opaque) < 0)
+                return -EINVAL;
+        }
+        
+        if (flags & RAM_SAVE_FLAG_COMPRESS) {
+            uint8_t ch = qemu_get_byte(f);
+            memset(qemu_get_ram_ptr(addr), ch, TARGET_PAGE_SIZE);
+        } else if (flags & RAM_SAVE_FLAG_PAGE)
+            qemu_get_buffer(f, qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE);
+    } while (!(flags & RAM_SAVE_FLAG_EOS));
+
+    return 0;
+}
+
+void qemu_service_io(void)
+{
+    qemu_notify_event();
+}
+
 /***********************************************************/
 /* bottom halves (can be seen as timers which expire ASAP) */
 
@@ -7443,6 +3366,8 @@
     QEMUBHFunc *cb;
     void *opaque;
     int scheduled;
+    int idle;
+    int deleted;
     QEMUBH *next;
 };
 
@@ -7452,69 +3377,97 @@
 {
     QEMUBH *bh;
     bh = qemu_mallocz(sizeof(QEMUBH));
-    if (!bh)
-        return NULL;
     bh->cb = cb;
     bh->opaque = opaque;
+    bh->next = first_bh;
+    first_bh = bh;
     return bh;
 }
 
 int qemu_bh_poll(void)
 {
-    QEMUBH *bh, **pbh;
+    QEMUBH *bh, **bhp;
     int ret;
 
     ret = 0;
-    for(;;) {
-        pbh = &first_bh;
-        bh = *pbh;
-        if (!bh)
-            break;
-        ret = 1;
-        *pbh = bh->next;
-        bh->scheduled = 0;
-        bh->cb(bh->opaque);
+    for (bh = first_bh; bh; bh = bh->next) {
+        if (!bh->deleted && bh->scheduled) {
+            bh->scheduled = 0;
+            if (!bh->idle)
+                ret = 1;
+            bh->idle = 0;
+            bh->cb(bh->opaque);
+        }
     }
+
+    /* remove deleted bhs */
+    bhp = &first_bh;
+    while (*bhp) {
+        bh = *bhp;
+        if (bh->deleted) {
+            *bhp = bh->next;
+            qemu_free(bh);
+        } else
+            bhp = &bh->next;
+    }
+
     return ret;
 }
 
+void qemu_bh_schedule_idle(QEMUBH *bh)
+{
+    if (bh->scheduled)
+        return;
+    bh->scheduled = 1;
+    bh->idle = 1;
+}
+
 void qemu_bh_schedule(QEMUBH *bh)
 {
-    CPUState *env = cpu_single_env;
     if (bh->scheduled)
         return;
     bh->scheduled = 1;
-    bh->next = first_bh;
-    first_bh = bh;
-
+    bh->idle = 0;
     /* stop the currently executing CPU to execute the BH ASAP */
-    if (env) {
-        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
-    }
+    qemu_notify_event();
 }
 
 void qemu_bh_cancel(QEMUBH *bh)
 {
-    QEMUBH **pbh;
-    if (bh->scheduled) {
-        pbh = &first_bh;
-        while (*pbh != bh)
-            pbh = &(*pbh)->next;
-        *pbh = bh->next;
-        bh->scheduled = 0;
-    }
+    bh->scheduled = 0;
 }
 
 void qemu_bh_delete(QEMUBH *bh)
 {
-    qemu_bh_cancel(bh);
-    qemu_free(bh);
+    bh->scheduled = 0;
+    bh->deleted = 1;
+}
+
+static void qemu_bh_update_timeout(int *timeout)
+{
+    QEMUBH *bh;
+
+    for (bh = first_bh; bh; bh = bh->next) {
+        if (!bh->deleted && bh->scheduled) {
+            if (bh->idle) {
+                /* idle bottom halves will be polled at least
+                 * every 10ms */
+                *timeout = MIN(10, *timeout);
+            } else {
+                /* non-idle bottom halves will be executed
+                 * immediately */
+                *timeout = 0;
+                break;
+            }
+        }
+    }
 }
 
 /***********************************************************/
 /* machine registration */
 
-QEMUMachine *first_machine = NULL;
+static QEMUMachine *first_machine = NULL;
+QEMUMachine *current_machine = NULL;
 
 int qemu_register_machine(QEMUMachine *m)
 {
@@ -7538,18 +3491,43 @@
     return NULL;
 }
 
+static QEMUMachine *find_default_machine(void)
+{
+    QEMUMachine *m;
+
+    for(m = first_machine; m != NULL; m = m->next) {
+        if (m->is_default) {
+            return m;
+        }
+    }
+    return NULL;
+}
+
 /***********************************************************/
 /* main execution loop */
 
 static void gui_update(void *opaque)
 {
+    uint64_t interval = GUI_REFRESH_INTERVAL;
     DisplayState *ds = opaque;
-    ds->dpy_refresh(ds);
-    qemu_mod_timer(ds->gui_timer,
-        (ds->gui_timer_interval ?
-	    ds->gui_timer_interval :
-	    GUI_REFRESH_INTERVAL)
-	+ qemu_get_clock(rt_clock));
+    DisplayChangeListener *dcl = ds->listeners;
+
+    dpy_refresh(ds);
+
+    while (dcl != NULL) {
+        if (dcl->gui_timer_interval &&
+            dcl->gui_timer_interval < interval)
+            interval = dcl->gui_timer_interval;
+        dcl = dcl->next;
+    }
+    qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock));
+}
+
+static void nographic_update(void *opaque)
+{
+    uint64_t interval = GUI_REFRESH_INTERVAL;
+
+    qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
 }
 
 struct vm_change_state_entry {
@@ -7566,8 +3544,6 @@
     VMChangeStateEntry *e;
 
     e = qemu_mallocz(sizeof (*e));
-    if (!e)
-        return NULL;
 
     e->cb = cb;
     e->opaque = opaque;
@@ -7581,52 +3557,26 @@
     qemu_free (e);
 }
 
-static void vm_state_notify(int running)
+static void vm_state_notify(int running, int reason)
 {
     VMChangeStateEntry *e;
 
     for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
-        e->cb(e->opaque, running);
+        e->cb(e->opaque, running, reason);
     }
 }
 
-/* XXX: support several handlers */
-static VMStopHandler *vm_stop_cb;
-static void *vm_stop_opaque;
-
-int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque)
-{
-    vm_stop_cb = cb;
-    vm_stop_opaque = opaque;
-    return 0;
-}
-
-void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque)
-{
-    vm_stop_cb = NULL;
-}
+static void resume_all_vcpus(void);
+static void pause_all_vcpus(void);
 
 void vm_start(void)
 {
     if (!vm_running) {
         cpu_enable_ticks();
         vm_running = 1;
-        vm_state_notify(1);
+        vm_state_notify(1, 0);
         qemu_rearm_alarm_timer(alarm_timer);
-    }
-}
-
-void vm_stop(int reason)
-{
-    if (vm_running) {
-        cpu_disable_ticks();
-        vm_running = 0;
-        if (reason != 0) {
-            if (vm_stop_cb) {
-                vm_stop_cb(vm_stop_opaque, reason);
-            }
-        }
-        vm_state_notify(0);
+        resume_all_vcpus();
     }
 }
 
@@ -7635,6 +3585,7 @@
 typedef struct QEMUResetEntry {
     QEMUResetHandler *func;
     void *opaque;
+    int order;
     struct QEMUResetEntry *next;
 } QEMUResetEntry;
 
@@ -7642,6 +3593,8 @@
 static int reset_requested;
 static int shutdown_requested;
 static int powerdown_requested;
+static int debug_requested;
+static int vmstop_requested;
 
 int qemu_shutdown_requested(void)
 {
@@ -7664,16 +3617,42 @@
     return r;
 }
 
-void qemu_register_reset(QEMUResetHandler *func, void *opaque)
+static int qemu_debug_requested(void)
+{
+    int r = debug_requested;
+    debug_requested = 0;
+    return r;
+}
+
+static int qemu_vmstop_requested(void)
+{
+    int r = vmstop_requested;
+    vmstop_requested = 0;
+    return r;
+}
+
+static void do_vm_stop(int reason)
+{
+    if (vm_running) {
+        cpu_disable_ticks();
+        vm_running = 0;
+        pause_all_vcpus();
+        vm_state_notify(0, reason);
+    }
+}
+
+void qemu_register_reset(QEMUResetHandler *func, int order, void *opaque)
 {
     QEMUResetEntry **pre, *re;
 
     pre = &first_reset_entry;
-    while (*pre != NULL)
+    while (*pre != NULL && (*pre)->order >= order) {
         pre = &(*pre)->next;
+    }
     re = qemu_mallocz(sizeof(QEMUResetEntry));
     re->func = func;
     re->opaque = opaque;
+    re->order = order;
     re->next = NULL;
     *pre = re;
 }
@@ -7695,95 +3674,501 @@
     } else {
         reset_requested = 1;
     }
-    if (cpu_single_env)
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+    qemu_notify_event();
 }
 
-#ifdef HAS_AUDIO
-extern void  AUD_cleanup();
-#endif
-
 void qemu_system_shutdown_request(void)
 {
     shutdown_requested = 1;
-    if (cpu_single_env)
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+    qemu_notify_event();
 }
 
 void qemu_system_powerdown_request(void)
 {
     powerdown_requested = 1;
-    if (cpu_single_env)
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+    qemu_notify_event();
 }
 
-#define  MAIN_LOOP_STATS  0
-
-#if  MAIN_LOOP_STATS
-typedef struct {
-    int         counter;
-	int64_t     reset_time;       // time when counter is reset
-    int64_t     spent_time_total; // total time spent since last counter reset
-	int64_t     spent_time_min;   // minimum time spent in call
-	int64_t     spent_time_max;   // maximum time spent in call
-	int64_t     wait_time_total;  // total time spent waiting for select()
-} MainLoopStats;
-
-static __inline__ int64_t
-mainloopstats_now( void )
+#ifdef CONFIG_IOTHREAD
+static void qemu_system_vmstop_request(int reason)
 {
-	return  qemu_get_clock( vm_clock );
+    vmstop_requested = reason;
+    qemu_notify_event();
 }
-
-static __inline__ double
-mainloopstats_to_ms( int64_t  duration )
-{
-	return duration / 1000000.;
-}
-
-static void
-mainloopstats_reset( MainLoopStats*  s )
-{
-	int64_t   now = qemu_get_clock( vm_clock );
-
-	s->counter          = 0;
-	s->reset_time       = now;
-	s->spent_time_total = 0;
-	s->wait_time_total  = 0;
-	s->spent_time_min   = INT_MAX;
-	s->spent_time_max   = 0;
-}
-
-static MainLoopStats   main_loop_stats;
-#endif  /* MAIN_LOOP_STATS */
-
-void main_loop_wait(int timeout)
-{
-    IOHandlerRecord *ioh;
-    fd_set rfds, wfds, xfds;
-    int ret, nfds;
-#ifdef _WIN32
-    int ret2, i;
 #endif
-    struct timeval tv;
+
+#ifndef _WIN32
+static int io_thread_fd = -1;
+
+static void qemu_event_increment(void)
+{
+    static const char byte = 0;
+
+    if (io_thread_fd == -1)
+        return;
+
+    write(io_thread_fd, &byte, sizeof(byte));
+}
+
+static void qemu_event_read(void *opaque)
+{
+    int fd = (unsigned long)opaque;
+    ssize_t len;
+
+    /* Drain the notify pipe */
+    do {
+        char buffer[512];
+        len = read(fd, buffer, sizeof(buffer));
+    } while ((len == -1 && errno == EINTR) || len > 0);
+}
+
+static int qemu_event_init(void)
+{
+    int err;
+    int fds[2];
+
+    err = pipe(fds);
+    if (err == -1)
+        return -errno;
+
+    err = fcntl_setfl(fds[0], O_NONBLOCK);
+    if (err < 0)
+        goto fail;
+
+    err = fcntl_setfl(fds[1], O_NONBLOCK);
+    if (err < 0)
+        goto fail;
+
+    qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
+                         (void *)(unsigned long)fds[0]);
+
+    io_thread_fd = fds[1];
+    return 0;
+
+fail:
+    close(fds[0]);
+    close(fds[1]);
+    return err;
+}
+#else
+HANDLE qemu_event_handle;
+
+static void dummy_event_handler(void *opaque)
+{
+}
+
+static int qemu_event_init(void)
+{
+    qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!qemu_event_handle) {
+        perror("Failed CreateEvent");
+        return -1;
+    }
+    qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+    return 0;
+}
+
+static void qemu_event_increment(void)
+{
+    SetEvent(qemu_event_handle);
+}
+#endif
+
+static int cpu_can_run(CPUState *env)
+{
+    if (env->stop)
+        return 0;
+    if (env->stopped)
+        return 0;
+    return 1;
+}
+
+#ifndef CONFIG_IOTHREAD
+static int qemu_init_main_loop(void)
+{
+    return qemu_event_init();
+}
+
+void qemu_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+
+    if (kvm_enabled())
+        kvm_init_vcpu(env);
+    return;
+}
+
+int qemu_cpu_self(void *env)
+{
+    return 1;
+}
+
+static void resume_all_vcpus(void)
+{
+}
+
+static void pause_all_vcpus(void)
+{
+}
+
+void qemu_cpu_kick(void *env)
+{
+    return;
+}
+
+void qemu_notify_event(void)
+{
+    CPUState *env = cpu_single_env;
+
+    if (env) {
+        cpu_exit(env);
+#ifdef USE_KQEMU
+        if (env->kqemu_enabled)
+            kqemu_cpu_interrupt(env);
+#endif
+     }
+}
+
+#define qemu_mutex_lock_iothread() do { } while (0)
+#define qemu_mutex_unlock_iothread() do { } while (0)
+
+void vm_stop(int reason)
+{
+    do_vm_stop(reason);
+}
+
+#else /* CONFIG_IOTHREAD */
+
+#include "qemu-thread.h"
+
+QemuMutex qemu_global_mutex;
+static QemuMutex qemu_fair_mutex;
+
+static QemuThread io_thread;
+
+static QemuThread *tcg_cpu_thread;
+static QemuCond *tcg_halt_cond;
+
+static int qemu_system_ready;
+/* cpu creation */
+static QemuCond qemu_cpu_cond;
+/* system init */
+static QemuCond qemu_system_cond;
+static QemuCond qemu_pause_cond;
+
+static void block_io_signals(void);
+static void unblock_io_signals(void);
+static int tcg_has_work(void);
+
+static int qemu_init_main_loop(void)
+{
+    int ret;
+
+    ret = qemu_event_init();
+    if (ret)
+        return ret;
+
+    qemu_cond_init(&qemu_pause_cond);
+    qemu_mutex_init(&qemu_fair_mutex);
+    qemu_mutex_init(&qemu_global_mutex);
+    qemu_mutex_lock(&qemu_global_mutex);
+
+    unblock_io_signals();
+    qemu_thread_self(&io_thread);
+
+    return 0;
+}
+
+static void qemu_wait_io_event(CPUState *env)
+{
+    while (!tcg_has_work())
+        qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
+
+    qemu_mutex_unlock(&qemu_global_mutex);
+
+    /*
+     * Users of qemu_global_mutex can be starved, having no chance
+     * to acquire it since this path will get to it first.
+     * So use another lock to provide fairness.
+     */
+    qemu_mutex_lock(&qemu_fair_mutex);
+    qemu_mutex_unlock(&qemu_fair_mutex);
+
+    qemu_mutex_lock(&qemu_global_mutex);
+    if (env->stop) {
+        env->stop = 0;
+        env->stopped = 1;
+        qemu_cond_signal(&qemu_pause_cond);
+    }
+}
+
+static int qemu_cpu_exec(CPUState *env);
+
+static void *kvm_cpu_thread_fn(void *arg)
+{
+    CPUState *env = arg;
+
+    block_io_signals();
+    qemu_thread_self(env->thread);
+
+    /* signal CPU creation */
+    qemu_mutex_lock(&qemu_global_mutex);
+    env->created = 1;
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    /* and wait for machine initialization */
+    while (!qemu_system_ready)
+        qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+
+    while (1) {
+        if (cpu_can_run(env))
+            qemu_cpu_exec(env);
+        qemu_wait_io_event(env);
+    }
+
+    return NULL;
+}
+
+static void tcg_cpu_exec(void);
+
+static void *tcg_cpu_thread_fn(void *arg)
+{
+    CPUState *env = arg;
+
+    block_io_signals();
+    qemu_thread_self(env->thread);
+
+    /* signal CPU creation */
+    qemu_mutex_lock(&qemu_global_mutex);
+    for (env = first_cpu; env != NULL; env = env->next_cpu)
+        env->created = 1;
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    /* and wait for machine initialization */
+    while (!qemu_system_ready)
+        qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
+
+    while (1) {
+        tcg_cpu_exec();
+        qemu_wait_io_event(cur_cpu);
+    }
+
+    return NULL;
+}
+
+void qemu_cpu_kick(void *_env)
+{
+    CPUState *env = _env;
+    qemu_cond_broadcast(env->halt_cond);
+    if (kvm_enabled())
+        qemu_thread_signal(env->thread, SIGUSR1);
+}
+
+int qemu_cpu_self(void *env)
+{
+    return (cpu_single_env != NULL);
+}
+
+static void cpu_signal(int sig)
+{
+    if (cpu_single_env)
+        cpu_exit(cpu_single_env);
+}
+
+static void block_io_signals(void)
+{
+    sigset_t set;
+    struct sigaction sigact;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR2);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR1);
+    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+    memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_handler = cpu_signal;
+    sigaction(SIGUSR1, &sigact, NULL);
+}
+
+static void unblock_io_signals(void)
+{
+    sigset_t set;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR2);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
+    pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGUSR1);
+    pthread_sigmask(SIG_BLOCK, &set, NULL);
+}
+
+static void qemu_signal_lock(unsigned int msecs)
+{
+    qemu_mutex_lock(&qemu_fair_mutex);
+
+    while (qemu_mutex_trylock(&qemu_global_mutex)) {
+        qemu_thread_signal(tcg_cpu_thread, SIGUSR1);
+        if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
+            break;
+    }
+    qemu_mutex_unlock(&qemu_fair_mutex);
+}
+
+static void qemu_mutex_lock_iothread(void)
+{
+    if (kvm_enabled()) {
+        qemu_mutex_lock(&qemu_fair_mutex);
+        qemu_mutex_lock(&qemu_global_mutex);
+        qemu_mutex_unlock(&qemu_fair_mutex);
+    } else
+        qemu_signal_lock(100);
+}
+
+static void qemu_mutex_unlock_iothread(void)
+{
+    qemu_mutex_unlock(&qemu_global_mutex);
+}
+
+static int all_vcpus_paused(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        if (!penv->stopped)
+            return 0;
+        penv = (CPUState *)penv->next_cpu;
+    }
+
+    return 1;
+}
+
+static void pause_all_vcpus(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        penv->stop = 1;
+        qemu_thread_signal(penv->thread, SIGUSR1);
+        qemu_cpu_kick(penv);
+        penv = (CPUState *)penv->next_cpu;
+    }
+
+    while (!all_vcpus_paused()) {
+        qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
+        penv = first_cpu;
+        while (penv) {
+            qemu_thread_signal(penv->thread, SIGUSR1);
+            penv = (CPUState *)penv->next_cpu;
+        }
+    }
+}
+
+static void resume_all_vcpus(void)
+{
+    CPUState *penv = first_cpu;
+
+    while (penv) {
+        penv->stop = 0;
+        penv->stopped = 0;
+        qemu_thread_signal(penv->thread, SIGUSR1);
+        qemu_cpu_kick(penv);
+        penv = (CPUState *)penv->next_cpu;
+    }
+}
+
+static void tcg_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+    /* share a single thread for all cpus with TCG */
+    if (!tcg_cpu_thread) {
+        env->thread = qemu_mallocz(sizeof(QemuThread));
+        env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+        qemu_cond_init(env->halt_cond);
+        qemu_thread_create(env->thread, tcg_cpu_thread_fn, env);
+        while (env->created == 0)
+            qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+        tcg_cpu_thread = env->thread;
+        tcg_halt_cond = env->halt_cond;
+    } else {
+        env->thread = tcg_cpu_thread;
+        env->halt_cond = tcg_halt_cond;
+    }
+}
+
+static void kvm_start_vcpu(CPUState *env)
+{
+    kvm_init_vcpu(env);
+    env->thread = qemu_mallocz(sizeof(QemuThread));
+    env->halt_cond = qemu_mallocz(sizeof(QemuCond));
+    qemu_cond_init(env->halt_cond);
+    qemu_thread_create(env->thread, kvm_cpu_thread_fn, env);
+    while (env->created == 0)
+        qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
+}
+
+void qemu_init_vcpu(void *_env)
+{
+    CPUState *env = _env;
+
+    if (kvm_enabled())
+        kvm_start_vcpu(env);
+    else
+        tcg_init_vcpu(env);
+}
+
+void qemu_notify_event(void)
+{
+    qemu_event_increment();
+}
+
+void vm_stop(int reason)
+{
+    QemuThread me;
+    qemu_thread_self(&me);
+
+    if (!qemu_thread_equal(&me, &io_thread)) {
+        qemu_system_vmstop_request(reason);
+        /*
+         * FIXME: should not return to device code in case
+         * vm_stop() has been requested.
+         */
+        if (cpu_single_env) {
+            cpu_exit(cpu_single_env);
+            cpu_single_env->stop = 1;
+        }
+        return;
+    }
+    do_vm_stop(reason);
+}
+
+#endif
+
+
+#ifdef _WIN32
+static void host_main_loop_wait(int *timeout)
+{
+    int ret, ret2, i;
     PollingEntry *pe;
 
-#if MAIN_LOOP_STATS
-	int64   time_before = mainloopstats_now();
-	int64   time_after_select;
-#endif
 
     /* XXX: need to suppress polling by better using win32 events */
     ret = 0;
     for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
         ret |= pe->func(pe->opaque);
     }
-#ifdef _WIN32
     if (ret == 0) {
         int err;
         WaitObjects *w = &wait_objects;
 
-        ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
+        ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
         if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
             if (w->func[ret - WAIT_OBJECT_0])
                 w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
@@ -7808,7 +4193,26 @@
             fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
         }
     }
+
+    *timeout = 0;
+}
+#else
+static void host_main_loop_wait(int *timeout)
+{
+}
 #endif
+
+void main_loop_wait(int timeout)
+{
+    IOHandlerRecord *ioh;
+    fd_set rfds, wfds, xfds;
+    int ret, nfds;
+    struct timeval tv;
+
+    qemu_bh_update_timeout(&timeout);
+
+    host_main_loop_wait(&timeout);
+
     /* poll any events */
     /* XXX: separate device handlers from system ones */
     nfds = -1;
@@ -7832,21 +4236,17 @@
         }
     }
 
-    tv.tv_sec = 0;
-#ifdef _WIN32
-    tv.tv_usec = 0;
-#else
-    tv.tv_usec = timeout * 1000;
-#endif
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+
 #if defined(CONFIG_SLIRP)
-    if (slirp_inited) {
+    if (slirp_is_inited()) {
         slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
     }
 #endif
+    qemu_mutex_unlock_iothread();
     ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
-#if MAIN_LOOP_STATS
-	time_after_select = mainloopstats_now();
-#endif
+    qemu_mutex_lock_iothread();
     if (ret > 0) {
         IOHandlerRecord **pioh;
 
@@ -7871,7 +4271,7 @@
         }
     }
 #if defined(CONFIG_SLIRP)
-    if (slirp_inited) {
+    if (slirp_is_inited()) {
         if (ret < 0) {
             FD_ZERO(&rfds);
             FD_ZERO(&wfds);
@@ -7880,378 +4280,251 @@
         slirp_select_poll(&rfds, &wfds, &xfds);
     }
 #endif
-    charpipe_poll();
 
+    /* rearm timer, if not periodic */
+    if (alarm_timer->flags & ALARM_FLAG_EXPIRED) {
+        alarm_timer->flags &= ~ALARM_FLAG_EXPIRED;
+        qemu_rearm_alarm_timer(alarm_timer);
+    }
+
+    /* vm time timers */
     if (vm_running) {
-        if (likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER)))
-        qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
-                        qemu_get_clock(vm_clock));
-        /* run dma transfers, if any */
-        DMA_run();
+        if (!cur_cpu || likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER)))
+            qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
+                qemu_get_clock(vm_clock));
     }
 
     /* real time timers */
     qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
                     qemu_get_clock(rt_clock));
 
-    if (alarm_timer->flags & ALARM_FLAG_EXPIRED) {
-        alarm_timer->flags &= ~(ALARM_FLAG_EXPIRED);
-        qemu_rearm_alarm_timer(alarm_timer);
-    }
-
     /* Check bottom-halves last in case any of the earlier events triggered
        them.  */
     qemu_bh_poll();
 
-#if MAIN_LOOP_STATS
-	{
-		MainLoopStats*  s = &main_loop_stats;
-		int64_t         time_after = mainloopstats_now();
-		int64_t         time_diff  = time_after - time_before;
-
-		s->spent_time_total += time_diff;
-		if (time_diff < s->spent_time_min)
-			s->spent_time_min = time_diff;
-	    if (time_diff > s->spent_time_max)
-		    s->spent_time_max = time_diff;
-
-		time_diff = time_after_select - time_before;
-		s->wait_time_total += time_diff;
-
-		if (++s->counter == 1000) {
-			double  period        = time_after - s->reset_time;
-			double  average_spent = s->spent_time_total * 1. / s->counter;
-			double  average_wait  = s->wait_time_total * 1. / s->counter;
-
-			printf( "main loop stats:  iterations: %8ld,  period: %10.2f ms, avg wait time: %10.2f ms  (%.3f %%), avg exec time %10.2f ms (%.3f %%)\n",
-			        s->counter,
-					mainloopstats_to_ms(period),
-					mainloopstats_to_ms(average_wait),
-					s->wait_time_total * 100. / period,
-					mainloopstats_to_ms(average_spent),
-					s->spent_time_total * 100. / period );
-
-			mainloopstats_reset( s );
-		}
-	}
-#endif  /* MAIN_LOOP_STATS */
 }
 
-static int main_loop(void)
+static int qemu_cpu_exec(CPUState *env)
 {
-    int ret, timeout;
+    int ret;
 #ifdef CONFIG_PROFILER
     int64_t ti;
 #endif
+
+#ifdef CONFIG_PROFILER
+    ti = profile_getclock();
+#endif
+    if (use_icount) {
+        int64_t count;
+        int decr;
+        qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
+        env->icount_decr.u16.low = 0;
+        env->icount_extra = 0;
+        count = qemu_next_deadline();
+        count = (count + (1 << icount_time_shift) - 1)
+                >> icount_time_shift;
+        qemu_icount += count;
+        decr = (count > 0xffff) ? 0xffff : count;
+        count -= decr;
+        env->icount_decr.u16.low = decr;
+        env->icount_extra = count;
+    }
+    ret = cpu_exec(env);
+#ifdef CONFIG_PROFILER
+    qemu_time += profile_getclock() - ti;
+#endif
+    if (use_icount) {
+        /* Fold pending instructions back into the
+           instruction counter, and clear the interrupt flag.  */
+        qemu_icount -= (env->icount_decr.u16.low
+                        + env->icount_extra);
+        env->icount_decr.u32 = 0;
+        env->icount_extra = 0;
+    }
+    return ret;
+}
+
+static void tcg_cpu_exec(void)
+{
+    int ret = 0;
+
+    if (next_cpu == NULL)
+        next_cpu = first_cpu;
+    for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) {
+        CPUState *env = cur_cpu = next_cpu;
+
+        if (!vm_running)
+            break;
+        if (timer_alarm_pending) {
+            timer_alarm_pending = 0;
+            break;
+        }
+        if (cpu_can_run(env))
+            ret = qemu_cpu_exec(env);
+        if (ret == EXCP_DEBUG) {
+            gdb_set_stop_cpu(env);
+            debug_requested = 1;
+            break;
+        }
+    }
+}
+
+static int cpu_has_work(CPUState *env)
+{
+    if (env->stop)
+        return 1;
+    if (env->stopped)
+        return 0;
+    if (!env->halted)
+        return 1;
+    if (qemu_cpu_has_work(env))
+        return 1;
+    return 0;
+}
+
+static int tcg_has_work(void)
+{
     CPUState *env;
 
-    cur_cpu = first_cpu;
-    next_cpu = cur_cpu->next_cpu ?: first_cpu;
-    for(;;) {
-        if (vm_running) {
+    for (env = first_cpu; env != NULL; env = env->next_cpu)
+        if (cpu_has_work(env))
+            return 1;
+    return 0;
+}
 
-            for(;;) {
-                /* get next cpu */
-                env = next_cpu;
-#ifdef CONFIG_PROFILER
-                ti = profile_getclock();
-#endif
-                if (use_icount) {
-                    int64_t count;
-                    int decr;
-                    qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
-                    env->icount_decr.u16.low = 0;
-                    env->icount_extra = 0;
-                    count = qemu_next_deadline();
-                    count = (count + (1 << icount_time_shift) - 1)
-                            >> icount_time_shift;
-                    qemu_icount += count;
-                    decr = (count > 0xffff) ? 0xffff : count;
-                    count -= decr;
-                    env->icount_decr.u16.low = decr;
-                    env->icount_extra = count;
-                }
-                ret = cpu_exec(env);
-#ifdef CONFIG_PROFILER
-                qemu_time += profile_getclock() - ti;
-#endif
-                if (use_icount) {
-                    /* Fold pending instructions back into the
-                       instruction counter, and clear the interrupt flag.  */
-                    qemu_icount -= (env->icount_decr.u16.low
-                                    + env->icount_extra);
-                    env->icount_decr.u32 = 0;
-                    env->icount_extra = 0;
-                }
-                next_cpu = env->next_cpu ?: first_cpu;
-                if (event_pending && likely(ret != EXCP_DEBUG)) {
-                    ret = EXCP_INTERRUPT;
-                    event_pending = 0;
-                    break;
-                }
-                if (ret == EXCP_HLT) {
-                    /* Give the next CPU a chance to run.  */
-                    cur_cpu = env;
-                    continue;
-                }
-                if (ret != EXCP_HALTED)
-                    break;
-                /* all CPUs are halted ? */
-                if (env == cur_cpu)
-                    break;
-            }
-            cur_cpu = env;
+static int qemu_calculate_timeout(void)
+{
+#ifndef CONFIG_IOTHREAD
+    int timeout;
 
-#ifdef CONFIG_TRACE
-            if (tbflush_requested) {
-                tbflush_requested = 0;
-                tb_flush(env);
-                ret = EXCP_INTERRUPT;
-            } else if (exit_requested)
-				goto ExitRequested;
-#endif
-
-            if (shutdown_requested) {
-                ret = EXCP_INTERRUPT;
-                if (no_shutdown) {
-                    vm_stop(0);
-                    no_shutdown = 0;
-                }
-                else
-                    break;
-            }
-            if (reset_requested) {
-                reset_requested = 0;
-                qemu_system_reset();
-                ret = EXCP_INTERRUPT;
-            }
-            if (powerdown_requested) {
-                powerdown_requested = 0;
-		qemu_system_powerdown();
-                ret = EXCP_INTERRUPT;
-            }
-            if (unlikely(ret == EXCP_DEBUG)) {
-                vm_stop(EXCP_DEBUG);
-            }
-            /* If all cpus are halted then wait until the next IRQ */
-            /* XXX: use timeout computed from timers */
-            if (ret == EXCP_HALTED) {
-                if (use_icount) {
-                    int64_t add;
-                    int64_t delta;
-                    /* Advance virtual time to the next event.  */
-                    if (use_icount == 1) {
-                        /* When not using an adaptive execution frequency
-                           we tend to get badly out of sync with real time,
-                           so just delay for a reasonable amount of time.  */
-                        delta = 0;
-                    } else {
-                        delta = cpu_get_icount() - cpu_get_clock();
-                    }
-                    if (delta > 0) {
-                        /* If virtual time is ahead of real time then just
-                           wait for IO.  */
-                        timeout = (delta / 1000000) + 1;
-                    } else {
-                        /* Wait for either IO to occur or the next
-                           timer event.  */
-                        add = qemu_next_deadline();
-                        /* We advance the timer before checking for IO.
-                           Limit the amount we advance so that early IO
-                           activity won't get the guest too far ahead.  */
-                        if (add > 10000000)
-                            add = 10000000;
-                        delta += add;
-                        add = (add + (1 << icount_time_shift) - 1)
-                              >> icount_time_shift;
-                        qemu_icount += add;
-                        timeout = delta / 1000000;
-                        if (timeout < 0)
-                            timeout = 0;
-                    }
-                } else {
-                    timeout = 10;
-                }
-            } else {
-                timeout = 0;
-            }
+    if (!vm_running)
+        timeout = 5000;
+    else if (tcg_has_work())
+        timeout = 0;
+    else if (!use_icount)
+        timeout = 5000;
+    else {
+     /* XXX: use timeout computed from timers */
+        int64_t add;
+        int64_t delta;
+        /* Advance virtual time to the next event.  */
+        if (use_icount == 1) {
+            /* When not using an adaptive execution frequency
+               we tend to get badly out of sync with real time,
+               so just delay for a reasonable amount of time.  */
+            delta = 0;
         } else {
-            if (shutdown_requested)
-                break;
-            timeout = 10;
+            delta = cpu_get_icount() - cpu_get_clock();
         }
-#ifdef CONFIG_PROFILER
-        ti = profile_getclock();
-#endif
-        main_loop_wait(timeout);
-#ifdef CONFIG_PROFILER
-        dev_time += profile_getclock() - ti;
-#endif
+        if (delta > 0) {
+            /* If virtual time is ahead of real time then just
+               wait for IO.  */
+            timeout = (delta / 1000000) + 1;
+        } else {
+            /* Wait for either IO to occur or the next
+               timer event.  */
+            add = qemu_next_deadline();
+            /* We advance the timer before checking for IO.
+               Limit the amount we advance so that early IO
+               activity won't get the guest too far ahead.  */
+            if (add > 10000000)
+                add = 10000000;
+            delta += add;
+            add = (add + (1 << icount_time_shift) - 1)
+                  >> icount_time_shift;
+            qemu_icount += add;
+            timeout = delta / 1000000;
+            if (timeout < 0)
+                timeout = 0;
+        }
     }
-    cpu_disable_ticks();
-    return ret;
 
-#ifdef CONFIG_TRACE
-ExitRequested:
-#  ifdef HAS_AUDIO
-    AUD_cleanup();
-#  endif
-    exit(1);
-	return 0;
+    return timeout;
+#else /* CONFIG_IOTHREAD */
+    return 1000;
 #endif
 }
 
-void qemu_help(int exitcode)
+static int vm_can_run(void)
 {
-    printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
-           "usage: %s [options] [disk_image]\n"
+    if (powerdown_requested)
+        return 0;
+    if (reset_requested)
+        return 0;
+    if (shutdown_requested)
+        return 0;
+    if (debug_requested)
+        return 0;
+    return 1;
+}
+
+static void main_loop(void)
+{
+    int r;
+
+#ifdef CONFIG_IOTHREAD
+    qemu_system_ready = 1;
+    qemu_cond_broadcast(&qemu_system_cond);
+#endif
+
+    for (;;) {
+        do {
+#ifdef CONFIG_PROFILER
+            int64_t ti;
+#endif
+#ifndef CONFIG_IOTHREAD
+            tcg_cpu_exec();
+#endif
+#ifdef CONFIG_PROFILER
+            ti = profile_getclock();
+#endif
+            main_loop_wait(qemu_calculate_timeout());
+#ifdef CONFIG_PROFILER
+            dev_time += profile_getclock() - ti;
+#endif
+        } while (vm_can_run());
+
+        if (qemu_debug_requested())
+            vm_stop(EXCP_DEBUG);
+        if (qemu_shutdown_requested()) {
+            if (no_shutdown) {
+                vm_stop(0);
+                no_shutdown = 0;
+            } else
+                break;
+        }
+        if (qemu_reset_requested()) {
+            pause_all_vcpus();
+            qemu_system_reset();
+            resume_all_vcpus();
+        }
+        if (qemu_powerdown_requested())
+            qemu_system_powerdown();
+        if ((r = qemu_vmstop_requested()))
+            vm_stop(r);
+    }
+    pause_all_vcpus();
+}
+
+static void version(void)
+{
+    printf("QEMU PC emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+}
+
+static void help(int exitcode)
+{
+    version();
+    printf("usage: %s [options] [disk_image]\n"
            "\n"
            "'disk_image' is a raw hard image image for IDE hard disk 0\n"
            "\n"
-           "Standard options:\n"
-           "-M machine      select emulated machine (-M ? for list)\n"
-           "-cpu cpu        select CPU (-cpu ? for list)\n"
-           "-fda/-fdb file  use 'file' as floppy disk 0/1 image\n"
-           "-hda/-hdb file  use 'file' as IDE hard disk 0/1 image\n"
-           "-hdc/-hdd file  use 'file' as IDE hard disk 2/3 image\n"
-           "-cdrom file     use 'file' as IDE cdrom image (cdrom is ide1 master)\n"
-	   "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
-           "       [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
-           "       [,cache=on|off][,format=f]\n"
-	   "                use 'file' as a drive image\n"
-           "-mtdblock file  use 'file' as on-board Flash memory image\n"
-           "-sd file        use 'file' as SecureDigital card image\n"
-           "-pflash file    use 'file' as a parallel flash image\n"
-           "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n"
-           "-snapshot       write to temporary files instead of disk image files\n"
-#ifdef CONFIG_SDL
-           "-no-frame       open SDL window without a frame and window decorations\n"
-           "-alt-grab       use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n"
-           "-no-quit        disable SDL window close capability\n"
-#endif
-#ifdef TARGET_I386
-           "-no-fd-bootchk  disable boot signature checking for floppy disks\n"
-#endif
-           "-m megs         set virtual RAM size to megs MB [default=%d]\n"
-           "-smp n          set the number of CPUs to 'n' [default=1]\n"
-           "-nographic      disable graphical output and redirect serial I/Os to console\n"
-           "-portrait       rotate graphical output 90 deg left (only PXA LCD)\n"
-#ifndef _WIN32
-           "-k language     use keyboard layout (for example \"fr\" for French)\n"
-#endif
-#ifdef HAS_AUDIO
-           "-audio-help     print list of audio drivers and their options\n"
-           "-soundhw c1,... enable audio support\n"
-           "                and only specified sound cards (comma separated list)\n"
-           "                use -soundhw ? to get the list of supported cards\n"
-           "                use -soundhw all to enable all of them\n"
-#endif
-           "-localtime      set the real time clock to local time [default=utc]\n"
-           "-full-screen    start in full screen\n"
-#ifdef TARGET_I386
-           "-win2k-hack     use it when installing Windows 2000 to avoid a disk full bug\n"
-#endif
-           "-usb            enable the USB driver (will be the default soon)\n"
-           "-usbdevice name add the host or guest USB device 'name'\n"
-#if defined(TARGET_PPC) || defined(TARGET_SPARC)
-           "-g WxH[xDEPTH]  Set the initial graphical resolution and depth\n"
-#endif
-           "-name string    set the name of the guest\n"
-           "\n"
-           "Network options:\n"
-           "-net nic[,vlan=n][,macaddr=addr][,model=type]\n"
-           "                create a new Network Interface Card and connect it to VLAN 'n'\n"
-#ifdef CONFIG_SLIRP
-           "-net user[,vlan=n][,hostname=host]\n"
-           "                connect the user mode network stack to VLAN 'n' and send\n"
-           "                hostname 'host' to DHCP clients\n"
-#endif
-#ifdef _WIN32
-           "-net tap[,vlan=n],ifname=name\n"
-           "                connect the host TAP network interface to VLAN 'n'\n"
-#else
-           "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file][,downscript=dfile]\n"
-           "                connect the host TAP network interface to VLAN 'n' and use the\n"
-           "                network scripts 'file' (default=%s)\n"
-           "                and 'dfile' (default=%s);\n"
-           "                use '[down]script=no' to disable script execution;\n"
-           "                use 'fd=h' to connect to an already opened TAP interface\n"
-#endif
-           "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n"
-           "                connect the vlan 'n' to another VLAN using a socket connection\n"
-           "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n"
-           "                connect the vlan 'n' to multicast maddr and port\n"
-           "-net none       use it alone to have zero network devices; if no -net option\n"
-           "                is provided, the default is '-net nic -net user'\n"
-           "\n"
-#ifdef CONFIG_SLIRP
-           "-tftp dir       allow tftp access to files in dir [-net user]\n"
-           "-bootp file     advertise file in BOOTP replies\n"
-#ifndef _WIN32
-           "-smb dir        allow SMB access to files in 'dir' [-net user]\n"
-#endif
-           "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n"
-           "                redirect TCP or UDP connections from host to guest [-net user]\n"
-#endif
-           "\n"
-           "Linux boot specific:\n"
-           "-kernel bzImage use 'bzImage' as kernel image\n"
-           "-append cmdline use 'cmdline' as kernel command line\n"
-           "-initrd file    use 'file' as initial ram disk\n"
-           "\n"
-           "Debug/Expert options:\n"
-           "-monitor dev    redirect the monitor to char device 'dev'\n"
-           "-serial dev     redirect the serial port to char device 'dev'\n"
-           "-parallel dev   redirect the parallel port to char device 'dev'\n"
-           "-pidfile file   Write PID to 'file'\n"
-           "-S              freeze CPU at startup (use 'c' to start execution)\n"
-           "-s              wait gdb connection to port\n"
-           "-p port         set gdb connection port [default=%s]\n"
-           "-d item1,...    output log to %s (use -d ? for a list of log items)\n"
-           "-hdachs c,h,s[,t]  force hard disk 0 physical geometry and the optional BIOS\n"
-           "                translation (t=none or lba) (usually qemu can guess them)\n"
-           "-L path         set the directory for the BIOS, VGA BIOS and keymaps\n"
-#ifdef USE_KQEMU
-           "-kernel-kqemu   enable KQEMU full virtualization (default is user mode only)\n"
-           "-no-kqemu       disable KQEMU kernel module usage\n"
-#endif
-#ifdef TARGET_I386
-           "-std-vga        simulate a standard VGA card with VESA Bochs Extensions\n"
-           "                (default is CL-GD5446 PCI VGA)\n"
-           "-no-acpi        disable ACPI\n"
-#endif
-#ifdef CONFIG_CURSES
-           "-curses         use a curses/ncurses interface instead of SDL\n"
-#endif
-           "-no-reboot      exit instead of rebooting\n"
-           "-no-shutdown    stop before shutdown\n"
-           "-loadvm [tag|id]  start right away with a saved state (loadvm in monitor)\n"
-	   "-vnc display    start a VNC server on display\n"
-#ifdef CONFIG_TRACE
-	   "-trace file     create an execution trace in 'file' (implies -tracing on)\n"
-	   "-tracing off    start with tracing off\n"
-	   "-trace_miss     include tracing of cache miss addresses\n"
-	   "-trace_addr     include tracing of all load/store addresses\n"
-	   "-dcache_load_miss cycles\n"
-           "                set the dcache load miss penalty to 'cycles'\n"
-	   "-dcache_store_miss cycles\n"
-           "                set the dcache store miss penalty to 'cycles'\n"
-#endif
-#ifdef CONFIG_NAND
-           "-nand name[,readonly][,size=size][,pagesize=size][,extrasize=size][,erasepages=pages][,initfile=file][,file=file]"
-#endif
-#ifndef _WIN32
-	   "-daemonize      daemonize QEMU after initializing\n"
-#endif
-	   "-option-rom rom load a file, rom, into the option ROM space\n"
-#ifdef TARGET_SPARC
-           "-prom-env variable=value  set OpenBIOS nvram variables\n"
-#endif
-           "-clock          force the use of the given methods for timer alarm.\n"
-           "                To see what timers are available use -clock ?\n"
-           "-startdate      select initial date of the clock\n"
-           "-icount [N|auto]\n"
-           "                Enable virtual instruction counter with 2^N clock ticks per instruction\n"
+#define DEF(option, opt_arg, opt_enum, opt_help)        \
+           opt_help
+#define DEFHEADING(text) stringify(text) "\n"
+#include "qemu-options.h"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
            "\n"
            "During emulation, the following keys are useful:\n"
            "ctrl-alt-f      toggle full screen\n"
@@ -8274,101 +4547,13 @@
 #define HAS_ARG 0x0001
 
 enum {
-    QEMU_OPTION_h,
-
-    QEMU_OPTION_M,
-    QEMU_OPTION_cpu,
-    QEMU_OPTION_fda,
-    QEMU_OPTION_fdb,
-    QEMU_OPTION_hda,
-    QEMU_OPTION_hdb,
-    QEMU_OPTION_hdc,
-    QEMU_OPTION_hdd,
-    QEMU_OPTION_drive,
-    QEMU_OPTION_cdrom,
-    QEMU_OPTION_mtdblock,
-    QEMU_OPTION_sd,
-    QEMU_OPTION_pflash,
-    QEMU_OPTION_boot,
-    QEMU_OPTION_snapshot,
-#ifdef TARGET_I386
-    QEMU_OPTION_no_fd_bootchk,
-#endif
-    QEMU_OPTION_m,
-    QEMU_OPTION_nographic,
-    QEMU_OPTION_portrait,
-#ifdef HAS_AUDIO
-    QEMU_OPTION_audio_help,
-    QEMU_OPTION_soundhw,
-#endif
-
-    QEMU_OPTION_net,
-    QEMU_OPTION_tftp,
-    QEMU_OPTION_bootp,
-    QEMU_OPTION_smb,
-    QEMU_OPTION_redir,
-
-    QEMU_OPTION_kernel,
-    QEMU_OPTION_append,
-    QEMU_OPTION_initrd,
-
-    QEMU_OPTION_S,
-    QEMU_OPTION_s,
-    QEMU_OPTION_p,
-    QEMU_OPTION_d,
-    QEMU_OPTION_hdachs,
-    QEMU_OPTION_L,
-    QEMU_OPTION_bios,
-    QEMU_OPTION_k,
-    QEMU_OPTION_localtime,
-    QEMU_OPTION_cirrusvga,
-    QEMU_OPTION_vmsvga,
-    QEMU_OPTION_g,
-    QEMU_OPTION_std_vga,
-    QEMU_OPTION_echr,
-    QEMU_OPTION_monitor,
-    QEMU_OPTION_serial,
-    QEMU_OPTION_parallel,
-    QEMU_OPTION_loadvm,
-    QEMU_OPTION_full_screen,
-    QEMU_OPTION_no_frame,
-    QEMU_OPTION_alt_grab,
-    QEMU_OPTION_no_quit,
-    QEMU_OPTION_pidfile,
-    QEMU_OPTION_no_kqemu,
-    QEMU_OPTION_kernel_kqemu,
-    QEMU_OPTION_win2k_hack,
-    QEMU_OPTION_usb,
-    QEMU_OPTION_usbdevice,
-    QEMU_OPTION_smp,
-    QEMU_OPTION_vnc,
-    QEMU_OPTION_no_acpi,
-    QEMU_OPTION_curses,
-    QEMU_OPTION_no_reboot,
-    QEMU_OPTION_no_shutdown,
-    QEMU_OPTION_show_cursor,
-    QEMU_OPTION_daemonize,
-    QEMU_OPTION_option_rom,
-    QEMU_OPTION_semihosting,
-    QEMU_OPTION_name,
-    QEMU_OPTION_prom_env,
-    QEMU_OPTION_old_param,
-    QEMU_OPTION_mic,
-#ifdef CONFIG_TRACE
-    QEMU_OPTION_trace_file,
-    QEMU_OPTION_tracing,
-    QEMU_OPTION_trace_miss,
-    QEMU_OPTION_trace_addr,
-    QEMU_OPTION_dcache_load_miss,
-    QEMU_OPTION_dcache_store_miss,
-#endif
-#ifdef CONFIG_NAND
-    QEMU_OPTION_nand,
-#endif
-    QEMU_OPTION_clock,
-    QEMU_OPTION_startdate,
-    QEMU_OPTION_tb_size,
-    QEMU_OPTION_icount,
+#define DEF(option, opt_arg, opt_enum, opt_help)        \
+    opt_enum,
+#define DEFHEADING(text)
+#include "qemu-options.h"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
 };
 
 typedef struct QEMUOption {
@@ -8377,168 +4562,22 @@
     int index;
 } QEMUOption;
 
-const QEMUOption qemu_options[] = {
+static const QEMUOption qemu_options[] = {
     { "h", 0, QEMU_OPTION_h },
-    { "help", 0, QEMU_OPTION_h },
-
-    { "M", HAS_ARG, QEMU_OPTION_M },
-    { "cpu", HAS_ARG, QEMU_OPTION_cpu },
-    { "fda", HAS_ARG, QEMU_OPTION_fda },
-    { "fdb", HAS_ARG, QEMU_OPTION_fdb },
-    { "hda", HAS_ARG, QEMU_OPTION_hda },
-    { "hdb", HAS_ARG, QEMU_OPTION_hdb },
-    { "hdc", HAS_ARG, QEMU_OPTION_hdc },
-    { "hdd", HAS_ARG, QEMU_OPTION_hdd },
-    { "drive", HAS_ARG, QEMU_OPTION_drive },
-    { "cdrom", HAS_ARG, QEMU_OPTION_cdrom },
-    { "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock },
-    { "sd", HAS_ARG, QEMU_OPTION_sd },
-    { "pflash", HAS_ARG, QEMU_OPTION_pflash },
-    { "boot", HAS_ARG, QEMU_OPTION_boot },
-    { "snapshot", 0, QEMU_OPTION_snapshot },
-#ifdef TARGET_I386
-    { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk },
-#endif
-    { "m", HAS_ARG, QEMU_OPTION_m },
-    { "nographic", 0, QEMU_OPTION_nographic },
-    { "portrait", 0, QEMU_OPTION_portrait },
-    { "k", HAS_ARG, QEMU_OPTION_k },
-#ifdef HAS_AUDIO
-    { "audio-help", 0, QEMU_OPTION_audio_help },
-    { "soundhw", HAS_ARG, QEMU_OPTION_soundhw },
-#endif
-
-    { "net", HAS_ARG, QEMU_OPTION_net},
-#ifdef CONFIG_SLIRP
-    { "tftp", HAS_ARG, QEMU_OPTION_tftp },
-    { "bootp", HAS_ARG, QEMU_OPTION_bootp },
-#ifndef _WIN32
-    { "smb", HAS_ARG, QEMU_OPTION_smb },
-#endif
-    { "redir", HAS_ARG, QEMU_OPTION_redir },
-#endif
-
-    { "kernel", HAS_ARG, QEMU_OPTION_kernel },
-    { "append", HAS_ARG, QEMU_OPTION_append },
-    { "initrd", HAS_ARG, QEMU_OPTION_initrd },
-
-    { "S", 0, QEMU_OPTION_S },
-    { "s", 0, QEMU_OPTION_s },
-    { "p", HAS_ARG, QEMU_OPTION_p },
-    { "d", HAS_ARG, QEMU_OPTION_d },
-    { "hdachs", HAS_ARG, QEMU_OPTION_hdachs },
-    { "L", HAS_ARG, QEMU_OPTION_L },
-    { "bios", HAS_ARG, QEMU_OPTION_bios },
-#ifdef USE_KQEMU
-    { "no-kqemu", 0, QEMU_OPTION_no_kqemu },
-    { "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu },
-#endif
-#if defined(TARGET_PPC) || defined(TARGET_SPARC)
-    { "g", HAS_ARG, QEMU_OPTION_g },
-#endif
-    { "localtime", 0, QEMU_OPTION_localtime },
-    { "std-vga", 0, QEMU_OPTION_std_vga },
-    { "echr", HAS_ARG, QEMU_OPTION_echr },
-    { "monitor", HAS_ARG, QEMU_OPTION_monitor },
-    { "serial", HAS_ARG, QEMU_OPTION_serial },
-    { "parallel", HAS_ARG, QEMU_OPTION_parallel },
-    { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
-    { "full-screen", 0, QEMU_OPTION_full_screen },
-#ifdef CONFIG_SDL
-    { "no-frame", 0, QEMU_OPTION_no_frame },
-    { "alt-grab", 0, QEMU_OPTION_alt_grab },
-    { "no-quit", 0, QEMU_OPTION_no_quit },
-#endif
-    { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
-    { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
-    { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
-    { "smp", HAS_ARG, QEMU_OPTION_smp },
-    { "vnc", HAS_ARG, QEMU_OPTION_vnc },
-#ifdef CONFIG_CURSES
-    { "curses", 0, QEMU_OPTION_curses },
-#endif
-
-    /* temporary options */
-    { "usb", 0, QEMU_OPTION_usb },
-    { "cirrusvga", 0, QEMU_OPTION_cirrusvga },
-    { "vmwarevga", 0, QEMU_OPTION_vmsvga },
-    { "no-acpi", 0, QEMU_OPTION_no_acpi },
-    { "no-reboot", 0, QEMU_OPTION_no_reboot },
-    { "no-shutdown", 0, QEMU_OPTION_no_shutdown },
-    { "show-cursor", 0, QEMU_OPTION_show_cursor },
-    { "daemonize", 0, QEMU_OPTION_daemonize },
-    { "option-rom", HAS_ARG, QEMU_OPTION_option_rom },
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
-    { "semihosting", 0, QEMU_OPTION_semihosting },
-#endif
-    { "name", HAS_ARG, QEMU_OPTION_name },
-#if defined(TARGET_SPARC)
-    { "prom-env", HAS_ARG, QEMU_OPTION_prom_env },
-#endif
-#if defined(TARGET_ARM)
-    { "old-param", 0, QEMU_OPTION_old_param },
-#endif
-
-    /* android stuff */
-    { "mic", HAS_ARG, QEMU_OPTION_mic },
-#ifdef CONFIG_TRACE
-    { "trace", HAS_ARG, QEMU_OPTION_trace_file },
-    { "tracing", HAS_ARG, QEMU_OPTION_tracing },
-    { "trace_miss", 0, QEMU_OPTION_trace_miss },
-    { "trace_addr", 0, QEMU_OPTION_trace_addr },
-    { "dcache_load_miss", HAS_ARG, QEMU_OPTION_dcache_load_miss },
-    { "dcache_store_miss", HAS_ARG, QEMU_OPTION_dcache_store_miss },
-#endif
-#ifdef CONFIG_NAND
-    { "nand", HAS_ARG, QEMU_OPTION_nand },
-#endif
-    { "clock", HAS_ARG, QEMU_OPTION_clock },
-    { NULL, 0, 0 },
+#define DEF(option, opt_arg, opt_enum, opt_help)        \
+    { option, opt_arg, opt_enum },
+#define DEFHEADING(text)
+#include "qemu-options.h"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
+    { NULL },
 };
 
-/* password input */
-
-int qemu_key_check(BlockDriverState *bs, const char *name)
-{
-    char password[256];
-    int i;
-
-    if (!bdrv_is_encrypted(bs))
-        return 0;
-
-    term_printf("%s is encrypted.\n", name);
-    for(i = 0; i < 3; i++) {
-        monitor_readline("Password: ", 1, password, sizeof(password));
-        if (bdrv_set_key(bs, password) == 0)
-            return 0;
-        term_printf("invalid password\n");
-    }
-    return -EPERM;
-}
-
-static BlockDriverState *get_bdrv(int index)
-{
-    if (index > nb_drives)
-        return NULL;
-    return drives_table[index].bdrv;
-}
-
-static void read_passwords(void)
-{
-    BlockDriverState *bs;
-    int i;
-
-    for(i = 0; i < 6; i++) {
-        bs = get_bdrv(i);
-        if (bs)
-            qemu_key_check(bs, bdrv_get_device_name(bs));
-    }
-}
-
 #ifdef HAS_AUDIO
 struct soundhw soundhw[] = {
-#if 0  /* ANDROID */
-#ifdef TARGET_I386
+#ifdef HAS_AUDIO_CHOICE
+#if defined(TARGET_I386) || defined(TARGET_MIPS)
     {
         "pcspk",
         "PC speaker",
@@ -8547,6 +4586,8 @@
         { .init_isa = pcspk_audio_init }
     },
 #endif
+
+#ifdef CONFIG_SB16
     {
         "sb16",
         "Creative Sound Blaster 16",
@@ -8554,6 +4595,7 @@
         1,
         { .init_isa = SB16_init }
     },
+#endif
 
 #ifdef CONFIG_CS4231A
     {
@@ -8599,6 +4641,7 @@
     },
 #endif
 
+#ifdef CONFIG_ES1370
     {
         "es1370",
         "ENSONIQ AudioPCI ES1370",
@@ -8606,7 +4649,9 @@
         0,
         { .init_pci = es1370_init }
     },
-#endif /* ANDROID */
+#endif
+
+#endif /* HAS_AUDIO_CHOICE */
 
     { NULL, NULL, 0, 0, { NULL } }
 };
@@ -8670,6 +4715,42 @@
 }
 #endif
 
+static void select_vgahw (const char *p)
+{
+    const char *opts;
+
+    cirrus_vga_enabled = 0;
+    std_vga_enabled = 0;
+    vmsvga_enabled = 0;
+    xenfb_enabled = 0;
+    if (strstart(p, "std", &opts)) {
+        std_vga_enabled = 1;
+    } else if (strstart(p, "cirrus", &opts)) {
+        cirrus_vga_enabled = 1;
+    } else if (strstart(p, "vmware", &opts)) {
+        vmsvga_enabled = 1;
+    } else if (strstart(p, "xenfb", &opts)) {
+        xenfb_enabled = 1;
+    } else if (!strstart(p, "none", &opts)) {
+    invalid_vga:
+        fprintf(stderr, "Unknown vga type: %s\n", p);
+        exit(1);
+    }
+    while (*opts) {
+        const char *nextopt;
+
+        if (strstart(opts, ",retrace=", &nextopt)) {
+            opts = nextopt;
+            if (strstart(opts, "dumb", &nextopt))
+                vga_retrace_method = VGA_RETRACE_DUMB;
+            else if (strstart(opts, "precise", &nextopt))
+                vga_retrace_method = VGA_RETRACE_PRECISE;
+            else goto invalid_vga;
+        } else goto invalid_vga;
+        opts = nextopt;
+    }
+}
+
 #ifdef _WIN32
 static BOOL WINAPI qemu_ctrl_handler(DWORD type)
 {
@@ -8678,6 +4759,27 @@
 }
 #endif
 
+int qemu_uuid_parse(const char *str, uint8_t *uuid)
+{
+    int ret;
+
+    if(strlen(str) != 36)
+        return -1;
+
+    ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3],
+            &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9],
+            &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14], &uuid[15]);
+
+    if(ret != 16)
+        return -1;
+
+#ifdef TARGET_I386
+    smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid);
+#endif
+
+    return 0;
+}
+
 #define MAX_NET_CLIENTS 32
 
 #ifndef _WIN32
@@ -8687,7 +4789,12 @@
     qemu_system_shutdown_request();
 }
 
-static void termsig_setup(void)
+static void sigchld_handler(int signal)
+{
+    waitpid(-1, NULL, WNOHANG);
+}
+
+static void sighandler_setup(void)
 {
     struct sigaction act;
 
@@ -8696,44 +4803,186 @@
     sigaction(SIGINT,  &act, NULL);
     sigaction(SIGHUP,  &act, NULL);
     sigaction(SIGTERM, &act, NULL);
+
+    act.sa_handler = sigchld_handler;
+    act.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGCHLD, &act, NULL);
 }
 
 #endif
 
-int main(int argc, char **argv)
+#ifdef _WIN32
+/* Look for support files in the same directory as the executable.  */
+static char *find_datadir(const char *argv0)
 {
-#ifdef CONFIG_GDBSTUB
-    int use_gdbstub;
-    const char *gdbstub_port;
+    char *p;
+    char buf[MAX_PATH];
+    DWORD len;
+
+    len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
+    if (len == 0) {
+        return NULL;
+    }
+
+    buf[len] = 0;
+    p = buf + len - 1;
+    while (p != buf && *p != '\\')
+        p--;
+    *p = 0;
+    if (access(buf, R_OK) == 0) {
+        return qemu_strdup(buf);
+    }
+    return NULL;
+}
+#else /* !_WIN32 */
+
+/* Find a likely location for support files using the location of the binary.
+   For installed binaries this will be "$bindir/../share/qemu".  When
+   running from the build tree this will be "$bindir/../pc-bios".  */
+#define SHARE_SUFFIX "/share/qemu"
+#define BUILD_SUFFIX "/pc-bios"
+static char *find_datadir(const char *argv0)
+{
+    char *dir;
+    char *p = NULL;
+    char *res;
+#ifdef PATH_MAX
+    char buf[PATH_MAX];
 #endif
+    size_t max_len;
+
+#if defined(__linux__)
+    {
+        int len;
+        len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
+        if (len > 0) {
+            buf[len] = 0;
+            p = buf;
+        }
+    }
+#elif defined(__FreeBSD__)
+    {
+        int len;
+        len = readlink("/proc/curproc/file", buf, sizeof(buf) - 1);
+        if (len > 0) {
+            buf[len] = 0;
+            p = buf;
+        }
+    }
+#endif
+    /* If we don't have any way of figuring out the actual executable
+       location then try argv[0].  */
+    if (!p) {
+#ifdef PATH_MAX
+        p = buf;
+#endif
+        p = realpath(argv0, p);
+        if (!p) {
+            return NULL;
+        }
+    }
+    dir = dirname(p);
+    dir = dirname(dir);
+
+    max_len = strlen(dir) +
+        MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
+    res = qemu_mallocz(max_len);
+    snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
+    if (access(res, R_OK)) {
+        snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
+        if (access(res, R_OK)) {
+            qemu_free(res);
+            res = NULL;
+        }
+    }
+#ifndef PATH_MAX
+    free(p);
+#endif
+    return res;
+}
+#undef SHARE_SUFFIX
+#undef BUILD_SUFFIX
+#endif
+
+char *qemu_find_file(int type, const char *name)
+{
+    int len;
+    const char *subdir;
+    char *buf;
+
+    /* If name contains path separators then try it as a straight path.  */
+    if ((strchr(name, '/') || strchr(name, '\\'))
+        && access(name, R_OK) == 0) {
+        return strdup(name);
+    }
+    switch (type) {
+    case QEMU_FILE_TYPE_BIOS:
+        subdir = "";
+        break;
+    case QEMU_FILE_TYPE_KEYMAP:
+        subdir = "keymaps/";
+        break;
+    default:
+        abort();
+    }
+    len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2;
+    buf = qemu_mallocz(len);
+    snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
+    if (access(buf, R_OK)) {
+        qemu_free(buf);
+        return NULL;
+    }
+    return buf;
+}
+
+int main(int argc, char **argv, char **envp)
+{
+    const char *gdbstub_dev = NULL;
     uint32_t boot_devices_bitmap = 0;
     int i;
     int snapshot, linux_boot, net_boot;
     const char *initrd_filename;
     const char *kernel_filename, *kernel_cmdline;
     const char *boot_devices = "";
-    DisplayState *ds = &display_state;
+    DisplayState *ds;
+    DisplayChangeListener *dcl;
     int cyls, heads, secs, translation;
     const char *net_clients[MAX_NET_CLIENTS];
     int nb_net_clients;
+    const char *bt_opts[MAX_BT_CMDLINE];
+    int nb_bt_opts;
     int hda_index;
     int optind;
     const char *r, *optarg;
-    CharDriverState *monitor_hd;
+    CharDriverState *monitor_hd = NULL;
     const char *monitor_device;
     const char *serial_devices[MAX_SERIAL_PORTS];
     int serial_device_index;
     const char *parallel_devices[MAX_PARALLEL_PORTS];
     int parallel_device_index;
+    const char *virtio_consoles[MAX_VIRTIO_CONSOLES];
+    int virtio_console_index;
     const char *loadvm = NULL;
     QEMUMachine *machine;
     const char *cpu_model;
     const char *usb_devices[MAX_USB_CMDLINE];
     int usb_devices_index;
+#ifndef _WIN32
     int fds[2];
+#endif
     int tb_size;
     const char *pid_file = NULL;
-    VLANState *vlan;
+    const char *incoming = NULL;
+#ifndef _WIN32
+    int fd = 0;
+    struct passwd *pwd = NULL;
+    const char *chroot_dir = NULL;
+    const char *run_as = NULL;
+#endif
+    CPUState *env;
+    int show_vnc_port = 0;
+
+    qemu_cache_utils_init(envp);
 
     LIST_INIT (&vm_change_state_head);
 #ifndef _WIN32
@@ -8766,45 +5015,52 @@
     }
 #endif
 
-    register_machines();
-    machine = first_machine;
+    module_call_init(MODULE_INIT_MACHINE);
+    machine = find_default_machine();
     cpu_model = NULL;
     initrd_filename = NULL;
     ram_size = 0;
-    vga_ram_size = VGA_RAM_SIZE;
-#ifdef CONFIG_GDBSTUB
-    use_gdbstub = 0;
-    gdbstub_port = DEFAULT_GDBSTUB_PORT;
-#endif
     snapshot = 0;
-    nographic = 0;
-    curses = 0;
     kernel_filename = NULL;
     kernel_cmdline = "";
     cyls = heads = secs = 0;
     translation = BIOS_ATA_TRANSLATION_AUTO;
-    monitor_device = "vc";
+    monitor_device = "vc:80Cx24C";
 
     serial_devices[0] = "vc:80Cx24C";
     for(i = 1; i < MAX_SERIAL_PORTS; i++)
         serial_devices[i] = NULL;
     serial_device_index = 0;
 
-    parallel_devices[0] = "vc:640x480";
+    parallel_devices[0] = "vc:80Cx24C";
     for(i = 1; i < MAX_PARALLEL_PORTS; i++)
         parallel_devices[i] = NULL;
     parallel_device_index = 0;
 
+    for(i = 0; i < MAX_VIRTIO_CONSOLES; i++)
+        virtio_consoles[i] = NULL;
+    virtio_console_index = 0;
+
+    for (i = 0; i < MAX_NODES; i++) {
+        node_mem[i] = 0;
+        node_cpumask[i] = 0;
+    }
+
     usb_devices_index = 0;
 
     nb_net_clients = 0;
+    nb_bt_opts = 0;
     nb_drives = 0;
     nb_drives_opt = 0;
+    nb_numa_nodes = 0;
     hda_index = -1;
 
     nb_nics = 0;
 
     tb_size = 0;
+    autostart= 1;
+
+    register_watchdogs();
 
     optind = 1;
     for(;;) {
@@ -8851,7 +5107,7 @@
                     for(m = first_machine; m != NULL; m = m->next) {
                         printf("%-10s %s%s\n",
                                m->name, m->desc,
-                               m == first_machine ? " (default)" : "");
+                               m->is_default ? " (default)" : "");
                     }
                     exit(*optarg != '?');
                 }
@@ -8948,12 +5204,19 @@
 			             ",trans=none" : "");
                 }
                 break;
+            case QEMU_OPTION_numa:
+                if (nb_numa_nodes >= MAX_NODES) {
+                    fprintf(stderr, "qemu: too many NUMA nodes\n");
+                    exit(1);
+                }
+                numa_add(optarg);
+                break;
             case QEMU_OPTION_nographic:
-                nographic = 1;
+                display_type = DT_NOGRAPHIC;
                 break;
 #ifdef CONFIG_CURSES
             case QEMU_OPTION_curses:
-                curses = 1;
+                display_type = DT_CURSES;
                 break;
 #endif
             case QEMU_OPTION_portrait:
@@ -9023,15 +5286,22 @@
             case QEMU_OPTION_bootp:
                 bootp_filename = optarg;
                 break;
-#if 0  /* ANDROID disabled */
+#ifndef _WIN32
             case QEMU_OPTION_smb:
 		net_slirp_smb(optarg);
                 break;
 #endif
             case QEMU_OPTION_redir:
-                net_slirp_redir(optarg);
+                net_slirp_redir(NULL, optarg, NULL);
                 break;
 #endif
+            case QEMU_OPTION_bt:
+                if (nb_bt_opts >= MAX_BT_CMDLINE) {
+                    fprintf(stderr, "qemu: too many bluetooth options\n");
+                    exit(1);
+                }
+                bt_opts[nb_bt_opts++] = optarg;
+                break;
 #ifdef HAS_AUDIO
             case QEMU_OPTION_audio_help:
                 AUD_help ();
@@ -9042,7 +5312,11 @@
                 break;
 #endif
             case QEMU_OPTION_h:
-                qemu_help(0);
+                help(0);
+                break;
+            case QEMU_OPTION_version:
+                version();
+                exit(0);
                 break;
             case QEMU_OPTION_m: {
                 uint64_t value;
@@ -9063,7 +5337,7 @@
 
                 /* On 32-bit hosts, QEMU is limited by virtual address space */
                 if (value > (2047 << 20)
-#ifndef USE_KQEMU
+#ifndef CONFIG_KQEMU
                     && HOST_LONG_BITS == 32
 #endif
                     ) {
@@ -9080,7 +5354,7 @@
             case QEMU_OPTION_d:
                 {
                     int mask;
-                    CPULogItem *item;
+                    const CPULogItem *item;
 
                     mask = cpu_str_to_log_mask(optarg);
                     if (!mask) {
@@ -9093,43 +5367,36 @@
                     cpu_set_log(mask);
                 }
                 break;
-#ifdef CONFIG_GDBSTUB
             case QEMU_OPTION_s:
-                use_gdbstub = 1;
+                gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
                 break;
-            case QEMU_OPTION_p:
-                gdbstub_port = optarg;
+            case QEMU_OPTION_gdb:
+                gdbstub_dev = optarg;
                 break;
-#endif
             case QEMU_OPTION_L:
-                bios_dir = optarg;
+                data_dir = optarg;
+                break;
+            case QEMU_OPTION_bios:
+                bios_name = optarg;
+                break;
+            case QEMU_OPTION_singlestep:
+                singlestep = 1;
                 break;
             case QEMU_OPTION_S:
-#if 1  /* ANDROID */
-                fprintf(stderr, "Sorry, stopped launch is not supported in the Android emulator\n" );
-                exit(1);
-#else
                 autostart = 0;
                 break;
-#endif
+#ifndef _WIN32
 	    case QEMU_OPTION_k:
 		keyboard_layout = optarg;
 		break;
+#endif
             case QEMU_OPTION_localtime:
                 rtc_utc = 0;
                 break;
-            case QEMU_OPTION_cirrusvga:
-                cirrus_vga_enabled = 1;
-                vmsvga_enabled = 0;
+            case QEMU_OPTION_vga:
+                select_vgahw (optarg);
                 break;
-            case QEMU_OPTION_vmsvga:
-                cirrus_vga_enabled = 0;
-                vmsvga_enabled = 1;
-                break;
-            case QEMU_OPTION_std_vga:
-                cirrus_vga_enabled = 0;
-                vmsvga_enabled = 0;
-                break;
+#if defined(TARGET_PPC) || defined(TARGET_SPARC)
             case QEMU_OPTION_g:
                 {
                     const char *p;
@@ -9164,6 +5431,7 @@
                     graphic_depth = depth;
                 }
                 break;
+#endif
             case QEMU_OPTION_echr:
                 {
                     char *r;
@@ -9183,6 +5451,25 @@
                 serial_devices[serial_device_index] = optarg;
                 serial_device_index++;
                 break;
+            case QEMU_OPTION_watchdog:
+                i = select_watchdog(optarg);
+                if (i > 0)
+                    exit (i == 1 ? 1 : 0);
+                break;
+            case QEMU_OPTION_watchdog_action:
+                if (select_watchdog_action(optarg) == -1) {
+                    fprintf(stderr, "Unknown -watchdog-action parameter\n");
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_virtiocon:
+                if (virtio_console_index >= MAX_VIRTIO_CONSOLES) {
+                    fprintf(stderr, "qemu: too many virtio consoles\n");
+                    exit(1);
+                }
+                virtio_consoles[virtio_console_index] = optarg;
+                virtio_console_index++;
+                break;
             case QEMU_OPTION_parallel:
                 if (parallel_device_index >= MAX_PARALLEL_PORTS) {
                     fprintf(stderr, "qemu: too many parallel ports\n");
@@ -9207,6 +5494,9 @@
             case QEMU_OPTION_no_quit:
                 no_quit = 1;
                 break;
+            case QEMU_OPTION_sdl:
+                display_type = DT_SDL;
+                break;
 #endif
             case QEMU_OPTION_pidfile:
                 pid_file = optarg;
@@ -9215,8 +5505,23 @@
             case QEMU_OPTION_win2k_hack:
                 win2k_install_hack = 1;
                 break;
+            case QEMU_OPTION_rtc_td_hack:
+                rtc_td_hack = 1;
+                break;
+            case QEMU_OPTION_acpitable:
+                if(acpi_table_add(optarg) < 0) {
+                    fprintf(stderr, "Wrong acpi table provided\n");
+                    exit(1);
+                }
+                break;
+            case QEMU_OPTION_smbios:
+                if(smbios_entry_add(optarg) < 0) {
+                    fprintf(stderr, "Wrong smbios provided\n");
+                    exit(1);
+                }
+                break;
 #endif
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
             case QEMU_OPTION_no_kqemu:
                 kqemu_allowed = 0;
                 break;
@@ -9224,6 +5529,14 @@
                 kqemu_allowed = 2;
                 break;
 #endif
+#ifdef CONFIG_KVM
+            case QEMU_OPTION_enable_kvm:
+                kvm_allowed = 1;
+#ifdef CONFIG_KQEMU
+                kqemu_allowed = 0;
+#endif
+                break;
+#endif
             case QEMU_OPTION_usb:
                 usb_enabled = 1;
                 break;
@@ -9238,17 +5551,26 @@
                 break;
             case QEMU_OPTION_smp:
                 smp_cpus = atoi(optarg);
-                if (smp_cpus < 1 || smp_cpus > MAX_CPUS) {
+                if (smp_cpus < 1) {
                     fprintf(stderr, "Invalid number of CPUs\n");
                     exit(1);
                 }
                 break;
 	    case QEMU_OPTION_vnc:
+                display_type = DT_VNC;
 		vnc_display = optarg;
 		break;
+#ifdef TARGET_I386
             case QEMU_OPTION_no_acpi:
                 acpi_enabled = 0;
                 break;
+            case QEMU_OPTION_no_hpet:
+                no_hpet = 1;
+                break;
+            case QEMU_OPTION_no_virtio_balloon:
+                no_virtio_balloon = 1;
+                break;
+#endif
             case QEMU_OPTION_no_reboot:
                 no_reboot = 1;
                 break;
@@ -9258,9 +5580,18 @@
             case QEMU_OPTION_show_cursor:
                 cursor_hide = 0;
                 break;
+            case QEMU_OPTION_uuid:
+                if(qemu_uuid_parse(optarg, qemu_uuid) < 0) {
+                    fprintf(stderr, "Fail to parse UUID string."
+                            " Wrong format.\n");
+                    exit(1);
+                }
+                break;
+#ifndef _WIN32
 	    case QEMU_OPTION_daemonize:
 		daemonize = 1;
 		break;
+#endif
 	    case QEMU_OPTION_option_rom:
 		if (nb_option_roms >= MAX_OPTION_ROMS) {
 		    fprintf(stderr, "Too many option ROMs\n");
@@ -9269,13 +5600,15 @@
 		option_rom[nb_option_roms] = optarg;
 		nb_option_roms++;
 		break;
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
             case QEMU_OPTION_semihosting:
                 semihosting_enabled = 1;
                 break;
+#endif
             case QEMU_OPTION_name:
                 qemu_name = optarg;
                 break;
-#ifdef TARGET_SPARC
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
             case QEMU_OPTION_prom_env:
                 if (nb_prom_envs >= MAX_PROM_ENVS) {
                     fprintf(stderr, "Too many prom variables\n");
@@ -9344,49 +5677,59 @@
                     icount_time_shift = strtol(optarg, NULL, 0);
                 }
                 break;
-
-            case QEMU_OPTION_mic:
-                audio_input_source = (char*)optarg;
+            case QEMU_OPTION_incoming:
+                incoming = optarg;
                 break;
-#ifdef CONFIG_TRACE
-            case QEMU_OPTION_trace_file:
-                trace_filename = optarg;
-                tracing = 1;
+#ifndef _WIN32
+            case QEMU_OPTION_chroot:
+                chroot_dir = optarg;
                 break;
-            case QEMU_OPTION_trace_miss:
-                trace_cache_miss = 1;
-                break;
-            case QEMU_OPTION_trace_addr:
-                trace_all_addr = 1;
-                break;
-            case QEMU_OPTION_tracing:
-                if (strcmp(optarg, "off") == 0)
-                    tracing = 0;
-                else if (strcmp(optarg, "on") == 0 && trace_filename)
-                    tracing = 1;
-                else {
-                    fprintf(stderr, "Unexpected option to -tracing ('%s')\n",
-                            optarg);
-                    exit(1);
-                }
-                break;
-            case QEMU_OPTION_dcache_load_miss:
-                dcache_load_miss_penalty = atoi(optarg);
-                break;
-            case QEMU_OPTION_dcache_store_miss:
-                dcache_store_miss_penalty = atoi(optarg);
+            case QEMU_OPTION_runas:
+                run_as = optarg;
                 break;
 #endif
-#ifdef CONFIG_NAND
-            case QEMU_OPTION_nand:
-                nand_add_dev(optarg);
+#ifdef CONFIG_XEN
+            case QEMU_OPTION_xen_domid:
+                xen_domid = atoi(optarg);
+                break;
+            case QEMU_OPTION_xen_create:
+                xen_mode = XEN_CREATE;
+                break;
+            case QEMU_OPTION_xen_attach:
+                xen_mode = XEN_ATTACH;
                 break;
 #endif
             }
         }
     }
 
-    if (nographic) {
+    /* If no data_dir is specified then try to find it relative to the
+       executable path.  */
+    if (!data_dir) {
+        data_dir = find_datadir(argv[0]);
+    }
+    /* If all else fails use the install patch specified when building.  */
+    if (!data_dir) {
+        data_dir = CONFIG_QEMU_SHAREDIR;
+    }
+
+#if defined(CONFIG_KVM) && defined(CONFIG_KQEMU)
+    if (kvm_allowed && kqemu_allowed) {
+        fprintf(stderr,
+                "You can not enable both KVM and kqemu at the same time\n");
+        exit(1);
+    }
+#endif
+
+    machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
+    if (smp_cpus > machine->max_cpus) {
+        fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus "
+                "supported by machine `%s' (%d)\n", smp_cpus,  machine->name,
+                machine->max_cpus);
+        exit(1);
+    }
+
+    if (display_type == DT_NOGRAPHIC) {
        if (serial_device_index == 0)
            serial_devices[0] = "stdio";
        if (parallel_device_index == 0)
@@ -9438,7 +5781,6 @@
         signal(SIGTTOU, SIG_IGN);
         signal(SIGTTIN, SIG_IGN);
     }
-#endif
 
     if (pid_file && qemu_create_pidfile(pid_file) != 0) {
         if (daemonize) {
@@ -9448,18 +5790,19 @@
             fprintf(stderr, "Could not acquire pid file\n");
         exit(1);
     }
+#endif
 
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
     if (smp_cpus > 1)
         kqemu_allowed = 0;
 #endif
+    if (qemu_init_main_loop()) {
+        fprintf(stderr, "qemu_init_main_loop failed\n");
+        exit(1);
+    }
     linux_boot = (kernel_filename != NULL);
     net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
 
-    if (!linux_boot && net_boot == 0 &&
-        !machine->nodisk_ok && nb_drives_opt == 0)
-        qemu_help(1);
-
     if (!linux_boot && *kernel_cmdline != '\0') {
         fprintf(stderr, "-append only allowed with -kernel option\n");
         exit(1);
@@ -9477,8 +5820,10 @@
     setvbuf(stdout, NULL, _IOLBF, 0);
 
     init_timers();
-    init_timer_alarm();
-    qemu_aio_init();
+    if (init_timer_alarm() < 0) {
+        fprintf(stderr, "could not initialize alarm timer\n");
+        exit(1);
+    }
     if (use_icount && icount_time_shift < 0) {
         use_icount = 2;
         /* 125MIPS seems a reasonable initial guess at the guest speed.
@@ -9504,16 +5849,7 @@
         if (net_client_parse(net_clients[i]) < 0)
             exit(1);
     }
-    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
-        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
-            continue;
-        if (vlan->nb_guest_devs == 0)
-            fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
-        if (vlan->nb_host_devs == 0)
-            fprintf(stderr,
-                    "Warning: vlan %d is not connected to host network\n",
-                    vlan->id);
-    }
+    net_client_check();
 
 #ifdef TARGET_I386
     /* XXX: this should be moved in the PC machine instantiation code */
@@ -9522,19 +5858,24 @@
 	for (i = 0; i < nb_nics && i < 4; i++) {
 	    const char *model = nd_table[i].model;
 	    char buf[1024];
+            char *filename;
             if (net_boot & (1 << i)) {
                 if (model == NULL)
                     model = "ne2k_pci";
-                snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model);
-                if (get_image_size(buf) > 0) {
+                snprintf(buf, sizeof(buf), "pxe-%s.bin", model);
+                filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, buf);
+                if (filename && get_image_size(filename) > 0) {
                     if (nb_option_roms >= MAX_OPTION_ROMS) {
                         fprintf(stderr, "Too many option ROMs\n");
                         exit(1);
                     }
-                    option_rom[nb_option_roms] = strdup(buf);
+                    option_rom[nb_option_roms] = qemu_strdup(buf);
                     nb_option_roms++;
                     netroms++;
                 }
+                if (filename) {
+                    qemu_free(filename);
+                }
             }
 	}
 	if (netroms == 0) {
@@ -9544,32 +5885,27 @@
     }
 #endif
 
+    /* init the bluetooth world */
+    for (i = 0; i < nb_bt_opts; i++)
+        if (bt_parse(bt_opts[i]))
+            exit(1);
+
     /* init the memory */
-    phys_ram_size = machine->ram_require & ~RAMSIZE_FIXED;
+    if (ram_size == 0)
+        ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
 
-    if (machine->ram_require & RAMSIZE_FIXED) {
-        if (ram_size > 0) {
-            if (ram_size < phys_ram_size) {
-                fprintf(stderr, "Machine `%s' requires %llu bytes of memory\n",
-                                machine->name, (unsigned long long) phys_ram_size);
-                exit(-1);
-            }
-
-            phys_ram_size = ram_size;
-        } else
-            ram_size = phys_ram_size;
-    } else {
-        if (ram_size == 0)
-            ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
-
-        phys_ram_size += ram_size;
+#ifdef CONFIG_KQEMU
+    /* FIXME: This is a nasty hack because kqemu can't cope with dynamic
+       guest ram allocation.  It needs to go away.  */
+    if (kqemu_allowed) {
+        kqemu_phys_ram_size = ram_size + 8 * 1024 * 1024 + 4 * 1024 * 1024;
+        kqemu_phys_ram_base = qemu_vmalloc(kqemu_phys_ram_size);
+        if (!kqemu_phys_ram_base) {
+            fprintf(stderr, "Could not allocate physical memory\n");
+            exit(1);
+        }
     }
-
-    phys_ram_base = qemu_vmalloc(phys_ram_size);
-    if (!phys_ram_base) {
-        fprintf(stderr, "Could not allocate physical memory\n");
-        exit(1);
-    }
+#endif
 
     /* init the dynamic translator */
     cpu_exec_init_all(tb_size * 1024 * 1024);
@@ -9598,40 +5934,11 @@
 	    exit(1);
 
     register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
-    register_savevm("ram", 0, 2, ram_save, ram_load, NULL);
-
-    /* terminal init */
-    memset(&display_state, 0, sizeof(display_state));
-    if (nographic) {
-        if (curses) {
-            fprintf(stderr, "fatal: -nographic can't be used with -curses\n");
-            exit(1);
-        }
-        /* nearly nothing to do */
-        dumb_display_init(ds);
-    } else if (vnc_display != NULL) {
-        vnc_display_init(ds);
-        if (vnc_display_open(ds, vnc_display) < 0)
-            exit(1);
-    } else
-#if defined(CONFIG_CURSES)
-    if (curses) {
-        curses_display_init(ds, full_screen);
-    } else
-#endif
-    {
-#if defined(CONFIG_SDL)
-        sdl_display_init(ds, full_screen, no_frame);
-#elif defined(CONFIG_COCOA)
-        cocoa_display_init(ds, full_screen);
-#else
-        dumb_display_init(ds);
-#endif
-    }
+    register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL);
 
 #ifndef _WIN32
     /* must be after terminal init, SDL library changes signal handlers */
-    termsig_setup();
+    sighandler_setup();
 #endif
 
     /* Maintain compatibility with multiple stdio monitors */
@@ -9648,24 +5955,216 @@
             }
         }
     }
+
+    if (nb_numa_nodes > 0) {
+        int i;
+
+        if (nb_numa_nodes > smp_cpus) {
+            nb_numa_nodes = smp_cpus;
+        }
+
+        /* If no memory size if given for any node, assume the default case
+         * and distribute the available memory equally across all nodes
+         */
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_mem[i] != 0)
+                break;
+        }
+        if (i == nb_numa_nodes) {
+            uint64_t usedmem = 0;
+
+            /* On Linux, the each node's border has to be 8MB aligned,
+             * the final node gets the rest.
+             */
+            for (i = 0; i < nb_numa_nodes - 1; i++) {
+                node_mem[i] = (ram_size / nb_numa_nodes) & ~((1 << 23UL) - 1);
+                usedmem += node_mem[i];
+            }
+            node_mem[i] = ram_size - usedmem;
+        }
+
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_cpumask[i] != 0)
+                break;
+        }
+        /* assigning the VCPUs round-robin is easier to implement, guest OSes
+         * must cope with this anyway, because there are BIOSes out there in
+         * real machines which also use this scheme.
+         */
+        if (i == nb_numa_nodes) {
+            for (i = 0; i < smp_cpus; i++) {
+                node_cpumask[i % nb_numa_nodes] |= 1 << i;
+            }
+        }
+    }
+
+    if (kvm_enabled()) {
+        int ret;
+
+        ret = kvm_init(smp_cpus);
+        if (ret < 0) {
+            fprintf(stderr, "failed to initialize KVM\n");
+            exit(1);
+        }
+    }
+
     if (monitor_device) {
-        monitor_hd = qemu_chr_open(monitor_device);
+        monitor_hd = qemu_chr_open("monitor", monitor_device, NULL);
         if (!monitor_hd) {
             fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
             exit(1);
         }
-        monitor_init(monitor_hd, !nographic);
     }
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         const char *devname = serial_devices[i];
         if (devname && strcmp(devname, "none")) {
-            serial_hds[i] = qemu_chr_open(devname);
+            char label[32];
+            snprintf(label, sizeof(label), "serial%d", i);
+            serial_hds[i] = qemu_chr_open(label, devname, NULL);
             if (!serial_hds[i]) {
                 fprintf(stderr, "qemu: could not open serial device '%s'\n",
                         devname);
                 exit(1);
             }
+        }
+    }
+
+    for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+        const char *devname = parallel_devices[i];
+        if (devname && strcmp(devname, "none")) {
+            char label[32];
+            snprintf(label, sizeof(label), "parallel%d", i);
+            parallel_hds[i] = qemu_chr_open(label, devname, NULL);
+            if (!parallel_hds[i]) {
+                fprintf(stderr, "qemu: could not open parallel device '%s'\n",
+                        devname);
+                exit(1);
+            }
+        }
+    }
+
+    for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+        const char *devname = virtio_consoles[i];
+        if (devname && strcmp(devname, "none")) {
+            char label[32];
+            snprintf(label, sizeof(label), "virtcon%d", i);
+            virtcon_hds[i] = qemu_chr_open(label, devname, NULL);
+            if (!virtcon_hds[i]) {
+                fprintf(stderr, "qemu: could not open virtio console '%s'\n",
+                        devname);
+                exit(1);
+            }
+        }
+    }
+
+    module_call_init(MODULE_INIT_DEVICE);
+
+    machine->init(ram_size, boot_devices,
+                  kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
+
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        for (i = 0; i < nb_numa_nodes; i++) {
+            if (node_cpumask[i] & (1 << env->cpu_index)) {
+                env->numa_node = i;
+            }
+        }
+    }
+
+    current_machine = machine;
+
+    /* Set KVM's vcpu state to qemu's initial CPUState. */
+    if (kvm_enabled()) {
+        int ret;
+
+        ret = kvm_sync_vcpus();
+        if (ret < 0) {
+            fprintf(stderr, "failed to initialize vcpus\n");
+            exit(1);
+        }
+    }
+
+    /* init USB devices */
+    if (usb_enabled) {
+        for(i = 0; i < usb_devices_index; i++) {
+            if (usb_device_add(usb_devices[i], 0) < 0) {
+                fprintf(stderr, "Warning: could not add USB device %s\n",
+                        usb_devices[i]);
+            }
+        }
+    }
+
+    if (!display_state)
+        dumb_display_init();
+    /* just use the first displaystate for the moment */
+    ds = display_state;
+
+    if (display_type == DT_DEFAULT) {
+#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+        display_type = DT_SDL;
+#else
+        display_type = DT_VNC;
+        vnc_display = "localhost:0,to=99";
+        show_vnc_port = 1;
+#endif
+    }
+        
+
+    switch (display_type) {
+    case DT_NOGRAPHIC:
+        break;
+#if defined(CONFIG_CURSES)
+    case DT_CURSES:
+        curses_display_init(ds, full_screen);
+        break;
+#endif
+#if defined(CONFIG_SDL)
+    case DT_SDL:
+        sdl_display_init(ds, full_screen, no_frame);
+        break;
+#elif defined(CONFIG_COCOA)
+    case DT_SDL:
+        cocoa_display_init(ds, full_screen);
+        break;
+#endif
+    case DT_VNC:
+        vnc_display_init(ds);
+        if (vnc_display_open(ds, vnc_display) < 0)
+            exit(1);
+
+        if (show_vnc_port) {
+            printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
+        }
+        break;
+    default:
+        break;
+    }
+    dpy_resize(ds);
+
+    dcl = ds->listeners;
+    while (dcl != NULL) {
+        if (dcl->dpy_refresh != NULL) {
+            ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
+            qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
+        }
+        dcl = dcl->next;
+    }
+
+    if (display_type == DT_NOGRAPHIC || display_type == DT_VNC) {
+        nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL);
+        qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
+    }
+
+    text_consoles_set_display(display_state);
+    qemu_chr_initial_reset();
+
+    if (monitor_device && monitor_hd)
+        monitor_init(monitor_hd, MONITOR_USE_READLINE | MONITOR_IS_DEFAULT);
+
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        const char *devname = serial_devices[i];
+        if (devname && strcmp(devname, "none")) {
             if (strstart(devname, "vc", 0))
                 qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i);
         }
@@ -9674,79 +6173,40 @@
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
         const char *devname = parallel_devices[i];
         if (devname && strcmp(devname, "none")) {
-            parallel_hds[i] = qemu_chr_open(devname);
-            if (!parallel_hds[i]) {
-                fprintf(stderr, "qemu: could not open parallel device '%s'\n",
-                        devname);
-                exit(1);
-            }
             if (strstart(devname, "vc", 0))
                 qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i);
         }
     }
 
-#ifdef CONFIG_TRACE
-    if (trace_filename) {
-        trace_init(trace_filename);
-#if 0
-        // We don't need the dcache code until we can get load and store tracing
-        // working again.
-        dcache_init(dcache_size, dcache_ways, dcache_line_size,
-                    dcache_replace_policy, dcache_load_miss_penalty,
-                    dcache_store_miss_penalty);
-#endif
-        fprintf(stderr, "-- When done tracing, exit the emulator. --\n");
-    }
-#endif
-
-    machine->init(ram_size, vga_ram_size, boot_devices, ds,
-                  kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
-
-    /* init USB devices */
-    if (usb_enabled) {
-        for(i = 0; i < usb_devices_index; i++) {
-            if (usb_device_add(usb_devices[i]) < 0) {
-                fprintf(stderr, "Warning: could not add USB device %s\n",
-                        usb_devices[i]);
-            }
+    for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+        const char *devname = virtio_consoles[i];
+        if (virtcon_hds[i] && devname) {
+            if (strstart(devname, "vc", 0))
+                qemu_chr_printf(virtcon_hds[i], "virtio console%d\r\n", i);
         }
     }
 
-    if (display_state.dpy_refresh) {
-        display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state);
-        qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock));
+    if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
+        fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
+                gdbstub_dev);
+        exit(1);
     }
 
-#ifdef CONFIG_GDBSTUB
-    if (use_gdbstub) {
-        /* XXX: use standard host:port notation and modify options
-           accordingly. */
-        if (gdbserver_start(gdbstub_port) < 0) {
-            fprintf(stderr, "qemu: could not open gdbstub device on port '%s'\n",
-                    gdbstub_port);
-            exit(1);
-        }
-    }
-#endif
-
     if (loadvm)
-        do_loadvm(loadvm);
+        do_loadvm(cur_mon, loadvm);
 
-    /* call android-specific setup function */
-    android_emulation_setup();
-
-    {
-        /* XXX: simplify init */
-        read_passwords();
-        if (autostart) {
-            vm_start();
-        }
+    if (incoming) {
+        autostart = 0; /* fixme how to deal with -daemonize */
+        qemu_start_incoming_migration(incoming);
     }
 
+    if (autostart)
+        vm_start();
+
+#ifndef _WIN32
     if (daemonize) {
 	uint8_t status = 0;
 	ssize_t len;
-	int fd;
 
     again1:
 	len = write(fds[1], &status, 1);
@@ -9760,41 +6220,51 @@
 	TFR(fd = open("/dev/null", O_RDWR));
 	if (fd == -1)
 	    exit(1);
-
-	dup2(fd, 0);
-	dup2(fd, 1);
-	dup2(fd, 2);
-
-	close(fd);
     }
 
+    if (run_as) {
+        pwd = getpwnam(run_as);
+        if (!pwd) {
+            fprintf(stderr, "User \"%s\" doesn't exist\n", run_as);
+            exit(1);
+        }
+    }
+
+    if (chroot_dir) {
+        if (chroot(chroot_dir) < 0) {
+            fprintf(stderr, "chroot failed\n");
+            exit(1);
+        }
+        chdir("/");
+    }
+
+    if (run_as) {
+        if (setgid(pwd->pw_gid) < 0) {
+            fprintf(stderr, "Failed to setgid(%d)\n", pwd->pw_gid);
+            exit(1);
+        }
+        if (setuid(pwd->pw_uid) < 0) {
+            fprintf(stderr, "Failed to setuid(%d)\n", pwd->pw_uid);
+            exit(1);
+        }
+        if (setuid(0) != -1) {
+            fprintf(stderr, "Dropping privileges failed\n");
+            exit(1);
+        }
+    }
+
+    if (daemonize) {
+        dup2(fd, 0);
+        dup2(fd, 1);
+        dup2(fd, 2);
+
+        close(fd);
+    }
+#endif
+
     main_loop();
     quit_timers();
+    net_cleanup();
 
-#if !defined(_WIN32)
-    /* close network clients */
-    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
-        VLANClientState *vc;
-
-        for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
-            if (vc->fd_read == tap_receive) {
-                char ifname[64];
-                TAPState *s = vc->opaque;
-
-                if (sscanf(vc->info_str, "tap: ifname=%63s ", ifname) == 1 &&
-                    s->down_script[0])
-                    launch_script(s->down_script, ifname, s->fd);
-            }
-#if defined(CONFIG_VDE)
-            if (vc->fd_read == vde_from_qemu) {
-                VDEState *s = vc->opaque;
-                vde_close(s->vde);
-            }
-#endif
-        }
-    }
-#endif
-
-    android_emulation_teardown();
     return 0;
 }
diff --git a/vnc-android.c b/vnc-android.c
new file mode 100644
index 0000000..2d5063d
--- /dev/null
+++ b/vnc-android.c
@@ -0,0 +1,2402 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc.h"
+#include "sysemu.h"
+#include "qemu_socket.h"
+#include "qemu-timer.h"
+#include "acl.h"
+
+#define VNC_REFRESH_INTERVAL (1000 / 30)
+
+#include "vnc_keysym.h"
+#include "d3des.h"
+
+#define count_bits(c, v) { \
+    for (c = 0; v; v >>= 1) \
+    { \
+        c += v & 1; \
+    } \
+}
+
+
+static VncDisplay *vnc_display; /* needed for info vnc */
+static DisplayChangeListener *dcl;
+
+static char *addr_to_string(const char *format, SockAddress*  sa)
+{
+    char *addr;
+    char host[256];
+    char serv[32];
+    int err;
+    size_t addrlen;
+
+#if 1 /* ANDROID */
+    err = sock_address_get_numeric_info (sa, host, sizeof(host),
+                                         serv, sizeof(serv));
+    if (err != 0) {
+        VNC_DEBUG("Cannot resolve address '%s': %s\n",
+                  sock_address_to_string(sa), errno_str);
+        return NULL;
+    }
+#else
+    if ((err = getnameinfo((struct sockaddr *)sa, salen,
+                           host, sizeof(host),
+                           serv, sizeof(serv),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+        VNC_DEBUG("Cannot resolve address %d: %s\n",
+                  err, gai_strerror(err));
+        return NULL;
+    }
+#endif
+
+    /* Enough for the existing format + the 2 vars we're
+     * substituting in. */
+    addrlen = strlen(format) + strlen(host) + strlen(serv);
+    addr = qemu_malloc(addrlen + 1);
+    snprintf(addr, addrlen, format, host, serv);
+    addr[addrlen] = '\0';
+
+    return addr;
+}
+
+
+char *vnc_socket_local_addr(const char *format, int fd) {
+    SockAddress  sa;
+
+    if (socket_get_address(fd, &sa) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa);
+}
+
+
+char *vnc_socket_remote_addr(const char *format, int fd) {
+    SockAddress  sa;
+
+    if (socket_get_peer_address(fd, &sa) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa);
+}
+
+static const char *vnc_auth_name(VncDisplay *vd) {
+    switch (vd->auth) {
+    case VNC_AUTH_INVALID:
+        return "invalid";
+    case VNC_AUTH_NONE:
+        return "none";
+    case VNC_AUTH_VNC:
+        return "vnc";
+    case VNC_AUTH_RA2:
+        return "ra2";
+    case VNC_AUTH_RA2NE:
+        return "ra2ne";
+    case VNC_AUTH_TIGHT:
+        return "tight";
+    case VNC_AUTH_ULTRA:
+        return "ultra";
+    case VNC_AUTH_TLS:
+        return "tls";
+    case VNC_AUTH_VENCRYPT:
+#ifdef CONFIG_VNC_TLS
+        switch (vd->subauth) {
+        case VNC_AUTH_VENCRYPT_PLAIN:
+            return "vencrypt+plain";
+        case VNC_AUTH_VENCRYPT_TLSNONE:
+            return "vencrypt+tls+none";
+        case VNC_AUTH_VENCRYPT_TLSVNC:
+            return "vencrypt+tls+vnc";
+        case VNC_AUTH_VENCRYPT_TLSPLAIN:
+            return "vencrypt+tls+plain";
+        case VNC_AUTH_VENCRYPT_X509NONE:
+            return "vencrypt+x509+none";
+        case VNC_AUTH_VENCRYPT_X509VNC:
+            return "vencrypt+x509+vnc";
+        case VNC_AUTH_VENCRYPT_X509PLAIN:
+            return "vencrypt+x509+plain";
+        case VNC_AUTH_VENCRYPT_TLSSASL:
+            return "vencrypt+tls+sasl";
+        case VNC_AUTH_VENCRYPT_X509SASL:
+            return "vencrypt+x509+sasl";
+        default:
+            return "vencrypt";
+        }
+#else
+        return "vencrypt";
+#endif
+    case VNC_AUTH_SASL:
+        return "sasl";
+    }
+    return "unknown";
+}
+
+static void do_info_vnc_client(Monitor *mon, VncState *client)
+{
+    char *clientAddr =
+        vnc_socket_remote_addr("     address: %s:%s\n",
+                               client->csock);
+    if (!clientAddr)
+        return;
+
+    monitor_printf(mon, "Client:\n");
+    monitor_printf(mon, "%s", clientAddr);
+    free(clientAddr);
+
+#ifdef CONFIG_VNC_TLS
+    if (client->tls.session &&
+        client->tls.dname)
+        monitor_printf(mon, "  x509 dname: %s\n", client->tls.dname);
+    else
+        monitor_printf(mon, "  x509 dname: none\n");
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (client->sasl.conn &&
+        client->sasl.username)
+        monitor_printf(mon, "    username: %s\n", client->sasl.username);
+    else
+        monitor_printf(mon, "    username: none\n");
+#endif
+}
+
+void do_info_vnc(Monitor *mon)
+{
+    if (vnc_display == NULL || vnc_display->display == NULL) {
+        monitor_printf(mon, "Server: disabled\n");
+    } else {
+        char *serverAddr = vnc_socket_local_addr("     address: %s:%s\n",
+                                                 vnc_display->lsock);
+
+        if (!serverAddr)
+            return;
+
+        monitor_printf(mon, "Server:\n");
+        monitor_printf(mon, "%s", serverAddr);
+        free(serverAddr);
+        monitor_printf(mon, "        auth: %s\n", vnc_auth_name(vnc_display));
+
+        if (vnc_display->clients) {
+            VncState *client = vnc_display->clients;
+            while (client) {
+                do_info_vnc_client(mon, client);
+                client = client->next;
+            }
+        } else {
+            monitor_printf(mon, "Client: none\n");
+        }
+    }
+}
+
+static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
+    return (vs->features & (1 << feature));
+}
+
+/* TODO
+   1) Get the queue working for IO.
+   2) there is some weirdness when using the -S option (the screen is grey
+      and not totally invalidated
+   3) resolutions > 1024
+*/
+
+static void vnc_update_client(void *opaque);
+static void vnc_disconnect_start(VncState *vs);
+static void vnc_disconnect_finish(VncState *vs);
+
+static void vnc_colordepth(VncState *vs);
+
+static inline void vnc_set_bit(uint32_t *d, int k)
+{
+    d[k >> 5] |= 1 << (k & 0x1f);
+}
+
+static inline void vnc_clear_bit(uint32_t *d, int k)
+{
+    d[k >> 5] &= ~(1 << (k & 0x1f));
+}
+
+static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
+{
+    int j;
+
+    j = 0;
+    while (n >= 32) {
+        d[j++] = -1;
+        n -= 32;
+    }
+    if (n > 0)
+        d[j++] = (1 << n) - 1;
+    while (j < nb_words)
+        d[j++] = 0;
+}
+
+static inline int vnc_get_bit(const uint32_t *d, int k)
+{
+    return (d[k >> 5] >> (k & 0x1f)) & 1;
+}
+
+static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
+                               int nb_words)
+{
+    int i;
+    for(i = 0; i < nb_words; i++) {
+        if ((d1[i] & d2[i]) != 0)
+            return 1;
+    }
+    return 0;
+}
+
+static void vnc_update(VncState *vs, int x, int y, int w, int h)
+{
+    struct VncSurface *s = &vs->guest;
+    int i;
+
+    h += y;
+
+    /* round x down to ensure the loop only spans one 16-pixel block per,
+       iteration.  otherwise, if (x % 16) != 0, the last iteration may span
+       two 16-pixel blocks but we only mark the first as dirty
+    */
+    w += (x % 16);
+    x -= (x % 16);
+
+    x = MIN(x, s->ds->width);
+    y = MIN(y, s->ds->height);
+    w = MIN(x + w, s->ds->width) - x;
+    h = MIN(h, s->ds->height);
+
+    for (; y < h; y++)
+        for (i = 0; i < w; i += 16)
+            vnc_set_bit(s->dirty[y], (x + i) / 16);
+}
+
+static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs = vd->clients;
+    while (vs != NULL) {
+        vnc_update(vs, x, y, w, h);
+        vs = vs->next;
+    }
+}
+
+static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
+                                   int32_t encoding)
+{
+    vnc_write_u16(vs, x);
+    vnc_write_u16(vs, y);
+    vnc_write_u16(vs, w);
+    vnc_write_u16(vs, h);
+
+    vnc_write_s32(vs, encoding);
+}
+
+void buffer_reserve(Buffer *buffer, size_t len)
+{
+    if ((buffer->capacity - buffer->offset) < len) {
+        buffer->capacity += (len + 1024);
+        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
+        if (buffer->buffer == NULL) {
+            fprintf(stderr, "vnc: out of memory\n");
+            exit(1);
+        }
+    }
+}
+
+int buffer_empty(Buffer *buffer)
+{
+    return buffer->offset == 0;
+}
+
+uint8_t *buffer_end(Buffer *buffer)
+{
+    return buffer->buffer + buffer->offset;
+}
+
+void buffer_reset(Buffer *buffer)
+{
+        buffer->offset = 0;
+}
+
+void buffer_append(Buffer *buffer, const void *data, size_t len)
+{
+    memcpy(buffer->buffer + buffer->offset, data, len);
+    buffer->offset += len;
+}
+
+static void vnc_resize(VncState *vs)
+{
+    DisplayState *ds = vs->ds;
+    int size_changed;
+
+    /* guest surface */
+    if (!vs->guest.ds)
+        vs->guest.ds = qemu_mallocz(sizeof(*vs->guest.ds));
+    if (ds_get_bytes_per_pixel(ds) != vs->guest.ds->pf.bytes_per_pixel)
+        console_color_init(ds);
+    vnc_colordepth(vs);
+    size_changed = ds_get_width(ds) != vs->guest.ds->width ||
+                   ds_get_height(ds) != vs->guest.ds->height;
+    *(vs->guest.ds) = *(ds->surface);
+    if (size_changed) {
+        if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
+            vnc_write_u8(vs, 0);  /* msg id */
+            vnc_write_u8(vs, 0);
+            vnc_write_u16(vs, 1); /* number of rects */
+            vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
+                                   VNC_ENCODING_DESKTOPRESIZE);
+            vnc_flush(vs);
+        }
+    }
+    memset(vs->guest.dirty, 0xFF, sizeof(vs->guest.dirty));
+
+    /* server surface */
+    if (!vs->server.ds)
+        vs->server.ds = qemu_mallocz(sizeof(*vs->server.ds));
+    if (vs->server.ds->data)
+        qemu_free(vs->server.ds->data);
+    *(vs->server.ds) = *(ds->surface);
+    vs->server.ds->data = qemu_mallocz(vs->server.ds->linesize *
+                                       vs->server.ds->height);
+    memset(vs->server.dirty, 0xFF, sizeof(vs->guest.dirty));
+}
+
+static void vnc_dpy_resize(DisplayState *ds)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs = vd->clients;
+    while (vs != NULL) {
+        vnc_resize(vs);
+        vs = vs->next;
+    }
+}
+
+/* fastest code */
+static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
+{
+    vnc_write(vs, pixels, size);
+}
+
+/* slowest but generic code. */
+static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
+{
+    uint8_t r, g, b;
+
+    r = ((((v & vs->server.ds->pf.rmask) >> vs->server.ds->pf.rshift) << vs->clientds.pf.rbits) >>
+        vs->server.ds->pf.rbits);
+    g = ((((v & vs->server.ds->pf.gmask) >> vs->server.ds->pf.gshift) << vs->clientds.pf.gbits) >>
+        vs->server.ds->pf.gbits);
+    b = ((((v & vs->server.ds->pf.bmask) >> vs->server.ds->pf.bshift) << vs->clientds.pf.bbits) >>
+        vs->server.ds->pf.bbits);
+    v = (r << vs->clientds.pf.rshift) |
+        (g << vs->clientds.pf.gshift) |
+        (b << vs->clientds.pf.bshift);
+    switch(vs->clientds.pf.bytes_per_pixel) {
+    case 1:
+        buf[0] = v;
+        break;
+    case 2:
+        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+            buf[0] = v >> 8;
+            buf[1] = v;
+        } else {
+            buf[1] = v >> 8;
+            buf[0] = v;
+        }
+        break;
+    default:
+    case 4:
+        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+            buf[0] = v >> 24;
+            buf[1] = v >> 16;
+            buf[2] = v >> 8;
+            buf[3] = v;
+        } else {
+            buf[3] = v >> 24;
+            buf[2] = v >> 16;
+            buf[1] = v >> 8;
+            buf[0] = v;
+        }
+        break;
+    }
+}
+
+static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
+{
+    uint8_t buf[4];
+
+    if (vs->server.ds->pf.bytes_per_pixel == 4) {
+        uint32_t *pixels = pixels1;
+        int n, i;
+        n = size >> 2;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else if (vs->server.ds->pf.bytes_per_pixel == 2) {
+        uint16_t *pixels = pixels1;
+        int n, i;
+        n = size >> 1;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else if (vs->server.ds->pf.bytes_per_pixel == 1) {
+        uint8_t *pixels = pixels1;
+        int n, i;
+        n = size;
+        for(i = 0; i < n; i++) {
+            vnc_convert_pixel(vs, buf, pixels[i]);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+        }
+    } else {
+        fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
+    }
+}
+
+static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
+{
+    int i;
+    uint8_t *row;
+
+    row = vs->server.ds->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
+    for (i = 0; i < h; i++) {
+        vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
+        row += ds_get_linesize(vs->ds);
+    }
+}
+
+static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
+{
+    ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
+    ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
+}
+
+#define BPP 8
+#include "vnchextile.h"
+#undef BPP
+
+#define BPP 16
+#include "vnchextile.h"
+#undef BPP
+
+#define BPP 32
+#include "vnchextile.h"
+#undef BPP
+
+#define GENERIC
+#define BPP 8
+#include "vnchextile.h"
+#undef BPP
+#undef GENERIC
+
+#define GENERIC
+#define BPP 16
+#include "vnchextile.h"
+#undef BPP
+#undef GENERIC
+
+#define GENERIC
+#define BPP 32
+#include "vnchextile.h"
+#undef BPP
+#undef GENERIC
+
+static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
+{
+    int i, j;
+    int has_fg, has_bg;
+    uint8_t *last_fg, *last_bg;
+
+    last_fg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
+    last_bg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
+    has_fg = has_bg = 0;
+    for (j = y; j < (y + h); j += 16) {
+        for (i = x; i < (x + w); i += 16) {
+            vs->send_hextile_tile(vs, i, j,
+                                  MIN(16, x + w - i), MIN(16, y + h - j),
+                                  last_bg, last_fg, &has_bg, &has_fg);
+        }
+    }
+    free(last_fg);
+    free(last_bg);
+
+}
+
+static void vnc_zlib_init(VncState *vs)
+{
+    int i;
+    for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
+        vs->zlib_stream[i].opaque = NULL;
+}
+
+static void vnc_zlib_start(VncState *vs)
+{
+    buffer_reset(&vs->zlib);
+
+    // make the output buffer be the zlib buffer, so we can compress it later
+    vs->zlib_tmp = vs->output;
+    vs->output = vs->zlib;
+}
+
+static int vnc_zlib_stop(VncState *vs, int stream_id)
+{
+    z_streamp zstream = &vs->zlib_stream[stream_id];
+    int previous_out;
+
+    // switch back to normal output/zlib buffers
+    vs->zlib = vs->output;
+    vs->output = vs->zlib_tmp;
+
+    // compress the zlib buffer
+
+    // initialize the stream
+    // XXX need one stream per session
+    if (zstream->opaque != vs) {
+        int err;
+
+        VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
+        VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
+        zstream->zalloc = Z_NULL;
+        zstream->zfree = Z_NULL;
+
+        err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
+                           MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+        if (err != Z_OK) {
+            fprintf(stderr, "VNC: error initializing zlib\n");
+            return -1;
+        }
+
+        zstream->opaque = vs;
+    }
+
+    // XXX what to do if tight_compression changed in between?
+
+    // reserve memory in output buffer
+    buffer_reserve(&vs->output, vs->zlib.offset + 64);
+
+    // set pointers
+    zstream->next_in = vs->zlib.buffer;
+    zstream->avail_in = vs->zlib.offset;
+    zstream->next_out = vs->output.buffer + vs->output.offset;
+    zstream->avail_out = vs->output.capacity - vs->output.offset;
+    zstream->data_type = Z_BINARY;
+    previous_out = zstream->total_out;
+
+    // start encoding
+    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
+        fprintf(stderr, "VNC: error during zlib compression\n");
+        return -1;
+    }
+
+    vs->output.offset = vs->output.capacity - zstream->avail_out;
+    return zstream->total_out - previous_out;
+}
+
+static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
+{
+    int old_offset, new_offset, bytes_written;
+
+    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
+
+    // remember where we put in the follow-up size
+    old_offset = vs->output.offset;
+    vnc_write_s32(vs, 0);
+
+    // compress the stream
+    vnc_zlib_start(vs);
+    send_framebuffer_update_raw(vs, x, y, w, h);
+    bytes_written = vnc_zlib_stop(vs, 0);
+
+    if (bytes_written == -1)
+        return;
+
+    // hack in the size
+    new_offset = vs->output.offset;
+    vs->output.offset = old_offset;
+    vnc_write_u32(vs, bytes_written);
+    vs->output.offset = new_offset;
+}
+
+static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    switch(vs->vnc_encoding) {
+        case VNC_ENCODING_ZLIB:
+            send_framebuffer_update_zlib(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
+            send_framebuffer_update_hextile(vs, x, y, w, h);
+            break;
+        default:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
+            send_framebuffer_update_raw(vs, x, y, w, h);
+            break;
+    }
+}
+
+static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+    vnc_write_u8(vs, 0);  /* msg id */
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1); /* number of rects */
+    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
+    vnc_write_u16(vs, src_x);
+    vnc_write_u16(vs, src_y);
+    vnc_flush(vs);
+}
+
+static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs, *vn;
+
+    for (vs = vd->clients; vs != NULL; vs = vn) {
+        vn = vs->next;
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+            vs->force_update = 1;
+            vnc_update_client(vs);
+            /* vs might be free()ed here */
+        }
+    }
+
+    for (vs = vd->clients; vs != NULL; vs = vs->next) {
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
+            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
+        else /* TODO */
+            vnc_update(vs, dst_x, dst_y, w, h);
+    }
+}
+
+static int find_and_clear_dirty_height(struct VncSurface *s,
+                                       int y, int last_x, int x)
+{
+    int h;
+
+    for (h = 1; h < (s->ds->height - y); h++) {
+        int tmp_x;
+        if (!vnc_get_bit(s->dirty[y + h], last_x))
+            break;
+        for (tmp_x = last_x; tmp_x < x; tmp_x++)
+            vnc_clear_bit(s->dirty[y + h], tmp_x);
+    }
+
+    return h;
+}
+
+static void vnc_update_client(void *opaque)
+{
+    VncState *vs = opaque;
+    if (vs->need_update && vs->csock != -1) {
+        int y;
+        uint8_t *guest_row;
+        uint8_t *server_row;
+        int cmp_bytes;
+        uint32_t width_mask[VNC_DIRTY_WORDS];
+        int n_rectangles;
+        int saved_offset;
+        int has_dirty = 0;
+
+        if (vs->output.offset && !vs->audio_cap && !vs->force_update) {
+            /* kernel send buffers are full -> drop frames to throttle */
+            qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+            return;
+        }
+
+        vga_hw_update();
+
+        /*
+         * Walk through the guest dirty map.
+         * Check and copy modified bits from guest to server surface.
+         * Update server dirty map.
+         */
+        vnc_set_bits(width_mask, (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+        cmp_bytes = 16 * ds_get_bytes_per_pixel(vs->ds);
+        guest_row  = vs->guest.ds->data;
+        server_row = vs->server.ds->data;
+        for (y = 0; y < vs->guest.ds->height; y++) {
+            if (vnc_and_bits(vs->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
+                int x;
+                uint8_t *guest_ptr;
+                uint8_t *server_ptr;
+
+                guest_ptr  = guest_row;
+                server_ptr = server_row;
+
+                for (x = 0; x < vs->guest.ds->width;
+                     x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
+                    if (!vnc_get_bit(vs->guest.dirty[y], (x / 16)))
+                        continue;
+                    vnc_clear_bit(vs->guest.dirty[y], (x / 16));
+                    if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
+                        continue;
+                    memcpy(server_ptr, guest_ptr, cmp_bytes);
+                    vnc_set_bit(vs->server.dirty[y], (x / 16));
+                    has_dirty++;
+                }
+            }
+            guest_row  += ds_get_linesize(vs->ds);
+            server_row += ds_get_linesize(vs->ds);
+        }
+
+        if (!has_dirty && !vs->audio_cap && !vs->force_update) {
+            qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+            return;
+        }
+
+        /*
+         * Send screen updates to the vnc client using the server
+         * surface and server dirty map.  guest surface updates
+         * happening in parallel don't disturb us, the next pass will
+         * send them to the client.
+         */
+        n_rectangles = 0;
+        vnc_write_u8(vs, 0);  /* msg id */
+        vnc_write_u8(vs, 0);
+        saved_offset = vs->output.offset;
+        vnc_write_u16(vs, 0);
+
+        for (y = 0; y < vs->server.ds->height; y++) {
+            int x;
+            int last_x = -1;
+            for (x = 0; x < vs->server.ds->width / 16; x++) {
+                if (vnc_get_bit(vs->server.dirty[y], x)) {
+                    if (last_x == -1) {
+                        last_x = x;
+                    }
+                    vnc_clear_bit(vs->server.dirty[y], x);
+                } else {
+                    if (last_x != -1) {
+                        int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
+                        send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
+                        n_rectangles++;
+                    }
+                    last_x = -1;
+                }
+            }
+            if (last_x != -1) {
+                int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
+                send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
+                n_rectangles++;
+            }
+        }
+        vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+        vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
+        vnc_flush(vs);
+        vs->force_update = 0;
+
+    }
+
+    if (vs->csock != -1) {
+        qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+    } else {
+        vnc_disconnect_finish(vs);
+    }
+
+}
+
+/* audio */
+static void audio_capture_notify(void *opaque, audcnotification_e cmd)
+{
+    VncState *vs = opaque;
+
+    switch (cmd) {
+    case AUD_CNOTIFY_DISABLE:
+        vnc_write_u8(vs, 255);
+        vnc_write_u8(vs, 1);
+        vnc_write_u16(vs, 0);
+        vnc_flush(vs);
+        break;
+
+    case AUD_CNOTIFY_ENABLE:
+        vnc_write_u8(vs, 255);
+        vnc_write_u8(vs, 1);
+        vnc_write_u16(vs, 1);
+        vnc_flush(vs);
+        break;
+    }
+}
+
+static void audio_capture_destroy(void *opaque)
+{
+}
+
+static void audio_capture(void *opaque, void *buf, int size)
+{
+    VncState *vs = opaque;
+
+    vnc_write_u8(vs, 255);
+    vnc_write_u8(vs, 1);
+    vnc_write_u16(vs, 2);
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
+    vnc_flush(vs);
+}
+
+static void audio_add(VncState *vs)
+{
+    Monitor *mon = cur_mon;
+    struct audio_capture_ops ops;
+
+    if (vs->audio_cap) {
+        monitor_printf(mon, "audio already running\n");
+        return;
+    }
+
+    ops.notify = audio_capture_notify;
+    ops.destroy = audio_capture_destroy;
+    ops.capture = audio_capture;
+
+    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
+    if (!vs->audio_cap) {
+        monitor_printf(mon, "Failed to add audio capture\n");
+    }
+}
+
+static void audio_del(VncState *vs)
+{
+    if (vs->audio_cap) {
+        AUD_del_capture(vs->audio_cap, vs);
+        vs->audio_cap = NULL;
+    }
+}
+
+static void vnc_disconnect_start(VncState *vs)
+{
+    if (vs->csock == -1)
+        return;
+    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+    closesocket(vs->csock);
+    vs->csock = -1;
+}
+
+static void vnc_disconnect_finish(VncState *vs)
+{
+    qemu_del_timer(vs->timer);
+    qemu_free_timer(vs->timer);
+    if (vs->input.buffer) qemu_free(vs->input.buffer);
+    if (vs->output.buffer) qemu_free(vs->output.buffer);
+#ifdef CONFIG_VNC_TLS
+    vnc_tls_client_cleanup(vs);
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    vnc_sasl_client_cleanup(vs);
+#endif /* CONFIG_VNC_SASL */
+    audio_del(vs);
+
+    VncState *p, *parent = NULL;
+    for (p = vs->vd->clients; p != NULL; p = p->next) {
+        if (p == vs) {
+            if (parent)
+                parent->next = p->next;
+            else
+                vs->vd->clients = p->next;
+            break;
+        }
+        parent = p;
+    }
+    if (!vs->vd->clients)
+        dcl->idle = 1;
+
+    qemu_free(vs->server.ds->data);
+    qemu_free(vs->server.ds);
+    qemu_free(vs->guest.ds);
+    qemu_free(vs);
+}
+
+int vnc_client_io_error(VncState *vs, int ret, int last_errno)
+{
+    if (ret == 0 || ret == -1) {
+        if (ret == -1) {
+            switch (last_errno) {
+                case EINTR:
+                case EAGAIN:
+#ifdef _WIN32
+                case WSAEWOULDBLOCK:
+#endif
+                    return 0;
+                default:
+                    break;
+            }
+        }
+
+        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
+                  ret, ret < 0 ? last_errno : 0);
+        vnc_disconnect_start(vs);
+
+        return 0;
+    }
+    return ret;
+}
+
+
+void vnc_client_error(VncState *vs)
+{
+    VNC_DEBUG("Closing down client sock: protocol error\n");
+    vnc_disconnect_start(vs);
+}
+
+
+/*
+ * Called to write a chunk of data to the client socket. The data may
+ * be the raw data, or may have already been encoded by SASL.
+ * The data will be written either straight onto the socket, or
+ * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes written, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
+{
+    long ret;
+#ifdef CONFIG_VNC_TLS
+    if (vs->tls.session) {
+        ret = gnutls_write(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        ret = socket_send(vs->csock, data, datalen);
+    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+
+/*
+ * Called to write buffered data to the client socket, when not
+ * using any SASL SSF encryption layers. Will write as much data
+ * as possible without blocking. If all buffered data is written,
+ * will switch the FD poll() handler back to read monitoring.
+ *
+ * Returns the number of bytes written, which may be less than
+ * the buffered output data if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+static long vnc_client_write_plain(VncState *vs)
+{
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
+              vs->output.buffer, vs->output.capacity, vs->output.offset,
+              vs->sasl.waitWriteSSF);
+
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        vs->sasl.waitWriteSSF) {
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
+        if (ret)
+            vs->sasl.waitWriteSSF -= ret;
+    } else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
+    if (!ret)
+        return 0;
+
+    memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
+    vs->output.offset -= ret;
+
+    if (vs->output.offset == 0) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    }
+
+    return ret;
+}
+
+
+/*
+ * First function called whenever there is data to be written to
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring encryption calls)
+ */
+void vnc_client_write(void *opaque)
+{
+    long ret;
+    VncState *vs = opaque;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        !vs->sasl.waitWriteSSF)
+        ret = vnc_client_write_sasl(vs);
+    else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_write_plain(vs);
+}
+
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
+{
+    vs->read_handler = func;
+    vs->read_handler_expect = expecting;
+}
+
+
+/*
+ * Called to read a chunk of data from the client socket. The data may
+ * be the raw data, or may need to be further decoded by SASL.
+ * The data will be read either straight from to the socket, or
+ * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes read, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
+{
+    long ret;
+#ifdef CONFIG_VNC_TLS
+    if (vs->tls.session) {
+        ret = gnutls_read(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        ret = socket_recv(vs->csock, data, datalen);
+    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+
+/*
+ * Called to read data from the client socket to the input buffer,
+ * when not using any SASL SSF encryption layers. Will read as much
+ * data as possible without blocking.
+ *
+ * Returns the number of bytes read. Returns -1 on error, and
+ * disconnects the client socket.
+ */
+static long vnc_client_read_plain(VncState *vs)
+{
+    int ret;
+    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
+              vs->input.buffer, vs->input.capacity, vs->input.offset);
+    buffer_reserve(&vs->input, 4096);
+    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
+    if (!ret)
+        return 0;
+    vs->input.offset += ret;
+    return ret;
+}
+
+
+/*
+ * First function called whenever there is more data to be read from
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring decryption calls)
+ */
+void vnc_client_read(void *opaque)
+{
+    VncState *vs = opaque;
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn && vs->sasl.runSSF)
+        ret = vnc_client_read_sasl(vs);
+    else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_read_plain(vs);
+    if (!ret) {
+        if (vs->csock == -1)
+            vnc_disconnect_finish(vs);
+        return;
+    }
+
+    while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
+        size_t len = vs->read_handler_expect;
+        int ret;
+
+        ret = vs->read_handler(vs, vs->input.buffer, len);
+        if (vs->csock == -1) {
+            vnc_disconnect_finish(vs);
+            return;
+        }
+
+        if (!ret) {
+            memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
+            vs->input.offset -= len;
+        } else {
+            vs->read_handler_expect = ret;
+        }
+    }
+}
+
+void vnc_write(VncState *vs, const void *data, size_t len)
+{
+    buffer_reserve(&vs->output, len);
+
+    if (vs->csock != -1 && buffer_empty(&vs->output)) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+    }
+
+    buffer_append(&vs->output, data, len);
+}
+
+void vnc_write_s32(VncState *vs, int32_t value)
+{
+    vnc_write_u32(vs, *(uint32_t *)&value);
+}
+
+void vnc_write_u32(VncState *vs, uint32_t value)
+{
+    uint8_t buf[4];
+
+    buf[0] = (value >> 24) & 0xFF;
+    buf[1] = (value >> 16) & 0xFF;
+    buf[2] = (value >>  8) & 0xFF;
+    buf[3] = value & 0xFF;
+
+    vnc_write(vs, buf, 4);
+}
+
+void vnc_write_u16(VncState *vs, uint16_t value)
+{
+    uint8_t buf[2];
+
+    buf[0] = (value >> 8) & 0xFF;
+    buf[1] = value & 0xFF;
+
+    vnc_write(vs, buf, 2);
+}
+
+void vnc_write_u8(VncState *vs, uint8_t value)
+{
+    vnc_write(vs, (char *)&value, 1);
+}
+
+void vnc_flush(VncState *vs)
+{
+    if (vs->csock != -1 && vs->output.offset)
+        vnc_client_write(vs);
+}
+
+uint8_t read_u8(uint8_t *data, size_t offset)
+{
+    return data[offset];
+}
+
+uint16_t read_u16(uint8_t *data, size_t offset)
+{
+    return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
+}
+
+int32_t read_s32(uint8_t *data, size_t offset)
+{
+    return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
+                     (data[offset + 2] << 8) | data[offset + 3]);
+}
+
+uint32_t read_u32(uint8_t *data, size_t offset)
+{
+    return ((data[offset] << 24) | (data[offset + 1] << 16) |
+            (data[offset + 2] << 8) | data[offset + 3]);
+}
+
+static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
+{
+}
+
+static void check_pointer_type_change(VncState *vs, int absolute)
+{
+    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
+        vnc_write_u8(vs, 0);
+        vnc_write_u8(vs, 0);
+        vnc_write_u16(vs, 1);
+        vnc_framebuffer_update(vs, absolute, 0,
+                               ds_get_width(vs->ds), ds_get_height(vs->ds),
+                               VNC_ENCODING_POINTER_TYPE_CHANGE);
+        vnc_flush(vs);
+    }
+    vs->absolute = absolute;
+}
+
+static void pointer_event(VncState *vs, int button_mask, int x, int y)
+{
+    int buttons = 0;
+    int dz = 0;
+
+    if (button_mask & 0x01)
+        buttons |= MOUSE_EVENT_LBUTTON;
+    if (button_mask & 0x02)
+        buttons |= MOUSE_EVENT_MBUTTON;
+    if (button_mask & 0x04)
+        buttons |= MOUSE_EVENT_RBUTTON;
+    if (button_mask & 0x08)
+        dz = -1;
+    if (button_mask & 0x10)
+        dz = 1;
+
+    if (vs->absolute) {
+        kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
+                        y * 0x7FFF / (ds_get_height(vs->ds) - 1),
+                        dz, buttons);
+    } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
+        x -= 0x7FFF;
+        y -= 0x7FFF;
+
+        kbd_mouse_event(x, y, dz, buttons);
+    } else {
+        if (vs->last_x != -1)
+            kbd_mouse_event(x - vs->last_x,
+                            y - vs->last_y,
+                            dz, buttons);
+        vs->last_x = x;
+        vs->last_y = y;
+    }
+
+    check_pointer_type_change(vs, kbd_mouse_is_absolute());
+}
+
+static void reset_keys(VncState *vs)
+{
+    int i;
+    for(i = 0; i < 256; i++) {
+        if (vs->modifiers_state[i]) {
+            if (i & 0x80)
+                kbd_put_keycode(0xe0);
+            kbd_put_keycode(i | 0x80);
+            vs->modifiers_state[i] = 0;
+        }
+    }
+}
+
+static void press_key(VncState *vs, int keysym)
+{
+    kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
+    kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
+}
+
+static void do_key_event(VncState *vs, int down, int keycode, int sym)
+{
+    /* QEMU console switch */
+    switch(keycode) {
+    case 0x2a:                          /* Left Shift */
+    case 0x36:                          /* Right Shift */
+    case 0x1d:                          /* Left CTRL */
+    case 0x9d:                          /* Right CTRL */
+    case 0x38:                          /* Left ALT */
+    case 0xb8:                          /* Right ALT */
+        if (down)
+            vs->modifiers_state[keycode] = 1;
+        else
+            vs->modifiers_state[keycode] = 0;
+        break;
+    case 0x02 ... 0x0a: /* '1' to '9' keys */
+        if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
+            /* Reset the modifiers sent to the current console */
+            reset_keys(vs);
+            console_select(keycode - 0x02);
+            return;
+        }
+        break;
+    case 0x3a:                        /* CapsLock */
+    case 0x45:                        /* NumLock */
+        if (!down)
+            vs->modifiers_state[keycode] ^= 1;
+        break;
+    }
+
+    if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
+        /* If the numlock state needs to change then simulate an additional
+           keypress before sending this one.  This will happen if the user
+           toggles numlock away from the VNC window.
+        */
+        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
+            if (!vs->modifiers_state[0x45]) {
+                vs->modifiers_state[0x45] = 1;
+                press_key(vs, 0xff7f);
+            }
+        } else {
+            if (vs->modifiers_state[0x45]) {
+                vs->modifiers_state[0x45] = 0;
+                press_key(vs, 0xff7f);
+            }
+        }
+    }
+
+    if (is_graphic_console()) {
+        if (keycode & 0x80)
+            kbd_put_keycode(0xe0);
+        if (down)
+            kbd_put_keycode(keycode & 0x7f);
+        else
+            kbd_put_keycode(keycode | 0x80);
+    } else {
+        /* QEMU console emulation */
+        if (down) {
+            int numlock = vs->modifiers_state[0x45];
+            switch (keycode) {
+            case 0x2a:                          /* Left Shift */
+            case 0x36:                          /* Right Shift */
+            case 0x1d:                          /* Left CTRL */
+            case 0x9d:                          /* Right CTRL */
+            case 0x38:                          /* Left ALT */
+            case 0xb8:                          /* Right ALT */
+                break;
+            case 0xc8:
+                kbd_put_keysym(QEMU_KEY_UP);
+                break;
+            case 0xd0:
+                kbd_put_keysym(QEMU_KEY_DOWN);
+                break;
+            case 0xcb:
+                kbd_put_keysym(QEMU_KEY_LEFT);
+                break;
+            case 0xcd:
+                kbd_put_keysym(QEMU_KEY_RIGHT);
+                break;
+            case 0xd3:
+                kbd_put_keysym(QEMU_KEY_DELETE);
+                break;
+            case 0xc7:
+                kbd_put_keysym(QEMU_KEY_HOME);
+                break;
+            case 0xcf:
+                kbd_put_keysym(QEMU_KEY_END);
+                break;
+            case 0xc9:
+                kbd_put_keysym(QEMU_KEY_PAGEUP);
+                break;
+            case 0xd1:
+                kbd_put_keysym(QEMU_KEY_PAGEDOWN);
+                break;
+
+            case 0x47:
+                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
+                break;
+            case 0x48:
+                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
+                break;
+            case 0x49:
+                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
+                break;
+            case 0x4b:
+                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
+                break;
+            case 0x4c:
+                kbd_put_keysym('5');
+                break;
+            case 0x4d:
+                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
+                break;
+            case 0x4f:
+                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
+                break;
+            case 0x50:
+                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
+                break;
+            case 0x51:
+                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
+                break;
+            case 0x52:
+                kbd_put_keysym('0');
+                break;
+            case 0x53:
+                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
+                break;
+
+            case 0xb5:
+                kbd_put_keysym('/');
+                break;
+            case 0x37:
+                kbd_put_keysym('*');
+                break;
+            case 0x4a:
+                kbd_put_keysym('-');
+                break;
+            case 0x4e:
+                kbd_put_keysym('+');
+                break;
+            case 0x9c:
+                kbd_put_keysym('\n');
+                break;
+
+            default:
+                kbd_put_keysym(sym);
+                break;
+            }
+        }
+    }
+}
+
+static void key_event(VncState *vs, int down, uint32_t sym)
+{
+    int keycode;
+
+    if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
+        sym = sym - 'A' + 'a';
+
+    keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);
+    do_key_event(vs, down, keycode, sym);
+}
+
+static void ext_key_event(VncState *vs, int down,
+                          uint32_t sym, uint16_t keycode)
+{
+    /* if the user specifies a keyboard layout, always use it */
+    if (keyboard_layout)
+        key_event(vs, down, sym);
+    else
+        do_key_event(vs, down, keycode, sym);
+}
+
+static void framebuffer_update_request(VncState *vs, int incremental,
+                                       int x_position, int y_position,
+                                       int w, int h)
+{
+    if (x_position > ds_get_width(vs->ds))
+        x_position = ds_get_width(vs->ds);
+    if (y_position > ds_get_height(vs->ds))
+        y_position = ds_get_height(vs->ds);
+    if (x_position + w >= ds_get_width(vs->ds))
+        w = ds_get_width(vs->ds)  - x_position;
+    if (y_position + h >= ds_get_height(vs->ds))
+        h = ds_get_height(vs->ds) - y_position;
+
+    int i;
+    vs->need_update = 1;
+    if (!incremental) {
+        vs->force_update = 1;
+        for (i = 0; i < h; i++) {
+            vnc_set_bits(vs->guest.dirty[y_position + i],
+                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+            vnc_set_bits(vs->server.dirty[y_position + i],
+                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+        }
+    }
+}
+
+static void send_ext_key_event_ack(VncState *vs)
+{
+    vnc_write_u8(vs, 0);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
+                           VNC_ENCODING_EXT_KEY_EVENT);
+    vnc_flush(vs);
+}
+
+static void send_ext_audio_ack(VncState *vs)
+{
+    vnc_write_u8(vs, 0);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
+                           VNC_ENCODING_AUDIO);
+    vnc_flush(vs);
+}
+
+static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
+{
+    int i;
+    unsigned int enc = 0;
+
+    vnc_zlib_init(vs);
+    vs->features = 0;
+    vs->vnc_encoding = 0;
+    vs->tight_compression = 9;
+    vs->tight_quality = 9;
+    vs->absolute = -1;
+
+    for (i = n_encodings - 1; i >= 0; i--) {
+        enc = encodings[i];
+        switch (enc) {
+        case VNC_ENCODING_RAW:
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_COPYRECT:
+            vs->features |= VNC_FEATURE_COPYRECT_MASK;
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vs->features |= VNC_FEATURE_HEXTILE_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_ZLIB:
+            vs->features |= VNC_FEATURE_ZLIB_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_DESKTOPRESIZE:
+            vs->features |= VNC_FEATURE_RESIZE_MASK;
+            break;
+        case VNC_ENCODING_POINTER_TYPE_CHANGE:
+            vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
+            break;
+        case VNC_ENCODING_EXT_KEY_EVENT:
+            send_ext_key_event_ack(vs);
+            break;
+        case VNC_ENCODING_AUDIO:
+            send_ext_audio_ack(vs);
+            break;
+        case VNC_ENCODING_WMVi:
+            vs->features |= VNC_FEATURE_WMVI_MASK;
+            break;
+        case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
+            vs->tight_compression = (enc & 0x0F);
+            break;
+        case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
+            vs->tight_quality = (enc & 0x0F);
+            break;
+        default:
+            VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
+            break;
+        }
+    }
+
+    check_pointer_type_change(vs, kbd_mouse_is_absolute());
+}
+
+static void set_pixel_conversion(VncState *vs)
+{
+    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && 
+        !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
+        vs->write_pixels = vnc_write_pixels_copy;
+        switch (vs->ds->surface->pf.bits_per_pixel) {
+            case 8:
+                vs->send_hextile_tile = send_hextile_tile_8;
+                break;
+            case 16:
+                vs->send_hextile_tile = send_hextile_tile_16;
+                break;
+            case 32:
+                vs->send_hextile_tile = send_hextile_tile_32;
+                break;
+        }
+    } else {
+        vs->write_pixels = vnc_write_pixels_generic;
+        switch (vs->ds->surface->pf.bits_per_pixel) {
+            case 8:
+                vs->send_hextile_tile = send_hextile_tile_generic_8;
+                break;
+            case 16:
+                vs->send_hextile_tile = send_hextile_tile_generic_16;
+                break;
+            case 32:
+                vs->send_hextile_tile = send_hextile_tile_generic_32;
+                break;
+        }
+    }
+}
+
+static void set_pixel_format(VncState *vs,
+                             int bits_per_pixel, int depth,
+                             int big_endian_flag, int true_color_flag,
+                             int red_max, int green_max, int blue_max,
+                             int red_shift, int green_shift, int blue_shift)
+{
+    if (!true_color_flag) {
+        vnc_client_error(vs);
+        return;
+    }
+
+    vs->clientds = *(vs->guest.ds);
+    vs->clientds.pf.rmax = red_max;
+    count_bits(vs->clientds.pf.rbits, red_max);
+    vs->clientds.pf.rshift = red_shift;
+    vs->clientds.pf.rmask = red_max << red_shift;
+    vs->clientds.pf.gmax = green_max;
+    count_bits(vs->clientds.pf.gbits, green_max);
+    vs->clientds.pf.gshift = green_shift;
+    vs->clientds.pf.gmask = green_max << green_shift;
+    vs->clientds.pf.bmax = blue_max;
+    count_bits(vs->clientds.pf.bbits, blue_max);
+    vs->clientds.pf.bshift = blue_shift;
+    vs->clientds.pf.bmask = blue_max << blue_shift;
+    vs->clientds.pf.bits_per_pixel = bits_per_pixel;
+    vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
+    vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
+    vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
+
+    set_pixel_conversion(vs);
+
+    vga_hw_invalidate();
+    vga_hw_update();
+}
+
+static void pixel_format_message (VncState *vs) {
+    char pad[3] = { 0, 0, 0 };
+
+    vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
+    vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
+
+#ifdef WORDS_BIGENDIAN
+    vnc_write_u8(vs, 1);             /* big-endian-flag */
+#else
+    vnc_write_u8(vs, 0);             /* big-endian-flag */
+#endif
+    vnc_write_u8(vs, 1);             /* true-color-flag */
+    vnc_write_u16(vs, vs->ds->surface->pf.rmax);     /* red-max */
+    vnc_write_u16(vs, vs->ds->surface->pf.gmax);     /* green-max */
+    vnc_write_u16(vs, vs->ds->surface->pf.bmax);     /* blue-max */
+    vnc_write_u8(vs, vs->ds->surface->pf.rshift);    /* red-shift */
+    vnc_write_u8(vs, vs->ds->surface->pf.gshift);    /* green-shift */
+    vnc_write_u8(vs, vs->ds->surface->pf.bshift);    /* blue-shift */
+    if (vs->ds->surface->pf.bits_per_pixel == 32)
+        vs->send_hextile_tile = send_hextile_tile_32;
+    else if (vs->ds->surface->pf.bits_per_pixel == 16)
+        vs->send_hextile_tile = send_hextile_tile_16;
+    else if (vs->ds->surface->pf.bits_per_pixel == 8)
+        vs->send_hextile_tile = send_hextile_tile_8;
+    vs->clientds = *(vs->ds->surface);
+    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
+    vs->write_pixels = vnc_write_pixels_copy;
+
+    vnc_write(vs, pad, 3);           /* padding */
+}
+
+static void vnc_dpy_setdata(DisplayState *ds)
+{
+    /* We don't have to do anything */
+}
+
+static void vnc_colordepth(VncState *vs)
+{
+    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
+        /* Sending a WMVi message to notify the client*/
+        vnc_write_u8(vs, 0);  /* msg id */
+        vnc_write_u8(vs, 0);
+        vnc_write_u16(vs, 1); /* number of rects */
+        vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
+                               ds_get_height(vs->ds), VNC_ENCODING_WMVi);
+        pixel_format_message(vs);
+        vnc_flush(vs);
+    } else {
+        set_pixel_conversion(vs);
+    }
+}
+
+static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
+{
+    int i;
+    uint16_t limit;
+
+    switch (data[0]) {
+    case 0:
+        if (len == 1)
+            return 20;
+
+        set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
+                         read_u8(data, 6), read_u8(data, 7),
+                         read_u16(data, 8), read_u16(data, 10),
+                         read_u16(data, 12), read_u8(data, 14),
+                         read_u8(data, 15), read_u8(data, 16));
+        break;
+    case 2:
+        if (len == 1)
+            return 4;
+
+        if (len == 4) {
+            limit = read_u16(data, 2);
+            if (limit > 0)
+                return 4 + (limit * 4);
+        } else
+            limit = read_u16(data, 2);
+
+        for (i = 0; i < limit; i++) {
+            int32_t val = read_s32(data, 4 + (i * 4));
+            memcpy(data + 4 + (i * 4), &val, sizeof(val));
+        }
+
+        set_encodings(vs, (int32_t *)(data + 4), limit);
+        break;
+    case 3:
+        if (len == 1)
+            return 10;
+
+        framebuffer_update_request(vs,
+                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
+                                   read_u16(data, 6), read_u16(data, 8));
+        break;
+    case 4:
+        if (len == 1)
+            return 8;
+
+        key_event(vs, read_u8(data, 1), read_u32(data, 4));
+        break;
+    case 5:
+        if (len == 1)
+            return 6;
+
+        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
+        break;
+    case 6:
+        if (len == 1)
+            return 8;
+
+        if (len == 8) {
+            uint32_t dlen = read_u32(data, 4);
+            if (dlen > 0)
+                return 8 + dlen;
+        }
+
+        client_cut_text(vs, read_u32(data, 4), data + 8);
+        break;
+    case 255:
+        if (len == 1)
+            return 2;
+
+        switch (read_u8(data, 1)) {
+        case 0:
+            if (len == 2)
+                return 12;
+
+            ext_key_event(vs, read_u16(data, 2),
+                          read_u32(data, 4), read_u32(data, 8));
+            break;
+        case 1:
+            if (len == 2)
+                return 4;
+
+            switch (read_u16 (data, 2)) {
+            case 0:
+                audio_add(vs);
+                break;
+            case 1:
+                audio_del(vs);
+                break;
+            case 2:
+                if (len == 4)
+                    return 10;
+                switch (read_u8(data, 4)) {
+                case 0: vs->as.fmt = AUD_FMT_U8; break;
+                case 1: vs->as.fmt = AUD_FMT_S8; break;
+                case 2: vs->as.fmt = AUD_FMT_U16; break;
+                case 3: vs->as.fmt = AUD_FMT_S16; break;
+                case 4: vs->as.fmt = AUD_FMT_U32; break;
+                case 5: vs->as.fmt = AUD_FMT_S32; break;
+                default:
+                    printf("Invalid audio format %d\n", read_u8(data, 4));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.nchannels = read_u8(data, 5);
+                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
+                    printf("Invalid audio channel coount %d\n",
+                           read_u8(data, 5));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.freq = read_u32(data, 6);
+                break;
+            default:
+                printf ("Invalid audio message %d\n", read_u8(data, 4));
+                vnc_client_error(vs);
+                break;
+            }
+            break;
+
+        default:
+            printf("Msg: %d\n", read_u16(data, 0));
+            vnc_client_error(vs);
+            break;
+        }
+        break;
+    default:
+        printf("Msg: %d\n", data[0]);
+        vnc_client_error(vs);
+        break;
+    }
+
+    vnc_read_when(vs, protocol_client_msg, 1);
+    return 0;
+}
+
+static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
+{
+    char buf[1024];
+    int size;
+
+    vnc_write_u16(vs, ds_get_width(vs->ds));
+    vnc_write_u16(vs, ds_get_height(vs->ds));
+
+    pixel_format_message(vs);
+
+    if (qemu_name)
+        size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
+    else
+        size = snprintf(buf, sizeof(buf), "QEMU");
+
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
+    vnc_flush(vs);
+
+    vnc_read_when(vs, protocol_client_msg, 1);
+
+    return 0;
+}
+
+void start_client_init(VncState *vs)
+{
+    vnc_read_when(vs, protocol_client_init, 1);
+}
+
+static void make_challenge(VncState *vs)
+{
+    int i;
+
+    srand(time(NULL)+getpid()+getpid()*987654+rand());
+
+    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
+        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
+}
+
+static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
+{
+    unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
+    int i, j, pwlen;
+    unsigned char key[8];
+
+    if (!vs->vd->password || !vs->vd->password[0]) {
+        VNC_DEBUG("No password configured on server");
+        vnc_write_u32(vs, 1); /* Reject auth */
+        if (vs->minor >= 8) {
+            static const char err[] = "Authentication failed";
+            vnc_write_u32(vs, sizeof(err));
+            vnc_write(vs, err, sizeof(err));
+        }
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
+    }
+
+    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
+
+    /* Calculate the expected challenge response */
+    pwlen = strlen(vs->vd->password);
+    for (i=0; i<sizeof(key); i++)
+        key[i] = i<pwlen ? vs->vd->password[i] : 0;
+    deskey(key, EN0);
+    for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
+        des(response+j, response+j);
+
+    /* Compare expected vs actual challenge response */
+    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
+        VNC_DEBUG("Client challenge reponse did not match\n");
+        vnc_write_u32(vs, 1); /* Reject auth */
+        if (vs->minor >= 8) {
+            static const char err[] = "Authentication failed";
+            vnc_write_u32(vs, sizeof(err));
+            vnc_write(vs, err, sizeof(err));
+        }
+        vnc_flush(vs);
+        vnc_client_error(vs);
+    } else {
+        VNC_DEBUG("Accepting VNC challenge response\n");
+        vnc_write_u32(vs, 0); /* Accept auth */
+        vnc_flush(vs);
+
+        start_client_init(vs);
+    }
+    return 0;
+}
+
+void start_auth_vnc(VncState *vs)
+{
+    make_challenge(vs);
+    /* Send client a 'random' challenge */
+    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
+    vnc_flush(vs);
+
+    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
+}
+
+
+static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
+{
+    /* We only advertise 1 auth scheme at a time, so client
+     * must pick the one we sent. Verify this */
+    if (data[0] != vs->vd->auth) { /* Reject auth */
+       VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
+       vnc_write_u32(vs, 1);
+       if (vs->minor >= 8) {
+           static const char err[] = "Authentication failed";
+           vnc_write_u32(vs, sizeof(err));
+           vnc_write(vs, err, sizeof(err));
+       }
+       vnc_client_error(vs);
+    } else { /* Accept requested auth */
+       VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
+       switch (vs->vd->auth) {
+       case VNC_AUTH_NONE:
+           VNC_DEBUG("Accept auth none\n");
+           if (vs->minor >= 8) {
+               vnc_write_u32(vs, 0); /* Accept auth completion */
+               vnc_flush(vs);
+           }
+           start_client_init(vs);
+           break;
+
+       case VNC_AUTH_VNC:
+           VNC_DEBUG("Start VNC auth\n");
+           start_auth_vnc(vs);
+           break;
+
+#ifdef CONFIG_VNC_TLS
+       case VNC_AUTH_VENCRYPT:
+           VNC_DEBUG("Accept VeNCrypt auth\n");;
+           start_auth_vencrypt(vs);
+           break;
+#endif /* CONFIG_VNC_TLS */
+
+#ifdef CONFIG_VNC_SASL
+       case VNC_AUTH_SASL:
+           VNC_DEBUG("Accept SASL auth\n");
+           start_auth_sasl(vs);
+           break;
+#endif /* CONFIG_VNC_SASL */
+
+       default: /* Should not be possible, but just in case */
+           VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
+           vnc_write_u8(vs, 1);
+           if (vs->minor >= 8) {
+               static const char err[] = "Authentication failed";
+               vnc_write_u32(vs, sizeof(err));
+               vnc_write(vs, err, sizeof(err));
+           }
+           vnc_client_error(vs);
+       }
+    }
+    return 0;
+}
+
+static int protocol_version(VncState *vs, uint8_t *version, size_t len)
+{
+    char local[13];
+
+    memcpy(local, version, 12);
+    local[12] = 0;
+
+    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
+        VNC_DEBUG("Malformed protocol version %s\n", local);
+        vnc_client_error(vs);
+        return 0;
+    }
+    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
+    if (vs->major != 3 ||
+        (vs->minor != 3 &&
+         vs->minor != 4 &&
+         vs->minor != 5 &&
+         vs->minor != 7 &&
+         vs->minor != 8)) {
+        VNC_DEBUG("Unsupported client version\n");
+        vnc_write_u32(vs, VNC_AUTH_INVALID);
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
+    }
+    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
+     * as equivalent to v3.3 by servers
+     */
+    if (vs->minor == 4 || vs->minor == 5)
+        vs->minor = 3;
+
+    if (vs->minor == 3) {
+        if (vs->vd->auth == VNC_AUTH_NONE) {
+            VNC_DEBUG("Tell client auth none\n");
+            vnc_write_u32(vs, vs->vd->auth);
+            vnc_flush(vs);
+            start_client_init(vs);
+       } else if (vs->vd->auth == VNC_AUTH_VNC) {
+            VNC_DEBUG("Tell client VNC auth\n");
+            vnc_write_u32(vs, vs->vd->auth);
+            vnc_flush(vs);
+            start_auth_vnc(vs);
+       } else {
+            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
+            vnc_write_u32(vs, VNC_AUTH_INVALID);
+            vnc_flush(vs);
+            vnc_client_error(vs);
+       }
+    } else {
+        VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
+        vnc_write_u8(vs, 1); /* num auth */
+        vnc_write_u8(vs, vs->vd->auth);
+        vnc_read_when(vs, protocol_client_auth, 1);
+        vnc_flush(vs);
+    }
+
+    return 0;
+}
+
+static void vnc_connect(VncDisplay *vd, int csock)
+{
+    VncState *vs = qemu_mallocz(sizeof(VncState));
+    vs->csock = csock;
+
+    VNC_DEBUG("New client on socket %d\n", csock);
+    dcl->idle = 0;
+    socket_set_nonblock(vs->csock);
+    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+
+    vs->vd = vd;
+    vs->ds = vd->ds;
+    vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
+    vs->last_x = -1;
+    vs->last_y = -1;
+
+    vs->as.freq = 44100;
+    vs->as.nchannels = 2;
+    vs->as.fmt = AUD_FMT_S16;
+    vs->as.endianness = 0;
+
+    vnc_resize(vs);
+    vnc_write(vs, "RFB 003.008\n", 12);
+    vnc_flush(vs);
+    vnc_read_when(vs, protocol_version, 12);
+    reset_keys(vs);
+
+    vs->next = vd->clients;
+    vd->clients = vs;
+
+    vnc_update_client(vs);
+    /* vs might be free()ed here */
+}
+
+static void vnc_listen_read(void *opaque)
+{
+    VncDisplay *vs = opaque;
+
+    /* Catch-up */
+    vga_hw_update();
+
+    int csock = socket_accept(vs->lsock, NULL);
+    if (csock != -1) {
+        vnc_connect(vs, csock);
+    }
+}
+
+void vnc_display_init(DisplayState *ds)
+{
+    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
+
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
+
+    ds->opaque = vs;
+    dcl->idle = 1;
+    vnc_display = vs;
+
+    vs->lsock = -1;
+
+    vs->ds = ds;
+
+    if (keyboard_layout)
+        vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
+    else
+        vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
+
+    if (!vs->kbd_layout)
+        exit(1);
+
+    dcl->dpy_copy = vnc_dpy_copy;
+    dcl->dpy_update = vnc_dpy_update;
+    dcl->dpy_resize = vnc_dpy_resize;
+    dcl->dpy_setdata = vnc_dpy_setdata;
+    register_displaychangelistener(ds, dcl);
+}
+
+
+void vnc_display_close(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    if (!vs)
+        return;
+    if (vs->display) {
+        qemu_free(vs->display);
+        vs->display = NULL;
+    }
+    if (vs->lsock != -1) {
+        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
+        close(vs->lsock);
+        vs->lsock = -1;
+    }
+    vs->auth = VNC_AUTH_INVALID;
+#ifdef CONFIG_VNC_TLS
+    vs->subauth = VNC_AUTH_INVALID;
+    vs->tls.x509verify = 0;
+#endif
+}
+
+int vnc_display_password(DisplayState *ds, const char *password)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+    if (vs->password) {
+        qemu_free(vs->password);
+        vs->password = NULL;
+    }
+    if (password && password[0]) {
+        if (!(vs->password = qemu_strdup(password)))
+            return -1;
+    }
+
+    return 0;
+}
+
+char *vnc_display_local_addr(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    
+    return vnc_socket_local_addr("%s:%s", vs->lsock);
+}
+
+int vnc_display_open(DisplayState *ds, const char *display)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    const char *options;
+    int password = 0;
+    int reverse = 0;
+    int to_port = 0;
+#ifdef CONFIG_VNC_TLS
+    int tls = 0, x509 = 0;
+#endif
+#ifdef CONFIG_VNC_SASL
+    int sasl = 0;
+    int saslErr;
+#endif
+    int acl = 0;
+
+    if (!vnc_display)
+        return -1;
+    vnc_display_close(ds);
+    if (strcmp(display, "none") == 0)
+        return 0;
+
+    if (!(vs->display = strdup(display)))
+        return -1;
+
+    options = display;
+    while ((options = strchr(options, ','))) {
+        options++;
+        if (strncmp(options, "password", 8) == 0) {
+            password = 1; /* Require password auth */
+        } else if (strncmp(options, "reverse", 7) == 0) {
+            reverse = 1;
+        } else if (strncmp(options, "to=", 3) == 0) {
+            to_port = atoi(options+3) + 5900;
+#ifdef CONFIG_VNC_SASL
+        } else if (strncmp(options, "sasl", 4) == 0) {
+            sasl = 1; /* Require SASL auth */
+#endif
+#ifdef CONFIG_VNC_TLS
+        } else if (strncmp(options, "tls", 3) == 0) {
+            tls = 1; /* Require TLS */
+        } else if (strncmp(options, "x509", 4) == 0) {
+            char *start, *end;
+            x509 = 1; /* Require x509 certificates */
+            if (strncmp(options, "x509verify", 10) == 0)
+                vs->tls.x509verify = 1; /* ...and verify client certs */
+
+            /* Now check for 'x509=/some/path' postfix
+             * and use that to setup x509 certificate/key paths */
+            start = strchr(options, '=');
+            end = strchr(options, ',');
+            if (start && (!end || (start < end))) {
+                int len = end ? end-(start+1) : strlen(start+1);
+                char *path = qemu_strndup(start + 1, len);
+
+                VNC_DEBUG("Trying certificate path '%s'\n", path);
+                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
+                    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
+                    qemu_free(path);
+                    qemu_free(vs->display);
+                    vs->display = NULL;
+                    return -1;
+                }
+                qemu_free(path);
+            } else {
+                fprintf(stderr, "No certificate path provided\n");
+                qemu_free(vs->display);
+                vs->display = NULL;
+                return -1;
+            }
+#endif
+        } else if (strncmp(options, "acl", 3) == 0) {
+            acl = 1;
+        }
+    }
+
+#ifdef CONFIG_VNC_TLS
+    if (acl && x509 && vs->tls.x509verify) {
+        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
+            fprintf(stderr, "Failed to create x509 dname ACL\n");
+            exit(1);
+        }
+    }
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (acl && sasl) {
+        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
+            fprintf(stderr, "Failed to create username ACL\n");
+            exit(1);
+        }
+    }
+#endif
+
+    /*
+     * Combinations we support here:
+     *
+     *  - no-auth                (clear text, no auth)
+     *  - password               (clear text, weak auth)
+     *  - sasl                   (encrypt, good auth *IF* using Kerberos via GSSAPI)
+     *  - tls                    (encrypt, weak anonymous creds, no auth)
+     *  - tls + password         (encrypt, weak anonymous creds, weak auth)
+     *  - tls + sasl             (encrypt, weak anonymous creds, good auth)
+     *  - tls + x509             (encrypt, good x509 creds, no auth)
+     *  - tls + x509 + password  (encrypt, good x509 creds, weak auth)
+     *  - tls + x509 + sasl      (encrypt, good x509 creds, good auth)
+     *
+     * NB1. TLS is a stackable auth scheme.
+     * NB2. the x509 schemes have option to validate a client cert dname
+     */
+    if (password) {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+            VNC_DEBUG("Initializing VNC server with password auth\n");
+            vs->auth = VNC_AUTH_VNC;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    } else if (sasl) {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+            VNC_DEBUG("Initializing VNC server with SASL auth\n");
+            vs->auth = VNC_AUTH_SASL;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#endif /* CONFIG_VNC_SASL */
+    } else {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+            }
+        } else {
+#endif
+            VNC_DEBUG("Initializing VNC server with no auth\n");
+            vs->auth = VNC_AUTH_NONE;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif
+    }
+
+#ifdef CONFIG_VNC_SASL
+    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
+        fprintf(stderr, "Failed to initialize SASL auth %s",
+                sasl_errstring(saslErr, NULL, NULL));
+        free(vs->display);
+        vs->display = NULL;
+        return -1;
+    }
+#endif
+
+    if (reverse) {
+        /* connect to viewer */
+        if (strncmp(display, "unix:", 5) == 0)
+            vs->lsock = unix_connect(display+5);
+        else
+            vs->lsock = inet_connect(display, SOCKET_STREAM);
+        if (-1 == vs->lsock) {
+            free(vs->display);
+            vs->display = NULL;
+            return -1;
+        } else {
+            int csock = vs->lsock;
+            vs->lsock = -1;
+            vnc_connect(vs, csock);
+        }
+        return 0;
+
+    } else {
+        /* listen for connects */
+        char *dpy;
+        dpy = qemu_malloc(256);
+        if (strncmp(display, "unix:", 5) == 0) {
+            pstrcpy(dpy, 256, "unix:");
+            vs->lsock = unix_listen(display+5, dpy+5, 256-5);
+        } else {
+            vs->lsock = inet_listen(display, dpy, 256, SOCKET_STREAM, 5900);
+        }
+        if (-1 == vs->lsock) {
+            free(dpy);
+            return -1;
+        } else {
+            free(vs->display);
+            vs->display = dpy;
+        }
+    }
+    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
+}
diff --git a/vnc-tls.h b/vnc-tls.h
new file mode 100644
index 0000000..2b93633
--- /dev/null
+++ b/vnc-tls.h
@@ -0,0 +1,76 @@
+/*
+ * QEMU VNC display driver. TLS helpers
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#ifndef __QEMU_VNC_TLS_H__
+#define __QEMU_VNC_TLS_H__
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "acl.h"
+
+enum {
+    VNC_WIREMODE_CLEAR,
+    VNC_WIREMODE_TLS,
+};
+
+typedef struct VncDisplayTLS VncDisplayTLS;
+typedef struct VncStateTLS VncStateTLS;
+
+/* Server state */
+struct VncDisplayTLS {
+    int x509verify; /* Non-zero if server requests & validates client cert */
+    qemu_acl *acl;
+
+    /* Paths to x509 certs/keys */
+    char *x509cacert;
+    char *x509cacrl;
+    char *x509cert;
+    char *x509key;
+};
+
+/* Per client state */
+struct VncStateTLS {
+    /* Whether data is being TLS encrypted yet */
+    int wiremode;
+    gnutls_session_t session;
+
+    /* Client's Distinguished Name from the x509 cert */
+    char *dname;
+};
+
+int vnc_tls_client_setup(VncState *vs, int x509Creds);
+void vnc_tls_client_cleanup(VncState *vs);
+
+int vnc_tls_validate_certificate(VncState *vs);
+
+int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
+			       const char *path);
+
+
+#endif /* __QEMU_VNC_TLS_H__ */
+
diff --git a/vnc.c b/vnc.c
index 8b7d19f..de0ff87 100644
--- a/vnc.c
+++ b/vnc.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
  * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -23,174 +24,188 @@
  * THE SOFTWARE.
  */
 
-#include "qemu-common.h"
-#include "console.h"
+#include "vnc.h"
 #include "sysemu.h"
 #include "qemu_socket.h"
 #include "qemu-timer.h"
+#include "acl.h"
 
 #define VNC_REFRESH_INTERVAL (1000 / 30)
 
 #include "vnc_keysym.h"
-#include "keymaps.c"
 #include "d3des.h"
 
-#ifdef CONFIG_VNC_TLS
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-#endif /* CONFIG_VNC_TLS */
-
-// #define _VNC_DEBUG 1
-
-#ifdef _VNC_DEBUG
-#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-
-#if CONFIG_VNC_TLS && _VNC_DEBUG >= 2
-/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
-static void vnc_debug_gnutls_log(int level, const char* str) {
-    VNC_DEBUG("%d %s", level, str);
+#define count_bits(c, v) { \
+    for (c = 0; v; v >>= 1) \
+    { \
+        c += v & 1; \
+    } \
 }
-#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
-#else
-#define VNC_DEBUG(fmt, ...) do { } while (0)
-#endif
 
 
-typedef struct Buffer
-{
-    size_t capacity;
-    size_t offset;
-    uint8_t *buffer;
-} Buffer;
+static VncDisplay *vnc_display; /* needed for info vnc */
+static DisplayChangeListener *dcl;
 
-typedef struct VncState VncState;
+static char *addr_to_string(const char *format,
+                            struct sockaddr_storage *sa,
+                            socklen_t salen) {
+    char *addr;
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    int err;
+    size_t addrlen;
 
-typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
-
-typedef void VncWritePixels(VncState *vs, void *data, int size);
-
-typedef void VncSendHextileTile(VncState *vs,
-                                int x, int y, int w, int h,
-                                void *last_bg,
-                                void *last_fg,
-                                int *has_bg, int *has_fg);
-
-#define VNC_MAX_WIDTH 2048
-#define VNC_MAX_HEIGHT 2048
-#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
-
-#define VNC_AUTH_CHALLENGE_SIZE 16
-
-enum {
-    VNC_AUTH_INVALID = 0,
-    VNC_AUTH_NONE = 1,
-    VNC_AUTH_VNC = 2,
-    VNC_AUTH_RA2 = 5,
-    VNC_AUTH_RA2NE = 6,
-    VNC_AUTH_TIGHT = 16,
-    VNC_AUTH_ULTRA = 17,
-    VNC_AUTH_TLS = 18,
-    VNC_AUTH_VENCRYPT = 19
-};
-
-#ifdef CONFIG_VNC_TLS
-enum {
-    VNC_WIREMODE_CLEAR,
-    VNC_WIREMODE_TLS,
-};
-
-enum {
-    VNC_AUTH_VENCRYPT_PLAIN = 256,
-    VNC_AUTH_VENCRYPT_TLSNONE = 257,
-    VNC_AUTH_VENCRYPT_TLSVNC = 258,
-    VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
-    VNC_AUTH_VENCRYPT_X509NONE = 260,
-    VNC_AUTH_VENCRYPT_X509VNC = 261,
-    VNC_AUTH_VENCRYPT_X509PLAIN = 262,
-};
-
-#define X509_CA_CERT_FILE "ca-cert.pem"
-#define X509_CA_CRL_FILE "ca-crl.pem"
-#define X509_SERVER_KEY_FILE "server-key.pem"
-#define X509_SERVER_CERT_FILE "server-cert.pem"
-
-#endif /* CONFIG_VNC_TLS */
-
-struct VncState
-{
-    QEMUTimer *timer;
-    int lsock;
-    int csock;
-    DisplayState *ds;
-    int need_update;
-    int width;
-    int height;
-    uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
-    char *old_data;
-    int depth; /* internal VNC frame buffer byte per pixel */
-    int has_resize;
-    int has_hextile;
-    int has_pointer_type_change;
-    int has_WMVi;
-    int absolute;
-    int last_x;
-    int last_y;
-
-    int major;
-    int minor;
-
-    char *display;
-    char *password;
-    int auth;
-#ifdef CONFIG_VNC_TLS
-    int subauth;
-    int x509verify;
-
-    char *x509cacert;
-    char *x509cacrl;
-    char *x509cert;
-    char *x509key;
-#endif
-    char challenge[VNC_AUTH_CHALLENGE_SIZE];
-
-#ifdef CONFIG_VNC_TLS
-    int wiremode;
-    gnutls_session_t tls_session;
-#endif
-
-    Buffer output;
-    Buffer input;
-    kbd_layout_t *kbd_layout;
-    /* current output mode information */
-    VncWritePixels *write_pixels;
-    VncSendHextileTile *send_hextile_tile;
-    int pix_bpp, pix_big_endian;
-    int client_red_shift, client_red_max, server_red_shift, server_red_max;
-    int client_green_shift, client_green_max, server_green_shift, server_green_max;
-    int client_blue_shift, client_blue_max, server_blue_shift, server_blue_max;
-
-    VncReadEvent *read_handler;
-    size_t read_handler_expect;
-    /* input */
-    uint8_t modifiers_state[256];
-};
-
-static VncState *vnc_state; /* needed for info vnc */
-
-void do_info_vnc(void)
-{
-    if (vnc_state == NULL)
-	term_printf("VNC server disabled\n");
-    else {
-	term_printf("VNC server active on: ");
-	term_print_filename(vnc_state->display);
-	term_printf("\n");
-
-	if (vnc_state->csock == -1)
-	    term_printf("No client connected\n");
-	else
-	    term_printf("Client connected\n");
+    if ((err = getnameinfo((struct sockaddr *)sa, salen,
+                           host, sizeof(host),
+                           serv, sizeof(serv),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+        VNC_DEBUG("Cannot resolve address %d: %s\n",
+                  err, gai_strerror(err));
+        return NULL;
     }
+
+    /* Enough for the existing format + the 2 vars we're
+     * substituting in. */
+    addrlen = strlen(format) + strlen(host) + strlen(serv);
+    addr = qemu_malloc(addrlen + 1);
+    snprintf(addr, addrlen, format, host, serv);
+    addr[addrlen] = '\0';
+
+    return addr;
+}
+
+
+char *vnc_socket_local_addr(const char *format, int fd) {
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa, salen);
+}
+
+char *vnc_socket_remote_addr(const char *format, int fd) {
+    struct sockaddr_storage sa;
+    socklen_t salen;
+
+    salen = sizeof(sa);
+    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
+        return NULL;
+
+    return addr_to_string(format, &sa, salen);
+}
+
+static const char *vnc_auth_name(VncDisplay *vd) {
+    switch (vd->auth) {
+    case VNC_AUTH_INVALID:
+        return "invalid";
+    case VNC_AUTH_NONE:
+        return "none";
+    case VNC_AUTH_VNC:
+        return "vnc";
+    case VNC_AUTH_RA2:
+        return "ra2";
+    case VNC_AUTH_RA2NE:
+        return "ra2ne";
+    case VNC_AUTH_TIGHT:
+        return "tight";
+    case VNC_AUTH_ULTRA:
+        return "ultra";
+    case VNC_AUTH_TLS:
+        return "tls";
+    case VNC_AUTH_VENCRYPT:
+#ifdef CONFIG_VNC_TLS
+        switch (vd->subauth) {
+        case VNC_AUTH_VENCRYPT_PLAIN:
+            return "vencrypt+plain";
+        case VNC_AUTH_VENCRYPT_TLSNONE:
+            return "vencrypt+tls+none";
+        case VNC_AUTH_VENCRYPT_TLSVNC:
+            return "vencrypt+tls+vnc";
+        case VNC_AUTH_VENCRYPT_TLSPLAIN:
+            return "vencrypt+tls+plain";
+        case VNC_AUTH_VENCRYPT_X509NONE:
+            return "vencrypt+x509+none";
+        case VNC_AUTH_VENCRYPT_X509VNC:
+            return "vencrypt+x509+vnc";
+        case VNC_AUTH_VENCRYPT_X509PLAIN:
+            return "vencrypt+x509+plain";
+        case VNC_AUTH_VENCRYPT_TLSSASL:
+            return "vencrypt+tls+sasl";
+        case VNC_AUTH_VENCRYPT_X509SASL:
+            return "vencrypt+x509+sasl";
+        default:
+            return "vencrypt";
+        }
+#else
+        return "vencrypt";
+#endif
+    case VNC_AUTH_SASL:
+        return "sasl";
+    }
+    return "unknown";
+}
+
+static void do_info_vnc_client(Monitor *mon, VncState *client)
+{
+    char *clientAddr =
+        vnc_socket_remote_addr("     address: %s:%s\n",
+                               client->csock);
+    if (!clientAddr)
+        return;
+
+    monitor_printf(mon, "Client:\n");
+    monitor_printf(mon, "%s", clientAddr);
+    free(clientAddr);
+
+#ifdef CONFIG_VNC_TLS
+    if (client->tls.session &&
+        client->tls.dname)
+        monitor_printf(mon, "  x509 dname: %s\n", client->tls.dname);
+    else
+        monitor_printf(mon, "  x509 dname: none\n");
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (client->sasl.conn &&
+        client->sasl.username)
+        monitor_printf(mon, "    username: %s\n", client->sasl.username);
+    else
+        monitor_printf(mon, "    username: none\n");
+#endif
+}
+
+void do_info_vnc(Monitor *mon)
+{
+    if (vnc_display == NULL || vnc_display->display == NULL) {
+        monitor_printf(mon, "Server: disabled\n");
+    } else {
+        char *serverAddr = vnc_socket_local_addr("     address: %s:%s\n",
+                                                 vnc_display->lsock);
+
+        if (!serverAddr)
+            return;
+
+        monitor_printf(mon, "Server:\n");
+        monitor_printf(mon, "%s", serverAddr);
+        free(serverAddr);
+        monitor_printf(mon, "        auth: %s\n", vnc_auth_name(vnc_display));
+
+        if (vnc_display->clients) {
+            VncState *client = vnc_display->clients;
+            while (client) {
+                do_info_vnc_client(mon, client);
+                client = client->next;
+            }
+        } else {
+            monitor_printf(mon, "Client: none\n");
+        }
+    }
+}
+
+static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
+    return (vs->features & (1 << feature));
 }
 
 /* TODO
@@ -200,16 +215,11 @@
    3) resolutions > 1024
 */
 
-static void vnc_write(VncState *vs, const void *data, size_t len);
-static void vnc_write_u32(VncState *vs, uint32_t value);
-static void vnc_write_s32(VncState *vs, int32_t value);
-static void vnc_write_u16(VncState *vs, uint16_t value);
-static void vnc_write_u8(VncState *vs, uint8_t value);
-static void vnc_flush(VncState *vs);
 static void vnc_update_client(void *opaque);
-static void vnc_client_read(void *opaque);
+static void vnc_disconnect_start(VncState *vs);
+static void vnc_disconnect_finish(VncState *vs);
 
-static void vnc_colordepth(DisplayState *ds, int depth);
+static void vnc_colordepth(VncState *vs);
 
 static inline void vnc_set_bit(uint32_t *d, int k)
 {
@@ -252,9 +262,9 @@
     return 0;
 }
 
-static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+static void vnc_update(VncState *vs, int x, int y, int w, int h)
 {
-    VncState *vs = ds->opaque;
+    struct VncSurface *s = &vs->guest;
     int i;
 
     h += y;
@@ -266,18 +276,28 @@
     w += (x % 16);
     x -= (x % 16);
 
-    x = MIN(x, vs->width);
-    y = MIN(y, vs->height);
-    w = MIN(x + w, vs->width) - x;
-    h = MIN(h, vs->height);
+    x = MIN(x, s->ds->width);
+    y = MIN(y, s->ds->height);
+    w = MIN(x + w, s->ds->width) - x;
+    h = MIN(h, s->ds->height);
 
     for (; y < h; y++)
-	for (i = 0; i < w; i += 16)
-	    vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
+        for (i = 0; i < w; i += 16)
+            vnc_set_bit(s->dirty[y], (x + i) / 16);
+}
+
+static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs = vd->clients;
+    while (vs != NULL) {
+        vnc_update(vs, x, y, w, h);
+        vs = vs->next;
+    }
 }
 
 static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
-				   int32_t encoding)
+                                   int32_t encoding)
 {
     vnc_write_u16(vs, x);
     vnc_write_u16(vs, y);
@@ -287,41 +307,84 @@
     vnc_write_s32(vs, encoding);
 }
 
-static void vnc_dpy_resize(DisplayState *ds, int w, int h)
+void buffer_reserve(Buffer *buffer, size_t len)
 {
+    if ((buffer->capacity - buffer->offset) < len) {
+        buffer->capacity += (len + 1024);
+        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
+        if (buffer->buffer == NULL) {
+            fprintf(stderr, "vnc: out of memory\n");
+            exit(1);
+        }
+    }
+}
+
+int buffer_empty(Buffer *buffer)
+{
+    return buffer->offset == 0;
+}
+
+uint8_t *buffer_end(Buffer *buffer)
+{
+    return buffer->buffer + buffer->offset;
+}
+
+void buffer_reset(Buffer *buffer)
+{
+        buffer->offset = 0;
+}
+
+void buffer_append(Buffer *buffer, const void *data, size_t len)
+{
+    memcpy(buffer->buffer + buffer->offset, data, len);
+    buffer->offset += len;
+}
+
+static void vnc_resize(VncState *vs)
+{
+    DisplayState *ds = vs->ds;
     int size_changed;
-    VncState *vs = ds->opaque;
 
-    ds->data = qemu_realloc(ds->data, w * h * vs->depth);
-    vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth);
-
-    if (ds->data == NULL || vs->old_data == NULL) {
-	fprintf(stderr, "vnc: memory allocation failed\n");
-	exit(1);
-    }
-
-    if (ds->depth != vs->depth * 8) {
-        ds->depth = vs->depth * 8;
+    /* guest surface */
+    if (!vs->guest.ds)
+        vs->guest.ds = qemu_mallocz(sizeof(*vs->guest.ds));
+    if (ds_get_bytes_per_pixel(ds) != vs->guest.ds->pf.bytes_per_pixel)
         console_color_init(ds);
-    }
-    size_changed = ds->width != w || ds->height != h;
-    ds->width = w;
-    ds->height = h;
-    ds->linesize = w * vs->depth;
+    vnc_colordepth(vs);
+    size_changed = ds_get_width(ds) != vs->guest.ds->width ||
+                   ds_get_height(ds) != vs->guest.ds->height;
+    *(vs->guest.ds) = *(ds->surface);
     if (size_changed) {
-        vs->width = ds->width;
-        vs->height = ds->height;
-        if (vs->csock != -1 && vs->has_resize) {
+        if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
             vnc_write_u8(vs, 0);  /* msg id */
             vnc_write_u8(vs, 0);
             vnc_write_u16(vs, 1); /* number of rects */
-            vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223);
+            vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
+                                   VNC_ENCODING_DESKTOPRESIZE);
             vnc_flush(vs);
         }
     }
+    memset(vs->guest.dirty, 0xFF, sizeof(vs->guest.dirty));
 
-    memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
-    memset(vs->old_data, 42, vs->ds->linesize * vs->ds->height);
+    /* server surface */
+    if (!vs->server.ds)
+        vs->server.ds = qemu_mallocz(sizeof(*vs->server.ds));
+    if (vs->server.ds->data)
+        qemu_free(vs->server.ds->data);
+    *(vs->server.ds) = *(ds->surface);
+    vs->server.ds->data = qemu_mallocz(vs->server.ds->linesize *
+                                       vs->server.ds->height);
+    memset(vs->server.dirty, 0xFF, sizeof(vs->guest.dirty));
+}
+
+static void vnc_dpy_resize(DisplayState *ds)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs = vd->clients;
+    while (vs != NULL) {
+        vnc_resize(vs);
+        vs = vs->next;
+    }
 }
 
 /* fastest code */
@@ -335,21 +398,21 @@
 {
     uint8_t r, g, b;
 
-    r = ((v >> vs->server_red_shift) & vs->server_red_max) * (vs->client_red_max + 1) /
-        (vs->server_red_max + 1);
-    g = ((v >> vs->server_green_shift) & vs->server_green_max) * (vs->client_green_max + 1) /
-        (vs->server_green_max + 1);
-    b = ((v >> vs->server_blue_shift) & vs->server_blue_max) * (vs->client_blue_max + 1) /
-        (vs->server_blue_max + 1);
-    v = (r << vs->client_red_shift) |
-        (g << vs->client_green_shift) |
-        (b << vs->client_blue_shift);
-    switch(vs->pix_bpp) {
+    r = ((((v & vs->server.ds->pf.rmask) >> vs->server.ds->pf.rshift) << vs->clientds.pf.rbits) >>
+        vs->server.ds->pf.rbits);
+    g = ((((v & vs->server.ds->pf.gmask) >> vs->server.ds->pf.gshift) << vs->clientds.pf.gbits) >>
+        vs->server.ds->pf.gbits);
+    b = ((((v & vs->server.ds->pf.bmask) >> vs->server.ds->pf.bshift) << vs->clientds.pf.bbits) >>
+        vs->server.ds->pf.bbits);
+    v = (r << vs->clientds.pf.rshift) |
+        (g << vs->clientds.pf.gshift) |
+        (b << vs->clientds.pf.bshift);
+    switch(vs->clientds.pf.bytes_per_pixel) {
     case 1:
         buf[0] = v;
         break;
     case 2:
-        if (vs->pix_big_endian) {
+        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
             buf[0] = v >> 8;
             buf[1] = v;
         } else {
@@ -359,7 +422,7 @@
         break;
     default:
     case 4:
-        if (vs->pix_big_endian) {
+        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
             buf[0] = v >> 24;
             buf[1] = v >> 16;
             buf[2] = v >> 8;
@@ -378,29 +441,29 @@
 {
     uint8_t buf[4];
 
-    if (vs->depth == 4) {
+    if (vs->server.ds->pf.bytes_per_pixel == 4) {
         uint32_t *pixels = pixels1;
         int n, i;
         n = size >> 2;
         for(i = 0; i < n; i++) {
             vnc_convert_pixel(vs, buf, pixels[i]);
-            vnc_write(vs, buf, vs->pix_bpp);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }
-    } else if (vs->depth == 2) {
+    } else if (vs->server.ds->pf.bytes_per_pixel == 2) {
         uint16_t *pixels = pixels1;
         int n, i;
         n = size >> 1;
         for(i = 0; i < n; i++) {
             vnc_convert_pixel(vs, buf, pixels[i]);
-            vnc_write(vs, buf, vs->pix_bpp);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }
-    } else if (vs->depth == 1) {
+    } else if (vs->server.ds->pf.bytes_per_pixel == 1) {
         uint8_t *pixels = pixels1;
         int n, i;
         n = size;
         for(i = 0; i < n; i++) {
             vnc_convert_pixel(vs, buf, pixels[i]);
-            vnc_write(vs, buf, vs->pix_bpp);
+            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }
     } else {
         fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
@@ -412,12 +475,10 @@
     int i;
     uint8_t *row;
 
-    vnc_framebuffer_update(vs, x, y, w, h, 0);
-
-    row = vs->ds->data + y * vs->ds->linesize + x * vs->depth;
+    row = vs->server.ds->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
     for (i = 0; i < h; i++) {
-	vs->write_pixels(vs, row, w * vs->depth);
-	row += vs->ds->linesize;
+        vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
+        row += ds_get_linesize(vs->ds);
     }
 }
 
@@ -463,82 +524,178 @@
     int has_fg, has_bg;
     uint8_t *last_fg, *last_bg;
 
-    vnc_framebuffer_update(vs, x, y, w, h, 5);
-
-    last_fg = (uint8_t *) malloc(vs->depth);
-    last_bg = (uint8_t *) malloc(vs->depth);
+    last_fg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
+    last_bg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
     has_fg = has_bg = 0;
     for (j = y; j < (y + h); j += 16) {
-	for (i = x; i < (x + w); i += 16) {
+        for (i = x; i < (x + w); i += 16) {
             vs->send_hextile_tile(vs, i, j,
                                   MIN(16, x + w - i), MIN(16, y + h - j),
                                   last_bg, last_fg, &has_bg, &has_fg);
-	}
+        }
     }
     free(last_fg);
     free(last_bg);
 
 }
 
-static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+static void vnc_zlib_init(VncState *vs)
 {
-	if (vs->has_hextile)
-	    send_framebuffer_update_hextile(vs, x, y, w, h);
-	else
-	    send_framebuffer_update_raw(vs, x, y, w, h);
+    int i;
+    for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
+        vs->zlib_stream[i].opaque = NULL;
 }
 
-static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+static void vnc_zlib_start(VncState *vs)
 {
-    int src, dst;
-    uint8_t *src_row;
-    uint8_t *dst_row;
-    char *old_row;
-    int y = 0;
-    int pitch = ds->linesize;
-    VncState *vs = ds->opaque;
+    buffer_reset(&vs->zlib);
 
-    vnc_update_client(vs);
+    // make the output buffer be the zlib buffer, so we can compress it later
+    vs->zlib_tmp = vs->output;
+    vs->output = vs->zlib;
+}
 
-    if (dst_y > src_y) {
-	y = h - 1;
-	pitch = -pitch;
+static int vnc_zlib_stop(VncState *vs, int stream_id)
+{
+    z_streamp zstream = &vs->zlib_stream[stream_id];
+    int previous_out;
+
+    // switch back to normal output/zlib buffers
+    vs->zlib = vs->output;
+    vs->output = vs->zlib_tmp;
+
+    // compress the zlib buffer
+
+    // initialize the stream
+    // XXX need one stream per session
+    if (zstream->opaque != vs) {
+        int err;
+
+        VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
+        VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
+        zstream->zalloc = Z_NULL;
+        zstream->zfree = Z_NULL;
+
+        err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
+                           MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+        if (err != Z_OK) {
+            fprintf(stderr, "VNC: error initializing zlib\n");
+            return -1;
+        }
+
+        zstream->opaque = vs;
     }
 
-    src = (ds->linesize * (src_y + y) + vs->depth * src_x);
-    dst = (ds->linesize * (dst_y + y) + vs->depth * dst_x);
+    // XXX what to do if tight_compression changed in between?
 
-    src_row = ds->data + src;
-    dst_row = ds->data + dst;
-    old_row = vs->old_data + dst;
+    // reserve memory in output buffer
+    buffer_reserve(&vs->output, vs->zlib.offset + 64);
 
-    for (y = 0; y < h; y++) {
-	memmove(old_row, src_row, w * vs->depth);
-	memmove(dst_row, src_row, w * vs->depth);
-	src_row += pitch;
-	dst_row += pitch;
-	old_row += pitch;
+    // set pointers
+    zstream->next_in = vs->zlib.buffer;
+    zstream->avail_in = vs->zlib.offset;
+    zstream->next_out = vs->output.buffer + vs->output.offset;
+    zstream->avail_out = vs->output.capacity - vs->output.offset;
+    zstream->data_type = Z_BINARY;
+    previous_out = zstream->total_out;
+
+    // start encoding
+    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
+        fprintf(stderr, "VNC: error during zlib compression\n");
+        return -1;
     }
 
+    vs->output.offset = vs->output.capacity - zstream->avail_out;
+    return zstream->total_out - previous_out;
+}
+
+static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
+{
+    int old_offset, new_offset, bytes_written;
+
+    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
+
+    // remember where we put in the follow-up size
+    old_offset = vs->output.offset;
+    vnc_write_s32(vs, 0);
+
+    // compress the stream
+    vnc_zlib_start(vs);
+    send_framebuffer_update_raw(vs, x, y, w, h);
+    bytes_written = vnc_zlib_stop(vs, 0);
+
+    if (bytes_written == -1)
+        return;
+
+    // hack in the size
+    new_offset = vs->output.offset;
+    vs->output.offset = old_offset;
+    vnc_write_u32(vs, bytes_written);
+    vs->output.offset = new_offset;
+}
+
+static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+{
+    switch(vs->vnc_encoding) {
+        case VNC_ENCODING_ZLIB:
+            send_framebuffer_update_zlib(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
+            send_framebuffer_update_hextile(vs, x, y, w, h);
+            break;
+        default:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
+            send_framebuffer_update_raw(vs, x, y, w, h);
+            break;
+    }
+}
+
+static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
     vnc_write_u8(vs, 0);  /* msg id */
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1); /* number of rects */
-    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, 1);
+    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
     vnc_write_u16(vs, src_x);
     vnc_write_u16(vs, src_y);
     vnc_flush(vs);
 }
 
-static int find_dirty_height(VncState *vs, int y, int last_x, int x)
+static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs, *vn;
+
+    for (vs = vd->clients; vs != NULL; vs = vn) {
+        vn = vs->next;
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+            vs->force_update = 1;
+            vnc_update_client(vs);
+            /* vs might be free()ed here */
+        }
+    }
+
+    for (vs = vd->clients; vs != NULL; vs = vs->next) {
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
+            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
+        else /* TODO */
+            vnc_update(vs, dst_x, dst_y, w, h);
+    }
+}
+
+static int find_and_clear_dirty_height(struct VncSurface *s,
+                                       int y, int last_x, int x)
 {
     int h;
 
-    for (h = 1; h < (vs->height - y); h++) {
-	int tmp_x;
-	if (!vnc_get_bit(vs->dirty_row[y + h], last_x))
-	    break;
-	for (tmp_x = last_x; tmp_x < x; tmp_x++)
-	    vnc_clear_bit(vs->dirty_row[y + h], tmp_x);
+    for (h = 1; h < (s->ds->height - y); h++) {
+        int tmp_x;
+        if (!vnc_get_bit(s->dirty[y + h], last_x))
+            break;
+        for (tmp_x = last_x; tmp_x < x; tmp_x++)
+            vnc_clear_bit(s->dirty[y + h], tmp_x);
     }
 
     return h;
@@ -547,141 +704,224 @@
 static void vnc_update_client(void *opaque)
 {
     VncState *vs = opaque;
-
     if (vs->need_update && vs->csock != -1) {
-	int y;
-	uint8_t *row;
-	char *old_row;
-	uint32_t width_mask[VNC_DIRTY_WORDS];
-	int n_rectangles;
-	int saved_offset;
-	int has_dirty = 0;
+        int y;
+        uint8_t *guest_row;
+        uint8_t *server_row;
+        int cmp_bytes;
+        uint32_t width_mask[VNC_DIRTY_WORDS];
+        int n_rectangles;
+        int saved_offset;
+        int has_dirty = 0;
+
+        if (vs->output.offset && !vs->audio_cap && !vs->force_update) {
+            /* kernel send buffers are full -> drop frames to throttle */
+            qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+            return;
+        }
 
         vga_hw_update();
 
-        vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS);
+        /*
+         * Walk through the guest dirty map.
+         * Check and copy modified bits from guest to server surface.
+         * Update server dirty map.
+         */
+        vnc_set_bits(width_mask, (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+        cmp_bytes = 16 * ds_get_bytes_per_pixel(vs->ds);
+        guest_row  = vs->guest.ds->data;
+        server_row = vs->server.ds->data;
+        for (y = 0; y < vs->guest.ds->height; y++) {
+            if (vnc_and_bits(vs->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
+                int x;
+                uint8_t *guest_ptr;
+                uint8_t *server_ptr;
 
-	/* Walk through the dirty map and eliminate tiles that
-	   really aren't dirty */
-	row = vs->ds->data;
-	old_row = vs->old_data;
+                guest_ptr  = guest_row;
+                server_ptr = server_row;
 
-	for (y = 0; y < vs->height; y++) {
-	    if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) {
-		int x;
-		uint8_t *ptr;
-		char *old_ptr;
+                for (x = 0; x < vs->guest.ds->width;
+                     x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
+                    if (!vnc_get_bit(vs->guest.dirty[y], (x / 16)))
+                        continue;
+                    vnc_clear_bit(vs->guest.dirty[y], (x / 16));
+                    if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
+                        continue;
+                    memcpy(server_ptr, guest_ptr, cmp_bytes);
+                    vnc_set_bit(vs->server.dirty[y], (x / 16));
+                    has_dirty++;
+                }
+            }
+            guest_row  += ds_get_linesize(vs->ds);
+            server_row += ds_get_linesize(vs->ds);
+        }
 
-		ptr = row;
-		old_ptr = (char*)old_row;
+        if (!has_dirty && !vs->audio_cap && !vs->force_update) {
+            qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+            return;
+        }
 
-		for (x = 0; x < vs->ds->width; x += 16) {
-		    if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) {
-			vnc_clear_bit(vs->dirty_row[y], (x / 16));
-		    } else {
-			has_dirty = 1;
-			memcpy(old_ptr, ptr, 16 * vs->depth);
-		    }
+        /*
+         * Send screen updates to the vnc client using the server
+         * surface and server dirty map.  guest surface updates
+         * happening in parallel don't disturb us, the next pass will
+         * send them to the client.
+         */
+        n_rectangles = 0;
+        vnc_write_u8(vs, 0);  /* msg id */
+        vnc_write_u8(vs, 0);
+        saved_offset = vs->output.offset;
+        vnc_write_u16(vs, 0);
 
-		    ptr += 16 * vs->depth;
-		    old_ptr += 16 * vs->depth;
-		}
-	    }
-
-	    row += vs->ds->linesize;
-	    old_row += vs->ds->linesize;
-	}
-
-	if (!has_dirty) {
-	    qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
-	    return;
-	}
-
-	/* Count rectangles */
-	n_rectangles = 0;
-	vnc_write_u8(vs, 0);  /* msg id */
-	vnc_write_u8(vs, 0);
-	saved_offset = vs->output.offset;
-	vnc_write_u16(vs, 0);
-
-	for (y = 0; y < vs->height; y++) {
-	    int x;
-	    int last_x = -1;
-	    for (x = 0; x < vs->width / 16; x++) {
-		if (vnc_get_bit(vs->dirty_row[y], x)) {
-		    if (last_x == -1) {
-			last_x = x;
-		    }
-		    vnc_clear_bit(vs->dirty_row[y], x);
-		} else {
-		    if (last_x != -1) {
-			int h = find_dirty_height(vs, y, last_x, x);
-			send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
-			n_rectangles++;
-		    }
-		    last_x = -1;
-		}
-	    }
-	    if (last_x != -1) {
-		int h = find_dirty_height(vs, y, last_x, x);
-		send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
-		n_rectangles++;
-	    }
-	}
-	vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
-	vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
-	vnc_flush(vs);
+        for (y = 0; y < vs->server.ds->height; y++) {
+            int x;
+            int last_x = -1;
+            for (x = 0; x < vs->server.ds->width / 16; x++) {
+                if (vnc_get_bit(vs->server.dirty[y], x)) {
+                    if (last_x == -1) {
+                        last_x = x;
+                    }
+                    vnc_clear_bit(vs->server.dirty[y], x);
+                } else {
+                    if (last_x != -1) {
+                        int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
+                        send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
+                        n_rectangles++;
+                    }
+                    last_x = -1;
+                }
+            }
+            if (last_x != -1) {
+                int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
+                send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
+                n_rectangles++;
+            }
+        }
+        vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+        vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
+        vnc_flush(vs);
+        vs->force_update = 0;
 
     }
 
     if (vs->csock != -1) {
         qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+    } else {
+        vnc_disconnect_finish(vs);
     }
 
 }
 
-static int vnc_listen_poll(void *opaque)
+/* audio */
+static void audio_capture_notify(void *opaque, audcnotification_e cmd)
 {
     VncState *vs = opaque;
-    if (vs->csock == -1)
-	return 1;
-    return 0;
-}
 
-static void buffer_reserve(Buffer *buffer, size_t len)
-{
-    if ((buffer->capacity - buffer->offset) < len) {
-	buffer->capacity += (len + 1024);
-	buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
-	if (buffer->buffer == NULL) {
-	    fprintf(stderr, "vnc: out of memory\n");
-	    exit(1);
-	}
+    switch (cmd) {
+    case AUD_CNOTIFY_DISABLE:
+        vnc_write_u8(vs, 255);
+        vnc_write_u8(vs, 1);
+        vnc_write_u16(vs, 0);
+        vnc_flush(vs);
+        break;
+
+    case AUD_CNOTIFY_ENABLE:
+        vnc_write_u8(vs, 255);
+        vnc_write_u8(vs, 1);
+        vnc_write_u16(vs, 1);
+        vnc_flush(vs);
+        break;
     }
 }
 
-static int buffer_empty(Buffer *buffer)
+static void audio_capture_destroy(void *opaque)
 {
-    return buffer->offset == 0;
 }
 
-static uint8_t *buffer_end(Buffer *buffer)
+static void audio_capture(void *opaque, void *buf, int size)
 {
-    return buffer->buffer + buffer->offset;
+    VncState *vs = opaque;
+
+    vnc_write_u8(vs, 255);
+    vnc_write_u8(vs, 1);
+    vnc_write_u16(vs, 2);
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
+    vnc_flush(vs);
 }
 
-static void buffer_reset(Buffer *buffer)
+static void audio_add(VncState *vs)
 {
-	buffer->offset = 0;
+    Monitor *mon = cur_mon;
+    struct audio_capture_ops ops;
+
+    if (vs->audio_cap) {
+        monitor_printf(mon, "audio already running\n");
+        return;
+    }
+
+    ops.notify = audio_capture_notify;
+    ops.destroy = audio_capture_destroy;
+    ops.capture = audio_capture;
+
+    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
+    if (!vs->audio_cap) {
+        monitor_printf(mon, "Failed to add audio capture\n");
+    }
 }
 
-static void buffer_append(Buffer *buffer, const void *data, size_t len)
+static void audio_del(VncState *vs)
 {
-    memcpy(buffer->buffer + buffer->offset, data, len);
-    buffer->offset += len;
+    if (vs->audio_cap) {
+        AUD_del_capture(vs->audio_cap, vs);
+        vs->audio_cap = NULL;
+    }
 }
 
-static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
+static void vnc_disconnect_start(VncState *vs)
+{
+    if (vs->csock == -1)
+        return;
+    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+    closesocket(vs->csock);
+    vs->csock = -1;
+}
+
+static void vnc_disconnect_finish(VncState *vs)
+{
+    qemu_del_timer(vs->timer);
+    qemu_free_timer(vs->timer);
+    if (vs->input.buffer) qemu_free(vs->input.buffer);
+    if (vs->output.buffer) qemu_free(vs->output.buffer);
+#ifdef CONFIG_VNC_TLS
+    vnc_tls_client_cleanup(vs);
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    vnc_sasl_client_cleanup(vs);
+#endif /* CONFIG_VNC_SASL */
+    audio_del(vs);
+
+    VncState *p, *parent = NULL;
+    for (p = vs->vd->clients; p != NULL; p = p->next) {
+        if (p == vs) {
+            if (parent)
+                parent->next = p->next;
+            else
+                vs->vd->clients = p->next;
+            break;
+        }
+        parent = p;
+    }
+    if (!vs->vd->clients)
+        dcl->idle = 1;
+
+    qemu_free(vs->server.ds->data);
+    qemu_free(vs->server.ds);
+    qemu_free(vs->guest.ds);
+    qemu_free(vs);
+}
+
+int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 {
     if (ret == 0 || ret == -1) {
         if (ret == -1) {
@@ -689,7 +929,7 @@
                 case EINTR:
                 case EAGAIN:
 #ifdef _WIN32
-                case EWOULDBLOCK:
+                case WSAEWOULDBLOCK:
 #endif
                     return 0;
                 default:
@@ -697,127 +937,244 @@
             }
         }
 
-	VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
-	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
-	socket_close(vs->csock);
-	vs->csock = -1;
-	vs->ds->idle = 1;
-	buffer_reset(&vs->input);
-	buffer_reset(&vs->output);
-	vs->need_update = 0;
-#ifdef CONFIG_VNC_TLS
-	if (vs->tls_session) {
-	    gnutls_deinit(vs->tls_session);
-	    vs->tls_session = NULL;
-	}
-	vs->wiremode = VNC_WIREMODE_CLEAR;
-#endif /* CONFIG_VNC_TLS */
-	return 0;
+        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
+                  ret, ret < 0 ? last_errno : 0);
+        vnc_disconnect_start(vs);
+
+        return 0;
     }
     return ret;
 }
 
-static void vnc_client_error(VncState *vs)
+
+void vnc_client_error(VncState *vs)
 {
-    vnc_client_io_error(vs, -1, EINVAL);
+    VNC_DEBUG("Closing down client sock: protocol error\n");
+    vnc_disconnect_start(vs);
 }
 
-static void vnc_client_write(void *opaque)
+
+/*
+ * Called to write a chunk of data to the client socket. The data may
+ * be the raw data, or may have already been encoded by SASL.
+ * The data will be written either straight onto the socket, or
+ * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes written, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
 {
     long ret;
-    VncState *vs = opaque;
-
 #ifdef CONFIG_VNC_TLS
-    if (vs->tls_session) {
-	ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
-	if (ret < 0) {
-	    if (ret == GNUTLS_E_AGAIN)
-		errno = EAGAIN;
-	    else
-		errno = EIO;
-	    ret = -1;
-	}
+    if (vs->tls.session) {
+        ret = gnutls_write(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
     } else
 #endif /* CONFIG_VNC_TLS */
-	ret = socket_send(vs->csock, vs->output.buffer, vs->output.offset);
-    ret = vnc_client_io_error(vs, ret, errno_str);
+        ret = send(vs->csock, (const void *)data, datalen, 0);
+    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+
+/*
+ * Called to write buffered data to the client socket, when not
+ * using any SASL SSF encryption layers. Will write as much data
+ * as possible without blocking. If all buffered data is written,
+ * will switch the FD poll() handler back to read monitoring.
+ *
+ * Returns the number of bytes written, which may be less than
+ * the buffered output data if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+static long vnc_client_write_plain(VncState *vs)
+{
+    long ret;
+
+#ifdef CONFIG_VNC_SASL
+    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
+              vs->output.buffer, vs->output.capacity, vs->output.offset,
+              vs->sasl.waitWriteSSF);
+
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        vs->sasl.waitWriteSSF) {
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
+        if (ret)
+            vs->sasl.waitWriteSSF -= ret;
+    } else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
     if (!ret)
-	return;
+        return 0;
 
     memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
     vs->output.offset -= ret;
 
     if (vs->output.offset == 0) {
-	qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
     }
+
+    return ret;
 }
 
-static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
+
+/*
+ * First function called whenever there is data to be written to
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring encryption calls)
+ */
+void vnc_client_write(void *opaque)
+{
+    long ret;
+    VncState *vs = opaque;
+
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn &&
+        vs->sasl.runSSF &&
+        !vs->sasl.waitWriteSSF)
+        ret = vnc_client_write_sasl(vs);
+    else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_write_plain(vs);
+}
+
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
 {
     vs->read_handler = func;
     vs->read_handler_expect = expecting;
 }
 
-static void vnc_client_read(void *opaque)
+
+/*
+ * Called to read a chunk of data from the client socket. The data may
+ * be the raw data, or may need to be further decoded by SASL.
+ * The data will be read either straight from to the socket, or
+ * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
+ *
+ * NB, it is theoretically possible to have 2 layers of encryption,
+ * both SASL, and this TLS layer. It is highly unlikely in practice
+ * though, since SASL encryption will typically be a no-op if TLS
+ * is active
+ *
+ * Returns the number of bytes read, which may be less than
+ * the requested 'datalen' if the socket would block. Returns
+ * -1 on error, and disconnects the client socket.
+ */
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
+{
+    long ret;
+#ifdef CONFIG_VNC_TLS
+    if (vs->tls.session) {
+        ret = gnutls_read(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
+    } else
+#endif /* CONFIG_VNC_TLS */
+        ret = recv(vs->csock, (void *)data, datalen, 0);
+    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
+    return vnc_client_io_error(vs, ret, socket_error());
+}
+
+
+/*
+ * Called to read data from the client socket to the input buffer,
+ * when not using any SASL SSF encryption layers. Will read as much
+ * data as possible without blocking.
+ *
+ * Returns the number of bytes read. Returns -1 on error, and
+ * disconnects the client socket.
+ */
+static long vnc_client_read_plain(VncState *vs)
+{
+    int ret;
+    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
+              vs->input.buffer, vs->input.capacity, vs->input.offset);
+    buffer_reserve(&vs->input, 4096);
+    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
+    if (!ret)
+        return 0;
+    vs->input.offset += ret;
+    return ret;
+}
+
+
+/*
+ * First function called whenever there is more data to be read from
+ * the client socket. Will delegate actual work according to whether
+ * SASL SSF layers are enabled (thus requiring decryption calls)
+ */
+void vnc_client_read(void *opaque)
 {
     VncState *vs = opaque;
     long ret;
 
-    buffer_reserve(&vs->input, 4096);
-
-#ifdef CONFIG_VNC_TLS
-    if (vs->tls_session) {
-	ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
-	if (ret < 0) {
-	    if (ret == GNUTLS_E_AGAIN)
-		errno = EAGAIN;
-	    else
-		errno = EIO;
-	    ret = -1;
-	}
-    } else
-#endif /* CONFIG_VNC_TLS */
-	ret = socket_recv(vs->csock, buffer_end(&vs->input), 4096);
-    ret = vnc_client_io_error(vs, ret, errno_str);
-    if (!ret)
-	return;
-
-    vs->input.offset += ret;
+#ifdef CONFIG_VNC_SASL
+    if (vs->sasl.conn && vs->sasl.runSSF)
+        ret = vnc_client_read_sasl(vs);
+    else
+#endif /* CONFIG_VNC_SASL */
+        ret = vnc_client_read_plain(vs);
+    if (!ret) {
+        if (vs->csock == -1)
+            vnc_disconnect_finish(vs);
+        return;
+    }
 
     while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
-	size_t len = vs->read_handler_expect;
-	int ret;
+        size_t len = vs->read_handler_expect;
+        int ret;
 
-	ret = vs->read_handler(vs, vs->input.buffer, len);
-	if (vs->csock == -1)
-	    return;
+        ret = vs->read_handler(vs, vs->input.buffer, len);
+        if (vs->csock == -1) {
+            vnc_disconnect_finish(vs);
+            return;
+        }
 
-	if (!ret) {
-	    memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
-	    vs->input.offset -= len;
-	} else {
-	    vs->read_handler_expect = ret;
-	}
+        if (!ret) {
+            memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
+            vs->input.offset -= len;
+        } else {
+            vs->read_handler_expect = ret;
+        }
     }
 }
 
-static void vnc_write(VncState *vs, const void *data, size_t len)
+void vnc_write(VncState *vs, const void *data, size_t len)
 {
     buffer_reserve(&vs->output, len);
 
-    if (buffer_empty(&vs->output)) {
-	qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+    if (vs->csock != -1 && buffer_empty(&vs->output)) {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
     }
 
     buffer_append(&vs->output, data, len);
 }
 
-static void vnc_write_s32(VncState *vs, int32_t value)
+void vnc_write_s32(VncState *vs, int32_t value)
 {
     vnc_write_u32(vs, *(uint32_t *)&value);
 }
 
-static void vnc_write_u32(VncState *vs, uint32_t value)
+void vnc_write_u32(VncState *vs, uint32_t value)
 {
     uint8_t buf[4];
 
@@ -829,7 +1186,7 @@
     vnc_write(vs, buf, 4);
 }
 
-static void vnc_write_u16(VncState *vs, uint16_t value)
+void vnc_write_u16(VncState *vs, uint16_t value)
 {
     uint8_t buf[2];
 
@@ -839,71 +1196,53 @@
     vnc_write(vs, buf, 2);
 }
 
-static void vnc_write_u8(VncState *vs, uint8_t value)
+void vnc_write_u8(VncState *vs, uint8_t value)
 {
     vnc_write(vs, (char *)&value, 1);
 }
 
-static void vnc_flush(VncState *vs)
+void vnc_flush(VncState *vs)
 {
-    if (vs->output.offset)
-	vnc_client_write(vs);
+    if (vs->csock != -1 && vs->output.offset)
+        vnc_client_write(vs);
 }
 
-static uint8_t read_u8(uint8_t *data, size_t offset)
+uint8_t read_u8(uint8_t *data, size_t offset)
 {
     return data[offset];
 }
 
-static uint16_t read_u16(uint8_t *data, size_t offset)
+uint16_t read_u16(uint8_t *data, size_t offset)
 {
     return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
 }
 
-static int32_t read_s32(uint8_t *data, size_t offset)
+int32_t read_s32(uint8_t *data, size_t offset)
 {
     return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
-		     (data[offset + 2] << 8) | data[offset + 3]);
+                     (data[offset + 2] << 8) | data[offset + 3]);
 }
 
-static uint32_t read_u32(uint8_t *data, size_t offset)
+uint32_t read_u32(uint8_t *data, size_t offset)
 {
     return ((data[offset] << 24) | (data[offset + 1] << 16) |
-	    (data[offset + 2] << 8) | data[offset + 3]);
+            (data[offset + 2] << 8) | data[offset + 3]);
 }
 
-#ifdef CONFIG_VNC_TLS
-static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
-                            const void *data,
-                            size_t len) {
-    struct VncState *vs = (struct VncState *)transport;
-
-    return socket_send(vs->csock, data, len);
-}
-
-
-static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
-                            void *data,
-                            size_t len) {
-    struct VncState *vs = (struct VncState *)transport;
-
-    return socket_recv(vs->csock, data, len);
-}
-#endif /* CONFIG_VNC_TLS */
-
 static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
 {
 }
 
 static void check_pointer_type_change(VncState *vs, int absolute)
 {
-    if (vs->has_pointer_type_change && vs->absolute != absolute) {
-	vnc_write_u8(vs, 0);
-	vnc_write_u8(vs, 0);
-	vnc_write_u16(vs, 1);
-	vnc_framebuffer_update(vs, absolute, 0,
-			       vs->ds->width, vs->ds->height, -257);
-	vnc_flush(vs);
+    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
+        vnc_write_u8(vs, 0);
+        vnc_write_u8(vs, 0);
+        vnc_write_u16(vs, 1);
+        vnc_framebuffer_update(vs, absolute, 0,
+                               ds_get_width(vs->ds), ds_get_height(vs->ds),
+                               VNC_ENCODING_POINTER_TYPE_CHANGE);
+        vnc_flush(vs);
     }
     vs->absolute = absolute;
 }
@@ -914,32 +1253,32 @@
     int dz = 0;
 
     if (button_mask & 0x01)
-	buttons |= MOUSE_EVENT_LBUTTON;
+        buttons |= MOUSE_EVENT_LBUTTON;
     if (button_mask & 0x02)
-	buttons |= MOUSE_EVENT_MBUTTON;
+        buttons |= MOUSE_EVENT_MBUTTON;
     if (button_mask & 0x04)
-	buttons |= MOUSE_EVENT_RBUTTON;
+        buttons |= MOUSE_EVENT_RBUTTON;
     if (button_mask & 0x08)
-	dz = -1;
+        dz = -1;
     if (button_mask & 0x10)
-	dz = 1;
+        dz = 1;
 
     if (vs->absolute) {
-	kbd_mouse_event(x * 0x7FFF / (vs->ds->width - 1),
-			y * 0x7FFF / (vs->ds->height - 1),
-			dz, buttons);
-    } else if (vs->has_pointer_type_change) {
-	x -= 0x7FFF;
-	y -= 0x7FFF;
+        kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
+                        y * 0x7FFF / (ds_get_height(vs->ds) - 1),
+                        dz, buttons);
+    } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
+        x -= 0x7FFF;
+        y -= 0x7FFF;
 
-	kbd_mouse_event(x, y, dz, buttons);
+        kbd_mouse_event(x, y, dz, buttons);
     } else {
-	if (vs->last_x != -1)
-	    kbd_mouse_event(x - vs->last_x,
-			    y - vs->last_y,
-			    dz, buttons);
-	vs->last_x = x;
-	vs->last_y = y;
+        if (vs->last_x != -1)
+            kbd_mouse_event(x - vs->last_x,
+                            y - vs->last_y,
+                            dz, buttons);
+        vs->last_x = x;
+        vs->last_y = y;
     }
 
     check_pointer_type_change(vs, kbd_mouse_is_absolute());
@@ -960,8 +1299,8 @@
 
 static void press_key(VncState *vs, int keysym)
 {
-    kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f);
-    kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80);
+    kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
+    kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
 }
 
 static void do_key_event(VncState *vs, int down, int keycode, int sym)
@@ -987,19 +1326,19 @@
             return;
         }
         break;
-    case 0x3a:			/* CapsLock */
-    case 0x45:			/* NumLock */
+    case 0x3a:                        /* CapsLock */
+    case 0x45:                        /* NumLock */
         if (!down)
             vs->modifiers_state[keycode] ^= 1;
         break;
     }
 
-    if (keycode_is_keypad(vs->kbd_layout, keycode)) {
+    if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
         /* If the numlock state needs to change then simulate an additional
            keypress before sending this one.  This will happen if the user
            toggles numlock away from the VNC window.
         */
-        if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) {
+        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
             if (!vs->modifiers_state[0x45]) {
                 vs->modifiers_state[0x45] = 1;
                 press_key(vs, 0xff7f);
@@ -1022,6 +1361,7 @@
     } else {
         /* QEMU console emulation */
         if (down) {
+            int numlock = vs->modifiers_state[0x45];
             switch (keycode) {
             case 0x2a:                          /* Left Shift */
             case 0x36:                          /* Right Shift */
@@ -1057,6 +1397,57 @@
             case 0xd1:
                 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
                 break;
+
+            case 0x47:
+                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
+                break;
+            case 0x48:
+                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
+                break;
+            case 0x49:
+                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
+                break;
+            case 0x4b:
+                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
+                break;
+            case 0x4c:
+                kbd_put_keysym('5');
+                break;
+            case 0x4d:
+                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
+                break;
+            case 0x4f:
+                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
+                break;
+            case 0x50:
+                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
+                break;
+            case 0x51:
+                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
+                break;
+            case 0x52:
+                kbd_put_keysym('0');
+                break;
+            case 0x53:
+                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
+                break;
+
+            case 0xb5:
+                kbd_put_keysym('/');
+                break;
+            case 0x37:
+                kbd_put_keysym('*');
+                break;
+            case 0x4a:
+                kbd_put_keysym('-');
+                break;
+            case 0x4e:
+                kbd_put_keysym('+');
+                break;
+            case 0x9c:
+                kbd_put_keysym('\n');
+                break;
+
             default:
                 kbd_put_keysym(sym);
                 break;
@@ -1070,9 +1461,9 @@
     int keycode;
 
     if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
-	sym = sym - 'A' + 'a';
+        sym = sym - 'A' + 'a';
 
-    keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
+    keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);
     do_key_event(vs, down, keycode, sym);
 }
 
@@ -1087,29 +1478,28 @@
 }
 
 static void framebuffer_update_request(VncState *vs, int incremental,
-				       int x_position, int y_position,
-				       int w, int h)
+                                       int x_position, int y_position,
+                                       int w, int h)
 {
-    if (x_position > vs->ds->width)
-        x_position = vs->ds->width;
-    if (y_position > vs->ds->height)
-        y_position = vs->ds->height;
-    if (x_position + w >= vs->ds->width)
-        w = vs->ds->width  - x_position;
-    if (y_position + h >= vs->ds->height)
-        h = vs->ds->height - y_position;
+    if (x_position > ds_get_width(vs->ds))
+        x_position = ds_get_width(vs->ds);
+    if (y_position > ds_get_height(vs->ds))
+        y_position = ds_get_height(vs->ds);
+    if (x_position + w >= ds_get_width(vs->ds))
+        w = ds_get_width(vs->ds)  - x_position;
+    if (y_position + h >= ds_get_height(vs->ds))
+        h = ds_get_height(vs->ds) - y_position;
 
     int i;
     vs->need_update = 1;
     if (!incremental) {
-	char *old_row = vs->old_data + y_position * vs->ds->linesize;
-
-	for (i = 0; i < h; i++) {
-            vnc_set_bits(vs->dirty_row[y_position + i],
-                         (vs->ds->width / 16), VNC_DIRTY_WORDS);
-	    memset(old_row, 42, vs->ds->width * vs->depth);
-	    old_row += vs->ds->linesize;
-	}
+        vs->force_update = 1;
+        for (i = 0; i < h; i++) {
+            vnc_set_bits(vs->guest.dirty[y_position + i],
+                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+            vnc_set_bits(vs->server.dirty[y_position + i],
+                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+        }
     }
 }
 
@@ -1118,121 +1508,143 @@
     vnc_write_u8(vs, 0);
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1);
-    vnc_framebuffer_update(vs, 0, 0, vs->ds->width, vs->ds->height, -258);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
+                           VNC_ENCODING_EXT_KEY_EVENT);
+    vnc_flush(vs);
+}
+
+static void send_ext_audio_ack(VncState *vs)
+{
+    vnc_write_u8(vs, 0);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
+                           VNC_ENCODING_AUDIO);
     vnc_flush(vs);
 }
 
 static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
 {
     int i;
+    unsigned int enc = 0;
 
-    vs->has_hextile = 0;
-    vs->has_resize = 0;
-    vs->has_pointer_type_change = 0;
-    vs->has_WMVi = 0;
+    vnc_zlib_init(vs);
+    vs->features = 0;
+    vs->vnc_encoding = 0;
+    vs->tight_compression = 9;
+    vs->tight_quality = 9;
     vs->absolute = -1;
-    vs->ds->dpy_copy = NULL;
 
     for (i = n_encodings - 1; i >= 0; i--) {
-	switch (encodings[i]) {
-	case 0: /* Raw */
-	    vs->has_hextile = 0;
-	    break;
-	case 1: /* CopyRect */
-	    vs->ds->dpy_copy = vnc_copy;
-	    break;
-	case 5: /* Hextile */
-	    vs->has_hextile = 1;
-	    break;
-	case -223: /* DesktopResize */
-	    vs->has_resize = 1;
-	    break;
-	case -257:
-	    vs->has_pointer_type_change = 1;
-	    break;
-        case -258:
+        enc = encodings[i];
+        switch (enc) {
+        case VNC_ENCODING_RAW:
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_COPYRECT:
+            vs->features |= VNC_FEATURE_COPYRECT_MASK;
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vs->features |= VNC_FEATURE_HEXTILE_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_ZLIB:
+            vs->features |= VNC_FEATURE_ZLIB_MASK;
+            vs->vnc_encoding = enc;
+            break;
+        case VNC_ENCODING_DESKTOPRESIZE:
+            vs->features |= VNC_FEATURE_RESIZE_MASK;
+            break;
+        case VNC_ENCODING_POINTER_TYPE_CHANGE:
+            vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
+            break;
+        case VNC_ENCODING_EXT_KEY_EVENT:
             send_ext_key_event_ack(vs);
             break;
-        case 0x574D5669:
-            vs->has_WMVi = 1;
+        case VNC_ENCODING_AUDIO:
+            send_ext_audio_ack(vs);
             break;
-	default:
-	    break;
-	}
+        case VNC_ENCODING_WMVi:
+            vs->features |= VNC_FEATURE_WMVI_MASK;
+            break;
+        case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
+            vs->tight_compression = (enc & 0x0F);
+            break;
+        case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
+            vs->tight_quality = (enc & 0x0F);
+            break;
+        default:
+            VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
+            break;
+        }
     }
 
     check_pointer_type_change(vs, kbd_mouse_is_absolute());
 }
 
-static void set_pixel_format(VncState *vs,
-			     int bits_per_pixel, int depth,
-			     int big_endian_flag, int true_color_flag,
-			     int red_max, int green_max, int blue_max,
-			     int red_shift, int green_shift, int blue_shift)
+static void set_pixel_conversion(VncState *vs)
 {
-    int host_big_endian_flag;
+    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && 
+        !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
+        vs->write_pixels = vnc_write_pixels_copy;
+        switch (vs->ds->surface->pf.bits_per_pixel) {
+            case 8:
+                vs->send_hextile_tile = send_hextile_tile_8;
+                break;
+            case 16:
+                vs->send_hextile_tile = send_hextile_tile_16;
+                break;
+            case 32:
+                vs->send_hextile_tile = send_hextile_tile_32;
+                break;
+        }
+    } else {
+        vs->write_pixels = vnc_write_pixels_generic;
+        switch (vs->ds->surface->pf.bits_per_pixel) {
+            case 8:
+                vs->send_hextile_tile = send_hextile_tile_generic_8;
+                break;
+            case 16:
+                vs->send_hextile_tile = send_hextile_tile_generic_16;
+                break;
+            case 32:
+                vs->send_hextile_tile = send_hextile_tile_generic_32;
+                break;
+        }
+    }
+}
 
-#ifdef WORDS_BIGENDIAN
-    host_big_endian_flag = 1;
-#else
-    host_big_endian_flag = 0;
-#endif
+static void set_pixel_format(VncState *vs,
+                             int bits_per_pixel, int depth,
+                             int big_endian_flag, int true_color_flag,
+                             int red_max, int green_max, int blue_max,
+                             int red_shift, int green_shift, int blue_shift)
+{
     if (!true_color_flag) {
-    fail:
-	vnc_client_error(vs);
+        vnc_client_error(vs);
         return;
     }
-    if (bits_per_pixel == 32 &&
-        bits_per_pixel == vs->depth * 8 &&
-        host_big_endian_flag == big_endian_flag &&
-        red_max == 0xff && green_max == 0xff && blue_max == 0xff &&
-        red_shift == 16 && green_shift == 8 && blue_shift == 0) {
-        vs->depth = 4;
-        vs->write_pixels = vnc_write_pixels_copy;
-        vs->send_hextile_tile = send_hextile_tile_32;
-    } else
-    if (bits_per_pixel == 16 &&
-        bits_per_pixel == vs->depth * 8 && 
-        host_big_endian_flag == big_endian_flag &&
-        red_max == 31 && green_max == 63 && blue_max == 31 &&
-        red_shift == 11 && green_shift == 5 && blue_shift == 0) {
-        vs->depth = 2;
-        vs->write_pixels = vnc_write_pixels_copy;
-        vs->send_hextile_tile = send_hextile_tile_16;
-    } else
-    if (bits_per_pixel == 8 &&
-        bits_per_pixel == vs->depth * 8 &&
-        red_max == 7 && green_max == 7 && blue_max == 3 &&
-        red_shift == 5 && green_shift == 2 && blue_shift == 0) {
-        vs->depth = 1;
-        vs->write_pixels = vnc_write_pixels_copy;
-        vs->send_hextile_tile = send_hextile_tile_8;
-    } else
-    {
-        /* generic and slower case */
-        if (bits_per_pixel != 8 &&
-            bits_per_pixel != 16 &&
-            bits_per_pixel != 32)
-            goto fail;
-        if (vs->depth == 4) {
-            vs->send_hextile_tile = send_hextile_tile_generic_32;
-        } else if (vs->depth == 2) {
-           vs->send_hextile_tile = send_hextile_tile_generic_16;
-        } else {
-            vs->send_hextile_tile = send_hextile_tile_generic_8;
-        }
 
-        vs->pix_big_endian = big_endian_flag;
-        vs->write_pixels = vnc_write_pixels_generic;
-    }
+    vs->clientds = *(vs->guest.ds);
+    vs->clientds.pf.rmax = red_max;
+    count_bits(vs->clientds.pf.rbits, red_max);
+    vs->clientds.pf.rshift = red_shift;
+    vs->clientds.pf.rmask = red_max << red_shift;
+    vs->clientds.pf.gmax = green_max;
+    count_bits(vs->clientds.pf.gbits, green_max);
+    vs->clientds.pf.gshift = green_shift;
+    vs->clientds.pf.gmask = green_max << green_shift;
+    vs->clientds.pf.bmax = blue_max;
+    count_bits(vs->clientds.pf.bbits, blue_max);
+    vs->clientds.pf.bshift = blue_shift;
+    vs->clientds.pf.bmask = blue_max << blue_shift;
+    vs->clientds.pf.bits_per_pixel = bits_per_pixel;
+    vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
+    vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
+    vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
 
-    vs->client_red_shift = red_shift;
-    vs->client_red_max = red_max;
-    vs->client_green_shift = green_shift;
-    vs->client_green_max = green_max;
-    vs->client_blue_shift = blue_shift;
-    vs->client_blue_max = blue_max;
-    vs->pix_bpp = bits_per_pixel / 8;
+    set_pixel_conversion(vs);
 
     vga_hw_invalidate();
     vga_hw_update();
@@ -1241,9 +1653,8 @@
 static void pixel_format_message (VncState *vs) {
     char pad[3] = { 0, 0, 0 };
 
-    vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */
-    if (vs->depth == 4) vnc_write_u8(vs, 24); /* depth */
-    else vnc_write_u8(vs, vs->depth * 8); /* depth */
+    vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
+    vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
 
 #ifdef WORDS_BIGENDIAN
     vnc_write_u8(vs, 1);             /* big-endian-flag */
@@ -1251,137 +1662,43 @@
     vnc_write_u8(vs, 0);             /* big-endian-flag */
 #endif
     vnc_write_u8(vs, 1);             /* true-color-flag */
-    if (vs->depth == 4) {
-        vnc_write_u16(vs, 0xFF);     /* red-max */
-        vnc_write_u16(vs, 0xFF);     /* green-max */
-        vnc_write_u16(vs, 0xFF);     /* blue-max */
-        vnc_write_u8(vs, 16);        /* red-shift */
-        vnc_write_u8(vs, 8);         /* green-shift */
-        vnc_write_u8(vs, 0);         /* blue-shift */
+    vnc_write_u16(vs, vs->ds->surface->pf.rmax);     /* red-max */
+    vnc_write_u16(vs, vs->ds->surface->pf.gmax);     /* green-max */
+    vnc_write_u16(vs, vs->ds->surface->pf.bmax);     /* blue-max */
+    vnc_write_u8(vs, vs->ds->surface->pf.rshift);    /* red-shift */
+    vnc_write_u8(vs, vs->ds->surface->pf.gshift);    /* green-shift */
+    vnc_write_u8(vs, vs->ds->surface->pf.bshift);    /* blue-shift */
+    if (vs->ds->surface->pf.bits_per_pixel == 32)
         vs->send_hextile_tile = send_hextile_tile_32;
-    } else if (vs->depth == 2) {
-        vnc_write_u16(vs, 31);       /* red-max */
-        vnc_write_u16(vs, 63);       /* green-max */
-        vnc_write_u16(vs, 31);       /* blue-max */
-        vnc_write_u8(vs, 11);        /* red-shift */
-        vnc_write_u8(vs, 5);         /* green-shift */
-        vnc_write_u8(vs, 0);         /* blue-shift */
+    else if (vs->ds->surface->pf.bits_per_pixel == 16)
         vs->send_hextile_tile = send_hextile_tile_16;
-    } else if (vs->depth == 1) {
-        /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */
-        vnc_write_u16(vs, 7);        /* red-max */
-        vnc_write_u16(vs, 7);        /* green-max */
-        vnc_write_u16(vs, 3);        /* blue-max */
-        vnc_write_u8(vs, 5);         /* red-shift */
-        vnc_write_u8(vs, 2);         /* green-shift */
-        vnc_write_u8(vs, 0);         /* blue-shift */
+    else if (vs->ds->surface->pf.bits_per_pixel == 8)
         vs->send_hextile_tile = send_hextile_tile_8;
-    }
-    vs->client_red_max = vs->server_red_max;
-    vs->client_green_max = vs->server_green_max;
-    vs->client_blue_max = vs->server_blue_max;
-    vs->client_red_shift = vs->server_red_shift;
-    vs->client_green_shift = vs->server_green_shift;
-    vs->client_blue_shift = vs->server_blue_shift;
-    vs->pix_bpp = vs->depth * 8;
+    vs->clientds = *(vs->ds->surface);
+    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
     vs->write_pixels = vnc_write_pixels_copy;
 
     vnc_write(vs, pad, 3);           /* padding */
 }
 
-static void vnc_colordepth(DisplayState *ds, int depth)
+static void vnc_dpy_setdata(DisplayState *ds)
 {
-    int host_big_endian_flag;
-    struct VncState *vs = ds->opaque;
+    /* We don't have to do anything */
+}
 
-    switch (depth) {
-        case 24:
-            if (ds->depth == 32) return;
-            depth = 32;
-            break;
-        case 15:
-        case 8:
-        case 0:
-            return;
-        default:
-            break;
-    }
-
-#ifdef WORDS_BIGENDIAN
-    host_big_endian_flag = 1;
-#else
-    host_big_endian_flag = 0;
-#endif   
-    
-    switch (depth) {
-        case 8:
-            vs->depth = depth / 8;
-            vs->server_red_max = 7;
-            vs->server_green_max = 7;
-            vs->server_blue_max = 3;
-            vs->server_red_shift = 5;
-            vs->server_green_shift = 2;
-            vs->server_blue_shift = 0;
-            break;
-        case 16:
-            vs->depth = depth / 8;
-            vs->server_red_max = 31;
-            vs->server_green_max = 63;
-            vs->server_blue_max = 31;
-            vs->server_red_shift = 11;
-            vs->server_green_shift = 5;
-            vs->server_blue_shift = 0;
-            break;
-        case 32:
-            vs->depth = 4;
-            vs->server_red_max = 255;
-            vs->server_green_max = 255;
-            vs->server_blue_max = 255;
-            vs->server_red_shift = 16;
-            vs->server_green_shift = 8;
-            vs->server_blue_shift = 0;
-            break;
-        default:
-            return;
-    }
-
-    if (vs->csock != -1 && vs->has_WMVi) {
+static void vnc_colordepth(VncState *vs)
+{
+    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
         /* Sending a WMVi message to notify the client*/
         vnc_write_u8(vs, 0);  /* msg id */
         vnc_write_u8(vs, 0);
         vnc_write_u16(vs, 1); /* number of rects */
-        vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669);
+        vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
+                               ds_get_height(vs->ds), VNC_ENCODING_WMVi);
         pixel_format_message(vs);
         vnc_flush(vs);
     } else {
-        if (vs->pix_bpp == 4 && vs->depth == 4 &&
-                host_big_endian_flag == vs->pix_big_endian &&
-                vs->client_red_max == 0xff && vs->client_green_max == 0xff && vs->client_blue_max == 0xff &&
-                vs->client_red_shift == 16 && vs->client_green_shift == 8 && vs->client_blue_shift == 0) {
-            vs->write_pixels = vnc_write_pixels_copy;
-            vs->send_hextile_tile = send_hextile_tile_32;
-        } else if (vs->pix_bpp == 2 && vs->depth == 2 &&
-                host_big_endian_flag == vs->pix_big_endian &&
-                vs->client_red_max == 31 && vs->client_green_max == 63 && vs->client_blue_max == 31 &&
-                vs->client_red_shift == 11 && vs->client_green_shift == 5 && vs->client_blue_shift == 0) {
-            vs->write_pixels = vnc_write_pixels_copy;
-            vs->send_hextile_tile = send_hextile_tile_16;
-        } else if (vs->pix_bpp == 1 && vs->depth == 1 &&
-                host_big_endian_flag == vs->pix_big_endian &&
-                vs->client_red_max == 7 && vs->client_green_max == 7 && vs->client_blue_max == 3 &&
-                vs->client_red_shift == 5 && vs->client_green_shift == 2 && vs->client_blue_shift == 0) {
-            vs->write_pixels = vnc_write_pixels_copy;
-            vs->send_hextile_tile = send_hextile_tile_8;
-        } else {
-            if (vs->depth == 4) {
-                vs->send_hextile_tile = send_hextile_tile_generic_32;
-            } else if (vs->depth == 2) {
-                vs->send_hextile_tile = send_hextile_tile_generic_16;
-            } else {
-                vs->send_hextile_tile = send_hextile_tile_generic_8;
-            }
-            vs->write_pixels = vnc_write_pixels_generic;
-        }
+        set_pixel_conversion(vs);
     }
 }
 
@@ -1392,62 +1709,65 @@
 
     switch (data[0]) {
     case 0:
-	if (len == 1)
-	    return 20;
+        if (len == 1)
+            return 20;
 
-	set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
-			 read_u8(data, 6), read_u8(data, 7),
-			 read_u16(data, 8), read_u16(data, 10),
-			 read_u16(data, 12), read_u8(data, 14),
-			 read_u8(data, 15), read_u8(data, 16));
-	break;
+        set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
+                         read_u8(data, 6), read_u8(data, 7),
+                         read_u16(data, 8), read_u16(data, 10),
+                         read_u16(data, 12), read_u8(data, 14),
+                         read_u8(data, 15), read_u8(data, 16));
+        break;
     case 2:
-	if (len == 1)
-	    return 4;
+        if (len == 1)
+            return 4;
 
-	if (len == 4)
-	    return 4 + (read_u16(data, 2) * 4);
+        if (len == 4) {
+            limit = read_u16(data, 2);
+            if (limit > 0)
+                return 4 + (limit * 4);
+        } else
+            limit = read_u16(data, 2);
 
-	limit = read_u16(data, 2);
-	for (i = 0; i < limit; i++) {
-	    int32_t val = read_s32(data, 4 + (i * 4));
-	    memcpy(data + 4 + (i * 4), &val, sizeof(val));
-	}
+        for (i = 0; i < limit; i++) {
+            int32_t val = read_s32(data, 4 + (i * 4));
+            memcpy(data + 4 + (i * 4), &val, sizeof(val));
+        }
 
-	set_encodings(vs, (int32_t *)(data + 4), limit);
-	break;
+        set_encodings(vs, (int32_t *)(data + 4), limit);
+        break;
     case 3:
-	if (len == 1)
-	    return 10;
+        if (len == 1)
+            return 10;
 
-	framebuffer_update_request(vs,
-				   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
-				   read_u16(data, 6), read_u16(data, 8));
-	break;
+        framebuffer_update_request(vs,
+                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
+                                   read_u16(data, 6), read_u16(data, 8));
+        break;
     case 4:
-	if (len == 1)
-	    return 8;
+        if (len == 1)
+            return 8;
 
-	key_event(vs, read_u8(data, 1), read_u32(data, 4));
-	break;
+        key_event(vs, read_u8(data, 1), read_u32(data, 4));
+        break;
     case 5:
-	if (len == 1)
-	    return 6;
+        if (len == 1)
+            return 6;
 
-	pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
-	break;
+        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
+        break;
     case 6:
-	if (len == 1)
-	    return 8;
+        if (len == 1)
+            return 8;
 
-	if (len == 8) {
+        if (len == 8) {
             uint32_t dlen = read_u32(data, 4);
             if (dlen > 0)
                 return 8 + dlen;
         }
 
-	client_cut_text(vs, read_u32(data, 4), data + 8);
-	break;
+        client_cut_text(vs, read_u32(data, 4), data + 8);
+        break;
     case 255:
         if (len == 1)
             return 2;
@@ -1460,6 +1780,48 @@
             ext_key_event(vs, read_u16(data, 2),
                           read_u32(data, 4), read_u32(data, 8));
             break;
+        case 1:
+            if (len == 2)
+                return 4;
+
+            switch (read_u16 (data, 2)) {
+            case 0:
+                audio_add(vs);
+                break;
+            case 1:
+                audio_del(vs);
+                break;
+            case 2:
+                if (len == 4)
+                    return 10;
+                switch (read_u8(data, 4)) {
+                case 0: vs->as.fmt = AUD_FMT_U8; break;
+                case 1: vs->as.fmt = AUD_FMT_S8; break;
+                case 2: vs->as.fmt = AUD_FMT_U16; break;
+                case 3: vs->as.fmt = AUD_FMT_S16; break;
+                case 4: vs->as.fmt = AUD_FMT_U32; break;
+                case 5: vs->as.fmt = AUD_FMT_S32; break;
+                default:
+                    printf("Invalid audio format %d\n", read_u8(data, 4));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.nchannels = read_u8(data, 5);
+                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
+                    printf("Invalid audio channel coount %d\n",
+                           read_u8(data, 5));
+                    vnc_client_error(vs);
+                    break;
+                }
+                vs->as.freq = read_u32(data, 6);
+                break;
+            default:
+                printf ("Invalid audio message %d\n", read_u8(data, 4));
+                vnc_client_error(vs);
+                break;
+            }
+            break;
+
         default:
             printf("Msg: %d\n", read_u16(data, 0));
             vnc_client_error(vs);
@@ -1467,9 +1829,9 @@
         }
         break;
     default:
-	printf("Msg: %d\n", data[0]);
-	vnc_client_error(vs);
-	break;
+        printf("Msg: %d\n", data[0]);
+        vnc_client_error(vs);
+        break;
     }
 
     vnc_read_when(vs, protocol_client_msg, 1);
@@ -1481,10 +1843,8 @@
     char buf[1024];
     int size;
 
-    vs->width = vs->ds->width;
-    vs->height = vs->ds->height;
-    vnc_write_u16(vs, vs->ds->width);
-    vnc_write_u16(vs, vs->ds->height);
+    vnc_write_u16(vs, ds_get_width(vs->ds));
+    vnc_write_u16(vs, ds_get_height(vs->ds));
 
     pixel_format_message(vs);
 
@@ -1502,6 +1862,11 @@
     return 0;
 }
 
+void start_client_init(VncState *vs)
+{
+    vnc_read_when(vs, protocol_client_init, 1);
+}
+
 static void make_challenge(VncState *vs)
 {
     int i;
@@ -1518,51 +1883,51 @@
     int i, j, pwlen;
     unsigned char key[8];
 
-    if (!vs->password || !vs->password[0]) {
-	VNC_DEBUG("No password configured on server");
-	vnc_write_u32(vs, 1); /* Reject auth */
-	if (vs->minor >= 8) {
-	    static const char err[] = "Authentication failed";
-	    vnc_write_u32(vs, sizeof(err));
-	    vnc_write(vs, err, sizeof(err));
-	}
-	vnc_flush(vs);
-	vnc_client_error(vs);
-	return 0;
+    if (!vs->vd->password || !vs->vd->password[0]) {
+        VNC_DEBUG("No password configured on server");
+        vnc_write_u32(vs, 1); /* Reject auth */
+        if (vs->minor >= 8) {
+            static const char err[] = "Authentication failed";
+            vnc_write_u32(vs, sizeof(err));
+            vnc_write(vs, err, sizeof(err));
+        }
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
     }
 
     memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
 
     /* Calculate the expected challenge response */
-    pwlen = strlen(vs->password);
+    pwlen = strlen(vs->vd->password);
     for (i=0; i<sizeof(key); i++)
-        key[i] = i<pwlen ? vs->password[i] : 0;
+        key[i] = i<pwlen ? vs->vd->password[i] : 0;
     deskey(key, EN0);
     for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
         des(response+j, response+j);
 
     /* Compare expected vs actual challenge response */
     if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
-	VNC_DEBUG("Client challenge reponse did not match\n");
-	vnc_write_u32(vs, 1); /* Reject auth */
-	if (vs->minor >= 8) {
-	    static const char err[] = "Authentication failed";
-	    vnc_write_u32(vs, sizeof(err));
-	    vnc_write(vs, err, sizeof(err));
-	}
-	vnc_flush(vs);
-	vnc_client_error(vs);
+        VNC_DEBUG("Client challenge reponse did not match\n");
+        vnc_write_u32(vs, 1); /* Reject auth */
+        if (vs->minor >= 8) {
+            static const char err[] = "Authentication failed";
+            vnc_write_u32(vs, sizeof(err));
+            vnc_write(vs, err, sizeof(err));
+        }
+        vnc_flush(vs);
+        vnc_client_error(vs);
     } else {
-	VNC_DEBUG("Accepting VNC challenge response\n");
-	vnc_write_u32(vs, 0); /* Accept auth */
-	vnc_flush(vs);
+        VNC_DEBUG("Accepting VNC challenge response\n");
+        vnc_write_u32(vs, 0); /* Accept auth */
+        vnc_flush(vs);
 
-	vnc_read_when(vs, protocol_client_init, 1);
+        start_client_init(vs);
     }
     return 0;
 }
 
-static int start_auth_vnc(VncState *vs)
+void start_auth_vnc(VncState *vs)
 {
     make_challenge(vs);
     /* Send client a 'random' challenge */
@@ -1570,425 +1935,15 @@
     vnc_flush(vs);
 
     vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
-    return 0;
 }
 
 
-#ifdef CONFIG_VNC_TLS
-#define DH_BITS 1024
-static gnutls_dh_params_t dh_params;
-
-static int vnc_tls_initialize(void)
-{
-    static int tlsinitialized = 0;
-
-    if (tlsinitialized)
-	return 1;
-
-    if (gnutls_global_init () < 0)
-	return 0;
-
-    /* XXX ought to re-generate diffie-hellmen params periodically */
-    if (gnutls_dh_params_init (&dh_params) < 0)
-	return 0;
-    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
-	return 0;
-
-#if _VNC_DEBUG == 2
-    gnutls_global_set_log_level(10);
-    gnutls_global_set_log_function(vnc_debug_gnutls_log);
-#endif
-
-    tlsinitialized = 1;
-
-    return 1;
-}
-
-static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
-{
-    gnutls_anon_server_credentials anon_cred;
-    int ret;
-
-    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
-	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
-	return NULL;
-    }
-
-    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
-
-    return anon_cred;
-}
-
-
-static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs)
-{
-    gnutls_certificate_credentials_t x509_cred;
-    int ret;
-
-    if (!vs->x509cacert) {
-	VNC_DEBUG("No CA x509 certificate specified\n");
-	return NULL;
-    }
-    if (!vs->x509cert) {
-	VNC_DEBUG("No server x509 certificate specified\n");
-	return NULL;
-    }
-    if (!vs->x509key) {
-	VNC_DEBUG("No server private key specified\n");
-	return NULL;
-    }
-
-    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
-	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
-	return NULL;
-    }
-    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
-						      vs->x509cacert,
-						      GNUTLS_X509_FMT_PEM)) < 0) {
-	VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
-	gnutls_certificate_free_credentials(x509_cred);
-	return NULL;
-    }
-
-    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
-						     vs->x509cert,
-						     vs->x509key,
-						     GNUTLS_X509_FMT_PEM)) < 0) {
-	VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
-	gnutls_certificate_free_credentials(x509_cred);
-	return NULL;
-    }
-
-    if (vs->x509cacrl) {
-	if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
-							vs->x509cacrl,
-							GNUTLS_X509_FMT_PEM)) < 0) {
-	    VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
-	    gnutls_certificate_free_credentials(x509_cred);
-	    return NULL;
-	}
-    }
-
-    gnutls_certificate_set_dh_params (x509_cred, dh_params);
-
-    return x509_cred;
-}
-
-static int vnc_validate_certificate(struct VncState *vs)
-{
-    int ret;
-    unsigned int status;
-    const gnutls_datum_t *certs;
-    unsigned int nCerts, i;
-    time_t now;
-
-    VNC_DEBUG("Validating client certificate\n");
-    if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) {
-	VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
-	return -1;
-    }
-
-    if ((now = time(NULL)) == ((time_t)-1)) {
-	return -1;
-    }
-
-    if (status != 0) {
-	if (status & GNUTLS_CERT_INVALID)
-	    VNC_DEBUG("The certificate is not trusted.\n");
-
-	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
-	    VNC_DEBUG("The certificate hasn't got a known issuer.\n");
-
-	if (status & GNUTLS_CERT_REVOKED)
-	    VNC_DEBUG("The certificate has been revoked.\n");
-
-	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
-	    VNC_DEBUG("The certificate uses an insecure algorithm\n");
-
-	return -1;
-    } else {
-	VNC_DEBUG("Certificate is valid!\n");
-    }
-
-    /* Only support x509 for now */
-    if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509)
-	return -1;
-
-    if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts)))
-	return -1;
-
-    for (i = 0 ; i < nCerts ; i++) {
-	gnutls_x509_crt_t cert;
-	VNC_DEBUG ("Checking certificate chain %d\n", i);
-	if (gnutls_x509_crt_init (&cert) < 0)
-	    return -1;
-
-	if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
-	    gnutls_x509_crt_deinit (cert);
-	    return -1;
-	}
-
-	if (gnutls_x509_crt_get_expiration_time (cert) < now) {
-	    VNC_DEBUG("The certificate has expired\n");
-	    gnutls_x509_crt_deinit (cert);
-	    return -1;
-	}
-
-	if (gnutls_x509_crt_get_activation_time (cert) > now) {
-	    VNC_DEBUG("The certificate is not yet activated\n");
-	    gnutls_x509_crt_deinit (cert);
-	    return -1;
-	}
-
-	if (gnutls_x509_crt_get_activation_time (cert) > now) {
-	    VNC_DEBUG("The certificate is not yet activated\n");
-	    gnutls_x509_crt_deinit (cert);
-	    return -1;
-	}
-
-	gnutls_x509_crt_deinit (cert);
-    }
-
-    return 0;
-}
-
-
-static int start_auth_vencrypt_subauth(VncState *vs)
-{
-    switch (vs->subauth) {
-    case VNC_AUTH_VENCRYPT_TLSNONE:
-    case VNC_AUTH_VENCRYPT_X509NONE:
-       VNC_DEBUG("Accept TLS auth none\n");
-       vnc_write_u32(vs, 0); /* Accept auth completion */
-       vnc_read_when(vs, protocol_client_init, 1);
-       break;
-
-    case VNC_AUTH_VENCRYPT_TLSVNC:
-    case VNC_AUTH_VENCRYPT_X509VNC:
-       VNC_DEBUG("Start TLS auth VNC\n");
-       return start_auth_vnc(vs);
-
-    default: /* Should not be possible, but just in case */
-       VNC_DEBUG("Reject auth %d\n", vs->auth);
-       vnc_write_u8(vs, 1);
-       if (vs->minor >= 8) {
-           static const char err[] = "Unsupported authentication type";
-           vnc_write_u32(vs, sizeof(err));
-           vnc_write(vs, err, sizeof(err));
-       }
-       vnc_client_error(vs);
-    }
-
-    return 0;
-}
-
-static void vnc_handshake_io(void *opaque);
-
-static int vnc_continue_handshake(struct VncState *vs) {
-    int ret;
-
-    if ((ret = gnutls_handshake(vs->tls_session)) < 0) {
-       if (!gnutls_error_is_fatal(ret)) {
-           VNC_DEBUG("Handshake interrupted (blocking)\n");
-           if (!gnutls_record_get_direction(vs->tls_session))
-               qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);
-           else
-               qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);
-           return 0;
-       }
-       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
-       vnc_client_error(vs);
-       return -1;
-    }
-
-    if (vs->x509verify) {
-	if (vnc_validate_certificate(vs) < 0) {
-	    VNC_DEBUG("Client verification failed\n");
-	    vnc_client_error(vs);
-	    return -1;
-	} else {
-	    VNC_DEBUG("Client verification passed\n");
-	}
-    }
-
-    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
-    vs->wiremode = VNC_WIREMODE_TLS;
-    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
-
-    return start_auth_vencrypt_subauth(vs);
-}
-
-static void vnc_handshake_io(void *opaque) {
-    struct VncState *vs = (struct VncState *)opaque;
-
-    VNC_DEBUG("Handshake IO continue\n");
-    vnc_continue_handshake(vs);
-}
-
-#define NEED_X509_AUTH(vs)			      \
-    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
-
-
-static int vnc_start_tls(struct VncState *vs) {
-    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
-    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
-    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
-    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
-
-    VNC_DEBUG("Do TLS setup\n");
-    if (vnc_tls_initialize() < 0) {
-	VNC_DEBUG("Failed to init TLS\n");
-	vnc_client_error(vs);
-	return -1;
-    }
-    if (vs->tls_session == NULL) {
-	if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) {
-	    vnc_client_error(vs);
-	    return -1;
-	}
-
-	if (gnutls_set_default_priority(vs->tls_session) < 0) {
-	    gnutls_deinit(vs->tls_session);
-	    vs->tls_session = NULL;
-	    vnc_client_error(vs);
-	    return -1;
-	}
-
-	if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) {
-	    gnutls_deinit(vs->tls_session);
-	    vs->tls_session = NULL;
-	    vnc_client_error(vs);
-	    return -1;
-	}
-
-	if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) {
-	    gnutls_deinit(vs->tls_session);
-	    vs->tls_session = NULL;
-	    vnc_client_error(vs);
-	    return -1;
-	}
-
-	if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) {
-	    gnutls_deinit(vs->tls_session);
-	    vs->tls_session = NULL;
-	    vnc_client_error(vs);
-	    return -1;
-	}
-
-	if (NEED_X509_AUTH(vs)) {
-	    gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs);
-	    if (!x509_cred) {
-		gnutls_deinit(vs->tls_session);
-		vs->tls_session = NULL;
-		vnc_client_error(vs);
-		return -1;
-	    }
-	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
-		gnutls_deinit(vs->tls_session);
-		vs->tls_session = NULL;
-		gnutls_certificate_free_credentials(x509_cred);
-		vnc_client_error(vs);
-		return -1;
-	    }
-	    if (vs->x509verify) {
-		VNC_DEBUG("Requesting a client certificate\n");
-		gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
-	    }
-
-	} else {
-	    gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
-	    if (!anon_cred) {
-		gnutls_deinit(vs->tls_session);
-		vs->tls_session = NULL;
-		vnc_client_error(vs);
-		return -1;
-	    }
-	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
-		gnutls_deinit(vs->tls_session);
-		vs->tls_session = NULL;
-		gnutls_anon_free_server_credentials(anon_cred);
-		vnc_client_error(vs);
-		return -1;
-	    }
-	}
-
-	gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
-	gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push);
-	gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull);
-    }
-
-    VNC_DEBUG("Start TLS handshake process\n");
-    return vnc_continue_handshake(vs);
-}
-
-static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
-{
-    int auth = read_u32(data, 0);
-
-    if (auth != vs->subauth) {
-	VNC_DEBUG("Rejecting auth %d\n", auth);
-	vnc_write_u8(vs, 0); /* Reject auth */
-	vnc_flush(vs);
-	vnc_client_error(vs);
-    } else {
-	VNC_DEBUG("Accepting auth %d, starting handshake\n", auth);
-	vnc_write_u8(vs, 1); /* Accept auth */
-	vnc_flush(vs);
-
-	if (vnc_start_tls(vs) < 0) {
-	    VNC_DEBUG("Failed to complete TLS\n");
-	    return 0;
-	}
-
-	if (vs->wiremode == VNC_WIREMODE_TLS) {
-	    VNC_DEBUG("Starting VeNCrypt subauth\n");
-	    return start_auth_vencrypt_subauth(vs);
-	} else {
-	    VNC_DEBUG("TLS handshake blocked\n");
-	    return 0;
-	}
-    }
-    return 0;
-}
-
-static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
-{
-    if (data[0] != 0 ||
-	data[1] != 2) {
-	VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
-	vnc_write_u8(vs, 1); /* Reject version */
-	vnc_flush(vs);
-	vnc_client_error(vs);
-    } else {
-	VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
-	vnc_write_u8(vs, 0); /* Accept version */
-	vnc_write_u8(vs, 1); /* Number of sub-auths */
-	vnc_write_u32(vs, vs->subauth); /* The supported auth */
-	vnc_flush(vs);
-	vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
-    }
-    return 0;
-}
-
-static int start_auth_vencrypt(VncState *vs)
-{
-    /* Send VeNCrypt version 0.2 */
-    vnc_write_u8(vs, 0);
-    vnc_write_u8(vs, 2);
-
-    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
-    return 0;
-}
-#endif /* CONFIG_VNC_TLS */
-
 static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
 {
     /* We only advertise 1 auth scheme at a time, so client
      * must pick the one we sent. Verify this */
-    if (data[0] != vs->auth) { /* Reject auth */
-       VNC_DEBUG("Reject auth %d\n", (int)data[0]);
+    if (data[0] != vs->vd->auth) { /* Reject auth */
+       VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
        vnc_write_u32(vs, 1);
        if (vs->minor >= 8) {
            static const char err[] = "Authentication failed";
@@ -1998,28 +1953,37 @@
        vnc_client_error(vs);
     } else { /* Accept requested auth */
        VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
-       switch (vs->auth) {
+       switch (vs->vd->auth) {
        case VNC_AUTH_NONE:
            VNC_DEBUG("Accept auth none\n");
            if (vs->minor >= 8) {
                vnc_write_u32(vs, 0); /* Accept auth completion */
                vnc_flush(vs);
            }
-           vnc_read_when(vs, protocol_client_init, 1);
+           start_client_init(vs);
            break;
 
        case VNC_AUTH_VNC:
            VNC_DEBUG("Start VNC auth\n");
-           return start_auth_vnc(vs);
+           start_auth_vnc(vs);
+           break;
 
 #ifdef CONFIG_VNC_TLS
        case VNC_AUTH_VENCRYPT:
            VNC_DEBUG("Accept VeNCrypt auth\n");;
-           return start_auth_vencrypt(vs);
+           start_auth_vencrypt(vs);
+           break;
 #endif /* CONFIG_VNC_TLS */
 
+#ifdef CONFIG_VNC_SASL
+       case VNC_AUTH_SASL:
+           VNC_DEBUG("Accept SASL auth\n");
+           start_auth_sasl(vs);
+           break;
+#endif /* CONFIG_VNC_SASL */
+
        default: /* Should not be possible, but just in case */
-           VNC_DEBUG("Reject auth %d\n", vs->auth);
+           VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
            vnc_write_u8(vs, 1);
            if (vs->minor >= 8) {
                static const char err[] = "Authentication failed";
@@ -2040,407 +2004,395 @@
     local[12] = 0;
 
     if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
-	VNC_DEBUG("Malformed protocol version %s\n", local);
-	vnc_client_error(vs);
-	return 0;
+        VNC_DEBUG("Malformed protocol version %s\n", local);
+        vnc_client_error(vs);
+        return 0;
     }
     VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
     if (vs->major != 3 ||
-	(vs->minor != 3 &&
-	 vs->minor != 4 &&
-	 vs->minor != 5 &&
-	 vs->minor != 7 &&
-	 vs->minor != 8)) {
-	VNC_DEBUG("Unsupported client version\n");
-	vnc_write_u32(vs, VNC_AUTH_INVALID);
-	vnc_flush(vs);
-	vnc_client_error(vs);
-	return 0;
+        (vs->minor != 3 &&
+         vs->minor != 4 &&
+         vs->minor != 5 &&
+         vs->minor != 7 &&
+         vs->minor != 8)) {
+        VNC_DEBUG("Unsupported client version\n");
+        vnc_write_u32(vs, VNC_AUTH_INVALID);
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
     }
     /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
      * as equivalent to v3.3 by servers
      */
     if (vs->minor == 4 || vs->minor == 5)
-	vs->minor = 3;
+        vs->minor = 3;
 
     if (vs->minor == 3) {
-	if (vs->auth == VNC_AUTH_NONE) {
+        if (vs->vd->auth == VNC_AUTH_NONE) {
             VNC_DEBUG("Tell client auth none\n");
-            vnc_write_u32(vs, vs->auth);
+            vnc_write_u32(vs, vs->vd->auth);
             vnc_flush(vs);
-            vnc_read_when(vs, protocol_client_init, 1);
-       } else if (vs->auth == VNC_AUTH_VNC) {
+            start_client_init(vs);
+       } else if (vs->vd->auth == VNC_AUTH_VNC) {
             VNC_DEBUG("Tell client VNC auth\n");
-            vnc_write_u32(vs, vs->auth);
+            vnc_write_u32(vs, vs->vd->auth);
             vnc_flush(vs);
             start_auth_vnc(vs);
        } else {
-            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
+            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
             vnc_write_u32(vs, VNC_AUTH_INVALID);
             vnc_flush(vs);
             vnc_client_error(vs);
        }
     } else {
-	VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
-	vnc_write_u8(vs, 1); /* num auth */
-	vnc_write_u8(vs, vs->auth);
-	vnc_read_when(vs, protocol_client_auth, 1);
-	vnc_flush(vs);
+        VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
+        vnc_write_u8(vs, 1); /* num auth */
+        vnc_write_u8(vs, vs->vd->auth);
+        vnc_read_when(vs, protocol_client_auth, 1);
+        vnc_flush(vs);
     }
 
     return 0;
 }
 
-static void vnc_connect(VncState *vs)
+static void vnc_connect(VncDisplay *vd, int csock)
 {
-    VNC_DEBUG("New client on socket %d\n", vs->csock);
-    vs->ds->idle = 0;
+    VncState *vs = qemu_mallocz(sizeof(VncState));
+    vs->csock = csock;
+
+    VNC_DEBUG("New client on socket %d\n", csock);
+    dcl->idle = 0;
     socket_set_nonblock(vs->csock);
     qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+
+    vs->vd = vd;
+    vs->ds = vd->ds;
+    vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
+    vs->last_x = -1;
+    vs->last_y = -1;
+
+    vs->as.freq = 44100;
+    vs->as.nchannels = 2;
+    vs->as.fmt = AUD_FMT_S16;
+    vs->as.endianness = 0;
+
+    vnc_resize(vs);
     vnc_write(vs, "RFB 003.008\n", 12);
     vnc_flush(vs);
     vnc_read_when(vs, protocol_version, 12);
-    memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height);
-    memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
-    vs->has_resize = 0;
-    vs->has_hextile = 0;
-    vs->ds->dpy_copy = NULL;
+    reset_keys(vs);
+
+    vs->next = vd->clients;
+    vd->clients = vs;
+
     vnc_update_client(vs);
+    /* vs might be free()ed here */
 }
 
 static void vnc_listen_read(void *opaque)
 {
-    VncState *vs = opaque;
+    VncDisplay *vs = opaque;
+    struct sockaddr_in addr;
+    socklen_t addrlen = sizeof(addr);
 
     /* Catch-up */
     vga_hw_update();
 
-    vs->csock = socket_accept(vs->lsock, NULL);
-    if (vs->csock != -1) {
-        vnc_connect(vs);
+    int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
+    if (csock != -1) {
+        vnc_connect(vs, csock);
     }
 }
 
-extern int parse_host_port(SockAddress* saddr, const char *str);
-
 void vnc_display_init(DisplayState *ds)
 {
-    VncState *vs;
+    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
 
-    vs = qemu_mallocz(sizeof(VncState));
-    if (!vs)
-	exit(1);
+    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
 
     ds->opaque = vs;
-    ds->idle = 1;
-    vnc_state = vs;
-    vs->display = NULL;
-    vs->password = NULL;
+    dcl->idle = 1;
+    vnc_display = vs;
 
     vs->lsock = -1;
-    vs->csock = -1;
-    vs->last_x = -1;
-    vs->last_y = -1;
 
     vs->ds = ds;
 
     if (keyboard_layout)
-        vs->kbd_layout = init_keyboard_layout(keyboard_layout);
+        vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
     else
-        vs->kbd_layout = init_keyboard_layout("en-us");
+        vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
 
     if (!vs->kbd_layout)
-	exit(1);
+        exit(1);
 
-    vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
-
-    vs->ds->data = NULL;
-    vs->ds->dpy_update = vnc_dpy_update;
-    vs->ds->dpy_resize = vnc_dpy_resize;
-    vs->ds->dpy_refresh = NULL;
-
-    vnc_colordepth(vs->ds, 32);
-    vnc_dpy_resize(vs->ds, 640, 400);
+    dcl->dpy_copy = vnc_dpy_copy;
+    dcl->dpy_update = vnc_dpy_update;
+    dcl->dpy_resize = vnc_dpy_resize;
+    dcl->dpy_setdata = vnc_dpy_setdata;
+    register_displaychangelistener(ds, dcl);
 }
 
-#ifdef CONFIG_VNC_TLS
-static int vnc_set_x509_credential(VncState *vs,
-				   const char *certdir,
-				   const char *filename,
-				   char **cred,
-				   int ignoreMissing)
-{
-    struct stat sb;
-
-    if (*cred) {
-	qemu_free(*cred);
-	*cred = NULL;
-    }
-
-    if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2)))
-	return -1;
-
-    strcpy(*cred, certdir);
-    strcat(*cred, "/");
-    strcat(*cred, filename);
-
-    VNC_DEBUG("Check %s\n", *cred);
-    if (stat(*cred, &sb) < 0) {
-	qemu_free(*cred);
-	*cred = NULL;
-	if (ignoreMissing && errno == ENOENT)
-	    return 0;
-	return -1;
-    }
-
-    return 0;
-}
-
-static int vnc_set_x509_credential_dir(VncState *vs,
-				       const char *certdir)
-{
-    if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
-	goto cleanup;
-    if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0)
-	goto cleanup;
-    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0)
-	goto cleanup;
-    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0)
-	goto cleanup;
-
-    return 0;
-
- cleanup:
-    qemu_free(vs->x509cacert);
-    qemu_free(vs->x509cacrl);
-    qemu_free(vs->x509cert);
-    qemu_free(vs->x509key);
-    vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL;
-    return -1;
-}
-#endif /* CONFIG_VNC_TLS */
 
 void vnc_display_close(DisplayState *ds)
 {
-    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
 
+    if (!vs)
+        return;
     if (vs->display) {
-	qemu_free(vs->display);
-	vs->display = NULL;
+        qemu_free(vs->display);
+        vs->display = NULL;
     }
     if (vs->lsock != -1) {
-	qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
-	close(vs->lsock);
-	vs->lsock = -1;
-    }
-    if (vs->csock != -1) {
-	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
-	socket_close(vs->csock);
-	vs->csock = -1;
-	buffer_reset(&vs->input);
-	buffer_reset(&vs->output);
-	vs->need_update = 0;
-#ifdef CONFIG_VNC_TLS
-	if (vs->tls_session) {
-	    gnutls_deinit(vs->tls_session);
-	    vs->tls_session = NULL;
-	}
-	vs->wiremode = VNC_WIREMODE_CLEAR;
-#endif /* CONFIG_VNC_TLS */
+        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
+        close(vs->lsock);
+        vs->lsock = -1;
     }
     vs->auth = VNC_AUTH_INVALID;
 #ifdef CONFIG_VNC_TLS
     vs->subauth = VNC_AUTH_INVALID;
-    vs->x509verify = 0;
+    vs->tls.x509verify = 0;
 #endif
 }
 
 int vnc_display_password(DisplayState *ds, const char *password)
 {
-    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
 
     if (vs->password) {
-	qemu_free(vs->password);
-	vs->password = NULL;
+        qemu_free(vs->password);
+        vs->password = NULL;
     }
     if (password && password[0]) {
-	if (!(vs->password = qemu_strdup(password)))
-	    return -1;
+        if (!(vs->password = qemu_strdup(password)))
+            return -1;
     }
 
     return 0;
 }
 
+char *vnc_display_local_addr(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    
+    return vnc_socket_local_addr("%s:%s", vs->lsock);
+}
+
 int vnc_display_open(DisplayState *ds, const char *display)
 {
-    SockAddress  addr;
-#ifndef _WIN32
-    const char *p;
-#endif
-    int ret;
-    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
     const char *options;
     int password = 0;
     int reverse = 0;
+    int to_port = 0;
 #ifdef CONFIG_VNC_TLS
     int tls = 0, x509 = 0;
 #endif
+#ifdef CONFIG_VNC_SASL
+    int sasl = 0;
+    int saslErr;
+#endif
+    int acl = 0;
 
-    sock_address_init_inet( &addr, SOCK_ADDRESS_INET_ANY, 0 );
-    vs->lsock = -1;
-
+    if (!vnc_display)
+        return -1;
     vnc_display_close(ds);
     if (strcmp(display, "none") == 0)
-	return 0;
+        return 0;
 
     if (!(vs->display = strdup(display)))
-	return -1;
+        return -1;
 
     options = display;
     while ((options = strchr(options, ','))) {
-	options++;
-	if (strncmp(options, "password", 8) == 0) {
-	    password = 1; /* Require password auth */
-	} else if (strncmp(options, "reverse", 7) == 0) {
-	    reverse = 1;
-#ifdef CONFIG_VNC_TLS
-	} else if (strncmp(options, "tls", 3) == 0) {
-	    tls = 1; /* Require TLS */
-	} else if (strncmp(options, "x509", 4) == 0) {
-	    char *start, *end;
-	    x509 = 1; /* Require x509 certificates */
-	    if (strncmp(options, "x509verify", 10) == 0)
-	        vs->x509verify = 1; /* ...and verify client certs */
-
-	    /* Now check for 'x509=/some/path' postfix
-	     * and use that to setup x509 certificate/key paths */
-	    start = strchr(options, '=');
-	    end = strchr(options, ',');
-	    if (start && (!end || (start < end))) {
-		int len = end ? end-(start+1) : strlen(start+1);
-		char *path = qemu_malloc(len+1);
-		strncpy(path, start+1, len);
-		path[len] = '\0';
-		VNC_DEBUG("Trying certificate path '%s'\n", path);
-		ret = vnc_set_x509_credential_dir(vs, path);
-                qemu_free(path);
-                if (ret < 0) {
-		    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
-		    goto FAIL;
-		}
-	    } else {
-		fprintf(stderr, "No certificate path provided\n");
-		goto FAIL;
-	    }
+        options++;
+        if (strncmp(options, "password", 8) == 0) {
+            password = 1; /* Require password auth */
+        } else if (strncmp(options, "reverse", 7) == 0) {
+            reverse = 1;
+        } else if (strncmp(options, "to=", 3) == 0) {
+            to_port = atoi(options+3) + 5900;
+#ifdef CONFIG_VNC_SASL
+        } else if (strncmp(options, "sasl", 4) == 0) {
+            sasl = 1; /* Require SASL auth */
 #endif
-	}
+#ifdef CONFIG_VNC_TLS
+        } else if (strncmp(options, "tls", 3) == 0) {
+            tls = 1; /* Require TLS */
+        } else if (strncmp(options, "x509", 4) == 0) {
+            char *start, *end;
+            x509 = 1; /* Require x509 certificates */
+            if (strncmp(options, "x509verify", 10) == 0)
+                vs->tls.x509verify = 1; /* ...and verify client certs */
+
+            /* Now check for 'x509=/some/path' postfix
+             * and use that to setup x509 certificate/key paths */
+            start = strchr(options, '=');
+            end = strchr(options, ',');
+            if (start && (!end || (start < end))) {
+                int len = end ? end-(start+1) : strlen(start+1);
+                char *path = qemu_strndup(start + 1, len);
+
+                VNC_DEBUG("Trying certificate path '%s'\n", path);
+                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
+                    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
+                    qemu_free(path);
+                    qemu_free(vs->display);
+                    vs->display = NULL;
+                    return -1;
+                }
+                qemu_free(path);
+            } else {
+                fprintf(stderr, "No certificate path provided\n");
+                qemu_free(vs->display);
+                vs->display = NULL;
+                return -1;
+            }
+#endif
+        } else if (strncmp(options, "acl", 3) == 0) {
+            acl = 1;
+        }
     }
 
+#ifdef CONFIG_VNC_TLS
+    if (acl && x509 && vs->tls.x509verify) {
+        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
+            fprintf(stderr, "Failed to create x509 dname ACL\n");
+            exit(1);
+        }
+    }
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (acl && sasl) {
+        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
+            fprintf(stderr, "Failed to create username ACL\n");
+            exit(1);
+        }
+    }
+#endif
+
+    /*
+     * Combinations we support here:
+     *
+     *  - no-auth                (clear text, no auth)
+     *  - password               (clear text, weak auth)
+     *  - sasl                   (encrypt, good auth *IF* using Kerberos via GSSAPI)
+     *  - tls                    (encrypt, weak anonymous creds, no auth)
+     *  - tls + password         (encrypt, weak anonymous creds, weak auth)
+     *  - tls + sasl             (encrypt, weak anonymous creds, good auth)
+     *  - tls + x509             (encrypt, good x509 creds, no auth)
+     *  - tls + x509 + password  (encrypt, good x509 creds, weak auth)
+     *  - tls + x509 + sasl      (encrypt, good x509 creds, good auth)
+     *
+     * NB1. TLS is a stackable auth scheme.
+     * NB2. the x509 schemes have option to validate a client cert dname
+     */
     if (password) {
 #ifdef CONFIG_VNC_TLS
-	if (tls) {
-	    vs->auth = VNC_AUTH_VENCRYPT;
-	    if (x509) {
-		VNC_DEBUG("Initializing VNC server with x509 password auth\n");
-		vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
-	    } else {
-		VNC_DEBUG("Initializing VNC server with TLS password auth\n");
-		vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
-	    }
-	} else {
-#endif
-	    VNC_DEBUG("Initializing VNC server with password auth\n");
-	    vs->auth = VNC_AUTH_VNC;
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+            VNC_DEBUG("Initializing VNC server with password auth\n");
+            vs->auth = VNC_AUTH_VNC;
 #ifdef CONFIG_VNC_TLS
-	    vs->subauth = VNC_AUTH_INVALID;
-	}
-#endif
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    } else if (sasl) {
+#ifdef CONFIG_VNC_TLS
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
+            }
+        } else {
+#endif /* CONFIG_VNC_TLS */
+            VNC_DEBUG("Initializing VNC server with SASL auth\n");
+            vs->auth = VNC_AUTH_SASL;
+#ifdef CONFIG_VNC_TLS
+            vs->subauth = VNC_AUTH_INVALID;
+        }
+#endif /* CONFIG_VNC_TLS */
+#endif /* CONFIG_VNC_SASL */
     } else {
 #ifdef CONFIG_VNC_TLS
-	if (tls) {
-	    vs->auth = VNC_AUTH_VENCRYPT;
-	    if (x509) {
-		VNC_DEBUG("Initializing VNC server with x509 no auth\n");
-		vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
-	    } else {
-		VNC_DEBUG("Initializing VNC server with TLS no auth\n");
-		vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
-	    }
-	} else {
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+            }
+        } else {
 #endif
-	    VNC_DEBUG("Initializing VNC server with no auth\n");
-	    vs->auth = VNC_AUTH_NONE;
+            VNC_DEBUG("Initializing VNC server with no auth\n");
+            vs->auth = VNC_AUTH_NONE;
 #ifdef CONFIG_VNC_TLS
-	    vs->subauth = VNC_AUTH_INVALID;
-	}
+            vs->subauth = VNC_AUTH_INVALID;
+        }
 #endif
     }
-#ifndef _WIN32
-    if (strstart(display, "unix:", &p)) {
-	sock_address_init_unix( &addr, p);
-	vs->lsock = socket_create( SOCKET_UNIX, SOCKET_STREAM );
-	if (vs->lsock == -1) {
-	    fprintf(stderr, "Could not create socket\n");
-	    goto FAIL;
-	}
 
-	if (!reverse) {
-	    unlink(p);
-	}
-    } else
-#endif
-    {
-	if (parse_host_port(&addr, display) < 0) {
-	    fprintf(stderr, "Could not parse VNC address\n");
-	    goto FAIL;
-	}
-
-	sock_address_set_port(&addr, reverse ? 0 : 5900);
-
-	vs->lsock = socket_create_inet( SOCKET_STREAM );
-	if (vs->lsock == -1) {
-	    fprintf(stderr, "Could not create socket\n");
-	    goto FAIL;
-	}
-
-	ret = socket_set_xreuseaddr(vs->lsock);
-	if (ret == -1) {
-	    fprintf(stderr, "setsockopt() failed\n");
-	    goto FAIL;
-	}
+#ifdef CONFIG_VNC_SASL
+    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
+        fprintf(stderr, "Failed to initialize SASL auth %s",
+                sasl_errstring(saslErr, NULL, NULL));
+        free(vs->display);
+        vs->display = NULL;
+        return -1;
     }
+#endif
 
     if (reverse) {
-        if (socket_connect(vs->lsock, &addr) == -1) {
-            fprintf(stderr, "Connection to VNC client failed\n");
-            goto FAIL;
+        /* connect to viewer */
+        if (strncmp(display, "unix:", 5) == 0)
+            vs->lsock = unix_connect(display+5);
+        else
+            vs->lsock = inet_connect(display, SOCK_STREAM);
+        if (-1 == vs->lsock) {
+            free(vs->display);
+            vs->display = NULL;
+            return -1;
+        } else {
+            int csock = vs->lsock;
+            vs->lsock = -1;
+            vnc_connect(vs, csock);
         }
-        vs->csock = vs->lsock;
-        vs->lsock = -1;
-        vnc_connect(vs);
         return 0;
+
+    } else {
+        /* listen for connects */
+        char *dpy;
+        dpy = qemu_malloc(256);
+        if (strncmp(display, "unix:", 5) == 0) {
+            pstrcpy(dpy, 256, "unix:");
+            vs->lsock = unix_listen(display+5, dpy+5, 256-5);
+        } else {
+            vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
+        }
+        if (-1 == vs->lsock) {
+            free(dpy);
+            return -1;
+        } else {
+            free(vs->display);
+            vs->display = dpy;
+        }
     }
-
-    if (socket_bind(vs->lsock, &addr) == -1) {
-	fprintf(stderr, "bind() failed\n");
-	goto FAIL;
-    }
-
-    if (socket_listen(vs->lsock, 1) == -1) {
-	fprintf(stderr, "listen() failed\n");
-	goto FAIL;
-    }
-
-    return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
-
-FAIL:
-    sock_address_done(&addr);
-
-    if (vs->lsock >= 0) {
-        socket_close(vs->lsock);
-        vs->lsock = -1;
-    }
-    free(vs->display);
-    vs->display = NULL;
-    return -1;
+    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
 }
diff --git a/vnc.h b/vnc.h
new file mode 100644
index 0000000..3ae95f3
--- /dev/null
+++ b/vnc.h
@@ -0,0 +1,319 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef __QEMU_VNC_H
+#define __QEMU_VNC_H
+
+#include "qemu-common.h"
+#include "console.h"
+#include "monitor.h"
+#include "audio/audio.h"
+#include <zlib.h>
+
+#include "keymaps.h"
+
+// #define _VNC_DEBUG 1
+
+#ifdef _VNC_DEBUG
+#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define VNC_DEBUG(fmt, ...) do { } while (0)
+#endif
+
+/*****************************************************************************
+ *
+ * Core data structures
+ *
+ *****************************************************************************/
+
+typedef struct Buffer
+{
+    size_t capacity;
+    size_t offset;
+    uint8_t *buffer;
+} Buffer;
+
+typedef struct VncState VncState;
+
+typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
+
+typedef void VncWritePixels(VncState *vs, void *data, int size);
+
+typedef void VncSendHextileTile(VncState *vs,
+                                int x, int y, int w, int h,
+                                void *last_bg,
+                                void *last_fg,
+                                int *has_bg, int *has_fg);
+
+#define VNC_MAX_WIDTH 2048
+#define VNC_MAX_HEIGHT 2048
+#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
+
+#define VNC_AUTH_CHALLENGE_SIZE 16
+
+typedef struct VncDisplay VncDisplay;
+
+#ifdef CONFIG_VNC_TLS
+#include "vnc-tls.h"
+#include "vnc-auth-vencrypt.h"
+#endif
+#ifdef CONFIG_VNC_SASL
+#include "vnc-auth-sasl.h"
+#endif
+
+
+struct VncDisplay
+{
+    int lsock;
+    DisplayState *ds;
+    VncState *clients;
+    kbd_layout_t *kbd_layout;
+
+    char *display;
+    char *password;
+    int auth;
+#ifdef CONFIG_VNC_TLS
+    int subauth; /* Used by VeNCrypt */
+    VncDisplayTLS tls;
+#endif
+#ifdef CONFIG_VNC_SASL
+    VncDisplaySASL sasl;
+#endif
+};
+
+struct VncSurface
+{
+    uint32_t dirty[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
+    DisplaySurface *ds;
+};
+
+struct VncState
+{
+    QEMUTimer *timer;
+    int csock;
+
+    DisplayState *ds;
+    struct VncSurface guest;   /* guest visible surface (aka ds->surface) */
+    struct VncSurface server;  /* vnc server surface */
+
+    VncDisplay *vd;
+    int need_update;
+    int force_update;
+    uint32_t features;
+    int absolute;
+    int last_x;
+    int last_y;
+
+    uint32_t vnc_encoding;
+    uint8_t tight_quality;
+    uint8_t tight_compression;
+
+    int major;
+    int minor;
+
+    char challenge[VNC_AUTH_CHALLENGE_SIZE];
+#ifdef CONFIG_VNC_TLS
+    VncStateTLS tls;
+#endif
+#ifdef CONFIG_VNC_SASL
+    VncStateSASL sasl;
+#endif
+
+    Buffer output;
+    Buffer input;
+    /* current output mode information */
+    VncWritePixels *write_pixels;
+    VncSendHextileTile *send_hextile_tile;
+    DisplaySurface clientds;
+
+    CaptureVoiceOut *audio_cap;
+    struct audsettings as;
+
+    VncReadEvent *read_handler;
+    size_t read_handler_expect;
+    /* input */
+    uint8_t modifiers_state[256];
+
+    Buffer zlib;
+    Buffer zlib_tmp;
+    z_stream zlib_stream[4];
+
+    VncState *next;
+};
+
+
+/*****************************************************************************
+ *
+ * Authentication modes
+ *
+ *****************************************************************************/
+
+enum {
+    VNC_AUTH_INVALID = 0,
+    VNC_AUTH_NONE = 1,
+    VNC_AUTH_VNC = 2,
+    VNC_AUTH_RA2 = 5,
+    VNC_AUTH_RA2NE = 6,
+    VNC_AUTH_TIGHT = 16,
+    VNC_AUTH_ULTRA = 17,
+    VNC_AUTH_TLS = 18,      /* Supported in GTK-VNC & VINO */
+    VNC_AUTH_VENCRYPT = 19, /* Supported in GTK-VNC & VeNCrypt */
+    VNC_AUTH_SASL = 20,     /* Supported in GTK-VNC & VINO */
+};
+
+enum {
+    VNC_AUTH_VENCRYPT_PLAIN = 256,
+    VNC_AUTH_VENCRYPT_TLSNONE = 257,
+    VNC_AUTH_VENCRYPT_TLSVNC = 258,
+    VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
+    VNC_AUTH_VENCRYPT_X509NONE = 260,
+    VNC_AUTH_VENCRYPT_X509VNC = 261,
+    VNC_AUTH_VENCRYPT_X509PLAIN = 262,
+    VNC_AUTH_VENCRYPT_X509SASL = 263,
+    VNC_AUTH_VENCRYPT_TLSSASL = 264,
+};
+
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define VNC_ENCODING_RAW                  0x00000000
+#define VNC_ENCODING_COPYRECT             0x00000001
+#define VNC_ENCODING_RRE                  0x00000002
+#define VNC_ENCODING_CORRE                0x00000004
+#define VNC_ENCODING_HEXTILE              0x00000005
+#define VNC_ENCODING_ZLIB                 0x00000006
+#define VNC_ENCODING_TIGHT                0x00000007
+#define VNC_ENCODING_ZLIBHEX              0x00000008
+#define VNC_ENCODING_TRLE                 0x0000000f
+#define VNC_ENCODING_ZRLE                 0x00000010
+#define VNC_ENCODING_ZYWRLE               0x00000011
+#define VNC_ENCODING_COMPRESSLEVEL0       0xFFFFFF00 /* -256 */
+#define VNC_ENCODING_QUALITYLEVEL0        0xFFFFFFE0 /* -32  */
+#define VNC_ENCODING_XCURSOR              0xFFFFFF10 /* -240 */
+#define VNC_ENCODING_RICH_CURSOR          0xFFFFFF11 /* -239 */
+#define VNC_ENCODING_POINTER_POS          0xFFFFFF18 /* -232 */
+#define VNC_ENCODING_LASTRECT             0xFFFFFF20 /* -224 */
+#define VNC_ENCODING_DESKTOPRESIZE        0xFFFFFF21 /* -223 */
+#define VNC_ENCODING_POINTER_TYPE_CHANGE  0XFFFFFEFF /* -257 */
+#define VNC_ENCODING_EXT_KEY_EVENT        0XFFFFFEFE /* -258 */
+#define VNC_ENCODING_AUDIO                0XFFFFFEFD /* -259 */
+#define VNC_ENCODING_WMVi                 0x574D5669
+
+/*****************************************************************************
+ *
+ * Other tight constants
+ *
+ *****************************************************************************/
+
+/*
+ * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+ */
+
+#define VNC_TIGHT_CCB_RESET_MASK   (0x0f)
+#define VNC_TIGHT_CCB_TYPE_MASK    (0x0f << 4)
+#define VNC_TIGHT_CCB_TYPE_FILL    (0x08 << 4)
+#define VNC_TIGHT_CCB_TYPE_JPEG    (0x09 << 4)
+#define VNC_TIGHT_CCB_BASIC_MAX    (0x07 << 4)
+#define VNC_TIGHT_CCB_BASIC_ZLIB   (0x03 << 4)
+#define VNC_TIGHT_CCB_BASIC_FILTER (0x04 << 4)
+
+/*****************************************************************************
+ *
+ * Features
+ *
+ *****************************************************************************/
+
+#define VNC_FEATURE_RESIZE                   0
+#define VNC_FEATURE_HEXTILE                  1
+#define VNC_FEATURE_POINTER_TYPE_CHANGE      2
+#define VNC_FEATURE_WMVI                     3
+#define VNC_FEATURE_TIGHT                    4
+#define VNC_FEATURE_ZLIB                     5
+#define VNC_FEATURE_COPYRECT                 6
+
+#define VNC_FEATURE_RESIZE_MASK              (1 << VNC_FEATURE_RESIZE)
+#define VNC_FEATURE_HEXTILE_MASK             (1 << VNC_FEATURE_HEXTILE)
+#define VNC_FEATURE_POINTER_TYPE_CHANGE_MASK (1 << VNC_FEATURE_POINTER_TYPE_CHANGE)
+#define VNC_FEATURE_WMVI_MASK                (1 << VNC_FEATURE_WMVI)
+#define VNC_FEATURE_TIGHT_MASK               (1 << VNC_FEATURE_TIGHT)
+#define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
+#define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
+
+
+/*****************************************************************************
+ *
+ * Internal APIs
+ *
+ *****************************************************************************/
+
+/* Event loop functions */
+void vnc_client_read(void *opaque);
+void vnc_client_write(void *opaque);
+
+long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
+long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
+
+/* Protocol I/O functions */
+void vnc_write(VncState *vs, const void *data, size_t len);
+void vnc_write_u32(VncState *vs, uint32_t value);
+void vnc_write_s32(VncState *vs, int32_t value);
+void vnc_write_u16(VncState *vs, uint16_t value);
+void vnc_write_u8(VncState *vs, uint8_t value);
+void vnc_flush(VncState *vs);
+void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
+
+
+/* Buffer I/O functions */
+uint8_t read_u8(uint8_t *data, size_t offset);
+uint16_t read_u16(uint8_t *data, size_t offset);
+int32_t read_s32(uint8_t *data, size_t offset);
+uint32_t read_u32(uint8_t *data, size_t offset);
+
+/* Protocol stage functions */
+void vnc_client_error(VncState *vs);
+int vnc_client_io_error(VncState *vs, int ret, int last_errno);
+
+void start_client_init(VncState *vs);
+void start_auth_vnc(VncState *vs);
+
+/* Buffer management */
+void buffer_reserve(Buffer *buffer, size_t len);
+int buffer_empty(Buffer *buffer);
+uint8_t *buffer_end(Buffer *buffer);
+void buffer_reset(Buffer *buffer);
+void buffer_append(Buffer *buffer, const void *data, size_t len);
+
+
+/* Misc helpers */
+
+char *vnc_socket_local_addr(const char *format, int fd);
+char *vnc_socket_remote_addr(const char *format, int fd);
+
+#endif /* __QEMU_VNC_H */
diff --git a/vnc_keysym.h b/vnc_keysym.h
index b6a172d..2d255c9 100644
--- a/vnc_keysym.h
+++ b/vnc_keysym.h
@@ -1,8 +1,7 @@
-typedef struct {
-	const char* name;
-	int keysym;
-} name2keysym_t;
-static name2keysym_t name2keysym[]={
+
+#include "keymaps.h"
+
+static const name2keysym_t name2keysym[]={
 /* ascii */
     { "space",                0x020},
     { "exclam",               0x021},
@@ -204,6 +203,7 @@
 {"EuroSign", 0x20ac},  /* XK_EuroSign */
 
     /* modifiers */
+{"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */
 {"Control_L", 0xffe3}, /* XK_Control_L */
 {"Control_R", 0xffe4}, /* XK_Control_R */
 {"Alt_L", 0xffe9},     /* XK_Alt_L */
@@ -286,6 +286,28 @@
 {"Pause", 0xff13},       /* XK_Pause */
 {"Escape", 0xff1b},      /* XK_Escape */
 
+/* dead keys */
+{"dead_grave", 0xfe50}, /* XK_dead_grave */
+{"dead_acute", 0xfe51}, /* XK_dead_acute */
+{"dead_circumflex", 0xfe52}, /* XK_dead_circumflex */
+{"dead_tilde", 0xfe53}, /* XK_dead_tilde */
+{"dead_macron", 0xfe54}, /* XK_dead_macron */
+{"dead_breve", 0xfe55}, /* XK_dead_breve */
+{"dead_abovedot", 0xfe56}, /* XK_dead_abovedot */
+{"dead_diaeresis", 0xfe57}, /* XK_dead_diaeresis */
+{"dead_abovering", 0xfe58}, /* XK_dead_abovering */
+{"dead_doubleacute", 0xfe59}, /* XK_dead_doubleacute */
+{"dead_caron", 0xfe5a}, /* XK_dead_caron */
+{"dead_cedilla", 0xfe5b}, /* XK_dead_cedilla */
+{"dead_ogonek", 0xfe5c}, /* XK_dead_ogonek */
+{"dead_iota", 0xfe5d}, /* XK_dead_iota */
+{"dead_voiced_sound", 0xfe5e}, /* XK_dead_voiced_sound */
+{"dead_semivoiced_sound", 0xfe5f}, /* XK_dead_semivoiced_sound */
+{"dead_belowdot", 0xfe60}, /* XK_dead_belowdot */
+{"dead_hook", 0xfe61}, /* XK_dead_hook */
+{"dead_horn", 0xfe62}, /* XK_dead_horn */
+
+
     /* localized keys */
 {"BackApostrophe", 0xff21},
 {"Muhenkan", 0xff22},
diff --git a/vnchextile.h b/vnchextile.h
index eb05feb..f5b6fcb 100644
--- a/vnchextile.h
+++ b/vnchextile.h
@@ -13,7 +13,7 @@
                                              void *last_fg_,
                                              int *has_bg, int *has_fg)
 {
-    uint8_t *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth);
+    uint8_t *row = vs->server.ds->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
     pixel_t *irow = (pixel_t *)row;
     int j, i;
     pixel_t *last_bg = (pixel_t *)last_bg_;
@@ -24,7 +24,7 @@
     int bg_count = 0;
     int fg_count = 0;
     int flags = 0;
-    uint8_t data[(vs->pix_bpp + 2) * 16 * 16];
+    uint8_t data[(vs->clientds.pf.bytes_per_pixel + 2) * 16 * 16];
     int n_data = 0;
     int n_subtiles = 0;
 
@@ -57,7 +57,7 @@
 	}
 	if (n_colors > 2)
 	    break;
-	irow += vs->ds->linesize / sizeof(pixel_t);
+	irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
     }
 
     if (n_colors > 1 && fg_count > bg_count) {
@@ -105,7 +105,7 @@
 		n_data += 2;
 		n_subtiles++;
 	    }
-	    irow += vs->ds->linesize / sizeof(pixel_t);
+	    irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
 	}
 	break;
     case 3:
@@ -132,7 +132,7 @@
 		    has_color = 0;
 #ifdef GENERIC
                     vnc_convert_pixel(vs, data + n_data, color);
-                    n_data += vs->pix_bpp;
+                    n_data += vs->clientds.pf.bytes_per_pixel;
 #else
 		    memcpy(data + n_data, &color, sizeof(color));
                     n_data += sizeof(pixel_t);
@@ -152,7 +152,7 @@
 	    if (has_color) {
 #ifdef GENERIC
                 vnc_convert_pixel(vs, data + n_data, color);
-                n_data += vs->pix_bpp;
+                n_data += vs->clientds.pf.bytes_per_pixel;
 #else
                 memcpy(data + n_data, &color, sizeof(color));
                 n_data += sizeof(pixel_t);
@@ -161,7 +161,7 @@
 		n_data += 2;
 		n_subtiles++;
 	    }
-	    irow += vs->ds->linesize / sizeof(pixel_t);
+	    irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
 	}
 
 	/* A SubrectsColoured subtile invalidates the foreground color */
@@ -197,8 +197,8 @@
 	}
     } else {
 	for (j = 0; j < h; j++) {
-	    vs->write_pixels(vs, row, w * vs->depth);
-	    row += vs->ds->linesize;
+	    vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
+	    row += ds_get_linesize(vs->ds);
 	}
     }
 }