summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS494
-rw-r--r--Makefile13
-rw-r--r--Makefile.objs32
-rw-r--r--Makefile.target8
-rw-r--r--QMP/README5
-rwxr-xr-xQMP/qmp-shell254
-rw-r--r--QMP/qmp.py157
-rwxr-xr-xQMP/vm-info33
-rw-r--r--default-configs/arm-softmmu.mak3
-rw-r--r--default-configs/cris-softmmu.mak1
-rw-r--r--default-configs/i386-softmmu.mak4
-rw-r--r--default-configs/m68k-softmmu.mak2
-rw-r--r--default-configs/microblaze-softmmu.mak1
-rw-r--r--default-configs/mips-softmmu.mak3
-rw-r--r--default-configs/mips64-softmmu.mak3
-rw-r--r--default-configs/mips64el-softmmu.mak3
-rw-r--r--default-configs/mipsel-softmmu.mak3
-rw-r--r--default-configs/pci.mak12
-rw-r--r--default-configs/ppc-softmmu.mak3
-rw-r--r--default-configs/ppc64-softmmu.mak3
-rw-r--r--default-configs/ppcemb-softmmu.mak3
-rw-r--r--default-configs/s390x-softmmu.mak1
-rw-r--r--default-configs/sh4-softmmu.mak3
-rw-r--r--default-configs/sh4eb-softmmu.mak3
-rw-r--r--default-configs/sparc-softmmu.mak2
-rw-r--r--default-configs/sparc64-softmmu.mak2
-rw-r--r--default-configs/x86_64-softmmu.mak4
-rw-r--r--hw/pcnet-pci.c345
-rw-r--r--hw/pcnet.c311
-rw-r--r--hw/pcnet.h3
-rw-r--r--make_device_config.sh28
-rw-r--r--monitor.c38
-rw-r--r--qemu-char.c64
-rw-r--r--qemu-char.h7
-rw-r--r--qmp-commands.hx45
35 files changed, 1338 insertions, 558 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index e5165fbae8..59effc7143 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1,88 +1,428 @@
 QEMU Maintainers
 ================
 
-Project leaders:
-----------------
+The intention of this file is not to establish who owns what portions of the
+code base, but to provide a set of names that developers can consult when they
+have a question about a particular subset and also to provide a set of names
+to be CC'd when submitting a patch to obtain appropriate review.
 
-Fabrice Bellard
-Paul Brook
+In general, if you have a question about inclusion of a patch, you should
+consult qemu-devel and not any specific individual privately.
 
-CPU cores:
-----------
+Descriptions of section entries:
+
+	M: Mail patches to: FullName <address@domain>
+	L: Mailing list that is relevant to this area
+	W: Web-page with status/info
+	Q: Patchwork web based patch tracking system site
+	T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit.
+	S: Status, one of the following:
+	   Supported:	Someone is actually paid to look after this.
+	   Maintained:	Someone actually looks after it.
+	   Odd Fixes:	It has a maintainer but they don't have time to do
+			much other than throw the odd patch in. See below..
+	   Orphan:	No current maintainer [but maybe you could take the
+			role as you write your new code].
+	   Obsolete:	Old code. Something tagged obsolete generally means
+			it has been replaced by a better system and you
+			should be using that.
+	F: Files and directories with wildcard patterns.
+	   A trailing slash includes all files and subdirectory files.
+	   F:	drivers/net/	all files in and below drivers/net
+	   F:	drivers/net/*	all files in drivers/net, but not below
+	   F:	*/net/*		all files in "any top level directory"/net
+	   One pattern per line.  Multiple F: lines acceptable.
+	X: Files and directories that are NOT maintained, same rules as F:
+	   Files exclusions are tested before file matches.
+	   Can be useful for excluding a specific subdirectory, for instance:
+	   F:	net/
+	   X:	net/ipv6/
+	   matches all files in and below net excluding net/ipv6/
+	K: Keyword perl extended regex pattern to match content in a
+	   patch or file.  For instance:
+	   K: of_get_profile
+	      matches patches or files that contain "of_get_profile"
+	   K: \b(printk|pr_(info|err))\b
+	      matches patches or files that contain one or more of the words
+	      printk, pr_info or pr_err
+	   One regex pattern per line.  Multiple K: lines acceptable.
+
+
+General Project Administration
+------------------------------
+M: Anthony Liguori <aliguori@us.ibm.com>
+M: Paul Brook <paul@codesourcery.com>
+
+Guest CPU cores (TCG):
+----------------------
+Alpha
+M: qemu-devel@nongnu.org
+S: Orphan
+F: target-alpha/
 
-x86                Fabrice Bellard
-ARM                Paul Brook
-SPARC              Blue Swirl
-MIPS               ?
-PowerPC            Alexander Graf
-M68K               Paul Brook
-SH4                ?
-CRIS               Edgar E. Iglesias
-Alpha              ?
-MicroBlaze         Edgar E. Iglesias
-S390               ?
-
-Machines (sorted by CPU):
--------------------------
-
-x86
-  pc.c                    Fabrice Bellard (new maintainer needed)
 ARM
-  integratorcp.c          Paul Brook
-  versatilepb.c           Paul Brook
-  Real View               Paul Brook
-  spitz.c                 Andrzej Zaborowski
-  palm.c                  Andrzej Zaborowski
-  nseries.c               Andrzej Zaborowski
-  stellaris.c             Paul Brook
-  gumstix.c               Thorsten Zitterell
-  mainstone.c             Armin Kuster
-  musicpal.c              Jan Kiszka
-SPARC
-  sun4u.c                 Blue Swirl
-  sun4m.c                 Blue Swirl
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: target-arm/
+
+CRIS
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: target-cris/
+
+M68K
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: target-m68k/
+
+MicroBlaze
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: target-microblaze/
+
 MIPS
-  mips_r4k.c              Aurelien Jarno
-  mips_malta.c            Aurelien Jarno
-  mips_jazz.c             Hervé Poussineau
-  mips_mipssim.c          ?
+M: qemu-devel@nongnu.org
+S: Orphan
+F: target-mips/
+
 PowerPC
-  ppc_prep.c              ?
-  ppc_oldworld.c          Alexander Graf
-  ppc_newworld.c          Alexander Graf
-  ppc405_boards.c         Alexander Graf
-M86K
-  mcf5208.c               Paul Brook
-  an5206.c                Paul Brook
-  dummy_m68k.c            Paul Brook
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: target-ppc/
+
+S390
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: target-s390x/
+
 SH4
-  shix.c                  ?
-  r2d.c                   Magnus Damm
-CRIS
-  etraxfs.c               Edgar E. Iglesias
-  axis_dev88.c            Edgar E. Iglesias
-Alpha
-MicroBlaze
-  petalogix_s3adsp1800.c  Edgar E. Iglesias
+M: qemu-devel@nongnu.org
+S: Orphan
+F: target-sh4/
+
+SPARC
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: target-sparc/
+
+X86
+M: qemu-devel@nongnu.org
+S: Odd Fixes
+F: target-i386/
+
+Guest CPU Cores (KVM):
+----------------------
+
+Overall
+M: Avi Kivity <avi@redhat.com>
+M: Marcelo Tosatti <mtosatti@redhat.com>
+L: kvm@vger.kernel.org
+S: Supported
+F: kvm-*
+F: */kvm.*
+
+PPC
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: target-ppc/kvm.c
+
 S390
