Merge remote branch 'origin/master' into pci

Conflicts:
	Makefile.objs
	hw/virtio.c
This commit is contained in:
Michael S. Tsirkin 2010-12-01 07:11:51 +02:00
commit c924f36a30
123 changed files with 2984 additions and 1199 deletions

2
.gitignore vendored
View file

@ -4,6 +4,8 @@ config-host.*
config-target.* config-target.*
trace.h trace.h
trace.c trace.c
trace-dtrace.h
trace-dtrace.dtrace
*-timestamp *-timestamp
*-softmmu *-softmmu
*-darwin-user *-darwin-user

View file

@ -1,88 +1,428 @@
QEMU Maintainers 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 In general, if you have a question about inclusion of a patch, you should
Paul Brook consult qemu-devel and not any specific individual privately.
CPU cores: Descriptions of section entries:
----------
x86 Fabrice Bellard M: Mail patches to: FullName <address@domain>
ARM Paul Brook L: Mailing list that is relevant to this area
SPARC Blue Swirl W: Web-page with status/info
MIPS ? Q: Patchwork web based patch tracking system site
PowerPC Alexander Graf T: SCM tree type and location. Type is one of: git, hg, quilt, stgit.
M68K Paul Brook S: Status, one of the following:
SH4 ? Supported: Someone is actually paid to look after this.
CRIS Edgar E. Iglesias Maintained: Someone actually looks after it.
Alpha ? Odd Fixes: It has a maintainer but they don't have time to do
MicroBlaze Edgar E. Iglesias much other than throw the odd patch in. See below..
S390 ? 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.
Machines (sorted by CPU):
-------------------------
x86 General Project Administration
pc.c Fabrice Bellard (new maintainer needed) ------------------------------
ARM M: Anthony Liguori <aliguori@us.ibm.com>
integratorcp.c Paul Brook M: Paul Brook <paul@codesourcery.com>
versatilepb.c Paul Brook
Real View Paul Brook Guest CPU cores (TCG):
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
MIPS
mips_r4k.c Aurelien Jarno
mips_malta.c Aurelien Jarno
mips_jazz.c Hervé Poussineau
mips_mipssim.c ?
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
SH4
shix.c ?
r2d.c Magnus Damm
CRIS
etraxfs.c Edgar E. Iglesias
axis_dev88.c Edgar E. Iglesias
Alpha Alpha
M: qemu-devel@nongnu.org
S: Orphan
F: target-alpha/
ARM
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 MicroBlaze
petalogix_s3adsp1800.c Edgar E. Iglesias M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: target-microblaze/
MIPS
M: qemu-devel@nongnu.org
S: Orphan
F: target-mips/
PowerPC
M: Alexander Graf <agraf@suse.de>
S: Maintained
F: target-ppc/
S390 S390
s390-*.c Alexander Graf M: Alexander Graf <agraf@suse.de>
S: Maintained
F: target-s390x/
Generic Subsystems: SH4
------------------- M: qemu-devel@nongnu.org
S: Orphan
F: target-sh4/
Dynamic translator Fabrice Bellard SPARC
Main loop Fabrice Bellard (new maintainer needed) M: Blue Swirl <blauwirbel@gmail.com>
TCG Fabrice Bellard S: Maintained
IDE device ? F: target-sparc/
SCSI device Paul Brook
PCI layer Michael S. Tsirkin X86
USB layer ? M: qemu-devel@nongnu.org
Block layer ? S: Odd Fixes
Graphic layer ? F: target-i386/
Audio device layer Vassili Karpov (malc)
Character device layer ? Guest CPU Cores (KVM):
Network device layer ? ----------------------
GDB stub ?
Linux user ? Overall
Darwin user ? M: Avi Kivity <avi@redhat.com>
SLIRP ? 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
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/

View file

@ -1,6 +1,9 @@
# Makefile for QEMU. # Makefile for QEMU.
GENERATED_HEADERS = config-host.h trace.h qemu-options.def GENERATED_HEADERS = config-host.h trace.h qemu-options.def
ifeq ($(TRACE_BACKEND),dtrace)
GENERATED_HEADERS += trace-dtrace.h
endif
ifneq ($(wildcard config-host.mak),) ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies. # Put the all: rule here so that config-host.mak can contain dependencies.
@ -36,18 +39,19 @@ endif
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS)) 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) config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@") $(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@")
-include $(SUBDIR_DEVICES_MAK_DEP)
%/config-devices.mak: default-configs/%.mak %/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 test -f $@; then \
if cmp -s $@.old $@; then \ if cmp -s $@.old $@; then \
if ! cmp -s $@ $@.tmp; then \ mv $@.tmp $@; \
mv $@.tmp $@; \ cp -p $@ $@.old; \
cp -p $@ $@.old; \
fi; \
else \ else \
if test -f $@.old; then \ if test -f $@.old; then \
echo "WARNING: $@ (user modified) out of date.";\ echo "WARNING: $@ (user modified) out of date.";\
@ -108,7 +112,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
ifeq ($(TRACE_BACKEND),dtrace)
trace.h: trace.h-timestamp trace-dtrace.h
else
trace.h: trace.h-timestamp trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") $(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h @cmp -s $@ trace.h || cp $@ trace.h
@ -120,6 +128,20 @@ trace.c-timestamp: $(SRC_PATH)/trace-events config-host.mak
trace.o: trace.c $(GENERATED_HEADERS) trace.o: trace.c $(GENERATED_HEADERS)
trace-dtrace.h: trace-dtrace.dtrace
$(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h")
# Normal practice is to name DTrace probe file with a '.d' extension
# but that gets picked up by QEMU's Makefile as an external dependancy
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
$(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
simpletrace.o: simpletrace.c $(GENERATED_HEADERS) simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
version.o: $(SRC_PATH)/version.rc config-host.mak version.o: $(SRC_PATH)/version.rc config-host.mak
@ -129,7 +151,7 @@ version-obj-$(CONFIG_WIN32) += version.o
###################################################################### ######################################################################
qemu-img.o: qemu-img-cmds.h 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 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
@ -142,12 +164,14 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS) check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
check-qint: check-qint.o qint.o qemu-malloc.o $(trace-obj-y) CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y)
check-qstring: check-qstring.o qstring.o qemu-malloc.o $(trace-obj-y)
check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o $(trace-obj-y) check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o $(trace-obj-y) check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o $(trace-obj-y) check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o $(trace-obj-y) check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
clean: clean:
# avoid old build problems by removing potentially incorrect old files # avoid old build problems by removing potentially incorrect old files
@ -157,6 +181,8 @@ clean:
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
rm -f qemu-img-cmds.h rm -f qemu-img-cmds.h
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
rm -f trace-dtrace.h trace-dtrace.h-timestamp
$(MAKE) -C tests clean $(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \ for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
@ -178,8 +204,9 @@ ar de en-us fi fr-be hr it lv nl pl ru th \
common de-ch es fo fr-ca hu ja mk nl-be pt sl tr common de-ch es fo fr-ca hu ja mk nl-be pt sl tr
ifdef INSTALL_BLOBS ifdef INSTALL_BLOBS
BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
openbios-sparc32 openbios-sparc64 openbios-ppc \ vgabios-stdvga.bin vgabios-vmware.bin \
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
gpxe-eepro100-80861209.rom \ gpxe-eepro100-80861209.rom \
pxe-e1000.bin \ pxe-e1000.bin \
pxe-ne2k_pci.bin pxe-pcnet.bin \ pxe-ne2k_pci.bin pxe-pcnet.bin \

View file

@ -42,6 +42,11 @@ net-nested-$(CONFIG_SLIRP) += slirp.o
net-nested-$(CONFIG_VDE) += vde.o net-nested-$(CONFIG_VDE) += vde.o
net-obj-y += $(addprefix net/, $(net-nested-y)) 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-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y)) fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
@ -102,6 +107,7 @@ common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o audio-obj-$(CONFIG_SDL) += sdlaudio.o
audio-obj-$(CONFIG_OSS) += ossaudio.o audio-obj-$(CONFIG_OSS) += ossaudio.o
audio-obj-$(CONFIG_SPICE) += spiceaudio.o
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
audio-obj-$(CONFIG_ALSA) += alsaaudio.o audio-obj-$(CONFIG_ALSA) += alsaaudio.o
audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
@ -158,9 +164,13 @@ user-obj-y += cutils.o cache-utils.o
hw-obj-y = hw-obj-y =
hw-obj-y += vl.o loader.o hw-obj-y += vl.o loader.o
hw-obj-y += virtio.o virtio-console.o hw-obj-$(CONFIG_VIRTIO) += 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 += fw_cfg.o
hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.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-y += watchdog.o
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
hw-obj-$(CONFIG_ECC) += ecc.o hw-obj-$(CONFIG_ECC) += ecc.o
@ -205,15 +215,16 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
hw-obj-$(CONFIG_PIIX4) += piix4.o hw-obj-$(CONFIG_PIIX4) += piix4.o
# PCI watchdog devices # PCI watchdog devices
hw-obj-y += wdt_i6300esb.o hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
hw-obj-y += pcie.o pcie_aer.o pcie_port.o hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
hw-obj-y += msix.o msi.o hw-obj-$(CONFIG_PCI) += msix.o msi.o
# PCI network cards # PCI network cards
hw-obj-y += ne2000.o hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
hw-obj-y += eepro100.o hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
hw-obj-y += pcnet.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_SMC91C111) += smc91c111.o
hw-obj-$(CONFIG_LAN9118) += lan9118.o hw-obj-$(CONFIG_LAN9118) += lan9118.o
@ -230,7 +241,7 @@ hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
hw-obj-$(CONFIG_IDE_VIA) += ide/via.o hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
# SCSI layer # SCSI layer
hw-obj-y += lsi53c895a.o hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
hw-obj-$(CONFIG_ESP) += esp.o hw-obj-$(CONFIG_ESP) += esp.o
hw-obj-y += dma-helpers.o sysbus.o isa-bus.o hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
@ -260,7 +271,8 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) 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 hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
###################################################################### ######################################################################
@ -285,11 +297,15 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
###################################################################### ######################################################################
# trace # trace
ifeq ($(TRACE_BACKEND),dtrace)
trace-obj-y = trace-dtrace.o
else
trace-obj-y = trace.o trace-obj-y = trace.o
ifeq ($(TRACE_BACKEND),simple) ifeq ($(TRACE_BACKEND),simple)
trace-obj-y += simpletrace.o trace-obj-y += simpletrace.o
user-obj-y += qemu-timer-common.o user-obj-y += qemu-timer-common.o
endif endif
endif
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)

View file

@ -30,6 +30,7 @@ endif
endif endif
PROGS=$(QEMU_PROG) PROGS=$(QEMU_PROG)
STPFILES=
ifndef CONFIG_HAIKU ifndef CONFIG_HAIKU
LIBS+=-lm LIBS+=-lm
@ -40,7 +41,27 @@ kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
config-target.h: config-target.h-timestamp config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak config-target.h-timestamp: config-target.mak
all: $(PROGS) ifdef CONFIG_SYSTEMTAP_TRACE
stap: $(QEMU_PROG).stp
ifdef CONFIG_USER_ONLY
TARGET_TYPE=user
else
TARGET_TYPE=system
endif
$(QEMU_PROG).stp:
$(call quiet-command,sh $(SRC_PATH)/tracetool \
--$(TRACE_BACKEND) \
--binary $(bindir)/$(QEMU_PROG) \
--target-arch $(TARGET_ARCH) \
--target-type $(TARGET_TYPE) \
--stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
else
stap:
endif
all: $(PROGS) stap
# Dummy command so that make thinks it has done something # Dummy command so that make thinks it has done something
@true @true
@ -167,11 +188,11 @@ ifdef CONFIG_SOFTMMU
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o 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. # virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly # 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-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
obj-y += vhost_net.o obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.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-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-$(CONFIG_NO_KVM) += kvm-stub.o
@ -189,8 +210,8 @@ obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
obj-$(CONFIG_USB_OHCI) += usb-ohci.o obj-$(CONFIG_USB_OHCI) += usb-ohci.o
# PCI network cards # PCI network cards
obj-y += rtl8139.o obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
obj-y += e1000.o obj-$(CONFIG_E1000_PCI) += e1000.o
# Inter-VM PCI shared memory # Inter-VM PCI shared memory
obj-$(CONFIG_KVM) += ivshmem.o obj-$(CONFIG_KVM) += ivshmem.o
@ -340,6 +361,9 @@ clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
rm -f *.d */*.d tcg/*.o ide/*.o rm -f *.d */*.d tcg/*.o ide/*.o
rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
ifdef CONFIG_SYSTEMTAP_TRACE
rm -f *.stp
endif
install: all install: all
ifneq ($(PROGS),) ifneq ($(PROGS),)
@ -348,6 +372,10 @@ ifneq ($(STRIP),)
$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS)) $(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
endif endif
endif endif
ifdef CONFIG_SYSTEMTAP_TRACE
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
$(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
endif
# Include automatically generated dependency files # Include automatically generated dependency files
-include $(wildcard *.d */*.d) -include $(wildcard *.d */*.d)

View file

@ -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-commands.txt QMP supported commands (auto-generated at build-time)
o qmp-events.txt List of available asynchronous events o qmp-events.txt List of available asynchronous events
There are also two simple Python scripts available: There is also a simple Python script called 'qmp-shell' available.
o qmp-shell A shell
o vm-info Show some information about the Virtual Machine
IMPORTANT: It's strongly recommended to read the 'Stability Considerations' IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
section in the qmp-commands.txt file before making any serious use of QMP. section in the qmp-commands.txt file before making any serious use of QMP.

View file

@ -1,8 +1,8 @@
#!/usr/bin/python #!/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: # Authors:
# Luiz Capitulino <lcapitulino@redhat.com> # Luiz Capitulino <lcapitulino@redhat.com>
@ -14,60 +14,246 @@
# #
# Start QEMU with: # Start QEMU with:
# #
# $ qemu [...] -monitor control,unix:./qmp,server # # qemu [...] -qmp unix:./qmp-sock,server
# #
# Run the shell: # Run the shell:
# #
# $ qmp-shell ./qmp # $ qmp-shell ./qmp-sock
# #
# Commands have the following format: # Commands have the following format:
# #
# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ] # < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
# #
# For example: # For example:
# #
# (QEMU) info item=network # (QEMU) device_add driver=e1000 id=net1
# {u'return': {}}
# (QEMU)
import qmp import qmp
import readline import readline
from sys import argv,exit import sys
def shell_help(): class QMPCompleter(list):
print 'bye exit from the shell' def complete(self, text, state):
for cmd in self:
if cmd.startswith(text):
if not state:
return cmd
else:
state -= 1
def main(): class QMPShellError(Exception):
if len(argv) != 2: pass
print 'qemu-shell <unix-socket>'
exit(1)
qemu = qmp.QEMUMonitorProtocol(argv[1]) class QMPShellBadPort(QMPShellError):
qemu.connect() pass
qemu.send("qmp_capabilities")
print 'Connected!' # 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
while True: 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('')
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: try:
cmd = raw_input('(QEMU) ') 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()
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'])
def read_exec_command(self, prompt):
"""
Read and execute a command.
@return True if execution was ok, return False if disconnected.
"""
try:
cmdline = raw_input(prompt)
except EOFError: except EOFError:
print print
break return False
if cmd == '': if cmdline == '':
continue for ev in self.get_events():
elif cmd == 'bye': print ev
break self.clear_events()
elif cmd == 'help': return True
shell_help()
else: 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: try:
resp = qemu.send(cmd) idx = int(cmdline.split()[1])
if resp == None: if not 'return' in self.__cmd_passthrough('info version', idx):
print 'Disconnected' print 'bad CPU index'
break return True
print resp self.__cpu_index = idx
except IndexError: except ValueError:
print '-> command format: <command-name> ', print 'cpu command takes an integer argument'
print '[arg-name1=arg1] ... [arg-nameN=argN]' 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__': if __name__ == '__main__':
main() main()

View file

@ -1,6 +1,6 @@
# QEMU Monitor Protocol Python class # QEMU Monitor Protocol Python class
# #
# Copyright (C) 2009 Red Hat Inc. # Copyright (C) 2009, 2010 Red Hat Inc.
# #
# Authors: # Authors:
# Luiz Capitulino <lcapitulino@redhat.com> # Luiz Capitulino <lcapitulino@redhat.com>
@ -8,7 +8,9 @@
# This work is licensed under the terms of the GNU GPL, version 2. See # This work is licensed under the terms of the GNU GPL, version 2. See
# the COPYING file in the top-level directory. # the COPYING file in the top-level directory.
import socket, json import json
import errno
import socket
class QMPError(Exception): class QMPError(Exception):
pass pass
@ -16,61 +18,114 @@ class QMPError(Exception):
class QMPConnectError(QMPError): class QMPConnectError(QMPError):
pass pass
class QMPCapabilitiesError(QMPError):
pass
class QEMUMonitorProtocol: class QEMUMonitorProtocol:
def connect(self): def __init__(self, address):
self.sock.connect(self.filename) """
data = self.__json_read() Create a QEMUMonitorProtocol class.
if data == None:
raise QMPConnectError
if not data.has_key('QMP'):
raise QMPConnectError
return data['QMP']['capabilities']
def close(self): @param address: QEMU address, can be either a unix socket path (string)
self.sock.close() 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 send_raw(self, line): def __get_sock(self):
self.sock.send(str(line)) if isinstance(self.__address, tuple):
return self.__json_read() family = socket.AF_INET
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: else:
return resp['return'] family = socket.AF_UNIX
return socket.socket(family, socket.SOCK_STREAM)
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 __json_read(self): def __json_read(self):
try: while True:
while True: data = self.__sockfile.readline()
line = json.loads(self.sockfile.readline()) if not data:
if not 'event' in line: return
return line resp = json.loads(data)
except ValueError: if 'event' in resp:
return self.__events.append(resp)
continue
return resp
def __init__(self, filename): error = socket.error
self.filename = filename
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) def connect(self):
self.sockfile = self.sock.makefile() """
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
# Greeting seems ok, negotiate capabilities
resp = self.cmd('qmp_capabilities')
if "return" in resp:
return greeting
raise QMPCapabilitiesError
def cmd_obj(self, qmp_cmd):
"""
Send a QMP command to the QMP Monitor.
@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 cmd(self, name, args=None, id=None):
"""
Build a QMP command and send it to the QMP Monitor.
@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:
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()

View file

@ -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()

View file

@ -44,6 +44,9 @@
that we generate the list. that we generate the list.
*/ */
static struct audio_driver *drvtab[] = { static struct audio_driver *drvtab[] = {
#ifdef CONFIG_SPICE
&spice_audio_driver,
#endif
CONFIG_AUDIO_DRIVERS CONFIG_AUDIO_DRIVERS
&no_audio_driver, &no_audio_driver,
&wav_audio_driver &wav_audio_driver
@ -1093,15 +1096,6 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
/* /*
* Timer * Timer
*/ */
static void audio_timer (void *opaque)
{
AudioState *s = opaque;
audio_run ("timer");
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
}
static int audio_is_timer_needed (void) static int audio_is_timer_needed (void)
{ {
HWVoiceIn *hwi = NULL; HWVoiceIn *hwi = NULL;
@ -1116,10 +1110,8 @@ static int audio_is_timer_needed (void)
return 0; return 0;
} }
static void audio_reset_timer (void) static void audio_reset_timer (AudioState *s)
{ {
AudioState *s = &glob_audio_state;
if (audio_is_timer_needed ()) { if (audio_is_timer_needed ()) {
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
} }
@ -1128,6 +1120,12 @@ static void audio_reset_timer (void)
} }
} }
static void audio_timer (void *opaque)
{
audio_run ("timer");
audio_reset_timer (opaque);
}
/* /*
* Public API * Public API
*/ */
@ -1192,7 +1190,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
hw->enabled = 1; hw->enabled = 1;
if (s->vm_running) { if (s->vm_running) {
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out); hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
audio_reset_timer (); audio_reset_timer (s);
} }
} }
} }
@ -1237,6 +1235,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
hw->enabled = 1; hw->enabled = 1;
if (s->vm_running) { if (s->vm_running) {
hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in); hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
audio_reset_timer (s);
} }
} }
sw->total_hw_samples_acquired = hw->total_samples_captured; sw->total_hw_samples_acquired = hw->total_samples_captured;
@ -1758,7 +1757,7 @@ static void audio_vm_change_state_handler (void *opaque, int running,
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) { while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in); hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
} }
audio_reset_timer (); audio_reset_timer (s);
} }
static void audio_atexit (void) static void audio_atexit (void)

