mirror of https://github.com/xqemu/xqemu.git
Merge remote branch 'origin/master' into pci
Conflicts: Makefile.objs hw/virtio.c
This commit is contained in:
commit
c924f36a30
|
@ -4,6 +4,8 @@ config-host.*
|
|||
config-target.*
|
||||
trace.h
|
||||
trace.c
|
||||
trace-dtrace.h
|
||||
trace-dtrace.dtrace
|
||||
*-timestamp
|
||||
*-softmmu
|
||||
*-darwin-user
|
||||
|
|
490
MAINTAINERS
490
MAINTAINERS
|
@ -1,88 +1,428 @@
|
|||
QEMU Maintainers
|
||||
================
|
||||
|
||||
Project leaders:
|
||||
----------------
|
||||
The intention of this file is not to establish who owns what portions of the
|
||||
code base, but to provide a set of names that developers can consult when they
|
||||
have a question about a particular subset and also to provide a set of names
|
||||
to be CC'd when submitting a patch to obtain appropriate review.
|
||||
|
||||
Fabrice Bellard
|
||||
Paul Brook
|
||||
In general, if you have a question about inclusion of a patch, you should
|
||||
consult qemu-devel and not any specific individual privately.
|
||||
|
||||
CPU cores:
|
||||
----------
|
||||
Descriptions of section entries:
|
||||
|
||||
x86 Fabrice Bellard
|
||||
ARM Paul Brook
|
||||
SPARC Blue Swirl
|
||||
MIPS ?
|
||||
PowerPC Alexander Graf
|
||||
M68K Paul Brook
|
||||
SH4 ?
|
||||
CRIS Edgar E. Iglesias
|
||||
Alpha ?
|
||||
MicroBlaze Edgar E. Iglesias
|
||||
S390 ?
|
||||
M: Mail patches to: FullName <address@domain>
|
||||
L: Mailing list that is relevant to this area
|
||||
W: Web-page with status/info
|
||||
Q: Patchwork web based patch tracking system site
|
||||
T: SCM tree type and location. Type is one of: git, hg, quilt, stgit.
|
||||
S: Status, one of the following:
|
||||
Supported: Someone is actually paid to look after this.
|
||||
Maintained: Someone actually looks after it.
|
||||
Odd Fixes: It has a maintainer but they don't have time to do
|
||||
much other than throw the odd patch in. See below..
|
||||
Orphan: No current maintainer [but maybe you could take the
|
||||
role as you write your new code].
|
||||
Obsolete: Old code. Something tagged obsolete generally means
|
||||
it has been replaced by a better system and you
|
||||
should be using that.
|
||||
F: Files and directories with wildcard patterns.
|
||||
A trailing slash includes all files and subdirectory files.
|
||||
F: drivers/net/ all files in and below drivers/net
|
||||
F: drivers/net/* all files in drivers/net, but not below
|
||||
F: */net/* all files in "any top level directory"/net
|
||||
One pattern per line. Multiple F: lines acceptable.
|
||||
X: Files and directories that are NOT maintained, same rules as F:
|
||||
Files exclusions are tested before file matches.
|
||||
Can be useful for excluding a specific subdirectory, for instance:
|
||||
F: net/
|
||||
X: net/ipv6/
|
||||
matches all files in and below net excluding net/ipv6/
|
||||
K: Keyword perl extended regex pattern to match content in a
|
||||
patch or file. For instance:
|
||||
K: of_get_profile
|
||||
matches patches or files that contain "of_get_profile"
|
||||
K: \b(printk|pr_(info|err))\b
|
||||
matches patches or files that contain one or more of the words
|
||||
printk, pr_info or pr_err
|
||||
One regex pattern per line. Multiple K: lines acceptable.
|
||||
|
||||
Machines (sorted by CPU):
|
||||
-------------------------
|
||||
|
||||
x86
|
||||
pc.c Fabrice Bellard (new maintainer needed)
|
||||
ARM
|
||||
integratorcp.c Paul Brook
|
||||
versatilepb.c Paul Brook
|
||||
Real View Paul Brook
|
||||
spitz.c Andrzej Zaborowski
|
||||
palm.c Andrzej Zaborowski
|
||||
nseries.c Andrzej Zaborowski
|
||||
stellaris.c Paul Brook
|
||||
gumstix.c Thorsten Zitterell
|
||||
mainstone.c Armin Kuster
|
||||
musicpal.c Jan Kiszka
|
||||
SPARC
|
||||
sun4u.c Blue Swirl
|
||||
sun4m.c Blue Swirl
|
||||
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
|
||||
General Project Administration
|
||||
------------------------------
|
||||
M: Anthony Liguori <aliguori@us.ibm.com>
|
||||
M: Paul Brook <paul@codesourcery.com>
|
||||
|
||||
Guest CPU cores (TCG):
|
||||
----------------------
|
||||
Alpha
|
||||
M: qemu-devel@nongnu.org
|
||||
S: Orphan
|
||||
F: target-alpha/
|
||||
|
||||
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
|
||||
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-*.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
|
||||
Main loop Fabrice Bellard (new maintainer needed)
|
||||
TCG Fabrice Bellard
|
||||
IDE device ?
|
||||
SCSI device Paul Brook
|
||||
PCI layer Michael S. Tsirkin
|
||||
USB layer ?
|
||||
Block layer ?
|
||||
Graphic layer ?
|
||||
Audio device layer Vassili Karpov (malc)
|
||||
Character device layer ?
|
||||
Network device layer ?
|
||||
GDB stub ?
|
||||
Linux user ?
|
||||
Darwin user ?
|
||||
SLIRP ?
|
||||
SPARC
|
||||
M: Blue Swirl <blauwirbel@gmail.com>
|
||||
S: Maintained
|
||||
F: target-sparc/
|
||||
|
||||
X86
|
||||
M: qemu-devel@nongnu.org
|
||||
S: Odd Fixes
|
||||
F: target-i386/
|
||||
|
||||
Guest CPU Cores (KVM):
|
||||
----------------------
|
||||
|
||||
Overall
|
||||
M: Avi Kivity <avi@redhat.com>
|
||||
M: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
S: Supported
|
||||
F: kvm-*
|
||||
F: */kvm.*
|
||||
|
||||
PPC
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: target-ppc/kvm.c
|
||||
|
||||
S390
|
||||
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/
|
||||
|
|
55
Makefile
55
Makefile
|
@ -1,6 +1,9 @@
|
|||
# Makefile for QEMU.
|
||||
|
||||
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),)
|
||||
# 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_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
|
||||
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS))
|
||||
|
||||
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
|
||||
$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@")
|
||||
|
||||
-include $(SUBDIR_DEVICES_MAK_DEP)
|
||||
|
||||
%/config-devices.mak: default-configs/%.mak
|
||||
$(call quiet-command,cat $< > $@.tmp, " GEN $@")
|
||||
$(call quiet-command,$(SHELL) $(SRC_PATH)/make_device_config.sh $@ $<, " GEN $@")
|
||||
@if test -f $@; then \
|
||||
if cmp -s $@.old $@; then \
|
||||
if ! cmp -s $@ $@.tmp; then \
|
||||
mv $@.tmp $@; \
|
||||
cp -p $@ $@.old; \
|
||||
fi; \
|
||||
mv $@.tmp $@; \
|
||||
cp -p $@ $@.old; \
|
||||
else \
|
||||
if test -f $@.old; then \
|
||||
echo "WARNING: $@ (user modified) out of date.";\
|
||||
|
@ -108,7 +112,11 @@ ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_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
|
||||
endif
|
||||
trace.h-timestamp: $(SRC_PATH)/trace-events config-host.mak
|
||||
$(call quiet-command,sh $(SRC_PATH)/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN 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-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)
|
||||
|
||||
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-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
|
||||
|
||||
|
@ -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: check-qint.o qint.o qemu-malloc.o $(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-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o $(trace-obj-y)
|
||||
check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o $(trace-obj-y)
|
||||
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_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y)
|
||||
|
||||
check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
|
||||
check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
|
||||
check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
|
||||
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:
|
||||
# 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 qemu-img-cmds.h
|
||||
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
|
||||
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
|
||||
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
|
||||
|
||||
ifdef INSTALL_BLOBS
|
||||
BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
|
||||
openbios-sparc32 openbios-sparc64 openbios-ppc \
|
||||
BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \
|
||||
vgabios-stdvga.bin vgabios-vmware.bin \
|
||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
|
||||
gpxe-eepro100-80861209.rom \
|
||||
pxe-e1000.bin \
|
||||
pxe-ne2k_pci.bin pxe-pcnet.bin \
|
||||
|
|
|
@ -42,6 +42,11 @@ net-nested-$(CONFIG_SLIRP) += slirp.o
|
|||
net-nested-$(CONFIG_VDE) += vde.o
|
||||
net-obj-y += $(addprefix net/, $(net-nested-y))
|
||||
|
||||
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy)
|
||||
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
||||
# only pull in the actual virtio-9p device if we also enabled virtio.
|
||||
CONFIG_REALLY_VIRTFS=y
|
||||
endif
|
||||
fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
|
||||
fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
|
||||
|
||||
|
@ -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-$(CONFIG_SDL) += sdlaudio.o
|
||||
audio-obj-$(CONFIG_OSS) += ossaudio.o
|
||||
audio-obj-$(CONFIG_SPICE) += spiceaudio.o
|
||||
audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o
|
||||
audio-obj-$(CONFIG_ALSA) += alsaaudio.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 += vl.o loader.o
|
||||
hw-obj-y += virtio.o virtio-console.o
|
||||
hw-obj-y += fw_cfg.o pci.o pci_host.o pcie_host.o pci_bridge.o
|
||||
hw-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
|
||||
hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
|
||||
hw-obj-y += fw_cfg.o
|
||||
# FIXME: Core PCI code and its direct dependencies are required by the
|
||||
# QMP query-pci command.
|
||||
hw-obj-y += pci.o pci_bridge.o msix.o msi.o
|
||||
hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
|
||||
hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
|
||||
hw-obj-y += watchdog.o
|
||||
hw-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
|
||||
hw-obj-$(CONFIG_ECC) += ecc.o
|
||||
|
@ -205,15 +215,16 @@ hw-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
|
|||
hw-obj-$(CONFIG_PIIX4) += piix4.o
|
||||
|
||||
# PCI watchdog devices
|
||||
hw-obj-y += wdt_i6300esb.o
|
||||
hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
|
||||
|
||||
hw-obj-y += pcie.o pcie_aer.o pcie_port.o
|
||||
hw-obj-y += msix.o msi.o
|
||||
hw-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
|
||||
hw-obj-$(CONFIG_PCI) += msix.o msi.o
|
||||
|
||||
# PCI network cards
|
||||
hw-obj-y += ne2000.o
|
||||
hw-obj-y += eepro100.o
|
||||
hw-obj-y += pcnet.o
|
||||
hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
|
||||
hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
|
||||
hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
|
||||
hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
|
||||
|
||||
hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
|
||||
hw-obj-$(CONFIG_LAN9118) += lan9118.o
|
||||
|
@ -230,7 +241,7 @@ hw-obj-$(CONFIG_IDE_MACIO) += ide/macio.o
|
|||
hw-obj-$(CONFIG_IDE_VIA) += ide/via.o
|
||||
|
||||
# SCSI layer
|
||||
hw-obj-y += lsi53c895a.o
|
||||
hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
|
||||
hw-obj-$(CONFIG_ESP) += esp.o
|
||||
|
||||
hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
|
||||
|
@ -260,7 +271,8 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
|
|||
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
|
||||
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
|
||||
|
||||
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-debug.o virtio-9p-local.o virtio-9p-xattr.o
|
||||
hw-obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p-debug.o
|
||||
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
|
||||
hw-obj-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
|
||||
|
||||
######################################################################
|
||||
|
@ -285,11 +297,15 @@ libdis-$(CONFIG_SPARC_DIS) += sparc-dis.o
|
|||
######################################################################
|
||||
# trace
|
||||
|
||||
ifeq ($(TRACE_BACKEND),dtrace)
|
||||
trace-obj-y = trace-dtrace.o
|
||||
else
|
||||
trace-obj-y = trace.o
|
||||
ifeq ($(TRACE_BACKEND),simple)
|
||||
trace-obj-y += simpletrace.o
|
||||
user-obj-y += qemu-timer-common.o
|
||||
endif
|
||||
endif
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ endif
|
|||
endif
|
||||
|
||||
PROGS=$(QEMU_PROG)
|
||||
STPFILES=
|
||||
|
||||
ifndef CONFIG_HAIKU
|
||||
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-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
|
||||
@true
|
||||
|
@ -167,11 +188,11 @@ ifdef CONFIG_SOFTMMU
|
|||
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
|
||||
# virtio has to be here due to weird dependency between PCI and virtio-net.
|
||||
# need to fix this properly
|
||||
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
|
||||
obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
|
||||
obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
|
||||
obj-y += vhost_net.o
|
||||
obj-$(CONFIG_VHOST_NET) += vhost.o
|
||||
obj-$(CONFIG_VIRTFS) += virtio-9p.o
|
||||
obj-$(CONFIG_REALLY_VIRTFS) += virtio-9p.o
|
||||
obj-y += rwhandler.o
|
||||
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
|
||||
obj-$(CONFIG_NO_KVM) += kvm-stub.o
|
||||
|
@ -189,8 +210,8 @@ obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
|
|||
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
|
||||
|
||||
# PCI network cards
|
||||
obj-y += rtl8139.o
|
||||
obj-y += e1000.o
|
||||
obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
|
||||
obj-$(CONFIG_E1000_PCI) += e1000.o
|
||||
|
||||
# Inter-VM PCI shared memory
|
||||
obj-$(CONFIG_KVM) += ivshmem.o
|
||||
|
@ -340,6 +361,9 @@ clean:
|
|||
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
|
||||
rm -f *.d */*.d tcg/*.o ide/*.o
|
||||
rm -f hmp-commands.h qmp-commands.h gdbstub-xml.c
|
||||
ifdef CONFIG_SYSTEMTAP_TRACE
|
||||
rm -f *.stp
|
||||
endif
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
|
@ -348,6 +372,10 @@ ifneq ($(STRIP),)
|
|||
$(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS))
|
||||
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 $(wildcard *.d */*.d)
|
||||
|
|
|
@ -19,10 +19,7 @@ o qmp-spec.txt QEMU Monitor Protocol current specification
|
|||
o qmp-commands.txt QMP supported commands (auto-generated at build-time)
|
||||
o qmp-events.txt List of available asynchronous events
|
||||
|
||||
There are also two simple Python scripts available:
|
||||
|
||||
o qmp-shell A shell
|
||||
o vm-info Show some information about the Virtual Machine
|
||||
There is also a simple Python script called 'qmp-shell' available.
|
||||
|
||||
IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
|
||||
section in the qmp-commands.txt file before making any serious use of QMP.
|
||||
|
|
254
QMP/qmp-shell
254
QMP/qmp-shell
|
@ -1,8 +1,8 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Simple QEMU shell on top of QMP
|
||||
# Low-level QEMU shell on top of QMP.
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat Inc.
|
||||
# Copyright (C) 2009, 2010 Red Hat Inc.
|
||||
#
|
||||
# Authors:
|
||||
# Luiz Capitulino <lcapitulino@redhat.com>
|
||||
|
@ -14,60 +14,246 @@
|
|||
#
|
||||
# Start QEMU with:
|
||||
#
|
||||
# $ qemu [...] -monitor control,unix:./qmp,server
|
||||
# # qemu [...] -qmp unix:./qmp-sock,server
|
||||
#
|
||||
# Run the shell:
|
||||
#
|
||||
# $ qmp-shell ./qmp
|
||||
# $ qmp-shell ./qmp-sock
|
||||
#
|
||||
# Commands have the following format:
|
||||
#
|
||||
# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
|
||||
# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# (QEMU) info item=network
|
||||
# (QEMU) device_add driver=e1000 id=net1
|
||||
# {u'return': {}}
|
||||
# (QEMU)
|
||||
|
||||
import qmp
|
||||
import readline
|
||||
from sys import argv,exit
|
||||
import sys
|
||||
|
||||
def shell_help():
|
||||
print 'bye exit from the shell'
|
||||
class QMPCompleter(list):
|
||||
def complete(self, text, state):
|
||||
for cmd in self:
|
||||
if cmd.startswith(text):
|
||||
if not state:
|
||||
return cmd
|
||||
else:
|
||||
state -= 1
|
||||
|
||||
def main():
|
||||
if len(argv) != 2:
|
||||
print 'qemu-shell <unix-socket>'
|
||||
exit(1)
|
||||
class QMPShellError(Exception):
|
||||
pass
|
||||
|
||||
qemu = qmp.QEMUMonitorProtocol(argv[1])
|
||||
qemu.connect()
|
||||
qemu.send("qmp_capabilities")
|
||||
class QMPShellBadPort(QMPShellError):
|
||||
pass
|
||||
|
||||
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:
|
||||
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:
|
||||
print
|
||||
break
|
||||
if cmd == '':
|
||||
continue
|
||||
elif cmd == 'bye':
|
||||
break
|
||||
elif cmd == 'help':
|
||||
shell_help()
|
||||
return False
|
||||
if cmdline == '':
|
||||
for ev in self.get_events():
|
||||
print ev
|
||||
self.clear_events()
|
||||
return True
|
||||
else:
|
||||
return self._execute_cmd(cmdline)
|
||||
|
||||
class HMPShell(QMPShell):
|
||||
def __init__(self, address):
|
||||
QMPShell.__init__(self, address)
|
||||
self.__cpu_index = 0
|
||||
|
||||
def __cmd_completion(self):
|
||||
for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
|
||||
if cmd and cmd[0] != '[' and cmd[0] != '\t':
|
||||
name = cmd.split()[0] # drop help text
|
||||
if name == 'info':
|
||||
continue
|
||||
if name.find('|') != -1:
|
||||
# Command in the form 'foobar|f' or 'f|foobar', take the
|
||||
# full name
|
||||
opt = name.split('|')
|
||||
if len(opt[0]) == 1:
|
||||
name = opt[1]
|
||||
else:
|
||||
name = opt[0]
|
||||
self._completer.append(name)
|
||||
self._completer.append('help ' + name) # help completion
|
||||
|
||||
def __info_completion(self):
|
||||
for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
|
||||
if cmd:
|
||||
self._completer.append('info ' + cmd.split()[1])
|
||||
|
||||
def __other_completion(self):
|
||||
# special cases
|
||||
self._completer.append('help info')
|
||||
|
||||
def _fill_completion(self):
|
||||
self.__cmd_completion()
|
||||
self.__info_completion()
|
||||
self.__other_completion()
|
||||
|
||||
def __cmd_passthrough(self, cmdline, cpu_index = 0):
|
||||
return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
|
||||
{ 'command-line': cmdline,
|
||||
'cpu-index': cpu_index } })
|
||||
|
||||
def _execute_cmd(self, cmdline):
|
||||
if cmdline.split()[0] == "cpu":
|
||||
# trap the cpu command, it requires special setting
|
||||
try:
|
||||
resp = qemu.send(cmd)
|
||||
if resp == None:
|
||||
print 'Disconnected'
|
||||
break
|
||||
print resp
|
||||
except IndexError:
|
||||
print '-> command format: <command-name> ',
|
||||
print '[arg-name1=arg1] ... [arg-nameN=argN]'
|
||||
idx = int(cmdline.split()[1])
|
||||
if not 'return' in self.__cmd_passthrough('info version', idx):
|
||||
print 'bad CPU index'
|
||||
return True
|
||||
self.__cpu_index = idx
|
||||
except ValueError:
|
||||
print 'cpu command takes an integer argument'
|
||||
return True
|
||||
resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
|
||||
if resp is None:
|
||||
print 'Disconnected'
|
||||
return False
|
||||
assert 'return' in resp or 'error' in resp
|
||||
if 'return' in resp:
|
||||
# Success
|
||||
if len(resp['return']) > 0:
|
||||
print resp['return'],
|
||||
else:
|
||||
# Error
|
||||
print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
|
||||
return True
|
||||
|
||||
def show_banner(self):
|
||||
QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
|
||||
|
||||
def die(msg):
|
||||
sys.stderr.write('ERROR: %s\n' % msg)
|
||||
sys.exit(1)
|
||||
|
||||
def fail_cmdline(option=None):
|
||||
if option:
|
||||
sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
|
||||
sys.stderr.write('qemu-shell [ -H ] < UNIX socket path> | < TCP address:port >\n')
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
addr = ''
|
||||
try:
|
||||
if len(sys.argv) == 2:
|
||||
qemu = QMPShell(sys.argv[1])
|
||||
addr = sys.argv[1]
|
||||
elif len(sys.argv) == 3:
|
||||
if sys.argv[1] != '-H':
|
||||
fail_cmdline(sys.argv[1])
|
||||
qemu = HMPShell(sys.argv[2])
|
||||
addr = sys.argv[2]
|
||||
else:
|
||||
fail_cmdline()
|
||||
except QMPShellBadPort:
|
||||
die('bad port number in command-line')
|
||||
|
||||
try:
|
||||
qemu.connect()
|
||||
except qmp.QMPConnectError:
|
||||
die('Didn\'t get QMP greeting message')
|
||||
except qmp.QMPCapabilitiesError:
|
||||
die('Could not negotiate capabilities')
|
||||
except qemu.error:
|
||||
die('Could not connect to %s' % addr)
|
||||
|
||||
qemu.show_banner()
|
||||
while qemu.read_exec_command('(QEMU) '):
|
||||
pass
|
||||
qemu.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
161
QMP/qmp.py
161
QMP/qmp.py
|
@ -1,6 +1,6 @@
|
|||
# QEMU Monitor Protocol Python class
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat Inc.
|
||||
# Copyright (C) 2009, 2010 Red Hat Inc.
|
||||
#
|
||||
# Authors:
|
||||
# Luiz Capitulino <lcapitulino@redhat.com>
|
||||
|
@ -8,7 +8,9 @@
|
|||
# This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
# the COPYING file in the top-level directory.
|
||||
|
||||
import socket, json
|
||||
import json
|
||||
import errno
|
||||
import socket
|
||||
|
||||
class QMPError(Exception):
|
||||
pass
|
||||
|
@ -16,61 +18,114 @@ class QMPError(Exception):
|
|||
class QMPConnectError(QMPError):
|
||||
pass
|
||||
|
||||
class QMPCapabilitiesError(QMPError):
|
||||
pass
|
||||
|
||||
class QEMUMonitorProtocol:
|
||||
def connect(self):
|
||||
self.sock.connect(self.filename)
|
||||
data = self.__json_read()
|
||||
if data == None:
|
||||
raise QMPConnectError
|
||||
if not data.has_key('QMP'):
|
||||
raise QMPConnectError
|
||||
return data['QMP']['capabilities']
|
||||
def __init__(self, address):
|
||||
"""
|
||||
Create a QEMUMonitorProtocol class.
|
||||
|
||||
def close(self):
|
||||
self.sock.close()
|
||||
@param address: QEMU address, can be either a unix socket path (string)
|
||||
or a tuple in the form ( address, port ) for a TCP
|
||||
connection
|
||||
@note No connection is established, this is done by the connect() method
|
||||
"""
|
||||
self.__events = []
|
||||
self.__address = address
|
||||
self.__sock = self.__get_sock()
|
||||
self.__sockfile = self.__sock.makefile()
|
||||
|
||||
def send_raw(self, line):
|
||||
self.sock.send(str(line))
|
||||
return self.__json_read()
|
||||
|
||||
def send(self, cmdline):
|
||||
cmd = self.__build_cmd(cmdline)
|
||||
self.__json_send(cmd)
|
||||
resp = self.__json_read()
|
||||
if resp == None:
|
||||
return
|
||||
elif resp.has_key('error'):
|
||||
return resp['error']
|
||||
def __get_sock(self):
|
||||
if isinstance(self.__address, tuple):
|
||||
family = socket.AF_INET
|
||||
else:
|
||||
return resp['return']
|
||||
|
||||
def __build_cmd(self, cmdline):
|
||||
cmdargs = cmdline.split()
|
||||
qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
|
||||
for arg in cmdargs[1:]:
|
||||
opt = arg.split('=')
|
||||
try:
|
||||
value = int(opt[1])
|
||||
except ValueError:
|
||||
value = opt[1]
|
||||
qmpcmd['arguments'][opt[0]] = value
|
||||
return qmpcmd
|
||||
|
||||
def __json_send(self, cmd):
|
||||
# XXX: We have to send any additional char, otherwise
|
||||
# the Server won't read our input
|
||||
self.sock.send(json.dumps(cmd) + ' ')
|
||||
family = socket.AF_UNIX
|
||||
return socket.socket(family, socket.SOCK_STREAM)
|
||||
|
||||
def __json_read(self):
|
||||
try:
|
||||
while True:
|
||||
line = json.loads(self.sockfile.readline())
|
||||
if not 'event' in line:
|
||||
return line
|
||||
except ValueError:
|
||||
return
|
||||
while True:
|
||||
data = self.__sockfile.readline()
|
||||
if not data:
|
||||
return
|
||||
resp = json.loads(data)
|
||||
if 'event' in resp:
|
||||
self.__events.append(resp)
|
||||
continue
|
||||
return resp
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
self.sockfile = self.sock.makefile()
|
||||
error = socket.error
|
||||
|
||||
def connect(self):
|
||||
"""
|
||||
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()
|
||||
|
|
33
QMP/vm-info
33
QMP/vm-info
|
@ -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()
|
|
@ -44,6 +44,9 @@
|
|||
that we generate the list.
|
||||
*/
|
||||
static struct audio_driver *drvtab[] = {
|
||||
#ifdef CONFIG_SPICE
|
||||
&spice_audio_driver,
|
||||
#endif
|
||||
CONFIG_AUDIO_DRIVERS
|
||||
&no_audio_driver,
|
||||
&wav_audio_driver
|
||||
|
@ -1093,15 +1096,6 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
|
|||
/*
|
||||
* 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)
|
||||
{
|
||||
HWVoiceIn *hwi = NULL;
|
||||
|
@ -1116,10 +1110,8 @@ static int audio_is_timer_needed (void)
|
|||
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 ()) {
|
||||
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
|
||||
*/
|
||||
|
@ -1192,7 +1190,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
|||
hw->enabled = 1;
|
||||
if (s->vm_running) {
|
||||
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;
|
||||
if (s->vm_running) {
|
||||
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;
|
||||
|
@ -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))) {
|
||||
hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
|
||||
}
|
||||
audio_reset_timer ();
|
||||
audio_reset_timer (s);
|
||||
}
|
||||
|
||||
static void audio_atexit (void)
|
||||
|
|
|
@ -209,6 +209,7 @@ extern struct audio_driver coreaudio_audio_driver;
|
|||
extern struct audio_driver dsound_audio_driver;
|
||||
extern struct audio_driver esd_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 mixeng_volume nominal_volume;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -49,12 +49,14 @@ typedef struct BlkMigDevState {
|
|||
int64_t total_sectors;
|
||||
int64_t dirty;
|
||||
QSIMPLEQ_ENTRY(BlkMigDevState) entry;
|
||||
unsigned long *aio_bitmap;
|
||||
} BlkMigDevState;
|
||||
|
||||
typedef struct BlkMigBlock {
|
||||
uint8_t *buf;
|
||||
BlkMigDevState *bmds;
|
||||
int64_t sector;
|
||||
int nr_sectors;
|
||||
struct iovec iov;
|
||||
QEMUIOVector qiov;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
BlkMigBlock *blk = opaque;
|
||||
|
@ -151,6 +199,7 @@ static void blk_mig_read_cb(void *opaque, int ret)
|
|||
add_avg_read_time(blk->time);
|
||||
|
||||
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.read_done++;
|
||||
|
@ -194,6 +243,7 @@ static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
|
|||
blk->buf = qemu_malloc(BLOCK_SIZE);
|
||||
blk->bmds = bmds;
|
||||
blk->sector = cur_sector;
|
||||
blk->nr_sectors = nr_sectors;
|
||||
|
||||
blk->iov.iov_base = blk->buf;
|
||||
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->completed_sectors = 0;
|
||||
bmds->shared_base = block_mig_state.shared_base;
|
||||
alloc_aio_bitmap(bmds);
|
||||
|
||||
block_mig_state.total_sector_sum += sectors;
|
||||
|
||||
|
@ -329,6 +380,9 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
|
|||
int nr_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 (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->bmds = bmds;
|
||||
blk->sector = sector;
|
||||
blk->nr_sectors = nr_sectors;
|
||||
|
||||
if (is_async) {
|
||||
blk->iov.iov_base = blk->buf;
|
||||
|
@ -354,6 +409,7 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
|
|||
goto error;
|
||||
}
|
||||
block_mig_state.submitted++;
|
||||
bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
|
||||
} else {
|
||||
if (bdrv_read(bmds->bs, sector, blk->buf,
|
||||
nr_sectors) < 0) {
|
||||
|
@ -474,6 +530,7 @@ static void blk_mig_cleanup(Monitor *mon)
|
|||
|
||||
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
|
||||
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
|
||||
qemu_free(bmds->aio_bitmap);
|
||||
qemu_free(bmds);
|
||||
}
|
||||
|
||||
|
|
75
block.c
75
block.c
|
@ -930,14 +930,14 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
|
|||
bit = start % (sizeof(unsigned long) * 8);
|
||||
val = bs->dirty_bitmap[idx];
|
||||
if (dirty) {
|
||||
if (!(val & (1 << bit))) {
|
||||
if (!(val & (1UL << bit))) {
|
||||
bs->dirty_count++;
|
||||
val |= 1 << bit;
|
||||
val |= 1UL << bit;
|
||||
}
|
||||
} else {
|
||||
if (val & (1 << bit)) {
|
||||
if (val & (1UL << bit)) {
|
||||
bs->dirty_count--;
|
||||
val &= ~(1 << bit);
|
||||
val &= ~(1UL << bit);
|
||||
}
|
||||
}
|
||||
bs->dirty_bitmap[idx] = val;
|
||||
|
@ -1453,14 +1453,27 @@ const char *bdrv_get_device_name(BlockDriverState *bs)
|
|||
return bs->device_name;
|
||||
}
|
||||
|
||||
void bdrv_flush(BlockDriverState *bs)
|
||||
int bdrv_flush(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->open_flags & BDRV_O_NO_FLUSH) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bs->drv && bs->drv->bdrv_flush)
|
||||
bs->drv->bdrv_flush(bs);
|
||||
if (bs->drv && bs->drv->bdrv_flush) {
|
||||
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)
|
||||
|
@ -2018,12 +2031,49 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
|||
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,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
BlockDriverAIOCB *ret;
|
||||
BlockCompleteData *blk_cb_data;
|
||||
|
||||
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;
|
||||
|
||||
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,
|
||||
|
@ -2672,8 +2725,8 @@ int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
|
|||
|
||||
if (bs->dirty_bitmap &&
|
||||
(sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
|
||||
return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
|
||||
(1 << (chunk % (sizeof(unsigned long) * 8)));
|
||||
return !!(bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
|
||||
(1UL << (chunk % (sizeof(unsigned long) * 8))));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
2
block.h
2
block.h
|
@ -142,7 +142,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
|
|||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
|
||||
/* Ensure contents are flushed to disk. */
|
||||
void bdrv_flush(BlockDriverState *bs);
|
||||
int bdrv_flush(BlockDriverState *bs);
|
||||
void bdrv_flush_all(void);
|
||||
void bdrv_close_all(void);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -116,12 +116,12 @@ static void blkverify_close(BlockDriverState *bs)
|
|||
s->test_file = NULL;
|
||||
}
|
||||
|
||||
static void blkverify_flush(BlockDriverState *bs)
|
||||
static int blkverify_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
|
||||
/* 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)
|
||||
|
@ -300,8 +300,8 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb)
|
|||
{
|
||||
ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov);
|
||||
if (offset != -1) {
|
||||
blkverify_err(acb, "contents mismatch in sector %lld",
|
||||
acb->sector_num + (offset / BDRV_SECTOR_SIZE));
|
||||
blkverify_err(acb, "contents mismatch in sector %" PRId64,
|
||||
acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -282,9 +282,9 @@ exit:
|
|||
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[] = {
|
||||
|
|
|
@ -54,7 +54,6 @@ typedef struct QCowHeader {
|
|||
#define L2_CACHE_SIZE 16
|
||||
|
||||
typedef struct BDRVQcowState {
|
||||
BlockDriverState *hd;
|
||||
int cluster_bits;
|
||||
int cluster_size;
|
||||
int cluster_sectors;
|
||||
|
@ -910,9 +909,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||
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,
|
||||
|
|
|
@ -188,6 +188,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
|
|||
ret = bdrv_pread(bs->file, l2_offset, *l2_table,
|
||||
s->l2_size * sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
qcow2_l2_cache_reset(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ static int load_refcount_block(BlockDriverState *bs,
|
|||
ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache,
|
||||
s->cluster_size);
|
||||
if (ret < 0) {
|
||||
s->refcount_block_cache_offset = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1148,9 +1148,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
|
|||
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,
|
||||
|
|
|
@ -79,7 +79,6 @@ typedef struct QCowSnapshot {
|
|||
} QCowSnapshot;
|
||||
|
||||
typedef struct BDRVQcowState {
|
||||
BlockDriverState *hd;
|
||||
int cluster_bits;
|
||||
int cluster_size;
|
||||
int cluster_sectors;
|
||||
|
|
|
@ -463,7 +463,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
|
|||
count -= ret;
|
||||
sum += ret;
|
||||
}
|
||||
/* here, count < 512 because (count & ~sector_mask) == 0 */
|
||||
/* here, count < sector_size because (count & ~sector_mask) == 0 */
|
||||
if (count) {
|
||||
ret = raw_pread_aligned(bs, offset, s->aligned_buf,
|
||||
bs->buffer_alignment);
|
||||
|
@ -734,10 +734,10 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
|
|||
return result;
|
||||
}
|
||||
|
||||
static void raw_flush(BlockDriverState *bs)
|
||||
static int raw_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
qemu_fdatasync(s->fd);
|
||||
return qemu_fdatasync(s->fd);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -147,10 +147,17 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
|
|||
return ret_count;
|
||||
}
|
||||
|
||||
static void raw_flush(BlockDriverState *bs)
|
||||
static int raw_flush(BlockDriverState *bs)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -186,7 +186,6 @@ typedef struct {
|
|||
} VdiHeader;
|
||||
|
||||
typedef struct {
|
||||
BlockDriverState *hd;
|
||||
/* The block map entries are little endian (even in memory). */
|
||||
uint32_t *bmap;
|
||||
/* 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");
|
||||
bdrv_flush(bs->file);
|
||||
return bdrv_flush(bs->file);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -61,7 +61,6 @@ typedef struct {
|
|||
#define L2_CACHE_SIZE 16
|
||||
|
||||
typedef struct BDRVVmdkState {
|
||||
BlockDriverState *hd;
|
||||
int64_t l1_table_offset;
|
||||
int64_t l1_backup_table_offset;
|
||||
uint32_t *l1_table;
|
||||
|
@ -823,9 +822,9 @@ static void vmdk_close(BlockDriverState *bs)
|
|||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
23
block/vpc.c
23
block/vpc.c
|
@ -110,8 +110,6 @@ struct vhd_dyndisk_header {
|
|||
};
|
||||
|
||||
typedef struct BDRVVPCState {
|
||||
BlockDriverState *hd;
|
||||
|
||||
uint8_t footer_buf[HEADER_SIZE];
|
||||
uint64_t free_data_block_offset;
|
||||
int max_table_entries;
|
||||
|
@ -439,6 +437,10 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vpc_flush(BlockDriverState *bs)
|
||||
{
|
||||
return bdrv_flush(bs->file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the number of cylinders, heads and sectors per cylinder
|
||||
|
@ -618,14 +620,15 @@ static QEMUOptionParameter vpc_create_options[] = {
|
|||
};
|
||||
|
||||
static BlockDriver bdrv_vpc = {
|
||||
.format_name = "vpc",
|
||||
.instance_size = sizeof(BDRVVPCState),
|
||||
.bdrv_probe = vpc_probe,
|
||||
.bdrv_open = vpc_open,
|
||||
.bdrv_read = vpc_read,
|
||||
.bdrv_write = vpc_write,
|
||||
.bdrv_close = vpc_close,
|
||||
.bdrv_create = vpc_create,
|
||||
.format_name = "vpc",
|
||||
.instance_size = sizeof(BDRVVPCState),
|
||||
.bdrv_probe = vpc_probe,
|
||||
.bdrv_open = vpc_open,
|
||||
.bdrv_read = vpc_read,
|
||||
.bdrv_write = vpc_write,
|
||||
.bdrv_flush = vpc_flush,
|
||||
.bdrv_close = vpc_close,
|
||||
.bdrv_create = vpc_create,
|
||||
|
||||
.create_options = vpc_create_options,
|
||||
};
|
||||
|
|
|
@ -59,7 +59,7 @@ struct BlockDriver {
|
|||
const uint8_t *buf, int nb_sectors);
|
||||
void (*bdrv_close)(BlockDriverState *bs);
|
||||
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 nb_sectors, int *pnum);
|
||||
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
|
||||
|
|
45
blockdev.c
45
blockdev.c
|
@ -14,6 +14,8 @@
|
|||
#include "qemu-option.h"
|
||||
#include "qemu-config.h"
|
||||
#include "sysemu.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "block_int.h"
|
||||
|
||||
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;
|
||||
if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -326,8 +328,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
|
|||
|
||||
on_read_error = BLOCK_ERR_REPORT;
|
||||
if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
|
||||
if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
|
||||
fprintf(stderr, "rerror is no supported by this format\n");
|
||||
if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
|
||||
fprintf(stderr, "rerror is not supported by this format\n");
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ struct DriveInfo {
|
|||
};
|
||||
|
||||
#define MAX_IDE_DEVS 2
|
||||
#define MAX_SCSI_DEVS 7
|
||||
#define MAX_SCSI_DEVS 255
|
||||
|
||||
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
|
||||
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_change_block(Monitor *mon, const char *device,
|
||||
const char *filename, const char *fmt);
|
||||
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -929,7 +929,7 @@ echo " --enable-docs enable documentation build"
|
|||
echo " --disable-docs disable documentation build"
|
||||
echo " --disable-vhost-net disable 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 " Default:trace-<pid>"
|
||||
echo " --disable-spice disable spice"
|
||||
|
@ -2193,6 +2193,22 @@ EOF
|
|||
exit 1
|
||||
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
|
||||
# After here, no more $cc or $ld runs
|
||||
|
@ -2633,6 +2649,9 @@ fi
|
|||
if test "$trace_backend" = "simple"; then
|
||||
trace_file="\"$trace_file-%u\""
|
||||
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 "TOOLS=$tools" >> $config_host_mak
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Default configuration for arm-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_GDBSTUB_XML=y
|
||||
CONFIG_USB_OHCI=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_NAND=y
|
||||
CONFIG_ECC=y
|
||||
|
@ -25,6 +25,5 @@ CONFIG_SSI_SD=y
|
|||
CONFIG_LAN9118=y
|
||||
CONFIG_SMC91C111=y
|
||||
CONFIG_DS1338=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
|
|
|
@ -2,5 +2,4 @@
|
|||
|
||||
CONFIG_NAND=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Default configuration for i386-softmmu
|
||||
|
||||
CONFIG_USB_OHCI=y
|
||||
include pci.mak
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
|
@ -9,7 +9,6 @@ CONFIG_PARALLEL=y
|
|||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_USB_UHCI=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
|
@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y
|
|||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_PIIX_PCI=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Default configuration for m68k-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_GDBSTUB_XML=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
# Default configuration for microblaze-softmmu
|
||||
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Default configuration for mips-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESP=y
|
||||
CONFIG_VGA_PCI=y
|
||||
|
@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
|
|||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_USB_UHCI=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
|
@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
|
|||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Default configuration for mips64-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESP=y
|
||||
CONFIG_VGA_PCI=y
|
||||
|
@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
|
|||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_USB_UHCI=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
|
@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
|
|||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Default configuration for mips64el-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESP=y
|
||||
CONFIG_VGA_PCI=y
|
||||
|
@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
|
|||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_USB_UHCI=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
|
@ -25,7 +25,6 @@ CONFIG_IDE_PIIX=y
|
|||
CONFIG_IDE_VIA=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Default configuration for mipsel-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESP=y
|
||||
CONFIG_VGA_PCI=y
|
||||
|
@ -11,7 +12,6 @@ CONFIG_PARALLEL=y
|
|||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_USB_UHCI=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
|
@ -24,7 +24,6 @@ CONFIG_IDE_ISA=y
|
|||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
|
|
|
@ -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
|
|
@ -1,7 +1,7 @@
|
|||
# Default configuration for ppc-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_GDBSTUB_XML=y
|
||||
CONFIG_USB_OHCI=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
|
@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
|
|||
CONFIG_IDE_MACIO=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_PTIMER=y
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Default configuration for ppc64-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_GDBSTUB_XML=y
|
||||
CONFIG_USB_OHCI=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
|
@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
|
|||
CONFIG_IDE_MACIO=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_PTIMER=y
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Default configuration for ppcemb-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_GDBSTUB_XML=y
|
||||
CONFIG_USB_OHCI=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
|
@ -31,7 +31,6 @@ CONFIG_IDE_CMD646=y
|
|||
CONFIG_IDE_MACIO=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_PTIMER=y
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
CONFIG_VIRTIO=y
|
|
@ -1,9 +1,8 @@
|
|||
# Default configuration for sh4-softmmu
|
||||
|
||||
CONFIG_USB_OHCI=y
|
||||
include pci.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_IDE_CORE=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
# Default configuration for sh4eb-softmmu
|
||||
|
||||
CONFIG_USB_OHCI=y
|
||||
include pci.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_IDE_CORE=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
|
|
|
@ -6,5 +6,5 @@ CONFIG_ESCC=y
|
|||
CONFIG_M48T59=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
CONFIG_PCNET_COMMON=y
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Default configuration for sparc64-softmmu
|
||||
|
||||
include pci.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_PTIMER=y
|
||||
|
@ -13,4 +14,3 @@ CONFIG_IDE_QDEV=y
|
|||
CONFIG_IDE_PCI=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_CMD646=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Default configuration for x86_64-softmmu
|
||||
|
||||
CONFIG_USB_OHCI=y
|
||||
include pci.mak
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
|
@ -9,7 +9,6 @@ CONFIG_PARALLEL=y
|
|||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_USB_UHCI=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
|
@ -22,4 +21,3 @@ CONFIG_IDE_PIIX=y
|
|||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_PIIX_PCI=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
|
|
|
@ -65,6 +65,24 @@ STEXI
|
|||
@item eject [-f] @var{device}
|
||||
@findex eject
|
||||
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
|
||||
|
||||
{
|
||||
|
|
|
@ -52,6 +52,7 @@ struct pci_status {
|
|||
|
||||
typedef struct PIIX4PMState {
|
||||
PCIDevice dev;
|
||||
IORange ioport;
|
||||
uint16_t pmsts;
|
||||
uint16_t pmen;
|
||||
uint16_t pmcntrl;
|
||||
|
@ -128,10 +129,16 @@ static void pm_tmr_timer(void *opaque)
|
|||
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;
|
||||
addr &= 0x3f;
|
||||
PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport);
|
||||
|
||||
if (width != 2) {
|
||||
PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n",
|
||||
(unsigned)addr, width, (unsigned)val);
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
addr &= 0x3f;
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
val = get_pmsts(s);
|
||||
|
@ -200,27 +207,6 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
|
|||
case 0x04:
|
||||
val = s->pmcntrl;
|
||||
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:
|
||||
val = get_pmtmr(s);
|
||||
break;
|
||||
|
@ -228,10 +214,15 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
|
|||
val = 0;
|
||||
break;
|
||||
}
|
||||
PIIX4_DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val);
|
||||
return val;
|
||||
PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, 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)
|
||||
{
|
||||
PIIX4PMState *s = arg;
|
||||
|
@ -265,10 +256,8 @@ static void pm_io_space_update(PIIX4PMState *s)
|
|||
|
||||
/* XXX: need to improve memory and ioport allocation */
|
||||
PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base);
|
||||
register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
|
||||
register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
|
||||
register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
|
||||
register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
|
||||
iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64);
|
||||
ioport_register(&s->ioport);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -437,6 +437,8 @@ static int apic_find_dest(uint8_t dest)
|
|||
apic = local_apics[i];
|
||||
if (apic && apic->id == dest)
|
||||
return i;
|
||||
if (!apic)
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -472,6 +474,8 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
|
|||
set_bit(deliver_bitmask, i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
hw/e1000.c
13
hw/e1000.c
|
@ -447,9 +447,10 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
|||
// data descriptor
|
||||
tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
|
||||
tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
|
||||
} else
|
||||
} else {
|
||||
// legacy descriptor
|
||||
tp->cptse = 0;
|
||||
}
|
||||
|
||||
if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
|
||||
(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);
|
||||
desc.length = cpu_to_le16(size + fcs_len(s));
|
||||
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");
|
||||
}
|
||||
cpu_physical_memory_write(base, (void *)&desc, sizeof(desc));
|
||||
|
||||
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
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
if (index < NWRITEOPS && macreg_writeops[index])
|
||||
if (index < NWRITEOPS && macreg_writeops[index]) {
|
||||
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);
|
||||
else
|
||||
} else {
|
||||
DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08x\n",
|
||||
index<<2, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -808,6 +808,28 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
|
|||
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)
|
||||
{
|
||||
HDAAudioState *a = opaque;
|
||||
|
@ -879,6 +901,7 @@ static HDACodecDeviceInfo hda_audio_info_output = {
|
|||
.qdev.vmsd = &vmstate_hda_audio,
|
||||
.qdev.props = hda_audio_properties,
|
||||
.init = hda_audio_init_output,
|
||||
.exit = hda_audio_exit,
|
||||
.command = hda_audio_command,
|
||||
.stream = hda_audio_stream,
|
||||
};
|
||||
|
@ -890,6 +913,7 @@ static HDACodecDeviceInfo hda_audio_info_duplex = {
|
|||
.qdev.vmsd = &vmstate_hda_audio,
|
||||
.qdev.props = hda_audio_properties,
|
||||
.init = hda_audio_init_duplex,
|
||||
.exit = hda_audio_exit,
|
||||
.command = hda_audio_command,
|
||||
.stream = hda_audio_stream,
|
||||
};
|
||||
|
|
|
@ -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_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
|
||||
register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
|
||||
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);
|
||||
iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
|
||||
ioport_register(&bm->addr_ioport);
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -473,11 +473,21 @@ static void dma_buf_commit(IDEState *s, int is_write)
|
|||
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)
|
||||
{
|
||||
ide_transfer_stop(s);
|
||||
s->error = ABRT_ERR;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -587,11 +597,8 @@ static void ide_read_dma_cb(void *opaque, int ret)
|
|||
s->status = READY_STAT | SEEK_STAT;
|
||||
ide_set_irq(s->bus);
|
||||
eot:
|
||||
bm->status &= ~BM_STATUS_DMAING;
|
||||
bm->status |= BM_STATUS_INT;
|
||||
bm->dma_cb = NULL;
|
||||
bm->unit = -1;
|
||||
bm->aiocb = NULL;
|
||||
ide_dma_set_inactive(bm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -733,11 +740,8 @@ static void ide_write_dma_cb(void *opaque, int ret)
|
|||
s->status = READY_STAT | SEEK_STAT;
|
||||
ide_set_irq(s->bus);
|
||||
eot:
|
||||
bm->status &= ~BM_STATUS_DMAING;
|
||||
bm->status |= BM_STATUS_INT;
|
||||
bm->dma_cb = NULL;
|
||||
bm->unit = -1;
|
||||
bm->aiocb = NULL;
|
||||
ide_dma_set_inactive(bm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -811,10 +815,16 @@ static void ide_flush_cb(void *opaque, int ret)
|
|||
|
||||
static void ide_flush_cache(IDEState *s)
|
||||
{
|
||||
if (s->bs) {
|
||||
bdrv_aio_flush(s->bs, ide_flush_cb, s);
|
||||
} else {
|
||||
BlockDriverAIOCB *acb;
|
||||
|
||||
if (s->bs == NULL) {
|
||||
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;
|
||||
ide_set_irq(s->bus);
|
||||
eot:
|
||||
bm->status &= ~BM_STATUS_DMAING;
|
||||
bm->status |= BM_STATUS_INT;
|
||||
bm->dma_cb = NULL;
|
||||
bm->unit = -1;
|
||||
bm->aiocb = NULL;
|
||||
ide_dma_set_inactive(bm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2948,12 +2955,10 @@ void ide_dma_cancel(BMDMAState *bm)
|
|||
printf("aio_cancel\n");
|
||||
#endif
|
||||
bdrv_aio_cancel(bm->aiocb);
|
||||
bm->aiocb = NULL;
|
||||
}
|
||||
bm->status &= ~BM_STATUS_DMAING;
|
||||
|
||||
/* cancel DMA request */
|
||||
bm->unit = -1;
|
||||
bm->dma_cb = NULL;
|
||||
ide_dma_set_inactive(bm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
#include <hw/ide.h>
|
||||
#include "block_int.h"
|
||||
#include "iorange.h"
|
||||
|
||||
/* debug IDE devices */
|
||||
//#define DEBUG_IDE
|
||||
|
@ -496,6 +497,7 @@ struct BMDMAState {
|
|||
QEMUIOVector qiov;
|
||||
int64_t sector_num;
|
||||
uint32_t nsector;
|
||||
IORange addr_ioport;
|
||||
QEMUBH *bh;
|
||||
};
|
||||
|
||||
|
|
137
hw/ide/pci.c
137
hw/ide/pci.c
|
@ -39,106 +39,75 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
|
|||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, val);
|
||||
#endif
|
||||
if (!(val & BM_CMD_START)) {
|
||||
/*
|
||||
* We can't cancel Scatter Gather DMA in the middle of the
|
||||
* operation or a partial (not full) DMA transfer would reach
|
||||
* the storage so we wait for completion instead (we beahve
|
||||
* like if the DMA was completed by the time the guest trying
|
||||
* to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
|
||||
* set).
|
||||
*
|
||||
* In the future we'll be able to safely cancel the I/O if the
|
||||
* whole DMA operation will be submitted to disk with a single
|
||||
* aio operation with preadv/pwritev.
|
||||
*/
|
||||
if (bm->aiocb) {
|
||||
qemu_aio_flush();
|
||||
|
||||
/* Ignore writes to SSBM if it keeps the old value */
|
||||
if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
|
||||
if (!(val & BM_CMD_START)) {
|
||||
/*
|
||||
* We can't cancel Scatter Gather DMA in the middle of the
|
||||
* operation or a partial (not full) DMA transfer would reach
|
||||
* the storage so we wait for completion instead (we beahve
|
||||
* like if the DMA was completed by the time the guest trying
|
||||
* to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
|
||||
* set).
|
||||
*
|
||||
* In the future we'll be able to safely cancel the I/O if the
|
||||
* whole DMA operation will be submitted to disk with a single
|
||||
* aio operation with preadv/pwritev.
|
||||
*/
|
||||
if (bm->aiocb) {
|
||||
qemu_aio_flush();
|
||||
#ifdef DEBUG_IDE
|
||||
if (bm->aiocb)
|
||||
printf("ide_dma_cancel: aiocb still pending");
|
||||
if (bm->status & BM_STATUS_DMAING)
|
||||
printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
|
||||
if (bm->aiocb)
|
||||
printf("ide_dma_cancel: aiocb still pending");
|
||||
if (bm->status & BM_STATUS_DMAING)
|
||||
printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
|
||||
#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;
|
||||
uint32_t val;
|
||||
val = (bm->addr >> ((addr & 3) * 8)) & 0xff;
|
||||
BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
|
||||
uint32_t mask = (1ULL << (width * 8)) - 1;
|
||||
|
||||
*data = (bm->addr >> (addr * 8)) & mask;
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, val);
|
||||
printf("%s: 0x%08x\n", __func__, (unsigned)*data);
|
||||
#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;
|
||||
int shift = (addr & 3) * 8;
|
||||
BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
|
||||
int shift = addr * 8;
|
||||
uint32_t mask = (1ULL << (width * 8)) - 1;
|
||||
|
||||
#ifdef DEBUG_IDE
|
||||
printf("%s: 0x%08x\n", __func__, val);
|
||||
printf("%s: 0x%08x\n", __func__, (unsigned)data);
|
||||
#endif
|
||||
bm->addr &= ~(0xFF << shift);
|
||||
bm->addr |= ((val & 0xFF) << shift) & ~3;
|
||||
bm->cur_addr = bm->addr;
|
||||
bm->addr &= ~(mask << shift);
|
||||
bm->addr |= ((data & mask) << shift) & ~3;
|
||||
}
|
||||
|
||||
uint32_t bmdma_addr_readw(void *opaque, uint32_t addr)
|
||||
{
|
||||
BMDMAState *bm = opaque;
|
||||
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;
|
||||
}
|
||||
const IORangeOps bmdma_addr_ioport_ops = {
|
||||
.read = bmdma_addr_read,
|
||||
.write = bmdma_addr_write,
|
||||
};
|
||||
|
||||
static bool ide_bmdma_current_needed(void *opaque)
|
||||
{
|
||||
|
|
|
@ -11,12 +11,7 @@ typedef struct PCIIDEState {
|
|||
} PCIIDEState;
|
||||
|
||||
void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t bmdma_addr_readb(void *opaque, uint32_t addr);
|
||||
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);
|
||||
extern const IORangeOps bmdma_addr_ioport_ops;
|
||||
void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
|
||||
|
||||
extern const VMStateDescription vmstate_ide_pci;
|
||||
|
|
|
@ -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_read(addr, 4, 1, bmdma_readb, bm);
|
||||
|
||||
register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
|
||||
register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
|
||||
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);
|
||||
iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
|
||||
ioport_register(&bm->addr_ioport);
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_read(addr, 4, 1, bmdma_readb, bm);
|
||||
|
||||
register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
|
||||
register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
|
||||
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);
|
||||
iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
|
||||
ioport_register(&bm->addr_ioport);
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "hw.h"
|
||||
#include "pci.h"
|
||||
#include "msi.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "audiodev.h"
|
||||
#include "intel-hda.h"
|
||||
|
@ -55,15 +56,27 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
|
|||
if (dev->cad == -1) {
|
||||
dev->cad = bus->next_cad;
|
||||
}
|
||||
if (dev->cad > 15)
|
||||
if (dev->cad >= 15) {
|
||||
return -1;
|
||||
}
|
||||
bus->next_cad = dev->cad + 1;
|
||||
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)
|
||||
{
|
||||
info->qdev.init = hda_codec_dev_init;
|
||||
info->qdev.exit = hda_codec_dev_exit;
|
||||
info->qdev.bus_info = &hda_codec_bus_info;
|
||||
qdev_register(&info->qdev);
|
||||
}
|
||||
|
@ -177,6 +190,7 @@ struct IntelHDAState {
|
|||
|
||||
/* properties */
|
||||
uint32_t debug;
|
||||
uint32_t msi;
|
||||
};
|
||||
|
||||
struct IntelHDAReg {
|
||||
|
@ -235,7 +249,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
|
|||
if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
|
||||
sts |= (1 << 30);
|
||||
}
|
||||
if (d->state_sts) {
|
||||
if (d->state_sts & d->wake_en) {
|
||||
sts |= (1 << 30);
|
||||
}
|
||||
|
||||
|
@ -257,6 +271,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
|
|||
|
||||
static void intel_hda_update_irq(IntelHDAState *d)
|
||||
{
|
||||
int msi = d->msi && msi_enabled(&d->pci);
|
||||
int level;
|
||||
|
||||
intel_hda_update_int_sts(d);
|
||||
|
@ -265,8 +280,15 @@ static void intel_hda_update_irq(IntelHDAState *d)
|
|||
} else {
|
||||
level = 0;
|
||||
}
|
||||
dprint(d, 2, "%s: level %d\n", __FUNCTION__, level);
|
||||
qemu_set_irq(d->pci.irq[0], level);
|
||||
dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
intel_hda_update_irq(d);
|
||||
|
@ -617,13 +644,15 @@ static const struct IntelHDAReg regtab[] = {
|
|||
[ ICH6_REG_WAKEEN ] = {
|
||||
.name = "WAKEEN",
|
||||
.size = 2,
|
||||
.wmask = 0x7fff,
|
||||
.offset = offsetof(IntelHDAState, wake_en),
|
||||
.whandler = intel_hda_set_wake_en,
|
||||
},
|
||||
[ ICH6_REG_STATESTS ] = {
|
||||
.name = "STATESTS",
|
||||
.size = 2,
|
||||
.wmask = 0x3fff,
|
||||
.wclear = 0x3fff,
|
||||
.wmask = 0x7fff,
|
||||
.wclear = 0x7fff,
|
||||
.offset = offsetof(IntelHDAState, state_sts),
|
||||
.whandler = intel_hda_set_state_sts,
|
||||
},
|
||||
|
@ -1130,6 +1159,9 @@ static int intel_hda_init(PCIDevice *pci)
|
|||
intel_hda_mmio_write, d);
|
||||
pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
||||
intel_hda_map);
|
||||
if (d->msi) {
|
||||
msi_init(&d->pci, 0x50, 1, true, false);
|
||||
}
|
||||
|
||||
hda_codec_bus_init(&d->pci.qdev, &d->codecs,
|
||||
intel_hda_response, intel_hda_xfer);
|
||||
|
@ -1137,6 +1169,28 @@ static int intel_hda_init(PCIDevice *pci)
|
|||
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)
|
||||
{
|
||||
IntelHDAState* d = opaque;
|
||||
|
@ -1219,8 +1273,11 @@ static PCIDeviceInfo intel_hda_info = {
|
|||
.qdev.vmsd = &vmstate_intel_hda,
|
||||
.qdev.reset = intel_hda_reset,
|
||||
.init = intel_hda_init,
|
||||
.exit = intel_hda_exit,
|
||||
.config_write = intel_hda_write_config,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
|
||||
DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@ struct HDACodecDevice {
|
|||
struct HDACodecDeviceInfo {
|
||||
DeviceInfo qdev;
|
||||
int (*init)(HDACodecDevice *dev);
|
||||
int (*exit)(HDACodecDevice *dev);
|
||||
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
|
||||
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
|
||||
};
|
||||
|
|
|
@ -977,7 +977,7 @@ void mips_malta_init (ram_addr_t ram_size,
|
|||
} else if (vmsvga_enabled) {
|
||||
pci_vmsvga_init(pci_bus);
|
||||
} else if (std_vga_enabled) {
|
||||
pci_vga_init(pci_bus, 0, 0);
|
||||
pci_vga_init(pci_bus);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,12 @@ int load_multiboot(void *fw_cfg,
|
|||
uint64_t elf_low, elf_high;
|
||||
int kernel_size;
|
||||
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,
|
||||
&elf_low, &elf_high, 0, ELF_MACHINE, 0);
|
||||
if (kernel_size < 0) {
|
||||
|
|
24
hw/pc.c
24
hw/pc.c
|
@ -75,12 +75,12 @@ struct e820_entry {
|
|||
uint64_t address;
|
||||
uint64_t length;
|
||||
uint32_t type;
|
||||
};
|
||||
} __attribute((__packed__, __aligned__(4)));
|
||||
|
||||
struct e820_table {
|
||||
uint32_t count;
|
||||
struct e820_entry entry[E820_NR_ENTRIES];
|
||||
};
|
||||
} __attribute((__packed__, __aligned__(4)));
|
||||
|
||||
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 */
|
||||
case 0x400:
|
||||
case 0x401:
|
||||
fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
|
||||
exit(1);
|
||||
/* used to be panic, now unused */
|
||||
break;
|
||||
case 0x402:
|
||||
case 0x403:
|
||||
#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 index = e820_table.count;
|
||||
int index = le32_to_cpu(e820_table.count);
|
||||
struct e820_entry *entry;
|
||||
|
||||
if (index >= E820_NR_ENTRIES)
|
||||
return -EBUSY;
|
||||
entry = &e820_table.entry[index];
|
||||
entry = &e820_table.entry[index++];
|
||||
|
||||
entry->address = address;
|
||||
entry->length = length;
|
||||
entry->type = type;
|
||||
entry->address = cpu_to_le64(address);
|
||||
entry->length = cpu_to_le64(length);
|
||||
entry->type = cpu_to_le32(type);
|
||||
|
||||
e820_table.count++;
|
||||
return e820_table.count;
|
||||
e820_table.count = cpu_to_le32(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
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__);
|
||||
} else if (std_vga_enabled) {
|
||||
if (pci_bus) {
|
||||
pci_vga_init(pci_bus, 0, 0);
|
||||
pci_vga_init(pci_bus);
|
||||
} else {
|
||||
isa_vga_init();
|
||||
}
|
||||
|
|
3
hw/pc.h
3
hw/pc.h
|
@ -154,8 +154,7 @@ enum vga_retrace_method {
|
|||
extern enum vga_retrace_method vga_retrace_method;
|
||||
|
||||
int isa_vga_init(void);
|
||||
int pci_vga_init(PCIBus *bus,
|
||||
unsigned long vga_bios_offset, int vga_bios_size);
|
||||
int pci_vga_init(PCIBus *bus);
|
||||
int isa_vga_mm_init(target_phys_addr_t vram_base,
|
||||
target_phys_addr_t ctrl_base, int it_shift);
|
||||
|
||||
|
|
34
hw/pc_piix.c
34
hw/pc_piix.c
|
@ -212,7 +212,7 @@ static void pc_init_isa(ram_addr_t ram_size,
|
|||
}
|
||||
|
||||
static QEMUMachine pc_machine = {
|
||||
.name = "pc-0.13",
|
||||
.name = "pc-0.14",
|
||||
.alias = "pc",
|
||||
.desc = "Standard PC",
|
||||
.init = pc_init_pci,
|
||||
|
@ -220,6 +220,29 @@ static QEMUMachine pc_machine = {
|
|||
.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 = {
|
||||
.name = "pc-0.12",
|
||||
.desc = "Standard PC",
|
||||
|
@ -234,6 +257,14 @@ static QEMUMachine pc_machine_v0_12 = {
|
|||
.driver = "virtio-serial-pci",
|
||||
.property = "vectors",
|
||||
.value = stringify(0),
|
||||
},{
|
||||
.driver = "VGA",
|
||||
.property = "rombar",
|
||||
.value = stringify(0),
|
||||
},{
|
||||
.driver = "vmware-svga",
|
||||
.property = "rombar",
|
||||
.value = stringify(0),
|
||||
},
|
||||
{ /* end of list */ }
|
||||
}
|
||||
|
@ -331,6 +362,7 @@ static QEMUMachine isapc_machine = {
|
|||
static void pc_machine_init(void)
|
||||
{
|
||||
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_11);
|
||||
qemu_register_machine(&pc_machine_v0_10);
|
||||
|
|
|
@ -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)
|
316
hw/pcnet.c
316
hw/pcnet.c
|
@ -35,9 +35,8 @@
|
|||
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
|
||||
*/
|
||||
|
||||
#include "pci.h"
|
||||
#include "qdev.h"
|
||||
#include "net.h"
|
||||
#include "loader.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "qemu_socket.h"
|
||||
|
||||
|
@ -52,11 +51,6 @@
|
|||
//#define PCNET_DEBUG_MATCH
|
||||
|
||||
|
||||
typedef struct {
|
||||
PCIDevice pci_dev;
|
||||
PCNetState state;
|
||||
} PCIPCNetState;
|
||||
|
||||
struct qemu_ether_header {
|
||||
uint8_t ether_dhost[6];
|
||||
uint8_t ether_shost[6];
|
||||
|
@ -704,7 +698,6 @@ static void pcnet_poll_timer(void *opaque);
|
|||
static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
|
||||
static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
|
||||
static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
|
||||
static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
|
||||
|
||||
static void pcnet_s_reset(PCNetState *s)
|
||||
{
|
||||
|
@ -1048,9 +1041,10 @@ ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
|
|||
int crc_err = 0;
|
||||
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;
|
||||
|
||||
}
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("pcnet_receive size=%d\n", size);
|
||||
#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;
|
||||
rap &= 127;
|
||||
|
@ -1594,27 +1588,6 @@ void pcnet_h_reset(void *opaque)
|
|||
pcnet_poll_timer(s);
|
||||
}
|
||||
|
||||
static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
/* Check APROMWE bit to enable write access */
|
||||
if (pcnet_bcr_readw(s,2) & 0x100)
|
||||
s->prom[addr & 15] = val;
|
||||
}
|
||||
|
||||
static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
uint32_t val = s->prom[addr & 15];
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
|
@ -1667,7 +1640,7 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
|
|||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
pcnet_poll_timer(s);
|
||||
|
@ -1697,7 +1670,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
|||
pcnet_update_irq(s);
|
||||
}
|
||||
|
||||
static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
|
||||
uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
uint32_t val = -1;
|
||||
|
@ -1726,125 +1699,6 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
|
|||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
|
||||
pcibus_t addr, pcibus_t size, int type)
|
||||
{
|
||||
PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
|
||||
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
|
||||
addr, size);
|
||||
#endif
|
||||
|
||||
register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
|
||||
register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
|
||||
|
||||
register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
|
||||
register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
|
||||
register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
|
||||
register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
|
||||
}
|
||||
|
||||
static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
|
||||
val);
|
||||
#endif
|
||||
if (!(addr & 0x10))
|
||||
pcnet_aprom_writeb(d, addr & 0x0f, val);
|
||||
}
|
||||
|
||||
static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
uint32_t val = -1;
|
||||
if (!(addr & 0x10))
|
||||
val = pcnet_aprom_readb(d, addr & 0x0f);
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
|
||||
val & 0xff);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
|
||||
val);
|
||||
#endif
|
||||
if (addr & 0x10)
|
||||
pcnet_ioport_writew(d, addr & 0x0f, val);
|
||||
else {
|
||||
addr &= 0x0f;
|
||||
pcnet_aprom_writeb(d, addr, val & 0xff);
|
||||
pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
uint32_t val = -1;
|
||||
if (addr & 0x10)
|
||||
val = pcnet_ioport_readw(d, addr & 0x0f);
|
||||
else {
|
||||
addr &= 0x0f;
|
||||
val = pcnet_aprom_readb(d, addr+1);
|
||||
val <<= 8;
|
||||
val |= pcnet_aprom_readb(d, addr);
|
||||
}
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
|
||||
val & 0xffff);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
|
||||
val);
|
||||
#endif
|
||||
if (addr & 0x10)
|
||||
pcnet_ioport_writel(d, addr & 0x0f, val);
|
||||
else {
|
||||
addr &= 0x0f;
|
||||
pcnet_aprom_writeb(d, addr, val & 0xff);
|
||||
pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
|
||||
pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
|
||||
pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
uint32_t val;
|
||||
if (addr & 0x10)
|
||||
val = pcnet_ioport_readl(d, addr & 0x0f);
|
||||
else {
|
||||
addr &= 0x0f;
|
||||
val = pcnet_aprom_readb(d, addr+3);
|
||||
val <<= 8;
|
||||
val |= pcnet_aprom_readb(d, addr+2);
|
||||
val <<= 8;
|
||||
val |= pcnet_aprom_readb(d, addr+1);
|
||||
val <<= 8;
|
||||
val |= pcnet_aprom_readb(d, addr);
|
||||
}
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
|
||||
val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static bool is_version_2(void *opaque, int version_id)
|
||||
{
|
||||
return version_id == 2;
|
||||
|
@ -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)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
|
|
|
@ -32,6 +32,9 @@ struct PCNetState_st {
|
|||
void pcnet_h_reset(void *opaque);
|
||||
void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
|
||||
void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
|
||||
uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
|
||||
int pcnet_can_receive(VLANClientState *nc);
|
||||
ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_);
|
||||
void pcnet_common_cleanup(PCNetState *d);
|
||||
|
|
|
@ -316,7 +316,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
|
|||
machine_arch = ARCH_MAC99;
|
||||
}
|
||||
/* 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],
|
||||
serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
|
||||
|
|
|
@ -227,7 +227,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
|
|||
}
|
||||
pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
|
||||
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],
|
||||
serial_hds[1], ESCC_CLOCK, 4);
|
||||
|
|
|
@ -694,7 +694,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
|
|||
cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
|
||||
|
||||
/* init basic PC hardware */
|
||||
pci_vga_init(pci_bus, 0, 0);
|
||||
pci_vga_init(pci_bus);
|
||||
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
|
||||
// pit = pit_init(0x40, i8259[0]);
|
||||
rtc_init(2000, NULL);
|
||||
|
|
|
@ -108,7 +108,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
|
|||
int res = 0, unit;
|
||||
|
||||
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);
|
||||
if (dinfo == NULL) {
|
||||
continue;
|
||||
|
@ -123,16 +123,6 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
|
|||
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 *req;
|
||||
|
|
|
@ -111,18 +111,20 @@
|
|||
#define BLANK 0xa1
|
||||
|
||||
/*
|
||||
* Status codes
|
||||
* SAM Status codes
|
||||
*/
|
||||
|
||||
#define GOOD 0x00
|
||||
#define CHECK_CONDITION 0x01
|
||||
#define CONDITION_GOOD 0x02
|
||||
#define BUSY 0x04
|
||||
#define INTERMEDIATE_GOOD 0x08
|
||||
#define INTERMEDIATE_C_GOOD 0x0a
|
||||
#define RESERVATION_CONFLICT 0x0c
|
||||
#define COMMAND_TERMINATED 0x11
|
||||
#define QUEUE_FULL 0x14
|
||||
#define CHECK_CONDITION 0x02
|
||||
#define CONDITION_GOOD 0x04
|
||||
#define BUSY 0x08
|
||||
#define INTERMEDIATE_GOOD 0x10
|
||||
#define INTERMEDIATE_C_GOOD 0x14
|
||||
#define RESERVATION_CONFLICT 0x18
|
||||
#define COMMAND_TERMINATED 0x22
|
||||
#define TASK_SET_FULL 0x28
|
||||
#define ACA_ACTIVE 0x30
|
||||
#define TASK_ABORTED 0x40
|
||||
|
||||
#define STATUS_MASK 0x3e
|
||||
|
||||
|
|
276
hw/scsi-disk.c
276
hw/scsi-disk.c
|
@ -41,10 +41,18 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
|
|||
#define SCSI_DMA_BUF_SIZE 131072
|
||||
#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 SCSISense {
|
||||
uint8_t key;
|
||||
} SCSISense;
|
||||
|
||||
typedef struct SCSIDiskReq {
|
||||
SCSIRequest req;
|
||||
/* ??? We should probably keep track of whether the data transfer is
|
||||
|
@ -68,8 +76,12 @@ struct SCSIDiskState
|
|||
QEMUBH *bh;
|
||||
char *version;
|
||||
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,
|
||||
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));
|
||||
}
|
||||
|
||||
static void scsi_req_set_status(SCSIRequest *req, int status, int sense_code)
|
||||
static void scsi_disk_clear_sense(SCSIDiskState *s)
|
||||
{
|
||||
req->status = status;
|
||||
scsi_dev_set_sense(req->dev, sense_code);
|
||||
memset(&s->sense, 0, sizeof(s->sense));
|
||||
}
|
||||
|
||||
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. */
|
||||
|
@ -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",
|
||||
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_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)
|
||||
{
|
||||
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
|
||||
int n;
|
||||
|
||||
r->req.aiocb = NULL;
|
||||
|
||||
if (ret) {
|
||||
DPRINTF("IO error\n");
|
||||
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
|
||||
scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
|
||||
return;
|
||||
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
SCSIDiskReq *r;
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||
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) {
|
||||
DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
|
||||
r->sector_count = 0;
|
||||
|
@ -167,6 +187,9 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
|
|||
return;
|
||||
}
|
||||
|
||||
/* No data transfer may already be in progress */
|
||||
assert(r->req.aiocb == NULL);
|
||||
|
||||
n = r->sector_count;
|
||||
if (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);
|
||||
r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
|
||||
scsi_read_complete, r);
|
||||
if (r->req.aiocb == NULL)
|
||||
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
|
||||
r->sector += n;
|
||||
r->sector_count -= n;
|
||||
if (r->req.aiocb == NULL) {
|
||||
scsi_read_complete(r, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
BlockErrorAction action = bdrv_get_on_error(s->bs, 0);
|
||||
BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
|
||||
|| 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);
|
||||
} 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,
|
||||
HARDWARE_ERROR);
|
||||
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, 0);
|
||||
bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -214,8 +260,9 @@ static void scsi_write_complete(void * opaque, int ret)
|
|||
r->req.aiocb = NULL;
|
||||
|
||||
if (ret) {
|
||||
if (scsi_handle_write_error(r, -ret))
|
||||
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t n;
|
||||
|
||||
/* No data transfer may already be in progress */
|
||||
assert(r->req.aiocb == NULL);
|
||||
|
||||
n = r->iov.iov_len / 512;
|
||||
if (n) {
|
||||
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
|
||||
r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
|
||||
scsi_write_complete, r);
|
||||
if (r->req.aiocb == NULL)
|
||||
scsi_command_complete(r, CHECK_CONDITION,
|
||||
HARDWARE_ERROR);
|
||||
if (r->req.aiocb == NULL) {
|
||||
scsi_write_complete(r, -EIO);
|
||||
}
|
||||
} else {
|
||||
/* Invoke completion routine to fetch data from host. */
|
||||
scsi_write_complete(r, 0);
|
||||
|
@ -268,9 +318,6 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (r->req.aiocb)
|
||||
BADF("Data transfer already in progress\n");
|
||||
|
||||
scsi_write_request(r);
|
||||
|
||||
return 0;
|
||||
|
@ -288,8 +335,25 @@ static void scsi_dma_restart_bh(void *opaque)
|
|||
QTAILQ_FOREACH(req, &s->qdev.requests, next) {
|
||||
r = DO_UPCAST(SCSIDiskReq, req, req);
|
||||
if (r->status & SCSI_REQ_STATUS_RETRY) {
|
||||
r->status &= ~SCSI_REQ_STATUS_RETRY;
|
||||
scsi_write_request(r);
|
||||
int status = r->status;
|
||||
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) {
|
||||
case 0x00: /* Supported page codes, mandatory */
|
||||
{
|
||||
int pages;
|
||||
DPRINTF("Inquiry EVPD[Supported pages] "
|
||||
"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++] = 0x80; // unit serial number
|
||||
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;
|
||||
|
||||
}
|
||||
case 0x80: /* Device serial number, optional */
|
||||
{
|
||||
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] "
|
||||
"buffer size %zd\n", req->cmd.xfer);
|
||||
|
||||
outbuf[buflen++] = 3 + id_len;
|
||||
outbuf[buflen++] = 4 + id_len;
|
||||
outbuf[buflen++] = 0x2; // ASCII
|
||||
outbuf[buflen++] = 0; // not officially assigned
|
||||
outbuf[buflen++] = 0; // reserved
|
||||
|
@ -404,6 +473,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||
unsigned int opt_io_size =
|
||||
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 */
|
||||
outbuf[3] = buflen = 0x3c;
|
||||
|
||||
|
@ -747,11 +821,13 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
|
|||
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);
|
||||
uint64_t nb_sectors;
|
||||
int buflen = 0;
|
||||
int ret;
|
||||
|
||||
switch (req->cmd.buf[0]) {
|
||||
case TEST_UNIT_READY:
|
||||
|
@ -763,7 +839,7 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
|
|||
goto illegal_request;
|
||||
memset(outbuf, 0, 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);
|
||||
buflen = 18;
|
||||
outbuf[7] = 10;
|
||||
|
@ -773,8 +849,8 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
|
|||
}
|
||||
outbuf[0] = 0xf0;
|
||||
outbuf[1] = 0;
|
||||
outbuf[2] = req->dev->sense.key;
|
||||
scsi_dev_clear_sense(req->dev);
|
||||
outbuf[2] = s->sense.key;
|
||||
scsi_disk_clear_sense(s);
|
||||
break;
|
||||
case INQUIRY:
|
||||
buflen = scsi_disk_emulate_inquiry(req, outbuf);
|
||||
|
@ -842,7 +918,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
|
|||
buflen = 8;
|
||||
break;
|
||||
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;
|
||||
case GET_CONFIGURATION:
|
||||
memset(outbuf, 0, 8);
|
||||
|
@ -902,16 +983,16 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
|
|||
default:
|
||||
goto illegal_request;
|
||||
}
|
||||
scsi_req_set_status(req, GOOD, NO_SENSE);
|
||||
scsi_req_set_status(r, GOOD, NO_SENSE);
|
||||
return buflen;
|
||||
|
||||
not_ready:
|
||||
scsi_req_set_status(req, CHECK_CONDITION, NOT_READY);
|
||||
return 0;
|
||||
scsi_command_complete(r, CHECK_CONDITION, NOT_READY);
|
||||
return -1;
|
||||
|
||||
illegal_request:
|
||||
scsi_req_set_status(req, CHECK_CONDITION, ILLEGAL_REQUEST);
|
||||
return 0;
|
||||
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
|
||||
uint64_t lba;
|
||||
uint32_t len;
|
||||
int cmdlen;
|
||||
int is_write;
|
||||
uint8_t command;
|
||||
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;
|
||||
is_write = 0;
|
||||
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
|
||||
switch (command >> 5) {
|
||||
case 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:
|
||||
|
||||
if (scsi_req_parse(&r->req, buf) != 0) {
|
||||
BADF("Unsupported command length, command %x\n", command);
|
||||
goto fail;
|
||||
}
|
||||
#ifdef DEBUG_SCSI
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < cmdlen; i++) {
|
||||
for (i = 1; i < r->req.cmd.len; i++) {
|
||||
printf(" 0x%02x", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#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) {
|
||||
/* Only LUN 0 supported. */
|
||||
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 VERIFY:
|
||||
case REZERO_UNIT:
|
||||
rc = scsi_disk_emulate_command(&r->req, outbuf);
|
||||
if (rc > 0) {
|
||||
r->iov.iov_len = rc;
|
||||
} else {
|
||||
scsi_req_complete(&r->req);
|
||||
scsi_remove_request(r);
|
||||
rc = scsi_disk_emulate_command(r, outbuf);
|
||||
if (rc < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->iov.iov_len = rc;
|
||||
break;
|
||||
case READ_6:
|
||||
case READ_10:
|
||||
case READ_12:
|
||||
case READ_16:
|
||||
DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len);
|
||||
if (lba > s->max_lba)
|
||||
len = r->req.cmd.xfer / d->blocksize;
|
||||
DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
|
||||
if (r->req.cmd.lba > s->max_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;
|
||||
break;
|
||||
case WRITE_6:
|
||||
|
@ -1045,42 +1089,45 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
|
|||
case WRITE_VERIFY:
|
||||
case WRITE_VERIFY_12:
|
||||
case WRITE_VERIFY_16:
|
||||
len = r->req.cmd.xfer / d->blocksize;
|
||||
DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
|
||||
(command & 0xe) == 0xe ? "And Verify " : "", lba, len);
|
||||
if (lba > s->max_lba)
|
||||
(command & 0xe) == 0xe ? "And Verify " : "",
|
||||
r->req.cmd.lba, len);
|
||||
if (r->req.cmd.lba > s->max_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;
|
||||
is_write = 1;
|
||||
break;
|
||||
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.
|
||||
Allow the mode parameter header + block descriptors only. */
|
||||
if (len > 12) {
|
||||
if (r->req.cmd.xfer > 12) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
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.
|
||||
Allow the mode parameter header + block descriptors only. */
|
||||
if (len > 16) {
|
||||
if (r->req.cmd.xfer > 16) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case SEEK_6:
|
||||
case SEEK_10:
|
||||
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, lba);
|
||||
if (lba > s->max_lba) {
|
||||
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
|
||||
r->req.cmd.lba);
|
||||
if (r->req.cmd.lba > s->max_lba) {
|
||||
goto illegal_lba;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||
fail:
|
||||
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
|
||||
return 0;
|
||||
return 0;
|
||||
illegal_lba:
|
||||
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
|
||||
return 0;
|
||||
|
@ -1152,11 +1199,6 @@ static int scsi_disk_initfn(SCSIDevice *dev)
|
|||
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) {
|
||||
/* try to fall back to value set with legacy -drive serial=... */
|
||||
dinfo = drive_get_by_blockdev(s->bs);
|
||||
|
|
|
@ -96,17 +96,17 @@ static void scsi_command_complete(void *opaque, int ret)
|
|||
s->senselen = r->io_header.sb_len_wr;
|
||||
|
||||
if (ret != 0)
|
||||
r->req.status = BUSY << 1;
|
||||
r->req.status = BUSY;
|
||||
else {
|
||||
if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
|
||||
r->req.status = BUSY << 1;
|
||||
r->req.status = BUSY;
|
||||
BADF("Driver Timeout\n");
|
||||
} else if (r->io_header.status)
|
||||
r->req.status = r->io_header.status;
|
||||
else if (s->driver_status & SG_ERR_DRIVER_SENSE)
|
||||
r->req.status = CHECK_CONDITION << 1;
|
||||
r->req.status = CHECK_CONDITION;
|
||||
else
|
||||
r->req.status = GOOD << 1;
|
||||
r->req.status = GOOD;
|
||||
}
|
||||
DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
|
||||
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->driver_status = SG_ERR_DRIVER_SENSE;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
11
hw/scsi.h
11
hw/scsi.h
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "qdev.h"
|
||||
#include "block.h"
|
||||
#include "blockdev.h"
|
||||
#include "block_int.h"
|
||||
|
||||
#define SCSI_CMD_BUF_SIZE 16
|
||||
|
@ -25,10 +26,6 @@ enum SCSIXferMode {
|
|||
SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */
|
||||
};
|
||||
|
||||
typedef struct SCSISense {
|
||||
uint8_t key;
|
||||
} SCSISense;
|
||||
|
||||
typedef struct SCSIRequest {
|
||||
SCSIBus *bus;
|
||||
SCSIDevice *dev;
|
||||
|
@ -56,7 +53,6 @@ struct SCSIDevice
|
|||
QTAILQ_HEAD(, SCSIRequest) requests;
|
||||
int blocksize;
|
||||
int type;
|
||||
struct SCSISense sense;
|
||||
};
|
||||
|
||||
/* cdrom.c */
|
||||
|
@ -86,7 +82,7 @@ struct SCSIBus {
|
|||
int tcq, ndev;
|
||||
scsi_completionfn complete;
|
||||
|
||||
SCSIDevice *devs[8];
|
||||
SCSIDevice *devs[MAX_SCSI_DEVS];
|
||||
};
|
||||
|
||||
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);
|
||||
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_find(SCSIDevice *d, uint32_t tag);
|
||||
void scsi_req_free(SCSIRequest *req);
|
||||
|
|
|
@ -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_bus3);
|
||||
isa_mem_base = APB_PCI_IO_BASE;
|
||||
pci_vga_init(pci_bus, 0, 0);
|
||||
pci_vga_init(pci_bus);
|
||||
|
||||
// XXX Should be pci_bus3
|
||||
pci_ebus_init(pci_bus, -1);
|
||||
|
|
|
@ -1142,7 +1142,7 @@ static int usb_net_handle_control(USBDevice *dev, int request, int value,
|
|||
break;
|
||||
|
||||
default:
|
||||
if (usb_net_stringtable[value & 0xff]) {
|
||||
if (ARRAY_SIZE(usb_net_stringtable) > (value & 0xff)) {
|
||||
ret = set_usb_string(data,
|
||||
usb_net_stringtable[value & 0xff]);
|
||||
break;
|
||||
|
|
44
hw/vga-pci.c
44
hw/vga-pci.c
|
@ -52,14 +52,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
|
|||
{
|
||||
PCIVGAState *d = (PCIVGAState *)pci_dev;
|
||||
VGACommonState *s = &d->vga;
|
||||
if (region_num == PCI_ROM_SLOT) {
|
||||
cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
|
||||
} else {
|
||||
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
|
||||
s->map_addr = addr;
|
||||
s->map_end = addr + s->vram_size;
|
||||
vga_dirty_log_start(s);
|
||||
}
|
||||
|
||||
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
|
||||
s->map_addr = addr;
|
||||
s->map_end = addr + s->vram_size;
|
||||
vga_dirty_log_start(s);
|
||||
}
|
||||
|
||||
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_BASE_ADDRESS_MEM_PREFETCH, vga_map);
|
||||
|
||||
if (s->bios_size) {
|
||||
unsigned int bios_total_size;
|
||||
/* must be a power of two */
|
||||
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);
|
||||
if (!dev->rom_bar) {
|
||||
/* compatibility with pc-0.13 and older */
|
||||
vga_init_vbe(s);
|
||||
}
|
||||
|
||||
vga_init_vbe(s);
|
||||
/* ROM BIOS */
|
||||
rom_add_vga(VGABIOS_FILENAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pci_vga_init(PCIBus *bus,
|
||||
unsigned long vga_bios_offset, int vga_bios_size)
|
||||
int pci_vga_init(PCIBus *bus)
|
||||
{
|
||||
PCIDevice *dev;
|
||||
|
||||
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);
|
||||
|
||||
pci_create_simple(bus, -1, "VGA");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -130,11 +112,7 @@ static PCIDeviceInfo vga_info = {
|
|||
.qdev.vmsd = &vmstate_vga_pci,
|
||||
.init = pci_vga_initfn,
|
||||
.config_write = pci_vga_write_config,
|
||||
.qdev.props = (Property[]) {
|
||||
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(),
|
||||
}
|
||||
.romfile = "vgabios-stdvga.bin",
|
||||
};
|
||||
|
||||
static void vga_register(void)
|
||||
|
|
2
hw/vga.c
2
hw/vga.c
|
@ -1934,8 +1934,6 @@ void vga_common_reset(VGACommonState *s)
|
|||
s->map_addr = 0;
|
||||
s->map_end = 0;
|
||||
s->lfb_vram_mapped = 0;
|
||||
s->bios_offset = 0;
|
||||
s->bios_size = 0;
|
||||
s->sr_index = 0;
|
||||
memset(s->sr, '\0', sizeof(s->sr));
|
||||
s->gr_index = 0;
|
||||
|
|
|
@ -112,8 +112,6 @@ typedef struct VGACommonState {
|
|||
uint32_t map_addr;
|
||||
uint32_t map_end;
|
||||
uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
|
||||
uint32_t bios_offset;
|
||||
uint32_t bios_size;
|
||||
uint32_t latch;
|
||||
uint8_t sr_index;
|
||||
uint8_t sr[256];
|
||||
|
|
|
@ -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);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
fprintf(stderr, "virtio-blk header not in correct element\n");
|
||||
error_report("virtio-blk header not in correct element");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,8 +120,8 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
|
|||
if (!n->vhost_started) {
|
||||
int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "unable to start vhost net: %d: "
|
||||
"falling back on userspace virtio\n", -r);
|
||||
error_report("unable to start vhost net: %d: "
|
||||
"falling back on userspace virtio", -r);
|
||||
} else {
|
||||
n->vhost_started = 1;
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
|
|||
uint8_t 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);
|
||||
}
|
||||
|
||||
|
@ -353,7 +353,7 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
|
|||
uint16_t 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;
|
||||
}
|
||||
|
||||
|
@ -381,13 +381,13 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
|||
|
||||
while (virtqueue_pop(vq, &elem)) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (elem.out_sg[0].iov_len < sizeof(ctrl) ||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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 (i == 0)
|
||||
return -1;
|
||||
fprintf(stderr, "virtio-net unexpected empty queue: "
|
||||
error_report("virtio-net unexpected empty queue: "
|
||||
"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,
|
||||
guest_hdr_len, host_hdr_len, n->vdev.guest_features);
|
||||
exit(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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -630,12 +630,11 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
|
|||
* Otherwise, drop it. */
|
||||
if (!n->mergeable_rx_bufs && offset < size) {
|
||||
#if 0
|
||||
fprintf(stderr, "virtio-net truncated non-mergeable packet: "
|
||||
|
||||
"i %zd mergeable %d offset %zd, size %zd, "
|
||||
"guest hdr len %zd, host hdr len %zd\n",
|
||||
i, n->mergeable_rx_bufs,
|
||||
offset, size, guest_hdr_len, host_hdr_len);
|
||||
error_report("virtio-net truncated non-mergeable packet: "
|
||||
"i %zd mergeable %d offset %zd, size %zd, "
|
||||
"guest hdr len %zd, host hdr len %zd",
|
||||
i, n->mergeable_rx_bufs,
|
||||
offset, size, guest_hdr_len, host_hdr_len);
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
@ -695,7 +694,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
|
|||
sizeof(struct virtio_net_hdr);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
|
||||
fprintf(stderr, "virtio-net: "
|
||||
"Unknown option tx=%s, valid options: \"timer\" \"bh\"\n",
|
||||
net->tx);
|
||||
fprintf(stderr, "Defaulting to \"bh\"\n");
|
||||
error_report("virtio-net: "
|
||||
"Unknown option tx=%s, valid options: \"timer\" \"bh\"",
|
||||
net->tx);
|
||||
error_report("Defaulting to \"bh\"");
|
||||
}
|
||||
|
||||
if (net->tx && !strcmp(net->tx, "timer")) {
|
||||
|
|
|
@ -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);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: unexpected address 0x%x value 0x%x\n",
|
||||
__func__, addr, val);
|
||||
error_report("%s: unexpected address 0x%x value 0x%x",
|
||||
__func__, addr, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -684,12 +684,14 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev)
|
|||
VirtIODevice *vdev;
|
||||
|
||||
vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
|
||||
vdev->nvectors = proxy->nvectors;
|
||||
virtio_init_pci(proxy, vdev,
|
||||
PCI_VENDOR_ID_REDHAT_QUMRANET,
|
||||
0x1009,
|
||||
0x2,
|
||||
0x00);
|
||||
|
||||
/* make the actual value visible */
|
||||
proxy->nvectors = vdev->nvectors;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -758,6 +760,7 @@ static PCIDeviceInfo virtio_info[] = {
|
|||
.qdev.size = sizeof(VirtIOPCIProxy),
|
||||
.init = virtio_9p_init_pci,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
|
||||
DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
|
||||
DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
|
||||
|
|
|
@ -114,14 +114,12 @@ struct pci_vmsvga_state_s {
|
|||
# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
|
||||
# define SVGA_IO_MUL 1
|
||||
# define SVGA_FIFO_SIZE 0x10000
|
||||
# define SVGA_MEM_BASE 0xe0000000
|
||||
# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2
|
||||
#else
|
||||
# define SVGA_ID SVGA_ID_1
|
||||
# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
|
||||
# define SVGA_IO_MUL 4
|
||||
# define SVGA_FIFO_SIZE 0x10000
|
||||
# define SVGA_MEM_BASE 0xe0000000
|
||||
# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA
|
||||
#endif
|
||||
|
||||
|
@ -1219,10 +1217,6 @@ static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
|
|||
vga_init(&s->vga);
|
||||
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
|
||||
|
||||
vga_init_vbe(&s->vga);
|
||||
|
||||
rom_add_vga(VGABIOS_FILENAME);
|
||||
|
||||
vmsvga_reset(s);
|
||||
}
|
||||
|
||||
|
@ -1307,6 +1301,11 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1320,6 +1319,7 @@ static PCIDeviceInfo vmsvga_info = {
|
|||
.qdev.size = sizeof(struct pci_vmsvga_state_s),
|
||||
.qdev.vmsd = &vmstate_vmware_vga,
|
||||
.init = pci_vmsvga_initfn,
|
||||
.romfile = "vgabios-vmware.bin",
|
||||
};
|
||||
|
||||
static void vmsvga_register(void)
|
||||
|
|
|
@ -181,6 +181,10 @@ static int ioreq_parse(struct ioreq *ioreq)
|
|||
ioreq->prot = PROT_WRITE; /* to memory */
|
||||
break;
|
||||
case BLKIF_OP_WRITE_BARRIER:
|
||||
if (!ioreq->req.nr_segments) {
|
||||
ioreq->presync = 1;
|
||||
return 0;
|
||||
}
|
||||
if (!syncwrite)
|
||||
ioreq->presync = ioreq->postsync = 1;
|
||||
/* fall through */
|
||||
|
@ -305,7 +309,7 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
|
|||
int i, rc, len = 0;
|
||||
off_t pos;
|
||||
|
||||
if (ioreq_map(ioreq) == -1)
|
||||
if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
|
||||
goto err;
|
||||
if (ioreq->presync)
|
||||
bdrv_flush(blkdev->bs);
|
||||
|
@ -329,6 +333,8 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
|
|||
break;
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_WRITE_BARRIER:
|
||||
if (!ioreq->req.nr_segments)
|
||||
break;
|
||||
pos = ioreq->start;
|
||||
for (i = 0; i < ioreq->v.niov; i++) {
|
||||
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;
|
||||
|
||||
if (ioreq_map(ioreq) == -1)
|
||||
if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
|
||||
goto err;
|
||||
|
||||
ioreq->aio_inflight++;
|
||||
|
@ -403,6 +409,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
|||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_WRITE_BARRIER:
|
||||
ioreq->aio_inflight++;
|
||||
if (!ioreq->req.nr_segments)
|
||||
break;
|
||||
bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
|
||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||
qemu_aio_complete, ioreq);
|
||||
|
|
64
ioport.c
64
ioport.c
|
@ -174,6 +174,70 @@ int register_ioport_write(pio_addr_t start, int length, int size,
|
|||
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)
|
||||
{
|
||||
int i;
|
||||
|
|
2
ioport.h
2
ioport.h
|
@ -25,6 +25,7 @@
|
|||
#define IOPORT_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "iorange.h"
|
||||
|
||||
typedef uint32_t pio_addr_t;
|
||||
#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 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,
|
||||
IOPortReadFunc *func, void *opaque);
|
||||
int register_ioport_write(pio_addr_t start, int length, int size,
|
||||
|
|
|
@ -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
|
|
@ -3071,11 +3071,11 @@ struct target_stack_t {
|
|||
};
|
||||
|
||||
struct target_ucontext {
|
||||
abi_ulong uc_flags;
|
||||
abi_ulong uc_link;
|
||||
struct target_stack_t uc_stack;
|
||||
struct target_sigcontext sc;
|
||||
uint32_t extramask[TARGET_NSIG_WORDS - 1];
|
||||
abi_ulong tuc_flags;
|
||||
abi_ulong tuc_link;
|
||||
struct target_stack_t tuc_stack;
|
||||
struct target_sigcontext tuc_mcontext;
|
||||
uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
|
||||
};
|
||||
|
||||
/* Signal frames. */
|
||||
|
@ -3189,7 +3189,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
goto badframe;
|
||||
|
||||
/* 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)
|
||||
goto badframe;
|
||||
|
||||
|
@ -3198,7 +3198,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
|||
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
|
||||
already in userspace. */
|
||||
|
@ -3261,7 +3261,7 @@ long do_sigreturn(CPUState *env)
|
|||
goto badframe;
|
||||
|
||||
/* 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;
|
||||
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||
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);
|
||||
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
|
||||
rtb insn so setup r14 for that. */
|
||||
env->regs[14] = env->sregs[SR_PC];
|
||||
|
|
|
@ -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
|
38
monitor.c
38
monitor.c
|
@ -491,6 +491,44 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mon_set_cpu(int cpu_index);
|
||||
static void handle_user_command(Monitor *mon, const char *cmdline);
|
||||
|
||||
static int do_hmp_passthrough(Monitor *mon, const QDict *params,
|
||||
QObject **ret_data)
|
||||
{
|
||||
int ret = 0;
|
||||
Monitor *old_mon, hmp;
|
||||
CharDriverState mchar;
|
||||
|
||||
memset(&hmp, 0, sizeof(hmp));
|
||||
qemu_chr_init_mem(&mchar);
|
||||
hmp.chr = &mchar;
|
||||
|
||||
old_mon = cur_mon;
|
||||
cur_mon = &hmp;
|
||||
|
||||
if (qdict_haskey(params, "cpu-index")) {
|
||||
ret = mon_set_cpu(qdict_get_int(params, "cpu-index"));
|
||||
if (ret < 0) {
|
||||
cur_mon = old_mon;
|
||||
qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
handle_user_command(&hmp, qdict_get_str(params, "command-line"));
|
||||
cur_mon = old_mon;
|
||||
|
||||
if (qemu_chr_mem_osize(hmp.chr) > 0) {
|
||||
*ret_data = QOBJECT(qemu_chr_mem_to_qs(hmp.chr));
|
||||
}
|
||||
|
||||
out:
|
||||
qemu_chr_close_mem(hmp.chr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compare_cmd(const char *name, const char *list)
|
||||
{
|
||||
const char *p, *pstart;
|
||||
|
|
|
@ -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 ))
|
||||
|
||||
# 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
|
||||
# add each byte's value to sum
|
||||
sum=`expr $sum + $i`
|
||||
sum=`expr \( $sum + $i \) % 256`
|
||||
done
|
||||
|
||||
sum=$(( $sum % 256 ))
|
||||
sum=$(( 256 - $sum ))
|
||||
sum=$(( (256 - $sum) % 256 ))
|
||||
sum_octal=$( printf "%o" $sum )
|
||||
|
||||
# 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
Loading…
Reference in New Issue