-  s390-*.c                Alexander Graf
-
-Generic Subsystems:
--------------------  
-
-Dynamic translator        Fabrice Bellard
-Main loop                 Fabrice Bellard (new maintainer needed)
-TCG                       Fabrice Bellard
-IDE device                ?
-SCSI device               Paul Brook
-PCI layer                 Michael S. Tsirkin
-USB layer                 ?
-Block layer               ?
-Graphic layer             ?
-Audio device layer        Vassili Karpov (malc)
-Character device layer    ?
-Network device layer      ?
-GDB stub                  ?
-Linux user                ?
-Darwin user               ?
-SLIRP                     ?
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: target-s390x/kvm.c
+
+X86
+M: Avi Kivity <avi@redhat.com>
+M: Marcelo Tosatti <mtosatti@redhat.com>
+L: kvm@vger.kernel.org
+S: Supported
+F: target-i386/kvm.c
+
+ARM Machines
+------------
+Gumstix
+M: qemu-devel@nongnu.org
+S: Orphan
+F: hw/gumstix.c
+
+Integrator CP
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/integratorcp.c
+
+Mainstone
+M: qemu-devel@nongnu.org
+S: Orphan
+F: hw/mainstone.c
+
+Musicpal
+M: Jan Kiszka <jan.kiszka@web.de>
+S: Maintained
+F: hw/musicpal.c
+
+nSeries
+M: Andrzej Zaborowski <balrogg@gmail.com>
+S: Maintained
+F: hw/nseries.c
+
+Palm
+M: Andrzej Zaborowski <balrogg@gmail.com>
+S: Maintained
+F: hw/palm.c
+
+Real View
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/realview*
+
+Spitz
+M: Andrzej Zaborowski <balrogg@gmail.com>
+S: Maintained
+F: hw/spitz.c
+
+Stellaris
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/stellaris.c
+
+Versatile PB
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/versatilepb.c
+
+CRIS Machines
+-------------
+Axis Dev88
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: hw/axis_dev88.c
+
+etraxfs
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: hw/etraxfs.c
+
+M86K Machines
+-------------
+an5206
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/an5206.c
+
+dummy_m68k
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/dummy_m68k.c
+
+mcf5208
+M: Paul Brook <paul@codesourcery.com>
+S: Maintained
+F: hw/mcf5208.c
+
+MicroBlaze Machines
+-------------------
+petalogix_s3adsp1800
+M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
+S: Maintained
+F: hw/petalogix_s3adsp1800.c
+
+MIPS Machines
+-------------
+Jazz
+M: Hervé Poussineau <hpoussin@reactos.org>
+S: Maintained
+F: hw/mips_jazz.c
+
+Malta
+M: Aurelien Jarno <aurelien@aurel32.net>
+S: Maintained
+F: hw/mips_malta.c
+
+Mipssim
+M: qemu-devel@nongnu.org
+S: Orphan
+F: hw/mips_mipssim.c
+
+R4000
+M: Aurelien Jarno <aurelien@aurel32.net>
+S: Maintained
+F: hw/mips_r4k.c
+
+PowerPC Machines
+----------------
+405
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: hw/ppc405_boards.c
+
+New World
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: hw/ppc_newworld.c
+
+Old World
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: hw/ppc_oldworld.c
+
+Prep
+M: qemu-devel@nongnu.org
+S: Orphan
+F: hw/ppc_prep.c
+
+SH4 Machines
+------------
+R2D
+M: Magnus Damm <magnus.damm@gmail.com>
+S: Maintained
+F: hw/r2d.c
+
+Shix
+M: Magnus Damm <magnus.damm@gmail.com>
+S: Oprhan
+F: hw/shix.c
+
+SPARC Machines
+--------------
+Sun4m
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: hw/sun4m.c
+
+Sun4u
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: hw/sun4u.c
+
+S390 Machines
+-------------
+S390 Virtio
+M: Alexander Graf <agraf@suse.de>
+S: Maintained
+F: hw/s390-*.c
+
+X86 Machines
+------------
+PC
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Supported
+F: hw/pc.[ch] hw/pc_piix.c
+
+Devices
+-------
+IDE
+M: Kevin Wolf <kwolf@redhat.com>
+S: Odd Fixes
+F: hw/ide/
+
+PCI
+M: Michael S. Tsirkin <mst@redhat.com>
+S: Supported
+F: hw/pci*
+F: hw/piix*
+
+SCSI
+M: Paul Brook <paul@codesourcery.com>
+M: Kevin Wolf <kwolf@redhat.com>
+S: Odd Fixes
+F: hw/lsi53c895a.c
+F: hw/scsi*
+
+USB
+M: qemu-devel@nongnu.org
+S: Odd Fixes
+F: hw/usb*
+
+vhost
+M: Michael S. Tsirkin <mst@redhat.com>
+S: Supported
+F: hw/vhost*
+
+virtio
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Supported
+F: hw/virtio*
+
+virtio-9p
+M: Venkateswararao Jujjuri (JV) <jvrao@linux.vnet.ibm.com>
+S: Supported
+F: hw/virtio-9p*
+
+virtio-blk
+M: Kevin Wolf <kwolf@redhat.com>
+S: Supported
+F: hw/virtio-blk*
+
+virtio-serial
+M: Amit Shah <amit.shah@redhat.com>
+S: Supported
+F: hw/virtio-serial*
+F: hw/virtio-console*
+
+Subsystems
+----------
+Audio
+M: Vassili Karpov (malc) <av1474@comtv.ru>
+S: Maintained
+F: audio/
+
+Block
+M: Kevin Wolf <kwolf@redhat.com>
+S: Supported
+F: block*
+F: block/
+
+Character Devices
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Maintained
+F: qemu-char.c
+
+GDB stub
+M: qemu-devel@nongnu.org
+S: Odd Fixes
+F: gdbstub*
+F: gdb-xml/
+
+Graphics
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Maintained
+F: ui/
+
+Main loop
+M: Anthony Liguori <aliguori@us.ibm.com>
+S: Supported
+F: vl.c
+
+Monitor (QMP/HMP)
+M: Luiz Capitulino <lcapitulino@redhat.com>
+M: Markus Armbruster <armbru@redhat.com>
+S: Supported
+F: monitor.c
+
+Network device layer
+M: Anthony Liguori <aliguori@us.ibm.com>
+M: Mark McLoughlin <markmc@redhat.com>
+S: Maintained
+F: net/
+
+SLIRP
+M: qemu-devel@nongnu.org
+S: Orphan
+F: slirp/
+
+Usermode Emulation
+------------------
+BSD user
+M: Blue Swirl <blauwirbel@gmail.com>
+S: Maintained
+F: bsd-user/
+
+Darwin user
+M: qemu-devel@nongnu.org
+S: Orphan
+F: darwin-user/
+
+Linux user
+M: Riku Voipio <riku.voipio@iki.fi>
+S: Maintained
+F: linux-user/
diff --git a/Makefile b/Makefile
index 4e120a2d3a..d3bc0f2c74 100644
--- a/Makefile
+++ b/Makefile
@@ -39,18 +39,19 @@ endif
 
 SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
 SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
+SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
 
 config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
 	$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@,"  GEN   $@")
 
+-include $(SUBDIR_DEVICES_MAK_DEP)
+
 %/config-devices.mak: default-configs/%.mak
-	$(call quiet-command,cat $< > $@.tmp, "  GEN   $@")
+	$(call quiet-command,$(SHELL) $(SRC_PATH)/make_device_config.sh $@ $<, "  GEN   $@")
 	@if test -f $@; then \
 	  if cmp -s $@.old $@; then \