View file

@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver; extern struct audio_driver dsound_audio_driver;
extern struct audio_driver esd_audio_driver; extern struct audio_driver esd_audio_driver;
extern struct audio_driver pa_audio_driver; extern struct audio_driver pa_audio_driver;
extern struct audio_driver spice_audio_driver;
extern struct audio_driver winwave_audio_driver; extern struct audio_driver winwave_audio_driver;
extern struct mixeng_volume nominal_volume; extern struct mixeng_volume nominal_volume;

346
audio/spiceaudio.c Normal file
View file

@ -0,0 +1,346 @@
/*
* Copyright (C) 2010 Red Hat, Inc.
*
* maintained by Gerd Hoffmann <kraxel@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/hw.h"
#include "qemu-timer.h"
#include "ui/qemu-spice.h"
#define AUDIO_CAP "spice"
#include "audio.h"
#include "audio_int.h"
#define LINE_IN_SAMPLES 1024
#define LINE_OUT_SAMPLES 1024
typedef struct SpiceRateCtl {
int64_t start_ticks;
int64_t bytes_sent;
} SpiceRateCtl;
typedef struct SpiceVoiceOut {
HWVoiceOut hw;
SpicePlaybackInstance sin;
SpiceRateCtl rate;
int active;
uint32_t *frame;
uint32_t *fpos;
uint32_t fsize;
} SpiceVoiceOut;
typedef struct SpiceVoiceIn {
HWVoiceIn hw;
SpiceRecordInstance sin;
SpiceRateCtl rate;
int active;
uint32_t samples[LINE_IN_SAMPLES];
} SpiceVoiceIn;
static const SpicePlaybackInterface playback_sif = {
.base.type = SPICE_INTERFACE_PLAYBACK,
.base.description = "playback",
.base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
.base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
};
static const SpiceRecordInterface record_sif = {
.base.type = SPICE_INTERFACE_RECORD,
.base.description = "record",
.base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
.base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
};
static void *spice_audio_init (void)
{
if (!using_spice) {
return NULL;
}
return &spice_audio_init;
}
static void spice_audio_fini (void *opaque)
{
/* nothing */
}
static void rate_start (SpiceRateCtl *rate)
{
memset (rate, 0, sizeof (*rate));
rate->start_ticks = qemu_get_clock (vm_clock);
}
static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
{
int64_t now;
int64_t ticks;
int64_t bytes;
int64_t samples;
now = qemu_get_clock (vm_clock);
ticks = now - rate->start_ticks;
bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
samples = (bytes - rate->bytes_sent) >> info->shift;
if (samples < 0 || samples > 65536) {
fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples);
rate_start (rate);
samples = 0;
}
rate->bytes_sent += samples << info->shift;
return samples;
}
/* playback */
static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
{
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
struct audsettings settings;
settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ;
settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN;
settings.fmt = AUD_FMT_S16;
settings.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &settings);
hw->samples = LINE_OUT_SAMPLES;
out->active = 0;
out->sin.base.sif = &playback_sif.base;
qemu_spice_add_interface (&out->sin.base);
return 0;
}
static void line_out_fini (HWVoiceOut *hw)
{
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
spice_server_remove_interface (&out->sin.base);
}
static int line_out_run (HWVoiceOut *hw, int live)
{
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
int rpos, decr;
int samples;
if (!live) {
return 0;
}
decr = rate_get_samples (&hw->info, &out->rate);
decr = audio_MIN (live, decr);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int len = audio_MIN (samples, left_till_end_samples);
if (!out->frame) {
spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
out->fpos = out->frame;
}
if (out->frame) {
len = audio_MIN (len, out->fsize);
hw->clip (out->fpos, hw->mix_buf + rpos, len);
out->fsize -= len;
out->fpos += len;
if (out->fsize == 0) {
spice_server_playback_put_samples (&out->sin, out->frame);
out->frame = out->fpos = NULL;
}
}
rpos = (rpos + len) % hw->samples;
samples -= len;
}
hw->rpos = rpos;
return decr;
}
static int line_out_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
{
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
switch (cmd) {
case VOICE_ENABLE:
if (out->active) {
break;
}
out->active = 1;
rate_start (&out->rate);
spice_server_playback_start (&out->sin);
break;
case VOICE_DISABLE:
if (!out->active) {
break;
}
out->active = 0;
if (out->frame) {
memset (out->fpos, 0, out->fsize << 2);
spice_server_playback_put_samples (&out->sin, out->frame);
out->frame = out->fpos = NULL;
}
spice_server_playback_stop (&out->sin);
break;
}
return 0;
}
/* record */
static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
struct audsettings settings;
settings.freq = SPICE_INTERFACE_RECORD_FREQ;
settings.nchannels = SPICE_INTERFACE_RECORD_CHAN;
settings.fmt = AUD_FMT_S16;
settings.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &settings);
hw->samples = LINE_IN_SAMPLES;
in->active = 0;
in->sin.base.sif = &record_sif.base;
qemu_spice_add_interface (&in->sin.base);
return 0;
}
static void line_in_fini (HWVoiceIn *hw)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
spice_server_remove_interface (&in->sin.base);
}
static int line_in_run (HWVoiceIn *hw)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
int num_samples;
int ready;
int len[2];
uint64_t delta_samp;
const uint32_t *samples;
if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
return 0;
}
delta_samp = rate_get_samples (&hw->info, &in->rate);
num_samples = audio_MIN (num_samples, delta_samp);
ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
samples = in->samples;
if (ready == 0) {
static const uint32_t silence[LINE_IN_SAMPLES];
samples = silence;
ready = LINE_IN_SAMPLES;
}
num_samples = audio_MIN (ready, num_samples);
if (hw->wpos + num_samples > hw->samples) {
len[0] = hw->samples - hw->wpos;
len[1] = num_samples - len[0];
} else {
len[0] = num_samples;
len[1] = 0;
}
hw->conv (hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume);
if (len[1]) {
hw->conv (hw->conv_buf, samples + len[0], len[1],
&nominal_volume);
}
hw->wpos = (hw->wpos + num_samples) % hw->samples;
return num_samples;
}
static int line_in_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
switch (cmd) {
case VOICE_ENABLE:
if (in->active) {
break;
}
in->active = 1;
rate_start (&in->rate);
spice_server_record_start (&in->sin);
break;
case VOICE_DISABLE:
if (!in->active) {
break;
}
in->active = 0;
spice_server_record_stop (&in->sin);
break;
}
return 0;
}
static struct audio_option audio_options[] = {
{ /* end of list */ },
};
static struct audio_pcm_ops audio_callbacks = {
.init_out = line_out_init,
.fini_out = line_out_fini,
.run_out = line_out_run,
.write = line_out_write,
.ctl_out = line_out_ctl,
.init_in = line_in_init,
.fini_in = line_in_fini,
.run_in = line_in_run,
.read = line_in_read,
.ctl_in = line_in_ctl,
};
struct audio_driver spice_audio_driver = {
.name = "spice",
.descr = "spice audio driver",
.options = audio_options,
.init = spice_audio_init,
.fini = spice_audio_fini,
.pcm_ops = &audio_callbacks,
.max_voices_out = 1,
.max_voices_in = 1,
.voice_size_out = sizeof (SpiceVoiceOut),
.voice_size_in = sizeof (SpiceVoiceIn),
};
void qemu_spice_audio_init (void)
{
spice_audio_driver.can_be_default = 1;
}

View file

@ -49,12 +49,14 @@ typedef struct BlkMigDevState {
int64_t total_sectors; int64_t total_sectors;
int64_t dirty; int64_t dirty;
QSIMPLEQ_ENTRY(BlkMigDevState) entry; QSIMPLEQ_ENTRY(BlkMigDevState) entry;
unsigned long *aio_bitmap;
} BlkMigDevState; } BlkMigDevState;
typedef struct BlkMigBlock { typedef struct BlkMigBlock {
uint8_t *buf; uint8_t *buf;
BlkMigDevState *bmds; BlkMigDevState *bmds;
int64_t sector; int64_t sector;
int nr_sectors;
struct iovec iov; struct iovec iov;
QEMUIOVector qiov; QEMUIOVector qiov;
BlockDriverAIOCB *aiocb; BlockDriverAIOCB *aiocb;
@ -140,6 +142,52 @@ static inline long double compute_read_bwidth(void)
return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time; return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time;
} }
static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
{
int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
if ((sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) {
return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] &
(1UL << (chunk % (sizeof(unsigned long) * 8))));
} else {
return 0;
}
}
static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
int nb_sectors, int set)
{
int64_t start, end;
unsigned long val, idx, bit;
start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
for (; start <= end; start++) {
idx = start / (sizeof(unsigned long) * 8);
bit = start % (sizeof(unsigned long) * 8);
val = bmds->aio_bitmap[idx];
if (set) {
val |= 1UL << bit;
} else {
val &= ~(1UL << bit);
}
bmds->aio_bitmap[idx] = val;
}
}
static void alloc_aio_bitmap(BlkMigDevState *bmds)
{
BlockDriverState *bs = bmds->bs;
int64_t bitmap_size;
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
bmds->aio_bitmap = qemu_mallocz(bitmap_size);
}
static void blk_mig_read_cb(void *opaque, int ret) static void blk_mig_read_cb(void *opaque, int ret)
{ {
BlkMigBlock *blk = opaque; BlkMigBlock *blk = opaque;
@ -151,6 +199,7 @@ static void blk_mig_read_cb(void *opaque, int ret)
add_avg_read_time(blk->time); add_avg_read_time(blk->time);
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
block_mig_state.submitted--; block_mig_state.submitted--;
block_mig_state.read_done++; block_mig_state.read_done++;
@ -194,6 +243,7 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
blk->buf = qemu_malloc(BLOCK_SIZE); blk->buf = qemu_malloc(BLOCK_SIZE);
blk->bmds = bmds; blk->bmds = bmds;
blk->sector = cur_sector; blk->sector = cur_sector;
blk->nr_sectors = nr_sectors;
blk->iov.iov_base = blk->buf; blk->iov.iov_base = blk->buf;
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
@ -248,6 +298,7 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
bmds->total_sectors = sectors; bmds->total_sectors = sectors;
bmds->completed_sectors = 0; bmds->completed_sectors = 0;
bmds->shared_base = block_mig_state.shared_base; bmds->shared_base = block_mig_state.shared_base;
alloc_aio_bitmap(bmds);
block_mig_state.total_sector_sum += sectors; block_mig_state.total_sector_sum += sectors;
@ -329,6 +380,9 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
int nr_sectors; int nr_sectors;
for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) { for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
if (bmds_aio_inflight(bmds, sector)) {
qemu_aio_flush();
}
if (bdrv_get_dirty(bmds->bs, sector)) { if (bdrv_get_dirty(bmds->bs, sector)) {
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) { if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
@ -340,6 +394,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
blk->buf = qemu_malloc(BLOCK_SIZE); blk->buf = qemu_malloc(BLOCK_SIZE);
blk->bmds = bmds; blk->bmds = bmds;
blk->sector = sector; blk->sector = sector;
blk->nr_sectors = nr_sectors;
if (is_async) { if (is_async) {
blk->iov.iov_base = blk->buf; blk->iov.iov_base = blk->buf;
@ -354,6 +409,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
goto error; goto error;
} }
block_mig_state.submitted++; block_mig_state.submitted++;
bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
} else { } else {
if (bdrv_read(bmds->bs, sector, blk->buf, if (bdrv_read(bmds->bs, sector, blk->buf,
nr_sectors) < 0) { nr_sectors) < 0) {
@ -474,6 +530,7 @@ static void blk_mig_cleanup(Monitor *mon)
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry); QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
qemu_free(bmds->aio_bitmap);
qemu_free(bmds); qemu_free(bmds);
} }

75
block.c
View file

@ -930,14 +930,14 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
bit = start % (sizeof(unsigned long) * 8); bit = start % (sizeof(unsigned long) * 8);
val = bs->dirty_bitmap[idx]; val = bs->dirty_bitmap[idx];
if (dirty) { if (dirty) {
if (!(val & (1 << bit))) { if (!(val & (1UL << bit))) {
bs->dirty_count++; bs->dirty_count++;
val |= 1 << bit; val |= 1UL << bit;
} }
} else { } else {
if (val & (1 << bit)) { if (val & (1UL << bit)) {
bs->dirty_count--; bs->dirty_count--;
val &= ~(1 << bit); val &= ~(1UL << bit);
} }
} }
bs->dirty_bitmap[idx] = val; bs->dirty_bitmap[idx] = val;
@ -1453,14 +1453,27 @@ const char *bdrv_get_device_name(BlockDriverState *bs)
return bs->device_name; return bs->device_name;
} }
void bdrv_flush(BlockDriverState *bs) int bdrv_flush(BlockDriverState *bs)
{ {
if (bs->open_flags & BDRV_O_NO_FLUSH) { if (bs->open_flags & BDRV_O_NO_FLUSH) {
return; return 0;
} }
if (bs->drv && bs->drv->bdrv_flush) if (bs->drv && bs->drv->bdrv_flush) {
bs->drv->bdrv_flush(bs); return bs->drv->bdrv_flush(bs);
}
/*
* Some block drivers always operate in either writethrough or unsafe mode
* and don't support bdrv_flush therefore. Usually qemu doesn't know how
* the server works (because the behaviour is hardcoded or depends on
* server-side configuration), so we can't ensure that everything is safe
* on disk. Returning an error doesn't work because that would break guests
* even if the server operates in writethrough mode.
*
* Let's hope the user knows what he's doing.
*/
return 0;
} }
void bdrv_flush_all(void) void bdrv_flush_all(void)
@ -2018,12 +2031,49 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
return ret; return ret;
} }
typedef struct BlockCompleteData {
BlockDriverCompletionFunc *cb;
void *opaque;
BlockDriverState *bs;
int64_t sector_num;
int nb_sectors;
} BlockCompleteData;
static void block_complete_cb(void *opaque, int ret)
{
BlockCompleteData *b = opaque;
if (b->bs->dirty_bitmap) {
set_dirty_bitmap(b->bs, b->sector_num, b->nb_sectors, 1);
}
b->cb(b->opaque, ret);
qemu_free(b);
}
static BlockCompleteData *blk_dirty_cb_alloc(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
BlockCompleteData *blkdata = qemu_mallocz(sizeof(BlockCompleteData));
blkdata->bs = bs;
blkdata->cb = cb;
blkdata->opaque = opaque;
blkdata->sector_num = sector_num;
blkdata->nb_sectors = nb_sectors;
return blkdata;
}
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque) BlockDriverCompletionFunc *cb, void *opaque)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BlockDriverAIOCB *ret; BlockDriverAIOCB *ret;
BlockCompleteData *blk_cb_data;
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque); trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
@ -2035,7 +2085,10 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
return NULL; return NULL;
if (bs->dirty_bitmap) { if (bs->dirty_bitmap) {
set_dirty_bitmap(bs, sector_num, nb_sectors, 1); blk_cb_data = blk_dirty_cb_alloc(bs, sector_num, nb_sectors, cb,
opaque);
cb = &block_complete_cb;
opaque = blk_cb_data;
} }
ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors, ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
@ -2672,8 +2725,8 @@ int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
if (bs->dirty_bitmap && if (bs->dirty_bitmap &&
(sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) { (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] & return !!(bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
(1 << (chunk % (sizeof(unsigned long) * 8))); (1UL << (chunk % (sizeof(unsigned long) * 8))));
} else { } else {
return 0; return 0;
} }

View file

@ -142,7 +142,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque); BlockDriverCompletionFunc *cb, void *opaque);
/* Ensure contents are flushed to disk. */ /* Ensure contents are flushed to disk. */
void bdrv_flush(BlockDriverState *bs); int bdrv_flush(BlockDriverState *bs);
void bdrv_flush_all(void); void bdrv_flush_all(void);
void bdrv_close_all(void); void bdrv_close_all(void);

