diff options
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 ================= |