-	    if ! cmp -s $@ $@.tmp; then \
-	      mv $@.tmp $@; \
-	      cp -p $@ $@.old; \
-	    fi; \
+	    mv $@.tmp $@; \
+	    cp -p $@ $@.old; \
 	  else \
 	    if test -f $@.old; then \
 	      echo "WARNING: $@ (user modified) out of date.";\
@@ -150,7 +151,7 @@ version-obj-$(CONFIG_WIN32) += version.o
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
-qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS)
+qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS)
 
 qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
diff --git a/Makefile.objs b/Makefile.objs
index 23b17cefad..13ba26fdcb 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -42,6 +42,11 @@ net-nested-$(CONFIG_SLIRP) += slirp.o
 net-nested-$(CONFIG_VDE) += vde.o
 net-obj-y += $(addprefix net/, $(net-nested-y))
 
+ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy)
+# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
+# only pull in the actual virtio-9p device if we also enabled virtio.
+CONFIG_REALLY_VIRTFS=y
+endif
 fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
 fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
 
@@ -159,9 +164,13 @@ user-obj-y += cutils.o cache-utils.o
 
 hw-obj-y =
 hw-obj-y += vl.o loader.o
-hw-obj-y += virtio.o virtio-console.o
-hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
-hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
+hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
+hw-obj-y += fw_cfg.o
+# FIXME: Core PCI code and its direct dependencies are required by the
+# QMP query-pci command.
+hw-obj-y += pci.o pci_bridge.o msix.o msi.o
+hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
+hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
 hw-obj-y += watchdog.o
 hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 hw-obj-$(CONFIG_ECC) += ecc.o
@@ -206,15 +215,15 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
 hw-obj-$(CONFIG_PIIX4) += piix4.o
 
 # PCI watchdog devices
-hw-obj-y += wdt_i6300esb.o
+hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
 
-hw-obj-y += pcie.o pcie_port.o
-hw-obj-y += msix.o msi.o
+hw-obj-$(CONFIG_PCI) += pcie.o pcie_port.o
 
 # PCI network cards
-hw-obj-y += ne2000.o
-hw-obj-y += eepro100.o
-hw-obj-y += pcnet.o
+hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
+hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
+hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
+hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
 
 hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
 hw-obj-$(CONFIG_LAN9118) += lan9118.o
@@ -231,7 +240,7 @@ hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
 hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
 
 # SCSI layer
-hw-obj-y += lsi53c895a.o
+hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
 hw-obj-$(CONFIG_ESP) += esp.o
 
 hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
@@ -261,7 +270,8 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
 adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 
-hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o virtio-9p-xattr.o
+hw-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p-debug.o
+hw-obj-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
 hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 
 ######################################################################
diff --git a/Makefile.target b/Makefile.target
index 2800f473b7..578484452b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -188,11 +188,11 @@ ifdef CONFIG_SOFTMMU
 obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
-obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
+obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
 obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 obj-y += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_VIRTFS) += virtio-9p.o
+obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o
 obj-y += rwhandler.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
@@ -210,8 +210,8 @@ obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
 obj-$(CONFIG_USB_OHCI) += usb-ohci.o
 
 # PCI network cards
-obj-y += rtl8139.o
-obj-y += e1000.o
+obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
+obj-$(CONFIG_E1000_PCI) += e1000.o
 
 # Inter-VM PCI shared memory
 obj-$(CONFIG_KVM) += ivshmem.o
diff --git a/QMP/README b/QMP/README
index 80503f2d7a..c95a08c234 100644
--- a/QMP/README
+++ b/QMP/README
@@ -19,10 +19,7 @@ o qmp-spec.txt      QEMU Monitor Protocol current specification
 o qmp-commands.txt  QMP supported commands (auto-generated at build-time)
 o qmp-events.txt    List of available asynchronous events
 
-There are also two simple Python scripts available:
-
-o qmp-shell  A shell
-o vm-info    Show some information about the Virtual Machine
+There is also a simple Python script called 'qmp-shell' available.
 
 IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
 section in the qmp-commands.txt file before making any serious use of QMP.
diff --git a/QMP/qmp-shell b/QMP/qmp-shell
index a5b72d15d1..42dabc8c6d 100755
--- a/QMP/qmp-shell
+++ b/QMP/qmp-shell
@@ -1,8 +1,8 @@
 #!/usr/bin/python
 #
-# Simple QEMU shell on top of QMP
+# Low-level QEMU shell on top of QMP.
 #
-# Copyright (C) 2009 Red Hat Inc.
+# Copyright (C) 2009, 2010 Red Hat Inc.
 #
 # Authors:
 #  Luiz Capitulino <lcapitulino@redhat.com>
@@ -14,60 +14,246 @@
 #
 # Start QEMU with:
 #
-# $ qemu [...] -monitor control,unix:./qmp,server
+# # qemu [...] -qmp unix:./qmp-sock,server
 #
 # Run the shell:
 #
-# $ qmp-shell ./qmp
+# $ qmp-shell ./qmp-sock
 #
 # Commands have the following format:
 #
-# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+#    < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
 #
 # For example:
 #
-# (QEMU) info item=network
+# (QEMU) device_add driver=e1000 id=net1
+# {u'return': {}}
+# (QEMU)
 
 import qmp
 import readline
-from sys import argv,exit
+import sys
 
-def shell_help():
-    print 'bye  exit from the shell'
+class QMPCompleter(list):
+    def complete(self, text, state):
+        for cmd in self:
+            if cmd.startswith(text):
+                if not state:
+                    return cmd
+                else:
+                    state -= 1
 
-def main():
-    if len(argv) != 2:
-        print 'qemu-shell <unix-socket>'
-        exit(1)
+class QMPShellError(Exception):
+    pass
+
+class QMPShellBadPort(QMPShellError):
+    pass
+
+# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
+#       _execute_cmd()). Let's design a better one.
+class QMPShell(qmp.QEMUMonitorProtocol):
+    def __init__(self, address):
+        qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
+        self._greeting = None
+        self._completer = None
+
+    def __get_address(self, arg):
+        """
+        Figure out if the argument is in the port:host form, if it's not it's
+        probably a file path.
+        """
+        addr = arg.split(':')
+        if len(addr) == 2:
+            try:
+                port = int(addr[1])
+            except ValueError:
+                raise QMPShellBadPort
+            return ( addr[0], port )
+        # socket path
+        return arg
+
+    def _fill_completion(self):
+        for cmd in self.cmd('query-commands')['return']:
+            self._completer.append(cmd['name'])
+
+    def __completer_setup(self):
+        self._completer = QMPCompleter()
+        self._fill_completion()
+        readline.set_completer(self._completer.complete)
+        readline.parse_and_bind("tab: complete")
+        # XXX: default delimiters conflict with some command names (eg. query-),
+        # clearing everything as it doesn't seem to matter
+        readline.set_completer_delims('')
 
-    qemu = qmp.QEMUMonitorProtocol(argv[1])
-    qemu.connect()
-    qemu.send("qmp_capabilities")
+    def __build_cmd(self, cmdline):
+        """
+        Build a QMP input object from a user provided command-line in the
+        following format:
+    
+            < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+        """
+        cmdargs = cmdline.split()
+        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
+        for arg in cmdargs[1:]:
+            opt = arg.split('=')
+            try:
+                value = int(opt[1])
+            except ValueError:
+                value = opt[1]
+            qmpcmd['arguments'][opt[0]] = value
+        return qmpcmd
+
+    def _execute_cmd(self, cmdline):
+        try:
+            qmpcmd = self.__build_cmd(cmdline)
+        except:
+            print 'command format: <command-name> ',
+            print '[arg-name1=arg1] ... [arg-nameN=argN]'
+            return True
+        resp = self.cmd_obj(qmpcmd)
+        if resp is None:
+            print 'Disconnected'
+            return False
+        print resp
+        return True
+
+    def connect(self):
+        self._greeting = qmp.QEMUMonitorProtocol.connect(self)
+        self.__completer_setup()
 