View file

@ -397,9 +397,9 @@ static void blkdebug_close(BlockDriverState *bs)
} }
} }
static void blkdebug_flush(BlockDriverState *bs) static int blkdebug_flush(BlockDriverState *bs)
{ {
bdrv_flush(bs->file); return bdrv_flush(bs->file);
} }
static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs, static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,

View file

@ -116,12 +116,12 @@ static void blkverify_close(BlockDriverState *bs)
s->test_file = NULL; s->test_file = NULL;
} }
static void blkverify_flush(BlockDriverState *bs) static int blkverify_flush(BlockDriverState *bs)
{ {
BDRVBlkverifyState *s = bs->opaque; BDRVBlkverifyState *s = bs->opaque;
/* Only flush test file, the raw file is not important */ /* Only flush test file, the raw file is not important */
bdrv_flush(s->test_file); return bdrv_flush(s->test_file);
} }
static int64_t blkverify_getlength(BlockDriverState *bs) static int64_t blkverify_getlength(BlockDriverState *bs)
@ -300,8 +300,8 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb)
{ {
ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov); ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
if (offset != -1) { if (offset != -1) {
blkverify_err(acb, "contents mismatch in sector %lld", blkverify_err(acb, "contents mismatch in sector %" PRId64,
acb->sector_num + (offset / BDRV_SECTOR_SIZE)); acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
} }
} }

View file

@ -282,9 +282,9 @@ exit:
return ret; return ret;
} }
static void cow_flush(BlockDriverState *bs) static int cow_flush(BlockDriverState *bs)
{ {
bdrv_flush(bs->file); return bdrv_flush(bs->file);
} }
static QEMUOptionParameter cow_create_options[] = { static QEMUOptionParameter cow_create_options[] = {

View file

@ -54,7 +54,6 @@ typedef struct QCowHeader {
#define L2_CACHE_SIZE 16 #define L2_CACHE_SIZE 16
typedef struct BDRVQcowState { typedef struct BDRVQcowState {
BlockDriverState *hd;
int cluster_bits; int cluster_bits;
int cluster_size; int cluster_size;
int cluster_sectors; int cluster_sectors;
@ -910,9 +909,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
return 0; return 0;
} }
static void qcow_flush(BlockDriverState *bs) static int qcow_flush(BlockDriverState *bs)
{ {
bdrv_flush(bs->file); return bdrv_flush(bs->file);
} }
static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,

View file

@ -188,6 +188,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
ret = bdrv_pread(bs->file, l2_offset, *l2_table, ret = bdrv_pread(bs->file, l2_offset, *l2_table,
s->l2_size * sizeof(uint64_t)); s->l2_size * sizeof(uint64_t));
if (ret < 0) { if (ret < 0) {
qcow2_l2_cache_reset(bs);
return ret; return ret;
} }

View file

@ -103,6 +103,7 @@ static int load_refcount_block(BlockDriverState *bs,
ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache, ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache,
s->cluster_size); s->cluster_size);
if (ret < 0) { if (ret < 0) {
s->refcount_block_cache_offset = 0;
return ret; return ret;
} }

View file

@ -1148,9 +1148,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
return 0; return 0;
} }
static void qcow_flush(BlockDriverState *bs) static int qcow_flush(BlockDriverState *bs)
{ {
bdrv_flush(bs->file); return bdrv_flush(bs->file);
} }
static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,

View file

@ -79,7 +79,6 @@ typedef struct QCowSnapshot {
} QCowSnapshot; } QCowSnapshot;
typedef struct BDRVQcowState { typedef struct BDRVQcowState {
BlockDriverState *hd;
int cluster_bits; int cluster_bits;
int cluster_size; int cluster_size;
int cluster_sectors; int cluster_sectors;

View file

@ -463,7 +463,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
count -= ret; count -= ret;
sum += ret; sum += ret;
} }
/* here, count < 512 because (count & ~sector_mask) == 0 */ /* here, count < sector_size because (count & ~sector_mask) == 0 */
if (count) { if (count) {
ret = raw_pread_aligned(bs, offset, s->aligned_buf, ret = raw_pread_aligned(bs, offset, s->aligned_buf,
bs->buffer_alignment); bs->buffer_alignment);
@ -734,10 +734,10 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
return result; return result;
} }
static void raw_flush(BlockDriverState *bs) static int raw_flush(BlockDriverState *bs)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
qemu_fdatasync(s->fd); return qemu_fdatasync(s->fd);
} }

View file

@ -147,10 +147,17 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
return ret_count; return ret_count;
} }
static void raw_flush(BlockDriverState *bs) static int raw_flush(BlockDriverState *bs)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
FlushFileBuffers(s->hfile); int ret;
ret = FlushFileBuffers(s->hfile);
if (ret != 0) {
return -EIO;
}
return 0;
} }
static void raw_close(BlockDriverState *bs) static void raw_close(BlockDriverState *bs)

View file

@ -39,9 +39,9 @@ static void raw_close(BlockDriverState *bs)
{ {
} }
static void raw_flush(BlockDriverState *bs) static int raw_flush(BlockDriverState *bs)
{ {
bdrv_flush(bs->file); return bdrv_flush(bs->file);
} }
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,

View file

@ -186,7 +186,6 @@ typedef struct {
} VdiHeader; } VdiHeader;
typedef struct { typedef struct {
BlockDriverState *hd;
/* The block map entries are little endian (even in memory). */ /* The block map entries are little endian (even in memory). */
uint32_t *bmap; uint32_t *bmap;
/* Size of block (bytes). */ /* Size of block (bytes). */
@ -900,10 +899,10 @@ static void vdi_close(BlockDriverState *bs)
{ {
} }
static void vdi_flush(BlockDriverState *bs) static int vdi_flush(BlockDriverState *bs)
{ {
logout("\n"); logout("\n");
bdrv_flush(bs->file); return bdrv_flush(bs->file);
} }

View file

@ -61,7 +61,6 @@ typedef struct {
#define L2_CACHE_SIZE 16 #define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState { typedef struct BDRVVmdkState {
BlockDriverState *hd;
int64_t l1_table_offset; int64_t l1_table_offset;
int64_t l1_backup_table_offset; int64_t l1_backup_table_offset;
uint32_t *l1_table; uint32_t *l1_table;
@ -823,9 +822,9 @@ static void vmdk_close(BlockDriverState *bs)
qemu_free(s->l2_cache); qemu_free(s->l2_cache);
} }
static void vmdk_flush(BlockDriverState *bs) static int vmdk_flush(BlockDriverState *bs)
{ {
bdrv_flush(bs->file); return bdrv_flush(bs->file);
} }

View file

@ -110,8 +110,6 @@ struct vhd_dyndisk_header {
}; };
typedef struct BDRVVPCState { typedef struct BDRVVPCState {
BlockDriverState *hd;
uint8_t footer_buf[HEADER_SIZE]; uint8_t footer_buf[HEADER_SIZE];
uint64_t free_data_block_offset; uint64_t free_data_block_offset;
int max_table_entries; int max_table_entries;
@ -439,6 +437,10 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
return 0; return 0;
} }
static int vpc_flush(BlockDriverState *bs)
{
return bdrv_flush(bs->file);
}
/* /*
* Calculates the number of cylinders, heads and sectors per cylinder * Calculates the number of cylinders, heads and sectors per cylinder
@ -618,14 +620,15 @@ static QEMUOptionParameter vpc_create_options[] = {
}; };
static BlockDriver bdrv_vpc = { static BlockDriver bdrv_vpc = {
.format_name = "vpc", .format_name = "vpc",
.instance_size = sizeof(BDRVVPCState), .instance_size = sizeof(BDRVVPCState),
.bdrv_probe = vpc_probe, .bdrv_probe = vpc_probe,
.bdrv_open = vpc_open, .bdrv_open = vpc_open,
.bdrv_read = vpc_read, .bdrv_read = vpc_read,
.bdrv_write = vpc_write, .bdrv_write = vpc_write,
.bdrv_close = vpc_close, .bdrv_flush = vpc_flush,
.bdrv_create = vpc_create, .bdrv_close = vpc_close,
.bdrv_create = vpc_create,
.create_options = vpc_create_options, .create_options = vpc_create_options,
}; };

View file

@ -59,7 +59,7 @@ struct BlockDriver {
const uint8_t *buf, int nb_sectors); const uint8_t *buf, int nb_sectors);
void (*bdrv_close)(BlockDriverState *bs); void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, QEMUOptionParameter *options); int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
void (*bdrv_flush)(BlockDriverState *bs); int (*bdrv_flush)(BlockDriverState *bs);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum); int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_set_key)(BlockDriverState *bs, const char *key);

View file

@ -14,6 +14,8 @@
#include "qemu-option.h" #include "qemu-option.h"
#include "qemu-config.h" #include "qemu-config.h"
#include "sysemu.h" #include "sysemu.h"
#include "hw/qdev.h"
#include "block_int.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@ -314,7 +316,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
on_write_error = BLOCK_ERR_STOP_ENOSPC; on_write_error = BLOCK_ERR_STOP_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) { if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
fprintf(stderr, "werror is no supported by this format\n"); fprintf(stderr, "werror is not supported by this format\n");
return NULL; return NULL;
} }
@ -326,8 +328,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
on_read_error = BLOCK_ERR_REPORT; on_read_error = BLOCK_ERR_REPORT;
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) { if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
fprintf(stderr, "rerror is no supported by this format\n"); fprintf(stderr, "rerror is not supported by this format\n");
return NULL; return NULL;
} }
@ -597,3 +599,40 @@ int do_change_block(Monitor *mon, const char *device,
} }
return monitor_read_bdrv_key_start(mon, bs, NULL, NULL); return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
} }
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *id = qdict_get_str(qdict, "id");
BlockDriverState *bs;
BlockDriverState **ptr;
Property *prop;
bs = bdrv_find(id);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, id);
return -1;
}
/* quiesce block driver; prevent further io */
qemu_aio_flush();
bdrv_flush(bs);
bdrv_close(bs);
/* clean up guest state from pointing to host resource by
* finding and removing DeviceState "drive" property */
for (prop = bs->peer->info->props; prop && prop->name; prop++) {
if (prop->info->type == PROP_TYPE_DRIVE) {
ptr = qdev_get_prop_ptr(bs->peer, prop);
if ((*ptr) == bs) {
bdrv_detach(bs, bs->peer);
*ptr = NULL;
break;
}
}
}
/* clean up host side */
drive_uninit(drive_get_by_blockdev(bs));
return 0;
}

View file

@ -32,7 +32,7 @@ struct DriveInfo {
}; };
#define MAX_IDE_DEVS 2 #define MAX_IDE_DEVS 2
#define MAX_SCSI_DEVS 7 #define MAX_SCSI_DEVS 255
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
int drive_get_max_bus(BlockInterfaceType type); int drive_get_max_bus(BlockInterfaceType type);
@ -51,5 +51,6 @@ int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_change_block(Monitor *mon, const char *device, int do_change_block(Monitor *mon, const char *device,
const char *filename, const char *fmt); const char *filename, const char *fmt);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
#endif #endif

21
configure vendored
View file

@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build" echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support" echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable vhost-net acceleration support" echo " --enable-vhost-net enable vhost-net acceleration support"
echo " --trace-backend=B Trace backend nop simple ust" echo " --trace-backend=B Trace backend nop simple ust dtrace"
echo " --trace-file=NAME Full PATH,NAME of file to store traces" echo " --trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>" echo " Default:trace-<pid>"
echo " --disable-spice disable spice" echo " --disable-spice disable spice"
@ -2193,6 +2193,22 @@ EOF
exit 1 exit 1
fi fi
fi fi
##########################################
# For 'dtrace' backend, test if 'dtrace' command is present
if test "$trace_backend" = "dtrace"; then
if ! has 'dtrace' ; then
echo
echo "Error: dtrace command is not found in PATH $PATH"
echo
exit 1
fi
trace_backend_stap="no"
if has 'stap' ; then
trace_backend_stap="yes"
fi
fi
########################################## ##########################################
# End of CC checks # End of CC checks
# After here, no more $cc or $ld runs # After here, no more $cc or $ld runs
@ -2633,6 +2649,9 @@ fi
if test "$trace_backend" = "simple"; then if test "$trace_backend" = "simple"; then
trace_file="\"$trace_file-%u\"" trace_file="\"$trace_file-%u\""
fi fi
if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then
echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak
fi
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
echo "TOOLS=$tools" >> $config_host_mak echo "TOOLS=$tools" >> $config_host_mak

View file

@ -1,7 +1,7 @@
# Default configuration for arm-softmmu # Default configuration for arm-softmmu
include pci.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_NAND=y CONFIG_NAND=y
CONFIG_ECC=y CONFIG_ECC=y
@ -25,6 +25,5 @@ CONFIG_SSI_SD=y
CONFIG_LAN9118=y CONFIG_LAN9118=y
CONFIG_SMC91C111=y CONFIG_SMC91C111=y
CONFIG_DS1338=y CONFIG_DS1338=y
CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y

View file

@ -2,5 +2,4 @@
CONFIG_NAND=y CONFIG_NAND=y
CONFIG_PTIMER=y CONFIG_PTIMER=y
CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y

View file

@ -1,6 +1,6 @@
# Default configuration for i386-softmmu # Default configuration for i386-softmmu
CONFIG_USB_OHCI=y include pci.mak
CONFIG_VGA_PCI=y CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y CONFIG_VGA_ISA=y
CONFIG_VMWARE_VGA=y CONFIG_VMWARE_VGA=y
@ -9,7 +9,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y CONFIG_I8254=y
CONFIG_PCSPK=y CONFIG_PCSPK=y
CONFIG_PCKBD=y CONFIG_PCKBD=y
CONFIG_USB_UHCI=y
CONFIG_FDC=y CONFIG_FDC=y
CONFIG_ACPI=y CONFIG_ACPI=y
CONFIG_APM=y CONFIG_APM=y
@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_PIIX_PCI=y CONFIG_PIIX_PCI=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y

View file

@ -1,5 +1,5 @@
# Default configuration for m68k-softmmu # Default configuration for m68k-softmmu
include pci.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_PTIMER=y CONFIG_PTIMER=y
CONFIG_VIRTIO_PCI=y

View file

@ -1,5 +1,4 @@
# Default configuration for microblaze-softmmu # Default configuration for microblaze-softmmu
CONFIG_PTIMER=y CONFIG_PTIMER=y
CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y

View file

@ -1,5 +1,6 @@
# Default configuration for mips-softmmu # Default configuration for mips-softmmu
include pci.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESP=y CONFIG_ESP=y
CONFIG_VGA_PCI=y CONFIG_VGA_PCI=y
@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y CONFIG_I8254=y
CONFIG_PCSPK=y CONFIG_PCSPK=y
CONFIG_PCKBD=y CONFIG_PCKBD=y
CONFIG_USB_UHCI=y
CONFIG_FDC=y CONFIG_FDC=y
CONFIG_ACPI=y CONFIG_ACPI=y
CONFIG_APM=y CONFIG_APM=y
@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y
CONFIG_RC4030=y CONFIG_RC4030=y
CONFIG_DP8393X=y CONFIG_DP8393X=y
CONFIG_DS1225Y=y CONFIG_DS1225Y=y

View file

@ -1,5 +1,6 @@
# Default configuration for mips64-softmmu # Default configuration for mips64-softmmu
include pci.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESP=y CONFIG_ESP=y
CONFIG_VGA_PCI=y CONFIG_VGA_PCI=y
@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y CONFIG_I8254=y
CONFIG_PCSPK=y CONFIG_PCSPK=y
CONFIG_PCKBD=y CONFIG_PCKBD=y
CONFIG_USB_UHCI=y
CONFIG_FDC=y CONFIG_FDC=y
CONFIG_ACPI=y CONFIG_ACPI=y
CONFIG_APM=y CONFIG_APM=y
@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y
CONFIG_RC4030=y CONFIG_RC4030=y
CONFIG_DP8393X=y CONFIG_DP8393X=y
CONFIG_DS1225Y=y CONFIG_DS1225Y=y

View file

@ -1,5 +1,6 @@
# Default configuration for mips64el-softmmu # Default configuration for mips64el-softmmu
include pci.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESP=y CONFIG_ESP=y
CONFIG_VGA_PCI=y CONFIG_VGA_PCI=y
@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y CONFIG_I8254=y
CONFIG_PCSPK=y CONFIG_PCSPK=y
CONFIG_PCKBD=y CONFIG_PCKBD=y
CONFIG_USB_UHCI=y
CONFIG_FDC=y CONFIG_FDC=y
CONFIG_ACPI=y CONFIG_ACPI=y
CONFIG_APM=y CONFIG_APM=y
@ -25,7 +25,6 @@ CONFIG_IDE_PIIX=y
CONFIG_IDE_VIA=y CONFIG_IDE_VIA=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y
CONFIG_RC4030=y CONFIG_RC4030=y
CONFIG_DP8393X=y CONFIG_DP8393X=y
CONFIG_DS1225Y=y CONFIG_DS1225Y=y

View file

@ -1,5 +1,6 @@
# Default configuration for mipsel-softmmu # Default configuration for mipsel-softmmu
include pci.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESP=y CONFIG_ESP=y
CONFIG_VGA_PCI=y CONFIG_VGA_PCI=y
@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y CONFIG_I8254=y
CONFIG_PCSPK=y CONFIG_PCSPK=y
CONFIG_PCKBD=y CONFIG_PCKBD=y
CONFIG_USB_UHCI=y
CONFIG_FDC=y CONFIG_FDC=y
CONFIG_ACPI=y CONFIG_ACPI=y
CONFIG_APM=y CONFIG_APM=y
@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y
CONFIG_RC4030=y CONFIG_RC4030=y
CONFIG_DP8393X=y CONFIG_DP8393X=y
CONFIG_DS1225Y=y CONFIG_DS1225Y=y

12
default-configs/pci.mak Normal file
View file

@ -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

View file

@ -1,7 +1,7 @@
# Default configuration for ppc-softmmu # Default configuration for ppc-softmmu
include pci.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESCC=y CONFIG_ESCC=y
CONFIG_M48T59=y CONFIG_M48T59=y
@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y CONFIG_PTIMER=y

View file

@ -1,7 +1,7 @@
# Default configuration for ppc64-softmmu # Default configuration for ppc64-softmmu
include pci.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESCC=y CONFIG_ESCC=y
CONFIG_M48T59=y CONFIG_M48T59=y
@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y CONFIG_PTIMER=y

View file

@ -1,7 +1,7 @@
# Default configuration for ppcemb-softmmu # Default configuration for ppcemb-softmmu
include pci.mak
CONFIG_GDBSTUB_XML=y CONFIG_GDBSTUB_XML=y
CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_ESCC=y CONFIG_ESCC=y
CONFIG_M48T59=y CONFIG_M48T59=y
@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
CONFIG_IDE_MACIO=y CONFIG_IDE_MACIO=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y
CONFIG_PTIMER=y CONFIG_PTIMER=y

View file

@ -0,0 +1 @@
CONFIG_VIRTIO=y

View file

@ -1,9 +1,8 @@
# Default configuration for sh4-softmmu # Default configuration for sh4-softmmu
CONFIG_USB_OHCI=y include pci.mak
CONFIG_SERIAL=y CONFIG_SERIAL=y
CONFIG_PTIMER=y CONFIG_PTIMER=y
CONFIG_VIRTIO_PCI=y
CONFIG_IDE_CORE=y CONFIG_IDE_CORE=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y

View file

@ -1,9 +1,8 @@
# Default configuration for sh4eb-softmmu # Default configuration for sh4eb-softmmu
CONFIG_USB_OHCI=y include pci.mak
CONFIG_SERIAL=y CONFIG_SERIAL=y
CONFIG_PTIMER=y CONFIG_PTIMER=y
CONFIG_VIRTIO_PCI=y
CONFIG_IDE_CORE=y CONFIG_IDE_CORE=y
CONFIG_PFLASH_CFI02=y CONFIG_PFLASH_CFI02=y
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y

View file

@ -6,5 +6,5 @@ CONFIG_ESCC=y
CONFIG_M48T59=y CONFIG_M48T59=y
CONFIG_PTIMER=y CONFIG_PTIMER=y
CONFIG_FDC=y CONFIG_FDC=y
CONFIG_VIRTIO_PCI=y
CONFIG_EMPTY_SLOT=y CONFIG_EMPTY_SLOT=y
CONFIG_PCNET_COMMON=y

View file

@ -1,5 +1,6 @@
# Default configuration for sparc64-softmmu # Default configuration for sparc64-softmmu
include pci.mak
CONFIG_ISA_MMIO=y CONFIG_ISA_MMIO=y
CONFIG_M48T59=y CONFIG_M48T59=y
CONFIG_PTIMER=y CONFIG_PTIMER=y
@ -13,4 +14,3 @@ CONFIG_IDE_QDEV=y
CONFIG_IDE_PCI=y CONFIG_IDE_PCI=y
CONFIG_IDE_ISA=y CONFIG_IDE_ISA=y
CONFIG_IDE_CMD646=y CONFIG_IDE_CMD646=y
CONFIG_VIRTIO_PCI=y

View file

@ -1,6 +1,6 @@
# Default configuration for x86_64-softmmu # Default configuration for x86_64-softmmu
CONFIG_USB_OHCI=y include pci.mak
CONFIG_VGA_PCI=y CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y CONFIG_VGA_ISA=y
CONFIG_VMWARE_VGA=y CONFIG_VMWARE_VGA=y
@ -9,7 +9,6 @@ CONFIG_PARALLEL=y
CONFIG_I8254=y CONFIG_I8254=y
CONFIG_PCSPK=y CONFIG_PCSPK=y
CONFIG_PCKBD=y CONFIG_PCKBD=y
CONFIG_USB_UHCI=y
CONFIG_FDC=y CONFIG_FDC=y
CONFIG_ACPI=y CONFIG_ACPI=y
CONFIG_APM=y CONFIG_APM=y
@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_PIIX_PCI=y CONFIG_PIIX_PCI=y
CONFIG_SOUND=y CONFIG_SOUND=y
CONFIG_VIRTIO_PCI=y

View file

@ -65,6 +65,24 @@ STEXI
@item eject [-f] @var{device} @item eject [-f] @var{device}
@findex eject @findex eject
Eject a removable medium (use -f to force it). Eject a removable medium (use -f to force it).
ETEXI
{
.name = "drive_del",
.args_type = "id:s",
.params = "device",
.help = "remove host block device",
.user_print = monitor_user_noop,
.mhandler.cmd_new = do_drive_del,
},
STEXI
@item drive_del @var{device}
@findex drive_del
Remove host block device. The result is that guest generated IO is no longer
submitted against the host device underlying the disk. Once a drive has
been deleted, the QEMU Block layer returns -EIO which results in IO
errors in the guest for applications that are reading/writing to the device.
ETEXI ETEXI
{ {

View file

@ -52,6 +52,7 @@ struct pci_status {
typedef struct PIIX4PMState { typedef struct PIIX4PMState {
PCIDevice dev; PCIDevice dev;
IORange ioport;
uint16_t pmsts; uint16_t pmsts;
uint16_t pmen; uint16_t pmen;
uint16_t pmcntrl; uint16_t pmcntrl;
@ -128,10 +129,16 @@ static void pm_tmr_timer(void *opaque)
pm_update_sci(s); pm_update_sci(s);
} }
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
uint64_t val)
{ {
PIIX4PMState *s = opaque; PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
addr &= 0x3f;
if (width != 2) {
PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n",
(unsigned)addr, width, (unsigned)val);
}
switch(addr) { switch(addr) {
case 0x00: case 0x00:
{ {
@ -184,12 +191,12 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val); PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val);
} }
static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
uint64_t *data)
{ {
PIIX4PMState *s = opaque; PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
uint32_t val; uint32_t val;
addr &= 0x3f;
switch(addr) { switch(addr) {
case 0x00: case 0x00:
val = get_pmsts(s); val = get_pmsts(s);
@ -200,27 +207,6 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
case 0x04: case 0x04:
val = s->pmcntrl; val = s->pmcntrl;
break; break;
default:
val = 0;
break;
}
PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
return val;
}
static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
// PIIX4PMState *s = opaque;
PIIX4_DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr & 0x3f, val);
}
static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
uint32_t val;
addr &= 0x3f;
switch(addr) {
case 0x08: case 0x08:
val = get_pmtmr(s); val = get_pmtmr(s);
break; break;
@ -228,10 +214,15 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
val = 0; val = 0;
break; break;
} }
PIIX4_DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val); PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
return val; *data = val;
} }
static const IORangeOps pm_iorange_ops = {
.read = pm_ioport_read,
.write = pm_ioport_write,
};
static void apm_ctrl_changed(uint32_t val, void *arg) static void apm_ctrl_changed(uint32_t val, void *arg)
{ {
PIIX4PMState *s = arg; PIIX4PMState *s = arg;
@ -265,10 +256,8 @@ static void pm_io_space_update(PIIX4PMState *s)
/* XXX: need to improve memory and ioport allocation */ /* XXX: need to improve memory and ioport allocation */
PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base); PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base);
register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64);
register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); ioport_register(&s->ioport);
register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
} }
} }

View file

@ -437,6 +437,8 @@ static int apic_find_dest(uint8_t dest)
apic = local_apics[i]; apic = local_apics[i];
if (apic && apic->id == dest) if (apic && apic->id == dest)
return i; return i;
if (!apic)
break;
} }
return -1; return -1;
@ -472,6 +474,8 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
set_bit(deliver_bitmask, i); set_bit(deliver_bitmask, i);
} }
} }
} else {
break;
} }
} }
} }

View file

@ -447,9 +447,10 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
// data descriptor // data descriptor
tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0; tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
} else } else {
// legacy descriptor // legacy descriptor
tp->cptse = 0; tp->cptse = 0;
}
if (vlan_enabled(s) && is_vlan_txd(txd_lower) && if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
(tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) { (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
@ -685,8 +686,9 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
(void *)(buf + vlan_offset), size); (void *)(buf + vlan_offset), size);
desc.length = cpu_to_le16(size + fcs_len(s)); desc.length = cpu_to_le16(size + fcs_len(s));
desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM; desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM;
} else // as per intel docs; skip descriptors with null buf addr } else { // as per intel docs; skip descriptors with null buf addr
DBGOUT(RX, "Null RX descriptor!!\n"); DBGOUT(RX, "Null RX descriptor!!\n");
}
cpu_physical_memory_write(base, (void *)&desc, sizeof(desc)); cpu_physical_memory_write(base, (void *)&desc, sizeof(desc));
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
@ -858,13 +860,14 @@ e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
#ifdef TARGET_WORDS_BIGENDIAN #ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val); val = bswap32(val);
#endif #endif
if (index < NWRITEOPS && macreg_writeops[index]) if (index < NWRITEOPS && macreg_writeops[index]) {
macreg_writeops[index](s, index, val); macreg_writeops[index](s, index, val);
else if (index < NREADOPS && macreg_readops[index]) } else if (index < NREADOPS && macreg_readops[index]) {
DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val); DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04x\n", index<<2, val);
else } else {
DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n", DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n",
index<<2, val); index<<2, val);
}
} }
static void static void

View file

@ -808,6 +808,28 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
return 0; return 0;
} }
static int hda_audio_exit(HDACodecDevice *hda)
{
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
HDAAudioStream *st;
int i;
dprint(a, 1, "%s\n", __FUNCTION__);
for (i = 0; i < ARRAY_SIZE(a->st); i++) {
st = a->st + i;
if (st->node == NULL) {
continue;
}
if (st->output) {
AUD_close_out(&a->card, st->voice.out);
} else {
AUD_close_in(&a->card, st->voice.in);
}
}
AUD_remove_card(&a->card);
return 0;
}
static int hda_audio_post_load(void *opaque, int version) static int hda_audio_post_load(void *opaque, int version)
{ {
HDAAudioState *a = opaque; HDAAudioState *a = opaque;
@ -879,6 +901,7 @@ static HDACodecDeviceInfo hda_audio_info_output = {
.qdev.vmsd = &vmstate_hda_audio, .qdev.vmsd = &vmstate_hda_audio,
.qdev.props = hda_audio_properties, .qdev.props = hda_audio_properties,
.init = hda_audio_init_output, .init = hda_audio_init_output,
.exit = hda_audio_exit,
.command = hda_audio_command, .command = hda_audio_command,
.stream = hda_audio_stream, .stream = hda_audio_stream,
}; };
@ -890,6 +913,7 @@ static HDACodecDeviceInfo hda_audio_info_duplex = {
.qdev.vmsd = &vmstate_hda_audio, .qdev.vmsd = &vmstate_hda_audio,
.qdev.props = hda_audio_properties, .qdev.props = hda_audio_properties,
.init = hda_audio_init_duplex, .init = hda_audio_init_duplex,
.exit = hda_audio_exit,
.command = hda_audio_command, .command = hda_audio_command,
.stream = hda_audio_stream, .stream = hda_audio_stream,
}; };

View file

@ -179,12 +179,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 4, 1, bmdma_readb_1, d); register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
} }
register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); ioport_register(&bm->addr_ioport);
register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
addr += 8; addr += 8;
} }
} }

View file

@ -473,11 +473,21 @@ static void dma_buf_commit(IDEState *s, int is_write)
qemu_sglist_destroy(&s->sg); qemu_sglist_destroy(&s->sg);
} }
static void ide_dma_set_inactive(BMDMAState *bm)
{
bm->status &= ~BM_STATUS_DMAING;
bm->dma_cb = NULL;
bm->unit = -1;
bm->aiocb = NULL;
}
void ide_dma_error(IDEState *s) void ide_dma_error(IDEState *s)
{ {
ide_transfer_stop(s); ide_transfer_stop(s);
s->error = ABRT_ERR; s->error = ABRT_ERR;
s->status = READY_STAT | ERR_STAT; s->status = READY_STAT | ERR_STAT;
ide_dma_set_inactive(s->bus->bmdma);
s->bus->bmdma->status |= BM_STATUS_INT;
ide_set_irq(s->bus); ide_set_irq(s->bus);
} }
@ -587,11 +597,8 @@ static void ide_read_dma_cb(void *opaque, int ret)
s->status = READY_STAT | SEEK_STAT; s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s->bus); ide_set_irq(s->bus);
eot: eot:
bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT; bm->status |= BM_STATUS_INT;
bm->dma_cb = NULL; ide_dma_set_inactive(bm);
bm->unit = -1;
bm->aiocb = NULL;
return; return;
} }
@ -733,11 +740,8 @@ static void ide_write_dma_cb(void *opaque, int ret)
s->status = READY_STAT | SEEK_STAT; s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s->bus); ide_set_irq(s->bus);
eot: eot:
bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT; bm->status |= BM_STATUS_INT;
bm->dma_cb = NULL; ide_dma_set_inactive(bm);
bm->unit = -1;
bm->aiocb = NULL;
return; return;
} }
@ -811,10 +815,16 @@ static void ide_flush_cb(void *opaque, int ret)
static void ide_flush_cache(IDEState *s) static void ide_flush_cache(IDEState *s)
{ {
if (s->bs) { BlockDriverAIOCB *acb;
bdrv_aio_flush(s->bs, ide_flush_cb, s);
} else { if (s->bs == NULL) {
ide_flush_cb(s, 0); ide_flush_cb(s, 0);
return;
}
acb = bdrv_aio_flush(s->bs, ide_flush_cb, s);
if (acb == NULL) {
ide_flush_cb(s, -EIO);
} }
} }
@ -1055,11 +1065,8 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
ide_set_irq(s->bus); ide_set_irq(s->bus);
eot: eot:
bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT; bm->status |= BM_STATUS_INT;
bm->dma_cb = NULL; ide_dma_set_inactive(bm);
bm->unit = -1;
bm->aiocb = NULL;
return; return;
} }
@ -2948,12 +2955,10 @@ void ide_dma_cancel(BMDMAState *bm)
printf("aio_cancel\n"); printf("aio_cancel\n");
#endif #endif
bdrv_aio_cancel(bm->aiocb); bdrv_aio_cancel(bm->aiocb);
bm->aiocb = NULL;
} }
bm->status &= ~BM_STATUS_DMAING;
/* cancel DMA request */ /* cancel DMA request */
bm->unit = -1; ide_dma_set_inactive(bm);
bm->dma_cb = NULL;
} }
} }