-    print 'Connected!'
+    def show_banner(self, msg='Welcome to the QMP low-level shell!'):
+        print msg
+        version = self._greeting['QMP']['version']['qemu']
+        print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
 
-    while True:
+    def read_exec_command(self, prompt):
+        """
+        Read and execute a command.
+
+        @return True if execution was ok, return False if disconnected.
+        """
         try:
-            cmd = raw_input('(QEMU) ')
+            cmdline = raw_input(prompt)
         except EOFError:
             print
-            break
-        if cmd == '':
-            continue
-        elif cmd == 'bye':
-            break
-        elif cmd == 'help':
-            shell_help()
+            return False
+        if cmdline == '':
+            for ev in self.get_events():
+                print ev
+            self.clear_events()
+            return True
         else:
+            return self._execute_cmd(cmdline)
+
+class HMPShell(QMPShell):
+    def __init__(self, address):
+        QMPShell.__init__(self, address)
+        self.__cpu_index = 0
+
+    def __cmd_completion(self):
+        for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
+            if cmd and cmd[0] != '[' and cmd[0] != '\t':
+                name = cmd.split()[0] # drop help text
+                if name == 'info':
+                    continue
+                if name.find('|') != -1:
+                    # Command in the form 'foobar|f' or 'f|foobar', take the
+                    # full name
+                    opt = name.split('|')
+                    if len(opt[0]) == 1:
+                        name = opt[1]
+                    else:
+                        name = opt[0]
+                self._completer.append(name)
+                self._completer.append('help ' + name) # help completion
+
+    def __info_completion(self):
+        for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
+            if cmd:
+                self._completer.append('info ' + cmd.split()[1])
+
+    def __other_completion(self):
+        # special cases
+        self._completer.append('help info')
+
+    def _fill_completion(self):
+        self.__cmd_completion()
+        self.__info_completion()
+        self.__other_completion()
+
+    def __cmd_passthrough(self, cmdline, cpu_index = 0):
+        return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
+                              { 'command-line': cmdline,
+                                'cpu-index': cpu_index } })
+
+    def _execute_cmd(self, cmdline):
+        if cmdline.split()[0] == "cpu":
+            # trap the cpu command, it requires special setting
             try:
-                resp = qemu.send(cmd)
-                if resp == None:
-                    print 'Disconnected'
-                    break
-                print resp
-            except IndexError:
-                print '-> command format: <command-name> ',
-                print '[arg-name1=arg1] ... [arg-nameN=argN]'
+                idx = int(cmdline.split()[1])
+                if not 'return' in self.__cmd_passthrough('info version', idx):
+                    print 'bad CPU index'
+                    return True
+                self.__cpu_index = idx
+            except ValueError:
+                print 'cpu command takes an integer argument'
+                return True
+        resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
+        if resp is None:
+            print 'Disconnected'
+            return False
+        assert 'return' in resp or 'error' in resp
+        if 'return' in resp:
+            # Success
+            if len(resp['return']) > 0:
+                print resp['return'],
+        else:
+            # Error
+            print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
+        return True
+
+    def show_banner(self):
+        QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
+
+def die(msg):
+    sys.stderr.write('ERROR: %s\n' % msg)
+    sys.exit(1)
+
+def fail_cmdline(option=None):
+    if option:
+        sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
+    sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n')
+    sys.exit(1)
+
+def main():
+    addr = ''
+    try:
+        if len(sys.argv) == 2:
+            qemu = QMPShell(sys.argv[1])
+            addr = sys.argv[1]
+        elif len(sys.argv) == 3:
+            if sys.argv[1] != '-H':
+                fail_cmdline(sys.argv[1])
+            qemu = HMPShell(sys.argv[2])
+            addr = sys.argv[2]
+        else:
+                fail_cmdline()
+    except QMPShellBadPort:
+        die('bad port number in command-line')
+
+    try:
+        qemu.connect()
+    except qmp.QMPConnectError:
+        die('Didn\'t get QMP greeting message')
+    except qmp.QMPCapabilitiesError:
+        die('Could not negotiate capabilities')
+    except qemu.error:
+        die('Could not connect to %s' % addr)
+
+    qemu.show_banner()
+    while qemu.read_exec_command('(QEMU) '):
+        pass
+    qemu.close()
 
 if __name__ == '__main__':
     main()
diff --git a/QMP/qmp.py b/QMP/qmp.py
index 4062f84f36..14ce8b0d05 100644
--- a/QMP/qmp.py
+++ b/QMP/qmp.py
@@ -1,6 +1,6 @@
 # QEMU Monitor Protocol Python class
 # 
-# Copyright (C) 2009 Red Hat Inc.
+# Copyright (C) 2009, 2010 Red Hat Inc.
 #
 # Authors:
 #  Luiz Capitulino <lcapitulino@redhat.com>
@@ -8,7 +8,9 @@
 # This work is licensed under the terms of the GNU GPL, version 2.  See
 # the COPYING file in the top-level directory.
 
-import socket, json
+import json
+import errno
+import socket
 
 class QMPError(Exception):
     pass
@@ -16,61 +18,114 @@ class QMPError(Exception):
 class QMPConnectError(QMPError):
     pass
 
+class QMPCapabilitiesError(QMPError):
+    pass
+
 class QEMUMonitorProtocol:
+    def __init__(self, address):
+        """
+        Create a QEMUMonitorProtocol class.
+
+        @param address: QEMU address, can be either a unix socket path (string)
+                        or a tuple in the form ( address, port ) for a TCP
+                        connection
+        @note No connection is established, this is done by the connect() method
+        """
+        self.__events = []
+        self.__address = address
+        self.__sock = self.__get_sock()
+        self.__sockfile = self.__sock.makefile()
+
+    def __get_sock(self):
+        if isinstance(self.__address, tuple):
+            family = socket.AF_INET
+        else:
+            family = socket.AF_UNIX
+        return socket.socket(family, socket.SOCK_STREAM)
+
+    def __json_read(self):
+        while True:
+            data = self.__sockfile.readline()
+            if not data:
+                return
+            resp = json.loads(data)
+            if 'event' in resp:
+                self.__events.append(resp)
+                continue
+            return resp
+
+    error = socket.error
+
     def connect(self):
-        self.sock.connect(self.filename)
-        data = self.__json_read()
-        if data == None:
-            raise QMPConnectError
-        if not data.has_key('QMP'):
+        """
+        Connect to the QMP Monitor and perform capabilities negotiation.
+
+        @return QMP greeting dict
+        @raise socket.error on socket connection errors
+        @raise QMPConnectError if the greeting is not received
+        @raise QMPCapabilitiesError if fails to negotiate capabilities
+        """
+        self.__sock.connect(self.__address)
+        greeting = self.__json_read()
+        if greeting is None or not greeting.has_key('QMP'):
             raise QMPConnectError
-        return data['QMP']['capabilities']
+        # Greeting seems ok, negotiate capabilities
+        resp = self.cmd('qmp_capabilities')
+        if "return" in resp:
+            return greeting
+        raise QMPCapabilitiesError
 