View file

@ -8,6 +8,7 @@
*/ */
#include <hw/ide.h> #include <hw/ide.h>
#include "block_int.h" #include "block_int.h"
#include "iorange.h"
/* debug IDE devices */ /* debug IDE devices */
//#define DEBUG_IDE //#define DEBUG_IDE
@ -496,6 +497,7 @@ struct BMDMAState {
QEMUIOVector qiov; QEMUIOVector qiov;
int64_t sector_num; int64_t sector_num;
uint32_t nsector; uint32_t nsector;
IORange addr_ioport;
QEMUBH *bh; QEMUBH *bh;
}; };

View file

@ -39,106 +39,75 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
#ifdef DEBUG_IDE #ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val); printf("%s: 0x%08x\n", __func__, val);
#endif #endif
if (!(val & BM_CMD_START)) {
/* /* Ignore writes to SSBM if it keeps the old value */
* We can't cancel Scatter Gather DMA in the middle of the if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
* operation or a partial (not full) DMA transfer would reach if (!(val & BM_CMD_START)) {
* the storage so we wait for completion instead (we beahve /*
* like if the DMA was completed by the time the guest trying * We can't cancel Scatter Gather DMA in the middle of the
* to cancel dma with bmdma_cmd_writeb with BM_CMD_START not * operation or a partial (not full) DMA transfer would reach
* set). * the storage so we wait for completion instead (we beahve
* * like if the DMA was completed by the time the guest trying
* In the future we'll be able to safely cancel the I/O if the * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
* whole DMA operation will be submitted to disk with a single * set).
* aio operation with preadv/pwritev. *
*/ * In the future we'll be able to safely cancel the I/O if the
if (bm->aiocb) { * whole DMA operation will be submitted to disk with a single
qemu_aio_flush(); * aio operation with preadv/pwritev.
*/
if (bm->aiocb) {
qemu_aio_flush();
#ifdef DEBUG_IDE #ifdef DEBUG_IDE
if (bm->aiocb) if (bm->aiocb)
printf("ide_dma_cancel: aiocb still pending"); printf("ide_dma_cancel: aiocb still pending");
if (bm->status & BM_STATUS_DMAING) if (bm->status & BM_STATUS_DMAING)
printf("ide_dma_cancel: BM_STATUS_DMAING still pending"); printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
#endif #endif
}
} else {
bm->cur_addr = bm->addr;
if (!(bm->status & BM_STATUS_DMAING)) {
bm->status |= BM_STATUS_DMAING;
/* start dma transfer if possible */
if (bm->dma_cb)
bm->dma_cb(bm, 0);
}
} }
bm->cmd = val & 0x09;
} else {
if (!(bm->status & BM_STATUS_DMAING)) {
bm->status |= BM_STATUS_DMAING;
/* start dma transfer if possible */
if (bm->dma_cb)
bm->dma_cb(bm, 0);
}
bm->cmd = val & 0x09;
} }
bm->cmd = val & 0x09;
} }
uint32_t bmdma_addr_readb(void *opaque, uint32_t addr) static void bmdma_addr_read(IORange *ioport, uint64_t addr,
unsigned width, uint64_t *data)
{ {
BMDMAState *bm = opaque; BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
uint32_t val; uint32_t mask = (1ULL << (width * 8)) - 1;
val = (bm->addr >> ((addr & 3) * 8)) & 0xff;
*data = (bm->addr >> (addr * 8)) & mask;
#ifdef DEBUG_IDE #ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val); printf("%s: 0x%08x\n", __func__, (unsigned)*data);
#endif #endif
return val;
} }
void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val) static void bmdma_addr_write(IORange *ioport, uint64_t addr,
unsigned width, uint64_t data)
{ {
BMDMAState *bm = opaque; BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
int shift = (addr & 3) * 8; int shift = addr * 8;
uint32_t mask = (1ULL << (width * 8)) - 1;
#ifdef DEBUG_IDE #ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val); printf("%s: 0x%08x\n", __func__, (unsigned)data);
#endif #endif
bm->addr &= ~(0xFF << shift); bm->addr &= ~(mask << shift);
bm->addr |= ((val & 0xFF) << shift) & ~3; bm->addr |= ((data & mask) << shift) & ~3;
bm->cur_addr = bm->addr;
} }
uint32_t bmdma_addr_readw(void *opaque, uint32_t addr) const IORangeOps bmdma_addr_ioport_ops = {
{ .read = bmdma_addr_read,
BMDMAState *bm = opaque; .write = bmdma_addr_write,
uint32_t val; };
val = (bm->addr >> ((addr & 3) * 8)) & 0xffff;
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
#endif
return val;
}
void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val)
{
BMDMAState *bm = opaque;
int shift = (addr & 3) * 8;
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
#endif
bm->addr &= ~(0xFFFF << shift);
bm->addr |= ((val & 0xFFFF) << shift) & ~3;
bm->cur_addr = bm->addr;
}
uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
{
BMDMAState *bm = opaque;
uint32_t val;
val = bm->addr;
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
#endif
return val;
}
void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val)
{
BMDMAState *bm = opaque;
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
#endif
bm->addr = val & ~3;
bm->cur_addr = bm->addr;
}
static bool ide_bmdma_current_needed(void *opaque) static bool ide_bmdma_current_needed(void *opaque)
{ {

View file

@ -11,12 +11,7 @@ typedef struct PCIIDEState {
} PCIIDEState; } PCIIDEState;
void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val); void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val);
uint32_t bmdma_addr_readb(void *opaque, uint32_t addr); extern const IORangeOps bmdma_addr_ioport_ops;
void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val);
uint32_t bmdma_addr_readw(void *opaque, uint32_t addr);
void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val);
uint32_t bmdma_addr_readl(void *opaque, uint32_t addr);
void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val);
void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table); void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
extern const VMStateDescription vmstate_ide_pci; extern const VMStateDescription vmstate_ide_pci;

View file

@ -85,12 +85,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
register_ioport_read(addr, 4, 1, bmdma_readb, bm); register_ioport_read(addr, 4, 1, bmdma_readb, bm);
register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); ioport_register(&bm->addr_ioport);
register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
addr += 8; addr += 8;
} }
} }

View file

@ -87,12 +87,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
register_ioport_read(addr, 4, 1, bmdma_readb, bm); register_ioport_read(addr, 4, 1, bmdma_readb, bm);
register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); ioport_register(&bm->addr_ioport);
register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
addr += 8; addr += 8;
} }
} }

View file

@ -19,6 +19,7 @@
#include "hw.h" #include "hw.h"
#include "pci.h" #include "pci.h"
#include "msi.h"
#include "qemu-timer.h" #include "qemu-timer.h"
#include "audiodev.h" #include "audiodev.h"
#include "intel-hda.h" #include "intel-hda.h"
@ -55,15 +56,27 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
if (dev->cad == -1) { if (dev->cad == -1) {
dev->cad = bus->next_cad; dev->cad = bus->next_cad;
} }
if (dev->cad > 15) if (dev->cad >= 15) {
return -1; return -1;
}
bus->next_cad = dev->cad + 1; bus->next_cad = dev->cad + 1;
return info->init(dev); return info->init(dev);
} }
static int hda_codec_dev_exit(DeviceState *qdev)
{
HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (dev->info->exit) {
dev->info->exit(dev);
}
return 0;
}
void hda_codec_register(HDACodecDeviceInfo *info) void hda_codec_register(HDACodecDeviceInfo *info)
{ {
info->qdev.init = hda_codec_dev_init; info->qdev.init = hda_codec_dev_init;
info->qdev.exit = hda_codec_dev_exit;
info->qdev.bus_info = &hda_codec_bus_info; info->qdev.bus_info = &hda_codec_bus_info;
qdev_register(&info->qdev); qdev_register(&info->qdev);
} }
@ -177,6 +190,7 @@ struct IntelHDAState {
/* properties */ /* properties */
uint32_t debug; uint32_t debug;
uint32_t msi;
}; };
struct IntelHDAReg { struct IntelHDAReg {
@ -235,7 +249,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
if (d->rirb_sts & ICH6_RBSTS_OVERRUN) { if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
sts |= (1 << 30); sts |= (1 << 30);
} }
if (d->state_sts) { if (d->state_sts & d->wake_en) {
sts |= (1 << 30); sts |= (1 << 30);
} }
@ -257,6 +271,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
static void intel_hda_update_irq(IntelHDAState *d) static void intel_hda_update_irq(IntelHDAState *d)
{ {
int msi = d->msi && msi_enabled(&d->pci);
int level; int level;
intel_hda_update_int_sts(d); intel_hda_update_int_sts(d);
@ -265,8 +280,15 @@ static void intel_hda_update_irq(IntelHDAState *d)
} else { } else {
level = 0; level = 0;
} }
dprint(d, 2, "%s: level %d\n", __FUNCTION__, level); dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
qemu_set_irq(d->pci.irq[0], level); level, msi ? "msi" : "intx");
if (msi) {
if (level) {
msi_notify(&d->pci, 0);
}
} else {
qemu_set_irq(d->pci.irq[0], level);
}
} }
static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
@ -497,6 +519,11 @@ static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32
} }
} }
static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
{
intel_hda_update_irq(d);
}
static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
{ {
intel_hda_update_irq(d); intel_hda_update_irq(d);
@ -617,13 +644,15 @@ static const struct IntelHDAReg regtab[] = {
[ ICH6_REG_WAKEEN ] = { [ ICH6_REG_WAKEEN ] = {
.name = "WAKEEN", .name = "WAKEEN",
.size = 2, .size = 2,
.wmask = 0x7fff,
.offset = offsetof(IntelHDAState, wake_en), .offset = offsetof(IntelHDAState, wake_en),
.whandler = intel_hda_set_wake_en,
}, },
[ ICH6_REG_STATESTS ] = { [ ICH6_REG_STATESTS ] = {
.name = "STATESTS", .name = "STATESTS",
.size = 2, .size = 2,
.wmask = 0x3fff, .wmask = 0x7fff,
.wclear = 0x3fff, .wclear = 0x7fff,
.offset = offsetof(IntelHDAState, state_sts), .offset = offsetof(IntelHDAState, state_sts),
.whandler = intel_hda_set_state_sts, .whandler = intel_hda_set_state_sts,
}, },
@ -1130,6 +1159,9 @@ static int intel_hda_init(PCIDevice *pci)
intel_hda_mmio_write, d); intel_hda_mmio_write, d);
pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY, pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
intel_hda_map); intel_hda_map);
if (d->msi) {
msi_init(&d->pci, 0x50, 1, true, false);
}
hda_codec_bus_init(&d->pci.qdev, &d->codecs, hda_codec_bus_init(&d->pci.qdev, &d->codecs,
intel_hda_response, intel_hda_xfer); intel_hda_response, intel_hda_xfer);
@ -1137,6 +1169,28 @@ static int intel_hda_init(PCIDevice *pci)
return 0; return 0;
} }
static int intel_hda_exit(PCIDevice *pci)
{
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
if (d->msi) {
msi_uninit(&d->pci);
}
cpu_unregister_io_memory(d->mmio_addr);
return 0;
}
static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
uint32_t val, int len)
{
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
pci_default_write_config(pci, addr, val, len);
if (d->msi) {
msi_write_config(pci, addr, val, len);
}
}
static int intel_hda_post_load(void *opaque, int version) static int intel_hda_post_load(void *opaque, int version)
{ {
IntelHDAState* d = opaque; IntelHDAState* d = opaque;
@ -1219,8 +1273,11 @@ static PCIDeviceInfo intel_hda_info = {
.qdev.vmsd = &vmstate_intel_hda, .qdev.vmsd = &vmstate_intel_hda,
.qdev.reset = intel_hda_reset, .qdev.reset = intel_hda_reset,
.init = intel_hda_init, .init = intel_hda_init,
.exit = intel_hda_exit,
.config_write = intel_hda_write_config,
.qdev.props = (Property[]) { .qdev.props = (Property[]) {
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
} }
}; };

View file

@ -32,6 +32,7 @@ struct HDACodecDevice {
struct HDACodecDeviceInfo { struct HDACodecDeviceInfo {
DeviceInfo qdev; DeviceInfo qdev;
int (*init)(HDACodecDevice *dev); int (*init)(HDACodecDevice *dev);
int (*exit)(HDACodecDevice *dev);
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data); void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running); void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
}; };

View file

@ -977,7 +977,7 @@ void mips_malta_init (ram_addr_t ram_size,
} else if (vmsvga_enabled) { } else if (vmsvga_enabled) {
pci_vmsvga_init(pci_bus); pci_vmsvga_init(pci_bus);
} else if (std_vga_enabled) { } else if (std_vga_enabled) {
pci_vga_init(pci_bus, 0, 0); pci_vga_init(pci_bus);
} }
} }

View file

@ -171,6 +171,12 @@ int load_multiboot(void *fw_cfg,
uint64_t elf_low, elf_high; uint64_t elf_low, elf_high;
int kernel_size; int kernel_size;
fclose(f); fclose(f);
if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
exit(1);
}
kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
&elf_low, &elf_high, 0, ELF_MACHINE, 0); &elf_low, &elf_high, 0, ELF_MACHINE, 0);
if (kernel_size < 0) { if (kernel_size < 0) {

24
hw/pc.c
View file

@ -75,12 +75,12 @@ struct e820_entry {
uint64_t address; uint64_t address;
uint64_t length; uint64_t length;
uint32_t type; uint32_t type;
}; } __attribute((__packed__, __aligned__(4)));
struct e820_table { struct e820_table {
uint32_t count; uint32_t count;
struct e820_entry entry[E820_NR_ENTRIES]; struct e820_entry entry[E820_NR_ENTRIES];
}; } __attribute((__packed__, __aligned__(4)));
static struct e820_table e820_table; static struct e820_table e820_table;
@ -430,8 +430,8 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
/* Bochs BIOS messages */ /* Bochs BIOS messages */
case 0x400: case 0x400:
case 0x401: case 0x401:
fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); /* used to be panic, now unused */
exit(1); break;
case 0x402: case 0x402:
case 0x403: case 0x403:
#ifdef DEBUG_BIOS #ifdef DEBUG_BIOS
@ -467,19 +467,19 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
{ {
int index = e820_table.count; int index = le32_to_cpu(e820_table.count);
struct e820_entry *entry; struct e820_entry *entry;
if (index >= E820_NR_ENTRIES) if (index >= E820_NR_ENTRIES)
return -EBUSY; return -EBUSY;
entry = &e820_table.entry[index]; entry = &e820_table.entry[index++];
entry->address = address; entry->address = cpu_to_le64(address);
entry->length = length; entry->length = cpu_to_le64(length);
entry->type = type; entry->type = cpu_to_le32(type);
e820_table.count++; e820_table.count = cpu_to_le32(index);
return e820_table.count; return index;
} }
static void *bochs_bios_init(void) static void *bochs_bios_init(void)
@ -993,7 +993,7 @@ void pc_vga_init(PCIBus *pci_bus)
fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
} else if (std_vga_enabled) { } else if (std_vga_enabled) {
if (pci_bus) { if (pci_bus) {
pci_vga_init(pci_bus, 0, 0); pci_vga_init(pci_bus);
} else { } else {
isa_vga_init(); isa_vga_init();
} }

View file

@ -154,8 +154,7 @@ enum vga_retrace_method {
extern enum vga_retrace_method vga_retrace_method; extern enum vga_retrace_method vga_retrace_method;
int isa_vga_init(void); int isa_vga_init(void);
int pci_vga_init(PCIBus *bus, int pci_vga_init(PCIBus *bus);
unsigned long vga_bios_offset, int vga_bios_size);
int isa_vga_mm_init(target_phys_addr_t vram_base, int isa_vga_mm_init(target_phys_addr_t vram_base,
target_phys_addr_t ctrl_base, int it_shift); target_phys_addr_t ctrl_base, int it_shift);

View file

@ -212,7 +212,7 @@ static void pc_init_isa(ram_addr_t ram_size,
} }
static QEMUMachine pc_machine = { static QEMUMachine pc_machine = {
.name = "pc-0.13", .name = "pc-0.14",
.alias = "pc", .alias = "pc",
.desc = "Standard PC", .desc = "Standard PC",
.init = pc_init_pci, .init = pc_init_pci,
@ -220,6 +220,29 @@ static QEMUMachine pc_machine = {
.is_default = 1, .is_default = 1,
}; };
static QEMUMachine pc_machine_v0_13 = {
.name = "pc-0.13",
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
{
.driver = "virtio-9p-pci",
.property = "vectors",
.value = stringify(0),
},{
.driver = "VGA",
.property = "rombar",
.value = stringify(0),
},{
.driver = "vmware-svga",
.property = "rombar",
.value = stringify(0),
},
{ /* end of list */ }
},
};
static QEMUMachine pc_machine_v0_12 = { static QEMUMachine pc_machine_v0_12 = {
.name = "pc-0.12", .name = "pc-0.12",
.desc = "Standard PC", .desc = "Standard PC",
@ -234,6 +257,14 @@ static QEMUMachine pc_machine_v0_12 = {
.driver = "virtio-serial-pci", .driver = "virtio-serial-pci",
.property = "vectors", .property = "vectors",
.value = stringify(0), .value = stringify(0),
},{
.driver = "VGA",
.property = "rombar",
.value = stringify(0),
},{
.driver = "vmware-svga",
.property = "rombar",
.value = stringify(0),
}, },
{ /* end of list */ } { /* end of list */ }
} }
@ -331,6 +362,7 @@ static QEMUMachine isapc_machine = {
static void pc_machine_init(void) static void pc_machine_init(void)
{ {
qemu_register_machine(&pc_machine); qemu_register_machine(&pc_machine);
qemu_register_machine(&pc_machine_v0_13);
qemu_register_machine(&pc_machine_v0_12); qemu_register_machine(&pc_machine_v0_12);
qemu_register_machine(&pc_machine_v0_11); qemu_register_machine(&pc_machine_v0_11);
qemu_register_machine(&pc_machine_v0_10); qemu_register_machine(&pc_machine_v0_10);

345
hw/pcnet-pci.c Normal file
View file

@ -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)

View file

@ -35,9 +35,8 @@
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
*/ */
#include "pci.h" #include "qdev.h"
#include "net.h" #include "net.h"
#include "loader.h"
#include "qemu-timer.h" #include "qemu-timer.h"
#include "qemu_socket.h" #include "qemu_socket.h"
@ -52,11 +51,6 @@
//#define PCNET_DEBUG_MATCH //#define PCNET_DEBUG_MATCH
typedef struct {
PCIDevice pci_dev;
PCNetState state;
} PCIPCNetState;
struct qemu_ether_header { struct qemu_ether_header {
uint8_t ether_dhost[6]; uint8_t ether_dhost[6];
uint8_t ether_shost[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 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_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 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) static void pcnet_s_reset(PCNetState *s)
{ {
@ -1048,9 +1041,10 @@ ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
int crc_err = 0; int crc_err = 0;
int size = size_; int size = size_;
if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
(CSR_LOOP(s) && !s->looptest)) {
return -1; return -1;
}
#ifdef PCNET_DEBUG #ifdef PCNET_DEBUG
printf("pcnet_receive size=%d\n", size); printf("pcnet_receive size=%d\n", size);
#endif #endif
@ -1537,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; uint32_t val;
rap &= 127; rap &= 127;
@ -1594,27 +1588,6 @@ void pcnet_h_reset(void *opaque)
pcnet_poll_timer(s); 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) void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
{ {
PCNetState *s = opaque; PCNetState *s = opaque;
@ -1667,7 +1640,7 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
return val; 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; PCNetState *s = opaque;
pcnet_poll_timer(s); pcnet_poll_timer(s);
@ -1697,7 +1670,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
pcnet_update_irq(s); 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; PCNetState *s = opaque;
uint32_t val = -1; uint32_t val = -1;
@ -1726,125 +1699,6 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
return val; 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) static bool is_version_2(void *opaque, int version_id)
{ {
return version_id == 2; return version_id == 2;
@ -1874,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) void pcnet_common_cleanup(PCNetState *d)
{ {
d->nic = NULL; d->nic = NULL;
@ -1900,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); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
return 0; 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)

View file

@ -32,6 +32,9 @@ struct PCNetState_st {
void pcnet_h_reset(void *opaque); void pcnet_h_reset(void *opaque);
void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val); void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr); 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); int pcnet_can_receive(VLANClientState *nc);
ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_); ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_);
void pcnet_common_cleanup(PCNetState *d); void pcnet_common_cleanup(PCNetState *d);

View file

@ -316,7 +316,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
machine_arch = ARCH_MAC99; machine_arch = ARCH_MAC99;
} }
/* init basic PC hardware */ /* init basic PC hardware */
pci_vga_init(pci_bus, 0, 0); pci_vga_init(pci_bus);
escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24], escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);

View file

@ -227,7 +227,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
} }
pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs); pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
pci_bus = pci_grackle_init(0xfec00000, pic); pci_bus = pci_grackle_init(0xfec00000, pic);
pci_vga_init(pci_bus, 0, 0); pci_vga_init(pci_bus);
escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0], escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
serial_hds[1], ESCC_CLOCK, 4); serial_hds[1], ESCC_CLOCK, 4);

View file

@ -694,7 +694,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
/* init basic PC hardware */ /* init basic PC hardware */
pci_vga_init(pci_bus, 0, 0); pci_vga_init(pci_bus);
// openpic = openpic_init(0x00000000, 0xF0000000, 1); // openpic = openpic_init(0x00000000, 0xF0000000, 1);
// pit = pit_init(0x40, i8259[0]); // pit = pit_init(0x40, i8259[0]);
rtc_init(2000, NULL); rtc_init(2000, NULL);

View file

@ -108,7 +108,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
int res = 0, unit; int res = 0, unit;
loc_push_none(&loc); loc_push_none(&loc);
for (unit = 0; unit < MAX_SCSI_DEVS; unit++) { for (unit = 0; unit < bus->ndev; unit++) {
dinfo = drive_get(IF_SCSI, bus->busnr, unit); dinfo = drive_get(IF_SCSI, bus->busnr, unit);
if (dinfo == NULL) { if (dinfo == NULL) {
continue; continue;
@ -123,16 +123,6 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
return res; return res;
} }
void scsi_dev_clear_sense(SCSIDevice *dev)
{
memset(&dev->sense, 0, sizeof(dev->sense));
}
void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key)
{
dev->sense.key = key;
}
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun) SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun)
{ {
SCSIRequest *req; SCSIRequest *req;

View file

@ -111,18 +111,20 @@
#define BLANK 0xa1 #define BLANK 0xa1
/* /*
* Status codes * SAM Status codes
*/ */
#define GOOD 0x00 #define GOOD 0x00
#define CHECK_CONDITION 0x01 #define CHECK_CONDITION 0x02
#define CONDITION_GOOD 0x02 #define CONDITION_GOOD 0x04
#define BUSY 0x04 #define BUSY 0x08
#define INTERMEDIATE_GOOD 0x08 #define INTERMEDIATE_GOOD 0x10
#define INTERMEDIATE_C_GOOD 0x0a #define INTERMEDIATE_C_GOOD 0x14
#define RESERVATION_CONFLICT 0x0c #define RESERVATION_CONFLICT 0x18
#define COMMAND_TERMINATED 0x11 #define COMMAND_TERMINATED 0x22
#define QUEUE_FULL 0x14 #define TASK_SET_FULL 0x28
#define ACA_ACTIVE 0x30
#define TASK_ABORTED 0x40
#define STATUS_MASK 0x3e #define STATUS_MASK 0x3e

View file

@ -41,10 +41,18 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#define SCSI_DMA_BUF_SIZE 131072 #define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256 #define SCSI_MAX_INQUIRY_LEN 256
#define SCSI_REQ_STATUS_RETRY 0x01 #define SCSI_REQ_STATUS_RETRY 0x01
#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
#define SCSI_REQ_STATUS_RETRY_READ 0x00
#define SCSI_REQ_STATUS_RETRY_WRITE 0x02
#define SCSI_REQ_STATUS_RETRY_FLUSH 0x04
typedef struct SCSIDiskState SCSIDiskState; typedef struct SCSIDiskState SCSIDiskState;
typedef struct SCSISense {
uint8_t key;
} SCSISense;
typedef struct SCSIDiskReq { typedef struct SCSIDiskReq {
SCSIRequest req; SCSIRequest req;
/* ??? We should probably keep track of whether the data transfer is /* ??? We should probably keep track of whether the data transfer is
@ -68,8 +76,12 @@ struct SCSIDiskState
QEMUBH *bh; QEMUBH *bh;
char *version; char *version;
char *serial; char *serial;
SCSISense sense;
}; };
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag, static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
uint32_t lun) uint32_t lun)
{ {
@ -93,10 +105,22 @@ static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag)
return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag)); return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag));
} }
static void scsi_req_set_status(SCSIRequest *req, int status, int sense_code) static void scsi_disk_clear_sense(SCSIDiskState *s)
{ {
req->status = status; memset(&s->sense, 0, sizeof(s->sense));
scsi_dev_set_sense(req->dev, sense_code); }
static void scsi_disk_set_sense(SCSIDiskState *s, uint8_t key)
{
s->sense.key = key;
}
static void scsi_req_set_status(SCSIDiskReq *r, int status, int sense_code)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
r->req.status = status;
scsi_disk_set_sense(s, sense_code);
} }
/* Helper function for command completion. */ /* Helper function for command completion. */
@ -104,7 +128,7 @@ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense)
{ {
DPRINTF("Command complete tag=0x%x status=%d sense=%d\n", DPRINTF("Command complete tag=0x%x status=%d sense=%d\n",
r->req.tag, status, sense); r->req.tag, status, sense);
scsi_req_set_status(&r->req, status, sense); scsi_req_set_status(r, status, sense);
scsi_req_complete(&r->req); scsi_req_complete(&r->req);
scsi_remove_request(r); scsi_remove_request(r);
} }
@ -127,34 +151,30 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
static void scsi_read_complete(void * opaque, int ret) static void scsi_read_complete(void * opaque, int ret)
{ {
SCSIDiskReq *r = (SCSIDiskReq *)opaque; SCSIDiskReq *r = (SCSIDiskReq *)opaque;
int n;
r->req.aiocb = NULL; r->req.aiocb = NULL;
if (ret) { if (ret) {
DPRINTF("IO error\n"); if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); return;
scsi_command_complete(r, CHECK_CONDITION, NO_SENSE); }
return;
} }
DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len); DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
n = r->iov.iov_len / 512;
r->sector += n;
r->sector_count -= n;
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len); r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
} }
/* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIDevice *d, uint32_t tag) static void scsi_read_request(SCSIDiskReq *r)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
SCSIDiskReq *r;
uint32_t n; uint32_t n;
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad read tag 0x%x\n", tag);
/* ??? This is the wrong error. */
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
return;
}
if (r->sector_count == (uint32_t)-1) { if (r->sector_count == (uint32_t)-1) {
DPRINTF("Read buf_len=%zd\n", r->iov.iov_len); DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
r->sector_count = 0; r->sector_count = 0;
@ -167,6 +187,9 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
return; return;
} }
/* No data transfer may already be in progress */
assert(r->req.aiocb == NULL);
n = r->sector_count; n = r->sector_count;
if (n > SCSI_DMA_BUF_SIZE / 512) if (n > SCSI_DMA_BUF_SIZE / 512)
n = SCSI_DMA_BUF_SIZE / 512; n = SCSI_DMA_BUF_SIZE / 512;
@ -175,31 +198,54 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
qemu_iovec_init_external(&r->qiov, &r->iov, 1); qemu_iovec_init_external(&r->qiov, &r->iov, 1);
r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n, r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
scsi_read_complete, r); scsi_read_complete, r);
if (r->req.aiocb == NULL) if (r->req.aiocb == NULL) {
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); scsi_read_complete(r, -EIO);
r->sector += n; }
r->sector_count -= n;
} }
static int scsi_handle_write_error(SCSIDiskReq *r, int error) /* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIDiskReq *r;
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad read tag 0x%x\n", tag);
/* ??? This is the wrong error. */
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
return;
}
scsi_read_request(r);
}
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
{
int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
BlockErrorAction action = bdrv_get_on_error(s->bs, 0); BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
if (action == BLOCK_ERR_IGNORE) { if (action == BLOCK_ERR_IGNORE) {
bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, 0); bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
return 0; return 0;
} }
if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
|| action == BLOCK_ERR_STOP_ANY) { || action == BLOCK_ERR_STOP_ANY) {
r->status |= SCSI_REQ_STATUS_RETRY;
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0); type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
r->status |= SCSI_REQ_STATUS_RETRY | type;
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(0); vm_stop(0);
} else { } else {
if (type == SCSI_REQ_STATUS_RETRY_READ) {
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
}
scsi_command_complete(r, CHECK_CONDITION, scsi_command_complete(r, CHECK_CONDITION,
HARDWARE_ERROR); HARDWARE_ERROR);
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0); bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
} }
return 1; return 1;
@ -214,8 +260,9 @@ static void scsi_write_complete(void * opaque, int ret)
r->req.aiocb = NULL; r->req.aiocb = NULL;
if (ret) { if (ret) {
if (scsi_handle_write_error(r, -ret)) if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
return; return;
}
} }
n = r->iov.iov_len / 512; n = r->iov.iov_len / 512;
@ -239,14 +286,17 @@ static void scsi_write_request(SCSIDiskReq *r)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n; uint32_t n;
/* No data transfer may already be in progress */
assert(r->req.aiocb == NULL);
n = r->iov.iov_len / 512; n = r->iov.iov_len / 512;
if (n) { if (n) {
qemu_iovec_init_external(&r->qiov, &r->iov, 1); qemu_iovec_init_external(&r->qiov, &r->iov, 1);
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n, r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
scsi_write_complete, r); scsi_write_complete, r);
if (r->req.aiocb == NULL) if (r->req.aiocb == NULL) {
scsi_command_complete(r, CHECK_CONDITION, scsi_write_complete(r, -EIO);
HARDWARE_ERROR); }
} else { } else {
/* Invoke completion routine to fetch data from host. */ /* Invoke completion routine to fetch data from host. */
scsi_write_complete(r, 0); scsi_write_complete(r, 0);
@ -268,9 +318,6 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
return 1; return 1;
} }
if (r->req.aiocb)
BADF("Data transfer already in progress\n");
scsi_write_request(r); scsi_write_request(r);
return 0; return 0;
@ -288,8 +335,25 @@ static void scsi_dma_restart_bh(void *opaque)
QTAILQ_FOREACH(req, &s->qdev.requests, next) { QTAILQ_FOREACH(req, &s->qdev.requests, next) {
r = DO_UPCAST(SCSIDiskReq, req, req); r = DO_UPCAST(SCSIDiskReq, req, req);
if (r->status & SCSI_REQ_STATUS_RETRY) { if (r->status & SCSI_REQ_STATUS_RETRY) {
r->status &= ~SCSI_REQ_STATUS_RETRY; int status = r->status;
scsi_write_request(r); int ret;
r->status &=
~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
case SCSI_REQ_STATUS_RETRY_READ:
scsi_read_request(r);
break;
case SCSI_REQ_STATUS_RETRY_WRITE:
scsi_write_request(r);
break;
case SCSI_REQ_STATUS_RETRY_FLUSH:
ret = scsi_disk_emulate_command(r, r->iov.iov_base);
if (ret == 0) {
scsi_command_complete(r, GOOD, NO_SENSE);
}
}
} }
} }
} }
@ -351,15 +415,20 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
switch (page_code) { switch (page_code) {
case 0x00: /* Supported page codes, mandatory */ case 0x00: /* Supported page codes, mandatory */
{
int pages;
DPRINTF("Inquiry EVPD[Supported pages] " DPRINTF("Inquiry EVPD[Supported pages] "
"buffer size %zd\n", req->cmd.xfer); "buffer size %zd\n", req->cmd.xfer);
outbuf[buflen++] = 4; // number of pages pages = buflen++;
outbuf[buflen++] = 0x00; // list of supported pages (this page) outbuf[buflen++] = 0x00; // list of supported pages (this page)
outbuf[buflen++] = 0x80; // unit serial number outbuf[buflen++] = 0x80; // unit serial number
outbuf[buflen++] = 0x83; // device identification outbuf[buflen++] = 0x83; // device identification
outbuf[buflen++] = 0xb0; // block device characteristics if (bdrv_get_type_hint(s->bs) != BDRV_TYPE_CDROM) {
outbuf[buflen++] = 0xb0; // block device characteristics
}
outbuf[pages] = buflen - pages - 1; // number of pages
break; break;
}
case 0x80: /* Device serial number, optional */ case 0x80: /* Device serial number, optional */
{ {
int l = strlen(s->serial); int l = strlen(s->serial);
@ -387,7 +456,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
DPRINTF("Inquiry EVPD[Device identification] " DPRINTF("Inquiry EVPD[Device identification] "
"buffer size %zd\n", req->cmd.xfer); "buffer size %zd\n", req->cmd.xfer);
outbuf[buflen++] = 3 + id_len; outbuf[buflen++] = 4 + id_len;
outbuf[buflen++] = 0x2; // ASCII outbuf[buflen++] = 0x2; // ASCII
outbuf[buflen++] = 0; // not officially assigned outbuf[buflen++] = 0; // not officially assigned
outbuf[buflen++] = 0; // reserved outbuf[buflen++] = 0; // reserved
@ -404,6 +473,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
unsigned int opt_io_size = unsigned int opt_io_size =
s->qdev.conf.opt_io_size / s->qdev.blocksize; s->qdev.conf.opt_io_size / s->qdev.blocksize;
if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
page_code);
return -1;
}
/* required VPD size with unmap support */ /* required VPD size with unmap support */
outbuf[3] = buflen = 0x3c; outbuf[3] = buflen = 0x3c;
@ -747,11 +821,13 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
return toclen; return toclen;
} }
static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf) static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
{ {
SCSIRequest *req = &r->req;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
uint64_t nb_sectors; uint64_t nb_sectors;
int buflen = 0; int buflen = 0;
int ret;
switch (req->cmd.buf[0]) { switch (req->cmd.buf[0]) {
case TEST_UNIT_READY: case TEST_UNIT_READY:
@ -763,7 +839,7 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
goto illegal_request; goto illegal_request;
memset(outbuf, 0, 4); memset(outbuf, 0, 4);
buflen = 4; buflen = 4;
if (req->dev->sense.key == NOT_READY && req->cmd.xfer >= 18) { if (s->sense.key == NOT_READY && req->cmd.xfer >= 18) {
memset(outbuf, 0, 18); memset(outbuf, 0, 18);
buflen = 18; buflen = 18;
outbuf[7] = 10; outbuf[7] = 10;
@ -773,8 +849,8 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
} }
outbuf[0] = 0xf0; outbuf[0] = 0xf0;
outbuf[1] = 0; outbuf[1] = 0;
outbuf[2] = req->dev->sense.key; outbuf[2] = s->sense.key;
scsi_dev_clear_sense(req->dev); scsi_disk_clear_sense(s);
break; break;
case INQUIRY: case INQUIRY:
buflen = scsi_disk_emulate_inquiry(req, outbuf); buflen = scsi_disk_emulate_inquiry(req, outbuf);
@ -842,7 +918,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
buflen = 8; buflen = 8;
break; break;
case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE:
bdrv_flush(s->bs); ret = bdrv_flush(s->bs);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
return -1;
}
}
break; break;
case GET_CONFIGURATION: case GET_CONFIGURATION:
memset(outbuf, 0, 8); memset(outbuf, 0, 8);
@ -902,16 +983,16 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
default: default:
goto illegal_request; goto illegal_request;
} }
scsi_req_set_status(req, GOOD, NO_SENSE); scsi_req_set_status(r, GOOD, NO_SENSE);
return buflen; return buflen;
not_ready: not_ready:
scsi_req_set_status(req, CHECK_CONDITION, NOT_READY); scsi_command_complete(r, CHECK_CONDITION, NOT_READY);
return 0; return -1;
illegal_request: illegal_request:
scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST); scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
return 0; return -1;
} }
/* Execute a scsi command. Returns the length of the data expected by the /* Execute a scsi command. Returns the length of the data expected by the
@ -923,9 +1004,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
uint8_t *buf, int lun) uint8_t *buf, int lun)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
uint64_t lba;
uint32_t len; uint32_t len;
int cmdlen;
int is_write; int is_write;
uint8_t command; uint8_t command;
uint8_t *outbuf; uint8_t *outbuf;
@ -944,55 +1023,21 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
outbuf = (uint8_t *)r->iov.iov_base; outbuf = (uint8_t *)r->iov.iov_base;
is_write = 0; is_write = 0;
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
switch (command >> 5) {
case 0: if (scsi_req_parse(&r->req, buf) != 0) {
lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
(((uint64_t) buf[1] & 0x1f) << 16);
len = buf[4];
cmdlen = 6;
break;
case 1:
case 2:
lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
len = buf[8] | (buf[7] << 8);
cmdlen = 10;
break;
case 4:
lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
cmdlen = 16;
break;
case 5:
lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
cmdlen = 12;
break;
default:
BADF("Unsupported command length, command %x\n", command); BADF("Unsupported command length, command %x\n", command);
goto fail; goto fail;
} }
#ifdef DEBUG_SCSI #ifdef DEBUG_SCSI
{ {
int i; int i;
for (i = 1; i < cmdlen; i++) { for (i = 1; i < r->req.cmd.len; i++) {
printf(" 0x%02x", buf[i]); printf(" 0x%02x", buf[i]);
} }
printf("\n"); printf("\n");
} }
#endif #endif
if (scsi_req_parse(&r->req, buf) != 0) {
BADF("Unsupported command length, command %x\n", command);
goto fail;
}
assert(r->req.cmd.len == cmdlen);
assert(r->req.cmd.lba == lba);
if (lun || buf[1] >> 5) { if (lun || buf[1] >> 5) {
/* Only LUN 0 supported. */ /* Only LUN 0 supported. */
DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
@ -1019,23 +1064,22 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case REPORT_LUNS: case REPORT_LUNS:
case VERIFY: case VERIFY:
case REZERO_UNIT: case REZERO_UNIT:
rc = scsi_disk_emulate_command(&r->req, outbuf); rc = scsi_disk_emulate_command(r, outbuf);
if (rc > 0) { if (rc < 0) {
r->iov.iov_len = rc;
} else {
scsi_req_complete(&r->req);
scsi_remove_request(r);
return 0; return 0;
} }
r->iov.iov_len = rc;
break; break;
case READ_6: case READ_6:
case READ_10: case READ_10:
case READ_12: case READ_12:
case READ_16: case READ_16:
DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len); len = r->req.cmd.xfer / d->blocksize;
if (lba > s->max_lba) DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
if (r->req.cmd.lba > s->max_lba)
goto illegal_lba; goto illegal_lba;
r->sector = lba * s->cluster_size; r->sector = r->req.cmd.lba * s->cluster_size;
r->sector_count = len * s->cluster_size; r->sector_count = len * s->cluster_size;
break; break;
case WRITE_6: case WRITE_6:
@ -1045,42 +1089,45 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case WRITE_VERIFY: case WRITE_VERIFY:
case WRITE_VERIFY_12: case WRITE_VERIFY_12:
case WRITE_VERIFY_16: case WRITE_VERIFY_16:
len = r->req.cmd.xfer / d->blocksize;
DPRINTF("Write %s(sector %" PRId64 ", count %d)\n", DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
(command & 0xe) == 0xe ? "And Verify " : "", lba, len); (command & 0xe) == 0xe ? "And Verify " : "",
if (lba > s->max_lba) r->req.cmd.lba, len);
if (r->req.cmd.lba > s->max_lba)
goto illegal_lba; goto illegal_lba;
r->sector = lba * s->cluster_size; r->sector = r->req.cmd.lba * s->cluster_size;
r->sector_count = len * s->cluster_size; r->sector_count = len * s->cluster_size;
is_write = 1; is_write = 1;
break; break;
case MODE_SELECT: case MODE_SELECT:
DPRINTF("Mode Select(6) (len %d)\n", len); DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
/* We don't support mode parameter changes. /* We don't support mode parameter changes.
Allow the mode parameter header + block descriptors only. */ Allow the mode parameter header + block descriptors only. */
if (len > 12) { if (r->req.cmd.xfer > 12) {
goto fail; goto fail;
} }
break; break;
case MODE_SELECT_10: case MODE_SELECT_10:
DPRINTF("Mode Select(10) (len %d)\n", len); DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
/* We don't support mode parameter changes. /* We don't support mode parameter changes.
Allow the mode parameter header + block descriptors only. */ Allow the mode parameter header + block descriptors only. */
if (len > 16) { if (r->req.cmd.xfer > 16) {
goto fail; goto fail;
} }
break; break;
case SEEK_6: case SEEK_6:
case SEEK_10: case SEEK_10:
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, lba); DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
if (lba > s->max_lba) { r->req.cmd.lba);
if (r->req.cmd.lba > s->max_lba) {
goto illegal_lba; goto illegal_lba;
} }
break; break;
default: default:
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
fail: fail:
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST); scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
return 0; return 0;
illegal_lba: illegal_lba:
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
return 0; return 0;
@ -1152,11 +1199,6 @@ static int scsi_disk_initfn(SCSIDevice *dev)
return -1; return -1;
} }
if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
error_report("Device doesn't support drive option rerror");
return -1;
}
if (!s->serial) { if (!s->serial) {
/* try to fall back to value set with legacy -drive serial=... */ /* try to fall back to value set with legacy -drive serial=... */
dinfo = drive_get_by_blockdev(s->bs); dinfo = drive_get_by_blockdev(s->bs);

View file

@ -96,17 +96,17 @@ static void scsi_command_complete(void *opaque, int ret)
s->senselen = r->io_header.sb_len_wr; s->senselen = r->io_header.sb_len_wr;
if (ret != 0) if (ret != 0)
r->req.status = BUSY << 1; r->req.status = BUSY;
else { else {
if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) { if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
r->req.status = BUSY << 1; r->req.status = BUSY;
BADF("Driver Timeout\n"); BADF("Driver Timeout\n");
} else if (r->io_header.status) } else if (r->io_header.status)
r->req.status = r->io_header.status; r->req.status = r->io_header.status;
else if (s->driver_status & SG_ERR_DRIVER_SENSE) else if (s->driver_status & SG_ERR_DRIVER_SENSE)
r->req.status = CHECK_CONDITION << 1; r->req.status = CHECK_CONDITION;
else else
r->req.status = GOOD << 1; r->req.status = GOOD;
} }
DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
r, r->req.tag, r->req.status); r, r->req.tag, r->req.status);
@ -333,7 +333,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
s->senselen = 7; s->senselen = 7;
s->driver_status = SG_ERR_DRIVER_SENSE; s->driver_status = SG_ERR_DRIVER_SENSE;
bus = scsi_bus_from_device(d); bus = scsi_bus_from_device(d);
bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1); bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION);
return 0; return 0;
} }