-    def close(self):
-        self.sock.close()
+    def cmd_obj(self, qmp_cmd):
+        """
+        Send a QMP command to the QMP Monitor.
 
-    def send_raw(self, line):
-        self.sock.send(str(line))
+        @param qmp_cmd: QMP command to be sent as a Python dict
+        @return QMP response as a Python dict or None if the connection has
+                been closed
+        """
+        try:
+            self.__sock.sendall(json.dumps(qmp_cmd))
+        except socket.error, err:
+            if err[0] == errno.EPIPE:
+                return
+            raise socket.error(err)
         return self.__json_read()
 
-    def send(self, cmdline):
-        cmd = self.__build_cmd(cmdline)
-        self.__json_send(cmd)
-        resp = self.__json_read()
-        if resp == None:
-            return
-        elif resp.has_key('error'):
-            return resp['error']
-        else:
-            return resp['return']
-
-    def __build_cmd(self, cmdline):
-        cmdargs = cmdline.split()
-        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
-        for arg in cmdargs[1:]:
-            opt = arg.split('=')
-            try:
-                value = int(opt[1])
-            except ValueError:
-                value = opt[1]
-            qmpcmd['arguments'][opt[0]] = value
-        return qmpcmd
-
-    def __json_send(self, cmd):
-        # XXX: We have to send any additional char, otherwise
-        # the Server won't read our input
-        self.sock.send(json.dumps(cmd) + ' ')
+    def cmd(self, name, args=None, id=None):
+        """
+        Build a QMP command and send it to the QMP Monitor.
 
-    def __json_read(self):
+        @param name: command name (string)
+        @param args: command arguments (dict)
+        @param id: command id (dict, list, string or int)
+        """
+        qmp_cmd = { 'execute': name }
+        if args:
+            qmp_cmd['arguments'] = args
+        if id:
+            qmp_cmd['id'] = id
+        return self.cmd_obj(qmp_cmd)
+
+    def get_events(self):
+        """
+        Get a list of available QMP events.
+        """
+        self.__sock.setblocking(0)
         try:
-            while True:
-                line = json.loads(self.sockfile.readline())
-                if not 'event' in line:
-                    return line
-        except ValueError:
-            return
-
-    def __init__(self, filename):
-        self.filename = filename
-        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        self.sockfile = self.sock.makefile()
+            self.__json_read()
+        except socket.error, err:
+            if err[0] == errno.EAGAIN:
+                # No data available
+                pass
+        self.__sock.setblocking(1)
+        return self.__events
+
+    def clear_events(self):
+        """
+        Clear current list of pending events.
+        """
+        self.__events = []
+
+    def close(self):
+        self.__sock.close()
+        self.__sockfile.close()
diff --git a/QMP/vm-info b/QMP/vm-info
deleted file mode 100755
index be5b03843c..0000000000
--- a/QMP/vm-info
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/python
-#
-# Print Virtual Machine information
-#
-# Usage:
-#
-# Start QEMU with:
-#
-# $ qemu [...] -monitor control,unix:./qmp,server
-#
-# Run vm-info:
-#
-# $ vm-info ./qmp
-#
-# Luiz Capitulino <lcapitulino@redhat.com>
-
-import qmp
-from sys import argv,exit
-
-def main():
-    if len(argv) != 2:
-        print 'vm-info <unix-socket>'
-        exit(1)
-
-    qemu = qmp.QEMUMonitorProtocol(argv[1])
-    qemu.connect()
-    qemu.send("qmp_capabilities")
-
-    for cmd in [ 'version', 'kvm', 'status', 'uuid', 'balloon' ]:
-        print cmd + ': ' + str(qemu.send('query-' + cmd))
-
-if __name__ == '__main__':
-    main()
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index e7a4e84481..ac48dc1565 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -1,7 +1,7 @@
 # Default configuration for arm-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
 CONFIG_ISA_MMIO=y
 CONFIG_NAND=y
 CONFIG_ECC=y
@@ -25,6 +25,5 @@ CONFIG_SSI_SD=y
 CONFIG_LAN9118=y
 CONFIG_SMC91C111=y
 CONFIG_DS1338=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/cris-softmmu.mak b/default-configs/cris-softmmu.mak
index e0d2cabb2d..1a479cd8d3 100644
--- a/default-configs/cris-softmmu.mak
+++ b/default-configs/cris-softmmu.mak
@@ -2,5 +2,4 @@
 
 CONFIG_NAND=y
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI02=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index ed00471da2..ce905d23d1 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -1,6 +1,6 @@
 # Default configuration for i386-softmmu
 
-CONFIG_USB_OHCI=y
+include pci.mak
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VMWARE_VGA=y
@@ -9,7 +9,6 @@ CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak
index 69ca3ed08e..3e2ec3716c 100644
--- a/default-configs/m68k-softmmu.mak
+++ b/default-configs/m68k-softmmu.mak
@@ -1,5 +1,5 @@
 # Default configuration for m68k-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak
index 6c4f4f2f22..4399b8b361 100644
--- a/default-configs/microblaze-softmmu.mak
+++ b/default-configs/microblaze-softmmu.mak
@@ -1,5 +1,4 @@
 # Default configuration for microblaze-softmmu
 
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 3d0af83165..565e611c53 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for mips-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index 0030de45dc..03bd8ebf8d 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for mips64-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index fa2a3ffa45..4661617700 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for mips64el-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -25,7 +25,6 @@ CONFIG_IDE_PIIX=y
 CONFIG_IDE_VIA=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 238b73ace1..92fc473318 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for mipsel-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_ESP=y
 CONFIG_VGA_PCI=y
@@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_RC4030=y
 CONFIG_DP8393X=y
 CONFIG_DS1225Y=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
new file mode 100644
index 0000000000..c74a99f5c9
--- /dev/null
+++ b/default-configs/pci.mak
@@ -0,0 +1,12 @@
+CONFIG_PCI=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_OHCI=y
+CONFIG_NE2000_PCI=y
+CONFIG_EEPRO100_PCI=y
+CONFIG_PCNET_PCI=y
+CONFIG_PCNET_COMMON=y
+CONFIG_LSI_SCSI_PCI=y
+CONFIG_RTL8139_PCI=y
+CONFIG_E1000_PCI=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 940f4bf375..f1cb99e408 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -1,7 +1,7 @@
 # Default configuration for ppc-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
@@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
 CONFIG_IDE_MACIO=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index e1bc6b8f80..83cbe97f1e 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -1,7 +1,7 @@
 # Default configuration for ppc64-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
@@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
 CONFIG_IDE_MACIO=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index 8f1cc09add..2b52d4a3f3 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -1,7 +1,7 @@
 # Default configuration for ppcemb-softmmu
 
+include pci.mak
 CONFIG_GDBSTUB_XML=y
-CONFIG_USB_OHCI=y
 CONFIG_ISA_MMIO=y
 CONFIG_ESCC=y
 CONFIG_M48T59=y
@@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
 CONFIG_IDE_MACIO=y
 CONFIG_NE2000_ISA=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index e69de29bb2..3005729204 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -0,0 +1 @@
+CONFIG_VIRTIO=y
diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak
index 866ed7de34..87247a4e53 100644
--- a/default-configs/sh4-softmmu.mak
+++ b/default-configs/sh4-softmmu.mak
@@ -1,9 +1,8 @@
 # Default configuration for sh4-softmmu
 
-CONFIG_USB_OHCI=y
+include pci.mak
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_IDE_CORE=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak
index e3e08b7f1a..5b8a16eea2 100644
--- a/default-configs/sh4eb-softmmu.mak
+++ b/default-configs/sh4eb-softmmu.mak
@@ -1,9 +1,8 @@
 # Default configuration for sh4eb-softmmu
 