View file

@ -3,6 +3,7 @@
#include "qdev.h" #include "qdev.h"
#include "block.h" #include "block.h"
#include "blockdev.h"
#include "block_int.h" #include "block_int.h"
#define SCSI_CMD_BUF_SIZE 16 #define SCSI_CMD_BUF_SIZE 16
@ -25,10 +26,6 @@ enum SCSIXferMode {
SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */
}; };
typedef struct SCSISense {
uint8_t key;
} SCSISense;
typedef struct SCSIRequest { typedef struct SCSIRequest {
SCSIBus *bus; SCSIBus *bus;
SCSIDevice *dev; SCSIDevice *dev;
@ -56,7 +53,6 @@ struct SCSIDevice
QTAILQ_HEAD(, SCSIRequest) requests; QTAILQ_HEAD(, SCSIRequest) requests;
int blocksize; int blocksize;
int type; int type;
struct SCSISense sense;
}; };
/* cdrom.c */ /* cdrom.c */
@ -86,7 +82,7 @@ struct SCSIBus {
int tcq, ndev; int tcq, ndev;
scsi_completionfn complete; scsi_completionfn complete;
SCSIDevice *devs[8]; SCSIDevice *devs[MAX_SCSI_DEVS];
}; };
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev, void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
@ -101,9 +97,6 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit); SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit);
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus); int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
void scsi_dev_clear_sense(SCSIDevice *dev);
void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key);
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag);
void scsi_req_free(SCSIRequest *req); void scsi_req_free(SCSIRequest *req);

View file

@ -767,7 +767,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2, pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
&pci_bus3); &pci_bus3);
isa_mem_base = APB_PCI_IO_BASE; isa_mem_base = APB_PCI_IO_BASE;
pci_vga_init(pci_bus, 0, 0); pci_vga_init(pci_bus);
// XXX Should be pci_bus3 // XXX Should be pci_bus3
pci_ebus_init(pci_bus, -1); pci_ebus_init(pci_bus, -1);

View file

@ -1142,7 +1142,7 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
break; break;
default: default:
if (usb_net_stringtable[value & 0xff]) { if (ARRAY_SIZE(usb_net_stringtable) > (value & 0xff)) {
ret = set_usb_string(data, ret = set_usb_string(data,
usb_net_stringtable[value & 0xff]); usb_net_stringtable[value & 0xff]);
break; break;

View file

@ -52,14 +52,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
{ {
PCIVGAState *d = (PCIVGAState *)pci_dev; PCIVGAState *d = (PCIVGAState *)pci_dev;
VGACommonState *s = &d->vga; VGACommonState *s = &d->vga;
if (region_num == PCI_ROM_SLOT) {
cpu_register_physical_memory(addr, s->bios_size, s->bios_offset); cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
} else { s->map_addr = addr;
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); s->map_end = addr + s->vram_size;
s->map_addr = addr; vga_dirty_log_start(s);
s->map_end = addr + s->vram_size;
vga_dirty_log_start(s);
}
} }
static void pci_vga_write_config(PCIDevice *d, static void pci_vga_write_config(PCIDevice *d,
@ -95,32 +92,17 @@ static int pci_vga_initfn(PCIDevice *dev)
pci_register_bar(&d->dev, 0, VGA_RAM_SIZE, pci_register_bar(&d->dev, 0, VGA_RAM_SIZE,
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map); PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
if (s->bios_size) { if (!dev->rom_bar) {
unsigned int bios_total_size; /* compatibility with pc-0.13 and older */
/* must be a power of two */ vga_init_vbe(s);
bios_total_size = 1;
while (bios_total_size < s->bios_size)
bios_total_size <<= 1;
pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size,
PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map);
} }
vga_init_vbe(s);
/* ROM BIOS */
rom_add_vga(VGABIOS_FILENAME);
return 0; return 0;
} }
int pci_vga_init(PCIBus *bus, int pci_vga_init(PCIBus *bus)
unsigned long vga_bios_offset, int vga_bios_size)
{ {
PCIDevice *dev; pci_create_simple(bus, -1, "VGA");
dev = pci_create(bus, -1, "VGA");
qdev_prop_set_uint32(&dev->qdev, "bios-offset", vga_bios_offset);
qdev_prop_set_uint32(&dev->qdev, "bios-size", vga_bios_size);
qdev_init_nofail(&dev->qdev);
return 0; return 0;
} }
@ -130,11 +112,7 @@ static PCIDeviceInfo vga_info = {
.qdev.vmsd = &vmstate_vga_pci, .qdev.vmsd = &vmstate_vga_pci,
.init = pci_vga_initfn, .init = pci_vga_initfn,
.config_write = pci_vga_write_config, .config_write = pci_vga_write_config,
.qdev.props = (Property[]) { .romfile = "vgabios-stdvga.bin",
DEFINE_PROP_HEX32("bios-offset", PCIVGAState, vga.bios_offset, 0),
DEFINE_PROP_HEX32("bios-size", PCIVGAState, vga.bios_size, 0),
DEFINE_PROP_END_OF_LIST(),
}
}; };
static void vga_register(void) static void vga_register(void)

View file

@ -1934,8 +1934,6 @@ void vga_common_reset(VGACommonState *s)
s->map_addr = 0; s->map_addr = 0;
s->map_end = 0; s->map_end = 0;
s->lfb_vram_mapped = 0; s->lfb_vram_mapped = 0;
s->bios_offset = 0;
s->bios_size = 0;
s->sr_index = 0; s->sr_index = 0;
memset(s->sr, '\0', sizeof(s->sr)); memset(s->sr, '\0', sizeof(s->sr));
s->gr_index = 0; s->gr_index = 0;

View file