-CONFIG_USB_OHCI=y
+include pci.mak
 CONFIG_SERIAL=y
 CONFIG_PTIMER=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_IDE_CORE=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
diff --git a/default-configs/sparc-softmmu.mak b/default-configs/sparc-softmmu.mak
index becf88096c..b0310c51e2 100644
--- a/default-configs/sparc-softmmu.mak
+++ b/default-configs/sparc-softmmu.mak
@@ -6,5 +6,5 @@ CONFIG_ESCC=y
 CONFIG_M48T59=y
 CONFIG_PTIMER=y
 CONFIG_FDC=y
-CONFIG_VIRTIO_PCI=y
 CONFIG_EMPTY_SLOT=y
+CONFIG_PCNET_COMMON=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index 1cc3f13079..ecc31228ba 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -1,5 +1,6 @@
 # Default configuration for sparc64-softmmu
 
+include pci.mak
 CONFIG_ISA_MMIO=y
 CONFIG_M48T59=y
 CONFIG_PTIMER=y
@@ -13,4 +14,3 @@ CONFIG_IDE_QDEV=y
 CONFIG_IDE_PCI=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_CMD646=y
-CONFIG_VIRTIO_PCI=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 518320377f..7f22599fc8 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -1,6 +1,6 @@
 # Default configuration for x86_64-softmmu
 
-CONFIG_USB_OHCI=y
+include pci.mak
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VMWARE_VGA=y
@@ -9,7 +9,6 @@ CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCSPK=y
 CONFIG_PCKBD=y
-CONFIG_USB_UHCI=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
@@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
 CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
-CONFIG_VIRTIO_PCI=y
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
new file mode 100644
index 0000000000..3dfbe46472
--- /dev/null
+++ b/hw/pcnet-pci.c
@@ -0,0 +1,345 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) PCI emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+#include "pci.h"
+#include "net.h"
+#include "loader.h"
+#include "qemu-timer.h"
+
+#include "pcnet.h"
+
+//#define PCNET_DEBUG
+//#define PCNET_DEBUG_IO
+//#define PCNET_DEBUG_BCR
+//#define PCNET_DEBUG_CSR
+//#define PCNET_DEBUG_RMD
+//#define PCNET_DEBUG_TMD
+//#define PCNET_DEBUG_MATCH
+
+
+typedef struct {
+    PCIDevice pci_dev;
+    PCNetState state;
+} PCIPCNetState;
+
+static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCNetState *s = opaque;
+#ifdef PCNET_DEBUG
+    printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+    /* Check APROMWE bit to enable write access */
+    if (pcnet_bcr_readw(s,2) & 0x100)
+        s->prom[addr & 15] = val;
+}
+
+static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
+{
+    PCNetState *s = opaque;
+    uint32_t val = s->prom[addr & 15];
+#ifdef PCNET_DEBUG
+    printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
+                             pcibus_t addr, pcibus_t size, int type)
+{
+    PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
+
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
+           addr, size);
+#endif
+
+    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
+    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
+
+    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
+    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
+    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
+    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
+}
+
+static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
+           val);
+#endif
+    if (!(addr & 0x10))
+        pcnet_aprom_writeb(d, addr & 0x0f, val);
+}
+
+static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val = -1;
+    if (!(addr & 0x10))
+        val = pcnet_aprom_readb(d, addr & 0x0f);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
+           val & 0xff);
+#endif
+    return val;
+}
+
+static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
+           val);
+#endif
+    if (addr & 0x10)
+        pcnet_ioport_writew(d, addr & 0x0f, val);
+    else {
+        addr &= 0x0f;
+        pcnet_aprom_writeb(d, addr, val & 0xff);
+        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+    }
+}
+
+static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val = -1;
+    if (addr & 0x10)
+        val = pcnet_ioport_readw(d, addr & 0x0f);
+    else {
+        addr &= 0x0f;
+        val = pcnet_aprom_readb(d, addr+1);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr);
+    }
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
+           val & 0xffff);
+#endif
+    return val;
+}
+
+static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
+           val);
+#endif
+    if (addr & 0x10)
+        pcnet_ioport_writel(d, addr & 0x0f, val);
+    else {
+        addr &= 0x0f;
+        pcnet_aprom_writeb(d, addr, val & 0xff);
+        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+        pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
+        pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
+    }
+}
+
+static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val;
+    if (addr & 0x10)
+        val = pcnet_ioport_readl(d, addr & 0x0f);
+    else {
+        addr &= 0x0f;
+        val = pcnet_aprom_readb(d, addr+3);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr+2);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr+1);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr);
+    }
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
+           val);
+#endif
+    return val;
+}
+
+static const VMStateDescription vmstate_pci_pcnet = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
+        VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* PCI interface */
+
+static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
+    &pcnet_mmio_writeb,
+    &pcnet_mmio_writew,
+    &pcnet_mmio_writel
+};
+
+static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
+    &pcnet_mmio_readb,
+    &pcnet_mmio_readw,
+    &pcnet_mmio_readl
+};
+
+static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
+                            pcibus_t addr, pcibus_t size, int type)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
+           addr, size);
+#endif
+
+    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
+}
+
+static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
+                                      uint8_t *buf, int len, int do_bswap)
+{
+    cpu_physical_memory_write(addr, buf, len);
+}
+
+static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
+                                     uint8_t *buf, int len, int do_bswap)
+{
+    cpu_physical_memory_read(addr, buf, len);
+}
+
+static void pci_pcnet_cleanup(VLANClientState *nc)
+{
+    PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    pcnet_common_cleanup(d);
+}
+
+static int pci_pcnet_uninit(PCIDevice *dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
+
+    cpu_unregister_io_memory(d->state.mmio_index);
+    qemu_del_timer(d->state.poll_timer);
+    qemu_free_timer(d->state.poll_timer);
+    qemu_del_vlan_client(&d->state.nic->nc);
+    return 0;
+}
+
+static NetClientInfo net_pci_pcnet_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = pcnet_can_receive,
+    .receive = pcnet_receive,
+    .cleanup = pci_pcnet_cleanup,
+};
+
+static int pci_pcnet_init(PCIDevice *pci_dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+    PCNetState *s = &d->state;
+    uint8_t *pci_conf;
+
+#if 0
+    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
+        sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
+#endif
+
+    pci_conf = pci_dev->config;
+
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
+    pci_set_word(pci_conf + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+    pci_conf[PCI_REVISION_ID] = 0x10;
+    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
+
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
+    pci_conf[PCI_MIN_GNT] = 0x06;
+    pci_conf[PCI_MAX_LAT] = 0xff;
+
+    /* Handler for memory-mapped I/O */
+    s->mmio_index =
+      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
+
+    pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
+
+    pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
+                           PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
+
+    s->irq = pci_dev->irq[0];
+    s->phys_mem_read = pci_physical_memory_read;
+    s->phys_mem_write = pci_physical_memory_write;
+
+    if (!pci_dev->qdev.hotplugged) {
+        static int loaded = 0;
+        if (!loaded) {
+            rom_add_option("pxe-pcnet.bin");
+            loaded = 1;
+        }
+    }
+
+    return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
+}
+
+static void pci_reset(DeviceState *dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
+
+    pcnet_h_reset(&d->state);
+}
+
+static PCIDeviceInfo pcnet_info = {
+    .qdev.name  = "pcnet",
+    .qdev.size  = sizeof(PCIPCNetState),
+    .qdev.reset = pci_reset,
+    .qdev.vmsd  = &vmstate_pci_pcnet,
+    .init       = pci_pcnet_init,
+    .exit       = pci_pcnet_uninit,
+    .qdev.props = (Property[]) {
+        DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void pci_pcnet_register_devices(void)
+{
+    pci_qdev_register(&pcnet_info);
+}
+
+device_init(pci_pcnet_register_devices)
diff --git a/hw/pcnet.c b/hw/pcnet.c
index f970bdaf3c..37010b8fcf 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -35,9 +35,8 @@
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
  */
 
-#include "pci.h"
+#include "qdev.h"
 #include "net.h"
-#include "loader.h"
 #include "qemu-timer.h"
 #include "qemu_socket.h"
 
@@ -52,11 +51,6 @@
 //#define PCNET_DEBUG_MATCH
 
 
-typedef struct {
-    PCIDevice pci_dev;
-    PCNetState state;
-} PCIPCNetState;
-
 struct qemu_ether_header {
     uint8_t ether_dhost[6];
     uint8_t ether_shost[6];
@@ -704,7 +698,6 @@ static void pcnet_poll_timer(void *opaque);
 static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
 static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
 static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
-static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
 
 static void pcnet_s_reset(PCNetState *s)
 {
@@ -1538,7 +1531,7 @@ static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
     }
 }
 
-static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
 {
     uint32_t val;
     rap &= 127;
@@ -1595,27 +1588,6 @@ void pcnet_h_reset(void *opaque)
     pcnet_poll_timer(s);
 }
 
-static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCNetState *s = opaque;
-#ifdef PCNET_DEBUG
-    printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
-    /* Check APROMWE bit to enable write access */
-    if (pcnet_bcr_readw(s,2) & 0x100)
-        s->prom[addr & 15] = val;
-}
-
-static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
-{
-    PCNetState *s = opaque;
-    uint32_t val = s->prom[addr & 15];
-#ifdef PCNET_DEBUG
-    printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
-    return val;
-}
-
 void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
 {
     PCNetState *s = opaque;
@@ -1668,7 +1640,7 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
     return val;
 }
 
-static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
 {
     PCNetState *s = opaque;
     pcnet_poll_timer(s);
@@ -1698,7 +1670,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
     pcnet_update_irq(s);
 }
 
-static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
 {
     PCNetState *s = opaque;
     uint32_t val = -1;
@@ -1727,125 +1699,6 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
     return val;
 }
 
-static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
-                             pcibus_t addr, pcibus_t size, int type)
-{
-    PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
-
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
-           addr, size);
-#endif
-
-    register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
-    register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
-
-    register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
-    register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
-    register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
-    register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
-}
-
-static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
-           val);
-#endif
-    if (!(addr & 0x10))
-        pcnet_aprom_writeb(d, addr & 0x0f, val);
-}
-
-static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val = -1;
-    if (!(addr & 0x10))
-        val = pcnet_aprom_readb(d, addr & 0x0f);
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
-           val & 0xff);
-#endif
-    return val;
-}
-
-static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
-           val);
-#endif
-    if (addr & 0x10)
-        pcnet_ioport_writew(d, addr & 0x0f, val);
-    else {
-        addr &= 0x0f;
-        pcnet_aprom_writeb(d, addr, val & 0xff);
-        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
-    }
-}
-
-static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val = -1;
-    if (addr & 0x10)
-        val = pcnet_ioport_readw(d, addr & 0x0f);
-    else {
-        addr &= 0x0f;
-        val = pcnet_aprom_readb(d, addr+1);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr);
-    }
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
-           val & 0xffff);
-#endif
-    return val;
-}
-
-static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
-           val);
-#endif
-    if (addr & 0x10)
-        pcnet_ioport_writel(d, addr & 0x0f, val);
-    else {
-        addr &= 0x0f;
-        pcnet_aprom_writeb(d, addr, val & 0xff);
-        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
-        pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
-        pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
-    }
-}
-
-static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val;
-    if (addr & 0x10)
-        val = pcnet_ioport_readl(d, addr & 0x0f);
-    else {
-        addr &= 0x0f;
-        val = pcnet_aprom_readb(d, addr+3);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr+2);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr+1);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr);
-    }
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
-           val);
-#endif
-    return val;
-}
-
 static bool is_version_2(void *opaque, int version_id)
 {
     return version_id == 2;
@@ -1875,18 +1728,6 @@ const VMStateDescription vmstate_pcnet = {
     }
 };
 