@ -112,8 +112,6 @@ typedef struct VGACommonState {
uint32_t map_addr; uint32_t map_addr;
uint32_t map_end; uint32_t map_end;
uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */ uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
uint32_t bios_offset;
uint32_t bios_size;
uint32_t latch; uint32_t latch;
uint8_t sr_index; uint8_t sr_index;
uint8_t sr[256]; uint8_t sr[256];

View file

@ -273,7 +273,7 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req); acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
if (!acb) { if (!acb) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); virtio_blk_flush_complete(req, -EIO);
} }
} }
@ -324,13 +324,13 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
MultiReqBuffer *mrb) MultiReqBuffer *mrb)
{ {
if (req->elem.out_num < 1 || req->elem.in_num < 1) { if (req->elem.out_num < 1 || req->elem.in_num < 1) {
fprintf(stderr, "virtio-blk missing headers\n"); error_report("virtio-blk missing headers");
exit(1); exit(1);
} }
if (req->elem.out_sg[0].iov_len < sizeof(*req->out) || if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) { req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
fprintf(stderr, "virtio-blk header not in correct element\n"); error_report("virtio-blk header not in correct element");
exit(1); exit(1);
} }

View file

@ -120,8 +120,8 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
if (!n->vhost_started) { if (!n->vhost_started) {
int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev); int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
if (r < 0) { if (r < 0) {
fprintf(stderr, "unable to start vhost net: %d: " error_report("unable to start vhost net: %d: "
"falling back on userspace virtio\n", -r); "falling back on userspace virtio", -r);
} else { } else {
n->vhost_started = 1; n->vhost_started = 1;
} }
@ -271,7 +271,7 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
uint8_t on; uint8_t on;
if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) { if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) {
fprintf(stderr, "virtio-net ctrl invalid rx mode command\n"); error_report("virtio-net ctrl invalid rx mode command");
exit(1); exit(1);
} }
@ -353,7 +353,7 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
uint16_t vid; uint16_t vid;
if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(vid)) { if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(vid)) {
fprintf(stderr, "virtio-net ctrl invalid vlan command\n"); error_report("virtio-net ctrl invalid vlan command");
return VIRTIO_NET_ERR; return VIRTIO_NET_ERR;
} }
@ -381,13 +381,13 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
while (virtqueue_pop(vq, &elem)) { while (virtqueue_pop(vq, &elem)) {
if ((elem.in_num < 1) || (elem.out_num < 1)) { if ((elem.in_num < 1) || (elem.out_num < 1)) {
fprintf(stderr, "virtio-net ctrl missing headers\n"); error_report("virtio-net ctrl missing headers");
exit(1); exit(1);
} }
if (elem.out_sg[0].iov_len < sizeof(ctrl) || if (elem.out_sg[0].iov_len < sizeof(ctrl) ||
elem.in_sg[elem.in_num - 1].iov_len < sizeof(status)) { elem.in_sg[elem.in_num - 1].iov_len < sizeof(status)) {
fprintf(stderr, "virtio-net ctrl header not in correct element\n"); error_report("virtio-net ctrl header not in correct element");
exit(1); exit(1);
} }
@ -591,21 +591,21 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
if (virtqueue_pop(n->rx_vq, &elem) == 0) { if (virtqueue_pop(n->rx_vq, &elem) == 0) {
if (i == 0) if (i == 0)
return -1; return -1;
fprintf(stderr, "virtio-net unexpected empty queue: " error_report("virtio-net unexpected empty queue: "
"i %zd mergeable %d offset %zd, size %zd, " "i %zd mergeable %d offset %zd, size %zd, "
"guest hdr len %zd, host hdr len %zd guest features 0x%x\n", "guest hdr len %zd, host hdr len %zd guest features 0x%x",
i, n->mergeable_rx_bufs, offset, size, i, n->mergeable_rx_bufs, offset, size,
guest_hdr_len, host_hdr_len, n->vdev.guest_features); guest_hdr_len, host_hdr_len, n->vdev.guest_features);
exit(1); exit(1);
} }
if (elem.in_num < 1) { if (elem.in_num < 1) {
fprintf(stderr, "virtio-net receive queue contains no in buffers\n"); error_report("virtio-net receive queue contains no in buffers");
exit(1); exit(1);
} }
if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) { if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != guest_hdr_len) {
fprintf(stderr, "virtio-net header not in first element\n"); error_report("virtio-net header not in first element");
exit(1); exit(1);
} }
@ -630,12 +630,11 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
* Otherwise, drop it. */ * Otherwise, drop it. */
if (!n->mergeable_rx_bufs && offset < size) { if (!n->mergeable_rx_bufs && offset < size) {
#if 0 #if 0
fprintf(stderr, "virtio-net truncated non-mergeable packet: " error_report("virtio-net truncated non-mergeable packet: "
"i %zd mergeable %d offset %zd, size %zd, "
"i %zd mergeable %d offset %zd, size %zd, " "guest hdr len %zd, host hdr len %zd",
"guest hdr len %zd, host hdr len %zd\n", i, n->mergeable_rx_bufs,
i, n->mergeable_rx_bufs, offset, size, guest_hdr_len, host_hdr_len);
offset, size, guest_hdr_len, host_hdr_len);
#endif #endif
return size; return size;
} }
@ -695,7 +694,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
sizeof(struct virtio_net_hdr); sizeof(struct virtio_net_hdr);
if (out_num < 1 || out_sg->iov_len != hdr_len) { if (out_num < 1 || out_sg->iov_len != hdr_len) {
fprintf(stderr, "virtio-net header not in first element\n"); error_report("virtio-net header not in first element");
exit(1); exit(1);
} }
@ -981,10 +980,10 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) { if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
fprintf(stderr, "virtio-net: " error_report("virtio-net: "
"Unknown option tx=%s, valid options: \"timer\" \"bh\"\n", "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
net->tx); net->tx);
fprintf(stderr, "Defaulting to \"bh\"\n"); error_report("Defaulting to \"bh\"");
} }
if (net->tx && !strcmp(net->tx, "timer")) { if (net->tx && !strcmp(net->tx, "timer")) {

View file

@ -254,8 +254,8 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
virtio_queue_set_vector(vdev, vdev->queue_sel, val); virtio_queue_set_vector(vdev, vdev->queue_sel, val);
break; break;
default: default:
fprintf(stderr, "%s: unexpected address 0x%x value 0x%x\n", error_report("%s: unexpected address 0x%x value 0x%x",
__func__, addr, val); __func__, addr, val);
break; break;
} }
} }
@ -684,12 +684,14 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev)
VirtIODevice *vdev; VirtIODevice *vdev;
vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf); vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
vdev->nvectors = proxy->nvectors;
virtio_init_pci(proxy, vdev, virtio_init_pci(proxy, vdev,
PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_VENDOR_ID_REDHAT_QUMRANET,
0x1009, 0x1009,
0x2, 0x2,
0x00); 0x00);
/* make the actual value visible */
proxy->nvectors = vdev->nvectors;
return 0; return 0;
} }
#endif #endif
@ -758,6 +760,7 @@ static PCIDeviceInfo virtio_info[] = {
.qdev.size = sizeof(VirtIOPCIProxy), .qdev.size = sizeof(VirtIOPCIProxy),
.init = virtio_9p_init_pci, .init = virtio_9p_init_pci,
.qdev.props = (Property[]) { .qdev.props = (Property[]) {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),

View file

@ -114,14 +114,12 @@ struct pci_vmsvga_state_s {
# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
# define SVGA_IO_MUL 1 # define SVGA_IO_MUL 1
# define SVGA_FIFO_SIZE 0x10000 # define SVGA_FIFO_SIZE 0x10000
# define SVGA_MEM_BASE 0xe0000000
# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2 # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2
#else #else
# define SVGA_ID SVGA_ID_1 # define SVGA_ID SVGA_ID_1
# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
# define SVGA_IO_MUL 4 # define SVGA_IO_MUL 4
# define SVGA_FIFO_SIZE 0x10000 # define SVGA_FIFO_SIZE 0x10000
# define SVGA_MEM_BASE 0xe0000000
# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA
#endif #endif
@ -1219,10 +1217,6 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
vga_init(&s->vga); vga_init(&s->vga);
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
vga_init_vbe(&s->vga);
rom_add_vga(VGABIOS_FILENAME);
vmsvga_reset(s); vmsvga_reset(s);
} }
@ -1307,6 +1301,11 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
vmsvga_init(&s->chip, VGA_RAM_SIZE); vmsvga_init(&s->chip, VGA_RAM_SIZE);
if (!dev->rom_bar) {
/* compatibility with pc-0.13 and older */
vga_init_vbe(&s->chip.vga);
}
return 0; return 0;
} }
@ -1320,6 +1319,7 @@ static PCIDeviceInfo vmsvga_info = {
.qdev.size = sizeof(struct pci_vmsvga_state_s), .qdev.size = sizeof(struct pci_vmsvga_state_s),
.qdev.vmsd = &vmstate_vmware_vga, .qdev.vmsd = &vmstate_vmware_vga,
.init = pci_vmsvga_initfn, .init = pci_vmsvga_initfn,
.romfile = "vgabios-vmware.bin",
}; };
static void vmsvga_register(void) static void vmsvga_register(void)

View file

@ -181,6 +181,10 @@ static int ioreq_parse(struct ioreq *ioreq)
ioreq->prot = PROT_WRITE; /* to memory */ ioreq->prot = PROT_WRITE; /* to memory */
break; break;
case BLKIF_OP_WRITE_BARRIER: case BLKIF_OP_WRITE_BARRIER:
if (!ioreq->req.nr_segments) {
ioreq->presync = 1;
return 0;
}
if (!syncwrite) if (!syncwrite)
ioreq->presync = ioreq->postsync = 1; ioreq->presync = ioreq->postsync = 1;
/* fall through */ /* fall through */
@ -305,7 +309,7 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
int i, rc, len = 0; int i, rc, len = 0;
off_t pos; off_t pos;
if (ioreq_map(ioreq) == -1) if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
goto err; goto err;
if (ioreq->presync) if (ioreq->presync)
bdrv_flush(blkdev->bs); bdrv_flush(blkdev->bs);
@ -329,6 +333,8 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
break; break;
case BLKIF_OP_WRITE: case BLKIF_OP_WRITE:
case BLKIF_OP_WRITE_BARRIER: case BLKIF_OP_WRITE_BARRIER:
if (!ioreq->req.nr_segments)
break;
pos = ioreq->start; pos = ioreq->start;
for (i = 0; i < ioreq->v.niov; i++) { for (i = 0; i < ioreq->v.niov; i++) {
rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE, rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE,
@ -386,7 +392,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
{ {
struct XenBlkDev *blkdev = ioreq->blkdev; struct XenBlkDev *blkdev = ioreq->blkdev;
if (ioreq_map(ioreq) == -1) if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
goto err; goto err;
ioreq->aio_inflight++; ioreq->aio_inflight++;
@ -403,6 +409,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
case BLKIF_OP_WRITE: case BLKIF_OP_WRITE:
case BLKIF_OP_WRITE_BARRIER: case BLKIF_OP_WRITE_BARRIER:
ioreq->aio_inflight++; ioreq->aio_inflight++;
if (!ioreq->req.nr_segments)
break;
bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE, bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
&ioreq->v, ioreq->v.size / BLOCK_SIZE, &ioreq->v, ioreq->v.size / BLOCK_SIZE,
qemu_aio_complete, ioreq); qemu_aio_complete, ioreq);

View file

@ -174,6 +174,70 @@ int register_ioport_write(pio_addr_t start, int length, int size,
return 0; return 0;
} }
static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
{
IORange *ioport = opaque;
uint64_t data;
ioport->ops->read(ioport, addr - ioport->base, 1, &data);
return data;
}
static uint32_t ioport_readw_thunk(void *opaque, uint32_t addr)
{
IORange *ioport = opaque;
uint64_t data;
ioport->ops->read(ioport, addr - ioport->base, 2, &data);
return data;
}
static uint32_t ioport_readl_thunk(void *opaque, uint32_t addr)
{
IORange *ioport = opaque;
uint64_t data;
ioport->ops->read(ioport, addr - ioport->base, 4, &data);
return data;
}
static void ioport_writeb_thunk(void *opaque, uint32_t addr, uint32_t data)
{
IORange *ioport = opaque;
ioport->ops->write(ioport, addr - ioport->base, 1, data);
}
static void ioport_writew_thunk(void *opaque, uint32_t addr, uint32_t data)
{
IORange *ioport = opaque;
ioport->ops->write(ioport, addr - ioport->base, 2, data);
}
static void ioport_writel_thunk(void *opaque, uint32_t addr, uint32_t data)
{
IORange *ioport = opaque;
ioport->ops->write(ioport, addr - ioport->base, 4, data);
}
void ioport_register(IORange *ioport)
{
register_ioport_read(ioport->base, ioport->len, 1,
ioport_readb_thunk, ioport);
register_ioport_read(ioport->base, ioport->len, 2,
ioport_readw_thunk, ioport);
register_ioport_read(ioport->base, ioport->len, 4,
ioport_readl_thunk, ioport);
register_ioport_write(ioport->base, ioport->len, 1,
ioport_writeb_thunk, ioport);
register_ioport_write(ioport->base, ioport->len, 2,
ioport_writew_thunk, ioport);
register_ioport_write(ioport->base, ioport->len, 4,
ioport_writel_thunk, ioport);
}
void isa_unassign_ioport(pio_addr_t start, int length) void isa_unassign_ioport(pio_addr_t start, int length)
{ {
int i; int i;

View file

@ -25,6 +25,7 @@
#define IOPORT_H #define IOPORT_H
#include "qemu-common.h" #include "qemu-common.h"
#include "iorange.h"
typedef uint32_t pio_addr_t; typedef uint32_t pio_addr_t;
#define FMT_pioaddr PRIx32 #define FMT_pioaddr PRIx32
@ -36,6 +37,7 @@ typedef uint32_t pio_addr_t;
typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data); typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address); typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
void ioport_register(IORange *iorange);
int register_ioport_read(pio_addr_t start, int length, int size, int register_ioport_read(pio_addr_t start, int length, int size,
IOPortReadFunc *func, void *opaque); IOPortReadFunc *func, void *opaque);
int register_ioport_write(pio_addr_t start, int length, int size, int register_ioport_write(pio_addr_t start, int length, int size,

30
iorange.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef IORANGE_H
#define IORANGE_H
#include <stdint.h>
typedef struct IORange IORange;
typedef struct IORangeOps IORangeOps;
struct IORangeOps {
void (*read)(IORange *iorange, uint64_t offset, unsigned width,
uint64_t *data);
void (*write)(IORange *iorange, uint64_t offset, unsigned width,
uint64_t data);
};
struct IORange {
const IORangeOps *ops;
uint64_t base;
uint64_t len;
};
static inline void iorange_init(IORange *iorange, const IORangeOps *ops,
uint64_t base, uint64_t len)
{
iorange->ops = ops;
iorange->base = base;
iorange->len = len;
}
#endif

View file

@ -3071,11 +3071,11 @@ struct target_stack_t {
}; };
struct target_ucontext { struct target_ucontext {
abi_ulong uc_flags; abi_ulong tuc_flags;
abi_ulong uc_link; abi_ulong tuc_link;
struct target_stack_t uc_stack; struct target_stack_t tuc_stack;
struct target_sigcontext sc; struct target_sigcontext tuc_mcontext;
uint32_t extramask[TARGET_NSIG_WORDS - 1]; uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
}; };
/* Signal frames. */ /* Signal frames. */
@ -3189,7 +3189,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
goto badframe; goto badframe;
/* Save the mask. */ /* Save the mask. */
err |= __put_user(set->sig[0], &frame->uc.sc.oldmask); err |= __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
if (err) if (err)
goto badframe; goto badframe;
@ -3198,7 +3198,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
goto badframe; goto badframe;
} }
setup_sigcontext(&frame->uc.sc, env); setup_sigcontext(&frame->uc.tuc_mcontext, env);
/* Set up to return from userspace. If provided, use a stub /* Set up to return from userspace. If provided, use a stub
already in userspace. */ already in userspace. */
@ -3261,7 +3261,7 @@ long do_sigreturn(CPUState *env)
goto badframe; goto badframe;
/* Restore blocked signals */ /* Restore blocked signals */
if (__get_user(target_set.sig[0], &frame->uc.sc.oldmask)) if (__get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask))
goto badframe; goto badframe;
for(i = 1; i < TARGET_NSIG_WORDS; i++) { for(i = 1; i < TARGET_NSIG_WORDS; i++) {
if (__get_user(target_set.sig[i], &frame->extramask[i - 1])) if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
@ -3270,7 +3270,7 @@ long do_sigreturn(CPUState *env)
target_to_host_sigset_internal(&set, &target_set); target_to_host_sigset_internal(&set, &target_set);
sigprocmask(SIG_SETMASK, &set, NULL); sigprocmask(SIG_SETMASK, &set, NULL);
restore_sigcontext(&frame->uc.sc, env); restore_sigcontext(&frame->uc.tuc_mcontext, env);
/* We got here through a sigreturn syscall, our path back is via an /* We got here through a sigreturn syscall, our path back is via an
rtb insn so setup r14 for that. */ rtb insn so setup r14 for that. */
env->regs[14] = env->sregs[SR_PC]; env->regs[14] = env->sregs[SR_PC];

28
make_device_config.sh Normal file
View file

@ -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

View file

@ -491,6 +491,44 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params,
return 0; 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) static int compare_cmd(const char *name, const char *list)
{ {
const char *p, *pstart; const char *p, *pstart;

View file

@ -31,14 +31,13 @@ x=`dd if="$1" bs=1 count=1 skip=2 2>/dev/null | od -t u1 -A n`
size=$(( $x * 512 - 1 )) size=$(( $x * 512 - 1 ))
# now get the checksum # now get the checksum
nums=`od -A n -t u1 -v "$1"` nums=`od -A n -t u1 -v -N $size "$1"`
for i in ${nums}; do for i in ${nums}; do
# add each byte's value to sum # add each byte's value to sum
sum=`expr $sum + $i` sum=`expr \( $sum + $i \) % 256`
done done
sum=$(( $sum % 256 )) sum=$(( (256 - $sum) % 256 ))
sum=$(( 256 - $sum ))
sum_octal=$( printf "%o" $sum ) sum_octal=$( printf "%o" $sum )
# and write the output file # and write the output file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more