-static const VMStateDescription vmstate_pci_pcnet = {
-    .name = "pcnet",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
-        VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 void pcnet_common_cleanup(PCNetState *d)
 {
     d->nic = NULL;
@@ -1901,147 +1742,3 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
     return 0;
 }
-
-/* PCI interface */
-
-static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
-    &pcnet_mmio_writeb,
-    &pcnet_mmio_writew,
-    &pcnet_mmio_writel
-};
-
-static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
-    &pcnet_mmio_readb,
-    &pcnet_mmio_readw,
-    &pcnet_mmio_readl
-};
-
-static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
-                            pcibus_t addr, pcibus_t size, int type)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
-           addr, size);
-#endif
-
-    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
-}
-
-static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
-                                      uint8_t *buf, int len, int do_bswap)
-{
-    cpu_physical_memory_write(addr, buf, len);
-}
-
-static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
-                                     uint8_t *buf, int len, int do_bswap)
-{
-    cpu_physical_memory_read(addr, buf, len);
-}
-
-static void pci_pcnet_cleanup(VLANClientState *nc)
-{
-    PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
-
-    pcnet_common_cleanup(d);
-}
-
-static int pci_pcnet_uninit(PCIDevice *dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
-
-    cpu_unregister_io_memory(d->state.mmio_index);
-    qemu_del_timer(d->state.poll_timer);
-    qemu_free_timer(d->state.poll_timer);
-    qemu_del_vlan_client(&d->state.nic->nc);
-    return 0;
-}
-
-static NetClientInfo net_pci_pcnet_info = {
-    .type = NET_CLIENT_TYPE_NIC,
-    .size = sizeof(NICState),
-    .can_receive = pcnet_can_receive,
-    .receive = pcnet_receive,
-    .cleanup = pci_pcnet_cleanup,
-};
-
-static int pci_pcnet_init(PCIDevice *pci_dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-    PCNetState *s = &d->state;
-    uint8_t *pci_conf;
-
-#if 0
-    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
-        sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
-#endif
-
-    pci_conf = pci_dev->config;
-
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
-    pci_set_word(pci_conf + PCI_STATUS,
-                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_conf[PCI_REVISION_ID] = 0x10;
-    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
-
-    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
-    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
-
-    pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
-    pci_conf[PCI_MIN_GNT] = 0x06;
-    pci_conf[PCI_MAX_LAT] = 0xff;
-
-    /* Handler for memory-mapped I/O */
-    s->mmio_index =
-      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
-
-    pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
-
-    pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
-
-    s->irq = pci_dev->irq[0];
-    s->phys_mem_read = pci_physical_memory_read;
-    s->phys_mem_write = pci_physical_memory_write;
-
-    if (!pci_dev->qdev.hotplugged) {
-        static int loaded = 0;
-        if (!loaded) {
-            rom_add_option("pxe-pcnet.bin");
-            loaded = 1;
-        }
-    }
-
-    return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
-}
-
-static void pci_reset(DeviceState *dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
-
-    pcnet_h_reset(&d->state);
-}
-
-static PCIDeviceInfo pcnet_info = {
-    .qdev.name  = "pcnet",
-    .qdev.size  = sizeof(PCIPCNetState),
-    .qdev.reset = pci_reset,
-    .qdev.vmsd  = &vmstate_pci_pcnet,
-    .init       = pci_pcnet_init,
-    .exit       = pci_pcnet_uninit,
-    .qdev.props = (Property[]) {
-        DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
-        DEFINE_PROP_END_OF_LIST(),
-    }
-};
-
-static void pcnet_register_devices(void)
-{
-    pci_qdev_register(&pcnet_info);
-}
-
-device_init(pcnet_register_devices)
diff --git a/hw/pcnet.h b/hw/pcnet.h
index efacc9fa59..534bdf9c2b 100644
--- a/hw/pcnet.h
+++ b/hw/pcnet.h
@@ -32,6 +32,9 @@ struct PCNetState_st {
 void pcnet_h_reset(void *opaque);
 void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
 uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
 int pcnet_can_receive(VLANClientState *nc);
 ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_);
 void pcnet_common_cleanup(PCNetState *d);
diff --git a/make_device_config.sh b/make_device_config.sh
new file mode 100644
index 0000000000..8abadfef7c
--- /dev/null
+++ b/make_device_config.sh
@@ -0,0 +1,28 @@
+#! /bin/sh
+# Construct a target device config file from a default, pulling in any
+# files from include directives.
+
+dest=$1.tmp
+dep=$1.d
+src=$2
+src_dir=`dirname $src`
+all_includes=
+
+process_includes () {
+  cat $1 | grep '^include' | \
+  while read include file ; do
+    all_includes="$all_includes $src_dir/$file"
+    process_includes $src_dir/$file
+  done
+}
+
+f=$src
+while [ -n "$f" ] ; do
+  f=`awk '/^include / {ORS=" " ; print "'$src_dir'/" $2}' $f`
+  [ $? = 0 ] || exit 1
+  all_includes="$all_includes $f"
+done
+process_includes $src > $dest
+
+cat $src $all_includes | grep -v '^include' > $dest
+echo "$1: $all_includes" > $dep
diff --git a/monitor.c b/monitor.c
index 8cee35d77a..ec31eac8c1 100644
--- a/monitor.c
+++ b/monitor.c
@@ -491,6 +491,44 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params,
     return 0;
 }
 
+static int mon_set_cpu(int cpu_index);
+static void handle_user_command(Monitor *mon, const char *cmdline);
+
+static int do_hmp_passthrough(Monitor *mon, const QDict *params,
+                              QObject **ret_data)
+{
+    int ret = 0;
+    Monitor *old_mon, hmp;
+    CharDriverState mchar;
+
+    memset(&hmp, 0, sizeof(hmp));
+    qemu_chr_init_mem(&mchar);
+    hmp.chr = &mchar;
+
+    old_mon = cur_mon;
+    cur_mon = &hmp;
+
+    if (qdict_haskey(params, "cpu-index")) {
+        ret = mon_set_cpu(qdict_get_int(params, "cpu-index"));
+        if (ret < 0) {
+            cur_mon = old_mon;
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
+            goto out;
+        }
+    }
+
+    handle_user_command(&hmp, qdict_get_str(params, "command-line"));
+    cur_mon = old_mon;
+
+    if (qemu_chr_mem_osize(hmp.chr) > 0) {
+        *ret_data = QOBJECT(qemu_chr_mem_to_qs(hmp.chr));
+    }
+
+out:
+    qemu_chr_close_mem(hmp.chr);
+    return ret;
+}
+
 static int compare_cmd(const char *name, const char *list)
 {
     const char *p, *pstart;
diff --git a/qemu-char.c b/qemu-char.c
index 88997f9d5a..edc9ad6851 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2275,6 +2275,70 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     return NULL;
 }
 
+/***********************************************************/
+/* Memory chardev */
+typedef struct {
+    size_t outbuf_size;
+    size_t outbuf_capacity;
+    uint8_t *outbuf;
+} MemoryDriver;
+
+static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MemoryDriver *d = chr->opaque;
+
+    /* TODO: the QString implementation has the same code, we should
+     * introduce a generic way to do this in cutils.c */
+    if (d->outbuf_capacity < d->outbuf_size + len) {
+        /* grow outbuf */
+        d->outbuf_capacity += len;
+        d->outbuf_capacity *= 2;
+        d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity);
+    }
+
+    memcpy(d->outbuf + d->outbuf_size, buf, len);
+    d->outbuf_size += len;
+
+    return len;
+}
+
+void qemu_chr_init_mem(CharDriverState *chr)
+{
+    MemoryDriver *d;
+
+    d = qemu_malloc(sizeof(*d));
+    d->outbuf_size = 0;
+    d->outbuf_capacity = 4096;
+    d->outbuf = qemu_mallocz(d->outbuf_capacity);
+
+    memset(chr, 0, sizeof(*chr));
+    chr->opaque = d;
+    chr->chr_write = mem_chr_write;
+}
+
+QString *qemu_chr_mem_to_qs(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+    return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
+}
+
+/* NOTE: this driver can not be closed with qemu_chr_close()! */
+void qemu_chr_close_mem(CharDriverState *chr)
+{
+    MemoryDriver *d = chr->opaque;
+
+    qemu_free(d->outbuf);
+    qemu_free(chr->opaque);
+    chr->opaque = NULL;
+    chr->chr_write = NULL;
+}
+
+size_t qemu_chr_mem_osize(const CharDriverState *chr)
+{
+    const MemoryDriver *d = chr->opaque;
+    return d->outbuf_size;
+}
+
 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
 {
     char host[65], port[33], width[8], height[8];
diff --git a/qemu-char.h b/qemu-char.h
index 18ad12bb5d..e6ee6c4bc9 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -6,6 +6,7 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "qobject.h"
+#include "qstring.h"
 
 /* character device */
 
@@ -100,6 +101,12 @@ CharDriverState *qemu_chr_open_eventfd(int eventfd);
 
 extern int term_escape_char;
 
+/* memory chardev */
+void qemu_chr_init_mem(CharDriverState *chr);
+void qemu_chr_close_mem(CharDriverState *chr);
+QString *qemu_chr_mem_to_qs(CharDriverState *chr);
+size_t qemu_chr_mem_osize(const CharDriverState *chr);
+
 /* async I/O support */
 
 int qemu_set_fd_handler2(int fd,
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 793cf1c0f9..e5f157fe10 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -761,6 +761,51 @@ Example:
 
 Note: This command must be issued before issuing any other command.
 
+EQMP
+
+    {
+        .name       = "human-monitor-command",
+        .args_type  = "command-line:s,cpu-index:i?",
+        .params     = "",
+        .help       = "",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_hmp_passthrough,
+    },
+
+SQMP
+human-monitor-command
+---------------------
+
+Execute a Human Monitor command.
+
+Arguments: 
+
+- command-line: the command name and its arguments, just like the
+                Human Monitor's shell (json-string)
+- cpu-index: select the CPU number to be used by commands which access CPU
+             data, like 'info registers'. The Monitor selects CPU 0 if this
+             argument is not provided (json-int, optional)
+
+Example:
+
+-> { "execute": "human-monitor-command", "arguments": { "command-line": "info kvm" } }
+<- { "return": "kvm support: enabled\r\n" }
+
+Notes:
+
+(1) The Human Monitor is NOT an stable interface, this means that command
+    names, arguments and responses can change or be removed at ANY time.
+    Applications that rely on long term stability guarantees should NOT
+    use this command
+
+(2) Limitations:
+
+    o This command is stateless, this means that commands that depend
+      on state information (such as getfd) might not work
+
+    o Commands that prompt the user for data (eg. 'cont' when the block
+      device is encrypted) don't currently work
+
 3. Query Commands
 =================