[Spice-commits] 188 commits - MAINTAINERS Makefile Makefile.objs Makefile.target aio.c audio/audio.c audio/audio_int.h audio/audio_template.h audio/paaudio.c audio/spiceaudio.c block.c block/cow.c block/curl.c block/iscsi.c block/nbd.c block/qcow2-cluster.c block/qcow2-refcount.c block/qcow2-snapshot.c block/qcow2.c block/qcow2.h block/rbd.c block/sheepdog.c block_int.h cmd.c configure docs/specs error.c exec-all.h fpu/softfloat.c gdbstub.c hmp-commands.hx hw/ac97.c hw/arm_mptimer.c hw/e1000.c hw/ide hw/m48t59.c hw/pc.c hw/pc_piix.c hw/pflash_cfi01.c hw/ptimer.c hw/qdev-monitor.c hw/qdev.c hw/qxl-render.c hw/qxl.c hw/qxl.h hw/realview.c hw/scsi-bus.c hw/scsi-defs.h hw/scsi-disk.c hw/usb hw/usb.h hw/versatile_i2c.c hw/versatilepb.c hw/virtio-scsi.c hw/virtio.c hw/virtio.h hw/xen.h hw/xen_common.h include/qemu linux-aio.c nbd.c nbd.h pc-bios/bios.bin posix-aio-compat.c qapi-schema.json qapi/qmp-input-visitor.c qemu-aio.h qemu-char.c qemu-coroutine-sleep.c qemu-ga.c qemu-img.c qemu-io. c qemu-nbd.c qemu-tool.c qga/commands-posix.c qmp-commands.hx qom/container.c qtest.c qtest.h roms/seabios scripts/create_config scripts/tracetool scripts/tracetool.py spice-qemu-char.c target-arm/cpu-qom.h target-arm/cpu.c target-arm/cpu.h target-arm/helper.c target-cris/cpu-qom.h target-cris/cpu.c target-cris/cpu.h target-cris/translate.c target-microblaze/cpu-qom.h target-microblaze/cpu.c target-microblaze/cpu.h target-microblaze/translate.c target-sparc/cpu.c target-xtensa/translate.c tci.c tests/.gitignore tests/Makefile tests/libqtest.c tests/m48t59-test.c tests/qemu-iotests tests/rtc-test.c tests/tcg trace-events xen-all.c
Gerd Hoffmann
kraxel at kemper.freedesktop.org
Thu Apr 26 01:21:06 PDT 2012
MAINTAINERS | 2
Makefile | 16
Makefile.objs | 6
Makefile.target | 20 -
aio.c | 172 +++-----
audio/audio.c | 21 -
audio/audio_int.h | 6
audio/audio_template.h | 2
audio/paaudio.c | 475 ++++++++++++++++++++++--
audio/spiceaudio.c | 41 ++
block.c | 17
block/cow.c | 2
block/curl.c | 10
block/iscsi.c | 4
block/nbd.c | 61 ++-
block/qcow2-cluster.c | 226 ++++++++---
block/qcow2-refcount.c | 164 ++++----
block/qcow2-snapshot.c | 16
block/qcow2.c | 252 +++++++++++-
block/qcow2.h | 59 ++-
block/rbd.c | 5
block/sheepdog.c | 11
block_int.h | 1
cmd.c | 10
configure | 81 +++-
docs/specs/qcow2.txt | 122 +++++-
error.c | 2
exec-all.h | 2
fpu/softfloat.c | 4
gdbstub.c | 3
hmp-commands.hx | 4
hw/ac97.c | 139 ++-----
hw/arm_mptimer.c | 3
hw/e1000.c | 2
hw/ide/core.c | 137 ++++--
hw/ide/internal.h | 3
hw/m48t59.c | 6
hw/pc.c | 2
hw/pc_piix.c | 4
hw/pflash_cfi01.c | 1
hw/ptimer.c | 13
hw/qdev-monitor.c | 4
hw/qdev.c | 7
hw/qxl-render.c | 1
hw/qxl.c | 6
hw/qxl.h | 2
hw/realview.c | 83 ----
hw/scsi-bus.c | 8
hw/scsi-defs.h | 1
hw/scsi-disk.c | 170 +++++++-
hw/usb.h | 5
hw/usb/bus.c | 17
hw/usb/core.c | 17
hw/usb/desc.c | 126 +++---
hw/usb/desc.h | 63 +++
hw/usb/dev-hub.c | 43 ++
hw/usb/hcd-ehci.c | 16
hw/usb/hcd-uhci.c | 16
hw/usb/host-linux.c | 237 ++++++------
hw/usb/redirect.c | 11
hw/versatile_i2c.c | 105 +++++
hw/versatilepb.c | 22 +
hw/virtio-scsi.c | 26 -
hw/virtio.c | 7
hw/virtio.h | 1
hw/xen.h | 10
hw/xen_common.h | 15
include/qemu/object.h | 3
linux-aio.c | 2
nbd.c | 267 +++++++------
nbd.h | 6
pc-bios/bios.bin |binary
posix-aio-compat.c | 45 --
qapi-schema.json | 15
qapi/qmp-input-visitor.c | 25 -
qemu-aio.h | 19
qemu-char.c | 4
qemu-coroutine-sleep.c | 3
qemu-ga.c | 7
qemu-img.c | 4
qemu-io.c | 17
qemu-nbd.c | 45 +-
qemu-tool.c | 3
qga/commands-posix.c | 36 +
qmp-commands.hx | 6
qom/container.c | 4
qtest.c | 8
qtest.h | 18
roms/seabios | 2
scripts/create_config | 8
scripts/tracetool | 666 ----------------------------------
scripts/tracetool.py | 138 +++++++
scripts/tracetool/__init__.py | 271 +++++++++++++
scripts/tracetool/backend/__init__.py | 111 +++++
scripts/tracetool/backend/dtrace.py | 97 ++++
scripts/tracetool/backend/simple.py | 55 ++
scripts/tracetool/backend/stderr.py | 56 ++
scripts/tracetool/backend/ust.py | 90 ++++
scripts/tracetool/format/__init__.py | 99 +++++
scripts/tracetool/format/c.py | 20 +
scripts/tracetool/format/d.py | 20 +
scripts/tracetool/format/h.py | 45 ++
scripts/tracetool/format/stap.py | 20 +
spice-qemu-char.c | 2
target-arm/cpu-qom.h | 37 +
target-arm/cpu.c | 625 +++++++++++++++++++++++++++++++
target-arm/cpu.h | 10
target-arm/helper.c | 446 ++--------------------
target-cris/cpu-qom.h | 70 +++
target-cris/cpu.c | 90 ++++
target-cris/cpu.h | 2
target-cris/translate.c | 28 -
target-microblaze/cpu-qom.h | 70 +++
target-microblaze/cpu.c | 119 ++++++
target-microblaze/cpu.h | 2
target-microblaze/translate.c | 57 --
target-sparc/cpu.c | 4
target-xtensa/translate.c | 2
tci.c | 4
tests/.gitignore | 13
tests/Makefile | 3
tests/libqtest.c | 4
tests/m48t59-test.c | 259 +++++++++++++
tests/qemu-iotests/005 | 2
tests/qemu-iotests/005.out | 2
tests/qemu-iotests/013.out | 2
tests/qemu-iotests/014.out | 2
tests/qemu-iotests/015.out | 2
tests/qemu-iotests/019.out | 4
tests/qemu-iotests/022.out | 2
tests/qemu-iotests/023.out | 16
tests/qemu-iotests/024.out | 6
tests/qemu-iotests/026.out | 208 +++++-----
tests/qemu-iotests/029.out | 4
tests/qemu-iotests/030 | 12
tests/qemu-iotests/031 | 44 +-
tests/qemu-iotests/031.out | 132 ++++++
tests/qemu-iotests/032 | 69 +++
tests/qemu-iotests/032.out | 78 +++
tests/qemu-iotests/033 | 73 +++
tests/qemu-iotests/033.out | 29 +
tests/qemu-iotests/034 | 113 +++++
tests/qemu-iotests/034.out | 81 ++++
tests/qemu-iotests/check | 6
tests/qemu-iotests/common | 17
tests/qemu-iotests/common.config | 2
tests/qemu-iotests/common.rc | 38 +
tests/qemu-iotests/group | 3
tests/qemu-iotests/qcow2.py | 24 -
tests/rtc-test.c | 17
tests/tcg/xtensa/test_loop.S | 36 +
trace-events | 27 +
xen-all.c | 2
153 files changed, 5831 insertions(+), 2450 deletions(-)
New commits:
commit d6c05bbf29a40c531830e3968491f876328bb08f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Wed Apr 25 18:19:41 2012 +0200
fix paaudio.c warnings
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/audio/paaudio.c b/audio/paaudio.c
index e6708d0..aa15f16 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -505,8 +505,7 @@ fail:
pa_stream_unref (stream);
}
- qpa_logerr (pa_context_errno (g->context),
- "stream_new() failed\n");
+ *rerror = pa_context_errno (g->context);
return NULL;
}
commit cf36b31db209a261ee3bc2737e788e1ced0a1bec
Author: Peter Chubb <peter.chubb at nicta.com.au>
Date: Fri Apr 20 15:32:30 2012 +1000
Limit ptimer rate to something achievable
If a guest sets very short timeouts, and asks for a timer to be reloaded on
timeout, QEMU can go to 100%CPU utilisation and become unresponsive,
as it is spending all its time generating timeout interrupts. On real
hardware this doesn't matter, as the interrupts are just coalesced,
and the effect is to have the interrupt asserted all the time.
This patch is a band-aid, that prevents timeouts less than 10
microseconds from being set. 10 microseconds is a limit that was
determined empirically on a variety of machines as the shortest that
allowed QEMU to pick up a control-a c sequence to get at the monitor.
Reported-by: Anna Lyons <anna.lyons at nicta.com.au>
Signed-off-by: Peter Chubb <peter.chubb at nicta.com.au>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/ptimer.c b/hw/ptimer.c
index de7d664..bc0b3f8 100644
--- a/hw/ptimer.c
+++ b/hw/ptimer.c
@@ -180,6 +180,19 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq)
count = limit. */
void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
{
+ /*
+ * Artificially limit timeout rate to something
+ * achievable under QEMU. Otherwise, QEMU spends all
+ * its time generating timer interrupts, and there
+ * is no forward progress.
+ * About ten microseconds is the fastest that really works
+ * on the current generation of host machines.
+ */
+
+ if (limit * s->period < 10000 && s->period) {
+ limit = 10000 / s->period;
+ }
+
s->limit = limit;
if (reload)
s->delta = limit;
commit dfe47e7029e117f65a14c0948021654f7f7d5d05
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Apr 5 13:21:46 2012 +0200
qom: Refine container_get() to allow using a custom root
Specify the root to search from as argument. This avoids hardcoding
"/machine" in some places and makes it more flexible.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Cc: Paolo Bonzini <pbonzini at redhat.com>
Cc: Anthony Liguori <anthony at codemonkey.ws>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 81d6548..dc4e4e1 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -181,7 +181,7 @@ static Object *qdev_get_peripheral(void)
static Object *dev;
if (dev == NULL) {
- dev = container_get("/machine/peripheral");
+ dev = container_get(qdev_get_machine(), "/peripheral");
}
return dev;
@@ -192,7 +192,7 @@ static Object *qdev_get_peripheral_anon(void)
static Object *dev;
if (dev == NULL) {
- dev = container_get("/machine/peripheral-anon");
+ dev = container_get(qdev_get_machine(), "/peripheral-anon");
}
return dev;
diff --git a/hw/qdev.c b/hw/qdev.c
index afbc975..0bcde20 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -158,8 +158,9 @@ int qdev_init(DeviceState *dev)
static int unattached_count = 0;
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
- object_property_add_child(container_get("/machine/unattached"), name,
- OBJECT(dev), NULL);
+ object_property_add_child(container_get(qdev_get_machine(),
+ "/unattached"),
+ name, OBJECT(dev), NULL);
g_free(name);
}
@@ -677,7 +678,7 @@ Object *qdev_get_machine(void)
static Object *dev;
if (dev == NULL) {
- dev = container_get("/machine");
+ dev = container_get(object_get_root(), "/machine");
}
return dev;
diff --git a/include/qemu/object.h b/include/qemu/object.h
index a675937..ca1649c 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -905,6 +905,7 @@ void object_property_add_str(Object *obj, const char *name,
/**
* container_get:
+ * @root: root of the #path, e.g., object_get_root()
* @path: path to the container
*
* Return a container object whose path is @path. Create more containers
@@ -912,7 +913,7 @@ void object_property_add_str(Object *obj, const char *name,
*
* Returns: the container object.
*/
-Object *container_get(const char *path);
+Object *container_get(Object *root, const char *path);
#endif
diff --git a/qom/container.c b/qom/container.c
index 67e9e8a..c9940ab 100644
--- a/qom/container.c
+++ b/qom/container.c
@@ -25,7 +25,7 @@ static void container_register_types(void)
type_register_static(&container_info);
}
-Object *container_get(const char *path)
+Object *container_get(Object *root, const char *path)
{
Object *obj, *child;
gchar **parts;
@@ -33,7 +33,7 @@ Object *container_get(const char *path)
parts = g_strsplit(path, "/", 0);
assert(parts != NULL && parts[0] != NULL && !parts[0][0]);
- obj = object_get_root();
+ obj = root;
for (i = 1; parts[i] != NULL; i++, obj = child) {
child = object_resolve_path_component(obj, parts[i]);
commit 7f3bf92fad79dff1edcb796a875b5c0d57666162
Author: Richard Henderson <rth at twiddle.net>
Date: Thu Apr 19 07:09:33 2012 -0500
qtest: Fix tv_usec != long
Sparc Debian 5.0.8 does not define __suseconds_t as long,
but FMT_timeval expects %ld.
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Richard Henderson <rth at twiddle.net>
Cc: Anthony Liguori <aliguori at us.ibm.com>
Cc: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qtest.c b/qtest.c
index 18afcd9..fbfab4e 100644
--- a/qtest.c
+++ b/qtest.c
@@ -153,7 +153,7 @@ static void qtest_send_prefix(CharDriverState *chr)
qtest_get_time(&tv);
fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
- tv.tv_sec, tv.tv_usec);
+ tv.tv_sec, (long) tv.tv_usec);
}
static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
@@ -201,7 +201,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
qtest_get_time(&tv);
fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
- tv.tv_sec, tv.tv_usec);
+ tv.tv_sec, (long) tv.tv_usec);
for (i = 0; words[i]; i++) {
fprintf(qtest_log_fp, " %s", words[i]);
}
@@ -399,7 +399,7 @@ static void qtest_event(void *opaque, int event)
qtest_opened = true;
if (qtest_log_fp) {
fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
- start_time.tv_sec, start_time.tv_usec);
+ start_time.tv_sec, (long) start_time.tv_usec);
}
break;
case CHR_EVENT_CLOSED:
@@ -408,7 +408,7 @@ static void qtest_event(void *opaque, int event)
qemu_timeval tv;
qtest_get_time(&tv);
fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
- tv.tv_sec, tv.tv_usec);
+ tv.tv_sec, (long) tv.tv_usec);
}
break;
default:
commit e3c56761b465a4253871c32b06ebbc2d8b3fc3e1
Author: Peter Portante <peter.portante at redhat.com>
Date: Fri Apr 20 10:36:12 2012 -0400
Remove extra pthread switch
remove the extra pthread switch which might be there
from the package config check for gthreads.
Signed-off-by: Peter Portante <peter.portante at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index b8baf4f..dd09f1a 100755
--- a/configure
+++ b/configure
@@ -2083,7 +2083,16 @@ else
for pthread_lib in $PTHREADLIBS_LIST; do
if compile_prog "" "$pthread_lib" ; then
pthread=yes
- LIBS="$pthread_lib $LIBS"
+ found=no
+ for lib_entry in $LIBS; do
+ if test "$lib_entry" = "$pthread_lib"; then
+ found=yes
+ break
+ fi
+ done
+ if test "$found" = "no"; then
+ LIBS="$pthread_lib $LIBS"
+ fi
break
fi
done
commit d10f9056bacf7991fd6a5f63ac2e0190e84ea3a7
Author: Kusanagi Kouichi <slash at ac.auone-net.jp>
Date: Sun Apr 22 19:16:05 2012 +0900
configure: Virtfs doesn't require libcap.
Only proxy helper does.
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kusanagi Kouichi <slash at ac.auone-net.jp>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index 2dffab8..b8baf4f 100755
--- a/configure
+++ b/configure
@@ -2889,9 +2889,11 @@ tools=
if test "$softmmu" = yes ; then
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
if test "$virtfs" != no ; then
- if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
+ if test "$linux" = yes && test "$attr" = yes ; then
virtfs=yes
- tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
+ if test "$cap" = yes ; then
+ tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
+ fi
else
if test "$virtfs" = yes; then
feature_not_found "virtfs"
commit ac3107340fbb9422ea63ee5d6729775965e121fd
Author: Stefan Weil <sw at weilnetz.de>
Date: Thu Apr 19 22:27:14 2012 +0200
qemu-char: Fix crash when switching consoles
qemu-system-arm (and other system emulations) crashes with SDL when
the user switches consoles (Alt-Ctrl-F4).
We already check for NULL pointers in qemu_chr_fe_ioctl,
qemu_chr_be_can_write and other functions, so do this also
for s->chr_read in qemu_chr_be_write. This fixes the crash.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qemu-char.c b/qemu-char.c
index 74c60e1..a9fc504 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -160,7 +160,9 @@ int qemu_chr_be_can_write(CharDriverState *s)
void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
{
- s->chr_read(s->handler_opaque, buf, len);
+ if (s->chr_read) {
+ s->chr_read(s->handler_opaque, buf, len);
+ }
}
int qemu_chr_fe_get_msgfd(CharDriverState *s)
commit 023d3d67c7dc6e7f492de5b2336194c500d1779d
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:50 2012 -0300
configure: add --with-confsuffix option
This will allow the user to make Qemu use a different subdirectory name
inside $datadir and $sysconfdir, instead of "/qemu".
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index df439c9..2dffab8 100755
--- a/configure
+++ b/configure
@@ -591,6 +591,8 @@ for opt do
;;
--datadir=*) datadir="$optarg"
;;
+ --with-confsuffix=*) confsuffix="$optarg"
+ ;;
--docdir=*) qemu_docdir="$optarg"
;;
--sysconfdir=*) sysconfdir="$optarg"
@@ -1007,10 +1009,11 @@ echo " --python=PYTHON use specified python [$python]"
echo " --smbd=SMBD use specified smbd [$smbd]"
echo " --static enable static build [$static]"
echo " --mandir=PATH install man pages in PATH"
-echo " --datadir=PATH install firmware in PATH/qemu"
-echo " --docdir=PATH install documentation in PATH"
+echo " --datadir=PATH install firmware in PATH$confsuffix"
+echo " --docdir=PATH install documentation in PATH$confsuffix"
echo " --bindir=PATH install binaries in PATH"
-echo " --sysconfdir=PATH install config in PATH/qemu"
+echo " --sysconfdir=PATH install config in PATH$confsuffix"
+echo " --with-confsuffix=SUFFIX suffix for Qemu data inside datadir and sysconfdir [$confsuffix]"
echo " --enable-debug-tcg enable TCG debugging"
echo " --disable-debug-tcg disable TCG debugging (default)"
echo " --enable-debug enable common debug build options"
commit 528ae5b85079ce5744c7d682b11045eee7e0fb70
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:49 2012 -0300
configure: change meaning of --datadir to Autoconf convention
Autoconf uses --datadir for the /usr/share directory, not the
program-specific subdirectory inside /usr/share. This changes configure
to match autoconf behavior.
Note that this will break compatibility with existing build scripts.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index bc0f7e2..df439c9 100755
--- a/configure
+++ b/configure
@@ -155,7 +155,7 @@ mingw32="no"
EXESUF=""
prefix="/usr/local"
mandir="\${prefix}/share/man"
-qemu_datadir="\${prefix}/share/qemu"
+datadir="\${prefix}/share"
qemu_docdir="\${prefix}/share/doc/qemu"
bindir="\${prefix}/bin"
libdir="\${prefix}/lib"
@@ -521,7 +521,7 @@ EOF
fi
prefix="c:/Program Files/QEMU"
mandir="\${prefix}"
- qemu_datadir="\${prefix}"
+ datadir="\${prefix}"
qemu_docdir="\${prefix}"
bindir="\${prefix}"
sysconfdir="\${prefix}"
@@ -589,7 +589,7 @@ for opt do
;;
--includedir=*) includedir="$optarg"
;;
- --datadir=*) qemu_datadir="$optarg"
+ --datadir=*) datadir="$optarg"
;;
--docdir=*) qemu_docdir="$optarg"
;;
@@ -1007,7 +1007,7 @@ echo " --python=PYTHON use specified python [$python]"
echo " --smbd=SMBD use specified smbd [$smbd]"
echo " --static enable static build [$static]"
echo " --mandir=PATH install man pages in PATH"
-echo " --datadir=PATH install firmware in PATH"
+echo " --datadir=PATH install firmware in PATH/qemu"
echo " --docdir=PATH install documentation in PATH"
echo " --bindir=PATH install binaries in PATH"
echo " --sysconfdir=PATH install config in PATH/qemu"
@@ -2880,6 +2880,7 @@ if test "$mingw32" = "yes" ; then
fi
qemu_confdir=$sysconfdir$confsuffix
+qemu_datadir=$datadir$confsuffix
tools=
if test "$softmmu" = yes ; then
commit 0b3b717470c02013d692e8055efae7d64334a448
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:48 2012 -0300
create_config: simplify prefix=* block, remove CONFIG_QEMU_PREFIX
As now that block handles only the prefix variable, the code can be much
simpler. This also removes the CONFIG_QEMU_PREFIX define as it is not
used by any C code.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/scripts/create_config b/scripts/create_config
index 1d06eb1..c471e8c 100755
--- a/scripts/create_config
+++ b/scripts/create_config
@@ -23,13 +23,8 @@ case $line in
eval "$name=\$define_value"
;;
prefix=*)
- name=${line%=*}
- value=${line#*=}
- define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
- eval "define_value=\"$value\""
- echo "#define CONFIG_QEMU_$define_name \"$define_value\""
# save for the next definitions
- eval "$name=\$define_value"
+ prefix=${line#*=}
;;
CONFIG_AUDIO_DRIVERS=*)
drivers=${line#*=}
commit c41cc50f66ea0e319cebd858af95423c880f8149
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:47 2012 -0300
create_config: remove *dir block
Now only the qemu_*dir variables will become #defines. The other
directory names aren't used by the C code.
That means the following #defines won't be available in C code anymore:
- CONFIG_QEMU_BINDIR
- CONFIG_QEMU_LIBDIR
- CONFIG_QEMU_INCLUDEDIR
- CONFIG_QEMU_MANDIR
- CONFIG_QEMU_SYSCONFDIR
- CONFIG_QEMU_LIBEXECDIR
The following #defines are going to be kept because they are handled by
the qemu_* block on create_config:
- CONFIG_QEMU_CONFDIR
- CONFIG_QEMU_DATADIR
- CONFIG_QEMU_DOCDIR
This one will be kept because it is set directly by ./configure:
- CONFIG_QEMU_HELPERDIR
This patch keeps the 'prefix=*' (CONFIG_QEMU_PREFIX) pattern because
other variables may use $prefix on their config-host.mak definitions.
The remaining code will be simplified on a further patch.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/scripts/create_config b/scripts/create_config
index f9ba2f5..1d06eb1 100755
--- a/scripts/create_config
+++ b/scripts/create_config
@@ -22,7 +22,7 @@ case $line in
# save for the next definitions
eval "$name=\$define_value"
;;
- prefix=* | [a-z]*dir=*) # directory configuration
+ prefix=*)
name=${line%=*}
value=${line#*=}
define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
commit 9afa52ceb2a2e19ccfb69e13eab558613a93fb6c
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:46 2012 -0300
config-host.mak: reorder variables a bit
Cosmetic change.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index 1f42031..bc0f7e2 100755
--- a/configure
+++ b/configure
@@ -3022,10 +3022,10 @@ echo "bindir=$bindir" >> $config_host_mak
echo "libdir=$libdir" >> $config_host_mak
echo "includedir=$includedir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
-echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
-echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
+echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
+echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
commit 5100cb446dbd3556897e08a81f6ef22b63373872
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:45 2012 -0300
config-host.mak: remove CONFIG_QEMU_SHAREDIR
There is no code using that variable according to 'git grep', so kill
it.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index c0fac32..1f42031 100755
--- a/configure
+++ b/configure
@@ -3027,7 +3027,6 @@ echo "sysconfdir=$sysconfdir" >> $config_host_mak
echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
-echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
commit d7dd65bae3fcc13190da312b1be90364e86cd6aa
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:44 2012 -0300
config-host.mak: rename docdir to qemu_docdir
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile b/Makefile
index a9bc796..4f43793 100644
--- a/Makefile
+++ b/Makefile
@@ -268,8 +268,8 @@ BLOBS=
endif
install-doc: $(DOCS)
- $(INSTALL_DIR) "$(DESTDIR)$(docdir)"
- $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
+ $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
ifdef CONFIG_POSIX
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
diff --git a/configure b/configure
index b64c99b..c0fac32 100755
--- a/configure
+++ b/configure
@@ -3024,7 +3024,7 @@ echo "includedir=$includedir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
-echo "docdir=$qemu_docdir" >> $config_host_mak
+echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
commit 80465e809af70cc311c1f47a84418f052209a3fe
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:43 2012 -0300
Makefile: use $(qemu_confdir) instead of $(sysconfdir)/qemu
Instead of hardcoding the directory suffix, use the qemu-specific
directory variable.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile b/Makefile
index c8e4b53..a9bc796 100644
--- a/Makefile
+++ b/Makefile
@@ -281,8 +281,8 @@ ifdef CONFIG_VIRTFS
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
endif
install-sysconfig:
- $(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)/qemu"
- $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(sysconfdir)/qemu"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
+ $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
commit 22d07038539429932b2de0489833e5987fbce496
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:42 2012 -0300
config-host.mak: rename confdir to qemu_confdir
$confdir is a confusing name, as it's not clear if it's "the system
config dir" or "the Qemus-specific directory inside the config dir".
$qemu_confdir makes it more clear.
The current C code that uses CONFIG_QEMU_CONFDIR should be safe, as now
create_config generates the same #define name (CONFIG_QEMU_CONFDIR) for
both "confdir" and "qemu_confdir" variables.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index 8788354..b64c99b 100755
--- a/configure
+++ b/configure
@@ -3025,7 +3025,7 @@ echo "mandir=$mandir" >> $config_host_mak
echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
echo "docdir=$qemu_docdir" >> $config_host_mak
-echo "confdir=$qemu_confdir" >> $config_host_mak
+echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
commit 6aae2a2e0e3c43e479f889389074cda8bef3a580
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:41 2012 -0300
config-host.mak: rename datadir to qemu_datadir
Autoconf concept of "datadir" is supposed to be "$prefix/share", not
"$prefix/share/PACKAGE", so using datadir for the Qemu-specific
directory is confusing.
The current C code that uses CONFIG_QEMU_DATADIR should be safe, as now
create_config generates the same #define name (CONFIG_QEMU_DATADIR) for
both "datadir" and "qemu_datadir" variables.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile b/Makefile
index e0fe680..c8e4b53 100644
--- a/Makefile
+++ b/Makefile
@@ -294,14 +294,14 @@ ifneq ($(HELPERS-y),)
$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
endif
ifneq ($(BLOBS),)
- $(INSTALL_DIR) "$(DESTDIR)$(datadir)"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
set -e; for x in $(BLOBS); do \
- $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
+ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
done
endif
- $(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
set -e; for x in $(KEYMAPS); do \
- $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
+ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
done
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
diff --git a/Makefile.target b/Makefile.target
index 172289a..4fbbabf 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -485,8 +485,8 @@ ifneq ($(STRIP),)
endif
endif
ifdef CONFIG_TRACE_SYSTEMTAP
- $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
- $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
+ $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
endif
# Include automatically generated dependency files
diff --git a/configure b/configure
index cba5976..8788354 100755
--- a/configure
+++ b/configure
@@ -3022,7 +3022,7 @@ echo "bindir=$bindir" >> $config_host_mak
echo "libdir=$libdir" >> $config_host_mak
echo "includedir=$includedir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
-echo "datadir=$qemu_datadir" >> $config_host_mak
+echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
echo "docdir=$qemu_docdir" >> $config_host_mak
echo "confdir=$qemu_confdir" >> $config_host_mak
commit eb72952b81f254e39c21f892b6109f09a762c313
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:40 2012 -0300
create_config: separate section for qemu_*dir variables (v2)
The generic *dir section will eventually go away and be replaced with
qemu_* section. By now, both sections will be kept, while the variables
get renamed on config-host.mak.
With this patch, a XXXdir variable will become a CONFIG_QEMU_XXXDIR
define, and a qemu_XXXdir variable will become CONFIG_QEMU_XXXDIR as
well (instead of becoming a CONFIG_QEMU_QEMU_XXXDIR define).
Changes v1 -> v2:
- Rebase on top of newer qemu.git changes, that changed
"tr '[:lower:]' '[:upper:]'" to "LC_ALL=C tr '[a-z]' '[A-Z]'".
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/scripts/create_config b/scripts/create_config
index 470e05e..f9ba2f5 100755
--- a/scripts/create_config
+++ b/scripts/create_config
@@ -13,6 +13,15 @@ case $line in
pkgversion=${line#*=}
echo "#define QEMU_PKGVERSION \"$pkgversion\""
;;
+ qemu_*dir=*) # qemu-specific directory configuration
+ name=${line%=*}
+ value=${line#*=}
+ define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
+ eval "define_value=\"$value\""
+ echo "#define CONFIG_$define_name \"$define_value\""
+ # save for the next definitions
+ eval "$name=\$define_value"
+ ;;
prefix=* | [a-z]*dir=*) # directory configuration
name=${line%=*}
value=${line#*=}
commit 10ea68b34378efd81a644f67cea7863c135a6fa8
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:39 2012 -0300
configure: rename $confdir to $qemu_confdir
There's no "confdir" variable on Autoconf, but it's good to make it
clear that it's a variable for the Qemu-specific subdirectory inside
$sysconfdir.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index 93b6db1..cba5976 100755
--- a/configure
+++ b/configure
@@ -2879,7 +2879,7 @@ if test "$mingw32" = "yes" ; then
done
fi
-confdir=$sysconfdir$confsuffix
+qemu_confdir=$sysconfdir$confsuffix
tools=
if test "$softmmu" = yes ; then
@@ -3025,7 +3025,7 @@ echo "mandir=$mandir" >> $config_host_mak
echo "datadir=$qemu_datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
echo "docdir=$qemu_docdir" >> $config_host_mak
-echo "confdir=$confdir" >> $config_host_mak
+echo "confdir=$qemu_confdir" >> $config_host_mak
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
commit 850da188a2f11eee72a806d638c1c2d0935d989e
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:38 2012 -0300
configure: rename $docdir to $qemu_docdir
The autoconf "docdir" variable is used for the program-specific
subdirectory, but anyway it's better to make it clear that the variable
is used for the qemu-specific subdirectory path.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index 76be4f2..93b6db1 100755
--- a/configure
+++ b/configure
@@ -156,7 +156,7 @@ EXESUF=""
prefix="/usr/local"
mandir="\${prefix}/share/man"
qemu_datadir="\${prefix}/share/qemu"
-docdir="\${prefix}/share/doc/qemu"
+qemu_docdir="\${prefix}/share/doc/qemu"
bindir="\${prefix}/bin"
libdir="\${prefix}/lib"
includedir="\${prefix}/include"
@@ -522,7 +522,7 @@ EOF
prefix="c:/Program Files/QEMU"
mandir="\${prefix}"
qemu_datadir="\${prefix}"
- docdir="\${prefix}"
+ qemu_docdir="\${prefix}"
bindir="\${prefix}"
sysconfdir="\${prefix}"
confsuffix=""
@@ -591,7 +591,7 @@ for opt do
;;
--datadir=*) qemu_datadir="$optarg"
;;
- --docdir=*) docdir="$optarg"
+ --docdir=*) qemu_docdir="$optarg"
;;
--sysconfdir=*) sysconfdir="$optarg"
;;
@@ -3024,7 +3024,7 @@ echo "includedir=$includedir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
echo "datadir=$qemu_datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
-echo "docdir=$docdir" >> $config_host_mak
+echo "docdir=$qemu_docdir" >> $config_host_mak
echo "confdir=$confdir" >> $config_host_mak
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
commit c00b2808053064a08b93f5ed901b21693a431b6d
Author: Eduardo Habkost <ehabkost at redhat.com>
Date: Wed Apr 18 16:55:37 2012 -0300
configure: rename $datadir to $qemu_datadir
The variable is used for the qemu-specific directory and has a different
meaning of the autoconf "datadir" variable (that's used for the
$prefix/share directory, not for $prefix/share/PACKAGE).
This doesn't change behavior or interfaces, it's just an internal
variable rename.
Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/configure b/configure
index 8ed5a03..76be4f2 100755
--- a/configure
+++ b/configure
@@ -155,7 +155,7 @@ mingw32="no"
EXESUF=""
prefix="/usr/local"
mandir="\${prefix}/share/man"
-datadir="\${prefix}/share/qemu"
+qemu_datadir="\${prefix}/share/qemu"
docdir="\${prefix}/share/doc/qemu"
bindir="\${prefix}/bin"
libdir="\${prefix}/lib"
@@ -521,7 +521,7 @@ EOF
fi
prefix="c:/Program Files/QEMU"
mandir="\${prefix}"
- datadir="\${prefix}"
+ qemu_datadir="\${prefix}"
docdir="\${prefix}"
bindir="\${prefix}"
sysconfdir="\${prefix}"
@@ -589,7 +589,7 @@ for opt do
;;
--includedir=*) includedir="$optarg"
;;
- --datadir=*) datadir="$optarg"
+ --datadir=*) qemu_datadir="$optarg"
;;
--docdir=*) docdir="$optarg"
;;
@@ -2914,7 +2914,7 @@ if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then
fi
echo "Install prefix $prefix"
-echo "BIOS directory `eval echo $datadir`"
+echo "BIOS directory `eval echo $qemu_datadir`"
echo "binary directory `eval echo $bindir`"
echo "library directory `eval echo $libdir`"
echo "include directory `eval echo $includedir`"
@@ -3022,7 +3022,7 @@ echo "bindir=$bindir" >> $config_host_mak
echo "libdir=$libdir" >> $config_host_mak
echo "includedir=$includedir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
-echo "datadir=$datadir" >> $config_host_mak
+echo "datadir=$qemu_datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
echo "docdir=$docdir" >> $config_host_mak
echo "confdir=$confdir" >> $config_host_mak
commit d0e71ef56fa22b7434d4e9f277a2091b2981ef98
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Apr 12 02:34:40 2012 +0200
target-microblaze: QOM'ify CPU init
Move code from cpu_mb_init() to a QOM initfn.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Tested-by: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
[AF: Leave cpu_reset() call in cpu_mb_init()]
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index 6f00b0d..9c3b74e 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -83,6 +83,16 @@ static void mb_cpu_reset(CPUState *s)
#endif
}
+static void mb_cpu_initfn(Object *obj)
+{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj);
+ CPUMBState *env = &cpu->env;
+
+ cpu_exec_init(env);
+
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+}
+
static void mb_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
@@ -96,6 +106,7 @@ static const TypeInfo mb_cpu_type_info = {
.name = TYPE_MICROBLAZE_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(MicroBlazeCPU),
+ .instance_init = mb_cpu_initfn,
.class_size = sizeof(MicroBlazeCPUClass),
.class_init = mb_cpu_class_init,
};
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index e730c32..742b395 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1899,10 +1899,8 @@ CPUMBState *cpu_mb_init (const char *cpu_model)
cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
env = &cpu->env;
- cpu_exec_init(env);
cpu_reset(CPU(cpu));
qemu_init_vcpu(env);
- set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
if (tcg_initialized)
return env;
commit 61b6208f8e2bfee096fbeefa20744dcc87c2530e
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Apr 12 02:26:28 2012 +0200
target-microblaze: QOM'ify CPU reset
Move code from cpu_state_reset() to QOM mb_cpu_reset().
Signed-off-by: Andreas Färber <afaerber at suse.de>
Tested-by: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
index 21b62c6..6f00b0d 100644
--- a/target-microblaze/cpu.c
+++ b/target-microblaze/cpu.c
@@ -1,6 +1,8 @@
/*
* QEMU MicroBlaze CPU
*
+ * Copyright (c) 2009 Edgar E. Iglesias
+ * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This library is free software; you can redistribute it and/or
@@ -29,9 +31,56 @@ static void mb_cpu_reset(CPUState *s)
MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(cpu);
CPUMBState *env = &cpu->env;
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
mcc->parent_reset(s);
- cpu_state_reset(env);
+ memset(env, 0, offsetof(CPUMBState, breakpoints));
+ tlb_flush(env, 1);
+
+ /* Disable stack protector. */
+ env->shr = ~0;
+
+ env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
+ | PVR0_USE_BARREL_MASK \
+ | PVR0_USE_DIV_MASK \
+ | PVR0_USE_HW_MUL_MASK \
+ | PVR0_USE_EXC_MASK \
+ | PVR0_USE_ICACHE_MASK \
+ | PVR0_USE_DCACHE_MASK \
+ | PVR0_USE_MMU \
+ | (0xb << 8);
+ env->pvr.regs[2] = PVR2_D_OPB_MASK \
+ | PVR2_D_LMB_MASK \
+ | PVR2_I_OPB_MASK \
+ | PVR2_I_LMB_MASK \
+ | PVR2_USE_MSR_INSTR \
+ | PVR2_USE_PCMP_INSTR \
+ | PVR2_USE_BARREL_MASK \
+ | PVR2_USE_DIV_MASK \
+ | PVR2_USE_HW_MUL_MASK \
+ | PVR2_USE_MUL64_MASK \
+ | PVR2_USE_FPU_MASK \
+ | PVR2_USE_FPU2_MASK \
+ | PVR2_FPU_EXC_MASK \
+ | 0;
+ env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
+ env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
+
+#if defined(CONFIG_USER_ONLY)
+ /* start in user mode with interrupts enabled. */
+ env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
+ env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp. */
+#else
+ env->sregs[SR_MSR] = 0;
+ mmu_init(&env->mmu);
+ env->mmu.c_mmu = 3;
+ env->mmu.c_mmu_tlb_access = 3;
+ env->mmu.c_mmu_zones = 16;
+#endif
}
static void mb_cpu_class_init(ObjectClass *oc, void *data)
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index f4d32c8..e730c32 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1900,7 +1900,7 @@ CPUMBState *cpu_mb_init (const char *cpu_model)
env = &cpu->env;
cpu_exec_init(env);
- cpu_state_reset(env);
+ cpu_reset(CPU(cpu));
qemu_init_vcpu(env);
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
@@ -1944,54 +1944,7 @@ CPUMBState *cpu_mb_init (const char *cpu_model)
void cpu_state_reset(CPUMBState *env)
{
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- memset(env, 0, offsetof(CPUMBState, breakpoints));
- tlb_flush(env, 1);
-
- /* Disable stack protector. */
- env->shr = ~0;
-
- env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
- | PVR0_USE_BARREL_MASK \
- | PVR0_USE_DIV_MASK \
- | PVR0_USE_HW_MUL_MASK \
- | PVR0_USE_EXC_MASK \
- | PVR0_USE_ICACHE_MASK \
- | PVR0_USE_DCACHE_MASK \
- | PVR0_USE_MMU \
- | (0xb << 8);
- env->pvr.regs[2] = PVR2_D_OPB_MASK \
- | PVR2_D_LMB_MASK \
- | PVR2_I_OPB_MASK \
- | PVR2_I_LMB_MASK \
- | PVR2_USE_MSR_INSTR \
- | PVR2_USE_PCMP_INSTR \
- | PVR2_USE_BARREL_MASK \
- | PVR2_USE_DIV_MASK \
- | PVR2_USE_HW_MUL_MASK \
- | PVR2_USE_MUL64_MASK \
- | PVR2_USE_FPU_MASK \
- | PVR2_USE_FPU2_MASK \
- | PVR2_FPU_EXC_MASK \
- | 0;
- env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
- env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
-
-#if defined(CONFIG_USER_ONLY)
- /* start in user mode with interrupts enabled. */
- env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
- env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp. */
-#else
- env->sregs[SR_MSR] = 0;
- mmu_init(&env->mmu);
- env->mmu.c_mmu = 3;
- env->mmu.c_mmu_tlb_access = 3;
- env->mmu.c_mmu_zones = 16;
-#endif
+ cpu_reset(ENV_GET_CPU(env));
}
void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, int pc_pos)
commit b77f98cadad07a0863a6bfe1492c64f3a16ccbc5
Author: Andreas Färber <afaerber at suse.de>
Date: Thu Apr 12 02:17:53 2012 +0200
target-microblaze: QOM'ify CPU
Embed CPUMBState as first member of QOM MicroBlazeCPU.
Let CPUClass::reset() call cpu_state_reset() for now.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Tested-by: Peter A. G. Crosthwaite <peter.crosthwaite at petalogix.com>
[AF: Updated cpu.c to include cpu-qom.h indirectly via cpu.h]
diff --git a/Makefile.target b/Makefile.target
index 1b5d62b..172289a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -96,6 +96,7 @@ libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-$(TARGET_ARM) += cpu.o
libobj-$(TARGET_CRIS) += cpu.o
libobj-$(TARGET_LM32) += cpu.o
+libobj-$(TARGET_MICROBLAZE) += cpu.o
libobj-$(TARGET_S390X) += cpu.o
ifeq ($(TARGET_BASE_ARCH), sparc)
libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h
new file mode 100644
index 0000000..4b23303
--- /dev/null
+++ b/target-microblaze/cpu-qom.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU MicroBlaze CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_MICROBLAZE_CPU_QOM_H
+#define QEMU_MICROBLAZE_CPU_QOM_H
+
+#include "qemu/cpu.h"
+
+#define TYPE_MICROBLAZE_CPU "microblaze-cpu"
+
+#define MICROBLAZE_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(MicroBlazeCPUClass, (klass), TYPE_MICROBLAZE_CPU)
+#define MICROBLAZE_CPU(obj) \
+ OBJECT_CHECK(MicroBlazeCPU, (obj), TYPE_MICROBLAZE_CPU)
+#define MICROBLAZE_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(MicroBlazeCPUClass, (obj), TYPE_MICROBLAZE_CPU)
+
+/**
+ * MicroBlazeCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A MicroBlaze CPU model.
+ */
+typedef struct MicroBlazeCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} MicroBlazeCPUClass;
+
+/**
+ * MicroBlazeCPU:
+ * @env: #CPUMBState
+ *
+ * A MicroBlaze CPU.
+ */
+typedef struct MicroBlazeCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUMBState env;
+} MicroBlazeCPU;
+
+static inline MicroBlazeCPU *mb_env_get_cpu(CPUMBState *env)
+{
+ return MICROBLAZE_CPU(container_of(env, MicroBlazeCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(mb_env_get_cpu(e))
+
+
+#endif
diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c
new file mode 100644
index 0000000..21b62c6
--- /dev/null
+++ b/target-microblaze/cpu.c
@@ -0,0 +1,59 @@
+/*
+ * QEMU MicroBlaze CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu.h"
+#include "qemu-common.h"
+
+
+/* CPUClass::reset() */
+static void mb_cpu_reset(CPUState *s)
+{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(s);
+ MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(cpu);
+ CPUMBState *env = &cpu->env;
+
+ mcc->parent_reset(s);
+
+ cpu_state_reset(env);
+}
+
+static void mb_cpu_class_init(ObjectClass *oc, void *data)
+{
+ CPUClass *cc = CPU_CLASS(oc);
+ MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_CLASS(oc);
+
+ mcc->parent_reset = cc->reset;
+ cc->reset = mb_cpu_reset;
+}
+
+static const TypeInfo mb_cpu_type_info = {
+ .name = TYPE_MICROBLAZE_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(MicroBlazeCPU),
+ .class_size = sizeof(MicroBlazeCPUClass),
+ .class_init = mb_cpu_class_init,
+};
+
+static void mb_cpu_register_types(void)
+{
+ type_register_static(&mb_cpu_type_info);
+}
+
+type_init(mb_cpu_register_types)
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 33b23c2..718d5bb 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -266,6 +266,8 @@ struct CPUMBState {
CPU_COMMON
};
+#include "cpu-qom.h"
+
CPUMBState *cpu_mb_init(const char *cpu_model);
int cpu_mb_exec(CPUMBState *s);
void cpu_mb_close(CPUMBState *s);
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index b602820..f4d32c8 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1891,11 +1891,13 @@ void cpu_dump_state (CPUMBState *env, FILE *f, fprintf_function cpu_fprintf,
CPUMBState *cpu_mb_init (const char *cpu_model)
{
+ MicroBlazeCPU *cpu;
CPUMBState *env;
static int tcg_initialized = 0;
int i;
- env = g_malloc0(sizeof(CPUMBState));
+ cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
+ env = &cpu->env;
cpu_exec_init(env);
cpu_state_reset(env);
commit aa0d1267b3aa69c87fbd37a896bdd3f44d45c3f3
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 23:41:06 2012 +0200
target-cris: Start QOM'ifying CPU init
Move VR-independent code from cpu_cris_init() into an initfn.
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 93c7e00..c596609 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -55,6 +55,14 @@ static void cris_cpu_reset(CPUState *s)
#endif
}
+static void cris_cpu_initfn(Object *obj)
+{
+ CRISCPU *cpu = CRIS_CPU(obj);
+ CPUCRISState *env = &cpu->env;
+
+ cpu_exec_init(env);
+}
+
static void cris_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
@@ -68,6 +76,7 @@ static const TypeInfo cris_cpu_type_info = {
.name = TYPE_CRIS_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(CRISCPU),
+ .instance_init = cris_cpu_initfn,
.abstract = false,
.class_size = sizeof(CRISCPUClass),
.class_init = cris_cpu_class_init,
diff --git a/target-cris/translate.c b/target-cris/translate.c
index d3dbac2..e353ea3 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3514,7 +3514,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
env = &cpu->env;
env->pregs[PR_VR] = vr_by_name(cpu_model);
- cpu_exec_init(env);
+
cpu_reset(CPU(cpu));
qemu_init_vcpu(env);
commit 1c3b52fb1a44b407b52f4852c1931c571e77d308
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 23:35:40 2012 +0200
target-cris: QOM'ify CPU reset
Move code from cpu_state_reset() into QOM cris_cpu_reset().
Let CPU init call cpu_reset().
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 784846b..93c7e00 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -1,6 +1,9 @@
/*
* QEMU CRIS CPU
*
+ * Copyright (c) 2008 AXIS Communications AB
+ * Written by Edgar E. Iglesias.
+ *
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This library is free software; you can redistribute it and/or
@@ -20,6 +23,7 @@
#include "cpu.h"
#include "qemu-common.h"
+#include "mmu.h"
/* CPUClass::reset() */
@@ -28,10 +32,27 @@ static void cris_cpu_reset(CPUState *s)
CRISCPU *cpu = CRIS_CPU(s);
CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(cpu);
CPUCRISState *env = &cpu->env;
+ uint32_t vr;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
ccc->parent_reset(s);
- cpu_state_reset(env);
+ vr = env->pregs[PR_VR];
+ memset(env, 0, offsetof(CPUCRISState, breakpoints));
+ env->pregs[PR_VR] = vr;
+ tlb_flush(env, 1);
+
+#if defined(CONFIG_USER_ONLY)
+ /* start in user mode with interrupts enabled. */
+ env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
+#else
+ cris_mmu_init(env);
+ env->pregs[PR_CCS] = 0;
+#endif
}
static void cris_cpu_class_init(ObjectClass *oc, void *data)
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 26c3f0b..d3dbac2 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3515,7 +3515,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
env->pregs[PR_VR] = vr_by_name(cpu_model);
cpu_exec_init(env);
- cpu_state_reset(env);
+ cpu_reset(CPU(cpu));
qemu_init_vcpu(env);
if (tcg_initialized)
@@ -3577,25 +3577,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
void cpu_state_reset(CPUCRISState *env)
{
- uint32_t vr;
-
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- vr = env->pregs[PR_VR];
- memset(env, 0, offsetof(CPUCRISState, breakpoints));
- env->pregs[PR_VR] = vr;
- tlb_flush(env, 1);
-
-#if defined(CONFIG_USER_ONLY)
- /* start in user mode with interrupts enabled. */
- env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
-#else
- cris_mmu_init(env);
- env->pregs[PR_CCS] = 0;
-#endif
+ cpu_reset(ENV_GET_CPU(env));
}
void restore_state_to_opc(CPUCRISState *env, TranslationBlock *tb, int pc_pos)
commit e739a48e58c41fc0d3caa24103abef9988c77cdf
Author: Andreas Färber <afaerber at suse.de>
Date: Wed Apr 11 23:12:05 2012 +0200
target-cris: QOM'ify CPU
Embed CPUCRISState as first member of QOM CRISCPU.
Let CPUClass::reset() call cpu_state_reset() for now.
Signed-off-by: Andreas Färber <afaerber at suse.de>
diff --git a/Makefile.target b/Makefile.target
index 7eda443..1b5d62b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -94,6 +94,7 @@ libobj-$(TARGET_SPARC64) += vis_helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-$(TARGET_ARM) += cpu.o
+libobj-$(TARGET_CRIS) += cpu.o
libobj-$(TARGET_LM32) += cpu.o
libobj-$(TARGET_S390X) += cpu.o
ifeq ($(TARGET_BASE_ARCH), sparc)
diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h
new file mode 100644
index 0000000..d0e5f04
--- /dev/null
+++ b/target-cris/cpu-qom.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU CRIS CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_CRIS_CPU_QOM_H
+#define QEMU_CRIS_CPU_QOM_H
+
+#include "qemu/cpu.h"
+
+#define TYPE_CRIS_CPU "cris-cpu"
+
+#define CRIS_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(CRISCPUClass, (klass), TYPE_CRIS_CPU)
+#define CRIS_CPU(obj) \
+ OBJECT_CHECK(CRISCPU, (obj), TYPE_CRIS_CPU)
+#define CRIS_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(CRISCPUClass, (obj), TYPE_CRIS_CPU)
+
+/**
+ * CRISCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A CRIS CPU model.
+ */
+typedef struct CRISCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} CRISCPUClass;
+
+/**
+ * CRISCPU:
+ * @env: #CPUCRISState
+ *
+ * A CRIS CPU.
+ */
+typedef struct CRISCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUCRISState env;
+} CRISCPU;
+
+static inline CRISCPU *cris_env_get_cpu(CPUCRISState *env)
+{
+ return CRIS_CPU(container_of(env, CRISCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(cris_env_get_cpu(e))
+
+
+#endif
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
new file mode 100644
index 0000000..784846b
--- /dev/null
+++ b/target-cris/cpu.c
@@ -0,0 +1,60 @@
+/*
+ * QEMU CRIS CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu.h"
+#include "qemu-common.h"
+
+
+/* CPUClass::reset() */
+static void cris_cpu_reset(CPUState *s)
+{
+ CRISCPU *cpu = CRIS_CPU(s);
+ CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(cpu);
+ CPUCRISState *env = &cpu->env;
+
+ ccc->parent_reset(s);
+
+ cpu_state_reset(env);
+}
+
+static void cris_cpu_class_init(ObjectClass *oc, void *data)
+{
+ CPUClass *cc = CPU_CLASS(oc);
+ CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
+
+ ccc->parent_reset = cc->reset;
+ cc->reset = cris_cpu_reset;
+}
+
+static const TypeInfo cris_cpu_type_info = {
+ .name = TYPE_CRIS_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(CRISCPU),
+ .abstract = false,
+ .class_size = sizeof(CRISCPUClass),
+ .class_init = cris_cpu_class_init,
+};
+
+static void cris_cpu_register_types(void)
+{
+ type_register_static(&cris_cpu_type_info);
+}
+
+type_init(cris_cpu_register_types)
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 31899c2..5449cc4 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -169,6 +169,8 @@ typedef struct CPUCRISState {
void *load_info;
} CPUCRISState;
+#include "cpu-qom.h"
+
CPUCRISState *cpu_cris_init(const char *cpu_model);
int cpu_cris_exec(CPUCRISState *s);
void cpu_cris_close(CPUCRISState *s);
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 7224f46..26c3f0b 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3505,11 +3505,13 @@ static uint32_t vr_by_name(const char *name)
CPUCRISState *cpu_cris_init (const char *cpu_model)
{
+ CRISCPU *cpu;
CPUCRISState *env;
static int tcg_initialized = 0;
int i;
- env = g_malloc0(sizeof(CPUCRISState));
+ cpu = CRIS_CPU(object_new(TYPE_CRIS_CPU));
+ env = &cpu->env;
env->pregs[PR_VR] = vr_by_name(cpu_model);
cpu_exec_init(env);
commit 092dfc7714ad7983aeb0cada5d5983e9fde8d84c
Merge: 6454678... ce6bf17...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 15:02:53 2012 -0500
Merge remote-tracking branch 'origin/master' into staging
* origin/master:
qtest: fix memread and memwrite on 32 bit hosts
commit 645467842339207d895c41f4e4526507b95a636a
Merge: 1f8bcac... 57a33d8...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 14:29:11 2012 -0500
Merge remote-tracking branch 'qmp/queue/qmp' into staging
* qmp/queue/qmp:
qapi: g_hash_table_find() instead of GHashTableIter.
qmp: make block job command naming consistent
commit ce6bf17a97aa53496a385db5642a323ce3b877a1
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Mon Apr 23 18:53:38 2012 +0000
qtest: fix memread and memwrite on 32 bit hosts
Use PRIx64 to print 64 bit values to avoid truncation
on 32 bit hosts.
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/libqtest.c b/tests/libqtest.c
index d47969e..1ce6fa1 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -356,7 +356,7 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
gchar **args;
size_t i;
- qtest_sendf(s, "read 0x%x 0x%x\n", addr, size);
+ qtest_sendf(s, "read 0x%" PRIx64 " 0x%x\n", addr, size);
args = qtest_rsp(s, 2);
for (i = 0; i < size; i++) {
@@ -378,7 +378,7 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
const uint8_t *ptr = data;
size_t i;
- qtest_sendf(s, "write 0x%x 0x%x 0x", addr, size);
+ qtest_sendf(s, "write 0x%" PRIx64 " 0x%x 0x", addr, size);
for (i = 0; i < size; i++) {
qtest_sendf(s, "%02x", ptr[i]);
}
commit 1f8bcac09af61e58c5121aa0a932190700ad554d
Merge: cb4c254... 1042ec9...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 14:27:04 2012 -0500
Merge remote-tracking branch 'kwolf/for-anthony' into staging
* kwolf/for-anthony: (38 commits)
qemu-iotests: Fix test 031 for qcow2 v3 support
qemu-iotests: Add -o and make v3 the default for qcow2
qcow2: Zero write support
qemu-iotests: Test backing file COW with zero clusters
qemu-iotests: add a simple test for write_zeroes
qcow2: Support for feature table header extension
qcow2: Support reading zero clusters
qcow2: Version 3 images
qcow2: Ignore reserved bits in check_refcounts
qcow2: Ignore reserved bits in refcount table entries
qcow2: Simplify count_cow_clusters
qcow2: Refactor qcow2_free_any_clusters
qcow2: Ignore reserved bits in L1/L2 entries
qcow2: Fail write_compressed when overwriting data
qcow2: Ignore reserved bits in count_contiguous_clusters()
qcow2: Ignore reserved bits in get_cluster_offset
qcow2: Save disk size in snapshot header
Specification for qcow2 version 3
qcow2: Fix refcount block allocation during qcow2_alloc_cluster_at()
iotests: Resolve test failures caused by hostname
...
diff --cc block/nbd.c
index e0af5b4,524c9cf..56dbf6e
--- a/block/nbd.c
+++ b/block/nbd.c
@@@ -203,12 -191,13 +203,12 @@@ static int nbd_co_send_request(BDRVNBDS
qemu_co_mutex_lock(&s->send_mutex);
s->send_coroutine = qemu_coroutine_self();
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
- nbd_have_request, NULL, s);
+ nbd_have_request, s);
rc = nbd_send_request(s->sock, request);
- if (rc != -1 && iov) {
+ if (rc >= 0 && iov) {
ret = qemu_co_sendv(s->sock, iov, request->len, offset);
if (ret != request->len) {
- errno = -EIO;
- rc = -1;
+ return -EIO;
}
}
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
commit cb4c2548ea7cceef7260465773c6b8e634c186d4
Merge: 5469963... 02f5da1...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 14:15:09 2012 -0500
Merge remote-tracking branch 'origin/master' into staging
* origin/master:
fix BCD mask for date (Solaris 2.5 guest hang fix)
commit 02f5da11d694df75af454205d8d81ac73dea50f0
Author: Artyom Tarasenko <atar4qemu at gmail.com>
Date: Mon Apr 23 16:48:31 2012 +0200
fix BCD mask for date (Solaris 2.5 guest hang fix)
Fix BCD mask for date. The most visible effect of this patch is
Solaris 2.5.1 doesn't hang at boot if the day of month is >21.
Signed-off-by: Artyom Tarasenko <atar4qemu at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/hw/m48t59.c b/hw/m48t59.c
index 60bbb00..0c50f45 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -239,7 +239,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
break;
case 0x1FF5:
/* alarm date */
- tmp = from_bcd(val & 0x1F);
+ tmp = from_bcd(val & 0x3F);
if (tmp != 0) {
NVRAM->alarm.tm_mday = tmp;
NVRAM->buffer[0x1FF5] = val;
@@ -310,8 +310,8 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
break;
case 0x1FFD:
case 0x07FD:
- /* date */
- tmp = from_bcd(val & 0x1F);
+ /* date (BCD) */
+ tmp = from_bcd(val & 0x3F);
if (tmp != 0) {
get_time(NVRAM, &tm);
tm.tm_mday = tmp;
commit 5469963394eba2df7c0a093a3792dc82e060cd65
Merge: 53878a1... 3c30dd5...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 11:49:59 2012 -0500
Merge remote-tracking branch 'origin/master' into staging
* origin/master: (27 commits)
target-arm: Move reset handling to arm_cpu_reset
target-arm: Drop cpu_reset_model_id()
target-arm: Move cache ID register setup to cpu specific init fns
target-arm: Move OMAP cp15_i_{max,min} reset to cpu_state_reset
target-arm: Move feature register setup to per-CPU init fns
target-arm: Move iWMMXT wCID reset to cpu_state_reset
target-arm: Drop JTAG_ID documentation
target-arm: Move SCTLR reset value setup to per cpu init fns
target-arm: Move CTR setup to per cpu init fns
target-arm: Move MVFR* setup to per cpu init fns
target-arm: Move FPSID config to cpu init fns
target-arm: Move feature bit settings to CPU init fns
target-arm: Add QOM subclasses for each ARM cpu implementation
target-arm: remind to keep arm features in sync with linux-user/elfload.c
tci: GETPC() macro must return an uintptr_t
gdbstub: Synchronize CPU state unconditionally in gdb_set_cpu_pc
softfloat: make USE_SOFTFLOAT_STRUCT_TYPES compile
target-xtensa: add tests for LOOPNEZ and LOOPGTZ
target-xtensa: fix LOOPNEZ/LOOPGTZ translation
qtest: add m48t59 tests for Sparc
...
commit 57a33d89672d7c6b1864185652b7cae0747f8323
Author: NODA, Kai <nodakai at gmail.com>
Date: Sat Apr 21 22:41:27 2012 +0900
qapi: g_hash_table_find() instead of GHashTableIter.
GHashTableIter was first introduced in glib 2.16.
This patch removes it in favor of older g_hash_table_find()
for better compatibility with RHEL5.
Signed-off-by: NODA, Kai <nodakai at gmail.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index 74386b9..4cdc47d 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -87,20 +87,29 @@ static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
qiv->nb_stack++;
}
+/** Only for qmp_input_pop. */
+static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
+{
+ *(const char **)user_pkey = (const char *)key;
+ return TRUE;
+}
+
static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
{
- GHashTableIter iter;
- gpointer key;
+ assert(qiv->nb_stack > 0);
- if (qiv->strict && qiv->stack[qiv->nb_stack - 1].h) {
- g_hash_table_iter_init(&iter, qiv->stack[qiv->nb_stack - 1].h);
- if (g_hash_table_iter_next(&iter, &key, NULL)) {
- error_set(errp, QERR_QMP_EXTRA_MEMBER, (char *) key);
+ if (qiv->strict) {
+ GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
+ if (top_ht) {
+ if (g_hash_table_size(top_ht)) {
+ const char *key;
+ g_hash_table_find(top_ht, always_true, &key);
+ error_set(errp, QERR_QMP_EXTRA_MEMBER, key);
+ }
+ g_hash_table_unref(top_ht);
}
- g_hash_table_unref(qiv->stack[qiv->nb_stack - 1].h);
}
- assert(qiv->nb_stack > 0);
qiv->nb_stack--;
}
commit db58f9c0605fa151b8c4d691aa9ff4c6cf0de62e
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Wed Apr 11 16:27:10 2012 +0100
qmp: make block job command naming consistent
The block streaming and job commands used '_' instead of '-' for reasons
of compatibility with libvirt, which already included support for the
'_' naming. However, the semantics of block_job_cancel have changed and
libvirt now needs to handle the new semantics.
Since the old semantics were never in a QEMU release we can still rename
the commands to use '-' instead of '_'. Libvirt is also happy because
the new name can be used to distinguish QEMU binaries that support the
latest block-job-cancel semantics from those that include a downstream
block_job_cancel command.
Therefore, let's apply the QAPI/QMP naming rules to the block streaming
and job commands. QEMU 1.1 will be the first release with these
commands so no upstream users can break.
Note that HMP commands are left with '_' because that is the convention
there.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qapi-schema.json b/qapi-schema.json
index ace55f3..6499895 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1548,7 +1548,8 @@
'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
-# @block_stream:
+##
+# @block-stream:
#
# Copy data from a backing file into a block device.
#
@@ -1556,7 +1557,7 @@
# backing file has been copied. This command returns immediately once streaming
# has started. The status of ongoing block streaming operations can be checked
# with query-block-jobs. The operation can be stopped before it has completed
-# using the block_job_cancel command.
+# using the block-job-cancel command.
#
# If a base file is specified then sectors are not copied from that base file and
# its backing chain. When streaming completes the image file will have the base
@@ -1578,10 +1579,10 @@
#
# Since: 1.1
##
-{ 'command': 'block_stream', 'data': { 'device': 'str', '*base': 'str' } }
+{ 'command': 'block-stream', 'data': { 'device': 'str', '*base': 'str' } }
##
-# @block_job_set_speed:
+# @block-job-set-speed:
#
# Set maximum speed for a background block operation.
#
@@ -1599,11 +1600,11 @@
#
# Since: 1.1
##
-{ 'command': 'block_job_set_speed',
+{ 'command': 'block-job-set-speed',
'data': { 'device': 'str', 'value': 'int' } }
##
-# @block_job_cancel:
+# @block-job-cancel:
#
# Stop an active block streaming operation.
#
@@ -1629,7 +1630,7 @@
#
# Since: 1.1
##
-{ 'command': 'block_job_cancel', 'data': { 'device': 'str' } }
+{ 'command': 'block-job-cancel', 'data': { 'device': 'str' } }
##
# @ObjectTypeInfo:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index c09ee85..f972332 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -687,19 +687,19 @@ Example:
EQMP
{
- .name = "block_stream",
+ .name = "block-stream",
.args_type = "device:B,base:s?",
.mhandler.cmd_new = qmp_marshal_input_block_stream,
},
{
- .name = "block_job_set_speed",
+ .name = "block-job-set-speed",
.args_type = "device:B,value:o",
.mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
},
{
- .name = "block_job_cancel",
+ .name = "block-job-cancel",
.args_type = "device:B",
.mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
},
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 1faf984..978fd82 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -49,7 +49,7 @@ class TestSingleDrive(ImageStreamingTestCase):
def test_stream(self):
self.assert_no_active_streams()
- result = self.vm.qmp('block_stream', device='drive0')
+ result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
completed = False
@@ -68,7 +68,7 @@ class TestSingleDrive(ImageStreamingTestCase):
'image file not fully populated after streaming')
def test_device_not_found(self):
- result = self.vm.qmp('block_stream', device='nonexistent')
+ result = self.vm.qmp('block-stream', device='nonexistent')
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
class TestStreamStop(ImageStreamingTestCase):
@@ -90,14 +90,14 @@ class TestStreamStop(ImageStreamingTestCase):
self.assert_no_active_streams()
- result = self.vm.qmp('block_stream', device='drive0')
+ result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
time.sleep(1)
events = self.vm.get_qmp_events(wait=False)
self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
- self.vm.qmp('block_job_cancel', device='drive0')
+ self.vm.qmp('block-job-cancel', device='drive0')
self.assert_qmp(result, 'return', {})
cancelled = False
@@ -129,10 +129,10 @@ class TestSetSpeed(ImageStreamingTestCase):
def perf_test_set_speed(self):
self.assert_no_active_streams()
- result = self.vm.qmp('block_stream', device='drive0')
+ result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
- result = self.vm.qmp('block_job_set_speed', device='drive0', value=8 * 1024 * 1024)
+ result = self.vm.qmp('block-job-set-speed', device='drive0', value=8 * 1024 * 1024)
self.assert_qmp(result, 'return', {})
completed = False
commit 53878a132aaadbedbe8fe0e44afa032a4ed73aea
Merge: 6b03296... 4c9f8d1...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 09:58:54 2012 -0500
Merge remote-tracking branch 'sstabellini/build_fix' into staging
* sstabellini/build_fix:
xen: add a dummy xc_hvm_inject_msi for Xen < 4.2
xen,configure: detect Xen 4.2
commit 6b03296606c665beb570eaa53a71f7688a43b9e7
Merge: 25896d8... fecccc4...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 09:58:33 2012 -0500
Merge remote-tracking branch 'stefanha/trivial-patches' into staging
* stefanha/trivial-patches:
Add .gitignore for tests/
e1000: Fix spelling (segmentaion -> segmentation) in debug output
spice-qemu-char.c: Show what name is unsupported
pflash_cfi01: remove redundant line
qxl: Add missing GCC_FMT_ATTR and fix format specifier
fix block_job_set_speed name in documentation
error.c: don't return value for void function
commit 25896d8063f0ea02d4cc9159f6da622aeb115945
Merge: bec8eb8... 4bdd041...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 09:58:19 2012 -0500
Merge remote-tracking branch 'mdroth/qga-pull-4-19-12' into staging
* mdroth/qga-pull-4-19-12:
qemu-ga: fix help output
qemu-ga: generate missing stubs for fsfreeze
commit bec8eb8136309104d18a4757d20470883f0d5ac1
Merge: 4a1873f... e25ceb7...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 09:58:01 2012 -0500
Merge remote-tracking branch 'bonzini/nbd-next' into staging
* bonzini/nbd-next:
nbd: obey FUA on reads
nbd: do not include block_int.h
nbd: do not block in nbd_wr_sync if no data at all is available
nbd: consistently return negative errno values
nbd: consistently check for <0 or >=0
nbd: consistently use ssize_t
nbd: avoid out of bounds access to recv_coroutine array
commit 4a1873fc8c3f692fcae25ed1ebf10003d5d5feb0
Merge: e5e3895... 3e46d87...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 09:57:47 2012 -0500
Merge remote-tracking branch 'bonzini/scsi-next' into staging
* bonzini/scsi-next:
scsi: add SANITIZE command
SCSI emulation: should tell the guest that we actually support thin provisioning
SCSI emulation: Support unmap via WRITE_SAME_10.
scsi: advertise DPOFUA
scsi: small refactoring of MMC mode-sense
scsi: support FUA on reads
scsi: add a started field to SCSIDiskReq
scsi: force unit access on VERIFY
scsi: add support for FUA on writes
scsi: move scsi_flush_complete around
scsi: make code more homogeneous in AIO callback functions
scsi: add missing test for cancelled request
virtio-scsi: add multiqueue capability
virtio: add virtio_queue_get_id
virtio-scsi: prepare migration format for multiqueue
scsi: fix memory leak
commit e5e3895702514253120965cfda75c58f28c39a00
Merge: 51006bb... 256a721...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Apr 23 09:57:04 2012 -0500
Merge remote-tracking branch 'stefanha/tracing' into staging
* stefanha/tracing:
tracetool: handle DTrace keywords 'in', 'next', 'self'
tracetool: Add MAINTAINERS info
tracetool: Add support for the 'dtrace' backend
tracetool: Add support for the 'ust' backend
tracetool: Add support for the 'simple' backend
tracetool: Add support for the 'stderr' backend
tracetool: Add module for the 'h' format
tracetool: Add module for the 'c' format
tracetool: Rewrite infrastructure as python modules
commit 3c30dd5a68e9fee6af67cfd0d14ed7520820f36a
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:36 2012 +0000
target-arm: Move reset handling to arm_cpu_reset
Now that cpu_reset_model_id() has gone we can move the
reset code over to the class reset function and have cpu_state_reset
simply do a reset on the CPU QOM object.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 8259a0d..cc67d4d 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -20,18 +20,106 @@
#include "cpu-qom.h"
#include "qemu-common.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/loader.h"
+#endif
/* CPUClass::reset() */
static void arm_cpu_reset(CPUState *s)
{
ARMCPU *cpu = ARM_CPU(s);
ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
+ CPUARMState *env = &cpu->env;
+ uint32_t tmp = 0;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
acc->parent_reset(s);
- /* TODO Inline the current contents of cpu_state_reset(),
- once cpu_reset_model_id() is eliminated. */
- cpu_state_reset(&cpu->env);
+ tmp = env->cp15.c15_config_base_address;
+ memset(env, 0, offsetof(CPUARMState, breakpoints));
+ env->cp15.c15_config_base_address = tmp;
+ env->cp15.c0_cpuid = cpu->midr;
+ env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
+ env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
+ env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
+ env->cp15.c0_cachetype = cpu->ctr;
+ env->cp15.c1_sys = cpu->reset_sctlr;
+ env->cp15.c0_c1[0] = cpu->id_pfr0;
+ env->cp15.c0_c1[1] = cpu->id_pfr1;
+ env->cp15.c0_c1[2] = cpu->id_dfr0;
+ env->cp15.c0_c1[3] = cpu->id_afr0;
+ env->cp15.c0_c1[4] = cpu->id_mmfr0;
+ env->cp15.c0_c1[5] = cpu->id_mmfr1;
+ env->cp15.c0_c1[6] = cpu->id_mmfr2;
+ env->cp15.c0_c1[7] = cpu->id_mmfr3;
+ env->cp15.c0_c2[0] = cpu->id_isar0;
+ env->cp15.c0_c2[1] = cpu->id_isar1;
+ env->cp15.c0_c2[2] = cpu->id_isar2;
+ env->cp15.c0_c2[3] = cpu->id_isar3;
+ env->cp15.c0_c2[4] = cpu->id_isar4;
+ env->cp15.c0_c2[5] = cpu->id_isar5;
+ env->cp15.c15_i_min = 0xff0;
+ env->cp15.c0_clid = cpu->clidr;
+ memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr));
+
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
+ }
+
+#if defined(CONFIG_USER_ONLY)
+ env->uncached_cpsr = ARM_CPU_MODE_USR;
+ /* For user mode we must enable access to coprocessors */
+ env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ env->cp15.c15_cpar = 3;
+ } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ env->cp15.c15_cpar = 1;
+ }
+#else
+ /* SVC mode with interrupts disabled. */
+ env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+ /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
+ clear at reset. Initial SP and PC are loaded from ROM. */
+ if (IS_M(env)) {
+ uint32_t pc;
+ uint8_t *rom;
+ env->uncached_cpsr &= ~CPSR_I;
+ rom = rom_ptr(0);
+ if (rom) {
+ /* We should really use ldl_phys here, in case the guest
+ modified flash and reset itself. However images
+ loaded via -kernel have not been copied yet, so load the
+ values directly from there. */
+ env->regs[13] = ldl_p(rom);
+ pc = ldl_p(rom + 4);
+ env->thumb = pc & 1;
+ env->regs[15] = pc & ~1;
+ }
+ }
+ env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+ env->cp15.c2_base_mask = 0xffffc000u;
+ /* v7 performance monitor control register: same implementor
+ * field as main ID register, and we implement no event counters.
+ */
+ env->cp15.c9_pmcr = (cpu->midr & 0xff000000);
+#endif
+ set_flush_to_zero(1, &env->vfp.standard_fp_status);
+ set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
+ set_default_nan_mode(1, &env->vfp.standard_fp_status);
+ set_float_detect_tininess(float_tininess_before_rounding,
+ &env->vfp.fp_status);
+ set_float_detect_tininess(float_tininess_before_rounding,
+ &env->vfp.standard_fp_status);
+ tlb_flush(env, 1);
+ /* Reset is a state change for some CPUARMState fields which we
+ * bake assumptions about into translated code, so we need to
+ * tb_flush().
+ */
+ tb_flush(env);
}
static inline void set_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 653885a..101031d 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2,106 +2,11 @@
#include "gdbstub.h"
#include "helper.h"
#include "host-utils.h"
-#if !defined(CONFIG_USER_ONLY)
-#include "hw/loader.h"
-#endif
#include "sysemu.h"
-/* TODO Move contents into arm_cpu_reset() in cpu.c,
- * once cpu_reset_model_id() is eliminated,
- * and then forward to cpu_reset() here.
- */
void cpu_state_reset(CPUARMState *env)
{
- uint32_t tmp = 0;
- ARMCPU *cpu = arm_env_get_cpu(env);
-
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- tmp = env->cp15.c15_config_base_address;
- memset(env, 0, offsetof(CPUARMState, breakpoints));
- env->cp15.c15_config_base_address = tmp;
- env->cp15.c0_cpuid = cpu->midr;
- env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
- env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
- env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
- env->cp15.c0_cachetype = cpu->ctr;
- env->cp15.c1_sys = cpu->reset_sctlr;
- env->cp15.c0_c1[0] = cpu->id_pfr0;
- env->cp15.c0_c1[1] = cpu->id_pfr1;
- env->cp15.c0_c1[2] = cpu->id_dfr0;
- env->cp15.c0_c1[3] = cpu->id_afr0;
- env->cp15.c0_c1[4] = cpu->id_mmfr0;
- env->cp15.c0_c1[5] = cpu->id_mmfr1;
- env->cp15.c0_c1[6] = cpu->id_mmfr2;
- env->cp15.c0_c1[7] = cpu->id_mmfr3;
- env->cp15.c0_c2[0] = cpu->id_isar0;
- env->cp15.c0_c2[1] = cpu->id_isar1;
- env->cp15.c0_c2[2] = cpu->id_isar2;
- env->cp15.c0_c2[3] = cpu->id_isar3;
- env->cp15.c0_c2[4] = cpu->id_isar4;
- env->cp15.c0_c2[5] = cpu->id_isar5;
- env->cp15.c15_i_min = 0xff0;
- env->cp15.c0_clid = cpu->clidr;
- memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr));
-
- if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
- env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
- }
-
-#if defined (CONFIG_USER_ONLY)
- env->uncached_cpsr = ARM_CPU_MODE_USR;
- /* For user mode we must enable access to coprocessors */
- env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
- if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
- env->cp15.c15_cpar = 3;
- } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
- env->cp15.c15_cpar = 1;
- }
-#else
- /* SVC mode with interrupts disabled. */
- env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
- /* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
- clear at reset. Initial SP and PC are loaded from ROM. */
- if (IS_M(env)) {
- uint32_t pc;
- uint8_t *rom;
- env->uncached_cpsr &= ~CPSR_I;
- rom = rom_ptr(0);
- if (rom) {
- /* We should really use ldl_phys here, in case the guest
- modified flash and reset itself. However images
- loaded via -kernel have not been copied yet, so load the
- values directly from there. */
- env->regs[13] = ldl_p(rom);
- pc = ldl_p(rom + 4);
- env->thumb = pc & 1;
- env->regs[15] = pc & ~1;
- }
- }
- env->vfp.xregs[ARM_VFP_FPEXC] = 0;
- env->cp15.c2_base_mask = 0xffffc000u;
- /* v7 performance monitor control register: same implementor
- * field as main ID register, and we implement no event counters.
- */
- env->cp15.c9_pmcr = (cpu->midr & 0xff000000);
-#endif
- set_flush_to_zero(1, &env->vfp.standard_fp_status);
- set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
- set_default_nan_mode(1, &env->vfp.standard_fp_status);
- set_float_detect_tininess(float_tininess_before_rounding,
- &env->vfp.fp_status);
- set_float_detect_tininess(float_tininess_before_rounding,
- &env->vfp.standard_fp_status);
- tlb_flush(env, 1);
- /* Reset is a state change for some CPUARMState fields which we
- * bake assumptions about into translated code, so we need to
- * tb_flush().
- */
- tb_flush(env);
+ cpu_reset(ENV_GET_CPU(env));
}
static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
commit caa1d0779e956afe694922ca4bf7e2903356fcff
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:35 2012 +0000
target-arm: Drop cpu_reset_model_id()
cpu_reset_model_id() is now empty and we can remove it.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5cbc7e0..653885a 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -7,66 +7,12 @@
#endif
#include "sysemu.h"
-static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
-{
- switch (id) {
- case ARM_CPUID_ARM926:
- break;
- case ARM_CPUID_ARM946:
- break;
- case ARM_CPUID_ARM1026:
- break;
- case ARM_CPUID_ARM1136:
- /* This is the 1136 r1, which is a v6K core */
- case ARM_CPUID_ARM1136_R2:
- break;
- case ARM_CPUID_ARM1176:
- break;
- case ARM_CPUID_ARM11MPCORE:
- break;
- case ARM_CPUID_CORTEXA8:
- break;
- case ARM_CPUID_CORTEXA9:
- break;
- case ARM_CPUID_CORTEXA15:
- break;
- case ARM_CPUID_CORTEXM3:
- break;
- case ARM_CPUID_ANY: /* For userspace emulation. */
- break;
- case ARM_CPUID_TI915T:
- case ARM_CPUID_TI925T:
- break;
- case ARM_CPUID_PXA250:
- case ARM_CPUID_PXA255:
- case ARM_CPUID_PXA260:
- case ARM_CPUID_PXA261:
- case ARM_CPUID_PXA262:
- break;
- case ARM_CPUID_PXA270_A0:
- case ARM_CPUID_PXA270_A1:
- case ARM_CPUID_PXA270_B0:
- case ARM_CPUID_PXA270_B1:
- case ARM_CPUID_PXA270_C0:
- case ARM_CPUID_PXA270_C5:
- break;
- case ARM_CPUID_SA1100:
- case ARM_CPUID_SA1110:
- break;
- default:
- cpu_abort(env, "Bad CPU ID: %x\n", id);
- break;
- }
-
-}
-
/* TODO Move contents into arm_cpu_reset() in cpu.c,
* once cpu_reset_model_id() is eliminated,
* and then forward to cpu_reset() here.
*/
void cpu_state_reset(CPUARMState *env)
{
- uint32_t id;
uint32_t tmp = 0;
ARMCPU *cpu = arm_env_get_cpu(env);
@@ -75,11 +21,8 @@ void cpu_state_reset(CPUARMState *env)
log_cpu_state(env, 0);
}
- id = cpu->midr;
tmp = env->cp15.c15_config_base_address;
memset(env, 0, offsetof(CPUARMState, breakpoints));
- if (id)
- cpu_reset_model_id(env, id);
env->cp15.c15_config_base_address = tmp;
env->cp15.c0_cpuid = cpu->midr;
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
@@ -144,7 +87,7 @@ void cpu_state_reset(CPUARMState *env)
/* v7 performance monitor control register: same implementor
* field as main ID register, and we implement no event counters.
*/
- env->cp15.c9_pmcr = (id & 0xff000000);
+ env->cp15.c9_pmcr = (cpu->midr & 0xff000000);
#endif
set_flush_to_zero(1, &env->vfp.standard_fp_status);
set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
commit 85df3786b21191d49d17dcb77f45ae75f6addad0
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:35 2012 +0000
target-arm: Move cache ID register setup to cpu specific init fns
Move cache ID register reset out of cpu_reset_model_id() by
creating a field for the reset value in ARMCPU and setting it
up in the cpu specific init functions.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 7603eff..b6c044a 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -89,6 +89,11 @@ typedef struct ARMCPU {
uint32_t id_isar3;
uint32_t id_isar4;
uint32_t id_isar5;
+ uint32_t clidr;
+ /* The elements of this array are the CCSIDR values for each cache,
+ * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
+ */
+ uint32_t ccsidr[16];
} ARMCPU;
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 333f7fc..8259a0d 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -270,6 +270,10 @@ static void cortex_a8_initfn(Object *obj)
cpu->id_isar2 = 0x21232031;
cpu->id_isar3 = 0x11112131;
cpu->id_isar4 = 0x00111142;
+ cpu->clidr = (1 << 27) | (2 << 24) | 3;
+ cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */
+ cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */
+ cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */
}
static void cortex_a9_initfn(Object *obj)
@@ -304,6 +308,9 @@ static void cortex_a9_initfn(Object *obj)
cpu->id_isar2 = 0x21232041;
cpu->id_isar3 = 0x11112131;
cpu->id_isar4 = 0x00111142;
+ cpu->clidr = (1 << 27) | (1 << 24) | 3;
+ cpu->ccsidr[0] = 0xe00fe015; /* 16k L1 dcache. */
+ cpu->ccsidr[1] = 0x200fe015; /* 16k L1 icache. */
}
static void cortex_a15_initfn(Object *obj)
@@ -336,6 +343,10 @@ static void cortex_a15_initfn(Object *obj)
cpu->id_isar2 = 0x21232041;
cpu->id_isar3 = 0x11112131;
cpu->id_isar4 = 0x10011142;
+ cpu->clidr = 0x0a200023;
+ cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
+ cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
+ cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
}
static void ti925t_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index fb618a7..5cbc7e0 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -25,21 +25,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_ARM11MPCORE:
break;
case ARM_CPUID_CORTEXA8:
- env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
- env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
- env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
- env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
break;
case ARM_CPUID_CORTEXA9:
- env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
- env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
- env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
break;
case ARM_CPUID_CORTEXA15:
- env->cp15.c0_clid = 0x0a200023;
- env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
- env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
- env->cp15.c0_ccsid[2] = 0x711fe07a; /* 4096K L2 unified cache */
break;
case ARM_CPUID_CORTEXM3:
break;
@@ -113,6 +102,8 @@ void cpu_state_reset(CPUARMState *env)
env->cp15.c0_c2[4] = cpu->id_isar4;
env->cp15.c0_c2[5] = cpu->id_isar5;
env->cp15.c15_i_min = 0xff0;
+ env->cp15.c0_clid = cpu->clidr;
+ memcpy(env->cp15.c0_ccsid, cpu->ccsidr, ARRAY_SIZE(cpu->ccsidr));
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
commit 8092d2f031e70eb2664d5fa1d9ed00ef1113ee71
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:35 2012 +0000
target-arm: Move OMAP cp15_i_{max,min} reset to cpu_state_reset
Move the OMAP-specific cp15_i_{max,min} reset to cpu_state_reset;
since these registers are only accessible on CPUs with the
OMAPCP feature set there's no need to guard this reset with
either a CPUID or feature bit check.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 84830ff..fb618a7 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -47,8 +47,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
break;
case ARM_CPUID_TI915T:
case ARM_CPUID_TI925T:
- env->cp15.c15_i_max = 0x000;
- env->cp15.c15_i_min = 0xff0;
break;
case ARM_CPUID_PXA250:
case ARM_CPUID_PXA255:
@@ -114,6 +112,7 @@ void cpu_state_reset(CPUARMState *env)
env->cp15.c0_c2[3] = cpu->id_isar3;
env->cp15.c0_c2[4] = cpu->id_isar4;
env->cp15.c0_c2[5] = cpu->id_isar5;
+ env->cp15.c15_i_min = 0xff0;
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
commit 2e4d7e3e3e97c4e0e68aca6221e3e7cb10b6041c
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:34 2012 +0000
target-arm: Move feature register setup to per-CPU init fns
Move feature register value setup to per-CPU init functions.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 97f7e90..7603eff 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -75,6 +75,20 @@ typedef struct ARMCPU {
uint32_t mvfr1;
uint32_t ctr;
uint32_t reset_sctlr;
+ uint32_t id_pfr0;
+ uint32_t id_pfr1;
+ uint32_t id_dfr0;
+ uint32_t id_afr0;
+ uint32_t id_mmfr0;
+ uint32_t id_mmfr1;
+ uint32_t id_mmfr2;
+ uint32_t id_mmfr3;
+ uint32_t id_isar0;
+ uint32_t id_isar1;
+ uint32_t id_isar2;
+ uint32_t id_isar3;
+ uint32_t id_isar4;
+ uint32_t id_isar5;
} ARMCPU;
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 74a7d20..333f7fc 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -130,6 +130,13 @@ static void arm1026_initfn(Object *obj)
static void arm1136_r2_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
+ * older core than plain "arm1136". In particular this does not
+ * have the v6K features.
+ * These ID register values are correct for 1136 but may be wrong
+ * for 1136_r2 (in particular r0p2 does not actually implement most
+ * of the ID registers).
+ */
set_feature(&cpu->env, ARM_FEATURE_V6);
set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM1136_R2;
@@ -138,6 +145,18 @@ static void arm1136_r2_initfn(Object *obj)
cpu->mvfr1 = 0x00000000;
cpu->ctr = 0x1dd20d2;
cpu->reset_sctlr = 0x00050078;
+ cpu->id_pfr0 = 0x111;
+ cpu->id_pfr1 = 0x1;
+ cpu->id_dfr0 = 0x2;
+ cpu->id_afr0 = 0x3;
+ cpu->id_mmfr0 = 0x01130003;
+ cpu->id_mmfr1 = 0x10030302;
+ cpu->id_mmfr2 = 0x01222110;
+ cpu->id_isar0 = 0x00140011;
+ cpu->id_isar1 = 0x12002111;
+ cpu->id_isar2 = 0x11231111;
+ cpu->id_isar3 = 0x01102131;
+ cpu->id_isar4 = 0x141;
}
static void arm1136_initfn(Object *obj)
@@ -152,6 +171,18 @@ static void arm1136_initfn(Object *obj)
cpu->mvfr1 = 0x00000000;
cpu->ctr = 0x1dd20d2;
cpu->reset_sctlr = 0x00050078;
+ cpu->id_pfr0 = 0x111;
+ cpu->id_pfr1 = 0x1;
+ cpu->id_dfr0 = 0x2;
+ cpu->id_afr0 = 0x3;
+ cpu->id_mmfr0 = 0x01130003;
+ cpu->id_mmfr1 = 0x10030302;
+ cpu->id_mmfr2 = 0x01222110;
+ cpu->id_isar0 = 0x00140011;
+ cpu->id_isar1 = 0x12002111;
+ cpu->id_isar2 = 0x11231111;
+ cpu->id_isar3 = 0x01102131;
+ cpu->id_isar4 = 0x141;
}
static void arm1176_initfn(Object *obj)
@@ -166,6 +197,18 @@ static void arm1176_initfn(Object *obj)
cpu->mvfr1 = 0x00000000;
cpu->ctr = 0x1dd20d2;
cpu->reset_sctlr = 0x00050078;
+ cpu->id_pfr0 = 0x111;
+ cpu->id_pfr1 = 0x11;
+ cpu->id_dfr0 = 0x33;
+ cpu->id_afr0 = 0;
+ cpu->id_mmfr0 = 0x01130003;
+ cpu->id_mmfr1 = 0x10030302;
+ cpu->id_mmfr2 = 0x01222100;
+ cpu->id_isar0 = 0x0140011;
+ cpu->id_isar1 = 0x12002111;
+ cpu->id_isar2 = 0x11231121;
+ cpu->id_isar3 = 0x01102131;
+ cpu->id_isar4 = 0x01141;
}
static void arm11mpcore_initfn(Object *obj)
@@ -179,6 +222,18 @@ static void arm11mpcore_initfn(Object *obj)
cpu->mvfr0 = 0x11111111;
cpu->mvfr1 = 0x00000000;
cpu->ctr = 0x1dd20d2;
+ cpu->id_pfr0 = 0x111;
+ cpu->id_pfr1 = 0x1;
+ cpu->id_dfr0 = 0;
+ cpu->id_afr0 = 0x2;
+ cpu->id_mmfr0 = 0x01100103;
+ cpu->id_mmfr1 = 0x10020302;
+ cpu->id_mmfr2 = 0x01222000;
+ cpu->id_isar0 = 0x00100011;
+ cpu->id_isar1 = 0x12002111;
+ cpu->id_isar2 = 0x11221011;
+ cpu->id_isar3 = 0x01102131;
+ cpu->id_isar4 = 0x141;
}
static void cortex_m3_initfn(Object *obj)
@@ -202,6 +257,19 @@ static void cortex_a8_initfn(Object *obj)
cpu->mvfr1 = 0x00011100;
cpu->ctr = 0x82048004;
cpu->reset_sctlr = 0x00c50078;
+ cpu->id_pfr0 = 0x1031;
+ cpu->id_pfr1 = 0x11;
+ cpu->id_dfr0 = 0x400;
+ cpu->id_afr0 = 0;
+ cpu->id_mmfr0 = 0x31100003;
+ cpu->id_mmfr1 = 0x20000000;
+ cpu->id_mmfr2 = 0x01202000;
+ cpu->id_mmfr3 = 0x11;
+ cpu->id_isar0 = 0x00101111;
+ cpu->id_isar1 = 0x12112111;
+ cpu->id_isar2 = 0x21232031;
+ cpu->id_isar3 = 0x11112131;
+ cpu->id_isar4 = 0x00111142;
}
static void cortex_a9_initfn(Object *obj)
@@ -223,6 +291,19 @@ static void cortex_a9_initfn(Object *obj)
cpu->mvfr1 = 0x01111111;
cpu->ctr = 0x80038003;
cpu->reset_sctlr = 0x00c50078;
+ cpu->id_pfr0 = 0x1031;
+ cpu->id_pfr1 = 0x11;
+ cpu->id_dfr0 = 0x000;
+ cpu->id_afr0 = 0;
+ cpu->id_mmfr0 = 0x00100103;
+ cpu->id_mmfr1 = 0x20000000;
+ cpu->id_mmfr2 = 0x01230000;
+ cpu->id_mmfr3 = 0x00002111;
+ cpu->id_isar0 = 0x00101111;
+ cpu->id_isar1 = 0x13112111;
+ cpu->id_isar2 = 0x21232041;
+ cpu->id_isar3 = 0x11112131;
+ cpu->id_isar4 = 0x00111142;
}
static void cortex_a15_initfn(Object *obj)
@@ -242,6 +323,19 @@ static void cortex_a15_initfn(Object *obj)
cpu->mvfr1 = 0x11111111;
cpu->ctr = 0x8444c004;
cpu->reset_sctlr = 0x00c50078;
+ cpu->id_pfr0 = 0x00001131;
+ cpu->id_pfr1 = 0x00011011;
+ cpu->id_dfr0 = 0x02010555;
+ cpu->id_afr0 = 0x00000000;
+ cpu->id_mmfr0 = 0x10201105;
+ cpu->id_mmfr1 = 0x20000000;
+ cpu->id_mmfr2 = 0x01240000;
+ cpu->id_mmfr3 = 0x02102211;
+ cpu->id_isar0 = 0x02101110;
+ cpu->id_isar1 = 0x13112111;
+ cpu->id_isar2 = 0x21232041;
+ cpu->id_isar3 = 0x11112131;
+ cpu->id_isar4 = 0x10011142;
}
static void ti925t_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 319614a..84830ff 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -7,45 +7,6 @@
#endif
#include "sysemu.h"
-static uint32_t cortexa15_cp15_c0_c1[8] = {
- 0x00001131, 0x00011011, 0x02010555, 0x00000000,
- 0x10201105, 0x20000000, 0x01240000, 0x02102211
-};
-
-static uint32_t cortexa15_cp15_c0_c2[8] = {
- 0x02101110, 0x13112111, 0x21232041, 0x11112131, 0x10011142, 0, 0, 0
-};
-
-static uint32_t cortexa9_cp15_c0_c1[8] =
-{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
-
-static uint32_t cortexa9_cp15_c0_c2[8] =
-{ 0x00101111, 0x13112111, 0x21232041, 0x11112131, 0x00111142, 0, 0, 0 };
-
-static uint32_t cortexa8_cp15_c0_c1[8] =
-{ 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 };
-
-static uint32_t cortexa8_cp15_c0_c2[8] =
-{ 0x00101111, 0x12112111, 0x21232031, 0x11112131, 0x00111142, 0, 0, 0 };
-
-static uint32_t mpcore_cp15_c0_c1[8] =
-{ 0x111, 0x1, 0, 0x2, 0x01100103, 0x10020302, 0x01222000, 0 };
-
-static uint32_t mpcore_cp15_c0_c2[8] =
-{ 0x00100011, 0x12002111, 0x11221011, 0x01102131, 0x141, 0, 0, 0 };
-
-static uint32_t arm1136_cp15_c0_c1[8] =
-{ 0x111, 0x1, 0x2, 0x3, 0x01130003, 0x10030302, 0x01222110, 0 };
-
-static uint32_t arm1136_cp15_c0_c2[8] =
-{ 0x00140011, 0x12002111, 0x11231111, 0x01102131, 0x141, 0, 0, 0 };
-
-static uint32_t arm1176_cp15_c0_c1[8] =
-{ 0x111, 0x11, 0x33, 0, 0x01130003, 0x10030302, 0x01222100, 0 };
-
-static uint32_t arm1176_cp15_c0_c2[8] =
-{ 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
-
static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
switch (id) {
@@ -58,43 +19,23 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_ARM1136:
/* This is the 1136 r1, which is a v6K core */
case ARM_CPUID_ARM1136_R2:
- /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
- * older core than plain "arm1136". In particular this does not
- * have the v6K features.
- */
- /* These ID register values are correct for 1136 but may be wrong
- * for 1136_r2 (in particular r0p2 does not actually implement most
- * of the ID registers).
- */
- memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
break;
case ARM_CPUID_ARM1176:
- memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
break;
case ARM_CPUID_ARM11MPCORE:
- memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
break;
case ARM_CPUID_CORTEXA8:
- memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
break;
case ARM_CPUID_CORTEXA9:
- memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
break;
case ARM_CPUID_CORTEXA15:
- memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
- memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_clid = 0x0a200023;
env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
@@ -159,6 +100,20 @@ void cpu_state_reset(CPUARMState *env)
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
env->cp15.c0_cachetype = cpu->ctr;
env->cp15.c1_sys = cpu->reset_sctlr;
+ env->cp15.c0_c1[0] = cpu->id_pfr0;
+ env->cp15.c0_c1[1] = cpu->id_pfr1;
+ env->cp15.c0_c1[2] = cpu->id_dfr0;
+ env->cp15.c0_c1[3] = cpu->id_afr0;
+ env->cp15.c0_c1[4] = cpu->id_mmfr0;
+ env->cp15.c0_c1[5] = cpu->id_mmfr1;
+ env->cp15.c0_c1[6] = cpu->id_mmfr2;
+ env->cp15.c0_c1[7] = cpu->id_mmfr3;
+ env->cp15.c0_c2[0] = cpu->id_isar0;
+ env->cp15.c0_c2[1] = cpu->id_isar1;
+ env->cp15.c0_c2[2] = cpu->id_isar2;
+ env->cp15.c0_c2[3] = cpu->id_isar3;
+ env->cp15.c0_c2[4] = cpu->id_isar4;
+ env->cp15.c0_c2[5] = cpu->id_isar5;
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
commit 0cc892fd97b2d232ae45a30aec342a2e0fb148aa
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:34 2012 +0000
target-arm: Move iWMMXT wCID reset to cpu_state_reset
Move the iWMMXT wCID reset to cpu_state_reset(). Since
we use the same value for all CPUs with this feature
(with the major/minor revision fields set to the QEMU
specific 'Q' value) there's no need to create an ARMCPU
field just for this.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Reviewed-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3e31f94..319614a 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -121,7 +121,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA270_B1:
case ARM_CPUID_PXA270_C0:
case ARM_CPUID_PXA270_C5:
- env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
break;
case ARM_CPUID_SA1100:
case ARM_CPUID_SA1110:
@@ -161,6 +160,10 @@ void cpu_state_reset(CPUARMState *env)
env->cp15.c0_cachetype = cpu->ctr;
env->cp15.c1_sys = cpu->reset_sctlr;
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
+ }
+
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
/* For user mode we must enable access to coprocessors */
commit 4e851c380eda2bf27ff2ded85e4c80a342e6a72f
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:33 2012 +0000
target-arm: Drop JTAG_ID documentation
None of the machines in QEMU offer a JTAG debug interface, so this info
was unused. Further, the PXA250 ID contradicts the February 2002
Developer's Manual, which has it as 0xn9264013 with n the MIDR Revision.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/target-arm/helper.c b/target-arm/helper.c
index eab25ca..3e31f94 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -114,7 +114,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA260:
case ARM_CPUID_PXA261:
case ARM_CPUID_PXA262:
- /* JTAG_ID is ((id << 28) | 0x09265013) */
break;
case ARM_CPUID_PXA270_A0:
case ARM_CPUID_PXA270_A1:
@@ -122,7 +121,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA270_B1:
case ARM_CPUID_PXA270_C0:
case ARM_CPUID_PXA270_C5:
- /* JTAG_ID is ((id << 28) | 0x09265013) */
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
break;
case ARM_CPUID_SA1100:
commit 0ca7e01cbc5f2850560e6a170ae1e4541aecce17
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:33 2012 +0000
target-arm: Move SCTLR reset value setup to per cpu init fns
Move the reset value of SCTLR to ARMCPU, initialised in
the per-cpu init functions. It can then be reset by a
simple copy, and we can drop the code from cpu_reset_model_id().
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index cb9198a..97f7e90 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -74,6 +74,7 @@ typedef struct ARMCPU {
uint32_t mvfr0;
uint32_t mvfr1;
uint32_t ctr;
+ uint32_t reset_sctlr;
} ARMCPU;
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 4f19d5c..74a7d20 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -102,6 +102,7 @@ static void arm926_initfn(Object *obj)
cpu->midr = ARM_CPUID_ARM926;
cpu->reset_fpsid = 0x41011090;
cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00090078;
}
static void arm946_initfn(Object *obj)
@@ -111,6 +112,7 @@ static void arm946_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_MPU);
cpu->midr = ARM_CPUID_ARM946;
cpu->ctr = 0x0f004006;
+ cpu->reset_sctlr = 0x00000078;
}
static void arm1026_initfn(Object *obj)
@@ -122,6 +124,7 @@ static void arm1026_initfn(Object *obj)
cpu->midr = ARM_CPUID_ARM1026;
cpu->reset_fpsid = 0x410110a0;
cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00090078;
}
static void arm1136_r2_initfn(Object *obj)
@@ -134,6 +137,7 @@ static void arm1136_r2_initfn(Object *obj)
cpu->mvfr0 = 0x11111111;
cpu->mvfr1 = 0x00000000;
cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00050078;
}
static void arm1136_initfn(Object *obj)
@@ -147,6 +151,7 @@ static void arm1136_initfn(Object *obj)
cpu->mvfr0 = 0x11111111;
cpu->mvfr1 = 0x00000000;
cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00050078;
}
static void arm1176_initfn(Object *obj)
@@ -160,6 +165,7 @@ static void arm1176_initfn(Object *obj)
cpu->mvfr0 = 0x11111111;
cpu->mvfr1 = 0x00000000;
cpu->ctr = 0x1dd20d2;
+ cpu->reset_sctlr = 0x00050078;
}
static void arm11mpcore_initfn(Object *obj)
@@ -195,6 +201,7 @@ static void cortex_a8_initfn(Object *obj)
cpu->mvfr0 = 0x11110222;
cpu->mvfr1 = 0x00011100;
cpu->ctr = 0x82048004;
+ cpu->reset_sctlr = 0x00c50078;
}
static void cortex_a9_initfn(Object *obj)
@@ -215,6 +222,7 @@ static void cortex_a9_initfn(Object *obj)
cpu->mvfr0 = 0x11110222;
cpu->mvfr1 = 0x01111111;
cpu->ctr = 0x80038003;
+ cpu->reset_sctlr = 0x00c50078;
}
static void cortex_a15_initfn(Object *obj)
@@ -233,6 +241,7 @@ static void cortex_a15_initfn(Object *obj)
cpu->mvfr0 = 0x10110222;
cpu->mvfr1 = 0x11111111;
cpu->ctr = 0x8444c004;
+ cpu->reset_sctlr = 0x00c50078;
}
static void ti925t_initfn(Object *obj)
@@ -242,6 +251,7 @@ static void ti925t_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_OMAPCP);
cpu->midr = ARM_CPUID_TI925T;
cpu->ctr = 0x5109149;
+ cpu->reset_sctlr = 0x00000070;
}
static void sa1100_initfn(Object *obj)
@@ -249,6 +259,7 @@ static void sa1100_initfn(Object *obj)
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
cpu->midr = ARM_CPUID_SA1100;
+ cpu->reset_sctlr = 0x00000070;
}
static void sa1110_initfn(Object *obj)
@@ -256,6 +267,7 @@ static void sa1110_initfn(Object *obj)
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
cpu->midr = ARM_CPUID_SA1110;
+ cpu->reset_sctlr = 0x00000070;
}
static void pxa250_initfn(Object *obj)
@@ -265,6 +277,7 @@ static void pxa250_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA250;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa255_initfn(Object *obj)
@@ -274,6 +287,7 @@ static void pxa255_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA255;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa260_initfn(Object *obj)
@@ -283,6 +297,7 @@ static void pxa260_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA260;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa261_initfn(Object *obj)
@@ -292,6 +307,7 @@ static void pxa261_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA261;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa262_initfn(Object *obj)
@@ -301,6 +317,7 @@ static void pxa262_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA262;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa270a0_initfn(Object *obj)
@@ -311,6 +328,7 @@ static void pxa270a0_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_A0;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa270a1_initfn(Object *obj)
@@ -321,6 +339,7 @@ static void pxa270a1_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_A1;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa270b0_initfn(Object *obj)
@@ -331,6 +350,7 @@ static void pxa270b0_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_B0;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa270b1_initfn(Object *obj)
@@ -341,6 +361,7 @@ static void pxa270b1_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_B1;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa270c0_initfn(Object *obj)
@@ -351,6 +372,7 @@ static void pxa270c0_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_C0;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void pxa270c5_initfn(Object *obj)
@@ -361,6 +383,7 @@ static void pxa270c5_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_C5;
cpu->ctr = 0xd172172;
+ cpu->reset_sctlr = 0x00000078;
}
static void arm_any_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index a23df14..eab25ca 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -50,13 +50,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
switch (id) {
case ARM_CPUID_ARM926:
- env->cp15.c1_sys = 0x00090078;
break;
case ARM_CPUID_ARM946:
- env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_ARM1026:
- env->cp15.c1_sys = 0x00090078;
break;
case ARM_CPUID_ARM1136:
/* This is the 1136 r1, which is a v6K core */
@@ -71,12 +68,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
*/
memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM1176:
memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM11MPCORE:
memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -89,7 +84,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
- env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXA9:
memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -97,7 +91,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
- env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXA15:
memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -106,7 +99,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
env->cp15.c0_ccsid[2] = 0x711fe07a; /* 4096K L2 unified cache */
- env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXM3:
break;
@@ -114,7 +106,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
break;
case ARM_CPUID_TI915T:
case ARM_CPUID_TI925T:
- env->cp15.c1_sys = 0x00000070;
env->cp15.c15_i_max = 0x000;
env->cp15.c15_i_min = 0xff0;
break;
@@ -124,7 +115,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA261:
case ARM_CPUID_PXA262:
/* JTAG_ID is ((id << 28) | 0x09265013) */
- env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_PXA270_A0:
case ARM_CPUID_PXA270_A1:
@@ -134,11 +124,9 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA270_C5:
/* JTAG_ID is ((id << 28) | 0x09265013) */
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
- env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_SA1100:
case ARM_CPUID_SA1110:
- env->cp15.c1_sys = 0x00000070;
break;
default:
cpu_abort(env, "Bad CPU ID: %x\n", id);
@@ -173,6 +161,7 @@ void cpu_state_reset(CPUARMState *env)
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
env->cp15.c0_cachetype = cpu->ctr;
+ env->cp15.c1_sys = cpu->reset_sctlr;
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
commit 64e1671fd46669f097763f71b9a8cbcc0bf61cce
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:33 2012 +0000
target-arm: Move CTR setup to per cpu init fns
Move CTR (cache type register) value to an ARMCPU field
set up by per-cpu init fns.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index c51eb84..cb9198a 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -73,6 +73,7 @@ typedef struct ARMCPU {
uint32_t reset_fpsid;
uint32_t mvfr0;
uint32_t mvfr1;
+ uint32_t ctr;
} ARMCPU;
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 80ca7aa..4f19d5c 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -101,6 +101,7 @@ static void arm926_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM926;
cpu->reset_fpsid = 0x41011090;
+ cpu->ctr = 0x1dd20d2;
}
static void arm946_initfn(Object *obj)
@@ -109,6 +110,7 @@ static void arm946_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_MPU);
cpu->midr = ARM_CPUID_ARM946;
+ cpu->ctr = 0x0f004006;
}
static void arm1026_initfn(Object *obj)
@@ -119,6 +121,7 @@ static void arm1026_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_AUXCR);
cpu->midr = ARM_CPUID_ARM1026;
cpu->reset_fpsid = 0x410110a0;
+ cpu->ctr = 0x1dd20d2;
}
static void arm1136_r2_initfn(Object *obj)
@@ -130,6 +133,7 @@ static void arm1136_r2_initfn(Object *obj)
cpu->reset_fpsid = 0x410120b4;
cpu->mvfr0 = 0x11111111;
cpu->mvfr1 = 0x00000000;
+ cpu->ctr = 0x1dd20d2;
}
static void arm1136_initfn(Object *obj)
@@ -142,6 +146,7 @@ static void arm1136_initfn(Object *obj)
cpu->reset_fpsid = 0x410120b4;
cpu->mvfr0 = 0x11111111;
cpu->mvfr1 = 0x00000000;
+ cpu->ctr = 0x1dd20d2;
}
static void arm1176_initfn(Object *obj)
@@ -154,6 +159,7 @@ static void arm1176_initfn(Object *obj)
cpu->reset_fpsid = 0x410120b5;
cpu->mvfr0 = 0x11111111;
cpu->mvfr1 = 0x00000000;
+ cpu->ctr = 0x1dd20d2;
}
static void arm11mpcore_initfn(Object *obj)
@@ -166,6 +172,7 @@ static void arm11mpcore_initfn(Object *obj)
cpu->reset_fpsid = 0x410120b4;
cpu->mvfr0 = 0x11111111;
cpu->mvfr1 = 0x00000000;
+ cpu->ctr = 0x1dd20d2;
}
static void cortex_m3_initfn(Object *obj)
@@ -187,6 +194,7 @@ static void cortex_a8_initfn(Object *obj)
cpu->reset_fpsid = 0x410330c0;
cpu->mvfr0 = 0x11110222;
cpu->mvfr1 = 0x00011100;
+ cpu->ctr = 0x82048004;
}
static void cortex_a9_initfn(Object *obj)
@@ -206,6 +214,7 @@ static void cortex_a9_initfn(Object *obj)
cpu->reset_fpsid = 0x41033090;
cpu->mvfr0 = 0x11110222;
cpu->mvfr1 = 0x01111111;
+ cpu->ctr = 0x80038003;
}
static void cortex_a15_initfn(Object *obj)
@@ -223,6 +232,7 @@ static void cortex_a15_initfn(Object *obj)
cpu->reset_fpsid = 0x410430f0;
cpu->mvfr0 = 0x10110222;
cpu->mvfr1 = 0x11111111;
+ cpu->ctr = 0x8444c004;
}
static void ti925t_initfn(Object *obj)
@@ -231,6 +241,7 @@ static void ti925t_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V4T);
set_feature(&cpu->env, ARM_FEATURE_OMAPCP);
cpu->midr = ARM_CPUID_TI925T;
+ cpu->ctr = 0x5109149;
}
static void sa1100_initfn(Object *obj)
@@ -253,6 +264,7 @@ static void pxa250_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA250;
+ cpu->ctr = 0xd172172;
}
static void pxa255_initfn(Object *obj)
@@ -261,6 +273,7 @@ static void pxa255_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA255;
+ cpu->ctr = 0xd172172;
}
static void pxa260_initfn(Object *obj)
@@ -269,6 +282,7 @@ static void pxa260_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA260;
+ cpu->ctr = 0xd172172;
}
static void pxa261_initfn(Object *obj)
@@ -277,6 +291,7 @@ static void pxa261_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA261;
+ cpu->ctr = 0xd172172;
}
static void pxa262_initfn(Object *obj)
@@ -285,6 +300,7 @@ static void pxa262_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA262;
+ cpu->ctr = 0xd172172;
}
static void pxa270a0_initfn(Object *obj)
@@ -294,6 +310,7 @@ static void pxa270a0_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_A0;
+ cpu->ctr = 0xd172172;
}
static void pxa270a1_initfn(Object *obj)
@@ -303,6 +320,7 @@ static void pxa270a1_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_A1;
+ cpu->ctr = 0xd172172;
}
static void pxa270b0_initfn(Object *obj)
@@ -312,6 +330,7 @@ static void pxa270b0_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_B0;
+ cpu->ctr = 0xd172172;
}
static void pxa270b1_initfn(Object *obj)
@@ -321,6 +340,7 @@ static void pxa270b1_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_B1;
+ cpu->ctr = 0xd172172;
}
static void pxa270c0_initfn(Object *obj)
@@ -330,6 +350,7 @@ static void pxa270c0_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_C0;
+ cpu->ctr = 0xd172172;
}
static void pxa270c5_initfn(Object *obj)
@@ -339,6 +360,7 @@ static void pxa270c5_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_XSCALE);
set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_C5;
+ cpu->ctr = 0xd172172;
}
static void arm_any_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 777bb03..a23df14 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -50,15 +50,12 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
switch (id) {
case ARM_CPUID_ARM926:
- env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00090078;
break;
case ARM_CPUID_ARM946:
- env->cp15.c0_cachetype = 0x0f004006;
env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_ARM1026:
- env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00090078;
break;
case ARM_CPUID_ARM1136:
@@ -74,24 +71,20 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
*/
memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM1176:
memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM11MPCORE:
memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x1dd20d2;
break;
case ARM_CPUID_CORTEXA8:
memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x82048004;
env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
@@ -101,7 +94,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_CORTEXA9:
memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x80038003;
env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
@@ -110,7 +102,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_CORTEXA15:
memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x8444c004;
env->cp15.c0_clid = 0x0a200023;
env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
@@ -123,7 +114,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
break;
case ARM_CPUID_TI915T:
case ARM_CPUID_TI925T:
- env->cp15.c0_cachetype = 0x5109149;
env->cp15.c1_sys = 0x00000070;
env->cp15.c15_i_max = 0x000;
env->cp15.c15_i_min = 0xff0;
@@ -134,7 +124,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA261:
case ARM_CPUID_PXA262:
/* JTAG_ID is ((id << 28) | 0x09265013) */
- env->cp15.c0_cachetype = 0xd172172;
env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_PXA270_A0:
@@ -145,7 +134,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA270_C5:
/* JTAG_ID is ((id << 28) | 0x09265013) */
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
- env->cp15.c0_cachetype = 0xd172172;
env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_SA1100:
@@ -184,6 +172,7 @@ void cpu_state_reset(CPUARMState *env)
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
+ env->cp15.c0_cachetype = cpu->ctr;
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
commit bd35c3553bfe6acb47034b1bfb2cf093684f406d
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:32 2012 +0000
target-arm: Move MVFR* setup to per cpu init fns
Move the MVFR* VFP feature register values to ARMCPU,
so they are set up by the implementation-specific instance
init functions rather than in cpu_reset_model_id().
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 7cc4cd5..c51eb84 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -71,6 +71,8 @@ typedef struct ARMCPU {
*/
uint32_t midr;
uint32_t reset_fpsid;
+ uint32_t mvfr0;
+ uint32_t mvfr1;
} ARMCPU;
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 5fb7803..80ca7aa 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -128,6 +128,8 @@ static void arm1136_r2_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM1136_R2;
cpu->reset_fpsid = 0x410120b4;
+ cpu->mvfr0 = 0x11111111;
+ cpu->mvfr1 = 0x00000000;
}
static void arm1136_initfn(Object *obj)
@@ -138,6 +140,8 @@ static void arm1136_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM1136;
cpu->reset_fpsid = 0x410120b4;
+ cpu->mvfr0 = 0x11111111;
+ cpu->mvfr1 = 0x00000000;
}
static void arm1176_initfn(Object *obj)
@@ -148,6 +152,8 @@ static void arm1176_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VAPA);
cpu->midr = ARM_CPUID_ARM1176;
cpu->reset_fpsid = 0x410120b5;
+ cpu->mvfr0 = 0x11111111;
+ cpu->mvfr1 = 0x00000000;
}
static void arm11mpcore_initfn(Object *obj)
@@ -158,6 +164,8 @@ static void arm11mpcore_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VAPA);
cpu->midr = ARM_CPUID_ARM11MPCORE;
cpu->reset_fpsid = 0x410120b4;
+ cpu->mvfr0 = 0x11111111;
+ cpu->mvfr1 = 0x00000000;
}
static void cortex_m3_initfn(Object *obj)
@@ -177,6 +185,8 @@ static void cortex_a8_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
cpu->midr = ARM_CPUID_CORTEXA8;
cpu->reset_fpsid = 0x410330c0;
+ cpu->mvfr0 = 0x11110222;
+ cpu->mvfr1 = 0x00011100;
}
static void cortex_a9_initfn(Object *obj)
@@ -194,6 +204,8 @@ static void cortex_a9_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V7MP);
cpu->midr = ARM_CPUID_CORTEXA9;
cpu->reset_fpsid = 0x41033090;
+ cpu->mvfr0 = 0x11110222;
+ cpu->mvfr1 = 0x01111111;
}
static void cortex_a15_initfn(Object *obj)
@@ -209,6 +221,8 @@ static void cortex_a15_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
cpu->midr = ARM_CPUID_CORTEXA15;
cpu->reset_fpsid = 0x410430f0;
+ cpu->mvfr0 = 0x10110222;
+ cpu->mvfr1 = 0x11111111;
}
static void ti925t_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3247dd3..777bb03 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -72,31 +72,23 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
* for 1136_r2 (in particular r0p2 does not actually implement most
* of the ID registers).
*/
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM1176:
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, arm1176_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM11MPCORE:
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_cachetype = 0x1dd20d2;
break;
case ARM_CPUID_CORTEXA8:
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_cachetype = 0x82048004;
@@ -107,8 +99,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXA9:
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, cortexa9_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_cachetype = 0x80038003;
@@ -118,8 +108,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXA15:
- env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
- env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
env->cp15.c0_cachetype = 0x8444c004;
@@ -194,6 +182,8 @@ void cpu_state_reset(CPUARMState *env)
env->cp15.c15_config_base_address = tmp;
env->cp15.c0_cpuid = cpu->midr;
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
+ env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
+ env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
commit 325b3ceff69c987e90acf9c8ef6f55e646b39767
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:32 2012 +0000
target-arm: Move FPSID config to cpu init fns
Move the reset FPSID to the ARMCPU struct, and set it in the
per-implementation instance init function. At reset we then
just copy the reset value into the CPUARMState field.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 7e2d4c9..7cc4cd5 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -70,6 +70,7 @@ typedef struct ARMCPU {
* prefix means a constant register.
*/
uint32_t midr;
+ uint32_t reset_fpsid;
} ARMCPU;
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 46fbc2d..5fb7803 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -100,6 +100,7 @@ static void arm926_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM926;
+ cpu->reset_fpsid = 0x41011090;
}
static void arm946_initfn(Object *obj)
@@ -117,6 +118,7 @@ static void arm1026_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_AUXCR);
cpu->midr = ARM_CPUID_ARM1026;
+ cpu->reset_fpsid = 0x410110a0;
}
static void arm1136_r2_initfn(Object *obj)
@@ -125,6 +127,7 @@ static void arm1136_r2_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V6);
set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM1136_R2;
+ cpu->reset_fpsid = 0x410120b4;
}
static void arm1136_initfn(Object *obj)
@@ -134,6 +137,7 @@ static void arm1136_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V6);
set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM1136;
+ cpu->reset_fpsid = 0x410120b4;
}
static void arm1176_initfn(Object *obj)
@@ -143,6 +147,7 @@ static void arm1176_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_VAPA);
cpu->midr = ARM_CPUID_ARM1176;
+ cpu->reset_fpsid = 0x410120b5;
}
static void arm11mpcore_initfn(Object *obj)
@@ -152,6 +157,7 @@ static void arm11mpcore_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_VAPA);
cpu->midr = ARM_CPUID_ARM11MPCORE;
+ cpu->reset_fpsid = 0x410120b4;
}
static void cortex_m3_initfn(Object *obj)
@@ -170,6 +176,7 @@ static void cortex_a8_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
cpu->midr = ARM_CPUID_CORTEXA8;
+ cpu->reset_fpsid = 0x410330c0;
}
static void cortex_a9_initfn(Object *obj)
@@ -186,6 +193,7 @@ static void cortex_a9_initfn(Object *obj)
*/
set_feature(&cpu->env, ARM_FEATURE_V7MP);
cpu->midr = ARM_CPUID_CORTEXA9;
+ cpu->reset_fpsid = 0x41033090;
}
static void cortex_a15_initfn(Object *obj)
@@ -200,6 +208,7 @@ static void cortex_a15_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V7MP);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
cpu->midr = ARM_CPUID_CORTEXA15;
+ cpu->reset_fpsid = 0x410430f0;
}
static void ti925t_initfn(Object *obj)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index e495de6..3247dd3 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -50,7 +50,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
switch (id) {
case ARM_CPUID_ARM926:
- env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00090078;
break;
@@ -59,7 +58,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_ARM1026:
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00090078;
break;
@@ -74,7 +72,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
* for 1136_r2 (in particular r0p2 does not actually implement most
* of the ID registers).
*/
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -83,7 +80,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM1176:
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
memcpy(env->cp15.c0_c1, arm1176_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -92,7 +88,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM11MPCORE:
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -100,7 +95,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_cachetype = 0x1dd20d2;
break;
case ARM_CPUID_CORTEXA8:
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -113,7 +107,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXA9:
- env->vfp.xregs[ARM_VFP_FPSID] = 0x41033090;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
memcpy(env->cp15.c0_c1, cortexa9_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -125,7 +118,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXA15:
- env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
@@ -201,6 +193,8 @@ void cpu_state_reset(CPUARMState *env)
cpu_reset_model_id(env, id);
env->cp15.c15_config_base_address = tmp;
env->cp15.c0_cpuid = cpu->midr;
+ env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
+
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
/* For user mode we must enable access to coprocessors */
commit 581be09434f155ebe0ee7b532c20974843188958
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:31 2012 +0000
target-arm: Move feature bit settings to CPU init fns
Move the setting of the feature bits from cpu_reset_model_id()
to each CPU's instance init function. This requires us to move
the features field in CPUARMState so that it is not cleared
on reset.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index a4bcb31..7e2d4c9 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -79,5 +79,6 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
#define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e))
+void arm_cpu_realize(ARMCPU *cpu);
#endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 6d4f8fe..46fbc2d 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -34,6 +34,11 @@ static void arm_cpu_reset(CPUState *s)
cpu_state_reset(&cpu->env);
}
+static inline void set_feature(CPUARMState *env, int feature)
+{
+ env->features |= 1u << feature;
+}
+
static void arm_cpu_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -41,161 +46,288 @@ static void arm_cpu_initfn(Object *obj)
cpu_exec_init(&cpu->env);
}
+void arm_cpu_realize(ARMCPU *cpu)
+{
+ /* This function is called by cpu_arm_init() because it
+ * needs to do common actions based on feature bits, etc
+ * that have been set by the subclass init functions.
+ * When we have QOM realize support it should become
+ * a true realize function instead.
+ */
+ CPUARMState *env = &cpu->env;
+ /* Some features automatically imply others: */
+ if (arm_feature(env, ARM_FEATURE_V7)) {
+ set_feature(env, ARM_FEATURE_VAPA);
+ set_feature(env, ARM_FEATURE_THUMB2);
+ if (!arm_feature(env, ARM_FEATURE_M)) {
+ set_feature(env, ARM_FEATURE_V6K);
+ } else {
+ set_feature(env, ARM_FEATURE_V6);
+ }
+ }
+ if (arm_feature(env, ARM_FEATURE_V6K)) {
+ set_feature(env, ARM_FEATURE_V6);
+ set_feature(env, ARM_FEATURE_MVFR);
+ }
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ set_feature(env, ARM_FEATURE_V5);
+ if (!arm_feature(env, ARM_FEATURE_M)) {
+ set_feature(env, ARM_FEATURE_AUXCR);
+ }
+ }
+ if (arm_feature(env, ARM_FEATURE_V5)) {
+ set_feature(env, ARM_FEATURE_V4T);
+ }
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ set_feature(env, ARM_FEATURE_THUMB_DIV);
+ }
+ if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
+ set_feature(env, ARM_FEATURE_THUMB_DIV);
+ }
+ if (arm_feature(env, ARM_FEATURE_VFP4)) {
+ set_feature(env, ARM_FEATURE_VFP3);
+ }
+ if (arm_feature(env, ARM_FEATURE_VFP3)) {
+ set_feature(env, ARM_FEATURE_VFP);
+ }
+}
+
/* CPU models */
static void arm926_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM926;
}
static void arm946_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_MPU);
cpu->midr = ARM_CPUID_ARM946;
}
static void arm1026_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ set_feature(&cpu->env, ARM_FEATURE_AUXCR);
cpu->midr = ARM_CPUID_ARM1026;
}
static void arm1136_r2_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V6);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM1136_R2;
}
static void arm1136_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V6K);
+ set_feature(&cpu->env, ARM_FEATURE_V6);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
cpu->midr = ARM_CPUID_ARM1136;
}
static void arm1176_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V6K);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ set_feature(&cpu->env, ARM_FEATURE_VAPA);
cpu->midr = ARM_CPUID_ARM1176;
}
static void arm11mpcore_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V6K);
+ set_feature(&cpu->env, ARM_FEATURE_VFP);
+ set_feature(&cpu->env, ARM_FEATURE_VAPA);
cpu->midr = ARM_CPUID_ARM11MPCORE;
}
static void cortex_m3_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_M);
cpu->midr = ARM_CPUID_CORTEXM3;
}
static void cortex_a8_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_VFP3);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
cpu->midr = ARM_CPUID_CORTEXA8;
}
static void cortex_a9_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_VFP3);
+ set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ /* Note that A9 supports the MP extensions even for
+ * A9UP and single-core A9MP (which are both different
+ * and valid configurations; we don't model A9UP).
+ */
+ set_feature(&cpu->env, ARM_FEATURE_V7MP);
cpu->midr = ARM_CPUID_CORTEXA9;
}
static void cortex_a15_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_VFP4);
+ set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
+ set_feature(&cpu->env, ARM_FEATURE_V7MP);
+ set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
cpu->midr = ARM_CPUID_CORTEXA15;
}
static void ti925t_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V4T);
+ set_feature(&cpu->env, ARM_FEATURE_OMAPCP);
cpu->midr = ARM_CPUID_TI925T;
}
static void sa1100_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
cpu->midr = ARM_CPUID_SA1100;
}
static void sa1110_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
cpu->midr = ARM_CPUID_SA1110;
}
static void pxa250_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA250;
}
static void pxa255_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA255;
}
static void pxa260_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA260;
}
static void pxa261_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA261;
}
static void pxa262_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
cpu->midr = ARM_CPUID_PXA262;
}
static void pxa270a0_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_A0;
}
static void pxa270a1_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_A1;
}
static void pxa270b0_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_B0;
}
static void pxa270b1_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_B1;
}
static void pxa270c0_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_C0;
}
static void pxa270c5_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V5);
+ set_feature(&cpu->env, ARM_FEATURE_XSCALE);
+ set_feature(&cpu->env, ARM_FEATURE_IWMMXT);
cpu->midr = ARM_CPUID_PXA270_C5;
}
static void arm_any_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ set_feature(&cpu->env, ARM_FEATURE_V7);
+ set_feature(&cpu->env, ARM_FEATURE_VFP4);
+ set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+ set_feature(&cpu->env, ARM_FEATURE_NEON);
+ set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+ set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
+ set_feature(&cpu->env, ARM_FEATURE_V7MP);
cpu->midr = ARM_CPUID_ANY;
}
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index d2f5c76..01e0e36 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -170,9 +170,6 @@ typedef struct CPUARMState {
uint32_t teecr;
uint32_t teehbr;
- /* Internal CPU feature flags. */
- uint32_t features;
-
/* VFP coprocessor state. */
struct {
float64 regs[32];
@@ -228,6 +225,9 @@ typedef struct CPUARMState {
/* These fields after the common ones so they are preserved on reset. */
+ /* Internal CPU feature flags. */
+ uint32_t features;
+
/* Coprocessor IO used by peripherals */
struct {
ARMReadCPFunc *cp_read;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index afcd68c..e495de6 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -46,46 +46,30 @@ static uint32_t arm1176_cp15_c0_c1[8] =
static uint32_t arm1176_cp15_c0_c2[8] =
{ 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
-static inline void set_feature(CPUARMState *env, int feature)
-{
- env->features |= 1u << feature;
-}
-
static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
switch (id) {
case ARM_CPUID_ARM926:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_VFP);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00090078;
break;
case ARM_CPUID_ARM946:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_MPU);
env->cp15.c0_cachetype = 0x0f004006;
env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_ARM1026:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_VFP);
- set_feature(env, ARM_FEATURE_AUXCR);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00090078;
break;
case ARM_CPUID_ARM1136:
/* This is the 1136 r1, which is a v6K core */
- set_feature(env, ARM_FEATURE_V6K);
- /* Fall through */
case ARM_CPUID_ARM1136_R2:
/* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
* older core than plain "arm1136". In particular this does not
* have the v6K features.
*/
- set_feature(env, ARM_FEATURE_V6);
- set_feature(env, ARM_FEATURE_VFP);
/* These ID register values are correct for 1136 but may be wrong
* for 1136_r2 (in particular r0p2 does not actually implement most
* of the ID registers).
@@ -99,9 +83,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM1176:
- set_feature(env, ARM_FEATURE_V6K);
- set_feature(env, ARM_FEATURE_VFP);
- set_feature(env, ARM_FEATURE_VAPA);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -111,9 +92,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00050078;
break;
case ARM_CPUID_ARM11MPCORE:
- set_feature(env, ARM_FEATURE_V6K);
- set_feature(env, ARM_FEATURE_VFP);
- set_feature(env, ARM_FEATURE_VAPA);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -122,10 +100,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_cachetype = 0x1dd20d2;
break;
case ARM_CPUID_CORTEXA8:
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_VFP3);
- set_feature(env, ARM_FEATURE_NEON);
- set_feature(env, ARM_FEATURE_THUMB2EE);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
@@ -139,16 +113,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXA9:
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_VFP3);
- set_feature(env, ARM_FEATURE_VFP_FP16);
- set_feature(env, ARM_FEATURE_NEON);
- set_feature(env, ARM_FEATURE_THUMB2EE);
- /* Note that A9 supports the MP extensions even for
- * A9UP and single-core A9MP (which are both different
- * and valid configurations; we don't model A9UP).
- */
- set_feature(env, ARM_FEATURE_V7MP);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41033090;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
@@ -161,14 +125,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXA15:
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_VFP4);
- set_feature(env, ARM_FEATURE_VFP_FP16);
- set_feature(env, ARM_FEATURE_NEON);
- set_feature(env, ARM_FEATURE_THUMB2EE);
- set_feature(env, ARM_FEATURE_ARM_DIV);
- set_feature(env, ARM_FEATURE_V7MP);
- set_feature(env, ARM_FEATURE_GENERIC_TIMER);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
@@ -182,22 +138,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c1_sys = 0x00c50078;
break;
case ARM_CPUID_CORTEXM3:
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_M);
break;
case ARM_CPUID_ANY: /* For userspace emulation. */
- set_feature(env, ARM_FEATURE_V7);
- set_feature(env, ARM_FEATURE_VFP4);
- set_feature(env, ARM_FEATURE_VFP_FP16);
- set_feature(env, ARM_FEATURE_NEON);
- set_feature(env, ARM_FEATURE_THUMB2EE);
- set_feature(env, ARM_FEATURE_ARM_DIV);
- set_feature(env, ARM_FEATURE_V7MP);
break;
case ARM_CPUID_TI915T:
case ARM_CPUID_TI925T:
- set_feature(env, ARM_FEATURE_V4T);
- set_feature(env, ARM_FEATURE_OMAPCP);
env->cp15.c0_cachetype = 0x5109149;
env->cp15.c1_sys = 0x00000070;
env->cp15.c15_i_max = 0x000;
@@ -208,8 +153,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA260:
case ARM_CPUID_PXA261:
case ARM_CPUID_PXA262:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_XSCALE);
/* JTAG_ID is ((id << 28) | 0x09265013) */
env->cp15.c0_cachetype = 0xd172172;
env->cp15.c1_sys = 0x00000078;
@@ -220,17 +163,13 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA270_B1:
case ARM_CPUID_PXA270_C0:
case ARM_CPUID_PXA270_C5:
- set_feature(env, ARM_FEATURE_V5);
- set_feature(env, ARM_FEATURE_XSCALE);
/* JTAG_ID is ((id << 28) | 0x09265013) */
- set_feature(env, ARM_FEATURE_IWMMXT);
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
env->cp15.c0_cachetype = 0xd172172;
env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_SA1100:
case ARM_CPUID_SA1110:
- set_feature(env, ARM_FEATURE_STRONGARM);
env->cp15.c1_sys = 0x00000070;
break;
default:
@@ -238,41 +177,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
break;
}
- /* Some features automatically imply others: */
- if (arm_feature(env, ARM_FEATURE_V7)) {
- set_feature(env, ARM_FEATURE_VAPA);
- set_feature(env, ARM_FEATURE_THUMB2);
- if (!arm_feature(env, ARM_FEATURE_M)) {
- set_feature(env, ARM_FEATURE_V6K);
- } else {
- set_feature(env, ARM_FEATURE_V6);
- }
- }
- if (arm_feature(env, ARM_FEATURE_V6K)) {
- set_feature(env, ARM_FEATURE_V6);
- set_feature(env, ARM_FEATURE_MVFR);
- }
- if (arm_feature(env, ARM_FEATURE_V6)) {
- set_feature(env, ARM_FEATURE_V5);
- if (!arm_feature(env, ARM_FEATURE_M)) {
- set_feature(env, ARM_FEATURE_AUXCR);
- }
- }
- if (arm_feature(env, ARM_FEATURE_V5)) {
- set_feature(env, ARM_FEATURE_V4T);
- }
- if (arm_feature(env, ARM_FEATURE_M)) {
- set_feature(env, ARM_FEATURE_THUMB_DIV);
- }
- if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
- set_feature(env, ARM_FEATURE_THUMB_DIV);
- }
- if (arm_feature(env, ARM_FEATURE_VFP4)) {
- set_feature(env, ARM_FEATURE_VFP3);
- }
- if (arm_feature(env, ARM_FEATURE_VFP3)) {
- set_feature(env, ARM_FEATURE_VFP);
- }
}
/* TODO Move contents into arm_cpu_reset() in cpu.c,
@@ -413,6 +317,7 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
cpu = ARM_CPU(object_new(cpu_model));
env = &cpu->env;
env->cpu_model_str = cpu_model;
+ arm_cpu_realize(cpu);
if (tcg_enabled() && !inited) {
inited = 1;
commit 777dc78411865f2721f8728c71edb0b215da57fc
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 17:58:31 2012 +0000
target-arm: Add QOM subclasses for each ARM cpu implementation
Register subclasses for each ARM CPU implementation.
Let arm_cpu_list() enumerate CPU subclasses in alphabetical order,
except for special value "any".
Replace cpu_arm_find_by_name()'s string -> CPUID lookup by storing the
CPUID (aka MIDR, Main ID Register) value in the class.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 42d2a6b..a4bcb31 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -58,6 +58,18 @@ typedef struct ARMCPU {
/*< public >*/
CPUARMState env;
+
+ /* The instance init functions for implementation-specific subclasses
+ * set these fields to specify the implementation-dependent values of
+ * various constant registers and reset values of non-constant
+ * registers.
+ * Some of these might become QOM properties eventually.
+ * Field names match the official register names as defined in the
+ * ARMv7AR ARM Architecture Reference Manual. A reset_ prefix
+ * is used for reset values of non-constant registers; no reset_
+ * prefix means a constant register.
+ */
+ uint32_t midr;
} ARMCPU;
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index c3ed45b..6d4f8fe 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -34,6 +34,211 @@ static void arm_cpu_reset(CPUState *s)
cpu_state_reset(&cpu->env);
}
+static void arm_cpu_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ cpu_exec_init(&cpu->env);
+}
+
+/* CPU models */
+
+static void arm926_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_ARM926;
+}
+
+static void arm946_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_ARM946;
+}
+
+static void arm1026_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_ARM1026;
+}
+
+static void arm1136_r2_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_ARM1136_R2;
+}
+
+static void arm1136_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_ARM1136;
+}
+
+static void arm1176_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_ARM1176;
+}
+
+static void arm11mpcore_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_ARM11MPCORE;
+}
+
+static void cortex_m3_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_CORTEXM3;
+}
+
+static void cortex_a8_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_CORTEXA8;
+}
+
+static void cortex_a9_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_CORTEXA9;
+}
+
+static void cortex_a15_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_CORTEXA15;
+}
+
+static void ti925t_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_TI925T;
+}
+
+static void sa1100_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_SA1100;
+}
+
+static void sa1110_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_SA1110;
+}
+
+static void pxa250_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA250;
+}
+
+static void pxa255_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA255;
+}
+
+static void pxa260_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA260;
+}
+
+static void pxa261_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA261;
+}
+
+static void pxa262_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA262;
+}
+
+static void pxa270a0_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA270_A0;
+}
+
+static void pxa270a1_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA270_A1;
+}
+
+static void pxa270b0_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA270_B0;
+}
+
+static void pxa270b1_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA270_B1;
+}
+
+static void pxa270c0_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA270_C0;
+}
+
+static void pxa270c5_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_PXA270_C5;
+}
+
+static void arm_any_initfn(Object *obj)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ cpu->midr = ARM_CPUID_ANY;
+}
+
+typedef struct ARMCPUInfo {
+ const char *name;
+ void (*initfn)(Object *obj);
+} ARMCPUInfo;
+
+static const ARMCPUInfo arm_cpus[] = {
+ { .name = "arm926", .initfn = arm926_initfn },
+ { .name = "arm946", .initfn = arm946_initfn },
+ { .name = "arm1026", .initfn = arm1026_initfn },
+ /* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an
+ * older core than plain "arm1136". In particular this does not
+ * have the v6K features.
+ */
+ { .name = "arm1136-r2", .initfn = arm1136_r2_initfn },
+ { .name = "arm1136", .initfn = arm1136_initfn },
+ { .name = "arm1176", .initfn = arm1176_initfn },
+ { .name = "arm11mpcore", .initfn = arm11mpcore_initfn },
+ { .name = "cortex-m3", .initfn = cortex_m3_initfn },
+ { .name = "cortex-a8", .initfn = cortex_a8_initfn },
+ { .name = "cortex-a9", .initfn = cortex_a9_initfn },
+ { .name = "cortex-a15", .initfn = cortex_a15_initfn },
+ { .name = "ti925t", .initfn = ti925t_initfn },
+ { .name = "sa1100", .initfn = sa1100_initfn },
+ { .name = "sa1110", .initfn = sa1110_initfn },
+ { .name = "pxa250", .initfn = pxa250_initfn },
+ { .name = "pxa255", .initfn = pxa255_initfn },
+ { .name = "pxa260", .initfn = pxa260_initfn },
+ { .name = "pxa261", .initfn = pxa261_initfn },
+ { .name = "pxa262", .initfn = pxa262_initfn },
+ /* "pxa270" is an alias for "pxa270-a0" */
+ { .name = "pxa270", .initfn = pxa270a0_initfn },
+ { .name = "pxa270-a0", .initfn = pxa270a0_initfn },
+ { .name = "pxa270-a1", .initfn = pxa270a1_initfn },
+ { .name = "pxa270-b0", .initfn = pxa270b0_initfn },
+ { .name = "pxa270-b1", .initfn = pxa270b1_initfn },
+ { .name = "pxa270-c0", .initfn = pxa270c0_initfn },
+ { .name = "pxa270-c5", .initfn = pxa270c5_initfn },
+ { .name = "any", .initfn = arm_any_initfn },
+};
+
static void arm_cpu_class_init(ObjectClass *oc, void *data)
{
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -43,18 +248,37 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->reset = arm_cpu_reset;
}
+static void cpu_register(const ARMCPUInfo *info)
+{
+ TypeInfo type_info = {
+ .name = info->name,
+ .parent = TYPE_ARM_CPU,
+ .instance_size = sizeof(ARMCPU),
+ .instance_init = info->initfn,
+ .class_size = sizeof(ARMCPUClass),
+ };
+
+ type_register_static(&type_info);
+}
+
static const TypeInfo arm_cpu_type_info = {
.name = TYPE_ARM_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(ARMCPU),
- .abstract = false,
+ .instance_init = arm_cpu_initfn,
+ .abstract = true,
.class_size = sizeof(ARMCPUClass),
.class_init = arm_cpu_class_init,
};
static void arm_cpu_register_types(void)
{
+ int i;
+
type_register_static(&arm_cpu_type_info);
+ for (i = 0; i < ARRAY_SIZE(arm_cpus); i++) {
+ cpu_register(&arm_cpus[i]);
+ }
}
type_init(arm_cpu_register_types)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 28f127b..afcd68c 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -46,8 +46,6 @@ static uint32_t arm1176_cp15_c0_c1[8] =
static uint32_t arm1176_cp15_c0_c2[8] =
{ 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
-static uint32_t cpu_arm_find_by_name(const char *name);
-
static inline void set_feature(CPUARMState *env, int feature)
{
env->features |= 1u << feature;
@@ -55,7 +53,6 @@ static inline void set_feature(CPUARMState *env, int feature)
static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
- env->cp15.c0_cpuid = id;
switch (id) {
case ARM_CPUID_ARM926:
set_feature(env, ARM_FEATURE_V5);
@@ -201,7 +198,6 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_TI925T:
set_feature(env, ARM_FEATURE_V4T);
set_feature(env, ARM_FEATURE_OMAPCP);
- env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */
env->cp15.c0_cachetype = 0x5109149;
env->cp15.c1_sys = 0x00000070;
env->cp15.c15_i_max = 0x000;
@@ -287,18 +283,20 @@ void cpu_state_reset(CPUARMState *env)
{
uint32_t id;
uint32_t tmp = 0;
+ ARMCPU *cpu = arm_env_get_cpu(env);
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
log_cpu_state(env, 0);
}
- id = env->cp15.c0_cpuid;
+ id = cpu->midr;
tmp = env->cp15.c15_config_base_address;
memset(env, 0, offsetof(CPUARMState, breakpoints));
if (id)
cpu_reset_model_id(env, id);
env->cp15.c15_config_base_address = tmp;
+ env->cp15.c0_cpuid = cpu->midr;
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
/* For user mode we must enable access to coprocessors */
@@ -407,22 +405,20 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
{
ARMCPU *cpu;
CPUARMState *env;
- uint32_t id;
static int inited = 0;
- id = cpu_arm_find_by_name(cpu_model);
- if (id == 0)
+ if (!object_class_by_name(cpu_model)) {
return NULL;
- cpu = ARM_CPU(object_new(TYPE_ARM_CPU));
+ }
+ cpu = ARM_CPU(object_new(cpu_model));
env = &cpu->env;
- cpu_exec_init(env);
+ env->cpu_model_str = cpu_model;
+
if (tcg_enabled() && !inited) {
inited = 1;
arm_translate_init();
}
- env->cpu_model_str = cpu_model;
- env->cp15.c0_cpuid = id;
cpu_state_reset(env);
if (arm_feature(env, ARM_FEATURE_NEON)) {
gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
@@ -438,66 +434,51 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
return env;
}
-struct arm_cpu_t {
- uint32_t id;
- const char *name;
-};
-
-static const struct arm_cpu_t arm_cpu_names[] = {
- { ARM_CPUID_ARM926, "arm926"},
- { ARM_CPUID_ARM946, "arm946"},
- { ARM_CPUID_ARM1026, "arm1026"},
- { ARM_CPUID_ARM1136, "arm1136"},
- { ARM_CPUID_ARM1136_R2, "arm1136-r2"},
- { ARM_CPUID_ARM1176, "arm1176"},
- { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
- { ARM_CPUID_CORTEXM3, "cortex-m3"},
- { ARM_CPUID_CORTEXA8, "cortex-a8"},
- { ARM_CPUID_CORTEXA9, "cortex-a9"},
- { ARM_CPUID_CORTEXA15, "cortex-a15" },
- { ARM_CPUID_TI925T, "ti925t" },
- { ARM_CPUID_PXA250, "pxa250" },
- { ARM_CPUID_SA1100, "sa1100" },
- { ARM_CPUID_SA1110, "sa1110" },
- { ARM_CPUID_PXA255, "pxa255" },
- { ARM_CPUID_PXA260, "pxa260" },
- { ARM_CPUID_PXA261, "pxa261" },
- { ARM_CPUID_PXA262, "pxa262" },
- { ARM_CPUID_PXA270, "pxa270" },
- { ARM_CPUID_PXA270_A0, "pxa270-a0" },
- { ARM_CPUID_PXA270_A1, "pxa270-a1" },
- { ARM_CPUID_PXA270_B0, "pxa270-b0" },
- { ARM_CPUID_PXA270_B1, "pxa270-b1" },
- { ARM_CPUID_PXA270_C0, "pxa270-c0" },
- { ARM_CPUID_PXA270_C5, "pxa270-c5" },
- { ARM_CPUID_ANY, "any"},
- { 0, NULL}
-};
+typedef struct ARMCPUListState {
+ fprintf_function cpu_fprintf;
+ FILE *file;
+} ARMCPUListState;
-void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+/* Sort alphabetically by type name, except for "any". */
+static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b)
{
- int i;
+ ObjectClass *class_a = (ObjectClass *)a;
+ ObjectClass *class_b = (ObjectClass *)b;
+ const char *name_a, *name_b;
- (*cpu_fprintf)(f, "Available CPUs:\n");
- for (i = 0; arm_cpu_names[i].name; i++) {
- (*cpu_fprintf)(f, " %s\n", arm_cpu_names[i].name);
+ name_a = object_class_get_name(class_a);
+ name_b = object_class_get_name(class_b);
+ if (strcmp(name_a, "any") == 0) {
+ return 1;
+ } else if (strcmp(name_b, "any") == 0) {
+ return -1;
+ } else {
+ return strcmp(name_a, name_b);
}
}
-/* return 0 if not found */
-static uint32_t cpu_arm_find_by_name(const char *name)
+static void arm_cpu_list_entry(gpointer data, gpointer user_data)
{
- int i;
- uint32_t id;
+ ObjectClass *oc = data;
+ ARMCPUListState *s = user_data;
- id = 0;
- for (i = 0; arm_cpu_names[i].name; i++) {
- if (strcmp(name, arm_cpu_names[i].name) == 0) {
- id = arm_cpu_names[i].id;
- break;
- }
- }
- return id;
+ (*s->cpu_fprintf)(s->file, " %s\n",
+ object_class_get_name(oc));
+}
+
+void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+ ARMCPUListState s = {
+ .file = f,
+ .cpu_fprintf = cpu_fprintf,
+ };
+ GSList *list;
+
+ list = object_class_get_list(TYPE_ARM_CPU, false);
+ list = g_slist_sort(list, arm_cpu_list_compare);
+ (*cpu_fprintf)(f, "Available CPUs:\n");
+ g_slist_foreach(list, arm_cpu_list_entry, &s);
+ g_slist_free(list);
}
static int bad_mode_switch(CPUARMState *env, int mode)
commit ce854d7cc3ba71e8d2a97e1fb33e13ac3283cbd4
Author: Benoit Canet <benoit.canet at gmail.com>
Date: Wed Nov 9 07:32:59 2011 +0000
target-arm: remind to keep arm features in sync with linux-user/elfload.c
Signed-off-by: Benoit Canet <benoit.canet at gmail.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c208c80..d2f5c76 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -360,6 +360,10 @@ enum arm_cpu_mode {
#define ARM_IWMMXT_wCGR2 10
#define ARM_IWMMXT_wCGR3 11
+/* If adding a feature bit which corresponds to a Linux ELF
+ * HWCAP bit, remember to update the feature-bit-to-hwcap
+ * mapping in linux-user/elfload.c:get_elf_hwcap().
+ */
enum arm_features {
ARM_FEATURE_VFP,
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
commit 75f05e4fd770d64e5ace1bf8e9bda536903da709
Merge: c3ca046... 964c695...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sat Apr 21 13:33:55 2012 +0000
Merge branch 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
* 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm:
versatiblepb: add NOR flash support
hw/arm_mptimer: Reset the qemu_timer at reset
versatilepb: add ds1338 rtc device
realview: break out versatile i2c controller code
commit c3ca04679e93a72635d6ef347886dbeba799b2d6
Author: Stefan Weil <sw at weilnetz.de>
Date: Tue Apr 17 19:22:39 2012 +0200
tci: GETPC() macro must return an uintptr_t
Change the data type of tci_tb_ptr, so GETPC() returns an
uintptr_t now (like for all other TCG targets).
This completes commit 2050396801ca0c8359364d61eaadece951006057
and fixes builds with TCI.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Reviewed-by: Eric Blake <eblake at redhat.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/exec-all.h b/exec-all.h
index 6bcc075..937d3ce 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -283,7 +283,7 @@ extern int tb_invalidated_flag;
/* Alpha and SH4 user mode emulations and Softmmu call GETPC().
For all others, GETPC remains undefined (which makes TCI a little faster. */
# if defined(CONFIG_SOFTMMU) || defined(TARGET_ALPHA) || defined(TARGET_SH4)
-extern void *tci_tb_ptr;
+extern uintptr_t tci_tb_ptr;
# define GETPC() tci_tb_ptr
# endif
#elif defined(__s390__) && !defined(__s390x__)
diff --git a/tci.c b/tci.c
index c43fe7d..71de66d 100644
--- a/tci.c
+++ b/tci.c
@@ -58,7 +58,7 @@ CPUArchState *env;
/* Targets which don't use GETPC also don't need tci_tb_ptr
which makes them a little faster. */
#if defined(GETPC)
-void *tci_tb_ptr;
+uintptr_t tci_tb_ptr;
#endif
static tcg_target_ulong tci_reg[TCG_TARGET_NB_REGS];
@@ -450,7 +450,7 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr)
for (;;) {
#if defined(GETPC)
- tci_tb_ptr = tb_ptr;
+ tci_tb_ptr = (uintptr_t)tb_ptr;
#endif
TCGOpcode opc = tb_ptr[0];
#if !defined(NDEBUG)
commit a896d03bb5f70ed76b3e9e1acba864115cfb5e01
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Mon Mar 12 06:24:45 2012 +0000
gdbstub: Synchronize CPU state unconditionally in gdb_set_cpu_pc
Synchronize the CPU state via cpu_sychronize_state() unconditionally
in gdb_set_cpu_pc() rather than only in some of the target ifdef
ladder cases.
We can divide the CPUs into three categories:
* non-KVM targets: no change of behaviour since we will use the
kvm-stub.c no-op function.
* i386 and s390: no change of behaviour since they were already
calling this function
* PPC (in KVM mode): this fixes an error: failing to synchronise
was accidental and probably a bug.
This also paves the way for other targets (specifically ARM) which
can add KVM support in future without having to add another target
specific change to this bit of code.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/gdbstub.c b/gdbstub.c
index 6a7e2c4..6a77a66 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1903,8 +1903,8 @@ static void gdb_breakpoint_remove_all(void)
static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
{
-#if defined(TARGET_I386)
cpu_synchronize_state(s->c_cpu);
+#if defined(TARGET_I386)
s->c_cpu->eip = pc;
#elif defined (TARGET_PPC)
s->c_cpu->nip = pc;
@@ -1929,7 +1929,6 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
#elif defined (TARGET_ALPHA)
s->c_cpu->pc = pc;
#elif defined (TARGET_S390X)
- cpu_synchronize_state(s->c_cpu);
s->c_cpu->psw.addr = pc;
#elif defined (TARGET_LM32)
s->c_cpu->pc = pc;
commit 0eb4fc817fa14347a381d018eb29f1eef2fb43e4
Author: Juan Quintela <quintela at redhat.com>
Date: Tue Mar 20 05:24:25 2012 +0000
softfloat: make USE_SOFTFLOAT_STRUCT_TYPES compile
This change makes it compile and return the same value than the #undef one.
Signed-off-by: Juan Quintela <quintela at redhat.com>
Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
Acked-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index d37090a..9e1b5f9 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -2219,7 +2219,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM)
}
}
/* Zero plus something non-zero : just return the something */
- return c ^ (signflip << 31);
+ return make_float32(float32_val(c) ^ (signflip << 31));
}
if (aExp == 0) {
@@ -3772,7 +3772,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM)
}
}
/* Zero plus something non-zero : just return the something */
- return c ^ ((uint64_t)signflip << 63);
+ return make_float64(float64_val(c) ^ ((uint64_t)signflip << 63));
}
if (aExp == 0) {
commit 536a98d4d66444437e01ff2920df1a554df15efb
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Mon Apr 16 01:47:07 2012 +0400
target-xtensa: add tests for LOOPNEZ and LOOPGTZ
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/tcg/xtensa/test_loop.S b/tests/tcg/xtensa/test_loop.S
index 5cead47..1c240e8 100644
--- a/tests/tcg/xtensa/test_loop.S
+++ b/tests/tcg/xtensa/test_loop.S
@@ -124,4 +124,40 @@ test lend_invalidation
assert eqi, a2, 7
test_end
+test loopnez
+ movi a2, 0
+ movi a3, 5
+ loopnez a3, 1f
+ addi a2, a2, 1
+1:
+ assert eqi, a2, 5
+
+ movi a2, 0
+ movi a3, 0
+ loopnez a3, 1f
+ test_fail
+1:
+test_end
+
+test loopgtz
+ movi a2, 0
+ movi a3, 5
+ loopgtz a3, 1f
+ addi a2, a2, 1
+1:
+ assert eqi, a2, 5
+
+ movi a2, 0
+ movi a3, 0
+ loopgtz a3, 1f
+ test_fail
+1:
+
+ movi a2, 0
+ movi a3, 0x80000000
+ loopgtz a3, 1f
+ test_fail
+1:
+test_end
+
test_suite_end
commit b18b37f7c5bc96dabdb08bcfb699b339a76104bf
Author: Max Filippov <jcmvbkbc at gmail.com>
Date: Mon Apr 16 01:47:06 2012 +0400
target-xtensa: fix LOOPNEZ/LOOPGTZ translation
Translation of LOOP instructions used to call LEND SR write handler to
update LEND and invalidate relevant TBs. Now that LEND SR write handler
ends TB, LOOPNEZ and LOOPGTZ generate wrong code (same as for simple
LOOP). Fix it by calling wsr_lend helper directly.
Signed-off-by: Max Filippov <jcmvbkbc at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 6900123..521c0e6 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -2278,7 +2278,7 @@ static void disas_xtensa_insn(DisasContext *dc)
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1);
tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc);
- gen_wsr_lend(dc, LEND, tmp);
+ gen_helper_wsr_lend(tmp);
tcg_temp_free(tmp);
if (BRI8_R > 8) {
commit f91837a7f173e0334539024e4d8ba10c19a78bb7
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sun Apr 15 11:45:18 2012 +0000
qtest: add m48t59 tests for Sparc
Add simple m48t59 qtests, enable test only for Sparc32
and Sparc64. On PPC, the device is behind PCI bus.
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/Makefile b/tests/Makefile
index baf1d70..9988681 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -20,6 +20,8 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
# really in libqtest, not in the testcases themselves.
check-qtest-i386-y = tests/rtc-test
check-qtest-x86_64-y = $(check-qtest-i386-y)
+check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
+check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
@@ -64,6 +66,7 @@ tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-
tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
+tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y)
# QTest rules
diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c
new file mode 100644
index 0000000..5179681
--- /dev/null
+++ b/tests/m48t59-test.c
@@ -0,0 +1,259 @@
+/*
+ * QTest testcase for the M48T59 and M48T08 real-time clocks
+ *
+ * Based on MC146818 RTC test:
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include "libqtest.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define RTC_SECONDS 0x9
+#define RTC_MINUTES 0xa
+#define RTC_HOURS 0xb
+
+#define RTC_DAY_OF_WEEK 0xc
+#define RTC_DAY_OF_MONTH 0xd
+#define RTC_MONTH 0xe
+#define RTC_YEAR 0xf
+
+static uint32_t base;
+static uint16_t reg_base = 0x1ff0; /* 0x7f0 for m48t02 */
+static int base_year;
+static bool use_mmio;
+
+static uint8_t cmos_read_mmio(uint8_t reg)
+{
+ uint8_t data;
+
+ memread(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1);
+ return data;
+}
+
+static void cmos_write_mmio(uint8_t reg, uint8_t val)
+{
+ uint8_t data = val;
+
+ memwrite(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1);
+}
+
+static uint8_t cmos_read_ioio(uint8_t reg)
+{
+ outw(base + 0, reg_base + (uint16_t)reg);
+ return inb(base + 3);
+}
+
+static void cmos_write_ioio(uint8_t reg, uint8_t val)
+{
+ outw(base + 0, reg_base + (uint16_t)reg);
+ outb(base + 3, val);
+}
+
+static uint8_t cmos_read(uint8_t reg)
+{
+ if (use_mmio) {
+ return cmos_read_mmio(reg);
+ } else {
+ return cmos_read_ioio(reg);
+ }
+}
+
+static void cmos_write(uint8_t reg, uint8_t val)
+{
+ if (use_mmio) {
+ cmos_write_mmio(reg, val);
+ } else {
+ cmos_write_ioio(reg, val);
+ }
+}
+
+static int bcd2dec(int value)
+{
+ return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
+}
+
+static int tm_cmp(struct tm *lhs, struct tm *rhs)
+{
+ time_t a, b;
+ struct tm d1, d2;
+
+ memcpy(&d1, lhs, sizeof(d1));
+ memcpy(&d2, rhs, sizeof(d2));
+
+ a = mktime(&d1);
+ b = mktime(&d2);
+
+ if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ }
+
+ return 0;
+}
+
+#if 0
+static void print_tm(struct tm *tm)
+{
+ printf("%04d-%02d-%02d %02d:%02d:%02d %+02ld\n",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
+}
+#endif
+
+static void cmos_get_date_time(struct tm *date)
+{
+ int sec, min, hour, mday, mon, year;
+ time_t ts;
+ struct tm dummy;
+
+ sec = cmos_read(RTC_SECONDS);
+ min = cmos_read(RTC_MINUTES);
+ hour = cmos_read(RTC_HOURS);
+ mday = cmos_read(RTC_DAY_OF_MONTH);
+ mon = cmos_read(RTC_MONTH);
+ year = cmos_read(RTC_YEAR);
+
+ sec = bcd2dec(sec);
+ min = bcd2dec(min);
+ hour = bcd2dec(hour);
+ mday = bcd2dec(mday);
+ mon = bcd2dec(mon);
+ year = bcd2dec(year);
+
+ ts = time(NULL);
+ localtime_r(&ts, &dummy);
+
+ date->tm_isdst = dummy.tm_isdst;
+ date->tm_sec = sec;
+ date->tm_min = min;
+ date->tm_hour = hour;
+ date->tm_mday = mday;
+ date->tm_mon = mon - 1;
+ date->tm_year = base_year + year - 1900;
+ date->tm_gmtoff = 0;
+
+ ts = mktime(date);
+}
+
+static void check_time(int wiggle)
+{
+ struct tm start, date[4], end;
+ struct tm *datep;
+ time_t ts;
+
+ /*
+ * This check assumes a few things. First, we cannot guarantee that we get
+ * a consistent reading from the wall clock because we may hit an edge of
+ * the clock while reading. To work around this, we read four clock readings
+ * such that at least two of them should match. We need to assume that one
+ * reading is corrupt so we need four readings to ensure that we have at
+ * least two consecutive identical readings
+ *
+ * It's also possible that we'll cross an edge reading the host clock so
+ * simply check to make sure that the clock reading is within the period of
+ * when we expect it to be.
+ */
+
+ ts = time(NULL);
+ gmtime_r(&ts, &start);
+
+ cmos_get_date_time(&date[0]);
+ cmos_get_date_time(&date[1]);
+ cmos_get_date_time(&date[2]);
+ cmos_get_date_time(&date[3]);
+
+ ts = time(NULL);
+ gmtime_r(&ts, &end);
+
+ if (tm_cmp(&date[0], &date[1]) == 0) {
+ datep = &date[0];
+ } else if (tm_cmp(&date[1], &date[2]) == 0) {
+ datep = &date[1];
+ } else if (tm_cmp(&date[2], &date[3]) == 0) {
+ datep = &date[2];
+ } else {
+ g_assert_not_reached();
+ }
+
+ if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
+ long t, s;
+
+ start.tm_isdst = datep->tm_isdst;
+
+ t = (long)mktime(datep);
+ s = (long)mktime(&start);
+ if (t < s) {
+ g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
+ } else {
+ g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
+ }
+
+ g_assert_cmpint(ABS(t - s), <=, wiggle);
+ }
+}
+
+static int wiggle = 2;
+
+static void bcd_check_time(void)
+{
+ if (strcmp(qtest_get_arch(), "sparc64") == 0) {
+ base = 0x74;
+ base_year = 1900;
+ use_mmio = false;
+ } else if (strcmp(qtest_get_arch(), "sparc") == 0) {
+ base = 0x71200000;
+ base_year = 1968;
+ use_mmio = true;
+ } else { /* PPC: need to map macio in PCI */
+ g_assert_not_reached();
+ }
+ check_time(wiggle);
+}
+
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < 1000; i++) {
+ uint8_t reg, val;
+
+ reg = (uint8_t)g_test_rand_int_range(0, 16);
+ val = (uint8_t)g_test_rand_int_range(0, 256);
+
+ cmos_write(reg, val);
+ cmos_read(reg);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s = NULL;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ s = qtest_start("-display none -rtc clock=vm");
+
+ qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
+ qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+
+ return ret;
+}
commit 964c695a54ceda3ac8c965542829d4e482e28de7
Author: Eric Benard <eric at eukrea.com>
Date: Mon Apr 16 05:02:47 2012 +0000
versatiblepb: add NOR flash support
- add support for the 64MB NOR CFI01 flash available at
0x34000000 on the versatilepb board
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0225d/BBAJIHEC.html
- tested with barebox bootloader
Signed-off-by: Eric Bénard <eric at eukrea.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index d011554..7c79c54 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -17,6 +17,11 @@
#include "boards.h"
#include "blockdev.h"
#include "exec-memory.h"
+#include "flash.h"
+
+#define VERSATILE_FLASH_ADDR 0x34000000
+#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
+#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
/* Primary interrupt controller. */
@@ -182,6 +187,7 @@ static void versatile_init(ram_addr_t ram_size,
i2c_bus *i2c;
int n;
int done_smc = 0;
+ DriveInfo *dinfo;
if (!cpu_model)
cpu_model = "arm926";
@@ -316,6 +322,16 @@ static void versatile_init(ram_addr_t ram_size,
/* 0x101f2000 UART1. */
/* 0x101f3000 UART2. */
/* 0x101f4000 SSPI. */
+ /* 0x34000000 NOR Flash */
+
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
+ VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
+ VERSATILE_FLASH_SECT_SIZE,
+ VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
+ 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
+ fprintf(stderr, "qemu: Error registering flash memory.\n");
+ }
versatile_binfo.ram_size = ram_size;
versatile_binfo.kernel_filename = kernel_filename;
commit bdac1c1e958c3b0bb1d02e8fb8cc141306eea103
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Fri Apr 20 15:38:52 2012 +0000
hw/arm_mptimer: Reset the qemu_timer at reset
On reset of the mpcore timer/watchdog block we need to
delete the qemu_timer in case it was running.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index df7fb4c..fe43cbb 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -228,6 +228,9 @@ static void timerblock_reset(timerblock *tb)
tb->control = 0;
tb->status = 0;
tb->tick = 0;
+ if (tb->timer) {
+ qemu_del_timer(tb->timer);
+ }
}
static void arm_mptimer_reset(DeviceState *dev)
commit b1f05696ccc7ee2a04a541e373d098ad17568d13
Author: Oskar Andero <oskar.andero at gmail.com>
Date: Fri Apr 20 15:38:52 2012 +0000
versatilepb: add ds1338 rtc device
Add ds1338 rtc attached on i2c.
Signed-off-by: Oskar Andero <oskar.andero at gmail.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 25afb1e..d011554 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -13,6 +13,7 @@
#include "net.h"
#include "sysemu.h"
#include "pci.h"
+#include "i2c.h"
#include "boards.h"
#include "blockdev.h"
#include "exec-memory.h"
@@ -178,6 +179,7 @@ static void versatile_init(ram_addr_t ram_size,
DeviceState *pl041;
PCIBus *pci_bus;
NICInfo *nd;
+ i2c_bus *i2c;
int n;
int done_smc = 0;
@@ -268,6 +270,10 @@ static void versatile_init(ram_addr_t ram_size,
/* Add PL031 Real Time Clock. */
sysbus_create_simple("pl031", 0x101e8000, pic[10]);
+ dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
+ i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+ i2c_create_slave(i2c, "ds1338", 0x68);
+
/* Add PL041 AACI Interface to the LM4549 codec */
pl041 = qdev_create(NULL, "pl041");
qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
commit d1157ca418b9426be5e1857eca8142966397a32b
Author: Oskar Andero <oskar.andero at gmail.com>
Date: Fri Apr 20 15:38:52 2012 +0000
realview: break out versatile i2c controller code
The versatile i2c controller implementation was separated to
its own file called versatile_i2c.c. This is done as a preparation
for adding i2c support to the versatilepb board.
Signed-off-by: Oskar Andero <oskar.andero at gmail.com>
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
diff --git a/Makefile.target b/Makefile.target
index 84951a0..b6a9330 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -364,6 +364,7 @@ endif
obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
obj-arm-y += versatile_pci.o
+obj-arm-y += versatile_i2c.o
obj-arm-y += cadence_uart.o
obj-arm-y += cadence_ttc.o
obj-arm-y += cadence_gem.o
diff --git a/hw/realview.c b/hw/realview.c
index cf55204..ecf4701 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -15,91 +15,13 @@
#include "net.h"
#include "sysemu.h"
#include "boards.h"
-#include "bitbang_i2c.h"
+#include "i2c.h"
#include "blockdev.h"
#include "exec-memory.h"
#define SMP_BOOT_ADDR 0xe0000000
#define SMP_BOOTREG_ADDR 0x10000030
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- bitbang_i2c_interface *bitbang;
- int out;
- int in;
-} RealViewI2CState;
-
-static uint64_t realview_i2c_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- RealViewI2CState *s = (RealViewI2CState *)opaque;
-
- if (offset == 0) {
- return (s->out & 1) | (s->in << 1);
- } else {
- hw_error("realview_i2c_read: Bad offset 0x%x\n", (int)offset);
- return -1;
- }
-}
-
-static void realview_i2c_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- RealViewI2CState *s = (RealViewI2CState *)opaque;
-
- switch (offset) {
- case 0:
- s->out |= value & 3;
- break;
- case 4:
- s->out &= ~value;
- break;
- default:
- hw_error("realview_i2c_write: Bad offset 0x%x\n", (int)offset);
- }
- bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
- s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
-}
-
-static const MemoryRegionOps realview_i2c_ops = {
- .read = realview_i2c_read,
- .write = realview_i2c_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int realview_i2c_init(SysBusDevice *dev)
-{
- RealViewI2CState *s = FROM_SYSBUS(RealViewI2CState, dev);
- i2c_bus *bus;
-
- bus = i2c_init_bus(&dev->qdev, "i2c");
- s->bitbang = bitbang_i2c_init(bus);
- memory_region_init_io(&s->iomem, &realview_i2c_ops, s,
- "realview-i2c", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
-}
-
-static void realview_i2c_class_init(ObjectClass *klass, void *data)
-{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = realview_i2c_init;
-}
-
-static TypeInfo realview_i2c_info = {
- .name = "realview_i2c",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(RealViewI2CState),
- .class_init = realview_i2c_class_init,
-};
-
-static void realview_register_types(void)
-{
- type_register_static(&realview_i2c_info);
-}
-
/* Board init. */
static struct arm_boot_info realview_binfo = {
@@ -328,7 +250,7 @@ static void realview_init(ram_addr_t ram_size,
}
}
- dev = sysbus_create_simple("realview_i2c", 0x10002000, NULL);
+ dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
i2c_create_slave(i2c, "ds1338", 0x68);
@@ -492,4 +414,3 @@ static void realview_machine_init(void)
}
machine_init(realview_machine_init);
-type_init(realview_register_types)
diff --git a/hw/versatile_i2c.c b/hw/versatile_i2c.c
new file mode 100644
index 0000000..88f530a
--- /dev/null
+++ b/hw/versatile_i2c.c
@@ -0,0 +1,105 @@
+/*
+ * ARM Versatile I2C controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Copyright (c) 2012 Oskar Andero <oskar.andero at gmail.com>
+ *
+ * This file is derived from hw/realview.c by Paul Brook
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "sysbus.h"
+#include "bitbang_i2c.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ bitbang_i2c_interface *bitbang;
+ int out;
+ int in;
+} VersatileI2CState;
+
+static uint64_t versatile_i2c_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ VersatileI2CState *s = (VersatileI2CState *)opaque;
+
+ if (offset == 0) {
+ return (s->out & 1) | (s->in << 1);
+ } else {
+ hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
+ return -1;
+ }
+}
+
+static void versatile_i2c_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ VersatileI2CState *s = (VersatileI2CState *)opaque;
+
+ switch (offset) {
+ case 0:
+ s->out |= value & 3;
+ break;
+ case 4:
+ s->out &= ~value;
+ break;
+ default:
+ hw_error("%s: Bad offset 0x%x\n", __func__, (int)offset);
+ }
+ bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
+ s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
+}
+
+static const MemoryRegionOps versatile_i2c_ops = {
+ .read = versatile_i2c_read,
+ .write = versatile_i2c_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int versatile_i2c_init(SysBusDevice *dev)
+{
+ VersatileI2CState *s = FROM_SYSBUS(VersatileI2CState, dev);
+ i2c_bus *bus;
+
+ bus = i2c_init_bus(&dev->qdev, "i2c");
+ s->bitbang = bitbang_i2c_init(bus);
+ memory_region_init_io(&s->iomem, &versatile_i2c_ops, s,
+ "versatile_i2c", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
+ return 0;
+}
+
+static void versatile_i2c_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = versatile_i2c_init;
+}
+
+static const TypeInfo versatile_i2c_info = {
+ .name = "versatile_i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(VersatileI2CState),
+ .class_init = versatile_i2c_class_init,
+};
+
+static void versatile_i2c_register_types(void)
+{
+ type_register_static(&versatile_i2c_info);
+}
+
+type_init(versatile_i2c_register_types)
commit 1042ec94b19e0bfaae74c912ebbdfdbff8dd7db2
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Apr 12 17:21:44 2012 +0200
qemu-iotests: Fix test 031 for qcow2 v3 support
qcow2.py must be updated to work with version 3 images at all, the
output has changed since the feature table extension has been added, and
version 2 and version 3 images can't possibly have the same test output.
Change the test case to completely ignore IMGOPTS and run the test for
both compat=1.1 and compat=0.10 regardless of the ./check command line.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
index 6365f28..2d5e3b1 100755
--- a/tests/qemu-iotests/031
+++ b/tests/qemu-iotests/031
@@ -45,26 +45,34 @@ _supported_proto generic
_supported_os Linux
CLUSTER_SIZE=65536
-echo
-echo === Create image with unknown header extension ===
-echo
-_make_test_img 64M
-./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
-./qcow2.py $TEST_IMG dump-header
-_check_test_img
-echo
-echo === Rewrite header with no backing file ===
-echo
-$QEMU_IMG rebase -u -b "" $TEST_IMG
-./qcow2.py $TEST_IMG dump-header
-_check_test_img
+# qcow2.py output depends on the exact options used, so override the command
+# line here as an exception
+for IMGOPTS in "compat=0.10" "compat=1.1"; do
-echo
-echo === Add a backing file and format ===
-echo
-$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
-./qcow2.py $TEST_IMG dump-header
+ echo
+ echo ===== Testing with -o $IMGOPTS =====
+ echo
+ echo === Create image with unknown header extension ===
+ echo
+ _make_test_img 64M
+ ./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
+ ./qcow2.py $TEST_IMG dump-header
+ _check_test_img
+
+ echo
+ echo === Rewrite header with no backing file ===
+ echo
+ $QEMU_IMG rebase -u -b "" $TEST_IMG
+ ./qcow2.py $TEST_IMG dump-header
+ _check_test_img
+
+ echo
+ echo === Add a backing file and format ===
+ echo
+ $QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
+ ./qcow2.py $TEST_IMG dump-header
+done
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
index e1a536e..d3cab30 100644
--- a/tests/qemu-iotests/031.out
+++ b/tests/qemu-iotests/031.out
@@ -1,5 +1,7 @@
QA output created by 031
+===== Testing with -o compat=0.10 =====
+
=== Create image with unknown header extension ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
@@ -16,6 +18,11 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 72
Header extension:
magic 0x12345678
@@ -39,6 +46,16 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 72
+
+Header extension:
+magic 0x6803f857
+length 0
+data ''
Header extension:
magic 0x12345678
@@ -51,7 +68,108 @@ No errors were found on the image.
magic 0x514649fb
version 2
-backing_file_offset 0x90
+backing_file_offset 0x98
+backing_file_size 0x17
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 72
+
+Header extension:
+magic 0xe2792aca
+length 11
+data 'host_device'
+
+Header extension:
+magic 0x6803f857
+length 0
+data ''
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+
+===== Testing with -o compat=1.1 =====
+
+=== Create image with unknown header extension ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+magic 0x514649fb
+version 3
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 104
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+No errors were found on the image.
+
+=== Rewrite header with no backing file ===
+
+magic 0x514649fb
+version 3
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 104
+
+Header extension:
+magic 0x6803f857
+length 0
+data ''
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+No errors were found on the image.
+
+=== Add a backing file and format ===
+
+magic 0x514649fb
+version 3
+backing_file_offset 0xb8
backing_file_size 0x17
cluster_bits 16
size 67108864
@@ -62,6 +180,11 @@ refcount_table_offset 0x10000
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 104
Header extension:
magic 0xe2792aca
@@ -69,6 +192,11 @@ length 11
data 'host_device'
Header extension:
+magic 0x6803f857
+length 0
+data ''
+
+Header extension:
magic 0x12345678
length 31
data 'This is a test header extension'
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
index bfb47e8..e27196a 100755
--- a/tests/qemu-iotests/qcow2.py
+++ b/tests/qemu-iotests/qcow2.py
@@ -35,6 +35,13 @@ class QcowHeader:
[ uint32_t, '%d', 'refcount_table_clusters' ],
[ uint32_t, '%d', 'nb_snapshots' ],
[ uint64_t, '%#x', 'snapshot_offset' ],
+
+ # Version 3 header fields
+ [ uint64_t, '%#x', 'incompatible_features' ],
+ [ uint64_t, '%#x', 'compatible_features' ],
+ [ uint64_t, '%#x', 'autoclear_features' ],
+ [ uint32_t, '%d', 'refcount_order' ],
+ [ uint32_t, '%d', 'header_length' ],
];
fmt = '>' + ''.join(field[0] for field in fields)
@@ -50,9 +57,10 @@ class QcowHeader:
self.__dict__ = dict((field[2], header[i])
for i, field in enumerate(QcowHeader.fields))
+ self.set_defaults()
self.cluster_size = 1 << self.cluster_bits
- fd.seek(self.get_header_length())
+ fd.seek(self.header_length)
self.load_extensions(fd)
if self.backing_file_offset:
@@ -61,11 +69,13 @@ class QcowHeader:
else:
self.backing_file = None
- def get_header_length(self):
+ def set_defaults(self):
if self.version == 2:
- return 72
- else:
- raise Exception("version != 2 not supported")
+ self.incompatible_features = 0
+ self.compatible_features = 0
+ self.autoclear_features = 0
+ self.refcount_order = 4
+ self.header_length = 72
def load_extensions(self, fd):
self.extensions = []
@@ -86,7 +96,7 @@ class QcowHeader:
def update_extensions(self, fd):
- fd.seek(self.get_header_length())
+ fd.seek(self.header_length)
extensions = self.extensions
extensions.append(QcowHeaderExtension(0, 0, ""))
for ex in extensions:
@@ -103,7 +113,7 @@ class QcowHeader:
def update(self, fd):
- header_bytes = self.get_header_length()
+ header_bytes = self.header_length
self.update_extensions(fd)
commit 8900436891cd8955b0795945aa020c04eaa0e5d2
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Mar 27 13:45:14 2012 +0200
qemu-iotests: Add -o and make v3 the default for qcow2
This adds an -o option to qemu-iotests, which is an option string that
is passed through to qemu-img create -o... This allows testing different
subformat with a command like './check -qcow2 -o compat=0.10'.
For qcow2, if no compat option is specified, compat=1.1 is the new
default.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index aae1378..432732c 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -41,9 +41,6 @@ then
exit 1
fi
-# we need common
-. ./common
-
# we need common.rc
if ! . ./common.rc
then
@@ -51,6 +48,9 @@ then
exit 1
fi
+# we need common
+. ./common
+
#if [ `id -u` -ne 0 ]
#then
# echo "check: QA must be run as root"
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index c187f6c..eeb70cb 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -35,6 +35,7 @@ diff="diff -u"
verbose=false
group=false
xgroup=false
+imgopts=false
showme=false
sortme=false
expunge=true
@@ -44,6 +45,7 @@ rm -f $tmp.list $tmp.tmp $tmp.sed
export IMGFMT=raw
export IMGPROTO=file
+export IMGOPTS=""
export QEMU_IO_OPTIONS=""
for r
@@ -103,6 +105,13 @@ s/ .*//p
mv $tmp.tmp $tmp.list
xgroup=false
continue
+
+ elif $imgopts
+ then
+ IMGOPTS="$r"
+ imgopts=false
+ continue
+
fi
xpand=true
@@ -130,6 +139,7 @@ check options
-nocache use O_DIRECT on backing file
-misalign misalign memory allocations
-n show me, do not run tests
+ -o options -o options to pass to qemu-img create/convert
-T output timestamps
-r randomize test order
@@ -223,6 +233,10 @@ testlist options
showme=true
xpand=false
;;
+ -o)
+ imgopts=true
+ xpand=false
+ ;;
-r) # randomize test order
randomize=true
xpand=false
@@ -299,6 +313,9 @@ BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
done
+# Set default options for qemu-img create -o if they were not specified
+_set_default_imgopts
+
if [ -s $tmp.list ]
then
# found some valid test numbers ... this is good
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 00ee754..4bc7420 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -53,19 +53,44 @@ else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi
+_optstr_add()
+{
+ if [ -n "$1" ]; then
+ echo "$1,$2"
+ else
+ echo "$2"
+ fi
+}
+
+_set_default_imgopts()
+{
+ if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
+ fi
+}
+
_make_test_img()
{
# extra qemu-img options can be added by tests
# at least one argument (the image size) needs to be added
local extra_img_options=""
local image_size=$*
+ local optstr=""
+
+ if [ -n "$IMGOPTS" ]; then
+ optstr=$(_optstr_add "$optstr" "$IMGOPTS")
+ fi
if [ "$1" = "-b" ]; then
extra_img_options="$1 $2"
image_size=$3
fi
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
- extra_img_options="-o cluster_size=$CLUSTER_SIZE $extra_img_options"
+ optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
+ fi
+
+ if [ -n "$optstr" ]; then
+ extra_img_options="-o $optstr $extra_img_options"
fi
# XXX(hch): have global image options?
@@ -76,6 +101,7 @@ _make_test_img()
sed -e "s# encryption=off##g" | \
sed -e "s# cluster_size=[0-9]\\+##g" | \
sed -e "s# table_size=0##g" | \
+ sed -e "s# compat='[^']*'##g" | \
sed -e "s# compat6=off##g" | \
sed -e "s# static=off##g"
}
@@ -268,7 +294,11 @@ _require_command()
_full_imgfmt_details()
{
- echo "$IMGFMT"
+ if [ -n "$IMGOPTS" ]; then
+ echo "$IMGFMT ($IMGOPTS)"
+ else
+ echo "$IMGFMT"
+ fi
}
_full_imgproto_details()
commit 621f058940ea9f1ef3d8774ef3203544f1228df1
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Mar 20 15:12:58 2012 +0100
qcow2: Zero write support
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index 421cd1b..fe74ddd 100644
--- a/block.c
+++ b/block.c
@@ -80,6 +80,8 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
void *opaque,
bool is_write);
static void coroutine_fn bdrv_co_do_rw(void *opaque);
+static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors);
static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
bool is_write, double elapsed_time, uint64_t *wait);
@@ -1708,8 +1710,8 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
if (drv->bdrv_co_write_zeroes &&
buffer_is_zero(bounce_buffer, iov.iov_len)) {
- ret = drv->bdrv_co_write_zeroes(bs, cluster_sector_num,
- cluster_nb_sectors);
+ ret = bdrv_co_do_write_zeroes(bs, cluster_sector_num,
+ cluster_nb_sectors);
} else {
ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
&bounce_qiov);
@@ -1819,9 +1821,15 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
struct iovec iov;
int ret;
+ /* TODO Emulate only part of misaligned requests instead of letting block
+ * drivers return -ENOTSUP and emulate everything */
+
/* First try the efficient write zeroes operation */
if (drv->bdrv_co_write_zeroes) {
- return drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+ ret = drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+ if (ret != -ENOTSUP) {
+ return ret;
+ }
}
/* Fall back to bounce buffer if write zeroes is unsupported */
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 5e5f5cf..a747a88 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1102,3 +1102,75 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
return 0;
}
+
+/*
+ * This zeroes as many clusters of nb_clusters as possible at once (i.e.
+ * all clusters in the same L2 table) and returns the number of zeroed
+ * clusters.
+ */
+static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
+ unsigned int nb_clusters)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t *l2_table;
+ int l2_index;
+ int ret;
+ int i;
+
+ ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Limit nb_clusters to one L2 table */
+ nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+
+ for (i = 0; i < nb_clusters; i++) {
+ uint64_t old_offset;
+
+ old_offset = be64_to_cpu(l2_table[l2_index + i]);
+
+ /* Update L2 entries */
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ if (old_offset & QCOW_OFLAG_COMPRESSED) {
+ l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
+ qcow2_free_any_clusters(bs, old_offset, 1);
+ } else {
+ l2_table[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
+ }
+ }
+
+ ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return nb_clusters;
+}
+
+int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
+{
+ BDRVQcowState *s = bs->opaque;
+ unsigned int nb_clusters;
+ int ret;
+
+ /* The zero flag is only supported by version 3 and newer */
+ if (s->qcow_version < 3) {
+ return -ENOTSUP;
+ }
+
+ /* Each L2 table is handled by its own loop iteration */
+ nb_clusters = size_to_clusters(s, nb_sectors << BDRV_SECTOR_BITS);
+
+ while (nb_clusters > 0) {
+ ret = zero_single_l2(bs, offset, nb_clusters);
+ if (ret < 0) {
+ return ret;
+ }
+
+ nb_clusters -= ret;
+ offset += (ret * s->cluster_size);
+ }
+
+ return 0;
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index 41b195d..ad46c03 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1281,6 +1281,26 @@ static int qcow2_make_empty(BlockDriverState *bs)
return 0;
}
+static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors)
+{
+ int ret;
+ BDRVQcowState *s = bs->opaque;
+
+ /* Emulate misaligned zero writes */
+ if (sector_num % s->cluster_sectors || nb_sectors % s->cluster_sectors) {
+ return -ENOTSUP;
+ }
+
+ /* Whatever is left can use real zero clusters */
+ qemu_co_mutex_lock(&s->lock);
+ ret = qcow2_zero_clusters(bs, sector_num << BDRV_SECTOR_BITS,
+ nb_sectors);
+ qemu_co_mutex_unlock(&s->lock);
+
+ return ret;
+}
+
static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors)
{
@@ -1558,6 +1578,7 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_co_writev = qcow2_co_writev,
.bdrv_co_flush_to_os = qcow2_co_flush_to_os,
+ .bdrv_co_write_zeroes = qcow2_co_write_zeroes,
.bdrv_co_discard = qcow2_co_discard,
.bdrv_truncate = qcow2_truncate,
.bdrv_write_compressed = qcow2_write_compressed,
diff --git a/block/qcow2.h b/block/qcow2.h
index 2a98244..93567f6 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -283,6 +283,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
int nb_sectors);
+int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
/* qcow2-snapshot.c functions */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
commit ab3a32ad5ea841c313e5f9c5f0d4ec02a8e9ddfc
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Apr 12 15:28:12 2012 +0200
qemu-iotests: Test backing file COW with zero clusters
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034
new file mode 100755
index 0000000..8254df8
--- /dev/null
+++ b/tests/qemu-iotests/034
@@ -0,0 +1,113 @@
+#!/bin/bash
+#
+# Test bdrv_write_zeroes with backing files
+#
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow qcow2 vmdk qed
+_supported_proto generic
+_supported_os Linux
+
+CLUSTER_SIZE=4k
+size=128M
+
+echo
+echo "== creating backing file for COW tests =="
+
+_make_test_img $size
+$QEMU_IO -c "write -P 0x55 0 1M" $TEST_IMG | _filter_qemu_io
+mv $TEST_IMG $TEST_IMG.base
+
+_make_test_img -b $TEST_IMG.base 6G
+
+echo
+echo "== zero write with backing file =="
+$QEMU_IO -c "write -z 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 513k 13k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (3) =="
+$QEMU_IO -c "read -P 0x55 0 64k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 256k 257k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 513k 13k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 526k 498k" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== overwriting zero cluster =="
+$QEMU_IO -c "write -P 0xa 60k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xb 64k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xc 76k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xd 252k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xe 248k 8k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (4) =="
+$QEMU_IO -c "read -P 0x55 0 60k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 60k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xb 64k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 72k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xc 76k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 80k 168k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xe 248k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xd 256k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 260k 64k" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== re-zeroing overwritten area =="
+$QEMU_IO -c "write -z 64k 192k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (5) =="
+$QEMU_IO -c "read -P 0x55 0 60k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 60k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xd 256k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 260k 253k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 513k 13k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 526k 498k" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/034.out b/tests/qemu-iotests/034.out
new file mode 100644
index 0000000..e82dae5
--- /dev/null
+++ b/tests/qemu-iotests/034.out
@@ -0,0 +1,81 @@
+QA output created by 034
+
+== creating backing file for COW tests ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+
+== zero write with backing file ==
+wrote 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (3) ==
+read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 263168/263168 bytes at offset 262144
+257 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 509952/509952 bytes at offset 538624
+498 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== overwriting zero cluster ==
+wrote 8192/8192 bytes at offset 61440
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 65536
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 4096/4096 bytes at offset 77824
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 258048
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 253952
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (4) ==
+read 61440/61440 bytes at offset 0
+60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 61440
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 8192/8192 bytes at offset 65536
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 73728
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 77824
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 172032/172032 bytes at offset 81920
+168 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 8192/8192 bytes at offset 253952
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 262144
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 266240
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== re-zeroing overwritten area ==
+wrote 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (5) ==
+read 61440/61440 bytes at offset 0
+60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 61440
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 262144
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 259072/259072 bytes at offset 266240
+253 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 509952/509952 bytes at offset 538624
+498 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index af34482..5934829 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -40,3 +40,4 @@
031 rw auto quick
032 rw auto
033 rw auto
+034 rw auto backing
commit ee3a315edfb12d3c18195410050eed0e2d49cc27
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Mar 8 18:15:01 2012 +0100
qemu-iotests: add a simple test for write_zeroes
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
new file mode 100755
index 0000000..9aee078
--- /dev/null
+++ b/tests/qemu-iotests/033
@@ -0,0 +1,73 @@
+#!/bin/bash
+#
+# Test aligned and misaligned write zeroes operations.
+#
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=pbonzini at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt generic
+_supported_proto generic
+_supported_os Linux
+
+
+size=128M
+_make_test_img $size
+
+echo
+echo "== preparing image =="
+$QEMU_IO -c "write -P 0xa 0x200 0x400" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xa 0x20000 0x600" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== verifying patterns (1) =="
+$QEMU_IO -c "read -P 0xa 0x200 0x200" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 0x20400 0x200" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== rewriting zeroes =="
+$QEMU_IO -c "write -P 0xb 0x10000 0x10000" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 0x10000 0x10000" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== verifying patterns (2) =="
+$QEMU_IO -c "read -P 0x0 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/033.out b/tests/qemu-iotests/033.out
new file mode 100644
index 0000000..8934883
--- /dev/null
+++ b/tests/qemu-iotests/033.out
@@ -0,0 +1,29 @@
+QA output created by 033
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+
+== preparing image ==
+wrote 1024/1024 bytes at offset 512
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1536/1536 bytes at offset 131072
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verifying patterns (1) ==
+read 512/512 bytes at offset 512
+512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 132096
+512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== rewriting zeroes ==
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verifying patterns (2) ==
+read 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 92508a7..af34482 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -39,3 +39,4 @@
030 rw auto
031 rw auto quick
032 rw auto
+033 rw auto
commit cfcc4c62ffe37170cf4b0c9e7acbd2dbaa792598
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Apr 12 15:20:27 2012 +0200
qcow2: Support for feature table header extension
Instead of printing an ugly bitmask, qemu can now print a more helpful
string even for yet unknown features.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2.c b/block/qcow2.c
index 9a8b354..41b195d 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -54,6 +54,7 @@ typedef struct {
} QCowExtension;
#define QCOW2_EXT_MAGIC_END 0
#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
+#define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
{
@@ -76,7 +77,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
* return 0 upon success, non-0 otherwise
*/
static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
- uint64_t end_offset)
+ uint64_t end_offset, void **p_feature_table)
{
BDRVQcowState *s = bs->opaque;
QCowExtension ext;
@@ -134,6 +135,18 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
#endif
break;
+ case QCOW2_EXT_MAGIC_FEATURE_TABLE:
+ if (p_feature_table != NULL) {
+ void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
+ ret = bdrv_pread(bs->file, offset , feature_table, ext.len);
+ if (ret < 0) {
+ return ret;
+ }
+
+ *p_feature_table = feature_table;
+ }
+ break;
+
default:
/* unknown magic - save it in case we need to rewrite the header */
{
@@ -182,6 +195,24 @@ static void report_unsupported(BlockDriverState *bs, const char *fmt, ...)
bs->device_name, "qcow2", msg);
}
+static void report_unsupported_feature(BlockDriverState *bs,
+ Qcow2Feature *table, uint64_t mask)
+{
+ while (table && table->name[0] != '\0') {
+ if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
+ if (mask & (1 << table->bit)) {
+ report_unsupported(bs, "%.46s",table->name);
+ mask &= ~(1 << table->bit);
+ }
+ }
+ table++;
+ }
+
+ if (mask) {
+ report_unsupported(bs, "Unknown incompatible feature: %" PRIx64, mask);
+ }
+}
+
static int qcow2_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
@@ -245,14 +276,23 @@ static int qcow2_open(BlockDriverState *bs, int flags)
}
}
+ if (header.backing_file_offset) {
+ ext_end = header.backing_file_offset;
+ } else {
+ ext_end = 1 << header.cluster_bits;
+ }
+
/* Handle feature bits */
s->incompatible_features = header.incompatible_features;
s->compatible_features = header.compatible_features;
s->autoclear_features = header.autoclear_features;
if (s->incompatible_features != 0) {
- report_unsupported(bs, "incompatible features mask %" PRIx64,
- header.incompatible_features);
+ void *feature_table = NULL;
+ qcow2_read_extensions(bs, header.header_length, ext_end,
+ &feature_table);
+ report_unsupported_feature(bs, feature_table,
+ s->incompatible_features);
ret = -ENOTSUP;
goto fail;
}
@@ -343,12 +383,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
QLIST_INIT(&s->cluster_allocs);
/* read qcow2 extensions */
- if (header.backing_file_offset) {
- ext_end = header.backing_file_offset;
- } else {
- ext_end = s->cluster_size;
- }
- if (qcow2_read_extensions(bs, header.header_length, ext_end)) {
+ if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL)) {
ret = -EINVAL;
goto fail;
}
@@ -912,6 +947,19 @@ int qcow2_update_header(BlockDriverState *bs)
buflen -= ret;
}
+ /* Feature table */
+ Qcow2Feature features[] = {
+ /* no feature defined yet */
+ };
+
+ ret = header_ext_add(buf, QCOW2_EXT_MAGIC_FEATURE_TABLE,
+ features, sizeof(features), buflen);
+ if (ret < 0) {
+ goto fail;
+ }
+ buf += ret;
+ buflen -= ret;
+
/* Keep unknown header extensions */
QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
diff --git a/block/qcow2.h b/block/qcow2.h
index df2bdfd..2a98244 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -104,6 +104,18 @@ typedef struct Qcow2UnknownHeaderExtension {
uint8_t data[];
} Qcow2UnknownHeaderExtension;
+enum {
+ QCOW2_FEAT_TYPE_INCOMPATIBLE = 0,
+ QCOW2_FEAT_TYPE_COMPATIBLE = 1,
+ QCOW2_FEAT_TYPE_AUTOCLEAR = 2,
+};
+
+typedef struct Qcow2Feature {
+ uint8_t type;
+ uint8_t bit;
+ char name[46];
+} QEMU_PACKED Qcow2Feature;
+
typedef struct BDRVQcowState {
int cluster_bits;
int cluster_size;
commit 6377af48b0445e7ee50db6e0bd73a3a70098f5f4
Author: Kevin Wolf <kwolf at redhat.com>
Date: Fri Mar 16 15:02:38 2012 +0100
qcow2: Support reading zero clusters
This adds support for reading zero clusters in version 3 images.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index b8836ba..5e5f5cf 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -453,6 +453,12 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
c = 1;
*cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
break;
+ case QCOW2_CLUSTER_ZERO:
+ c = count_contiguous_clusters(nb_clusters, s->cluster_size,
+ &l2_table[l2_index], 0,
+ QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
+ *cluster_offset = 0;
+ break;
case QCOW2_CLUSTER_UNALLOCATED:
/* how many empty clusters ? */
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
@@ -461,7 +467,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
case QCOW2_CLUSTER_NORMAL:
/* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index], 0, QCOW_OFLAG_COMPRESSED);
+ &l2_table[l2_index], 0,
+ QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
*cluster_offset &= L2E_OFFSET_MASK;
break;
}
@@ -720,6 +727,7 @@ static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
break;
case QCOW2_CLUSTER_UNALLOCATED:
case QCOW2_CLUSTER_COMPRESSED:
+ case QCOW2_CLUSTER_ZERO:
break;
default:
abort();
@@ -868,9 +876,10 @@ again:
&& (cluster_offset & QCOW_OFLAG_COPIED))
{
/* We keep all QCOW_OFLAG_COPIED clusters */
- keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index], 0,
- QCOW_OFLAG_COPIED);
+ keep_clusters =
+ count_contiguous_clusters(nb_clusters, s->cluster_size,
+ &l2_table[l2_index], 0,
+ QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
assert(keep_clusters <= nb_clusters);
nb_clusters -= keep_clusters;
} else {
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 0112cc3..812c93c 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -703,6 +703,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs,
nb_clusters << s->cluster_bits);
break;
case QCOW2_CLUSTER_UNALLOCATED:
+ case QCOW2_CLUSTER_ZERO:
break;
default:
abort();
@@ -973,6 +974,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
l2_entry & ~511, nb_csectors * 512);
break;
+ case QCOW2_CLUSTER_ZERO:
+ if ((l2_entry & L2E_OFFSET_MASK) == 0) {
+ break;
+ }
+ /* fall through */
+
case QCOW2_CLUSTER_NORMAL:
{
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
diff --git a/block/qcow2.c b/block/qcow2.c
index 3e1482f..9a8b354 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -536,6 +536,14 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
}
break;
+ case QCOW2_CLUSTER_ZERO:
+ if (s->qcow_version < 3) {
+ ret = -EIO;
+ goto fail;
+ }
+ qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
+ break;
+
case QCOW2_CLUSTER_COMPRESSED:
/* add AIO support for compressed blocks ? */
ret = qcow2_decompress_cluster(bs, cluster_offset);
diff --git a/block/qcow2.h b/block/qcow2.h
index 2dc8ca2..df2bdfd 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -43,6 +43,8 @@
#define QCOW_OFLAG_COPIED (1LL << 63)
/* indicate that the cluster is compressed (they never have the copied flag) */
#define QCOW_OFLAG_COMPRESSED (1LL << 62)
+/* The cluster reads as all zeros */
+#define QCOW_OFLAG_ZERO (1LL << 0)
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
@@ -184,6 +186,7 @@ enum {
QCOW2_CLUSTER_UNALLOCATED,
QCOW2_CLUSTER_NORMAL,
QCOW2_CLUSTER_COMPRESSED,
+ QCOW2_CLUSTER_ZERO
};
#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
@@ -213,6 +216,8 @@ static inline int qcow2_get_cluster_type(uint64_t l2_entry)
{
if (l2_entry & QCOW_OFLAG_COMPRESSED) {
return QCOW2_CLUSTER_COMPRESSED;
+ } else if (l2_entry & QCOW_OFLAG_ZERO) {
+ return QCOW2_CLUSTER_ZERO;
} else if (!(l2_entry & L2E_OFFSET_MASK)) {
return QCOW2_CLUSTER_UNALLOCATED;
} else {
commit 6744cbab8cd63b7ce72b3eee4f0055007acf0798
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Dec 15 12:20:58 2011 +0100
qcow2: Version 3 images
This adds the basic infrastructure to qcow2 to handle version 3 images.
It includes code to create v3 images, allow header updates for v3 images
and checks feature bits.
It still misses support for zero clusters, so this is not a fully
compliant implementation of v3 yet.
The default for creating new images stays at v2 for now.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2.c b/block/qcow2.c
index 4c82adc..3e1482f 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -61,7 +61,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
if (buf_size >= sizeof(QCowHeader) &&
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
- be32_to_cpu(cow_header->version) >= QCOW_VERSION)
+ be32_to_cpu(cow_header->version) >= 2)
return 100;
else
return 0;
@@ -169,6 +169,19 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs)
}
}
+static void report_unsupported(BlockDriverState *bs, const char *fmt, ...)
+{
+ char msg[64];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+
+ qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+ bs->device_name, "qcow2", msg);
+}
+
static int qcow2_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
@@ -199,14 +212,64 @@ static int qcow2_open(BlockDriverState *bs, int flags)
ret = -EINVAL;
goto fail;
}
- if (header.version != QCOW_VERSION) {
- char version[64];
- snprintf(version, sizeof(version), "QCOW version %d", header.version);
- qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
- bs->device_name, "qcow2", version);
+ if (header.version < 2 || header.version > 3) {
+ report_unsupported(bs, "QCOW version %d", header.version);
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
+ s->qcow_version = header.version;
+
+ /* Initialise version 3 header fields */
+ if (header.version == 2) {
+ header.incompatible_features = 0;
+ header.compatible_features = 0;
+ header.autoclear_features = 0;
+ header.refcount_order = 4;
+ header.header_length = 72;
+ } else {
+ be64_to_cpus(&header.incompatible_features);
+ be64_to_cpus(&header.compatible_features);
+ be64_to_cpus(&header.autoclear_features);
+ be32_to_cpus(&header.refcount_order);
+ be32_to_cpus(&header.header_length);
+ }
+
+ if (header.header_length > sizeof(header)) {
+ s->unknown_header_fields_size = header.header_length - sizeof(header);
+ s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
+ ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields,
+ s->unknown_header_fields_size);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
+ /* Handle feature bits */
+ s->incompatible_features = header.incompatible_features;
+ s->compatible_features = header.compatible_features;
+ s->autoclear_features = header.autoclear_features;
+
+ if (s->incompatible_features != 0) {
+ report_unsupported(bs, "incompatible features mask %" PRIx64,
+ header.incompatible_features);
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
+ if (!bs->read_only && s->autoclear_features != 0) {
+ s->autoclear_features = 0;
+ qcow2_update_header(bs);
+ }
+
+ /* Check support for various header values */
+ if (header.refcount_order != 4) {
+ report_unsupported(bs, "%d bit reference counts",
+ 1 << header.refcount_order);
ret = -ENOTSUP;
goto fail;
}
+
if (header.cluster_bits < MIN_CLUSTER_BITS ||
header.cluster_bits > MAX_CLUSTER_BITS) {
ret = -EINVAL;
@@ -285,7 +348,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
} else {
ext_end = s->cluster_size;
}
- if (qcow2_read_extensions(bs, sizeof(header), ext_end)) {
+ if (qcow2_read_extensions(bs, header.header_length, ext_end)) {
ret = -EINVAL;
goto fail;
}
@@ -321,6 +384,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
return ret;
fail:
+ g_free(s->unknown_header_fields);
cleanup_unknown_header_ext(bs);
qcow2_free_snapshots(bs);
qcow2_refcount_close(bs);
@@ -682,7 +746,9 @@ static void qcow2_close(BlockDriverState *bs)
qcow2_cache_destroy(bs, s->l2_table_cache);
qcow2_cache_destroy(bs, s->refcount_block_cache);
+ g_free(s->unknown_header_fields);
cleanup_unknown_header_ext(bs);
+
g_free(s->cluster_cache);
qemu_vfree(s->cluster_data);
qcow2_refcount_close(bs);
@@ -756,10 +822,10 @@ int qcow2_update_header(BlockDriverState *bs)
int ret;
uint64_t total_size;
uint32_t refcount_table_clusters;
+ size_t header_length;
Qcow2UnknownHeaderExtension *uext;
buf = qemu_blockalign(bs, buflen);
- memset(buf, 0, s->cluster_size);
/* Header structure */
header = (QCowHeader*) buf;
@@ -769,12 +835,14 @@ int qcow2_update_header(BlockDriverState *bs)
goto fail;
}
+ header_length = sizeof(*header) + s->unknown_header_fields_size;
total_size = bs->total_sectors * BDRV_SECTOR_SIZE;
refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
*header = (QCowHeader) {
+ /* Version 2 fields */
.magic = cpu_to_be32(QCOW_MAGIC),
- .version = cpu_to_be32(QCOW_VERSION),
+ .version = cpu_to_be32(s->qcow_version),
.backing_file_offset = 0,
.backing_file_size = 0,
.cluster_bits = cpu_to_be32(s->cluster_bits),
@@ -786,10 +854,42 @@ int qcow2_update_header(BlockDriverState *bs)
.refcount_table_clusters = cpu_to_be32(refcount_table_clusters),
.nb_snapshots = cpu_to_be32(s->nb_snapshots),
.snapshots_offset = cpu_to_be64(s->snapshots_offset),
+
+ /* Version 3 fields */
+ .incompatible_features = cpu_to_be64(s->incompatible_features),
+ .compatible_features = cpu_to_be64(s->compatible_features),
+ .autoclear_features = cpu_to_be64(s->autoclear_features),
+ .refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT),
+ .header_length = cpu_to_be32(header_length),
};
- buf += sizeof(*header);
- buflen -= sizeof(*header);
+ /* For older versions, write a shorter header */
+ switch (s->qcow_version) {
+ case 2:
+ ret = offsetof(QCowHeader, incompatible_features);
+ break;
+ case 3:
+ ret = sizeof(*header);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ buf += ret;
+ buflen -= ret;
+ memset(buf, 0, buflen);
+
+ /* Preserve any unknown field in the header */
+ if (s->unknown_header_fields_size) {
+ if (buflen < s->unknown_header_fields_size) {
+ ret = -ENOSPC;
+ goto fail;
+ }
+
+ memcpy(buf, s->unknown_header_fields, s->unknown_header_fields_size);
+ buf += s->unknown_header_fields_size;
+ buflen -= s->unknown_header_fields_size;
+ }
/* Backing file format header extension */
if (*bs->backing_format) {
@@ -921,7 +1021,7 @@ static int preallocate(BlockDriverState *bs)
static int qcow2_create2(const char *filename, int64_t total_size,
const char *backing_file, const char *backing_format,
int flags, size_t cluster_size, int prealloc,
- QEMUOptionParameter *options)
+ QEMUOptionParameter *options, int version)
{
/* Calculate cluster_bits */
int cluster_bits;
@@ -965,13 +1065,15 @@ static int qcow2_create2(const char *filename, int64_t total_size,
/* Write the header */
memset(&header, 0, sizeof(header));
header.magic = cpu_to_be32(QCOW_MAGIC);
- header.version = cpu_to_be32(QCOW_VERSION);
+ header.version = cpu_to_be32(version);
header.cluster_bits = cpu_to_be32(cluster_bits);
header.size = cpu_to_be64(0);
header.l1_table_offset = cpu_to_be64(0);
header.l1_size = cpu_to_be32(0);
header.refcount_table_offset = cpu_to_be64(cluster_size);
header.refcount_table_clusters = cpu_to_be32(1);
+ header.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT);
+ header.header_length = cpu_to_be32(sizeof(header));
if (flags & BLOCK_FLAG_ENCRYPT) {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
@@ -1053,6 +1155,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
int flags = 0;
size_t cluster_size = DEFAULT_CLUSTER_SIZE;
int prealloc = 0;
+ int version = 2;
/* Read out options */
while (options && options->name) {
@@ -1078,6 +1181,16 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
options->value.s);
return -EINVAL;
}
+ } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) {
+ if (!options->value.s || !strcmp(options->value.s, "0.10")) {
+ version = 2;
+ } else if (!strcmp(options->value.s, "1.1")) {
+ version = 3;
+ } else {
+ fprintf(stderr, "Invalid compatibility level: '%s'\n",
+ options->value.s);
+ return -EINVAL;
+ }
}
options++;
}
@@ -1089,7 +1202,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
}
return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
- cluster_size, prealloc, options);
+ cluster_size, prealloc, options, version);
}
static int qcow2_make_empty(BlockDriverState *bs)
@@ -1341,6 +1454,11 @@ static QEMUOptionParameter qcow2_create_options[] = {
.help = "Virtual disk size"
},
{
+ .name = BLOCK_OPT_COMPAT_LEVEL,
+ .type = OPT_STRING,
+ .help = "Compatibility level (0.10 or 1.1)"
+ },
+ {
.name = BLOCK_OPT_BACKING_FILE,
.type = OPT_STRING,
.help = "File name of a base image"
diff --git a/block/qcow2.h b/block/qcow2.h
index 291309a..2dc8ca2 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -33,7 +33,6 @@
//#define DEBUG_EXT
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
-#define QCOW_VERSION 2
#define QCOW_CRYPT_NONE 0
#define QCOW_CRYPT_AES 1
@@ -71,6 +70,14 @@ typedef struct QCowHeader {
uint32_t refcount_table_clusters;
uint32_t nb_snapshots;
uint64_t snapshots_offset;
+
+ /* The following fields are only valid for version >= 3 */
+ uint64_t incompatible_features;
+ uint64_t compatible_features;
+ uint64_t autoclear_features;
+
+ uint32_t refcount_order;
+ uint32_t header_length;
} QCowHeader;
typedef struct QCowSnapshot {
@@ -135,6 +142,14 @@ typedef struct BDRVQcowState {
QCowSnapshot *snapshots;
int flags;
+ int qcow_version;
+
+ uint64_t incompatible_features;
+ uint64_t compatible_features;
+ uint64_t autoclear_features;
+
+ size_t unknown_header_fields_size;
+ void* unknown_header_fields;
QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
} BDRVQcowState;
diff --git a/block_int.h b/block_int.h
index 0e5a032..0acb49f 100644
--- a/block_int.h
+++ b/block_int.h
@@ -50,6 +50,7 @@
#define BLOCK_OPT_TABLE_SIZE "table_size"
#define BLOCK_OPT_PREALLOC "preallocation"
#define BLOCK_OPT_SUBFMT "subformat"
+#define BLOCK_OPT_COMPAT_LEVEL "compat"
typedef struct BdrvTrackedRequest BdrvTrackedRequest;
commit afdf0abe779f4b11712eb306ab2d4299820457b8
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Mar 27 13:44:56 2012 +0200
qcow2: Ignore reserved bits in check_refcounts
Also don't infer the cluster type directly from the L2 entries, but use
qcow2_get_cluster_type() to keep everything in a single place.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index e0854dc..0112cc3 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -940,7 +940,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
int check_copied)
{
BDRVQcowState *s = bs->opaque;
- uint64_t *l2_table, offset;
+ uint64_t *l2_table, l2_entry;
int i, l2_size, nb_csectors, refcount;
/* Read L2 table from disk */
@@ -952,54 +952,64 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
/* Do the actual checks */
for(i = 0; i < s->l2_size; i++) {
- offset = be64_to_cpu(l2_table[i]);
- if (offset != 0) {
- if (offset & QCOW_OFLAG_COMPRESSED) {
- /* Compressed clusters don't have QCOW_OFLAG_COPIED */
- if (offset & QCOW_OFLAG_COPIED) {
- fprintf(stderr, "ERROR: cluster %" PRId64 ": "
- "copied flag must never be set for compressed "
- "clusters\n", offset >> s->cluster_bits);
- offset &= ~QCOW_OFLAG_COPIED;
- res->corruptions++;
- }
+ l2_entry = be64_to_cpu(l2_table[i]);
+
+ switch (qcow2_get_cluster_type(l2_entry)) {
+ case QCOW2_CLUSTER_COMPRESSED:
+ /* Compressed clusters don't have QCOW_OFLAG_COPIED */
+ if (l2_entry & QCOW_OFLAG_COPIED) {
+ fprintf(stderr, "ERROR: cluster %" PRId64 ": "
+ "copied flag must never be set for compressed "
+ "clusters\n", l2_entry >> s->cluster_bits);
+ l2_entry &= ~QCOW_OFLAG_COPIED;
+ res->corruptions++;
+ }
- /* Mark cluster as used */
- nb_csectors = ((offset >> s->csize_shift) &
- s->csize_mask) + 1;
- offset &= s->cluster_offset_mask;
- inc_refcounts(bs, res, refcount_table, refcount_table_size,
- offset & ~511, nb_csectors * 512);
- } else {
- /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
- if (check_copied) {
- uint64_t entry = offset;
- offset &= ~QCOW_OFLAG_COPIED;
- refcount = get_refcount(bs, offset >> s->cluster_bits);
- if (refcount < 0) {
- fprintf(stderr, "Can't get refcount for offset %"
- PRIx64 ": %s\n", entry, strerror(-refcount));
- goto fail;
- }
- if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
- fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
- PRIx64 " refcount=%d\n", entry, refcount);
- res->corruptions++;
- }
- }
+ /* Mark cluster as used */
+ nb_csectors = ((l2_entry >> s->csize_shift) &
+ s->csize_mask) + 1;
+ l2_entry &= s->cluster_offset_mask;
+ inc_refcounts(bs, res, refcount_table, refcount_table_size,
+ l2_entry & ~511, nb_csectors * 512);
+ break;
- /* Mark cluster as used */
- offset &= ~QCOW_OFLAG_COPIED;
- inc_refcounts(bs, res, refcount_table,refcount_table_size,
- offset, s->cluster_size);
+ case QCOW2_CLUSTER_NORMAL:
+ {
+ /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
+ uint64_t offset = l2_entry & L2E_OFFSET_MASK;
- /* Correct offsets are cluster aligned */
- if (offset & (s->cluster_size - 1)) {
- fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
- "properly aligned; L2 entry corrupted.\n", offset);
+ if (check_copied) {
+ refcount = get_refcount(bs, offset >> s->cluster_bits);
+ if (refcount < 0) {
+ fprintf(stderr, "Can't get refcount for offset %"
+ PRIx64 ": %s\n", l2_entry, strerror(-refcount));
+ goto fail;
+ }
+ if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
+ fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
+ PRIx64 " refcount=%d\n", l2_entry, refcount);
res->corruptions++;
}
}
+
+ /* Mark cluster as used */
+ inc_refcounts(bs, res, refcount_table,refcount_table_size,
+ offset, s->cluster_size);
+
+ /* Correct offsets are cluster aligned */
+ if (offset & (s->cluster_size - 1)) {
+ fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
+ "properly aligned; L2 entry corrupted.\n", offset);
+ res->corruptions++;
+ }
+ break;
+ }
+
+ case QCOW2_CLUSTER_UNALLOCATED:
+ break;
+
+ default:
+ abort();
}
}
@@ -1070,7 +1080,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
}
/* Mark L2 table as used */
- l2_offset &= ~QCOW_OFLAG_COPIED;
+ l2_offset &= L1E_OFFSET_MASK;
inc_refcounts(bs, res, refcount_table, refcount_table_size,
l2_offset, s->cluster_size);
commit 76dc9e0c8f369f1695e5413de2e28d69108476bb
Author: Kevin Wolf <kwolf at redhat.com>
Date: Fri Mar 16 14:09:08 2012 +0100
qcow2: Ignore reserved bits in refcount table entries
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 909d615..e0854dc 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -167,7 +167,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
if (refcount_table_index < s->refcount_table_size) {
uint64_t refcount_block_offset =
- s->refcount_table[refcount_table_index];
+ s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK;
/* If it's already there, we're done */
if (refcount_block_offset) {
diff --git a/block/qcow2.h b/block/qcow2.h
index a22d7fa..291309a 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -175,6 +175,8 @@ enum {
#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
+#define REFT_OFFSET_MASK 0xffffffffffffff00ULL
+
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
{
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
commit 143550a83ef4eef86a847d00023d148e1f59f743
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Mar 27 13:17:22 2012 +0200
qcow2: Simplify count_cow_clusters
count_cow_clusters() tries to reuse existing functions, and all it
achieves is to make things much more complicated than they really are:
Everything needs COW, unless it's a normal cluster with refcount 1.
This patch implements the obvious way of doing this, and by using
qcow2_get_cluster_type() it gets rid of all flag magic.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index d1602d4..b8836ba 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -706,30 +706,27 @@ err:
static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
uint64_t *l2_table, int l2_index)
{
- int i = 0;
- uint64_t cluster_offset;
+ int i;
- while (i < nb_clusters) {
- i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
- &l2_table[l2_index], i,
- QCOW_OFLAG_COPIED | QCOW_OFLAG_COMPRESSED);
- if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
- break;
- }
+ for (i = 0; i < nb_clusters; i++) {
+ uint64_t l2_entry = be64_to_cpu(l2_table[l2_index + i]);
+ int cluster_type = qcow2_get_cluster_type(l2_entry);
- i += count_contiguous_free_clusters(nb_clusters - i,
- &l2_table[l2_index + i]);
- if (i >= nb_clusters) {
+ switch(cluster_type) {
+ case QCOW2_CLUSTER_NORMAL:
+ if (l2_entry & QCOW_OFLAG_COPIED) {
+ goto out;
+ }
break;
- }
-
- cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
-
- if ((cluster_offset & QCOW_OFLAG_COPIED) ||
- (cluster_offset & QCOW_OFLAG_COMPRESSED))
+ case QCOW2_CLUSTER_UNALLOCATED:
+ case QCOW2_CLUSTER_COMPRESSED:
break;
+ default:
+ abort();
+ }
}
+out:
assert(i <= nb_clusters);
return i;
}
commit c7a4c37a0f768f7ad50f64414d578436019e1e96
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Mar 27 13:09:22 2012 +0200
qcow2: Refactor qcow2_free_any_clusters
Zero clusters will add another cluster type. Refactor the open-coded
cluster type detection into a switch of QCOW2_CLUSTER_* options so that
the detection is in a single place. This makes it easier to add new
cluster types.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 84fa343..909d615 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -679,31 +679,34 @@ void qcow2_free_clusters(BlockDriverState *bs,
}
/*
- * free_any_clusters
- *
- * free clusters according to its type: compressed or not
- *
+ * Free a cluster using its L2 entry (handles clusters of all types, e.g.
+ * normal cluster, compressed cluster, etc.)
*/
-
void qcow2_free_any_clusters(BlockDriverState *bs,
- uint64_t cluster_offset, int nb_clusters)
+ uint64_t l2_entry, int nb_clusters)
{
BDRVQcowState *s = bs->opaque;
- /* free the cluster */
-
- if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
- int nb_csectors;
- nb_csectors = ((cluster_offset >> s->csize_shift) &
- s->csize_mask) + 1;
- qcow2_free_clusters(bs,
- (cluster_offset & s->cluster_offset_mask) & ~511,
- nb_csectors * 512);
- return;
+ switch (qcow2_get_cluster_type(l2_entry)) {
+ case QCOW2_CLUSTER_COMPRESSED:
+ {
+ int nb_csectors;
+ nb_csectors = ((l2_entry >> s->csize_shift) &
+ s->csize_mask) + 1;
+ qcow2_free_clusters(bs,
+ (l2_entry & s->cluster_offset_mask) & ~511,
+ nb_csectors * 512);
+ }
+ break;
+ case QCOW2_CLUSTER_NORMAL:
+ qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
+ nb_clusters << s->cluster_bits);
+ break;
+ case QCOW2_CLUSTER_UNALLOCATED:
+ break;
+ default:
+ abort();
}
-
- qcow2_free_clusters(bs, cluster_offset & L2E_OFFSET_MASK,
- nb_clusters << s->cluster_bits);
}
commit 8e37f681d58bbe166c20559e77fd55b1cb8e6e4b
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Feb 23 15:40:55 2012 +0100
qcow2: Ignore reserved bits in L1/L2 entries
This changes the still existing places that assume that the only flags
are QCOW_OFLAG_COPIED and QCOW_OFLAG_COMPRESSED to properly mask out
reserved bits.
It does not convert bdrv_check yet.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index dff782f..d1602d4 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -195,7 +195,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
l2_table = *table;
- if (old_l2_offset == 0) {
+ if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
/* if there was no old l2 table, clear the new table */
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
} else {
@@ -203,7 +203,8 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
/* if there was an old l2 table, read it from the disk */
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
- ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_offset,
+ ret = qcow2_cache_get(bs, s->l2_table_cache,
+ old_l2_offset & L1E_OFFSET_MASK,
(void**) &old_table);
if (ret < 0) {
goto fail;
@@ -508,13 +509,13 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
return ret;
}
}
- l2_offset = s->l1_table[l1_index];
+
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
/* seek the l2 table of the given l2 offset */
- if (l2_offset & QCOW_OFLAG_COPIED) {
+ if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
/* load the l2 table in memory */
- l2_offset &= ~QCOW_OFLAG_COPIED;
ret = l2_load(bs, l2_offset, &l2_table);
if (ret < 0) {
return ret;
@@ -530,7 +531,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
if (l2_offset) {
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
}
- l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
}
/* find the cluster offset for the given disk offset */
@@ -687,8 +688,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
*/
if (j != 0) {
for (i = 0; i < j; i++) {
- qcow2_free_any_clusters(bs,
- be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
+ qcow2_free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1);
}
}
@@ -867,7 +867,9 @@ again:
* Check how many clusters are already allocated and don't need COW, and how
* many need a new allocation.
*/
- if (cluster_offset & QCOW_OFLAG_COPIED) {
+ if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
+ && (cluster_offset & QCOW_OFLAG_COPIED))
+ {
/* We keep all QCOW_OFLAG_COPIED clusters */
keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
@@ -886,7 +888,7 @@ again:
cluster_offset = 0;
}
- cluster_offset &= ~QCOW_OFLAG_COPIED;
+ cluster_offset &= L2E_OFFSET_MASK;
/* If there is something left to allocate, do that now */
*m = (QCowL2Meta) {
@@ -1041,9 +1043,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
uint64_t old_offset;
old_offset = be64_to_cpu(l2_table[l2_index + i]);
- old_offset &= ~QCOW_OFLAG_COPIED;
-
- if (old_offset == 0) {
+ if ((old_offset & L2E_OFFSET_MASK) == 0) {
continue;
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 6c38337..84fa343 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -702,9 +702,8 @@ void qcow2_free_any_clusters(BlockDriverState *bs,
return;
}
- qcow2_free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits);
-
- return;
+ qcow2_free_clusters(bs, cluster_offset & L2E_OFFSET_MASK,
+ nb_clusters << s->cluster_bits);
}
@@ -764,7 +763,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
l2_offset = l1_table[i];
if (l2_offset) {
old_l2_offset = l2_offset;
- l2_offset &= ~QCOW_OFLAG_COPIED;
+ l2_offset &= L1E_OFFSET_MASK;
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
(void**) &l2_table);
@@ -796,10 +795,11 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
/* compressed clusters are never modified */
refcount = 2;
} else {
+ uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
if (addend != 0) {
- refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
+ refcount = update_cluster_refcount(bs, cluster_index, addend);
} else {
- refcount = get_refcount(bs, offset >> s->cluster_bits);
+ refcount = get_refcount(bs, cluster_index);
}
if (refcount < 0) {
commit b0b6862e5e1a1394e0ab3d5da94ba8b0da8664e2
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Mar 15 17:20:11 2012 +0100
qcow2: Fail write_compressed when overwriting data
qcow2_alloc_compressed_cluster_offset() already fails if the copied flag
is set, because qcow2_write_compressed() doesn't perform COW as it would
have to do to allow this.
However, what we really want to check here is whether the cluster is
allocated or not. With internal snapshots the copied flag may not be set
on allocated clusters. Check the cluster offset instead.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 7b05990..dff782f 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -571,15 +571,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
return 0;
}
+ /* Compression can't overwrite anything. Fail if the cluster was already
+ * allocated. */
cluster_offset = be64_to_cpu(l2_table[l2_index]);
- if (cluster_offset & QCOW_OFLAG_COPIED) {
+ if (cluster_offset & L2E_OFFSET_MASK) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
return 0;
}
- if (cluster_offset)
- qcow2_free_any_clusters(bs, cluster_offset, 1);
-
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
if (cluster_offset < 0) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
commit 2bfcc4a0a0b5120b6518e1c823c18cf0e8b963cb
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Mar 15 16:37:40 2012 +0100
qcow2: Ignore reserved bits in count_contiguous_clusters()
Until now, count_contiguous_clusters() has an argument that allowed to
specify flags that should be ignored in the comparison, i.e. that are
allowed to change between contiguous clusters.
This patch changes the function so that it ignores all flags by default
now and you need to pass the flags on which it should stop.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index c8c85d2..7b05990 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -246,28 +246,44 @@ fail:
return ret;
}
+/*
+ * Checks how many clusters in a given L2 table are contiguous in the image
+ * file. As soon as one of the flags in the bitmask stop_flags changes compared
+ * to the first cluster, the search is stopped and the cluster is not counted
+ * as contiguous. (This allows it, for example, to stop at the first compressed
+ * cluster which may require a different handling)
+ */
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
- uint64_t *l2_table, uint64_t start, uint64_t mask)
+ uint64_t *l2_table, uint64_t start, uint64_t stop_flags)
{
int i;
- uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
+ uint64_t mask = stop_flags | L2E_OFFSET_MASK;
+ uint64_t offset = be64_to_cpu(l2_table[0]) & mask;
if (!offset)
return 0;
- for (i = start; i < start + nb_clusters; i++)
- if (offset + (uint64_t) i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
+ for (i = start; i < start + nb_clusters; i++) {
+ uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
+ if (offset + (uint64_t) i * cluster_size != l2_entry) {
break;
+ }
+ }
return (i - start);
}
static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
{
- int i = 0;
+ int i;
- while(nb_clusters-- && l2_table[i] == 0)
- i++;
+ for (i = 0; i < nb_clusters; i++) {
+ int type = qcow2_get_cluster_type(be64_to_cpu(l2_table[i]));
+
+ if (type != QCOW2_CLUSTER_UNALLOCATED) {
+ break;
+ }
+ }
return i;
}
@@ -444,7 +460,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
case QCOW2_CLUSTER_NORMAL:
/* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
+ &l2_table[l2_index], 0, QCOW_OFLAG_COMPRESSED);
*cluster_offset &= L2E_OFFSET_MASK;
break;
}
@@ -696,7 +712,8 @@ static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
while (i < nb_clusters) {
i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
- &l2_table[l2_index], i, 0);
+ &l2_table[l2_index], i,
+ QCOW_OFLAG_COPIED | QCOW_OFLAG_COMPRESSED);
if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
break;
}
@@ -854,7 +871,8 @@ again:
if (cluster_offset & QCOW_OFLAG_COPIED) {
/* We keep all QCOW_OFLAG_COPIED clusters */
keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index], 0, 0);
+ &l2_table[l2_index], 0,
+ QCOW_OFLAG_COPIED);
assert(keep_clusters <= nb_clusters);
nb_clusters -= keep_clusters;
} else {
commit 68d000a39074fe3888680491444a7fde2354cd84
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Mar 14 19:15:03 2012 +0100
qcow2: Ignore reserved bits in get_cluster_offset
With this change, reading from a qcow2 image ignores all reserved bits
that are set in an L1 or L2 table entry.
Now get_cluster_offset() assigns *cluster_offset only the offset without
any other flags. The cluster type is not longer encoded in the offset,
but a positive return value in case of success.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index dcf70a2..c8c85d2 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -367,11 +367,9 @@ out:
*
* on exit, *num is the number of contiguous sectors we can read.
*
- * Return 0, if the offset is found
- * Return -errno, otherwise.
- *
+ * Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
+ * cases.
*/
-
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num, uint64_t *cluster_offset)
{
@@ -407,19 +405,19 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
/* seek the the l2 offset in the l1 table */
l1_index = offset >> l1_bits;
- if (l1_index >= s->l1_size)
+ if (l1_index >= s->l1_size) {
+ ret = QCOW2_CLUSTER_UNALLOCATED;
goto out;
+ }
- l2_offset = s->l1_table[l1_index];
-
- /* seek the l2 table of the given l2 offset */
-
- if (!l2_offset)
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
+ if (!l2_offset) {
+ ret = QCOW2_CLUSTER_UNALLOCATED;
goto out;
+ }
/* load the l2 table in memory */
- l2_offset &= ~QCOW_OFLAG_COPIED;
ret = l2_load(bs, l2_offset, &l2_table);
if (ret < 0) {
return ret;
@@ -431,26 +429,37 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
nb_clusters = size_to_clusters(s, nb_needed << 9);
- if (!*cluster_offset) {
+ ret = qcow2_get_cluster_type(*cluster_offset);
+ switch (ret) {
+ case QCOW2_CLUSTER_COMPRESSED:
+ /* Compressed clusters can only be processed one by one */
+ c = 1;
+ *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
+ break;
+ case QCOW2_CLUSTER_UNALLOCATED:
/* how many empty clusters ? */
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
- } else {
+ *cluster_offset = 0;
+ break;
+ case QCOW2_CLUSTER_NORMAL:
/* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
+ *cluster_offset &= L2E_OFFSET_MASK;
+ break;
}
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- nb_available = (c * s->cluster_sectors);
+ nb_available = (c * s->cluster_sectors);
+
out:
if (nb_available > nb_needed)
nb_available = nb_needed;
*num = nb_available - index_in_cluster;
- *cluster_offset &=~QCOW_OFLAG_COPIED;
- return 0;
+ return ret;
}
/*
diff --git a/block/qcow2.c b/block/qcow2.c
index 70d3141..4c82adc 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -449,7 +449,8 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
cur_nr_sectors * 512);
- if (!cluster_offset) {
+ switch (ret) {
+ case QCOW2_CLUSTER_UNALLOCATED:
if (bs->backing_hd) {
/* read from the base image */
@@ -469,7 +470,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
/* Note: in this case, no need to wait */
qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
}
- } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+ break;
+
+ case QCOW2_CLUSTER_COMPRESSED:
/* add AIO support for compressed blocks ? */
ret = qcow2_decompress_cluster(bs, cluster_offset);
if (ret < 0) {
@@ -479,7 +482,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
qemu_iovec_from_buffer(&hd_qiov,
s->cluster_cache + index_in_cluster * 512,
512 * cur_nr_sectors);
- } else {
+ break;
+
+ case QCOW2_CLUSTER_NORMAL:
if ((cluster_offset & 511) != 0) {
ret = -EIO;
goto fail;
@@ -520,6 +525,12 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
qemu_iovec_from_buffer(&hd_qiov, cluster_data,
512 * cur_nr_sectors);
}
+ break;
+
+ default:
+ g_assert_not_reached();
+ ret = -EIO;
+ goto fail;
}
remaining_sectors -= cur_nr_sectors;
diff --git a/block/qcow2.h b/block/qcow2.h
index ddb976a..a22d7fa 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -165,6 +165,16 @@ typedef struct QCowL2Meta
QLIST_ENTRY(QCowL2Meta) next_in_flight;
} QCowL2Meta;
+enum {
+ QCOW2_CLUSTER_UNALLOCATED,
+ QCOW2_CLUSTER_NORMAL,
+ QCOW2_CLUSTER_COMPRESSED,
+};
+
+#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
+#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
+#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
+
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
{
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
@@ -182,6 +192,17 @@ static inline int64_t align_offset(int64_t offset, int n)
return offset;
}
+static inline int qcow2_get_cluster_type(uint64_t l2_entry)
+{
+ if (l2_entry & QCOW_OFLAG_COMPRESSED) {
+ return QCOW2_CLUSTER_COMPRESSED;
+ } else if (!(l2_entry & L2E_OFFSET_MASK)) {
+ return QCOW2_CLUSTER_UNALLOCATED;
+ } else {
+ return QCOW2_CLUSTER_NORMAL;
+ }
+}
+
// FIXME Need qcow2_ prefix to global functions
commit 90b277593df873d3a2480f002e2eb5fe1f8e5277
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Apr 11 16:33:50 2012 +0200
qcow2: Save disk size in snapshot header
This allows that different snapshots of an image can have different
sizes, which is a requirement for enabling image resizing even with
images that have internal snapshots.
We don't do the actual support for it now, but make sure that the
additional field is present and not completely ignored in all version 3
images. When trying to load a snapshot of different size, it returns
an error.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 7d3fde5..42f971b 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -48,6 +48,7 @@ typedef struct QEMU_PACKED QCowSnapshotHeader {
typedef struct QEMU_PACKED QCowSnapshotExtraData {
uint64_t vm_state_size_large;
+ uint64_t disk_size;
} QCowSnapshotExtraData;
void qcow2_free_snapshots(BlockDriverState *bs)
@@ -117,6 +118,12 @@ int qcow2_read_snapshots(BlockDriverState *bs)
sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
}
+ if (extra_data_size >= 16) {
+ sn->disk_size = be64_to_cpu(extra.disk_size);
+ } else {
+ sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
+ }
+
/* Read snapshot ID */
sn->id_str = g_malloc(id_str_size + 1);
ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
@@ -197,6 +204,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
memset(&extra, 0, sizeof(extra));
extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
+ extra.disk_size = cpu_to_be64(sn->disk_size);
id_str_size = strlen(sn->id_str);
name_size = strlen(sn->name);
@@ -330,6 +338,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
sn->id_str = g_strdup(sn_info->id_str);
sn->name = g_strdup(sn_info->name);
+ sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
sn->vm_state_size = sn_info->vm_state_size;
sn->date_sec = sn_info->date_sec;
sn->date_nsec = sn_info->date_nsec;
@@ -426,6 +435,13 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
}
sn = &s->snapshots[snapshot_index];
+ if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
+ error_report("qcow2: Loading snapshots with different disk "
+ "size is not implemented");
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
/*
* Make sure that the current L1 table is big enough to contain the whole
* L1 table of the snapshot. If the snapshot L1 table is smaller, the
diff --git a/block/qcow2.h b/block/qcow2.h
index e4ac366..ddb976a 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -78,6 +78,7 @@ typedef struct QCowSnapshot {
uint32_t l1_size;
char *id_str;
char *name;
+ uint64_t disk_size;
uint64_t vm_state_size;
uint32_t date_sec;
uint32_t date_nsec;
commit 4fabffc11234d0587a213418574095e036110cd2
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Apr 12 13:20:41 2012 +0200
Specification for qcow2 version 3
This updates the qcow2 specification to cover version 3. It contains the
following changes:
- Added compatible/incompatible/auto-clear feature bits plus an optional
feature name table to allow useful error messages even if an older
version doesn't know some feature at all.
- Configurable refcount width. If you don't want to use internal
snapshots, make refcounts one bit and save cache space and I/O.
- Zero cluster flags. This allows discard even with a backing file that
doesn't contain zeros. It is also useful for copy-on-read/image
streaming, as you'll want to keep sparseness without accessing the
remote image for an unallocated cluster all the time.
- Fixed internal snapshot metadata to use 64 bit VM state size. You
can't save a snapshot of a VM with >= 4 GB RAM today.
- Extended internal snapshot metadata to contain the disk size, so that
resizing images that have snapshots can be allowed in the future.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
index b6adcad..65e6325 100644
--- a/docs/specs/qcow2.txt
+++ b/docs/specs/qcow2.txt
@@ -18,7 +18,7 @@ The first cluster of a qcow2 image contains the file header:
QCOW magic string ("QFI\xfb")
4 - 7: version
- Version number (only valid value is 2)
+ Version number (valid values are 2 and 3)
8 - 15: backing_file_offset
Offset into the image file at which the backing file name
@@ -67,12 +67,45 @@ The first cluster of a qcow2 image contains the file header:
Offset into the image file at which the snapshot table
starts. Must be aligned to a cluster boundary.
+If the version is 3 or higher, the header has the following additional fields.
+For version 2, the values are assumed to be zero, unless specified otherwise
+in the description of a field.
+
+ 72 - 79: incompatible_features
+ Bitmask of incompatible features. An implementation must
+ fail to open an image if an unknown bit is set.
+
+ Bits 0-63: Reserved (set to 0)
+
+ 80 - 87: compatible_features
+ Bitmask of compatible features. An implementation can
+ safely ignore any unknown bits that are set.
+
+ Bits 0-63: Reserved (set to 0)
+
+ 88 - 95: autoclear_features
+ Bitmask of auto-clear features. An implementation may only
+ write to an image with unknown auto-clear features if it
+ clears the respective bits from this field first.
+
+ Bits 0-63: Reserved (set to 0)
+
+ 96 - 99: refcount_order
+ Describes the width of a reference count block entry (width
+ in bits = 1 << refcount_order). For version 2 images, the
+ order is always assumed to be 4 (i.e. the width is 16 bits).
+
+ 100 - 103: header_length
+ Length of the header structure in bytes. For version 2
+ images, the length is always assumed to be 72 bytes.
+
Directly after the image header, optional sections called header extensions can
be stored. Each extension has a structure like the following:
Byte 0 - 3: Header extension type:
0x00000000 - End of the header extension area
0xE2792ACA - Backing file format name
+ 0x6803f857 - Feature name table
other - Unknown header extension, can be safely
ignored
@@ -83,9 +116,37 @@ be stored. Each extension has a structure like the following:
n - m: Padding to round up the header extension size to the next
multiple of 8.
+Unless stated otherwise, each header extension type shall appear at most once
+in the same image.
+
The remaining space between the end of the header extension area and the end of
-the first cluster can be used for other data. Usually, the backing file name is
-stored there.
+the first cluster can be used for the backing file name. It is not allowed to
+store other data here, so that an implementation can safely modify the header
+and add extensions without harming data of compatible features that it
+doesn't support. Compatible features that need space for additional data can
+use a header extension.
+
+
+== Feature name table ==
+
+The feature name table is an optional header extension that contains the name
+for features used by the image. It can be used by applications that don't know
+the respective feature (e.g. because the feature was introduced only later) to
+display a useful error message.
+
+The number of entries in the feature name table is determined by the length of
+the header extension data. Each entry look like this:
+
+ Byte 0: Type of feature (select feature bitmap)
+ 0: Incompatible feature
+ 1: Compatible feature
+ 2: Autoclear feature
+
+ 1: Bit number within the selected feature bitmap (valid
+ values: 0-63)
+
+ 2 - 47: Feature name (padded with zeros, but not necessarily null
+ terminated if it has full length)
== Host cluster management ==
@@ -126,9 +187,11 @@ Refcount table entry:
been allocated. All refcounts managed by this refcount block
are 0.
-Refcount block entry:
+Refcount block entry (x = refcount_bits - 1):
- Bit 0 - 15: Reference count of the cluster
+ Bit 0 - x: Reference count of the cluster. If refcount_bits implies a
+ sub-byte width, note that bit 0 means the least significant
+ bit in this context.
== Cluster mapping ==
@@ -168,9 +231,29 @@ L1 table entry:
refcount is exactly one. This information is only accurate
in the active L1 table.
-L2 table entry (for normal clusters):
+L2 table entry:
- Bit 0 - 8: Reserved (set to 0)
+ Bit 0 - 61: Cluster descriptor
+
+ 62: 0 for standard clusters
+ 1 for compressed clusters
+
+ 63: 0 for a cluster that is unused or requires COW, 1 if its
+ refcount is exactly one. This information is only accurate
+ in L2 tables that are reachable from the the active L1
+ table.
+
+Standard Cluster Descriptor:
+
+ Bit 0: If set to 1, the cluster reads as all zeros. The host
+ cluster offset can be used to describe a preallocation,
+ but it won't be used for reading data from this cluster,
+ nor is data read from the backing file if the cluster is
+ unallocated.
+
+ With version 2, this is always 0.
+
+ 1 - 8: Reserved (set to 0)
9 - 55: Bits 9-55 of host cluster offset. Must be aligned to a
cluster boundary. If the offset is 0, the cluster is
@@ -178,30 +261,18 @@ L2 table entry (for normal clusters):
56 - 61: Reserved (set to 0)
- 62: 0 (this cluster is not compressed)
- 63: 0 for a cluster that is unused or requires COW, 1 if its
- refcount is exactly one. This information is only accurate
- in L2 tables that are reachable from the the active L1
- table.
-
-L2 table entry (for compressed clusters; x = 62 - (cluster_size - 8)):
+Compressed Clusters Descriptor (x = 62 - (cluster_size - 8)):
Bit 0 - x: Host cluster offset. This is usually _not_ aligned to a
cluster boundary!
x+1 - 61: Compressed size of the images in sectors of 512 bytes
- 62: 1 (this cluster is compressed using zlib)
-
- 63: 0 for a cluster that is unused or requires COW, 1 if its
- refcount is exactly one. This information is only accurate
- in L2 tables that are reachable from the the active L1
- table.
-
If a cluster is unallocated, read requests shall read the data from the backing
-file. If there is no backing file or the backing file is smaller than the image,
-they shall read zeros for all parts that are not covered by the backing file.
+file (except if bit 0 in the Standard Cluster Descriptor is set). If there is
+no backing file or the backing file is smaller than the image, they shall read
+zeros for all parts that are not covered by the backing file.
== Snapshots ==
@@ -261,6 +332,11 @@ Snapshot table entry:
state is saved. If this field is present,
the 32-bit value in bytes 32-35 is ignored.
+ Byte 48 - 55: Virtual disk size of the snapshot in bytes
+
+ Version 3 images must include extra data at least up to
+ byte 55.
+
variable: Unique ID string for the snapshot (not null terminated)
variable: Name of the snapshot (not null terminated)
commit f24423bd902bce29bc546cf8d030bfa369726ab1
Author: Kevin Wolf <kwolf at redhat.com>
Date: Fri Apr 20 15:50:39 2012 +0200
qcow2: Fix refcount block allocation during qcow2_alloc_cluster_at()
Refcount block allocation and refcount table growth rely on
s->free_cluster_index pointing to somewhere after the current
allocation. Change qcow2_alloc_cluster_at() to fulfill this
assumption.
Without this change it could happen that a newly allocated refcount
block and the allocated data block point to the same area in the image
file, causing data corruption in the long run.
This fixes a bug that became first visible after commit 250196f1.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 565bd54..6c38337 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -587,6 +587,7 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
{
BDRVQcowState *s = bs->opaque;
uint64_t cluster_index;
+ uint64_t old_free_cluster_index;
int i, refcount, ret;
/* Check how many clusters there are free */
@@ -602,11 +603,16 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
}
/* And then allocate them */
+ old_free_cluster_index = s->free_cluster_index;
+ s->free_cluster_index = cluster_index + i;
+
ret = update_refcount(bs, offset, i << s->cluster_bits, 1);
if (ret < 0) {
return ret;
}
+ s->free_cluster_index = old_free_cluster_index;
+
return i;
}
commit fecccc4477451f82028c042eb700a20185d8cf65
Author: David Gibson <david at gibson.dropbear.id.au>
Date: Fri Apr 20 11:40:24 2012 +1000
Add .gitignore for tests/
The new autotests in tests/ generate a number of files, both
executable and source, which are not caught by the existing .gitignore
files. This patch adds a new .gitignore in tests/ which covers these.
[Changed 'rtc-test' to '*-test' so future tests do not need to be added
to .gitignore on a case-by-case basis. Stefan]
Signed-off-by: David Gibson <david at gibson.dropbear.id.au>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..f9041f3
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,13 @@
+check-qdict
+check-qfloat
+check-qint
+check-qjson
+check-qlist
+check-qstring
+test-qapi-types.[ch]
+test-qapi-visit.[ch]
+test-qmp-commands.h
+test-qmp-commands
+test-qmp-input-strict
+test-qmp-marshal.c
+*-test
commit 362f5fb5643a9cfcf4b5127f67af8dcb0fcb9130
Author: Stefan Weil <sw at weilnetz.de>
Date: Wed Apr 18 07:28:34 2012 +0200
e1000: Fix spelling (segmentaion -> segmentation) in debug output
This was reported by https://bugs.launchpad.net/qemu/+bug/984476.
I also changed the case for 'error'.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hw/e1000.c b/hw/e1000.c
index 7babc0b..9c76462 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -481,7 +481,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
} while (split_size -= bytes);
} else if (!tp->tse && tp->cptse) {
// context descriptor TSE is not set, while data descriptor TSE is set
- DBGOUT(TXERR, "TCP segmentaion Error\n");
+ DBGOUT(TXERR, "TCP segmentation error\n");
} else {
split_size = MIN(sizeof(tp->data) - tp->size, split_size);
pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
commit 4f5c0177381e066604a5fe1ffe9a69a0759fa4bb
Author: Eduardo Elias Ferreira <edusf at linux.vnet.ibm.com>
Date: Mon Apr 16 09:51:42 2012 -0300
spice-qemu-char.c: Show what name is unsupported
Signed-off-by: Eduardo Elias Ferreira <edusf at linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 1e735ff..09aa22d 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -209,7 +209,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
}
}
if (subtype == NULL) {
- fprintf(stderr, "spice-qemu-char: unsupported name\n");
+ fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name);
print_allowed_subtypes();
return NULL;
}
commit 4d6145488c84df52a2a0a20e3f36493d7417042a
Author: Eric Bénard <eric at eukrea.com>
Date: Thu Apr 12 09:51:46 2012 +0200
pflash_cfi01: remove redundant line
Signed-off-by: Eric Bénard <eric at eukrea.com>
Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index b03f623..d1c7423 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -144,7 +144,6 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
} else {
ret = p[offset];
ret |= p[offset + 1] << 8;
- ret |= p[offset + 1] << 8;
ret |= p[offset + 2] << 16;
ret |= p[offset + 3] << 24;
}
commit 5f8daf2e04709800531bc1ecbb7b49b637182777
Author: Stefan Weil <sw at weilnetz.de>
Date: Sun Apr 1 22:07:30 2012 +0200
qxl: Add missing GCC_FMT_ATTR and fix format specifier
val is an uint64_t, therefore %d was not correct.
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Acked-by: Gerd Hoffmann <kraxel at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hw/qxl.c b/hw/qxl.c
index db2318e..c3540c3 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1370,7 +1370,7 @@ async_common:
case QXL_IO_DESTROY_SURFACE_WAIT:
if (val >= NUM_SURFACES) {
qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
- "%d >= NUM_SURFACES", async, val);
+ "%" PRIu64 " >= NUM_SURFACES", async, val);
goto cancel_async;
}
qxl_spice_destroy_surface_wait(d, val, async);
diff --git a/hw/qxl.h b/hw/qxl.h
index 11a0db3..cbb1e2d 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -127,7 +127,7 @@ typedef struct PCIQXLDevice {
/* qxl.c */
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) GCC_FMT_ATTR(2, 3);
void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
struct QXLRect *area, struct QXLRect *dirty_rects,
commit 4451b799626207ba66df78257fdf08c740cda6ae
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Apr 13 12:03:46 2012 +0200
fix block_job_set_speed name in documentation
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/hmp-commands.hx b/hmp-commands.hx
index a6f5a84..461fa59 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -92,8 +92,8 @@ ETEXI
},
STEXI
- at item block_job_set_stream
- at findex block_job_set_stream
+ at item block_job_set_speed
+ at findex block_job_set_speed
Set maximum speed for a background block operation.
ETEXI
commit 0ed6dc1a982fd029557a17fda7606d679a6ebb28
Author: Amos Kong <akong at redhat.com>
Date: Mon Apr 16 15:32:49 2012 +0800
error.c: don't return value for void function
It is invalid to return a value from a function
returning void.
[C99 6.8.6.4 says "A return statement with an expression shall not
appear in a function whose return type is void" but gcc 4.6.3 with QEMU
compile flags does not complain. It's still worth fixing this. Stefan]
Signed-off-by: Amos Kong <akong at redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/error.c b/error.c
index d3455ab..a52b771 100644
--- a/error.c
+++ b/error.c
@@ -93,7 +93,7 @@ QDict *error_get_data(Error *err)
void error_set_field(Error *err, const char *field, const char *value)
{
QDict *dict = qdict_get_qdict(err->obj, "data");
- return qdict_put(dict, field, qstring_from_str(value));
+ qdict_put(dict, field, qstring_from_str(value));
}
void error_free(Error *err)
commit 29926112a2fd619abedd8e21002f5d50c476b402
Author: Andreas Färber <afaerber at suse.de>
Date: Fri Apr 20 12:50:24 2012 +0200
iotests: Resolve test failures caused by hostname
`hostname -s` may output an errror:
hostname: Name or service not known
This causes all tests to fail for `make check-block`.
Suppress such error messages, letting the tests succeed.
Signed-off-by: Andreas Färber <afaerber at suse.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
index a220684..df082e7 100644
--- a/tests/qemu-iotests/common.config
+++ b/tests/qemu-iotests/common.config
@@ -36,7 +36,7 @@ export LANG=C
PATH=".:$PATH"
-HOST=`hostname -s`
+HOST=`hostname -s 2> /dev/null`
HOSTOS=`uname -s`
EMAIL=root at localhost # where auto-qa will send its status messages
commit 80ccf93b884a2edab5ec62634758e942bba81b7c
Author: Liu Yuan <tailai.ly at taobao.com>
Date: Fri Apr 20 17:10:56 2012 +0800
qemu-img: let 'qemu-img convert' flush data
The 'qemu-img convert -h' advertise that the default cache mode is
'writeback', while in fact it is 'unsafe'.
This patch 1) fix the help manual and 2) let bdrv_close() call bdrv_flush()
2) is needed because some backend storage doesn't have a self-flush
mechanism(for e.g., sheepdog), so we need to call bdrv_flush() to make
sure the image is really writen to the storage instead of hanging around
writeback cache forever.
Signed-off-by: Liu Yuan <tailai.ly at taobao.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index 4b96654..421cd1b 100644
--- a/block.c
+++ b/block.c
@@ -812,6 +812,7 @@ unlink_and_fail:
void bdrv_close(BlockDriverState *bs)
{
+ bdrv_flush(bs);
if (bs->drv) {
if (bs->job) {
block_job_cancel_sync(bs->job);
diff --git a/qemu-img.c b/qemu-img.c
index 6a61ca8..0ae543c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -66,8 +66,8 @@ static void help(void)
" 'filename' is a disk image filename\n"
" 'fmt' is the disk image format. It is guessed automatically in most cases\n"
" 'cache' is the cache mode used to write the output disk image, the valid\n"
- " options are: 'none', 'writeback' (default), 'writethrough', 'directsync'\n"
- " and 'unsafe'\n"
+ " options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
+ " 'directsync' and 'unsafe' (default for convert)\n"
" 'size' is the disk image size in bytes. Optional suffixes\n"
" 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
" and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
commit 90449c388711c3defdc76da490926d1eca177b06
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Thu Apr 19 18:33:05 2012 +0000
sparc: fix qtest
Initialize TCG only when enabled.
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index 24f90f1..7ac6bdb 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -119,7 +119,9 @@ CPUSPARCState *cpu_sparc_init(const char *cpu_model)
cpu = SPARC_CPU(object_new(TYPE_SPARC_CPU));
env = &cpu->env;
- gen_intermediate_code_init(env);
+ if (tcg_enabled()) {
+ gen_intermediate_code_init(env);
+ }
if (cpu_sparc_register(env, cpu_model) < 0) {
object_delete(OBJECT(cpu));
commit e776bffb53973619e93e805fa441bd5f3d999e27
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Thu Apr 19 18:52:35 2012 +0000
qtest: add dummy functions for user emulators
Allow qtest to be used also in files used for user emulators by
introducing dummy functions.
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/qtest.h b/qtest.h
index 1478343..723a4f9 100644
--- a/qtest.h
+++ b/qtest.h
@@ -16,6 +16,7 @@
#include "qemu-common.h"
+#if !defined(CONFIG_USER_ONLY)
extern int qtest_allowed;
extern const char *qtest_chrdev;
extern const char *qtest_log;
@@ -31,5 +32,22 @@ static inline int qtest_available(void)
}
int qtest_init(void);
+#else
+static inline bool qtest_enabled(void)
+{
+ return false;
+}
+
+static inline int qtest_available(void)
+{
+ return 0;
+}
+
+static inline int qtest_init(void)
+{
+ return 0;
+}
+
+#endif
#endif
commit 85215d419b17aeedbfe93ff8d739b27937f72739
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Sun Apr 15 07:36:49 2012 +0000
qtest: add register fuzzing to RTC test
Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index 983a980..f23ac3a 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -240,6 +240,22 @@ static void alarm_time(void)
g_assert(cmos_read(RTC_REG_C) == 0);
}
+/* success if no crash or abort */
+static void fuzz_registers(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < 1000; i++) {
+ uint8_t reg, val;
+
+ reg = (uint8_t)g_test_rand_int_range(0, 16);
+ val = (uint8_t)g_test_rand_int_range(0, 256);
+
+ cmos_write(reg, val);
+ cmos_read(reg);
+ }
+}
+
int main(int argc, char **argv)
{
QTestState *s = NULL;
@@ -253,6 +269,7 @@ int main(int argc, char **argv)
qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
qtest_add_func("/rtc/dec/check-time", dec_check_time);
qtest_add_func("/rtc/alarm-time", alarm_time);
+ qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
ret = g_test_run();
if (s) {
commit 4bdd04165a50899d8700d8009a3e044f88ade45f
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Tue Apr 17 11:28:27 2012 -0500
qemu-ga: fix help output
Reviewed-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qemu-ga.c b/qemu-ga.c
index d6f786e..74a1b02 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -117,12 +117,13 @@ static gboolean register_signal_handlers(void)
static void usage(const char *cmd)
{
printf(
-"Usage: %s -c <channel_opts>\n"
+"Usage: %s [-m <method> -p <path>] [<options>]\n"
"QEMU Guest Agent %s\n"
"\n"
" -m, --method transport method: one of unix-listen, virtio-serial, or\n"
" isa-serial (virtio-serial is the default)\n"
-" -p, --path device/socket path (%s is the default for virtio-serial)\n"
+" -p, --path device/socket path (the default for virtio-serial is:\n"
+" %s)\n"
" -l, --logfile set logfile path, logs to stderr by default\n"
" -f, --pidfile specify pidfile (default is %s)\n"
" -v, --verbose log extra debugging information\n"
@@ -131,7 +132,7 @@ static void usage(const char *cmd)
#ifdef _WIN32
" -s, --service service commands: install, uninstall\n"
#endif
-" -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\""
+" -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\"\n"
" to list available RPCs)\n"
" -h, --help display this help and exit\n"
"\n"
commit d35d4cb5175f75e503ee9da0b67ffbe22e8d63ab
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Fri Apr 13 21:07:36 2012 -0500
qemu-ga: generate missing stubs for fsfreeze
When linux-specific commands (including guest-fsfreeze-*) were consolidated
under defined(__linux__), we forgot to account for the case where
defined(__linux__) && !defined(FIFREEZE). As a result stubs are no longer
being generated on linux hosts that don't have FIFREEZE support. Fix
this.
Tested-by: Andreas Färber <afaerber at suse.de>
Reviewed-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index faf970d..087c3af 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -881,46 +881,50 @@ error:
#else /* defined(__linux__) */
-GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+void qmp_guest_suspend_disk(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
-
- return 0;
}
-int64_t qmp_guest_fsfreeze_freeze(Error **err)
+void qmp_guest_suspend_ram(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
-
- return 0;
}
-int64_t qmp_guest_fsfreeze_thaw(Error **err)
+void qmp_guest_suspend_hybrid(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
-
- return 0;
}
-void qmp_guest_suspend_disk(Error **err)
+GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
{
- error_set(err, QERR_UNSUPPORTED);
+ error_set(errp, QERR_UNSUPPORTED);
+ return NULL;
}
-void qmp_guest_suspend_ram(Error **err)
+#endif
+
+#if !defined(CONFIG_FSFREEZE)
+
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
}
-void qmp_guest_suspend_hybrid(Error **err)
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
}
-GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
{
- error_set(errp, QERR_UNSUPPORTED);
- return NULL;
+ error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
}
#endif
commit e25ceb76e5b90ec4197cbe1cb859200bf6ee1284
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 11:59:11 2012 +0200
nbd: obey FUA on reads
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/nbd.c b/nbd.c
index d4dafc6..153709f 100644
--- a/nbd.c
+++ b/nbd.c
@@ -842,6 +842,15 @@ static void nbd_trip(void *opaque)
case NBD_CMD_READ:
TRACE("Request type is READ");
+ if (request.type & NBD_CMD_FLAG_FUA) {
+ ret = bdrv_co_flush(exp->bs);
+ if (ret < 0) {
+ LOG("flush failed");
+ reply.error = -ret;
+ goto error_reply;
+ }
+ }
+
ret = bdrv_read(exp->bs, (request.from + exp->dev_offset) / 512,
req->data, request.len / 512);
if (ret < 0) {
commit 38ceff0412621a35fa618fb46cd7f0f6ff037c13
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 12 16:17:27 2012 +0100
nbd: do not include block_int.h
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/nbd.c b/nbd.c
index 4c6d7f1..d4dafc6 100644
--- a/nbd.c
+++ b/nbd.c
@@ -18,7 +18,6 @@
#include "nbd.h"
#include "block.h"
-#include "block_int.h"
#include "qemu-coroutine.h"
@@ -703,7 +702,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset,
exp->bs = bs;
exp->dev_offset = dev_offset;
exp->nbdflags = nbdflags;
- exp->size = size == -1 ? exp->bs->total_sectors * 512 : size;
+ exp->size = size == -1 ? bdrv_getlength(bs) : size;
return exp;
}
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 6c3f9b5..5a0300e 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -17,7 +17,7 @@
*/
#include "qemu-common.h"
-#include "block_int.h"
+#include "block.h"
#include "nbd.h"
#include <stdarg.h>
@@ -487,7 +487,7 @@ int main(int argc, char **argv)
err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
}
- fd_size = bs->total_sectors * 512;
+ fd_size = bdrv_getlength(bs);
if (partition != -1) {
ret = find_partition(bs, partition, &dev_offset, &fd_size);
commit 9eb0bfca960b8cf24fb42e017c3a6479e5676f75
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 12 14:00:56 2012 +0200
aio: simplify qemu_aio_wait
The do...while loop can never loop, because select will just not return
0 when invoked with infinite timeout.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/aio.c b/aio.c
index 5fcc0c6..0a9eb10 100644
--- a/aio.c
+++ b/aio.c
@@ -104,7 +104,11 @@ void qemu_aio_flush(void)
bool qemu_aio_wait(void)
{
+ AioHandler *node;
+ fd_set rdfds, wrfds;
+ int max_fd = -1;
int ret;
+ bool busy;
/*
* If there are callbacks left that have been queued, we need to call then.
@@ -115,85 +119,76 @@ bool qemu_aio_wait(void)
return true;
}
- do {
- AioHandler *node;
- fd_set rdfds, wrfds;
- bool busy;
- int max_fd = -1;
+ walking_handlers = 1;
- walking_handlers = 1;
+ FD_ZERO(&rdfds);
+ FD_ZERO(&wrfds);
- FD_ZERO(&rdfds);
- FD_ZERO(&wrfds);
-
- /* fill fd sets */
- busy = false;
- QLIST_FOREACH(node, &aio_handlers, node) {
- /* If there aren't pending AIO operations, don't invoke callbacks.
- * Otherwise, if there are no AIO requests, qemu_aio_wait() would
- * wait indefinitely.
- */
- if (node->io_flush) {
- if (node->io_flush(node->opaque) == 0) {
- continue;
- }
- busy = true;
- }
- if (!node->deleted && node->io_read) {
- FD_SET(node->fd, &rdfds);
- max_fd = MAX(max_fd, node->fd + 1);
- }
- if (!node->deleted && node->io_write) {
- FD_SET(node->fd, &wrfds);
- max_fd = MAX(max_fd, node->fd + 1);
+ /* fill fd sets */
+ busy = false;
+ QLIST_FOREACH(node, &aio_handlers, node) {
+ /* If there aren't pending AIO operations, don't invoke callbacks.
+ * Otherwise, if there are no AIO requests, qemu_aio_wait() would
+ * wait indefinitely.
+ */
+ if (node->io_flush) {
+ if (node->io_flush(node->opaque) == 0) {
+ continue;
}
+ busy = true;
+ }
+ if (!node->deleted && node->io_read) {
+ FD_SET(node->fd, &rdfds);
+ max_fd = MAX(max_fd, node->fd + 1);
}
+ if (!node->deleted && node->io_write) {
+ FD_SET(node->fd, &wrfds);
+ max_fd = MAX(max_fd, node->fd + 1);
+ }
+ }
- walking_handlers = 0;
+ walking_handlers = 0;
- /* No AIO operations? Get us out of here */
- if (!busy) {
- return false;
- }
+ /* No AIO operations? Get us out of here */
+ if (!busy) {
+ return false;
+ }
- /* wait until next event */
- ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
- if (ret == -1 && errno == EINTR)
- continue;
-
- /* if we have any readable fds, dispatch event */
- if (ret > 0) {
- walking_handlers = 1;
-
- /* we have to walk very carefully in case
- * qemu_aio_set_fd_handler is called while we're walking */
- node = QLIST_FIRST(&aio_handlers);
- while (node) {
- AioHandler *tmp;
-
- if (!node->deleted &&
- FD_ISSET(node->fd, &rdfds) &&
- node->io_read) {
- node->io_read(node->opaque);
- }
- if (!node->deleted &&
- FD_ISSET(node->fd, &wrfds) &&
- node->io_write) {
- node->io_write(node->opaque);
- }
-
- tmp = node;
- node = QLIST_NEXT(node, node);
-
- if (tmp->deleted) {
- QLIST_REMOVE(tmp, node);
- g_free(tmp);
- }
+ /* wait until next event */
+ ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
+
+ /* if we have any readable fds, dispatch event */
+ if (ret > 0) {
+ walking_handlers = 1;
+
+ /* we have to walk very carefully in case
+ * qemu_aio_set_fd_handler is called while we're walking */
+ node = QLIST_FIRST(&aio_handlers);
+ while (node) {
+ AioHandler *tmp;
+
+ if (!node->deleted &&
+ FD_ISSET(node->fd, &rdfds) &&
+ node->io_read) {
+ node->io_read(node->opaque);
+ }
+ if (!node->deleted &&
+ FD_ISSET(node->fd, &wrfds) &&
+ node->io_write) {
+ node->io_write(node->opaque);
}
- walking_handlers = 0;
+ tmp = node;
+ node = QLIST_NEXT(node, node);
+
+ if (tmp->deleted) {
+ QLIST_REMOVE(tmp, node);
+ g_free(tmp);
+ }
}
- } while (ret == 0);
+
+ walking_handlers = 0;
+ }
return true;
}
commit bcdc18578d5b41180db2e17baa7563c5f05b39ee
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 12 14:00:55 2012 +0200
aio: return "AIO in progress" state from qemu_aio_wait
The definition of when qemu_aio_flush should loop is much simpler
than it looks. It just has to call qemu_aio_wait until it makes
no progress and all flush callbacks return false. qemu_aio_wait
is the logical place to tell the caller about this.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/aio.c b/aio.c
index f19b3c6..5fcc0c6 100644
--- a/aio.c
+++ b/aio.c
@@ -99,41 +99,26 @@ int qemu_aio_set_fd_handler(int fd,
void qemu_aio_flush(void)
{
- AioHandler *node;
- int ret;
-
- do {
- ret = 0;
-
- /*
- * If there are pending emulated aio start them now so flush
- * will be able to return 1.
- */
- qemu_aio_wait();
-
- QLIST_FOREACH(node, &aio_handlers, node) {
- if (node->io_flush) {
- ret |= node->io_flush(node->opaque);
- }
- }
- } while (qemu_bh_poll() || ret > 0);
+ while (qemu_aio_wait());
}
-void qemu_aio_wait(void)
+bool qemu_aio_wait(void)
{
int ret;
/*
* If there are callbacks left that have been queued, we need to call then.
- * Return afterwards to avoid waiting needlessly in select().
+ * Do not call select in this case, because it is possible that the caller
+ * does not need a complete flush (as is the case for qemu_aio_wait loops).
*/
if (qemu_bh_poll()) {
- return;
+ return true;
}
do {
AioHandler *node;
fd_set rdfds, wrfds;
+ bool busy;
int max_fd = -1;
walking_handlers = 1;
@@ -142,14 +127,18 @@ void qemu_aio_wait(void)
FD_ZERO(&wrfds);
/* fill fd sets */
+ busy = false;
QLIST_FOREACH(node, &aio_handlers, node) {
/* If there aren't pending AIO operations, don't invoke callbacks.
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely.
*/
- if (node->io_flush && node->io_flush(node->opaque) == 0)
- continue;
-
+ if (node->io_flush) {
+ if (node->io_flush(node->opaque) == 0) {
+ continue;
+ }
+ busy = true;
+ }
if (!node->deleted && node->io_read) {
FD_SET(node->fd, &rdfds);
max_fd = MAX(max_fd, node->fd + 1);
@@ -163,8 +152,9 @@ void qemu_aio_wait(void)
walking_handlers = 0;
/* No AIO operations? Get us out of here */
- if (max_fd == -1)
- break;
+ if (!busy) {
+ return false;
+ }
/* wait until next event */
ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
@@ -204,4 +194,6 @@ void qemu_aio_wait(void)
walking_handlers = 0;
}
} while (ret == 0);
+
+ return true;
}
diff --git a/qemu-aio.h b/qemu-aio.h
index 0fc8409..bfdd35f 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -48,8 +48,10 @@ void qemu_aio_flush(void);
/* Wait for a single AIO completion to occur. This function will wait
* until a single AIO event has completed and it will ensure something
* has moved before returning. This can issue new pending aio as
- * result of executing I/O completion or bh callbacks. */
-void qemu_aio_wait(void);
+ * result of executing I/O completion or bh callbacks.
+ *
+ * Return whether there is still any pending AIO operation. */
+bool qemu_aio_wait(void);
/* Register a file descriptor and associated callbacks. Behaves very similarly
* to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will
commit bafbd6a1c69fef73500309dc31c86984c6d22b43
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 12 14:00:54 2012 +0200
aio: remove process_queue callback and qemu_aio_process_queue
Both unused after the previous patch.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/aio.c b/aio.c
index eb3bf42..f19b3c6 100644
--- a/aio.c
+++ b/aio.c
@@ -35,7 +35,6 @@ struct AioHandler
IOHandler *io_read;
IOHandler *io_write;
AioFlushHandler *io_flush;
- AioProcessQueue *io_process_queue;
int deleted;
void *opaque;
QLIST_ENTRY(AioHandler) node;
@@ -58,7 +57,6 @@ int qemu_aio_set_fd_handler(int fd,
IOHandler *io_read,
IOHandler *io_write,
AioFlushHandler *io_flush,
- AioProcessQueue *io_process_queue,
void *opaque)
{
AioHandler *node;
@@ -91,7 +89,6 @@ int qemu_aio_set_fd_handler(int fd,
node->io_read = io_read;
node->io_write = io_write;
node->io_flush = io_flush;
- node->io_process_queue = io_process_queue;
node->opaque = opaque;
}
@@ -122,39 +119,17 @@ void qemu_aio_flush(void)
} while (qemu_bh_poll() || ret > 0);
}
-int qemu_aio_process_queue(void)
-{
- AioHandler *node;
- int ret = 0;
-
- walking_handlers = 1;
-
- QLIST_FOREACH(node, &aio_handlers, node) {
- if (node->io_process_queue) {
- if (node->io_process_queue(node->opaque)) {
- ret = 1;
- }
- }
- }
-
- walking_handlers = 0;
-
- return ret;
-}
-
void qemu_aio_wait(void)
{
int ret;
- if (qemu_bh_poll())
- return;
-
/*
* If there are callbacks left that have been queued, we need to call then.
* Return afterwards to avoid waiting needlessly in select().
*/
- if (qemu_aio_process_queue())
+ if (qemu_bh_poll()) {
return;
+ }
do {
AioHandler *node;
diff --git a/block/curl.c b/block/curl.c
index a909eca..bf3680b 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -89,19 +89,17 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
switch (action) {
case CURL_POLL_IN:
- qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush,
- NULL, s);
+ qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush, s);
break;
case CURL_POLL_OUT:
- qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush,
- NULL, s);
+ qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush, s);
break;
case CURL_POLL_INOUT:
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
- curl_aio_flush, NULL, s);
+ curl_aio_flush, s);
break;
case CURL_POLL_REMOVE:
- qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL);
break;
}
diff --git a/block/iscsi.c b/block/iscsi.c
index bd3ca11..5222726 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -108,7 +108,7 @@ iscsi_set_events(IscsiLun *iscsilun)
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
(iscsi_which_events(iscsi) & POLLOUT)
? iscsi_process_write : NULL,
- iscsi_process_flush, NULL, iscsilun);
+ iscsi_process_flush, iscsilun);
}
static void
@@ -682,7 +682,7 @@ static void iscsi_close(BlockDriverState *bs)
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
- qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
iscsi_destroy_context(iscsi);
memset(iscsilun, 0, sizeof(IscsiLun));
}
diff --git a/block/nbd.c b/block/nbd.c
index 161b299..524c9cf 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -191,7 +191,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
qemu_co_mutex_lock(&s->send_mutex);
s->send_coroutine = qemu_coroutine_self();
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
- nbd_have_request, NULL, s);
+ nbd_have_request, s);
rc = nbd_send_request(s->sock, request);
if (rc != -1 && iov) {
ret = qemu_co_sendv(s->sock, iov, request->len, offset);
@@ -201,7 +201,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
}
}
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
- nbd_have_request, NULL, s);
+ nbd_have_request, s);
s->send_coroutine = NULL;
qemu_co_mutex_unlock(&s->send_mutex);
return rc;
@@ -274,7 +274,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
* kick the reply mechanism. */
socket_set_nonblock(sock);
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
- nbd_have_request, NULL, s);
+ nbd_have_request, s);
s->sock = sock;
s->size = size;
@@ -294,7 +294,7 @@ static void nbd_teardown_connection(BlockDriverState *bs)
request.len = 0;
nbd_send_request(s->sock, &request);
- qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL);
closesocket(s->sock);
}
diff --git a/block/rbd.c b/block/rbd.c
index 46a8579..6cd8448 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -504,7 +504,7 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
- NULL, qemu_rbd_aio_flush_cb, NULL, s);
+ NULL, qemu_rbd_aio_flush_cb, s);
return 0;
@@ -525,8 +525,7 @@ static void qemu_rbd_close(BlockDriverState *bs)
close(s->fds[0]);
close(s->fds[1]);
- qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
- NULL);
+ qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL, NULL);
rbd_close(s->image);
rados_ioctx_destroy(s->io_ctx);
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 3eaf625..0ed6b19 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -799,8 +799,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
return -1;
}
- qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request,
- NULL, s);
+ qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s);
return fd;
}
@@ -973,7 +972,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
qemu_co_mutex_lock(&s->lock);
s->co_send = qemu_coroutine_self();
qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request,
- aio_flush_request, NULL, s);
+ aio_flush_request, s);
socket_set_cork(s->fd, 1);
/* send a header */
@@ -995,7 +994,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
socket_set_cork(s->fd, 0);
qemu_aio_set_fd_handler(s->fd, co_read_response, NULL,
- aio_flush_request, NULL, s);
+ aio_flush_request, s);
qemu_co_mutex_unlock(&s->lock);
return 0;
@@ -1135,7 +1134,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
g_free(buf);
return 0;
out:
- qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
if (s->fd >= 0) {
closesocket(s->fd);
}
@@ -1349,7 +1348,7 @@ static void sd_close(BlockDriverState *bs)
error_report("%s, %s", sd_strerror(rsp->result), s->name);
}
- qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
closesocket(s->fd);
if (s->cache_enabled) {
closesocket(s->flush_fd);
diff --git a/linux-aio.c b/linux-aio.c
index 15261ec..fa0fbf3 100644
--- a/linux-aio.c
+++ b/linux-aio.c
@@ -214,7 +214,7 @@ void *laio_init(void)
goto out_close_efd;
qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
- qemu_laio_flush_cb, NULL, s);
+ qemu_laio_flush_cb, s);
return s;
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index 1066c60..68361f5 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -663,8 +663,7 @@ int paio_init(void)
fcntl(s->rfd, F_SETFL, O_NONBLOCK);
fcntl(s->wfd, F_SETFL, O_NONBLOCK);
- qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush,
- NULL, s);
+ qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
ret = pthread_attr_init(&attr);
if (ret)
diff --git a/qemu-aio.h b/qemu-aio.h
index 230c2f7..0fc8409 100644
--- a/qemu-aio.h
+++ b/qemu-aio.h
@@ -41,11 +41,6 @@ void qemu_aio_release(void *p);
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
typedef int (AioFlushHandler)(void *opaque);
-/* Runs all currently allowed AIO callbacks of completed requests in the
- * respective AIO backend. Returns 0 if no requests was handled, non-zero
- * if at least one queued request was handled. */
-typedef int (AioProcessQueue)(void *opaque);
-
/* Flush any pending AIO operation. This function will block until all
* outstanding AIO operations have been completed or cancelled. */
void qemu_aio_flush(void);
@@ -56,13 +51,6 @@ void qemu_aio_flush(void);
* result of executing I/O completion or bh callbacks. */
void qemu_aio_wait(void);
-/*
- * Runs all currently allowed AIO callbacks of completed requests. Returns 0
- * if no requests were handled, non-zero if at least one request was
- * processed.
- */
-int qemu_aio_process_queue(void);
-
/* Register a file descriptor and associated callbacks. Behaves very similarly
* to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will
* be invoked when using either qemu_aio_wait() or qemu_aio_flush().
@@ -74,7 +62,6 @@ int qemu_aio_set_fd_handler(int fd,
IOHandler *io_read,
IOHandler *io_write,
AioFlushHandler *io_flush,
- AioProcessQueue *io_process_queue,
void *opaque);
#endif
commit 7fe7b68b32ba609faeeee03556aac0eb1b187c91
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 5 09:10:35 2012 +0100
nbd: do not block in nbd_wr_sync if no data at all is available
Right now, nbd_wr_sync will hang if no data at all is available on the
socket and the other side is not going to provide any. Relax this by
making it loop only for writes or partial reads. This fixes a race
where one thread is executing qemu_aio_wait() and another is executing
main_loop_wait(). Then, the select() call in main_loop_wait() can return
stale data and call the "readable" callback with no data in the socket.
Reported-by: Laurent Vivier <laurent at vivier.eu>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/block/nbd.c b/block/nbd.c
index 1b0e384..e0af5b4 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -151,10 +151,18 @@ static void nbd_reply_ready(void *opaque)
{
BDRVNBDState *s = opaque;
uint64_t i;
+ int ret;
if (s->reply.handle == 0) {
- /* No reply already in flight. Fetch a header. */
- if (nbd_receive_reply(s->sock, &s->reply) < 0) {
+ /* No reply already in flight. Fetch a header. It is possible
+ * that another thread has done the same thing in parallel, so
+ * the socket is not readable anymore.
+ */
+ ret = nbd_receive_reply(s->sock, &s->reply);
+ if (ret == -EAGAIN) {
+ return;
+ }
+ if (ret < 0) {
s->reply.handle = 0;
goto fail;
}
diff --git a/nbd.c b/nbd.c
index b31b3b2..4c6d7f1 100644
--- a/nbd.c
+++ b/nbd.c
@@ -78,9 +78,6 @@
/* That's all folks */
-#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
-#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
-
ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
{
size_t offset = 0;
@@ -107,7 +104,7 @@ ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
err = socket_error();
/* recoverable error */
- if (err == EINTR || err == EAGAIN) {
+ if (err == EINTR || (offset > 0 && err == EAGAIN)) {
continue;
}
@@ -126,6 +123,26 @@ ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
return offset;
}
+static ssize_t read_sync(int fd, void *buffer, size_t size)
+{
+ /* Sockets are kept in blocking mode in the negotiation phase. After
+ * that, a non-readable socket simply means that another thread stole
+ * our request/reply. Synchronization is done with recv_coroutine, so
+ * that this is coroutine-safe.
+ */
+ return nbd_wr_sync(fd, buffer, size, true);
+}
+
+static ssize_t write_sync(int fd, void *buffer, size_t size)
+{
+ int ret;
+ do {
+ /* For writes, we do expect the socket to be writable. */
+ ret = nbd_wr_sync(fd, buffer, size, false);
+ } while (ret == -EAGAIN);
+ return ret;
+}
+
static void combine_addr(char *buf, size_t len, const char* address,
uint16_t port)
{
@@ -203,6 +220,7 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
[28 .. 151] reserved (0)
*/
+ socket_set_block(csock);
rc = -EINVAL;
TRACE("Beginning negotiation.");
@@ -222,6 +240,7 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
TRACE("Negotiation succeeded.");
rc = 0;
fail:
+ socket_set_nonblock(csock);
return rc;
}
@@ -235,6 +254,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
TRACE("Receiving negotiation.");
+ socket_set_block(csock);
rc = -EINVAL;
if (read_sync(csock, buf, 8) != 8) {
@@ -349,6 +369,7 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
rc = 0;
fail:
+ socket_set_nonblock(csock);
return rc;
}
@@ -742,8 +763,11 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *reque
ssize_t rc;
client->recv_coroutine = qemu_coroutine_self();
- if (nbd_receive_request(csock, request) < 0) {
- rc = -EIO;
+ rc = nbd_receive_request(csock, request);
+ if (rc < 0) {
+ if (rc != -EAGAIN) {
+ rc = -EIO;
+ }
goto out;
}
@@ -791,6 +815,9 @@ static void nbd_trip(void *opaque)
TRACE("Reading request.");
ret = nbd_co_receive_request(req, &request);
+ if (ret == -EAGAIN) {
+ goto done;
+ }
if (ret == -EIO) {
goto out;
}
@@ -901,6 +928,7 @@ static void nbd_trip(void *opaque)
TRACE("Request/Reply complete");
+done:
nbd_request_put(req);
return;
commit 185b43386ad999c80bdc58e41b87f05e5b3e8463
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 5 08:56:10 2012 +0100
nbd: consistently return negative errno values
In the next patch we need to look at the return code of nbd_wr_sync.
To avoid percolating the socket_error() ugliness all around, let's
handle errors by returning negative errno values.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/block/nbd.c b/block/nbd.c
index 25e5268..1b0e384 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -200,8 +200,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
if (rc >= 0 && iov) {
ret = qemu_co_sendv(s->sock, iov, request->len, offset);
if (ret != request->len) {
- errno = -EIO;
- rc = -1;
+ return -EIO;
}
}
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
@@ -271,7 +270,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
if (ret < 0) {
logout("Failed to negotiate with the NBD server\n");
closesocket(sock);
- return -errno;
+ return ret;
}
/* Now that we're connected, set the socket to be non-blocking and
@@ -340,7 +339,7 @@ static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
nbd_coroutine_start(s, &request);
ret = nbd_co_send_request(s, &request, NULL, 0);
if (ret < 0) {
- reply.error = errno;
+ reply.error = -ret;
} else {
nbd_co_receive_reply(s, &request, &reply, qiov->iov, offset);
}
@@ -369,7 +368,7 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
nbd_coroutine_start(s, &request);
ret = nbd_co_send_request(s, &request, qiov->iov, offset);
if (ret < 0) {
- reply.error = errno;
+ reply.error = -ret;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
}
@@ -437,7 +436,7 @@ static int nbd_co_flush(BlockDriverState *bs)
nbd_coroutine_start(s, &request);
ret = nbd_co_send_request(s, &request, NULL, 0);
if (ret < 0) {
- reply.error = errno;
+ reply.error = -ret;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
}
@@ -463,7 +462,7 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
nbd_coroutine_start(s, &request);
ret = nbd_co_send_request(s, &request, NULL, 0);
if (ret < 0) {
- reply.error = errno;
+ reply.error = -ret;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
}
diff --git a/nbd.c b/nbd.c
index 9832aa0..b31b3b2 100644
--- a/nbd.c
+++ b/nbd.c
@@ -81,9 +81,10 @@
#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
-size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
+ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
{
size_t offset = 0;
+ int err;
if (qemu_in_coroutine()) {
if (do_read) {
@@ -103,15 +104,15 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
}
if (len < 0) {
- errno = socket_error();
+ err = socket_error();
/* recoverable error */
- if (errno == EINTR || errno == EAGAIN) {
+ if (err == EINTR || err == EAGAIN) {
continue;
}
/* unrecoverable error */
- return 0;
+ return -err;
}
/* eof */
@@ -192,6 +193,7 @@ int unix_socket_outgoing(const char *path)
static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
{
char buf[8 + 8 + 8 + 128];
+ int rc;
/* Negotiate
[ 0 .. 7] passwd ("NBDMAGIC")
@@ -201,6 +203,8 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
[28 .. 151] reserved (0)
*/
+ rc = -EINVAL;
+
TRACE("Beginning negotiation.");
memcpy(buf, "NBDMAGIC", 8);
cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
@@ -212,13 +216,13 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
LOG("write failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
TRACE("Negotiation succeeded.");
-
- return 0;
+ rc = 0;
+fail:
+ return rc;
}
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
@@ -227,20 +231,21 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
char buf[256];
uint64_t magic, s;
uint16_t tmp;
+ int rc;
TRACE("Receiving negotiation.");
+ rc = -EINVAL;
+
if (read_sync(csock, buf, 8) != 8) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
buf[8] = '\0';
if (strlen(buf) == 0) {
LOG("server connection closed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
TRACE("Magic is %c%c%c%c%c%c%c%c",
@@ -255,14 +260,12 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
LOG("Invalid magic received");
- errno = EINVAL;
- return -1;
+ goto fail;
}
if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
magic = be64_to_cpu(magic);
TRACE("Magic is 0x%" PRIx64, magic);
@@ -275,61 +278,52 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
TRACE("Checking magic (opts_magic)");
if (magic != 0x49484156454F5054LL) {
LOG("Bad magic received");
- errno = EINVAL;
- return -1;
+ goto fail;
}
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
LOG("flags read failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
*flags = be16_to_cpu(tmp) << 16;
/* reserved for future use */
if (write_sync(csock, &reserved, sizeof(reserved)) !=
sizeof(reserved)) {
LOG("write failed (reserved)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
/* write the export name */
magic = cpu_to_be64(magic);
if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("write failed (magic)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
LOG("write failed (opt)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
namesize = cpu_to_be32(strlen(name));
if (write_sync(csock, &namesize, sizeof(namesize)) !=
sizeof(namesize)) {
LOG("write failed (namesize)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
LOG("write failed (name)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
} else {
TRACE("Checking magic (cli_magic)");
if (magic != 0x00420281861253LL) {
LOG("Bad magic received");
- errno = EINVAL;
- return -1;
+ goto fail;
}
}
if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
*size = be64_to_cpu(s);
*blocksize = 1024;
@@ -338,24 +332,24 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
if (!name) {
if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
LOG("read failed (flags)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
*flags = be32_to_cpup(flags);
} else {
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
LOG("read failed (tmp)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
*flags |= be32_to_cpu(tmp);
}
if (read_sync(csock, &buf, 124) != 124) {
LOG("read failed (buf)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
- return 0;
+ rc = 0;
+
+fail:
+ return rc;
}
#ifdef __linux__
@@ -366,8 +360,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
if (ioctl(fd, NBD_SET_SOCK, csock) < 0) {
int serrno = errno;
LOG("Failed to set NBD socket");
- errno = serrno;
- return -1;
+ return -serrno;
}
TRACE("Setting block size to %lu", (unsigned long)blocksize);
@@ -375,8 +368,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) < 0) {
int serrno = errno;
LOG("Failed setting NBD block size");
- errno = serrno;
- return -1;
+ return -serrno;
}
TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
@@ -384,8 +376,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) < 0) {
int serrno = errno;
LOG("Failed setting size (in blocks)");
- errno = serrno;
- return -1;
+ return -serrno;
}
if (flags & NBD_FLAG_READ_ONLY) {
@@ -395,8 +386,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
int serrno = errno;
LOG("Failed setting read-only attribute");
- errno = serrno;
- return -1;
+ return -serrno;
}
}
@@ -404,8 +394,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
&& errno != ENOTTY) {
int serrno = errno;
LOG("Failed setting flags");
- errno = serrno;
- return -1;
+ return -serrno;
}
TRACE("Negotiation ended");
@@ -452,26 +441,24 @@ int nbd_client(int fd)
#else
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
{
- errno = ENOTSUP;
- return -1;
+ return -ENOTSUP;
}
int nbd_disconnect(int fd)
{
- errno = ENOTSUP;
- return -1;
+ return -ENOTSUP;
}
int nbd_client(int fd)
{
- errno = ENOTSUP;
- return -1;
+ return -ENOTSUP;
}
#endif
ssize_t nbd_send_request(int csock, struct nbd_request *request)
{
uint8_t buf[4 + 4 + 8 + 8 + 4];
+ ssize_t ret;
cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
cpu_to_be32w((uint32_t*)(buf + 4), request->type);
@@ -483,10 +470,14 @@ ssize_t nbd_send_request(int csock, struct nbd_request *request)
"{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
request->from, request->len, request->handle, request->type);
- if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ ret = write_sync(csock, buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (ret != sizeof(buf)) {
LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
return 0;
}
@@ -495,11 +486,16 @@ static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
{
uint8_t buf[4 + 4 + 8 + 8 + 4];
uint32_t magic;
+ ssize_t ret;
- if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ ret = read_sync(csock, buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (ret != sizeof(buf)) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
/* Request
@@ -522,8 +518,7 @@ static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
if (magic != NBD_REQUEST_MAGIC) {
LOG("invalid magic (got 0x%x)", magic);
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
return 0;
}
@@ -532,11 +527,16 @@ ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
{
uint8_t buf[NBD_REPLY_SIZE];
uint32_t magic;
+ ssize_t ret;
+
+ ret = read_sync(csock, buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
- if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ if (ret != sizeof(buf)) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
/* Reply
@@ -555,8 +555,7 @@ ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
if (magic != NBD_REPLY_MAGIC) {
LOG("invalid magic (got 0x%x)", magic);
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
return 0;
}
@@ -564,6 +563,7 @@ ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
{
uint8_t buf[4 + 4 + 8];
+ ssize_t ret;
/* Reply
[ 0 .. 3] magic (NBD_REPLY_MAGIC)
@@ -576,10 +576,14 @@ static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
TRACE("Sending response to client");
- if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ ret = write_sync(csock, buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (ret != sizeof(buf)) {
LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
return 0;
}
@@ -713,22 +717,15 @@ static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
if (!len) {
rc = nbd_send_reply(csock, reply);
- if (rc < 0) {
- rc = -errno;
- }
} else {
socket_set_cork(csock, 1);
rc = nbd_send_reply(csock, reply);
if (rc >= 0) {
ret = qemu_co_send(csock, req->data, len);
if (ret != len) {
- errno = EIO;
- rc = -1;
+ rc = -EIO;
}
}
- if (rc < 0) {
- rc = -errno;
- }
socket_set_cork(csock, 0);
}
diff --git a/nbd.h b/nbd.h
index 217a82d..40d58d3 100644
--- a/nbd.h
+++ b/nbd.h
@@ -59,7 +59,7 @@ enum {
#define NBD_BUFFER_SIZE (1024*1024)
-size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
+ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
int tcp_socket_outgoing(const char *address, uint16_t port);
int tcp_socket_incoming(const char *address, uint16_t port);
int tcp_socket_outgoing_spec(const char *address_and_port);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 19cfb04..6c3f9b5 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -126,8 +126,7 @@ static int find_partition(BlockDriverState *bs, int partition,
}
if (data[510] != 0x55 || data[511] != 0xaa) {
- errno = -EINVAL;
- return -1;
+ return -EINVAL;
}
for (i = 0; i < 4; i++) {
@@ -165,8 +164,7 @@ static int find_partition(BlockDriverState *bs, int partition,
}
}
- errno = -ENOENT;
- return -1;
+ return -ENOENT;
}
static void termsig_handler(int signum)
@@ -491,9 +489,12 @@ int main(int argc, char **argv)
fd_size = bs->total_sectors * 512;
- if (partition != -1 &&
- find_partition(bs, partition, &dev_offset, &fd_size)) {
- err(EXIT_FAILURE, "Could not find partition %d", partition);
+ if (partition != -1) {
+ ret = find_partition(bs, partition, &dev_offset, &fd_size);
+ if (ret < 0) {
+ errno = -ret;
+ err(EXIT_FAILURE, "Could not find partition %d", partition);
+ }
}
exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags);
commit fc19f8a02e45c4d8ad24dd7eb374330b03dfc28e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Mar 7 11:05:34 2012 +0100
nbd: consistently check for <0 or >=0
This prepares for the following patch, which changes -1 return values
to negative errno.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/block/nbd.c b/block/nbd.c
index 9972cdb..25e5268 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -197,7 +197,7 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
nbd_have_request, NULL, s);
rc = nbd_send_request(s->sock, request);
- if (rc != -1 && iov) {
+ if (rc >= 0 && iov) {
ret = qemu_co_sendv(s->sock, iov, request->len, offset);
if (ret != request->len) {
errno = -EIO;
@@ -260,7 +260,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
}
/* Failed to establish connection */
- if (sock == -1) {
+ if (sock < 0) {
logout("Failed to establish connection to NBD server\n");
return -errno;
}
@@ -268,7 +268,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
/* NBD handshake */
ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size,
&blocksize);
- if (ret == -1) {
+ if (ret < 0) {
logout("Failed to negotiate with the NBD server\n");
closesocket(sock);
return -errno;
@@ -331,13 +331,15 @@ static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
request.type = NBD_CMD_READ;
request.from = sector_num * 512;
request.len = nb_sectors * 512;
nbd_coroutine_start(s, &request);
- if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
+ ret = nbd_co_send_request(s, &request, NULL, 0);
+ if (ret < 0) {
reply.error = errno;
} else {
nbd_co_receive_reply(s, &request, &reply, qiov->iov, offset);
@@ -354,6 +356,7 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
request.type = NBD_CMD_WRITE;
if (!bdrv_enable_write_cache(bs) && (s->nbdflags & NBD_FLAG_SEND_FUA)) {
@@ -364,7 +367,8 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
request.len = nb_sectors * 512;
nbd_coroutine_start(s, &request);
- if (nbd_co_send_request(s, &request, qiov->iov, offset) == -1) {
+ ret = nbd_co_send_request(s, &request, qiov->iov, offset);
+ if (ret < 0) {
reply.error = errno;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
@@ -416,6 +420,7 @@ static int nbd_co_flush(BlockDriverState *bs)
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
if (!(s->nbdflags & NBD_FLAG_SEND_FLUSH)) {
return 0;
@@ -430,7 +435,8 @@ static int nbd_co_flush(BlockDriverState *bs)
request.len = 0;
nbd_coroutine_start(s, &request);
- if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
+ ret = nbd_co_send_request(s, &request, NULL, 0);
+ if (ret < 0) {
reply.error = errno;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
@@ -445,6 +451,7 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
if (!(s->nbdflags & NBD_FLAG_SEND_TRIM)) {
return 0;
@@ -454,7 +461,8 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
request.len = nb_sectors * 512;
nbd_coroutine_start(s, &request);
- if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
+ ret = nbd_co_send_request(s, &request, NULL, 0);
+ if (ret < 0) {
reply.error = errno;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
diff --git a/nbd.c b/nbd.c
index 4a5849c..9832aa0 100644
--- a/nbd.c
+++ b/nbd.c
@@ -102,12 +102,16 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
len = send(fd, buffer + offset, size - offset, 0);
}
- if (len == -1)
+ if (len < 0) {
errno = socket_error();
- /* recoverable error */
- if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
- continue;
+ /* recoverable error */
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+
+ /* unrecoverable error */
+ return 0;
}
/* eof */
@@ -115,11 +119,6 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
break;
}
- /* unrecoverable error */
- if (len == -1) {
- return 0;
- }
-
offset += len;
}
@@ -364,7 +363,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
{
TRACE("Setting NBD socket");
- if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
+ if (ioctl(fd, NBD_SET_SOCK, csock) < 0) {
int serrno = errno;
LOG("Failed to set NBD socket");
errno = serrno;
@@ -373,7 +372,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
TRACE("Setting block size to %lu", (unsigned long)blocksize);
- if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
+ if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) < 0) {
int serrno = errno;
LOG("Failed setting NBD block size");
errno = serrno;
@@ -382,7 +381,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
- if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
+ if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) < 0) {
int serrno = errno;
LOG("Failed setting size (in blocks)");
errno = serrno;
@@ -430,7 +429,7 @@ int nbd_client(int fd)
TRACE("Doing NBD loop");
ret = ioctl(fd, NBD_DO_IT);
- if (ret == -1 && errno == EPIPE) {
+ if (ret < 0 && errno == EPIPE) {
/* NBD_DO_IT normally returns EPIPE when someone has disconnected
* the socket via NBD_DISCONNECT. We do not want to return 1 in
* that case.
@@ -714,20 +713,20 @@ static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
if (!len) {
rc = nbd_send_reply(csock, reply);
- if (rc == -1) {
+ if (rc < 0) {
rc = -errno;
}
} else {
socket_set_cork(csock, 1);
rc = nbd_send_reply(csock, reply);
- if (rc != -1) {
+ if (rc >= 0) {
ret = qemu_co_send(csock, req->data, len);
if (ret != len) {
errno = EIO;
rc = -1;
}
}
- if (rc == -1) {
+ if (rc < 0) {
rc = -errno;
}
socket_set_cork(csock, 0);
@@ -746,7 +745,7 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *reque
ssize_t rc;
client->recv_coroutine = qemu_coroutine_self();
- if (nbd_receive_request(csock, request) == -1) {
+ if (nbd_receive_request(csock, request) < 0) {
rc = -EIO;
goto out;
}
@@ -860,8 +859,9 @@ static void nbd_trip(void *opaque)
}
}
- if (nbd_co_send_reply(req, &reply, 0) < 0)
+ if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
+ }
break;
case NBD_CMD_DISC:
TRACE("Request type is DISCONNECT");
@@ -875,9 +875,9 @@ static void nbd_trip(void *opaque)
LOG("flush failed");
reply.error = -ret;
}
-
- if (nbd_co_send_reply(req, &reply, 0) < 0)
+ if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
+ }
break;
case NBD_CMD_TRIM:
TRACE("Request type is TRIM");
@@ -887,16 +887,18 @@ static void nbd_trip(void *opaque)
LOG("discard failed");
reply.error = -ret;
}
- if (nbd_co_send_reply(req, &reply, 0) < 0)
+ if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
+ }
break;
default:
LOG("invalid request type (%u) received", request.type);
invalid_request:
reply.error = -EINVAL;
error_reply:
- if (nbd_co_send_reply(req, &reply, 0) == -1)
+ if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
+ }
break;
}
@@ -939,7 +941,7 @@ NBDClient *nbd_client_new(NBDExport *exp, int csock,
void (*close)(NBDClient *))
{
NBDClient *client;
- if (nbd_send_negotiate(csock, exp->size, exp->nbdflags) == -1) {
+ if (nbd_send_negotiate(csock, exp->size, exp->nbdflags) < 0) {
return NULL;
}
client = g_malloc0(sizeof(NBDClient));
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d4e7041..19cfb04 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -186,7 +186,7 @@ static void *show_parts(void *arg)
* modprobe nbd max_part=63
*/
nbd = open(device, O_RDWR);
- if (nbd != -1) {
+ if (nbd >= 0) {
close(nbd);
}
return NULL;
@@ -203,25 +203,25 @@ static void *nbd_client_thread(void *arg)
pthread_t show_parts_thread;
sock = unix_socket_outgoing(sockpath);
- if (sock == -1) {
+ if (sock < 0) {
goto out;
}
ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
&size, &blocksize);
- if (ret == -1) {
+ if (ret < 0) {
goto out;
}
fd = open(device, O_RDWR);
- if (fd == -1) {
+ if (fd < 0) {
/* Linux-only, we can use %m in printf. */
fprintf(stderr, "Failed to open %s: %m", device);
goto out;
}
ret = nbd_init(fd, sock, nbdflags, size, blocksize);
- if (ret == -1) {
+ if (ret < 0) {
goto out;
}
@@ -268,7 +268,7 @@ static void nbd_accept(void *opaque)
int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
nbd_started = true;
- if (fd != -1 && nbd_client_new(exp, fd, nbd_client_closed)) {
+ if (fd >= 0 && nbd_client_new(exp, fd, nbd_client_closed)) {
nb_fds++;
}
}
@@ -410,9 +410,9 @@ int main(int argc, char **argv)
if (disconnect) {
fd = open(argv[optind], O_RDWR);
- if (fd == -1)
+ if (fd < 0) {
err(EXIT_FAILURE, "Cannot open %s", argv[optind]);
-
+ }
nbd_disconnect(fd);
close(fd);
@@ -427,7 +427,7 @@ int main(int argc, char **argv)
pid_t pid;
int ret;
- if (qemu_pipe(stderr_fd) == -1) {
+ if (qemu_pipe(stderr_fd) < 0) {
err(EXIT_FAILURE, "Error setting up communication pipe");
}
@@ -441,7 +441,7 @@ int main(int argc, char **argv)
/* Temporarily redirect stderr to the parent's pipe... */
dup2(stderr_fd[1], STDERR_FILENO);
- if (ret == -1) {
+ if (ret < 0) {
err(EXIT_FAILURE, "Failed to daemonize");
}
@@ -459,11 +459,11 @@ int main(int argc, char **argv)
while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
errors = true;
ret = qemu_write_full(STDERR_FILENO, buf, ret);
- if (ret == -1) {
+ if (ret < 0) {
exit(EXIT_FAILURE);
}
}
- if (ret == -1) {
+ if (ret < 0) {
err(EXIT_FAILURE, "Cannot read from daemon");
}
@@ -504,7 +504,7 @@ int main(int argc, char **argv)
fd = tcp_socket_incoming(bindto, port);
}
- if (fd == -1) {
+ if (fd < 0) {
return 1;
}
commit 94e7340b5db8bce7866e44e700ffa8fd26585c7e
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Mar 7 11:25:01 2012 +0100
nbd: consistently use ssize_t
GCC (pedantically, but correctly) considers that a negative ssize_t may
become positive when casted to int. This may cause uninitialized variable
warnings when a function returns such a negative ssize_t and is inlined.
Propagate ssize_t return types to avoid this.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/nbd.c b/nbd.c
index 406e555..4a5849c 100644
--- a/nbd.c
+++ b/nbd.c
@@ -470,7 +470,7 @@ int nbd_client(int fd)
}
#endif
-int nbd_send_request(int csock, struct nbd_request *request)
+ssize_t nbd_send_request(int csock, struct nbd_request *request)
{
uint8_t buf[4 + 4 + 8 + 8 + 4];
@@ -492,7 +492,7 @@ int nbd_send_request(int csock, struct nbd_request *request)
return 0;
}
-static int nbd_receive_request(int csock, struct nbd_request *request)
+static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
{
uint8_t buf[4 + 4 + 8 + 8 + 4];
uint32_t magic;
@@ -529,13 +529,11 @@ static int nbd_receive_request(int csock, struct nbd_request *request)
return 0;
}
-int nbd_receive_reply(int csock, struct nbd_reply *reply)
+ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
{
uint8_t buf[NBD_REPLY_SIZE];
uint32_t magic;
- memset(buf, 0xAA, sizeof(buf));
-
if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
LOG("read failed");
errno = EINVAL;
@@ -564,7 +562,7 @@ int nbd_receive_reply(int csock, struct nbd_reply *reply)
return 0;
}
-static int nbd_send_reply(int csock, struct nbd_reply *reply)
+static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
{
uint8_t buf[4 + 4 + 8];
@@ -702,12 +700,12 @@ static int nbd_can_read(void *opaque);
static void nbd_read(void *opaque);
static void nbd_restart_write(void *opaque);
-static int nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
- int len)
+static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
+ int len)
{
NBDClient *client = req->client;
int csock = client->sock;
- int rc, ret;
+ ssize_t rc, ret;
qemu_co_mutex_lock(&client->send_lock);
qemu_set_fd_handler2(csock, nbd_can_read, nbd_read,
@@ -741,11 +739,11 @@ static int nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
return rc;
}
-static int nbd_co_receive_request(NBDRequest *req, struct nbd_request *request)
+static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *request)
{
NBDClient *client = req->client;
int csock = client->sock;
- int rc;
+ ssize_t rc;
client->recv_coroutine = qemu_coroutine_self();
if (nbd_receive_request(csock, request) == -1) {
@@ -792,7 +790,7 @@ static void nbd_trip(void *opaque)
NBDExport *exp = client->exp;
struct nbd_request request;
struct nbd_reply reply;
- int ret;
+ ssize_t ret;
TRACE("Reading request.");
diff --git a/nbd.h b/nbd.h
index a8382f0..217a82d 100644
--- a/nbd.h
+++ b/nbd.h
@@ -70,8 +70,8 @@ int unix_socket_incoming(const char *path);
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
off_t *size, size_t *blocksize);
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
-int nbd_send_request(int csock, struct nbd_request *request);
-int nbd_receive_reply(int csock, struct nbd_reply *reply);
+ssize_t nbd_send_request(int csock, struct nbd_request *request);
+ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply);
int nbd_client(int fd);
int nbd_disconnect(int fd);
commit dd3e8ac413a74a58d6a3ba16a26952f84370fcff
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Mon Mar 12 15:23:13 2012 +0100
nbd: avoid out of bounds access to recv_coroutine array
This can happen with a buggy or malicious server.
Reported-by: Michael Tokarev <mjt at tls.msk.ru>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/block/nbd.c b/block/nbd.c
index 161b299..9972cdb 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -150,7 +150,7 @@ static int nbd_have_request(void *opaque)
static void nbd_reply_ready(void *opaque)
{
BDRVNBDState *s = opaque;
- int i;
+ uint64_t i;
if (s->reply.handle == 0) {
/* No reply already in flight. Fetch a header. */
@@ -164,6 +164,10 @@ static void nbd_reply_ready(void *opaque)
* handler acts as a synchronization point and ensures that only
* one coroutine is called until the reply finishes. */
i = HANDLE_TO_INDEX(s, s->reply.handle);
+ if (i >= MAX_NBD_REQUESTS) {
+ goto fail;
+ }
+
if (s->recv_coroutine[i]) {
qemu_coroutine_enter(s->recv_coroutine[i], NULL);
return;
commit adfe92f6d18c0e0a3694e19abb58eb55fd0c5993
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 12 14:00:53 2012 +0200
posix-aio: merge posix_aio_process_queue and posix_aio_read
posix_aio_read already calls qemu_aio_process_queue, and dually
qemu_aio_process_queue is always followed by a select loop that calls
posix_aio_read.
No races are possible, so there is no need for a separate process_queue
callback.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index d311d13..1066c60 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -468,26 +468,37 @@ static int qemu_paio_error(struct qemu_paiocb *aiocb)
return ret;
}
-static int posix_aio_process_queue(void *opaque)
+static void posix_aio_read(void *opaque)
{
PosixAioState *s = opaque;
struct qemu_paiocb *acb, **pacb;
int ret;
- int result = 0;
+ ssize_t len;
+
+ /* read all bytes from signal pipe */
+ for (;;) {
+ char bytes[16];
+
+ len = read(s->rfd, bytes, sizeof(bytes));
+ if (len == -1 && errno == EINTR)
+ continue; /* try again */
+ if (len == sizeof(bytes))
+ continue; /* more to read */
+ break;
+ }
for(;;) {
pacb = &s->first_aio;
for(;;) {
acb = *pacb;
if (!acb)
- return result;
+ return;
ret = qemu_paio_error(acb);
if (ret == ECANCELED) {
/* remove the request */
*pacb = acb->next;
qemu_aio_release(acb);
- result = 1;
} else if (ret != EINPROGRESS) {
/* end of aio */
if (ret == 0) {
@@ -507,35 +518,12 @@ static int posix_aio_process_queue(void *opaque)
/* call the callback */
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
- result = 1;
break;
} else {
pacb = &acb->next;
}
}
}
-
- return result;
-}
-
-static void posix_aio_read(void *opaque)
-{
- PosixAioState *s = opaque;
- ssize_t len;
-
- /* read all bytes from signal pipe */
- for (;;) {
- char bytes[16];
-
- len = read(s->rfd, bytes, sizeof(bytes));
- if (len == -1 && errno == EINTR)
- continue; /* try again */
- if (len == sizeof(bytes))
- continue; /* more to read */
- break;
- }
-
- posix_aio_process_queue(s);
}
static int posix_aio_flush(void *opaque)
@@ -676,7 +664,7 @@ int paio_init(void)
fcntl(s->wfd, F_SETFL, O_NONBLOCK);
qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush,
- posix_aio_process_queue, s);
+ NULL, s);
ret = pthread_attr_init(&attr);
if (ret)
commit 8a83205d34fbd7b12061f4e85148eb4b587acdcc
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 12 14:00:52 2012 +0200
qemu-tool: map vm_clock to rt_clock
QED uses vm_clock timers so that images are not touched during and after
migration. This however does not apply to qemu-io and qemu-img.
Treat vm_clock as a synonym for rt_clock there, and enable it.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/qemu-tool.c b/qemu-tool.c
index edb84f5..6579b00 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -61,7 +61,7 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
int64_t cpu_get_clock(void)
{
- return 0;
+ return qemu_get_clock_ns(rt_clock);
}
int64_t cpu_get_icount(void)
@@ -87,7 +87,6 @@ int qemu_init_main_loop(void)
{
init_clocks();
init_timer_alarm();
- qemu_clock_enable(vm_clock, false);
return main_loop_init();
}
commit a5a5238ee49cd6a0f598f6f63a4a43dbe18d12b7
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 12 14:00:51 2012 +0200
qemu-io: use main_loop_wait
This will let timers run during aio_read and aio_write commands,
though not during synchronous commands.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/cmd.c b/cmd.c
index 0806e18..7ffbb71 100644
--- a/cmd.c
+++ b/cmd.c
@@ -25,6 +25,7 @@
#include "cmd.h"
#include "qemu-aio.h"
+#include "main-loop.h"
#define _(x) x /* not gettext support yet */
@@ -146,7 +147,7 @@ static void prep_fetchline(void *opaque)
{
int *fetchable = opaque;
- qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+ qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
*fetchable= 1;
}
@@ -193,12 +194,11 @@ void command_loop(void)
if (!prompted) {
printf("%s", get_prompt());
fflush(stdout);
- qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
- NULL, &fetchable);
+ qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
prompted = 1;
}
- qemu_aio_wait();
+ main_loop_wait(false);
if (!fetchable) {
continue;
@@ -221,7 +221,7 @@ void command_loop(void)
prompted = 0;
fetchable = 0;
}
- qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+ qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
}
/* from libxcmd/input.c */
diff --git a/qemu-io.c b/qemu-io.c
index 3095a22..b48364f 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -15,6 +15,7 @@
#include <libgen.h>
#include "qemu-common.h"
+#include "main-loop.h"
#include "block_int.h"
#include "cmd.h"
#include "trace/control.h"
@@ -295,7 +296,7 @@ static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
aio_rw_done, &async_ret);
while (async_ret == NOT_DONE) {
- qemu_aio_wait();
+ main_loop_wait(false);
}
*total = qiov->size;
@@ -309,7 +310,7 @@ static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
aio_rw_done, &async_ret);
while (async_ret == NOT_DONE) {
- qemu_aio_wait();
+ main_loop_wait(false);
}
*total = qiov->size;
@@ -352,7 +353,7 @@ static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
}
while (async_ret.num_done < num_reqs) {
- qemu_aio_wait();
+ main_loop_wait(false);
}
return async_ret.error < 0 ? async_ret.error : 1;
commit 3e46d87d665bd9114f18e8d4a1b6de3641147775
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 15:43:41 2012 +0200
scsi: add SANITIZE command
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index d847396..dbdb99c 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1200,6 +1200,7 @@ static const char *scsi_command_name(uint8_t cmd)
[ UNMAP ] = "UNMAP",
[ READ_TOC ] = "READ_TOC",
[ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
+ [ SANITIZE ] = "SANITIZE",
[ GET_CONFIGURATION ] = "GET_CONFIGURATION",
[ LOG_SELECT ] = "LOG_SELECT",
[ LOG_SENSE ] = "LOG_SENSE",
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 354ed7b..ca24192 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -78,6 +78,7 @@
#define READ_TOC 0x43
#define REPORT_DENSITY_SUPPORT 0x44
#define GET_CONFIGURATION 0x46
+#define SANITIZE 0x48
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
#define LOG_SELECT 0x4c
#define LOG_SENSE 0x4d
commit f644a2904d5287332e4007f30c105a8622fb3db8
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date: Thu Apr 19 20:41:17 2012 +1000
SCSI emulation: should tell the guest that we actually support thin provisioning
Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
[Actually, we should report it only if discard_granularity is nonzero.
Older SBC drafts assigned 0 to thin provisioning and 1 to thick
(resource-provisioned, they call it). Newer drafts assign respectively
1 and 2 - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 85a75c4..a029ab6 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -628,7 +628,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
outbuf[3] = buflen = 8;
outbuf[4] = 0;
outbuf[5] = 0x60; /* write_same 10/16 supported */
- outbuf[6] = 0;
+ outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
outbuf[7] = 0;
break;
}
commit c9e4d8284e1f3205aa3c05dc18932f9ca2c05f53
Author: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Date: Thu Apr 19 20:41:16 2012 +1000
SCSI emulation: Support unmap via WRITE_SAME_10.
This was added in SBC r26 in place of the reserved bits that were
present up to that version.
It is the same as WRITE_SAME_16 as far as QEMU is concerned.
Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index fca31fa..85a75c4 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -627,7 +627,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
{
outbuf[3] = buflen = 8;
outbuf[4] = 0;
- outbuf[5] = 0x40; /* write same with unmap supported */
+ outbuf[5] = 0x60; /* write_same 10/16 supported */
outbuf[6] = 0;
outbuf[7] = 0;
break;
@@ -1558,10 +1558,11 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
goto illegal_lba;
}
break;
+ case WRITE_SAME_10:
case WRITE_SAME_16:
len = r->req.cmd.xfer / s->qdev.blocksize;
- DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
+ DPRINTF("WRITE SAME() (sector %" PRId64 ", count %d)\n",
r->req.cmd.lba, len);
if (r->req.cmd.lba > s->qdev.max_lba) {
commit 6a2de0f2038349716049c9b9a972d6777c85424b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 10:28:15 2012 +0200
scsi: advertise DPOFUA
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 2d9ac2d..fca31fa 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1093,14 +1093,15 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
memset(outbuf, 0, r->req.cmd.xfer);
p = outbuf;
- dev_specific_param = 0x00;
if (s->qdev.type == TYPE_DISK) {
+ dev_specific_param = 0x10; /* DPOFUA */
if (bdrv_is_read_only(s->qdev.conf.bs)) {
dev_specific_param |= 0x80; /* Readonly. */
}
} else {
/* MMC prescribes that CD/DVD drives have no block descriptors,
* and defines no device-specific parameter. */
+ dev_specific_param = 0x00;
dbd = true;
}
commit e590ecbed5da8716b83b348d26edb9e60b4e91c4
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 10:24:18 2012 +0200
scsi: small refactoring of MMC mode-sense
Make DBD a boolean value, and force device-specific parameter to zero.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 30ed3af..2d9ac2d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1080,11 +1080,12 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint64_t nb_sectors;
- int page, dbd, buflen, ret, page_control;
+ bool dbd;
+ int page, buflen, ret, page_control;
uint8_t *p;
uint8_t dev_specific_param;
- dbd = r->req.cmd.buf[1] & 0x8;
+ dbd = (r->req.cmd.buf[1] & 0x8) != 0;
page = r->req.cmd.buf[2] & 0x3f;
page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
@@ -1092,10 +1093,15 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
memset(outbuf, 0, r->req.cmd.xfer);
p = outbuf;
- if (bdrv_is_read_only(s->qdev.conf.bs)) {
- dev_specific_param = 0x80; /* Readonly. */
+ dev_specific_param = 0x00;
+ if (s->qdev.type == TYPE_DISK) {
+ if (bdrv_is_read_only(s->qdev.conf.bs)) {
+ dev_specific_param |= 0x80; /* Readonly. */
+ }
} else {
- dev_specific_param = 0x00;
+ /* MMC prescribes that CD/DVD drives have no block descriptors,
+ * and defines no device-specific parameter. */
+ dbd = true;
}
if (r->req.cmd.buf[0] == MODE_SENSE) {
@@ -1110,9 +1116,8 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
p += 8;
}
- /* MMC prescribes that CD/DVD drives have no block descriptors. */
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
- if (!dbd && s->qdev.type == TYPE_DISK && nb_sectors) {
+ if (!dbd && nb_sectors) {
if (r->req.cmd.buf[0] == MODE_SENSE) {
outbuf[3] = 8; /* Block descriptor length */
} else { /* MODE_SENSE_10 */
commit ac6684264642f1aea7cba5c0c3907409b1f7f904
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 11:55:28 2012 +0200
scsi: support FUA on reads
To force unit access on reads, flush the cache *before* doing the read.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 428d831..30ed3af 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -278,12 +278,48 @@ done:
}
}
+/* Actually issue a read to the block device. */
+static void scsi_do_read(void *opaque, int ret)
+{
+ SCSIDiskReq *r = opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ uint32_t n;
+
+ if (r->req.aiocb != NULL) {
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ }
+
+ if (ret < 0) {
+ if (scsi_handle_rw_error(r, -ret)) {
+ goto done;
+ }
+ }
+
+ if (r->req.sg) {
+ dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
+ r->req.resid -= r->req.sg->size;
+ r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
+ scsi_dma_complete, r);
+ } else {
+ n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
+ scsi_read_complete, r);
+ }
+
+done:
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
+}
+
/* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- uint32_t n;
+ bool first;
if (r->sector_count == (uint32_t)-1) {
DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
@@ -315,17 +351,13 @@ static void scsi_read_data(SCSIRequest *req)
return;
}
+ first = !r->started;
r->started = true;
- if (r->req.sg) {
- dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
- r->req.resid -= r->req.sg->size;
- r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
- scsi_dma_complete, r);
+ if (first && scsi_is_cmd_fua(&r->req.cmd)) {
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+ r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_do_read, r);
} else {
- n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
- bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
- scsi_read_complete, r);
+ scsi_do_read(r, 0);
}
}
commit a0e66a699e41f27cd70833045a71ddc52801dbb3
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 11:51:42 2012 +0200
scsi: add a started field to SCSIDiskReq
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 09c2715..428d831 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -55,6 +55,7 @@ typedef struct SCSIDiskReq {
uint64_t sector;
uint32_t sector_count;
uint32_t buflen;
+ bool started;
struct iovec iov;
QEMUIOVector qiov;
BlockAcctCookie acct;
@@ -287,6 +288,7 @@ static void scsi_read_data(SCSIRequest *req)
if (r->sector_count == (uint32_t)-1) {
DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
r->sector_count = 0;
+ r->started = true;
scsi_req_data(&r->req, r->iov.iov_len);
return;
}
@@ -313,6 +315,7 @@ static void scsi_read_data(SCSIRequest *req)
return;
}
+ r->started = true;
if (r->req.sg) {
dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
r->req.resid -= r->req.sg->size;
@@ -425,6 +428,7 @@ static void scsi_write_data(SCSIRequest *req)
if (!r->req.sg && !r->qiov.size) {
/* Called for the first time. Ask the driver to send us more data. */
+ r->started = true;
scsi_write_complete(r, 0);
return;
}
commit 7f64f8e2c3c5a02636c2a6b8d6e6c5f7a62b89f7
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 11:46:13 2012 +0200
scsi: force unit access on VERIFY
Also DMA data from the host, to avoid that the host reports an
underrun.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 7e6e17d..09c2715 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -185,6 +185,9 @@ static bool scsi_is_cmd_fua(SCSICommand *cmd)
case WRITE_16:
return (cmd->buf[1] & 8) != 0;
+ case VERIFY_10:
+ case VERIFY_12:
+ case VERIFY_16:
case WRITE_VERIFY_10:
case WRITE_VERIFY_12:
case WRITE_VERIFY_16:
@@ -218,7 +221,10 @@ static void scsi_dma_complete(void *opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ if (r->req.aiocb != NULL) {
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ }
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -427,6 +433,16 @@ static void scsi_write_data(SCSIRequest *req)
return;
}
+ if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
+ r->req.cmd.buf[0] == VERIFY_16) {
+ if (r->req.sg) {
+ scsi_dma_complete(r, 0);
+ } else {
+ scsi_write_complete(r, 0);
+ }
+ return;
+ }
+
if (r->req.sg) {
dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE);
r->req.resid -= r->req.sg->size;
@@ -1350,8 +1366,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
}
DPRINTF("Unsupported Service Action In\n");
goto illegal_request;
- case VERIFY_10:
- break;
default:
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
return -1;
@@ -1435,7 +1449,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
case MECHANISM_STATUS:
case SERVICE_ACTION_IN_16:
case REQUEST_SENSE:
- case VERIFY_10:
rc = scsi_disk_emulate_command(r);
if (rc < 0) {
return 0;
@@ -1461,6 +1474,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
r->sector_count = len * (s->qdev.blocksize / 512);
break;
+ case VERIFY_10:
+ case VERIFY_12:
+ case VERIFY_16:
case WRITE_6:
case WRITE_10:
case WRITE_12:
@@ -1811,6 +1827,9 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
case READ_10:
case READ_12:
case READ_16:
+ case VERIFY_10:
+ case VERIFY_12:
+ case VERIFY_16:
case WRITE_6:
case WRITE_10:
case WRITE_12:
commit 3ed9902528d0ffd244310014f7dcdcb3df3e2a04
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Apr 18 15:12:01 2012 +0200
block: allow interrupting a co_sleep_ns
In the next patch we want to reenter the coroutine from
block_job_cancel_sync and cancel the timer.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/qemu-coroutine-sleep.c b/qemu-coroutine-sleep.c
index fd65274..d7083ee 100644
--- a/qemu-coroutine-sleep.c
+++ b/qemu-coroutine-sleep.c
@@ -23,7 +23,6 @@ static void co_sleep_cb(void *opaque)
{
CoSleepCB *sleep_cb = opaque;
- qemu_free_timer(sleep_cb->ts);
qemu_coroutine_enter(sleep_cb->co, NULL);
}
@@ -35,4 +34,6 @@ void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns)
sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb);
qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns);
qemu_coroutine_yield();
+ qemu_del_timer(sleep_cb.ts);
+ qemu_free_timer(sleep_cb.ts);
}
commit 2795ecf681107d55e4113592b3045ece5f6e7b3b
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Apr 18 16:27:06 2012 +0200
qcow2: Fix return value of alloc_refcount_block
Someone forgot something in commit 29c1a730... Documenting the right
return value is not enough, you also need to actually return it in the
code.
This bug sometimes causes error return values even when everything has
succeeded: The new offset of the refcount block is truncated to 32 bits
and interpreted as signed. At least with small cluster sizes it's easy
to get a negative return value this way.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index f39928a..565bd54 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -400,7 +400,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
return ret;
}
- return new_block;
+ return 0;
fail_table:
g_free(new_table);
commit 8dc0a5e7a06c059683f9c379c0a4b0bbc20d5c74
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Apr 18 16:18:14 2012 +0200
qcow2: Fix error handling in qcow2_alloc_cluster_offset
If do_alloc_cluster_offset() fails, the error handling code tried to
remove the request from the in-flight queue, to which it wasn't added
yet, resulting in a NULL pointer dereference.
m->nb_clusters really only becomes != 0 when the request is in the list.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index cbd224d..dcf70a2 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -931,7 +931,7 @@ again:
fail:
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
fail_put:
- if (nb_clusters > 0) {
+ if (m->nb_clusters > 0) {
QLIST_REMOVE(m, next_in_flight);
}
return ret;
commit e82dabd82e7a8ce0294bce829b3d2dd25eb3a514
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Thu Mar 29 10:31:31 2012 +0100
ide: convert ide_sector_write() to asynchronous I/O
The IDE PIO write sector code path uses bdrv_write() and hence can make
the guest unresponsive while the I/O request is in progress. This patch
converts ide_sector_write() to use bdrv_aio_writev() by using the
BUSY_STAT bit to tell the guest that the request is in progress.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
Tested-by: Richard Davies <richard at arachsys.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9894b3b..a5216a6 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -688,40 +688,39 @@ static void ide_sector_write_timer_cb(void *opaque)
ide_set_irq(s->bus);
}
-void ide_sector_write(IDEState *s)
+static void ide_sector_write_cb(void *opaque, int ret)
{
- int64_t sector_num;
- int ret, n, n1;
-
- s->status = READY_STAT | SEEK_STAT;
- sector_num = ide_get_sector(s);
-#if defined(DEBUG_IDE)
- printf("write sector=%" PRId64 "\n", sector_num);
-#endif
- n = s->nsector;
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
+ IDEState *s = opaque;
+ int n;
- bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
bdrv_acct_done(s->bs, &s->acct);
+ s->pio_aiocb = NULL;
+ s->status &= ~BUSY_STAT;
+
if (ret != 0) {
- if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
+ if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY)) {
return;
+ }
}
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
s->nsector -= n;
if (s->nsector == 0) {
/* no more sectors to write */
ide_transfer_stop(s);
} else {
- n1 = s->nsector;
- if (n1 > s->req_nb_sectors)
+ int n1 = s->nsector;
+ if (n1 > s->req_nb_sectors) {
n1 = s->req_nb_sectors;
- ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
+ }
+ ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
+ ide_sector_write);
}
- ide_set_sector(s, sector_num + n);
+ ide_set_sector(s, ide_get_sector(s) + n);
if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
/* It seems there is a bug in the Windows 2000 installer HDD
@@ -737,6 +736,30 @@ void ide_sector_write(IDEState *s)
}
}
+void ide_sector_write(IDEState *s)
+{
+ int64_t sector_num;
+ int n;
+
+ s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
+ sector_num = ide_get_sector(s);
+#if defined(DEBUG_IDE)
+ printf("sector=%" PRId64 "\n", sector_num);
+#endif
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
+ s->iov.iov_base = s->io_buffer;
+ s->iov.iov_len = n * BDRV_SECTOR_SIZE;
+ qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+ bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ s->pio_aiocb = bdrv_aio_writev(s->bs, sector_num, &s->qiov, n,
+ ide_sector_write_cb, s);
+}
+
static void ide_flush_cb(void *opaque, int ret)
{
IDEState *s = opaque;
commit bef0fd5958120542f126f2dedbfce65d8839a94d
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Thu Mar 29 10:31:30 2012 +0100
ide: convert ide_sector_read() to asynchronous I/O
The IDE PIO interface currently uses bdrv_read() to perform reads
synchronously. Synchronous I/O in the vcpu thread is bad because it
prevents the guest from executing code - it makes the guest
unresponsive.
This patch converts IDE PIO to use bdrv_aio_readv(). We simply need to
use the BUSY_STAT status so the guest knows to wait while we are busy.
The only external user of ide_sector_read() is restart behavior on I/O
errors and it is not affected by this change. We still need to restart
I/O in the same way.
Migration is also unaffected if I understand the code correctly. We
continue to use the same transfer function and the BUSY_STAT status
should never be migrated since we flush I/O before migrating device
state.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
Reviewed-by: Zhi Yong Wu <wuzhy at linux.vnet.ibm.com>
Tested-by: Richard Davies <richard at arachsys.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 35723fd..9894b3b 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -471,40 +471,68 @@ static void ide_rw_error(IDEState *s) {
ide_set_irq(s->bus);
}
+static void ide_sector_read_cb(void *opaque, int ret)
+{
+ IDEState *s = opaque;
+ int n;
+
+ s->pio_aiocb = NULL;
+ s->status &= ~BUSY_STAT;
+
+ bdrv_acct_done(s->bs, &s->acct);
+ if (ret != 0) {
+ if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY |
+ BM_STATUS_RETRY_READ)) {
+ return;
+ }
+ }
+
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
+ /* Allow the guest to read the io_buffer */
+ ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
+
+ ide_set_irq(s->bus);
+
+ ide_set_sector(s, ide_get_sector(s) + n);
+ s->nsector -= n;
+}
+
void ide_sector_read(IDEState *s)
{
int64_t sector_num;
- int ret, n;
+ int n;
s->status = READY_STAT | SEEK_STAT;
s->error = 0; /* not needed by IDE spec, but needed by Windows */
sector_num = ide_get_sector(s);
n = s->nsector;
+
if (n == 0) {
- /* no more sector to read from disk */
ide_transfer_stop(s);
- } else {
+ return;
+ }
+
+ s->status |= BUSY_STAT;
+
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
#if defined(DEBUG_IDE)
- printf("read sector=%" PRId64 "\n", sector_num);
+ printf("sector=%" PRId64 "\n", sector_num);
#endif
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
- bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
- bdrv_acct_done(s->bs, &s->acct);
- if (ret != 0) {
- if (ide_handle_rw_error(s, -ret,
- BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
- {
- return;
- }
- }
- ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
- ide_set_irq(s->bus);
- ide_set_sector(s, sector_num + n);
- s->nsector -= n;
- }
+ s->iov.iov_base = s->io_buffer;
+ s->iov.iov_len = n * BDRV_SECTOR_SIZE;
+ qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+ bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ s->pio_aiocb = bdrv_aio_readv(s->bs, sector_num, &s->qiov, n,
+ ide_sector_read_cb, s);
}
static void dma_buf_commit(IDEState *s)
@@ -1765,6 +1793,12 @@ static void ide_reset(IDEState *s)
#ifdef DEBUG_IDE
printf("ide: reset\n");
#endif
+
+ if (s->pio_aiocb) {
+ bdrv_aio_cancel(s->pio_aiocb);
+ s->pio_aiocb = NULL;
+ }
+
if (s->drive_kind == IDE_CFATA)
s->mult_sectors = 0;
else
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 100efd3..f8a027d 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -385,6 +385,9 @@ struct IDEState {
int cd_sector_size;
int atapi_dma; /* true if dma is requested for the packet cmd */
BlockAcctCookie acct;
+ BlockDriverAIOCB *pio_aiocb;
+ struct iovec iov;
+ QEMUIOVector qiov;
/* ATA DMA state */
int io_buffer_size;
QEMUSGList sg;
commit 592fa07043095ba3141fb9d413693d3c202cba9a
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Apr 18 12:07:39 2012 +0200
qemu-io: Add command line switch for cache mode
To be used as in 'qemu-io -t writeback test.img'
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/qemu-io.c b/qemu-io.c
index e6fcd77..3095a22 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1784,6 +1784,7 @@ static void usage(const char *name)
" -g, --growable allow file to grow (only applies to protocols)\n"
" -m, --misalign misalign allocations for O_DIRECT\n"
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
+" -t, --cache=MODE use the given cache mode for the image\n"
" -T, --trace FILE enable trace events listed in the given file\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
@@ -1796,7 +1797,7 @@ int main(int argc, char **argv)
{
int readonly = 0;
int growable = 0;
- const char *sopt = "hVc:rsnmgkT:";
+ const char *sopt = "hVc:rsnmgkt:T:";
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
@@ -1808,6 +1809,7 @@ int main(int argc, char **argv)
{ "misalign", 0, NULL, 'm' },
{ "growable", 0, NULL, 'g' },
{ "native-aio", 0, NULL, 'k' },
+ { "cache", 1, NULL, 't' },
{ "trace", 1, NULL, 'T' },
{ NULL, 0, NULL, 0 }
};
@@ -1840,6 +1842,12 @@ int main(int argc, char **argv)
case 'k':
flags |= BDRV_O_NATIVE_AIO;
break;
+ case 't':
+ if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
+ error_report("Invalid cache option: %s", optarg);
+ exit(1);
+ }
+ break;
case 'T':
if (!trace_backend_init(optarg, NULL)) {
exit(1); /* error message will have been printed */
commit 4e35b92a51571002a68d3be74b774546d9aefd19
Author: Stefan Weil <sw at weilnetz.de>
Date: Tue Apr 17 19:41:08 2012 +0200
block: Fix spelling in comment (ineffcient -> inefficient)
Signed-off-by: Stefan Weil <sw at weilnetz.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/cow.c b/block/cow.c
index 8d3c9f8..a5a00eb 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -103,7 +103,7 @@ static int cow_open(BlockDriverState *bs, int flags)
}
/*
- * XXX(hch): right now these functions are extremely ineffcient.
+ * XXX(hch): right now these functions are extremely inefficient.
* We should just read the whole bitmap we'll need in one go instead.
*/
static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
commit 8ff9ae00da148ca98248eb2284ba432970e232ec
Author: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Date: Tue Apr 17 16:23:44 2012 +0800
iotests: fix error in 005
According comment, we should not read again, we will write.
Signed-off-by: Dong Xu Wang <wdongxu at linux.vnet.ibm.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
index 74537db..b7970e3 100755
--- a/tests/qemu-iotests/005
+++ b/tests/qemu-iotests/005
@@ -65,7 +65,7 @@ $QEMU_IO -c "read 1024 4096" $TEST_IMG | _filter_qemu_io
echo
echo "small write"
-$QEMU_IO -c "read 8192 4096" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write 8192 4096" $TEST_IMG | _filter_qemu_io
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/005.out b/tests/qemu-iotests/005.out
index 718a185..2d3e7df 100644
--- a/tests/qemu-iotests/005.out
+++ b/tests/qemu-iotests/005.out
@@ -8,6 +8,6 @@ read 4096/4096 bytes at offset 1024
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
small write
-read 4096/4096 bytes at offset 8192
+wrote 4096/4096 bytes at offset 8192
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
*** done
commit 7094f12f868fc1b75b105bcc676e15964dab77af
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Apr 11 11:06:37 2012 +0200
block: Drain requests in bdrv_close
If an AIO request is in flight that refers to a BlockDriverState that
has been closed and possibly even freed, more or less anything could
happen. I have seen segfaults, -EBADF return values and qcow2 sometimes
actually catches the situation in bdrv_close() and abort()s.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/block.c b/block.c
index c0c90f0..4b96654 100644
--- a/block.c
+++ b/block.c
@@ -816,6 +816,8 @@ void bdrv_close(BlockDriverState *bs)
if (bs->job) {
block_job_cancel_sync(bs->job);
}
+ bdrv_drain_all();
+
if (bs == bs_snapshots) {
bs_snapshots = NULL;
}
commit aafcdcc9ebd72b24bf8686f624ff98bb919de5fd
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Apr 11 10:45:51 2012 +0200
qemu-iotests: Test bdrv_close while AIO is in flight
If the BlockDriverState is closed/freed without draining the AIO
requests first, the request coroutines may work on invalid data and file
descriptors or have some dangling pointers that cause segfaults.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032
new file mode 100755
index 0000000..7155568
--- /dev/null
+++ b/tests/qemu-iotests/032
@@ -0,0 +1,69 @@
+#!/bin/bash
+#
+# Test that AIO requests are drained before an image is closed. This used
+# to segfault because the request coroutine kept running even after the
+# BlockDriverState was freed.
+#
+# Copyright (C) 2011 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf at redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+# This works for any image format (though unlikely to segfault for raw)
+_supported_fmt generic
+_supported_proto generic
+_supported_os Linux
+
+echo
+echo === Prepare image ===
+echo
+
+CLUSTER_SIZE=65536
+_make_test_img 64M
+
+# Allocate every other cluster so that afterwards a big write request will
+# actually loop a while and issue many I/O requests for the lower layer
+for i in $(seq 0 128 4096); do echo "write ${i}k 64k"; done | $QEMU_IO $TEST_IMG | _filter_qemu_io
+
+echo
+echo === AIO request during close ===
+echo
+$QEMU_IO -c "aio_write 0 4M" -c "close" $TEST_IMG | _filter_qemu_io
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/032.out b/tests/qemu-iotests/032.out
new file mode 100644
index 0000000..7272ac2
--- /dev/null
+++ b/tests/qemu-iotests/032.out
@@ -0,0 +1,78 @@
+QA output created by 032
+
+=== Prepare image ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+qemu-io> wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 131072
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 262144
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 393216
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 524288
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 655360
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 786432
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 917504
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1048576
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1179648
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1310720
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1441792
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1572864
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1703936
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1835008
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1966080
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2097152
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2228224
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2359296
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2490368
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2621440
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2752512
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2883584
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3014656
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3145728
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3276800
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3407872
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3538944
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3670016
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3801088
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3932160
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 4063232
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 4194304
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io>
+=== AIO request during close ===
+
+wrote 4194304/4194304 bytes at offset 0
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 1742ede..92508a7 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -38,3 +38,4 @@
029 rw auto quick
030 rw auto
031 rw auto quick
+032 rw auto
commit 7299550b252c2c88ae078030428435cf83315dd4
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Apr 11 11:21:25 2012 +0200
qemu-iotests: Always filter cluster_size out in _make_test_img
Some image formats do have a cluster size, others don't, but there are
tests that work with both sets of images and currently we get failures
because the qemu-img create output doesn't mention the cluster size for
some formats.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/tests/qemu-iotests/013.out b/tests/qemu-iotests/013.out
index 3073e3f..0d57187 100644
--- a/tests/qemu-iotests/013.out
+++ b/tests/qemu-iotests/013.out
@@ -1,5 +1,5 @@
QA output created by 013
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
Testing empty image
At offset 0:
diff --git a/tests/qemu-iotests/014.out b/tests/qemu-iotests/014.out
index 8045613..0258d75 100644
--- a/tests/qemu-iotests/014.out
+++ b/tests/qemu-iotests/014.out
@@ -1,5 +1,5 @@
QA output created by 014
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
Testing empty image:
test2: With offset 0
=== Clusters to be compressed [1]
diff --git a/tests/qemu-iotests/015.out b/tests/qemu-iotests/015.out
index 3ba723d..d4b961c 100644
--- a/tests/qemu-iotests/015.out
+++ b/tests/qemu-iotests/015.out
@@ -1,7 +1,7 @@
QA output created by 015
creating image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=37748736 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=37748736
creating first snapshot
wrote 37748736/37748736 bytes at offset 0
36 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/019.out b/tests/qemu-iotests/019.out
index 241d30c..b51224b 100644
--- a/tests/qemu-iotests/019.out
+++ b/tests/qemu-iotests/019.out
@@ -1,5 +1,5 @@
QA output created by 019
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
Filling base image
=== IO: pattern 42
@@ -269,7 +269,7 @@ qemu-io> wrote 65536/65536 bytes at offset 4296015872
qemu-io> No errors were found on the image.
Creating test image with backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base' cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
Filling test image
=== IO: pattern 43
diff --git a/tests/qemu-iotests/022.out b/tests/qemu-iotests/022.out
index b900c71..aed86d5 100644
--- a/tests/qemu-iotests/022.out
+++ b/tests/qemu-iotests/022.out
@@ -1,5 +1,5 @@
QA output created by 022
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
Testing empty image
At offset 10485760:
diff --git a/tests/qemu-iotests/023.out b/tests/qemu-iotests/023.out
index 138434e..8a7c5b2 100644
--- a/tests/qemu-iotests/023.out
+++ b/tests/qemu-iotests/023.out
@@ -1,7 +1,7 @@
QA output created by 023
Creating new image; cluster size: 1024
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
Testing empty image
At offset 0:
@@ -5664,7 +5664,7 @@ qemu-io> read 3072/3072 bytes at offset 4295491072
qemu-io> No errors were found on the image.
Creating another new image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
More complex patterns
test2: With offset 0
@@ -5887,7 +5887,7 @@ qemu-io> read 2048/2048 bytes at offset 4295001088
qemu-io> No errors were found on the image.
Creating new image; cluster size: 4096
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
Testing empty image
At offset 0:
@@ -12270,7 +12270,7 @@ qemu-io> read 12288/12288 bytes at offset 4301256704
qemu-io> No errors were found on the image.
Creating another new image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
More complex patterns
test2: With offset 0
@@ -12493,7 +12493,7 @@ qemu-io> read 8192/8192 bytes at offset 4295102464
qemu-io> No errors were found on the image.
Creating new image; cluster size: 16384
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=16384
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
Testing empty image
At offset 0:
@@ -18876,7 +18876,7 @@ qemu-io> read 49152/49152 bytes at offset 4395622400
qemu-io> No errors were found on the image.
Creating another new image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=16384
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
More complex patterns
test2: With offset 0
@@ -19099,7 +19099,7 @@ qemu-io> read 32768/32768 bytes at offset 4295507968
qemu-io> No errors were found on the image.
Creating new image; cluster size: 65536
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
Testing empty image
At offset 0:
@@ -25482,7 +25482,7 @@ qemu-io> read 196608/196608 bytes at offset 5905547264
qemu-io> No errors were found on the image.
Creating another new image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
More complex patterns
test2: With offset 0
diff --git a/tests/qemu-iotests/024.out b/tests/qemu-iotests/024.out
index 4cee216..072207c 100644
--- a/tests/qemu-iotests/024.out
+++ b/tests/qemu-iotests/024.out
@@ -1,7 +1,7 @@
QA output created by 024
Creating backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
=== IO: pattern 0x11
qemu-io> wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -21,7 +21,7 @@ qemu-io> wrote 65536/65536 bytes at offset 917504
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> Creating new backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
=== IO: pattern 0x22
qemu-io> wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -33,7 +33,7 @@ qemu-io> wrote 131072/131072 bytes at offset 786432
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> Creating COW image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old' cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old'
=== IO: pattern 0x33
qemu-io> wrote 262144/262144 bytes at offset 0
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
index b503cf2..fb4f20e 100644
--- a/tests/qemu-iotests/026.out
+++ b/tests/qemu-iotests/026.out
@@ -1,63 +1,63 @@
QA output created by 026
Errors while writing 128 kB
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: on; write
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: off; write
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: on; write
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: off; write
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 5; imm: off; once: on; write
wrote 131072/131072 bytes at offset 0
@@ -65,7 +65,7 @@ wrote 131072/131072 bytes at offset 0
write failed: Input/output error
read failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 5; imm: off; once: on; write -b
wrote 131072/131072 bytes at offset 0
@@ -73,7 +73,7 @@ wrote 131072/131072 bytes at offset 0
write failed: Input/output error
read failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 5; imm: off; once: off; write
wrote 131072/131072 bytes at offset 0
@@ -81,7 +81,7 @@ wrote 131072/131072 bytes at offset 0
write failed: Input/output error
read failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 5; imm: off; once: off; write -b
wrote 131072/131072 bytes at offset 0
@@ -89,7 +89,7 @@ wrote 131072/131072 bytes at offset 0
write failed: Input/output error
read failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 28; imm: off; once: on; write
wrote 131072/131072 bytes at offset 0
@@ -97,7 +97,7 @@ wrote 131072/131072 bytes at offset 0
write failed: No space left on device
read failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 28; imm: off; once: on; write -b
wrote 131072/131072 bytes at offset 0
@@ -105,7 +105,7 @@ wrote 131072/131072 bytes at offset 0
write failed: No space left on device
read failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 28; imm: off; once: off; write
wrote 131072/131072 bytes at offset 0
@@ -113,7 +113,7 @@ wrote 131072/131072 bytes at offset 0
write failed: No space left on device
read failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 28; imm: off; once: off; write -b
wrote 131072/131072 bytes at offset 0
@@ -121,306 +121,306 @@ wrote 131072/131072 bytes at offset 0
write failed: No space left on device
read failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: on; write
write failed: Input/output error
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: off; write
write failed: Input/output error
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: on; write
write failed: No space left on device
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: off; write
write failed: No space left on device
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
@@ -428,116 +428,116 @@ No errors were found on the image.
=== Refcout table growth tests ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write
write failed: No space left on device
55 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
251 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
23 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
23 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
@@ -547,54 +547,54 @@ This means waste of disk space, but no harm to data.
=== L1 growth tests ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.alloc_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.alloc_table; errno: 5; imm: off; once: off
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.alloc_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.alloc_table; errno: 28; imm: off; once: off
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.write_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.write_table; errno: 5; imm: off; once: off
qcow2_free_clusters failed: Input/output error
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.write_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.write_table; errno: 28; imm: off; once: off
qcow2_free_clusters failed: No space left on device
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.activate_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.activate_table; errno: 5; imm: off; once: off
qcow2_free_clusters failed: Input/output error
@@ -602,12 +602,12 @@ write failed: Input/output error
96 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.activate_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.activate_table; errno: 28; imm: off; once: off
qcow2_free_clusters failed: No space left on device
diff --git a/tests/qemu-iotests/029.out b/tests/qemu-iotests/029.out
index c2ad30c..0eedb3a 100644
--- a/tests/qemu-iotests/029.out
+++ b/tests/qemu-iotests/029.out
@@ -1,9 +1,9 @@
QA output created by 029
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216
wrote 4194304/4194304 bytes at offset 0
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
index 0f1bf68..e1a536e 100644
--- a/tests/qemu-iotests/031.out
+++ b/tests/qemu-iotests/031.out
@@ -2,7 +2,7 @@ QA output created by 031
=== Create image with unknown header extension ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
magic 0x514649fb
version 2
backing_file_offset 0x0
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 4cb8dae..00ee754 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -58,7 +58,6 @@ _make_test_img()
# extra qemu-img options can be added by tests
# at least one argument (the image size) needs to be added
local extra_img_options=""
- local cluster_size_filter="s# cluster_size=[0-9]\\+##g"
local image_size=$*
if [ "$1" = "-b" ]; then
@@ -67,7 +66,6 @@ _make_test_img()
fi
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
extra_img_options="-o cluster_size=$CLUSTER_SIZE $extra_img_options"
- cluster_size_filter=""
fi
# XXX(hch): have global image options?
@@ -76,7 +74,7 @@ _make_test_img()
sed -e "s#$TEST_DIR#TEST_DIR#g" | \
sed -e "s#$IMGFMT#IMGFMT#g" | \
sed -e "s# encryption=off##g" | \
- sed -e "$cluster_size_filter" | \
+ sed -e "s# cluster_size=[0-9]\\+##g" | \
sed -e "s# table_size=0##g" | \
sed -e "s# compat6=off##g" | \
sed -e "s# static=off##g"
commit 7e8c49c56154ab5c45d4f07edf0c22728735da35
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 10:10:54 2012 +0200
scsi: add support for FUA on writes
To force unit access, add a flush operation after the actual write.
WRITE AND VERIFY commands always flush according to SBC, so do it
even though we do not perform the reread.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 158ed5b..7e6e17d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -174,6 +174,45 @@ done:
}
}
+static bool scsi_is_cmd_fua(SCSICommand *cmd)
+{
+ switch (cmd->buf[0]) {
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ return (cmd->buf[1] & 8) != 0;
+
+ case WRITE_VERIFY_10:
+ case WRITE_VERIFY_12:
+ case WRITE_VERIFY_16:
+ return true;
+
+ case READ_6:
+ case WRITE_6:
+ default:
+ return false;
+ }
+}
+
+static void scsi_write_do_fua(SCSIDiskReq *r)
+{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ if (scsi_is_cmd_fua(&r->req.cmd)) {
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+ r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
+ return;
+ }
+
+ scsi_req_complete(&r->req, GOOD);
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
+}
+
static void scsi_dma_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -189,7 +228,12 @@ static void scsi_dma_complete(void *opaque, int ret)
r->sector += r->sector_count;
r->sector_count = 0;
- scsi_req_complete(&r->req, GOOD);
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+ scsi_write_do_fua(r);
+ return;
+ } else {
+ scsi_req_complete(&r->req, GOOD);
+ }
done:
if (!r->req.io_canceled) {
@@ -342,7 +386,8 @@ static void scsi_write_complete(void * opaque, int ret)
r->sector += n;
r->sector_count -= n;
if (r->sector_count == 0) {
- scsi_req_complete(&r->req, GOOD);
+ scsi_write_do_fua(r);
+ return;
} else {
scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
commit b77912a77a613451e9aac9a12f721eb5e9f09185
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 10:05:04 2012 +0200
scsi: move scsi_flush_complete around
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 1664793..158ed5b 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -153,7 +153,7 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
}
-static void scsi_dma_complete(void *opaque, int ret)
+static void scsi_flush_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
@@ -166,8 +166,6 @@ static void scsi_dma_complete(void *opaque, int ret)
}
}
- r->sector += r->sector_count;
- r->sector_count = 0;
scsi_req_complete(&r->req, GOOD);
done:
@@ -176,16 +174,12 @@ done:
}
}
-static void scsi_read_complete(void * opaque, int ret)
+static void scsi_dma_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- int n;
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- }
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -193,12 +187,9 @@ static void scsi_read_complete(void * opaque, int ret)
}
}
- DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
-
- n = r->qiov.size / 512;
- r->sector += n;
- r->sector_count -= n;
- scsi_req_data(&r->req, r->qiov.size);
+ r->sector += r->sector_count;
+ r->sector_count = 0;
+ scsi_req_complete(&r->req, GOOD);
done:
if (!r->req.io_canceled) {
@@ -206,12 +197,16 @@ done:
}
}
-static void scsi_flush_complete(void * opaque, int ret)
+static void scsi_read_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ int n;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ if (r->req.aiocb != NULL) {
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ }
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -219,7 +214,12 @@ static void scsi_flush_complete(void * opaque, int ret)
}
}
- scsi_req_complete(&r->req, GOOD);
+ DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
+
+ n = r->qiov.size / 512;
+ r->sector += n;
+ r->sector_count -= n;
+ scsi_req_data(&r->req, r->qiov.size);
done:
if (!r->req.io_canceled) {
commit 80624c938d2d9d2b2cca56326876f213c31e1202
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 14:00:24 2012 +0200
scsi: make code more homogeneous in AIO callback functions
First scsi_flush_complete, like scsi_dma_complete, is always called with
an active AIOCB.
Second, always test for "ret < 0" to check for errors.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 792e9d0..1664793 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -160,7 +160,7 @@ static void scsi_dma_complete(void *opaque, int ret)
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- if (ret) {
+ if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
@@ -187,7 +187,7 @@ static void scsi_read_complete(void * opaque, int ret)
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
- if (ret) {
+ if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
@@ -211,10 +211,7 @@ static void scsi_flush_complete(void * opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- }
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -335,7 +332,7 @@ static void scsi_write_complete(void * opaque, int ret)
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
- if (ret) {
+ if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
commit b8aba8d7e3031ee3411a8e5eb07ac61f5b18f045
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Thu Apr 19 10:09:49 2012 +0200
scsi: add missing test for cancelled request
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9949786..792e9d0 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -171,7 +171,9 @@ static void scsi_dma_complete(void *opaque, int ret)
scsi_req_complete(&r->req, GOOD);
done:
- scsi_req_unref(&r->req);
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
}
static void scsi_read_complete(void * opaque, int ret)
commit d2ad7dd46e72118a577e16b3c6dffdc43c961476
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Apr 6 10:39:46 2012 +0200
virtio-scsi: add multiqueue capability
Adding multiqueue is as simple as creating more than one virtqueues,
and saving the queue number for each request.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 0d90d9c..e8328f4 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -129,12 +129,12 @@ typedef struct {
VirtIOSCSIConf *conf;
SCSIBus bus;
- VirtQueue *ctrl_vq;
- VirtQueue *event_vq;
- VirtQueue *cmd_vq;
uint32_t sense_size;
uint32_t cdb_size;
int resetting;
+ VirtQueue *ctrl_vq;
+ VirtQueue *event_vq;
+ VirtQueue *cmd_vqs[0];
} VirtIOSCSI;
typedef struct VirtIOSCSIReq {
@@ -240,8 +240,9 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
{
VirtIOSCSIReq *req = sreq->hba_private;
- uint32_t n = 0;
+ uint32_t n = virtio_queue_get_id(req->vq) - 2;
+ assert(n < req->dev->conf->num_queues);
qemu_put_be32s(f, &n);
qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
}
@@ -255,9 +256,9 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
req = g_malloc(sizeof(*req));
qemu_get_be32s(f, &n);
- assert(n == 0);
+ assert(n < s->conf->num_queues);
qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
- virtio_scsi_parse_req(s, s->cmd_vq, req);
+ virtio_scsi_parse_req(s, s->cmd_vqs[n], req);
scsi_req_ref(sreq);
req->sreq = sreq;
@@ -584,10 +585,12 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
{
VirtIOSCSI *s;
static int virtio_scsi_id;
+ size_t sz;
+ int i;
+ sz = sizeof(VirtIOSCSI) + proxyconf->num_queues * sizeof(VirtQueue *);
s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
- sizeof(VirtIOSCSIConfig),
- sizeof(VirtIOSCSI));
+ sizeof(VirtIOSCSIConfig), sz);
s->qdev = dev;
s->conf = proxyconf;
@@ -602,8 +605,10 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
virtio_scsi_handle_ctrl);
s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
NULL);
- s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
- virtio_scsi_handle_cmd);
+ for (i = 0; i < s->conf->num_queues; i++) {
+ s->cmd_vqs[i] = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+ virtio_scsi_handle_cmd);
+ }
scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info);
if (!dev->hotplugged) {
commit c80decdbd9ea679a17f6b0202ea1df0f840e4828
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Apr 6 10:38:37 2012 +0200
virtio: add virtio_queue_get_id
Serializing virtio-scsi requests needs a simple way to get from a
VirtQueue to the number of the queue. The virtio_queue_get_id
provides this.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/virtio.c b/hw/virtio.c
index 064aecf..314abf8 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -624,6 +624,13 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n)
return vdev->vq[n].vring.num;
}
+int virtio_queue_get_id(VirtQueue *vq)
+{
+ VirtIODevice *vdev = vq->vdev;
+ assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_PCI_QUEUE_MAX]);
+ return vq - &vdev->vq[0];
+}
+
void virtio_queue_notify_vq(VirtQueue *vq)
{
if (vq->vring.desc) {
diff --git a/hw/virtio.h b/hw/virtio.h
index 400c092..0aef7d1 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -229,6 +229,7 @@ target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n);
uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
+int virtio_queue_get_id(VirtQueue *vq);
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
void virtio_queue_notify_vq(VirtQueue *vq);
commit fcf104a74cb8d6d39dc935ab692afface3beab30
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Apr 6 10:20:43 2012 +0200
virtio-scsi: prepare migration format for multiqueue
In order to restore requests correctly from a multitude of virtqueues,
we need to store the id of the request queue that each request came
from.
Do this even for single-queue, by storing a hard-coded zero, to
simplify future implementation of multiqueue.
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 45d54fa..0d90d9c 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -240,7 +240,9 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
{
VirtIOSCSIReq *req = sreq->hba_private;
+ uint32_t n = 0;
+ qemu_put_be32s(f, &n);
qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
}
@@ -249,8 +251,11 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
SCSIBus *bus = sreq->bus;
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
VirtIOSCSIReq *req;
+ uint32_t n;
req = g_malloc(sizeof(*req));
+ qemu_get_be32s(f, &n);
+ assert(n == 0);
qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
virtio_scsi_parse_req(s, s->cmd_vq, req);
commit b7c8c35f0afb62efcacd18a64067fe164e3206b6
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Fri Apr 6 14:12:42 2012 +0200
scsi: fix memory leak
scsibus_get_dev_path is leaking id if it is not NULL. Fix it.
Reported-by: Laszlo Ersek <lersek at redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 8e76c5d..d847396 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1430,15 +1430,18 @@ static char *scsibus_get_dev_path(DeviceState *dev)
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
DeviceState *hba = dev->parent_bus->parent;
char *id = NULL;
+ char *path;
if (hba && hba->parent_bus && hba->parent_bus->info->get_dev_path) {
id = hba->parent_bus->info->get_dev_path(hba);
}
if (id) {
- return g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
+ path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
} else {
- return g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
+ path = g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
}
+ g_free(id);
+ return path;
}
static char *scsibus_get_fw_dev_path(DeviceState *dev)
commit 51006bbc45bc74977ae538190a53df2af534acb9
Merge: 25b9e14... 6e7a7f3...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Apr 18 10:05:58 2012 -0500
Merge remote-tracking branch 'origin/master' into staging
* origin/master:
Allow controlling volume with PulseAudio backend
configure: pa_simple is not needed anymore
Do not use pa_simple PulseAudio API
audio/spice: add support for volume control
hw/ac97: add support for volume control
hw/ac97: the volume mask is not only 0x1f
hw/ac97: remove USE_MIXER code
audio: don't apply volume effect if backend has VOICE_VOLUME_CAP
audio: add VOICE_VOLUME ctl
commit 256a721d46a112d8807a488ec0176985c09bbbf1
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Mon Apr 16 12:47:58 2012 +0100
tracetool: handle DTrace keywords 'in', 'next', 'self'
Language keywords cannot be used as argument names. The DTrace backend
appends an underscore to the argument name in order to make the argument
name legal.
This patch adds 'in', 'next', and 'self' keywords to dtrace.py.
Also drop the unnecessary argument name lstrip() call. The
Arguments.build() method already ensures there is no space around
argument names. Furthermore it is misleading to do the lstrip() *after*
checking against keywords because the keyword check would not match if
spaces were in the name.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Reviewed-by: Alon Levy <alevy at redhat.com>
Reviewed-by: LluÃs Vilanova <vilanova at ac.upc.edu>
diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py
index cebbd57..9cab75c 100644
--- a/scripts/tracetool/backend/dtrace.py
+++ b/scripts/tracetool/backend/dtrace.py
@@ -86,10 +86,10 @@ def stap(events):
i = 1
if len(e.args) > 0:
for name in e.args.names():
- # 'limit' is a reserved keyword
- if name == 'limit':
- name = '_limit'
- out(' %s = $arg%d;' % (name.lstrip(), i))
+ # Append underscore to reserved keywords
+ if name in ('limit', 'in', 'next', 'self'):
+ name += '_'
+ out(' %s = $arg%d;' % (name, i))
i += 1
out('}')
commit f70fd8fdf646714c3f75d3b27a33f42caf856fc6
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Tue Apr 3 20:48:17 2012 +0200
tracetool: Add MAINTAINERS info
Update the MAINTAINERS file to reflect the new Python tracetool code.
[Commit description written by Stefan Hajnoczi]
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index 922945c..cce37e7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -553,6 +553,8 @@ Tracing
M: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
S: Maintained
F: trace/
+F: scripts/tracetool.py
+F: scripts/tracetool/
F: docs/tracing.txt
T: git://github.com/stefanha/qemu.git tracing
commit 52ef093aceddbe43dcc2cb4190e2178036dac60b
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Tue Apr 3 20:48:12 2012 +0200
tracetool: Add support for the 'dtrace' backend
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
index fe2ea34..cacfd99 100755
--- a/scripts/tracetool.py
+++ b/scripts/tracetool.py
@@ -44,6 +44,11 @@ Options:
--help This help message.
--list-backends Print list of available backends.
--check-backend Check if the given backend is valid.
+ --binary <path> Full path to QEMU binary.
+ --target-type <type> QEMU emulator target type ('system' or 'user').
+ --target-arch <arch> QEMU emulator target arch.
+ --probe-prefix <prefix> Prefix for dtrace probe names
+ (default: qemu-<target-type>-<target-arch>).\
""" % {
"script" : _SCRIPT,
"backends" : backend_descr,
@@ -71,6 +76,10 @@ def main(args):
check_backend = False
arg_backend = ""
arg_format = ""
+ binary = None
+ target_type = None
+ target_arch = None
+ probe_prefix = None
for opt, arg in opts:
if opt == "--help":
error_opt()
@@ -87,6 +96,15 @@ def main(args):
elif opt == "--check-backend":
check_backend = True
+ elif opt == "--binary":
+ binary = arg
+ elif opt == '--target-type':
+ target_type = arg
+ elif opt == '--target-arch':
+ target_arch = arg
+ elif opt == '--probe-prefix':
+ probe_prefix = arg
+
else:
error_opt("unhandled option: %s" % opt)
@@ -99,8 +117,20 @@ def main(args):
else:
sys.exit(1)
+ if arg_format == "stap":
+ if binary is None:
+ error_opt("--binary is required for SystemTAP tapset generator")
+ if probe_prefix is None and target_type is None:
+ error_opt("--target-type is required for SystemTAP tapset generator")
+ if probe_prefix is None and target_arch is None:
+ error_opt("--target-arch is required for SystemTAP tapset generator")
+
+ if probe_prefix is None:
+ probe_prefix = ".".join([ "qemu", target_type, target_arch ])
+
try:
- tracetool.generate(sys.stdin, arg_format, arg_backend)
+ tracetool.generate(sys.stdin, arg_format, arg_backend,
+ binary = binary, probe_prefix = probe_prefix)
except tracetool.TracetoolError as e:
error_opt(str(e))
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
index 1719bb4..74fe21b 100644
--- a/scripts/tracetool/__init__.py
+++ b/scripts/tracetool/__init__.py
@@ -212,7 +212,8 @@ def try_import(mod_name, attr_name = None, attr_default = None):
return False, None
-def generate(fevents, format, backend):
+def generate(fevents, format, backend,
+ binary = None, probe_prefix = None):
"""Generate the output for the given (format, backend) pair.
Parameters
@@ -223,6 +224,10 @@ def generate(fevents, format, backend):
Output format name.
backend : str
Output backend name.
+ binary : str or None
+ See tracetool.backend.dtrace.BINARY.
+ probe_prefix : str or None
+ See tracetool.backend.dtrace.PROBEPREFIX.
"""
# fix strange python error (UnboundLocalError tracetool)
import tracetool
@@ -245,6 +250,10 @@ def generate(fevents, format, backend):
raise TracetoolError("backend '%s' not compatible with format '%s'" %
(backend, format))
+ import tracetool.backend.dtrace
+ tracetool.backend.dtrace.BINARY = binary
+ tracetool.backend.dtrace.PROBEPREFIX = probe_prefix
+
events = _read_events(fevents)
if backend == "nop":
diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py
new file mode 100644
index 0000000..cebbd57
--- /dev/null
+++ b/scripts/tracetool/backend/dtrace.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+DTrace/SystemTAP backend.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+PROBEPREFIX = None
+
+def _probeprefix():
+ if PROBEPREFIX is None:
+ raise ValueError("you must set PROBEPREFIX")
+ return PROBEPREFIX
+
+
+BINARY = None
+
+def _binary():
+ if BINARY is None:
+ raise ValueError("you must set BINARY")
+ return BINARY
+
+
+def c(events):
+ pass
+
+
+def h(events):
+ out('#include "trace-dtrace.h"',
+ '')
+
+ for e in events:
+ out('static inline void trace_%(name)s(%(args)s) {',
+ ' QEMU_%(uppername)s(%(argnames)s);',
+ '}',
+ name = e.name,
+ args = e.args,
+ uppername = e.name.upper(),
+ argnames = ", ".join(e.args.names()),
+ )
+
+
+def d(events):
+ out('provider qemu {')
+
+ for e in events:
+ args = str(e.args)
+
+ # DTrace provider syntax expects foo() for empty
+ # params, not foo(void)
+ if args == 'void':
+ args = ''
+
+ # Define prototype for probe arguments
+ out('',
+ 'probe %(name)s(%(args)s);',
+ name = e.name,
+ args = args,
+ )
+
+ out('',
+ '};')
+
+
+def stap(events):
+ for e in events:
+ # Define prototype for probe arguments
+ out('probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")',
+ '{',
+ probeprefix = _probeprefix(),
+ name = e.name,
+ binary = _binary(),
+ )
+
+ i = 1
+ if len(e.args) > 0:
+ for name in e.args.names():
+ # 'limit' is a reserved keyword
+ if name == 'limit':
+ name = '_limit'
+ out(' %s = $arg%d;' % (name.lstrip(), i))
+ i += 1
+
+ out('}')
+
+ out()
diff --git a/scripts/tracetool/format/d.py b/scripts/tracetool/format/d.py
new file mode 100644
index 0000000..a2d5947
--- /dev/null
+++ b/scripts/tracetool/format/d.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .d file (DTrace only).
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */')
diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py
new file mode 100644
index 0000000..50a4c69
--- /dev/null
+++ b/scripts/tracetool/format/stap.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .stp file (DTrace with SystemTAP only).
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */')
commit fbc54b9412a905c460d0f5e9e0508d64f9e9759b
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Tue Apr 3 20:48:06 2012 +0200
tracetool: Add support for the 'ust' backend
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py
new file mode 100644
index 0000000..31a2ff0
--- /dev/null
+++ b/scripts/tracetool/backend/ust.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+LTTng User Space Tracing backend.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+ out('#include <ust/marker.h>',
+ '#undef mutex_lock',
+ '#undef mutex_unlock',
+ '#undef inline',
+ '#undef wmb',
+ '#include "trace.h"')
+
+ for e in events:
+ argnames = ", ".join(e.args.names())
+ if len(e.args) > 0:
+ argnames = ', ' + argnames
+
+ out('DEFINE_TRACE(ust_%(name)s);',
+ '',
+ 'static void ust_%(name)s_probe(%(args)s)',
+ '{',
+ ' trace_mark(ust, %(name)s, %(fmt)s%(argnames)s);',
+ '}',
+ name = e.name,
+ args = e.args,
+ fmt = e.fmt,
+ argnames = argnames,
+ )
+
+ else:
+ out('DEFINE_TRACE(ust_%(name)s);',
+ '',
+ 'static void ust_%(name)s_probe(%(args)s)',
+ '{',
+ ' trace_mark(ust, %(name)s, UST_MARKER_NOARGS);',
+ '}',
+ name = e.name,
+ args = e.args,
+ )
+
+ # register probes
+ out('',
+ 'static void __attribute__((constructor)) trace_init(void)',
+ '{')
+
+ for e in events:
+ out(' register_trace_ust_%(name)s(ust_%(name)s_probe);',
+ name = e.name,
+ )
+
+ out('}')
+
+
+def h(events):
+ out('#include <ust/tracepoint.h>',
+ '#undef mutex_lock',
+ '#undef mutex_unlock',
+ '#undef inline',
+ '#undef wmb')
+
+ for e in events:
+ if len(e.args) > 0:
+ out('DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s));',
+ '#define trace_%(name)s trace_ust_%(name)s',
+ name = e.name,
+ args = e.args,
+ argnames = ", ".join(e.args.names()),
+ )
+
+ else:
+ out('_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);',
+ '#define trace_%(name)s trace_ust_%(name)s',
+ name = e.name,
+ )
+
+ out()
commit dd03a39e8a5952fbb0d7a3960d45c33b726019a7
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Tue Apr 3 20:48:01 2012 +0200
tracetool: Add support for the 'simple' backend
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py
new file mode 100644
index 0000000..fbb5717
--- /dev/null
+++ b/scripts/tracetool/backend/simple.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Simple built-in backend.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+ out('#include "trace.h"',
+ '',
+ 'TraceEvent trace_list[] = {')
+
+ for e in events:
+ out('{.tp_name = "%(name)s", .state=0},',
+ name = e.name,
+ )
+
+ out('};')
+
+def h(events):
+ out('#include "trace/simple.h"',
+ '')
+
+ for num, e in enumerate(events):
+ if len(e.args):
+ argstr = e.args.names()
+ arg_prefix = ', (uint64_t)(uintptr_t)'
+ cast_args = arg_prefix + arg_prefix.join(argstr)
+ simple_args = (str(num) + cast_args)
+ else:
+ simple_args = str(num)
+
+ out('static inline void trace_%(name)s(%(args)s)',
+ '{',
+ ' trace%(argc)d(%(trace_args)s);',
+ '}',
+ name = e.name,
+ args = e.args,
+ argc = len(e.args),
+ trace_args = simple_args,
+ )
+
+ out('#define NR_TRACE_EVENTS %d' % len(events))
+ out('extern TraceEvent trace_list[NR_TRACE_EVENTS];')
commit 9008d85a96bb42ed40da6b4d70a0f14b9353f442
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Tue Apr 3 20:47:55 2012 +0200
tracetool: Add support for the 'stderr' backend
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/scripts/tracetool/backend/stderr.py b/scripts/tracetool/backend/stderr.py
new file mode 100644
index 0000000..917fde7
--- /dev/null
+++ b/scripts/tracetool/backend/stderr.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Stderr built-in backend.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+ out('#include "trace.h"',
+ '',
+ 'TraceEvent trace_list[] = {')
+
+ for e in events:
+ out('{.tp_name = "%(name)s", .state=0},',
+ name = e.name,
+ )
+
+ out('};')
+
+def h(events):
+ out('#include <stdio.h>',
+ '#include "trace/stderr.h"',
+ '',
+ 'extern TraceEvent trace_list[];')
+
+ for num, e in enumerate(events):
+ argnames = ", ".join(e.args.names())
+ if len(e.args) > 0:
+ argnames = ", " + argnames
+
+ out('static inline void trace_%(name)s(%(args)s)',
+ '{',
+ ' if (trace_list[%(event_num)s].state != 0) {',
+ ' fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);',
+ ' }',
+ '}',
+ name = e.name,
+ args = e.args,
+ event_num = num,
+ fmt = e.fmt,
+ argnames = argnames,
+ )
+
+ out('',
+ '#define NR_TRACE_EVENTS %d' % len(events))
commit c419e62a037d44520b3d3a3849b919f8cdaf2249
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Tue Apr 3 20:47:50 2012 +0200
tracetool: Add module for the 'h' format
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py
new file mode 100644
index 0000000..6ffb3c2
--- /dev/null
+++ b/scripts/tracetool/format/h.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .h file.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '',
+ '#ifndef TRACE_H',
+ '#define TRACE_H',
+ '',
+ '#include "qemu-common.h"')
+
+def end(events):
+ for e in events:
+ if "disable" in e.properties:
+ enabled = 0
+ else:
+ enabled = 1
+ out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled))
+ out('',
+ '#endif /* TRACE_H */')
+
+def nop(events):
+ for e in events:
+ out('',
+ 'static inline void trace_%(name)s(%(args)s)',
+ '{',
+ '}',
+ name = e.name,
+ args = e.args,
+ )
commit 5de7f9c8eefcb42e5657817574b6f8b3b3720af2
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Tue Apr 3 20:47:44 2012 +0200
tracetool: Add module for the 'c' format
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py
new file mode 100644
index 0000000..35555ae
--- /dev/null
+++ b/scripts/tracetool/format/c.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .c file.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */')
commit 650ab98d1d9551f0ca2180c0d88427acfcb081cf
Author: LluÃs Vilanova <vilanova at ac.upc.edu>
Date: Tue Apr 3 20:47:39 2012 +0200
tracetool: Rewrite infrastructure as python modules
The tracetool script is written in shell and has hit several portability
problems due to shell quirks or external tools across host platforms.
Additionally the amount of string processing and lack of real data
structures makes it tough to implement code generator backends for
tracers that are more complex.
This patch replaces the shell version of tracetool with a Python
version. The new tracetool design is:
scripts/tracetool.py - top-level script
scripts/tracetool/backend/ - tracer backends live here (simple, ust)
scripts/tracetool/format/ - output formats live here (.c, .h)
There is common code for trace-events definition parsing so that
backends can focus on generating code rather than parsing input.
Support for all existing backends (nop, stderr, simple, ust,
and dtrace) is added back in follow-up patches.
[Commit description written by Stefan Hajnoczi]
Signed-off-by: LluÃs Vilanova <vilanova at ac.upc.edu>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/Makefile.objs b/Makefile.objs
index 5c3bcda..6d6f24d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -378,12 +378,12 @@ else
trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=h --backend=$(TRACE_BACKEND) < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=c --backend=$(TRACE_BACKEND) < $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
@@ -396,7 +396,7 @@ trace-dtrace.h: trace-dtrace.dtrace
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=d --backend=$(TRACE_BACKEND) < $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
diff --git a/Makefile.target b/Makefile.target
index 84951a0..a0540cd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -59,12 +59,13 @@ TARGET_TYPE=system
endif
$(QEMU_PROG).stp: $(SRC_PATH)/trace-events
- $(call quiet-command,sh $(SRC_PATH)/scripts/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")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \
+ --format=stap \
+ --backend=$(TRACE_BACKEND) \
+ --binary=$(bindir)/$(QEMU_PROG) \
+ --target-arch=$(TARGET_ARCH) \
+ --target-type=$(TARGET_TYPE) \
+ < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
else
stap:
endif
diff --git a/configure b/configure
index 2d62d12..03b49f6 100755
--- a/configure
+++ b/configure
@@ -1097,7 +1097,7 @@ 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 " --enable-trace-backend=B Set trace backend"
-echo " Available backends:" $("$source_path"/scripts/tracetool --list-backends)
+echo " Available backends:" $($python "$source_path"/scripts/tracetool.py --list-backends)
echo " --with-trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
@@ -2670,7 +2670,7 @@ fi
##########################################
# check if trace backend exists
-sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
+$python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend > /dev/null 2> /dev/null
if test "$?" -ne 0 ; then
echo
echo "Error: invalid trace backend"
diff --git a/scripts/tracetool b/scripts/tracetool
deleted file mode 100755
index 7b1c142..0000000
--- a/scripts/tracetool
+++ /dev/null
@@ -1,666 +0,0 @@
-#!/bin/sh
-#
-# Code generator for trace events
-#
-# Copyright IBM, Corp. 2010
-#
-# This work is licensed under the terms of the GNU GPL, version 2. See
-# the COPYING file in the top-level directory.
-
-# Disable pathname expansion, makes processing text with '*' characters simpler
-set -f
-
-usage()
-{
- cat >&2 <<EOF
-usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
-Generate tracing code for a file on stdin.
-
-Backends:
- --nop Tracing disabled
- --simple Simple built-in backend
- --stderr Stderr built-in backend
- --ust LTTng User Space Tracing backend
- --dtrace DTrace/SystemTAP backend
-
-Output formats:
- -h Generate .h file
- -c Generate .c file
- -d Generate .d file (DTrace only)
- --stap Generate .stp file (DTrace with SystemTAP only)
-
-Options:
- --binary [path] Full path to QEMU binary
- --target-arch [arch] QEMU emulator target arch
- --target-type [type] QEMU emulator target type ('system' or 'user')
- --probe-prefix [prefix] Prefix for dtrace probe names
- (default: qemu-\$targettype-\$targetarch)
-
-EOF
- exit 1
-}
-
-# Print a line without interpreting backslash escapes
-#
-# The built-in echo command may interpret backslash escapes without an option
-# to disable this behavior.
-puts()
-{
- printf "%s\n" "$1"
-}
-
-# Get the name of a trace event
-get_name()
-{
- local name
- name=${1%%\(*}
- echo "${name##* }"
-}
-
-# Get the given property of a trace event
-# 1: trace-events line
-# 2: property name
-# -> return 0 if property is present, or 1 otherwise
-has_property()
-{
- local props prop
- props=${1%%\(*}
- props=${props% *}
- for prop in $props; do
- if [ "$prop" = "$2" ]; then
- return 0
- fi
- done
- return 1
-}
-
-# Get the argument list of a trace event, including types and names
-get_args()
-{
- local args
- args=${1#*\(}
- args=${args%%\)*}
- echo "$args"
-
- if (echo "$args" | grep "[ *]next\($\|[, ]\)" > /dev/null 2>&1); then
- echo -e "\n#error 'next' is a bad argument name (clash with systemtap keyword)\n "
- fi
-}
-
-# Get the argument name list of a trace event
-get_argnames()
-{
- local nfields field name sep
- nfields=0
- sep="$2"
- for field in $(get_args "$1"); do
- nfields=$((nfields + 1))
-
- # Drop pointer star
- field=${field#\*}
-
- # Only argument names have commas at the end
- name=${field%,}
- test "$field" = "$name" && continue
-
- printf "%s%s " $name $sep
- done
-
- # Last argument name
- if [ "$nfields" -gt 1 ]
- then
- printf "%s" "$name"
- fi
-}
-
-# Get the number of arguments to a trace event
-get_argc()
-{
- local name argc
- argc=0
- for name in $(get_argnames "$1", ","); do
- argc=$((argc + 1))
- done
- echo $argc
-}
-
-# Get the format string including double quotes for a trace event
-get_fmt()
-{
- puts "${1#*)}"
-}
-
-linetoh_begin_nop()
-{
- return
-}
-
-linetoh_nop()
-{
- local name args
- name=$(get_name "$1")
- args=$(get_args "$1")
-
- # Define an empty function for the trace event
- cat <<EOF
-static inline void trace_$name($args)
-{
-}
-EOF
-}
-
-linetoh_end_nop()
-{
- return
-}
-
-linetoc_begin_nop()
-{
- return
-}
-
-linetoc_nop()
-{
- # No need for function definitions in nop backend
- return
-}
-
-linetod_nop()
-{
- # Used when "disabled" events are processed
- return
-}
-
-linetostap_nop()
-{
- # Used when "disabled" events are processed
- return
-}
-
-linetoc_end_nop()
-{
- return
-}
-
-linetoh_begin_simple()
-{
- cat <<EOF
-#include "trace/simple.h"
-EOF
-
- simple_event_num=0
-}
-
-cast_args_to_uint64_t()
-{
- local arg
- for arg in $(get_argnames "$1", ","); do
- printf "%s" "(uint64_t)(uintptr_t)$arg"
- done
-}
-
-linetoh_simple()
-{
- local name args argc trace_args
- name=$(get_name "$1")
- args=$(get_args "$1")
- argc=$(get_argc "$1")
-
- trace_args="$simple_event_num"
- if [ "$argc" -gt 0 ]
- then
- trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
- fi
-
- cat <<EOF
-static inline void trace_$name($args)
-{
- trace$argc($trace_args);
-}
-EOF
-
- simple_event_num=$((simple_event_num + 1))
-}
-
-linetoh_end_simple()
-{
- cat <<EOF
-#define NR_TRACE_EVENTS $simple_event_num
-extern TraceEvent trace_list[NR_TRACE_EVENTS];
-EOF
-}
-
-linetoc_begin_simple()
-{
- cat <<EOF
-#include "trace.h"
-
-TraceEvent trace_list[] = {
-EOF
- simple_event_num=0
-
-}
-
-linetoc_simple()
-{
- local name
- name=$(get_name "$1")
- cat <<EOF
-{.tp_name = "$name", .state=0},
-EOF
- simple_event_num=$((simple_event_num + 1))
-}
-
-linetoc_end_simple()
-{
- cat <<EOF
-};
-EOF
-}
-
-#STDERR
-linetoh_begin_stderr()
-{
- cat <<EOF
-#include <stdio.h>
-#include "trace/stderr.h"
-
-extern TraceEvent trace_list[];
-EOF
-
- stderr_event_num=0
-}
-
-linetoh_stderr()
-{
- local name args argnames argc fmt
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1" ",")
- argc=$(get_argc "$1")
- fmt=$(get_fmt "$1")
-
- if [ "$argc" -gt 0 ]; then
- argnames=", $argnames"
- fi
-
- cat <<EOF
-static inline void trace_$name($args)
-{
- if (trace_list[$stderr_event_num].state != 0) {
- fprintf(stderr, "$name " $fmt "\n" $argnames);
- }
-}
-EOF
- stderr_event_num=$((stderr_event_num + 1))
-
-}
-
-linetoh_end_stderr()
-{
- cat <<EOF
-#define NR_TRACE_EVENTS $stderr_event_num
-EOF
-}
-
-linetoc_begin_stderr()
-{
- cat <<EOF
-#include "trace.h"
-
-TraceEvent trace_list[] = {
-EOF
- stderr_event_num=0
-}
-
-linetoc_stderr()
-{
- local name
- name=$(get_name "$1")
- cat <<EOF
-{.tp_name = "$name", .state=0},
-EOF
- stderr_event_num=$(($stderr_event_num + 1))
-}
-
-linetoc_end_stderr()
-{
- cat <<EOF
-};
-EOF
-}
-#END OF STDERR
-
-# Clean up after UST headers which pollute the namespace
-ust_clean_namespace() {
- cat <<EOF
-#undef mutex_lock
-#undef mutex_unlock
-#undef inline
-#undef wmb
-EOF
-}
-
-linetoh_begin_ust()
-{
- echo "#include <ust/tracepoint.h>"
- ust_clean_namespace
-}
-
-linetoh_ust()
-{
- local name args argnames
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
-
- cat <<EOF
-DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
-#define trace_$name trace_ust_$name
-EOF
-}
-
-linetoh_end_ust()
-{
- return
-}
-
-linetoc_begin_ust()
-{
- cat <<EOF
-#include <ust/marker.h>
-$(ust_clean_namespace)
-#include "trace.h"
-EOF
-}
-
-linetoc_ust()
-{
- local name args argnames fmt
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
- [ -z "$argnames" ] || argnames=", $argnames"
- fmt=$(get_fmt "$1")
-
- cat <<EOF
-DEFINE_TRACE(ust_$name);
-
-static void ust_${name}_probe($args)
-{
- trace_mark(ust, $name, $fmt$argnames);
-}
-EOF
-
- # Collect names for later
- names="$names $name"
-}
-
-linetoc_end_ust()
-{
- cat <<EOF
-static void __attribute__((constructor)) trace_init(void)
-{
-EOF
-
- for name in $names; do
- cat <<EOF
- register_trace_ust_$name(ust_${name}_probe);
-EOF
- done
-
- echo "}"
-}
-
-linetoh_begin_dtrace()
-{
- cat <<EOF
-#include "trace-dtrace.h"
-EOF
-}
-
-linetoh_dtrace()
-{
- local name args argnames nameupper
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
-
- nameupper=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
-
- # Define an empty function for the trace event
- cat <<EOF
-static inline void trace_$name($args) {
- QEMU_${nameupper}($argnames);
-}
-EOF
-}
-
-linetoh_end_dtrace()
-{
- return
-}
-
-linetoc_begin_dtrace()
-{
- return
-}
-
-linetoc_dtrace()
-{
- # No need for function definitions in dtrace backend
- return
-}
-
-linetoc_end_dtrace()
-{
- return
-}
-
-linetod_begin_dtrace()
-{
- cat <<EOF
-provider qemu {
-EOF
-}
-
-linetod_dtrace()
-{
- local name args
- name=$(get_name "$1")
- args=$(get_args "$1")
-
- # DTrace provider syntax expects foo() for empty
- # params, not foo(void)
- if [ "$args" = "void" ]; then
- args=""
- fi
-
- # Define prototype for probe arguments
- cat <<EOF
- probe $name($args);
-EOF
-}
-
-linetod_end_dtrace()
-{
- cat <<EOF
-};
-EOF
-}
-
-linetostap_begin_dtrace()
-{
- return
-}
-
-linetostap_dtrace()
-{
- local i arg name args arglist
- name=$(get_name "$1")
- args=$(get_args "$1")
- arglist=$(get_argnames "$1", "")
-
- # Define prototype for probe arguments
- cat <<EOF
-probe $probeprefix.$name = process("$binary").mark("$name")
-{
-EOF
-
- i=1
- for arg in $arglist
- do
- # postfix reserved words with '_'
- case "$arg" in
- limit|in|next|self)
- arg="${arg}_"
- ;;
- esac
- cat <<EOF
- $arg = \$arg$i;
-EOF
- i="$((i+1))"
- done
-
- cat <<EOF
-}
-EOF
-}
-
-linetostap_end_dtrace()
-{
- return
-}
-
-# Process stdin by calling begin, line, and end functions for the backend
-convert()
-{
- local begin process_line end str name NAME enabled
- begin="lineto$1_begin_$backend"
- process_line="lineto$1_$backend"
- end="lineto$1_end_$backend"
-
- "$begin"
-
- while read -r str; do
- # Skip comments and empty lines
- test -z "${str%%#*}" && continue
-
- echo
- # Process the line. The nop backend handles disabled lines.
- if has_property "$str" "disable"; then
- "lineto$1_nop" "$str"
- enabled=0
- else
- "$process_line" "$str"
- enabled=1
- fi
- if [ "$1" = "h" ]; then
- name=$(get_name "$str")
- NAME=$(echo $name | LC_ALL=C tr '[a-z]' '[A-Z]')
- echo "#define TRACE_${NAME}_ENABLED ${enabled}"
- fi
- done
-
- echo
- "$end"
-}
-
-tracetoh()
-{
- cat <<EOF
-#ifndef TRACE_H
-#define TRACE_H
-
-/* This file is autogenerated by tracetool, do not edit. */
-
-#include "qemu-common.h"
-EOF
- convert h
- echo "#endif /* TRACE_H */"
-}
-
-tracetoc()
-{
- echo "/* This file is autogenerated by tracetool, do not edit. */"
- convert c
-}
-
-tracetod()
-{
- if [ $backend != "dtrace" ]; then
- echo "DTrace probe generator not applicable to $backend backend"
- exit 1
- fi
- echo "/* This file is autogenerated by tracetool, do not edit. */"
- convert d
-}
-
-tracetostap()
-{
- if [ $backend != "dtrace" ]; then
- echo "SystemTAP tapset generator not applicable to $backend backend"
- exit 1
- fi
- if [ -z "$binary" ]; then
- echo "--binary is required for SystemTAP tapset generator"
- exit 1
- fi
- if [ -z "$probeprefix" -a -z "$targettype" ]; then
- echo "--target-type is required for SystemTAP tapset generator"
- exit 1
- fi
- if [ -z "$probeprefix" -a -z "$targetarch" ]; then
- echo "--target-arch is required for SystemTAP tapset generator"
- exit 1
- fi
- if [ -z "$probeprefix" ]; then
- probeprefix="qemu.$targettype.$targetarch";
- fi
- echo "/* This file is autogenerated by tracetool, do not edit. */"
- convert stap
-}
-
-
-backend=
-output=
-binary=
-targettype=
-targetarch=
-probeprefix=
-
-
-until [ -z "$1" ]
-do
- case "$1" in
- "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
-
- "--binary") shift ; binary="$1" ;;
- "--target-arch") shift ; targetarch="$1" ;;
- "--target-type") shift ; targettype="$1" ;;
- "--probe-prefix") shift ; probeprefix="$1" ;;
-
- "-h" | "-c" | "-d") output="${1#-}" ;;
- "--stap") output="${1#--}" ;;
-
- "--check-backend") exit 0 ;; # used by ./configure to test for backend
-
- "--list-backends") # used by ./configure to list available backends
- echo "nop simple stderr ust dtrace"
- exit 0
- ;;
-
- *)
- usage;;
- esac
- shift
-done
-
-if [ "$backend" = "" -o "$output" = "" ]; then
- usage
-fi
-
-gen="traceto$output"
-"$gen"
-
-exit 0
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
new file mode 100755
index 0000000..fe2ea34
--- /dev/null
+++ b/scripts/tracetool.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Command-line wrapper for the tracetool machinery.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+import sys
+import getopt
+
+from tracetool import error_write, out
+import tracetool.backend
+import tracetool.format
+
+
+_SCRIPT = ""
+
+def error_opt(msg = None):
+ if msg is not None:
+ error_write("Error: " + msg + "\n")
+
+ backend_descr = "\n".join([ " %-15s %s" % (n, d)
+ for n,d in tracetool.backend.get_list() ])
+ format_descr = "\n".join([ " %-15s %s" % (n, d)
+ for n,d in tracetool.format.get_list() ])
+ error_write("""\
+Usage: %(script)s --format=<format> --backend=<backend> [<options>]
+
+Backends:
+%(backends)s
+
+Formats:
+%(formats)s
+
+Options:
+ --help This help message.
+ --list-backends Print list of available backends.
+ --check-backend Check if the given backend is valid.
+""" % {
+ "script" : _SCRIPT,
+ "backends" : backend_descr,
+ "formats" : format_descr,
+ })
+
+ if msg is None:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+
+def main(args):
+ global _SCRIPT
+ _SCRIPT = args[0]
+
+ long_opts = [ "backend=", "format=", "help", "list-backends", "check-backend" ]
+ long_opts += [ "binary=", "target-type=", "target-arch=", "probe-prefix=" ]
+
+ try:
+ opts, args = getopt.getopt(args[1:], "", long_opts)
+ except getopt.GetoptError as err:
+ error_opt(str(err))
+
+ check_backend = False
+ arg_backend = ""
+ arg_format = ""
+ for opt, arg in opts:
+ if opt == "--help":
+ error_opt()
+
+ elif opt == "--backend":
+ arg_backend = arg
+ elif opt == "--format":
+ arg_format = arg
+
+ elif opt == "--list-backends":
+ backends = tracetool.backend.get_list()
+ out(", ".join([ b for b,_ in backends ]))
+ sys.exit(0)
+ elif opt == "--check-backend":
+ check_backend = True
+
+ else:
+ error_opt("unhandled option: %s" % opt)
+
+ if arg_backend is None:
+ error_opt("backend not set")
+
+ if check_backend:
+ if tracetool.backend.exists(arg_backend):
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+ try:
+ tracetool.generate(sys.stdin, arg_format, arg_backend)
+ except tracetool.TracetoolError as e:
+ error_opt(str(e))
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
new file mode 100644
index 0000000..1719bb4
--- /dev/null
+++ b/scripts/tracetool/__init__.py
@@ -0,0 +1,262 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Machinery for generating tracing-related intermediate files.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+import re
+import sys
+
+import tracetool.format
+import tracetool.backend
+
+
+def error_write(*lines):
+ """Write a set of error lines."""
+ sys.stderr.writelines("\n".join(lines) + "\n")
+
+def error(*lines):
+ """Write a set of error lines and exit."""
+ error_write(*lines)
+ sys.exit(1)
+
+
+def out(*lines, **kwargs):
+ """Write a set of output lines.
+
+ You can use kwargs as a shorthand for mapping variables when formating all
+ the strings in lines.
+ """
+ lines = [ l % kwargs for l in lines ]
+ sys.stdout.writelines("\n".join(lines) + "\n")
+
+
+class Arguments:
+ """Event arguments description."""
+
+ def __init__(self, args):
+ """
+ Parameters
+ ----------
+ args :
+ List of (type, name) tuples.
+ """
+ self._args = args
+
+ @staticmethod
+ def build(arg_str):
+ """Build and Arguments instance from an argument string.
+
+ Parameters
+ ----------
+ arg_str : str
+ String describing the event arguments.
+ """
+ res = []
+ for arg in arg_str.split(","):
+ arg = arg.strip()
+ parts = arg.split()
+ head, sep, tail = parts[-1].rpartition("*")
+ parts = parts[:-1]
+ if tail == "void":
+ assert len(parts) == 0 and sep == ""
+ continue
+ arg_type = " ".join(parts + [ " ".join([head, sep]).strip() ]).strip()
+ res.append((arg_type, tail))
+ return Arguments(res)
+
+ def __iter__(self):
+ """Iterate over the (type, name) pairs."""
+ return iter(self._args)
+
+ def __len__(self):
+ """Number of arguments."""
+ return len(self._args)
+
+ def __str__(self):
+ """String suitable for declaring function arguments."""
+ if len(self._args) == 0:
+ return "void"
+ else:
+ return ", ".join([ " ".join([t, n]) for t,n in self._args ])
+
+ def __repr__(self):
+ """Evaluable string representation for this object."""
+ return "Arguments(\"%s\")" % str(self)
+
+ def names(self):
+ """List of argument names."""
+ return [ name for _, name in self._args ]
+
+ def types(self):
+ """List of argument types."""
+ return [ type_ for type_, _ in self._args ]
+
+
+class Event(object):
+ """Event description.
+
+ Attributes
+ ----------
+ name : str
+ The event name.
+ fmt : str
+ The event format string.
+ properties : set(str)
+ Properties of the event.
+ args : Arguments
+ The event arguments.
+ """
+
+ _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
+
+ _VALID_PROPS = set(["disable"])
+
+ def __init__(self, name, props, fmt, args):
+ """
+ Parameters
+ ----------
+ name : string
+ Event name.
+ props : list of str
+ Property names.
+ fmt : str
+ Event printing format.
+ args : Arguments
+ Event arguments.
+ """
+ self.name = name
+ self.properties = props
+ self.fmt = fmt
+ self.args = args
+
+ unknown_props = set(self.properties) - self._VALID_PROPS
+ if len(unknown_props) > 0:
+ raise ValueError("Unknown properties: %s" % ", ".join(unknown_props))
+
+ @staticmethod
+ def build(line_str):
+ """Build an Event instance from a string.
+
+ Parameters
+ ----------
+ line_str : str
+ Line describing the event.
+ """
+ m = Event._CRE.match(line_str)
+ assert m is not None
+ groups = m.groupdict('')
+
+ name = groups["name"]
+ props = groups["props"].split()
+ fmt = groups["fmt"]
+ args = Arguments.build(groups["args"])
+
+ return Event(name, props, fmt, args)
+
+ def __repr__(self):
+ """Evaluable string representation for this object."""
+ return "Event('%s %s(%s) %s')" % (" ".join(self.properties),
+ self.name,
+ self.args,
+ self.fmt)
+
+def _read_events(fobj):
+ res = []
+ for line in fobj:
+ if not line.strip():
+ continue
+ if line.lstrip().startswith('#'):
+ continue
+ res.append(Event.build(line))
+ return res
+
+
+class TracetoolError (Exception):
+ """Exception for calls to generate."""
+ pass
+
+
+def try_import(mod_name, attr_name = None, attr_default = None):
+ """Try to import a module and get an attribute from it.
+
+ Parameters
+ ----------
+ mod_name : str
+ Module name.
+ attr_name : str, optional
+ Name of an attribute in the module.
+ attr_default : optional
+ Default value if the attribute does not exist in the module.
+
+ Returns
+ -------
+ A pair indicating whether the module could be imported and the module or
+ object or attribute value.
+ """
+ try:
+ module = __import__(mod_name, fromlist=["__package__"])
+ if attr_name is None:
+ return True, module
+ return True, getattr(module, str(attr_name), attr_default)
+ except ImportError:
+ return False, None
+
+
+def generate(fevents, format, backend):
+ """Generate the output for the given (format, backend) pair.
+
+ Parameters
+ ----------
+ fevents : file
+ Event description file.
+ format : str
+ Output format name.
+ backend : str
+ Output backend name.
+ """
+ # fix strange python error (UnboundLocalError tracetool)
+ import tracetool
+
+ format = str(format)
+ if len(format) is 0:
+ raise TracetoolError("format not set")
+ mformat = format.replace("-", "_")
+ if not tracetool.format.exists(mformat):
+ raise TracetoolError("unknown format: %s" % format)
+
+ backend = str(backend)
+ if len(backend) is 0:
+ raise TracetoolError("backend not set")
+ mbackend = backend.replace("-", "_")
+ if not tracetool.backend.exists(mbackend):
+ raise TracetoolError("unknown backend: %s" % backend)
+
+ if not tracetool.backend.compatible(mbackend, mformat):
+ raise TracetoolError("backend '%s' not compatible with format '%s'" %
+ (backend, format))
+
+ events = _read_events(fevents)
+
+ if backend == "nop":
+ ( e.properies.add("disable") for e in events )
+
+ tracetool.format.generate_begin(mformat, events)
+ tracetool.backend.generate("nop", format,
+ [ e
+ for e in events
+ if "disable" in e.properties ])
+ tracetool.backend.generate(backend, format,
+ [ e
+ for e in events
+ if "disable" not in e.properties ])
+ tracetool.format.generate_end(mformat, events)
diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py
new file mode 100644
index 0000000..34b7ed8
--- /dev/null
+++ b/scripts/tracetool/backend/__init__.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Backend management.
+
+
+Creating new backends
+---------------------
+
+A new backend named 'foo-bar' corresponds to Python module
+'tracetool/backend/foo_bar.py'.
+
+A backend module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All backends must generate their contents through the 'tracetool.out' routine.
+
+
+Backend functions
+-----------------
+
+======== =======================================================================
+Function Description
+======== =======================================================================
+<format> Called to generate the format- and backend-specific code for each of
+ the specified events. If the function does not exist, the backend is
+ considered not compatible with the given format.
+======== =======================================================================
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+import pkgutil
+
+import tracetool
+
+
+def get_list():
+ """Get a list of (name, description) pairs."""
+ res = [("nop", "Tracing disabled.")]
+ for _, modname, _ in pkgutil.iter_modules(tracetool.backend.__path__):
+ module = tracetool.try_import("tracetool.backend." + modname)
+
+ # just in case; should never fail unless non-module files are put there
+ if not module[0]:
+ continue
+ module = module[1]
+
+ doc = module.__doc__
+ if doc is None:
+ doc = ""
+ doc = doc.strip().split("\n")[0]
+
+ name = modname.replace("_", "-")
+ res.append((name, doc))
+ return res
+
+
+def exists(name):
+ """Return whether the given backend exists."""
+ if len(name) == 0:
+ return False
+ if name == "nop":
+ return True
+ name = name.replace("-", "_")
+ return tracetool.try_import("tracetool.backend." + name)[1]
+
+
+def compatible(backend, format):
+ """Whether a backend is compatible with the given format."""
+ if not exists(backend):
+ raise ValueError("unknown backend: %s" % backend)
+
+ backend = backend.replace("-", "_")
+ format = format.replace("-", "_")
+
+ if backend == "nop":
+ return True
+ else:
+ func = tracetool.try_import("tracetool.backend." + backend,
+ format, None)[1]
+ return func is not None
+
+
+def _empty(events):
+ pass
+
+def generate(backend, format, events):
+ """Generate the per-event output for the given (backend, format) pair."""
+ if not compatible(backend, format):
+ raise ValueError("backend '%s' not compatible with format '%s'" %
+ (backend, format))
+
+ backend = backend.replace("-", "_")
+ format = format.replace("-", "_")
+
+ if backend == "nop":
+ func = tracetool.try_import("tracetool.format." + format,
+ "nop", _empty)[1]
+ else:
+ func = tracetool.try_import("tracetool.backend." + backend,
+ format, None)[1]
+
+ func(events)
diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__init__.py
new file mode 100644
index 0000000..0e4baf0
--- /dev/null
+++ b/scripts/tracetool/format/__init__.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Format management.
+
+
+Creating new formats
+--------------------
+
+A new format named 'foo-bar' corresponds to Python module
+'tracetool/format/foo_bar.py'.
+
+A format module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All formats must generate their contents through the 'tracetool.out' routine.
+
+
+Format functions
+----------------
+
+All the following functions are optional, and no output will be generated if
+they do not exist.
+
+======== =======================================================================
+Function Description
+======== =======================================================================
+begin Called to generate the format-specific file header.
+end Called to generate the format-specific file footer.
+nop Called to generate the per-event contents when the event is disabled or
+ the selected backend is 'nop'.
+======== =======================================================================
+"""
+
+__author__ = "LluÃs Vilanova <vilanova at ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova at ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha at linux.vnet.ibm.com"
+
+
+import pkgutil
+
+import tracetool
+
+
+def get_list():
+ """Get a list of (name, description) pairs."""
+ res = []
+ for _, modname, _ in pkgutil.iter_modules(tracetool.format.__path__):
+ module = tracetool.try_import("tracetool.format." + modname)
+
+ # just in case; should never fail unless non-module files are put there
+ if not module[0]:
+ continue
+ module = module[1]
+
+ doc = module.__doc__
+ if doc is None:
+ doc = ""
+ doc = doc.strip().split("\n")[0]
+
+ name = modname.replace("_", "-")
+ res.append((name, doc))
+ return res
+
+
+def exists(name):
+ """Return whether the given format exists."""
+ if len(name) == 0:
+ return False
+ name = name.replace("-", "_")
+ return tracetool.try_import("tracetool.format." + name)[1]
+
+
+def _empty(events):
+ pass
+
+def generate_begin(name, events):
+ """Generate the header of the format-specific file."""
+ if not exists(name):
+ raise ValueError("unknown format: %s" % name)
+
+ name = name.replace("-", "_")
+ func = tracetool.try_import("tracetool.format." + name,
+ "begin", _empty)[1]
+ func(events)
+
+def generate_end(name, events):
+ """Generate the footer of the format-specific file."""
+ if not exists(name):
+ raise ValueError("unknown format: %s" % name)
+
+ name = name.replace("-", "_")
+ func = tracetool.try_import("tracetool.format." + name,
+ "end", _empty)[1]
+ func(events)
commit 25b9e14e78bf9790cdee12d57c45898e86866a24
Merge: b26d712... 06ddea4...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Apr 18 07:56:18 2012 -0500
Merge remote-tracking branch 'spice/spice.v52' into staging
* spice/spice.v52:
qxl-render: fix broken vnc+spice since commit f934493
qxl: set default values of vram*_size_mb to -1
trace-events: remove unused qxl_vga_ioport_while_not_in_vga_mode
commit b26d712ecc9558fcd2a77a0b677a18d4919228bd
Merge: 6b034aa... c7020c9...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Apr 18 07:55:56 2012 -0500
Merge remote-tracking branch 'kraxel/usb.46' into staging
* kraxel/usb.46: (21 commits)
usb-ehci: drop assert()
usb-redir: Notify our peer when we reject a device due to a speed mismatch
usb-ehci: Drop unused sofv value
usb-host: rewrite usb_linux_update_endp_table
usb: use USBDescriptor for endpoint descriptors.
usb: use USBDescriptor for interface descriptors.
usb: use USBDescriptor for config descriptors.
usb: use USBDescriptor for device qualifier descriptors.
usb: add USBDescriptor, use for device descriptors.
usb-ehci: frindex always is a 14 bits counter
usb-ehci: fix ehci_child_detach
usb-hub: add tracepoints
usb_packet_set_state: handle p->ep == NULL
usb-host: add property to turn off pipelining
usb-host: add usb packet to request tracepoints
usb-host: trace canceled requests
usb-host: trace emulated requests
Add bootindex support to usb-host and usb-redir
usb-uhci: queuing fix
usb-uhci: stop queue filling when we find a in-flight td
...
commit 06ddea49f8127bd055dbc7e83df896d9311c88cc
Author: Alon Levy <alevy at redhat.com>
Date: Wed Apr 18 12:27:00 2012 +0300
qxl-render: fix broken vnc+spice since commit f934493
Notify any listeners such as vnc that the displaysurface has been
changed, otherwise they will segfault when first accessing the freed old
displaysurface data.
Signed-off-by: Alon Levy <alevy at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 28ab182..f7f1bfd 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -127,6 +127,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
qxl->guest_primary.surface.width,
qxl->guest_primary.surface.height);
}
+ dpy_resize(vga->ds);
}
for (i = 0; i < qxl->num_dirty_rects; i++) {
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
commit 79ce3567017e32ac96f7de7a8b04ed75ee710f89
Author: Alon Levy <alevy at redhat.com>
Date: Thu Mar 29 22:24:38 2012 +0200
qxl: set default values of vram*_size_mb to -1
The addition of those values caused a regression where not specifying
any value for the vram bar size would result in a 4096 _byte_ surface
area. This is ok for the windows driver but causes the X driver to be
unusable. Also, it's a regression. This patch returns the default
behavior of having a 64 megabyte vram BAR.
Signed-off-by: Alon Levy <alevy at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/qxl.c b/hw/qxl.c
index 47a162e..db2318e 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1959,8 +1959,8 @@ static Property qxl_properties[] = {
DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1),
- DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0),
- DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0),
+ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
+ DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
DEFINE_PROP_END_OF_LIST(),
};
commit a9257af0b9735dbf7e8a52b4bf8d6c80dd4fc446
Author: Alon Levy <alevy at redhat.com>
Date: Wed Mar 28 11:30:08 2012 +0200
trace-events: remove unused qxl_vga_ioport_while_not_in_vga_mode
The resulting stp file fails to load because of an unresolvable probe.
Signed-off-by: Alon Levy <alevy at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/trace-events b/trace-events
index a5f276d..0e25d20 100644
--- a/trace-events
+++ b/trace-events
@@ -781,7 +781,6 @@ qxl_spice_reset_memslots(int qid) "%d"
qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]"
qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d"
qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d"
-qxl_vga_ioport_while_not_in_vga_mode(int qid) "%d (int qid, reset to VGA mode because of VGA io)"
# hw/qxl-render.c
qxl_render_blit_guest_primary_initialized(void) ""
commit 4c9f8d1b4eb0e1a7e69df6373e9c2d40a929494d
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date: Tue Apr 17 16:56:51 2012 +0000
xen: add a dummy xc_hvm_inject_msi for Xen < 4.2
xc_hvm_inject_msi is only available on Xen >= 4.2: add a dummy
compatibility function for Xen < 4.2.
Also enable msi support only on Xen >= 4.2.
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Acked-by: Anthony PERARD <anthony.perard at citrix.com>
diff --git a/hw/pc.c b/hw/pc.c
index 1f5aacb..4d34a33 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -916,7 +916,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
msi_supported = true;
}
- if (xen_enabled()) {
+ if (xen_msi_support()) {
msi_supported = true;
}
diff --git a/hw/xen.h b/hw/xen.h
index e5926b7..3ae4cd0 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -57,4 +57,14 @@ void xen_register_framebuffer(struct MemoryRegion *mr);
# define HVM_MAX_VCPUS 32
#endif
+static inline int xen_msi_support(void)
+{
+#if defined(CONFIG_XEN_CTRL_INTERFACE_VERSION) \
+ && CONFIG_XEN_CTRL_INTERFACE_VERSION >= 420
+ return xen_enabled();
+#else
+ return 0;
+#endif
+}
+
#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 0409ac7..7043c14 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -133,6 +133,21 @@ static inline int xc_fd(xc_interface *xen_xc)
}
#endif
+/* Xen before 4.2 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 420
+static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
+ uint64_t addr, uint32_t data)
+{
+ return -ENOSYS;
+}
+#else
+static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
+ uint64_t addr, uint32_t data)
+{
+ return xc_hvm_inject_msi(xen_xc, dom, addr, data);
+}
+#endif
+
void destroy_hvm_domain(void);
#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/xen-all.c b/xen-all.c
index a08eec0..bdf9c0f 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -129,7 +129,7 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
{
- xc_hvm_inject_msi(xen_xc, xen_domid, addr, data);
+ xen_xc_hvm_inject_msi(xen_xc, xen_domid, addr, data);
}
static void xen_suspend_notifier(Notifier *notifier, void *data)
commit 8688e0652dc4fde816316fbd10869e3e33411968
Author: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Date: Tue Apr 17 17:04:18 2012 +0000
xen,configure: detect Xen 4.2
Xen 4.2 is the first to support xc_hvm_inject_msi: use it to determine
if we are running on it.
Signed-off-by: Stefano Stabellini <stefano.stabellini at eu.citrix.com>
Acked-by: Anthony PERARD <anthony.perard at citrix.com>
diff --git a/configure b/configure
index 1d94acd..38f45f3 100755
--- a/configure
+++ b/configure
@@ -1398,6 +1398,31 @@ int main(void) {
xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
xc_gnttab_open(NULL, 0);
xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
+ xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000);
+ return 0;
+}
+EOF
+ compile_prog "" "$xen_libs"
+ ) ; then
+ xen_ctrl_version=420
+ xen=yes
+
+ elif (
+ cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+#include <stdint.h>
+#include <xen/hvm/hvm_info_table.h>
+#if !defined(HVM_MAX_VCPUS)
+# error HVM_MAX_VCPUS not defined
+#endif
+int main(void) {
+ xc_interface *xc;
+ xs_daemon_open();
+ xc = xc_interface_open(0, 0, 0);
+ xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+ xc_gnttab_open(NULL, 0);
+ xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
return 0;
}
EOF
commit 6e7a7f3d9bc2031b4c93c05400b18775ba1b1f55
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:43 2012 +0200
Allow controlling volume with PulseAudio backend
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 6f50c1c..e6708d0 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -677,15 +677,103 @@ static void qpa_fini_in (HWVoiceIn *hw)
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
- (void) hw;
- (void) cmd;
+ PAVoiceOut *pa = (PAVoiceOut *) hw;
+ pa_operation *op;
+ pa_cvolume v;
+ paaudio *g = &glob_paaudio;
+
+ pa_cvolume_init (&v);
+
+ switch (cmd) {
+ case VOICE_VOLUME:
+ {
+ SWVoiceOut *sw;
+ va_list ap;
+
+ va_start (ap, cmd);
+ sw = va_arg (ap, SWVoiceOut *);
+ va_end (ap);
+
+ v.channels = 2;
+ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
+ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
+
+ pa_threaded_mainloop_lock (g->mainloop);
+
+ op = pa_context_set_sink_input_volume (g->context,
+ pa_stream_get_index (pa->stream),
+ &v, NULL, NULL);
+ if (!op)
+ qpa_logerr (pa_context_errno (g->context),
+ "set_sink_input_volume() failed\n");
+ else
+ pa_operation_unref (op);
+
+ op = pa_context_set_sink_input_mute (g->context,
+ pa_stream_get_index (pa->stream),
+ sw->vol.mute, NULL, NULL);
+ if (!op) {
+ qpa_logerr (pa_context_errno (g->context),
+ "set_sink_input_mute() failed\n");
+ } else {
+ pa_operation_unref (op);
+ }
+
+ pa_threaded_mainloop_unlock (g->mainloop);
+ }
+ }
return 0;
}
static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
- (void) hw;
- (void) cmd;
+ PAVoiceIn *pa = (PAVoiceIn *) hw;
+ pa_operation *op;
+ pa_cvolume v;
+ paaudio *g = &glob_paaudio;
+
+ pa_cvolume_init (&v);
+
+ switch (cmd) {
+ case VOICE_VOLUME:
+ {
+ SWVoiceIn *sw;
+ va_list ap;
+
+ va_start (ap, cmd);
+ sw = va_arg (ap, SWVoiceIn *);
+ va_end (ap);
+
+ v.channels = 2;
+ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
+ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
+
+ pa_threaded_mainloop_lock (g->mainloop);
+
+ /* FIXME: use the upcoming "set_source_output_{volume,mute}" */
+ op = pa_context_set_source_volume_by_index (g->context,
+ pa_stream_get_device_index (pa->stream),
+ &v, NULL, NULL);
+ if (!op) {
+ qpa_logerr (pa_context_errno (g->context),
+ "set_source_volume() failed\n");
+ } else {
+ pa_operation_unref(op);
+ }
+
+ op = pa_context_set_source_mute_by_index (g->context,
+ pa_stream_get_index (pa->stream),
+ sw->vol.mute, NULL, NULL);
+ if (!op) {
+ qpa_logerr (pa_context_errno (g->context),
+ "set_source_mute() failed\n");
+ } else {
+ pa_operation_unref (op);
+ }
+
+ pa_threaded_mainloop_unlock (g->mainloop);
+ }
+ }
return 0;
}
@@ -822,5 +910,6 @@ struct audio_driver pa_audio_driver = {
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (PAVoiceOut),
- .voice_size_in = sizeof (PAVoiceIn)
+ .voice_size_in = sizeof (PAVoiceIn),
+ .ctl_caps = VOICE_VOLUME_CAP
};
commit a394aed235d6b3f048eeae83289f4d21eca7023c
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:42 2012 +0200
configure: pa_simple is not needed anymore
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/configure b/configure
index 1d94acd..2d62d12 100755
--- a/configure
+++ b/configure
@@ -1855,9 +1855,9 @@ for drv in $audio_drv_list; do
;;
pa)
- audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \
- "pa_simple *s = 0; pa_simple_free(s); return 0;"
- libs_softmmu="-lpulse -lpulse-simple $libs_softmmu"
+ audio_drv_probe $drv pulse/mainloop.h "-lpulse" \
+ "pa_mainloop *m = 0; pa_mainloop_free (m); return 0;"
+ libs_softmmu="-lpulse $libs_softmmu"
audio_pt_int="yes"
;;
commit ea9ebc2ce69198f7aca4b43652824c5d621ac978
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:41 2012 +0200
Do not use pa_simple PulseAudio API
Unfortunately, pa_simple is a limited API which doesn't let us
retrieve the associated pa_stream. It is needed to control the volume
of the stream.
In v4:
- add missing braces
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/audio/paaudio.c b/audio/paaudio.c
index d1f3912..6f50c1c 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -2,8 +2,7 @@
#include "qemu-common.h"
#include "audio.h"
-#include <pulse/simple.h>
-#include <pulse/error.h>
+#include <pulse/pulseaudio.h>
#define AUDIO_CAP "pulseaudio"
#include "audio_int.h"
@@ -15,7 +14,7 @@ typedef struct {
int live;
int decr;
int rpos;
- pa_simple *s;
+ pa_stream *stream;
void *pcm_buf;
struct audio_pt pt;
} PAVoiceOut;
@@ -26,17 +25,23 @@ typedef struct {
int dead;
int incr;
int wpos;
- pa_simple *s;
+ pa_stream *stream;
void *pcm_buf;
struct audio_pt pt;
+ const void *read_data;
+ size_t read_index, read_length;
} PAVoiceIn;
-static struct {
+typedef struct {
int samples;
char *server;
char *sink;
char *source;
-} conf = {
+ pa_threaded_mainloop *mainloop;
+ pa_context *context;
+} paaudio;
+
+static paaudio glob_paaudio = {
.samples = 4096,
};
@@ -51,6 +56,126 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
}
+#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \
+ do { \
+ if (!(expression)) { \
+ if (rerror) { \
+ *(rerror) = pa_context_errno ((c)->context); \
+ } \
+ goto label; \
+ } \
+ } while (0);
+
+#define CHECK_DEAD_GOTO(c, stream, rerror, label) \
+ do { \
+ if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
+ !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
+ if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
+ ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
+ if (rerror) { \
+ *(rerror) = pa_context_errno ((c)->context); \
+ } \
+ } else { \
+ if (rerror) { \
+ *(rerror) = PA_ERR_BADSTATE; \
+ } \
+ } \
+ goto label; \
+ } \
+ } while (0);
+
+static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
+{
+ paaudio *g = &glob_paaudio;
+
+ pa_threaded_mainloop_lock (g->mainloop);
+
+ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+
+ while (length > 0) {
+ size_t l;
+
+ while (!p->read_data) {
+ int r;
+
+ r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
+ CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
+
+ if (!p->read_data) {
+ pa_threaded_mainloop_wait (g->mainloop);
+ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+ } else {
+ p->read_index = 0;
+ }
+ }
+
+ l = p->read_length < length ? p->read_length : length;
+ memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
+
+ data = (uint8_t *) data + l;
+ length -= l;
+
+ p->read_index += l;
+ p->read_length -= l;
+
+ if (!p->read_length) {
+ int r;
+
+ r = pa_stream_drop (p->stream);
+ p->read_data = NULL;
+ p->read_length = 0;
+ p->read_index = 0;
+
+ CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
+ }
+ }
+
+ pa_threaded_mainloop_unlock (g->mainloop);
+ return 0;
+
+unlock_and_fail:
+ pa_threaded_mainloop_unlock (g->mainloop);
+ return -1;
+}
+
+static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
+{
+ paaudio *g = &glob_paaudio;
+
+ pa_threaded_mainloop_lock (g->mainloop);
+
+ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+
+ while (length > 0) {
+ size_t l;
+ int r;
+
+ while (!(l = pa_stream_writable_size (p->stream))) {
+ pa_threaded_mainloop_wait (g->mainloop);
+ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+ }
+
+ CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
+
+ if (l > length) {
+ l = length;
+ }
+
+ r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
+ CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
+
+ data = (const uint8_t *) data + l;
+ length -= l;
+ }
+
+ pa_threaded_mainloop_unlock (g->mainloop);
+ return 0;
+
+unlock_and_fail:
+ pa_threaded_mainloop_unlock (g->mainloop);
+ return -1;
+}
+
static void *qpa_thread_out (void *arg)
{
PAVoiceOut *pa = arg;
@@ -77,7 +202,7 @@ static void *qpa_thread_out (void *arg)
}
}
- decr = to_mix = audio_MIN (pa->live, conf.samples >> 2);
+ decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2);
rpos = pa->rpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
@@ -91,8 +216,8 @@ static void *qpa_thread_out (void *arg)
hw->clip (pa->pcm_buf, src, chunk);
- if (pa_simple_write (pa->s, pa->pcm_buf,
- chunk << hw->info.shift, &error) < 0) {
+ if (qpa_simple_write (pa, pa->pcm_buf,
+ chunk << hw->info.shift, &error) < 0) {
qpa_logerr (error, "pa_simple_write failed\n");
return NULL;
}
@@ -169,7 +294,7 @@ static void *qpa_thread_in (void *arg)
}
}
- incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2);
+ incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2);
wpos = pa->wpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
@@ -181,8 +306,8 @@ static void *qpa_thread_in (void *arg)
int chunk = audio_MIN (to_grab, hw->samples - wpos);
void *buf = advance (pa->pcm_buf, wpos);
- if (pa_simple_read (pa->s, buf,
- chunk << hw->info.shift, &error) < 0) {
+ if (qpa_simple_read (pa, buf,
+ chunk << hw->info.shift, &error) < 0) {
qpa_logerr (error, "pa_simple_read failed\n");
return NULL;
}
@@ -283,6 +408,109 @@ static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
}
}
+static void context_state_cb (pa_context *c, void *userdata)
+{
+ paaudio *g = &glob_paaudio;
+
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal (g->mainloop, 0);
+ break;
+
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+ }
+}
+
+static void stream_state_cb (pa_stream *s, void * userdata)
+{
+ paaudio *g = &glob_paaudio;
+
+ switch (pa_stream_get_state (s)) {
+
+ case PA_STREAM_READY:
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ pa_threaded_mainloop_signal (g->mainloop, 0);
+ break;
+
+ case PA_STREAM_UNCONNECTED:
+ case PA_STREAM_CREATING:
+ break;
+ }
+}
+
+static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
+{
+ paaudio *g = &glob_paaudio;
+
+ pa_threaded_mainloop_signal (g->mainloop, 0);
+}
+
+static pa_stream *qpa_simple_new (
+ const char *server,
+ const char *name,
+ pa_stream_direction_t dir,
+ const char *dev,
+ const char *stream_name,
+ const pa_sample_spec *ss,
+ const pa_channel_map *map,
+ const pa_buffer_attr *attr,
+ int *rerror)
+{
+ paaudio *g = &glob_paaudio;
+ int r;
+ pa_stream *stream;
+
+ pa_threaded_mainloop_lock (g->mainloop);
+
+ stream = pa_stream_new (g->context, name, ss, map);
+ if (!stream) {
+ goto fail;
+ }
+
+ pa_stream_set_state_callback (stream, stream_state_cb, g);
+ pa_stream_set_read_callback (stream, stream_request_cb, g);
+ pa_stream_set_write_callback (stream, stream_request_cb, g);
+
+ if (dir == PA_STREAM_PLAYBACK) {
+ r = pa_stream_connect_playback (stream, dev, attr,
+ PA_STREAM_INTERPOLATE_TIMING
+ |PA_STREAM_ADJUST_LATENCY
+ |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
+ } else {
+ r = pa_stream_connect_record (stream, dev, attr,
+ PA_STREAM_INTERPOLATE_TIMING
+ |PA_STREAM_ADJUST_LATENCY
+ |PA_STREAM_AUTO_TIMING_UPDATE);
+ }
+
+ if (r < 0) {
+ goto fail;
+ }
+
+ pa_threaded_mainloop_unlock (g->mainloop);
+
+ return stream;
+
+fail:
+ pa_threaded_mainloop_unlock (g->mainloop);
+
+ if (stream) {
+ pa_stream_unref (stream);
+ }
+
+ qpa_logerr (pa_context_errno (g->context),
+ "stream_new() failed\n");
+
+ return NULL;
+}
+
static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
{
int error;
@@ -306,24 +534,24 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
- pa->s = pa_simple_new (
- conf.server,
+ pa->stream = qpa_simple_new (
+ glob_paaudio.server,
"qemu",
PA_STREAM_PLAYBACK,
- conf.sink,
+ glob_paaudio.sink,
"pcm.playback",
&ss,
NULL, /* channel map */
&ba, /* buffering attributes */
&error
);
- if (!pa->s) {
+ if (!pa->stream) {
qpa_logerr (error, "pa_simple_new for playback failed\n");
goto fail1;
}
audio_pcm_init_info (&hw->info, &obt_as);
- hw->samples = conf.samples;
+ hw->samples = glob_paaudio.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
pa->rpos = hw->rpos;
if (!pa->pcm_buf) {
@@ -342,8 +570,10 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
g_free (pa->pcm_buf);
pa->pcm_buf = NULL;
fail2:
- pa_simple_free (pa->s);
- pa->s = NULL;
+ if (pa->stream) {
+ pa_stream_unref (pa->stream);
+ pa->stream = NULL;
+ }
fail1:
return -1;
}
@@ -361,24 +591,24 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
- pa->s = pa_simple_new (
- conf.server,
+ pa->stream = qpa_simple_new (
+ glob_paaudio.server,
"qemu",
PA_STREAM_RECORD,
- conf.source,
+ glob_paaudio.source,
"pcm.capture",
&ss,
NULL, /* channel map */
NULL, /* buffering attributes */
&error
);
- if (!pa->s) {
+ if (!pa->stream) {
qpa_logerr (error, "pa_simple_new for capture failed\n");
goto fail1;
}
audio_pcm_init_info (&hw->info, &obt_as);
- hw->samples = conf.samples;
+ hw->samples = glob_paaudio.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
pa->wpos = hw->wpos;
if (!pa->pcm_buf) {
@@ -397,8 +627,10 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
g_free (pa->pcm_buf);
pa->pcm_buf = NULL;
fail2:
- pa_simple_free (pa->s);
- pa->s = NULL;
+ if (pa->stream) {
+ pa_stream_unref (pa->stream);
+ pa->stream = NULL;
+ }
fail1:
return -1;
}
@@ -413,9 +645,9 @@ static void qpa_fini_out (HWVoiceOut *hw)
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
- if (pa->s) {
- pa_simple_free (pa->s);
- pa->s = NULL;
+ if (pa->stream) {
+ pa_stream_unref (pa->stream);
+ pa->stream = NULL;
}
audio_pt_fini (&pa->pt, AUDIO_FUNC);
@@ -433,9 +665,9 @@ static void qpa_fini_in (HWVoiceIn *hw)
audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
- if (pa->s) {
- pa_simple_free (pa->s);
- pa->s = NULL;
+ if (pa->stream) {
+ pa_stream_unref (pa->stream);
+ pa->stream = NULL;
}
audio_pt_fini (&pa->pt, AUDIO_FUNC);
@@ -460,37 +692,106 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
/* common */
static void *qpa_audio_init (void)
{
- return &conf;
+ paaudio *g = &glob_paaudio;
+
+ g->mainloop = pa_threaded_mainloop_new ();
+ if (!g->mainloop) {
+ goto fail;
+ }
+
+ g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server);
+ if (!g->context) {
+ goto fail;
+ }
+
+ pa_context_set_state_callback (g->context, context_state_cb, g);
+
+ if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) {
+ qpa_logerr (pa_context_errno (g->context),
+ "pa_context_connect() failed\n");
+ goto fail;
+ }
+
+ pa_threaded_mainloop_lock (g->mainloop);
+
+ if (pa_threaded_mainloop_start (g->mainloop) < 0) {
+ goto unlock_and_fail;
+ }
+
+ for (;;) {
+ pa_context_state_t state;
+
+ state = pa_context_get_state (g->context);
+
+ if (state == PA_CONTEXT_READY) {
+ break;
+ }
+
+ if (!PA_CONTEXT_IS_GOOD (state)) {
+ qpa_logerr (pa_context_errno (g->context),
+ "Wrong context state\n");
+ goto unlock_and_fail;
+ }
+
+ /* Wait until the context is ready */
+ pa_threaded_mainloop_wait (g->mainloop);
+ }
+
+ pa_threaded_mainloop_unlock (g->mainloop);
+
+ return &glob_paaudio;
+
+unlock_and_fail:
+ pa_threaded_mainloop_unlock (g->mainloop);
+fail:
+ AUD_log (AUDIO_CAP, "Failed to initialize PA context");
+ return NULL;
}
static void qpa_audio_fini (void *opaque)
{
- (void) opaque;
+ paaudio *g = opaque;
+
+ if (g->mainloop) {
+ pa_threaded_mainloop_stop (g->mainloop);
+ }
+
+ if (g->context) {
+ pa_context_disconnect (g->context);
+ pa_context_unref (g->context);
+ g->context = NULL;
+ }
+
+ if (g->mainloop) {
+ pa_threaded_mainloop_free (g->mainloop);
+ }
+
+ g->mainloop = NULL;
}
struct audio_option qpa_options[] = {
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
- .valp = &conf.samples,
+ .valp = &glob_paaudio.samples,
.descr = "buffer size in samples"
},
{
.name = "SERVER",
.tag = AUD_OPT_STR,
- .valp = &conf.server,
+ .valp = &glob_paaudio.server,
.descr = "server address"
},
{
.name = "SINK",
.tag = AUD_OPT_STR,
- .valp = &conf.sink,
+ .valp = &glob_paaudio.sink,
.descr = "sink device name"
},
{
.name = "SOURCE",
.tag = AUD_OPT_STR,
- .valp = &conf.source,
+ .valp = &glob_paaudio.source,
.descr = "source device name"
},
{ /* End of list */ }
commit a70c99c6140bd4b0d0bc3ddc7c5fc09a773921c6
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:40 2012 +0200
audio/spice: add support for volume control
Use Spice server volume control API when available.
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index f972110..6f15591 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -202,7 +202,26 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
}
spice_server_playback_stop (&out->sin);
break;
+ case VOICE_VOLUME:
+ {
+#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
+ SWVoiceOut *sw;
+ va_list ap;
+ uint16_t vol[2];
+
+ va_start (ap, cmd);
+ sw = va_arg (ap, SWVoiceOut *);
+ va_end (ap);
+
+ vol[0] = sw->vol.l / ((1ULL << 16) + 1);
+ vol[1] = sw->vol.r / ((1ULL << 16) + 1);
+ spice_server_playback_set_volume (&out->sin, 2, vol);
+ spice_server_playback_set_mute (&out->sin, sw->vol.mute);
+#endif
+ break;
+ }
}
+
return 0;
}
@@ -304,7 +323,26 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
in->active = 0;
spice_server_record_stop (&in->sin);
break;
+ case VOICE_VOLUME:
+ {
+#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
+ SWVoiceIn *sw;
+ va_list ap;
+ uint16_t vol[2];
+
+ va_start (ap, cmd);
+ sw = va_arg (ap, SWVoiceIn *);
+ va_end (ap);
+
+ vol[0] = sw->vol.l / ((1ULL << 16) + 1);
+ vol[1] = sw->vol.r / ((1ULL << 16) + 1);
+ spice_server_record_set_volume (&in->sin, 2, vol);
+ spice_server_record_set_mute (&in->sin, sw->vol.mute);
+#endif
+ break;
+ }
}
+
return 0;
}
@@ -337,6 +375,9 @@ struct audio_driver spice_audio_driver = {
.max_voices_in = 1,
.voice_size_out = sizeof (SpiceVoiceOut),
.voice_size_in = sizeof (SpiceVoiceIn),
+#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
+ .ctl_caps = VOICE_VOLUME_CAP
+#endif
};
void qemu_spice_audio_init (void)
commit 19677a380a70348134ed7650b294522617eb03fc
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:39 2012 +0200
hw/ac97: add support for volume control
Combine output volume with Master and PCM registers values.
Use default values in mixer_reset ().
Set volume on post-load to update backend values.
v4,v5:
- fix some code style
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/ac97.c b/hw/ac97.c
index f7866ed..177f729 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -436,6 +436,65 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
}
+static void get_volume (uint16_t vol, uint16_t mask, int inverse,
+ int *mute, uint8_t *lvol, uint8_t *rvol)
+{
+ *mute = (vol >> MUTE_SHIFT) & 1;
+ *rvol = (255 * (vol & mask)) / mask;
+ *lvol = (255 * ((vol >> 8) & mask)) / mask;
+
+ if (inverse) {
+ *rvol = 255 - *rvol;
+ *lvol = 255 - *lvol;
+ }
+}
+
+static void update_combined_volume_out (AC97LinkState *s)
+{
+ uint8_t lvol, rvol, plvol, prvol;
+ int mute, pmute;
+
+ get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1,
+ &mute, &lvol, &rvol);
+ /* FIXME: should be 1f according to spec */
+ get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1,
+ &pmute, &plvol, &prvol);
+
+ mute = mute | pmute;
+ lvol = (lvol * plvol) / 255;
+ rvol = (rvol * prvol) / 255;
+
+ AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
+}
+
+static void update_volume_in (AC97LinkState *s)
+{
+ uint8_t lvol, rvol;
+ int mute;
+
+ get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0,
+ &mute, &lvol, &rvol);
+
+ AUD_set_volume_in (s->voice_pi, mute, lvol, rvol);
+}
+
+static void set_volume (AC97LinkState *s, int index, uint32_t val)
+{
+ mixer_store (s, index, val);
+ if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) {
+ update_combined_volume_out (s);
+ } else if (index == AC97_Record_Gain_Mute) {
+ update_volume_in (s);
+ }
+}
+
+static void record_select (AC97LinkState *s, uint32_t val)
+{
+ uint8_t rs = val & REC_MASK;
+ uint8_t ls = (val >> 8) & REC_MASK;
+ mixer_store (s, AC97_Record_Select, rs | (ls << 8));
+}
+
static void mixer_reset (AC97LinkState *s)
{
uint8_t active[LAST_INDEX];
@@ -470,6 +529,11 @@ static void mixer_reset (AC97LinkState *s)
mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80);
mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80);
+ record_select (s, 0);
+ set_volume (s, AC97_Master_Volume_Mute, 0x8000);
+ set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808);
+ set_volume (s, AC97_Line_In_Volume_Mute, 0x8808);
+
reset_voices (s, active);
}
@@ -528,6 +592,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
val |= mixer_load (s, index) & 0xf;
mixer_store (s, index, val);
break;
+ case AC97_PCM_Out_Volume_Mute:
+ case AC97_Master_Volume_Mute:
+ case AC97_Record_Gain_Mute:
+ case AC97_Line_In_Volume_Mute:
+ set_volume (s, index, val);
+ break;
+ case AC97_Record_Select:
+ record_select (s, val);
+ break;
case AC97_Vendor_ID1:
case AC97_Vendor_ID2:
dolog ("Attempt to write vendor ID to %#x\n", val);
@@ -1080,6 +1153,14 @@ static int ac97_post_load (void *opaque, int version_id)
uint8_t active[LAST_INDEX];
AC97LinkState *s = opaque;
+ record_select (s, mixer_load (s, AC97_Record_Select));
+ set_volume (s, AC97_Master_Volume_Mute,
+ mixer_load (s, AC97_Master_Volume_Mute));
+ set_volume (s, AC97_PCM_Out_Volume_Mute,
+ mixer_load (s, AC97_PCM_Out_Volume_Mute));
+ set_volume (s, AC97_Line_In_Volume_Mute,
+ mixer_load (s, AC97_Line_In_Volume_Mute));
+
active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM);
commit 5b72392603b6fcb6ac533cb5b74d1cfb4917a0e1
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:38 2012 +0200
hw/ac97: the volume mask is not only 0x1f
It's a case by case (see Table 66. AC ?97 Baseline Audio Register Map)
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/ac97.c b/hw/ac97.c
index f2804e6..f7866ed 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -118,7 +118,6 @@ enum {
#define EACS_VRA 1
#define EACS_VRM 8
-#define VOL_MASK 0x1f
#define MUTE_SHIFT 15
#define REC_MASK 7
commit ed2997cdcbe483d453316ce1b2ff4eae6ce06b7d
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:37 2012 +0200
hw/ac97: remove USE_MIXER code
That code doesn't compile. The interesting bits for volume control are
going to be rewritten in the following patch.
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/hw/ac97.c b/hw/ac97.c
index c0fd019..f2804e6 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -437,99 +437,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
}
-#ifdef USE_MIXER
-static void set_volume (AC97LinkState *s, int index,
- audmixerctl_t mt, uint32_t val)
-{
- int mute = (val >> MUTE_SHIFT) & 1;
- uint8_t rvol = VOL_MASK - (val & VOL_MASK);
- uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK);
- rvol = 255 * rvol / VOL_MASK;
- lvol = 255 * lvol / VOL_MASK;
-
-#ifdef SOFT_VOLUME
- if (index == AC97_Master_Volume_Mute) {
- AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
- }
- else {
- AUD_set_volume (mt, &mute, &lvol, &rvol);
- }
-#else
- AUD_set_volume (mt, &mute, &lvol, &rvol);
-#endif
-
- rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
- lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
- mixer_store (s, index, val);
-}
-
-static audrecsource_t ac97_to_aud_record_source (uint8_t i)
-{
- switch (i) {
- case REC_MIC:
- return AUD_REC_MIC;
-
- case REC_CD:
- return AUD_REC_CD;
-
- case REC_VIDEO:
- return AUD_REC_VIDEO;
-
- case REC_AUX:
- return AUD_REC_AUX;
-
- case REC_LINE_IN:
- return AUD_REC_LINE_IN;
-
- case REC_PHONE:
- return AUD_REC_PHONE;
-
- default:
- dolog ("Unknown record source %d, using MIC\n", i);
- return AUD_REC_MIC;
- }
-}
-
-static uint8_t aud_to_ac97_record_source (audrecsource_t rs)
-{
- switch (rs) {
- case AUD_REC_MIC:
- return REC_MIC;
-
- case AUD_REC_CD:
- return REC_CD;
-
- case AUD_REC_VIDEO:
- return REC_VIDEO;
-
- case AUD_REC_AUX:
- return REC_AUX;
-
- case AUD_REC_LINE_IN:
- return REC_LINE_IN;
-
- case AUD_REC_PHONE:
- return REC_PHONE;
-
- default:
- dolog ("Unknown audio recording source %d using MIC\n", rs);
- return REC_MIC;
- }
-}
-
-static void record_select (AC97LinkState *s, uint32_t val)
-{
- uint8_t rs = val & REC_MASK;
- uint8_t ls = (val >> 8) & REC_MASK;
- audrecsource_t ars = ac97_to_aud_record_source (rs);
- audrecsource_t als = ac97_to_aud_record_source (ls);
- AUD_set_record_source (&als, &ars);
- rs = aud_to_ac97_record_source (ars);
- ls = aud_to_ac97_record_source (als);
- mixer_store (s, AC97_Record_Select, rs | (ls << 8));
-}
-#endif
-
static void mixer_reset (AC97LinkState *s)
{
uint8_t active[LAST_INDEX];
@@ -564,12 +471,6 @@ static void mixer_reset (AC97LinkState *s)
mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80);
mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80);
-#ifdef USE_MIXER
- record_select (s, 0);
- set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000);
- set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM , 0x8808);
- set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808);
-#endif
reset_voices (s, active);
}
@@ -628,20 +529,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
val |= mixer_load (s, index) & 0xf;
mixer_store (s, index, val);
break;
-#ifdef USE_MIXER
- case AC97_Master_Volume_Mute:
- set_volume (s, index, AUD_MIXER_VOLUME, val);
- break;
- case AC97_PCM_Out_Volume_Mute:
- set_volume (s, index, AUD_MIXER_PCM, val);
- break;
- case AC97_Line_In_Volume_Mute:
- set_volume (s, index, AUD_MIXER_LINE_IN, val);
- break;
- case AC97_Record_Select:
- record_select (s, val);
- break;
-#endif
case AC97_Vendor_ID1:
case AC97_Vendor_ID2:
dolog ("Attempt to write vendor ID to %#x\n", val);
@@ -1194,14 +1081,6 @@ static int ac97_post_load (void *opaque, int version_id)
uint8_t active[LAST_INDEX];
AC97LinkState *s = opaque;
-#ifdef USE_MIXER
- record_select (s, mixer_load (s, AC97_Record_Select));
-#define V_(a, b) set_volume (s, a, b, mixer_load (s, a))
- V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME);
- V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM);
- V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN);
-#undef V_
-#endif
active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM);
commit c01b2456238f73964876471452e27d4aad7900fb
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:36 2012 +0200
audio: don't apply volume effect if backend has VOICE_VOLUME_CAP
If the audio backend is capable of volume control, don't apply
software volume (mixeng_volume ()), but instead, rely on backend
volume control. This will allow guest to have full range volume
control.
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/audio/audio.c b/audio/audio.c
index d76c342..bd9237e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -957,7 +957,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
total += isamp;
}
- mixeng_volume (sw->buf, ret, &sw->vol);
+ if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) {
+ mixeng_volume (sw->buf, ret, &sw->vol);
+ }
sw->clip (buf, sw->buf, ret);
sw->total_hw_samples_acquired += total;
@@ -1041,7 +1043,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
swlim = audio_MIN (swlim, samples);
if (swlim) {
sw->conv (sw->buf, buf, swlim);
- mixeng_volume (sw->buf, swlim, &sw->vol);
+
+ if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) {
+ mixeng_volume (sw->buf, swlim, &sw->vol);
+ }
}
while (swlim) {
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 117f95e..b9b0676 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -82,6 +82,7 @@ typedef struct HWVoiceOut {
int samples;
QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
+ int ctl_caps;
struct audio_pcm_ops *pcm_ops;
QLIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
@@ -101,6 +102,7 @@ typedef struct HWVoiceIn {
int samples;
QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
+ int ctl_caps;
struct audio_pcm_ops *pcm_ops;
QLIST_ENTRY (HWVoiceIn) entries;
} HWVoiceIn;
@@ -150,6 +152,7 @@ struct audio_driver {
int max_voices_in;
int voice_size_out;
int voice_size_in;
+ int ctl_caps;
};
struct audio_pcm_ops {
@@ -233,6 +236,8 @@ void audio_run (const char *msg);
#define VOICE_DISABLE 2
#define VOICE_VOLUME 3
+#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
+
static inline int audio_ring_dist (int dst, int src, int len)
{
return (dst >= src) ? (dst - src) : (len - src + dst);
diff --git a/audio/audio_template.h b/audio/audio_template.h
index e62a713..519432a 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
}
hw->pcm_ops = drv->pcm_ops;
+ hw->ctl_caps = drv->ctl_caps;
+
QLIST_INIT (&hw->sw_head);
#ifdef DAC
QLIST_INIT (&hw->cap_head);
commit 6c95ab94f9f7e8d3156e4e16ecc7c499e141bb1a
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue Apr 17 14:32:35 2012 +0200
audio: add VOICE_VOLUME ctl
Add a new PCM control operation to update the stream volume on the
audio backend. The argument given is a SWVoiceOut/SWVoiceIn.
v4:
- verified other backends didn't fail/assert on this new control
they randomly return 0 or -1, but we ignore return value.
Signed-off-by: Marc-Andr? Lureau <marcandre.lureau at redhat.com>
Signed-off-by: malc <av1474 at comtv.ru>
diff --git a/audio/audio.c b/audio/audio.c
index 398763f..d76c342 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2053,17 +2053,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
{
if (sw) {
+ HWVoiceOut *hw = sw->hw;
+
sw->vol.mute = mute;
sw->vol.l = nominal_volume.l * lvol / 255;
sw->vol.r = nominal_volume.r * rvol / 255;
+
+ if (hw->pcm_ops->ctl_out) {
+ hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw);
+ }
}
}
void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
{
if (sw) {
+ HWVoiceIn *hw = sw->hw;
+
sw->vol.mute = mute;
sw->vol.l = nominal_volume.l * lvol / 255;
sw->vol.r = nominal_volume.r * rvol / 255;
+
+ if (hw->pcm_ops->ctl_in) {
+ hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw);
+ }
}
}
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 2003f8b..117f95e 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -231,6 +231,7 @@ void audio_run (const char *msg);
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
+#define VOICE_VOLUME 3
static inline int audio_ring_dist (int dst, int src, int len)
{
commit 6b034aa138716a515c88f7894940d5d0aff2f3ed
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue Apr 17 10:51:41 2012 +0200
seabios: update to 1.7.0
Update roms/seabios and pc-bios/bios.bin to the 1.7.0 release.
Most noticable new feature is virtio-scsi support.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index e1f3923..5734ae5 100644
Binary files a/pc-bios/bios.bin and b/pc-bios/bios.bin differ
diff --git a/roms/seabios b/roms/seabios
index 2e8bd61..a026308 160000
--- a/roms/seabios
+++ b/roms/seabios
@@ -1 +1 @@
-Subproject commit 2e8bd611ce4e1e36b5a80c9ca6e256e23802f095
+Subproject commit a0263083cb4cda172832fbc916dc1417ee930574
commit c7020c974073ba9c0110d45361720a29ff6b2f59
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Mar 30 13:20:21 2012 +0200
usb-ehci: drop assert()
Not sure what the purpose of the assert() was, in any case it is bogous.
We can arrive there if transfer descriptors passed to us from the guest
failed to pass sanity checks, i.e. it is guest-triggerable. We deal
with that case by resetting the host controller. Everything is ok, no
need to throw a core dump here.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index e12f098..23631a4 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2009,7 +2009,6 @@ static void ehci_advance_state(EHCIState *ehci,
fprintf(stderr, "processing error - resetting ehci HC\n");
ehci_reset(ehci);
again = 0;
- assert(0);
}
}
while (again);
commit 714f9db06c209fd42d67e6dffd4f7fd932b51b65
Author: Hans de Goede <hdegoede at redhat.com>
Date: Fri Mar 30 09:53:54 2012 +0200
usb-redir: Notify our peer when we reject a device due to a speed mismatch
Also cleanup (reset) our device state when we reject a device due to a
speed mismatch.
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 4288324..94ab463 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -836,7 +836,13 @@ static void usbredir_do_attach(void *opaque)
{
USBRedirDevice *dev = opaque;
- usb_device_attach(&dev->dev);
+ if (usb_device_attach(&dev->dev) != 0) {
+ usbredir_device_disconnect(dev);
+ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
+ usbredirparser_send_filter_reject(dev->parser);
+ usbredirparser_do_write(dev->parser);
+ }
+ }
}
/*
commit 8e24283b2687e1d58d5f6a4872198c29e8a45d00
Author: Hans de Goede <hdegoede at redhat.com>
Date: Fri Mar 30 09:53:53 2012 +0200
usb-ehci: Drop unused sofv value
The sofv value only ever gets a value assigned and is never used (read)
anywhere, so we can just drop it.
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index be02308..e12f098 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -403,7 +403,6 @@ struct EHCIState {
/*
* Internal states, shadow registers, etc
*/
- uint32_t sofv;
QEMUTimer *frame_timer;
int attach_poll_counter;
int astate; // Current state in asynchronous schedule
@@ -1102,10 +1101,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
val &= USBINTR_MASK;
break;
- case FRINDEX:
- s->sofv = val >> 3;
- break;
-
case CONFIGFLAG:
val &= 0x1;
if (val) {
@@ -2157,9 +2152,6 @@ static void ehci_frame_timer(void *opaque)
ehci_set_interrupt(ehci, USBSTS_FLR);
ehci->frindex = 0;
}
-
- ehci->sofv = (ehci->frindex - 1) >> 3;
- ehci->sofv &= 0x000003ff;
}
if (frames - i > ehci->maxframes) {
commit 96dd9aac37d30f3425088f81523942e67b2d03ac
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 29 16:06:28 2012 +0200
usb-host: rewrite usb_linux_update_endp_table
This patch carries a complete rewrite of the usb descriptor parser.
Changes / improvements:
* We are using the USBDescriptor struct instead of hard-coded offsets
now to access descriptor data.
* (debug) printfs are all gone, tracepoints have been added instead.
* We don't try (and fail) to skip over unneeded descriptors. We parse
them all one by one. We keep track of which configuration, interface
and altsetting we are looking at and use this information to figure
which desciptors are in use and which we can ignore.
* On parse errors we clear all endpoint information, which will
disallow any communication with the device, except control endpoint
messages. This makes sure we don't end up with a silly device state
where half of the endpoints got enabled and the other half was left
disabled.
* Some sanity checks have been added.
The new parser is more robust and also leaves complete device
information in the trace log if you enable the ush_host_parse_*
tracepoints.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index a382f0a..061a1b7 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -42,6 +42,7 @@
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
#include "hw/usb.h"
+#include "hw/usb/desc.h"
/* We redefine it to avoid version problems */
struct usb_ctrltransfer {
@@ -1108,121 +1109,128 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
return USB_RET_ASYNC;
}
-static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
- uint8_t configuration, uint8_t interface)
-{
- char device_name[64], line[1024];
- int alt_setting;
-
- sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
- (int)configuration, (int)interface);
-
- if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
- device_name)) {
- /* Assume alt 0 on error */
- return 0;
- }
- if (sscanf(line, "%d", &alt_setting) != 1) {
- /* Assume alt 0 on error */
- return 0;
- }
- return alt_setting;
-}
-
/* returns 1 on problem encountered or 0 for success */
static int usb_linux_update_endp_table(USBHostDevice *s)
{
- uint8_t *descriptors;
- uint8_t devep, type, alt_interface;
- uint16_t raw;
- int interface, length, i, ep, pid;
+ static const char *tname[] = {
+ [USB_ENDPOINT_XFER_CONTROL] = "control",
+ [USB_ENDPOINT_XFER_ISOC] = "isoc",
+ [USB_ENDPOINT_XFER_BULK] = "bulk",
+ [USB_ENDPOINT_XFER_INT] = "int",
+ };
+ uint8_t devep, type;
+ uint16_t mps, v, p;
+ int ep, pid;
+ unsigned int i, configuration = -1, interface = -1, altsetting = -1;
struct endp_data *epd;
+ USBDescriptor *d;
+ bool active = false;
usb_ep_init(&s->dev);
- if (s->dev.configuration == 0) {
- /* not configured yet -- leave all endpoints disabled */
- return 0;
- }
-
- /* get the desired configuration, interface, and endpoint descriptors
- * from device description */
- descriptors = &s->descr[18];
- length = s->descr_len - 18;
- i = 0;
-
- while (i < length) {
- if (descriptors[i + 1] != USB_DT_CONFIG) {
- fprintf(stderr, "invalid descriptor data\n");
- return 1;
- } else if (descriptors[i + 5] != s->dev.configuration) {
- DPRINTF("not requested configuration %d\n", s->dev.configuration);
- i += (descriptors[i + 3] << 8) + descriptors[i + 2];
- continue;
- }
- i += descriptors[i];
-
- if (descriptors[i + 1] != USB_DT_INTERFACE ||
- (descriptors[i + 1] == USB_DT_INTERFACE &&
- descriptors[i + 4] == 0)) {
- i += descriptors[i];
- continue;
+ for (i = 0;; i += d->bLength) {
+ if (i+2 >= s->descr_len) {
+ break;
}
-
- interface = descriptors[i + 2];
- alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
- interface);
-
- /* the current interface descriptor is the active interface
- * and has endpoints */
- if (descriptors[i + 3] != alt_interface) {
- i += descriptors[i];
- continue;
+ d = (void *)(s->descr + i);
+ if (d->bLength < 2) {
+ trace_usb_host_parse_error(s->bus_num, s->addr,
+ "descriptor too short");
+ goto error;
}
-
- /* advance to the endpoints */
- while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
- i += descriptors[i];
+ if (i + d->bLength > s->descr_len) {
+ trace_usb_host_parse_error(s->bus_num, s->addr,
+ "descriptor too long");
+ goto error;
}
-
- if (i >= length)
+ switch (d->bDescriptorType) {
+ case 0:
+ trace_usb_host_parse_error(s->bus_num, s->addr,
+ "invalid descriptor type");
+ goto error;
+ case USB_DT_DEVICE:
+ if (d->bLength < 0x12) {
+ trace_usb_host_parse_error(s->bus_num, s->addr,
+ "device descriptor too short");
+ goto error;
+ }
+ v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo;
+ p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo;
+ trace_usb_host_parse_device(s->bus_num, s->addr, v, p);
break;
-
- while (i < length) {
- if (descriptors[i + 1] != USB_DT_ENDPOINT) {
- break;
+ case USB_DT_CONFIG:
+ if (d->bLength < 0x09) {
+ trace_usb_host_parse_error(s->bus_num, s->addr,
+ "config descriptor too short");
+ goto error;
}
-
- devep = descriptors[i + 2];
+ configuration = d->u.config.bConfigurationValue;
+ active = (configuration == s->dev.configuration);
+ trace_usb_host_parse_config(s->bus_num, s->addr,
+ configuration, active);
+ break;
+ case USB_DT_INTERFACE:
+ if (d->bLength < 0x09) {
+ trace_usb_host_parse_error(s->bus_num, s->addr,
+ "interface descriptor too short");
+ goto error;
+ }
+ interface = d->u.interface.bInterfaceNumber;
+ altsetting = d->u.interface.bAlternateSetting;
+ active = (configuration == s->dev.configuration) &&
+ (altsetting == s->dev.altsetting[interface]);
+ trace_usb_host_parse_interface(s->bus_num, s->addr,
+ interface, altsetting, active);
+ break;
+ case USB_DT_ENDPOINT:
+ if (d->bLength < 0x07) {
+ trace_usb_host_parse_error(s->bus_num, s->addr,
+ "endpoint descriptor too short");
+ goto error;
+ }
+ devep = d->u.endpoint.bEndpointAddress;
pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
ep = devep & 0xf;
if (ep == 0) {
- fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
- return 1;
+ trace_usb_host_parse_error(s->bus_num, s->addr,
+ "invalid endpoint address");
+ goto error;
}
- type = descriptors[i + 3] & 0x3;
- raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
- usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
- assert(usb_ep_get_type(&s->dev, pid, ep) ==
- USB_ENDPOINT_XFER_INVALID);
- usb_ep_set_type(&s->dev, pid, ep, type);
- usb_ep_set_ifnum(&s->dev, pid, ep, interface);
- if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
- (type == USB_ENDPOINT_XFER_BULK)) {
- usb_ep_set_pipeline(&s->dev, pid, ep, true);
- }
+ type = d->u.endpoint.bmAttributes & 0x3;
+ mps = d->u.endpoint.wMaxPacketSize_lo |
+ (d->u.endpoint.wMaxPacketSize_hi << 8);
+ trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep,
+ (devep & USB_DIR_IN) ? "in" : "out",
+ tname[type], active);
+
+ if (active) {
+ usb_ep_set_max_packet_size(&s->dev, pid, ep, mps);
+ assert(usb_ep_get_type(&s->dev, pid, ep) ==
+ USB_ENDPOINT_XFER_INVALID);
+ usb_ep_set_type(&s->dev, pid, ep, type);
+ usb_ep_set_ifnum(&s->dev, pid, ep, interface);
+ if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
+ (type == USB_ENDPOINT_XFER_BULK)) {
+ usb_ep_set_pipeline(&s->dev, pid, ep, true);
+ }
- epd = get_endp(s, pid, ep);
- epd->halted = 0;
+ epd = get_endp(s, pid, ep);
+ epd->halted = 0;
+ }
- i += descriptors[i];
+ break;
+ default:
+ trace_usb_host_parse_unknown(s->bus_num, s->addr,
+ d->bLength, d->bDescriptorType);
+ break;
}
}
-#ifdef DEBUG
- usb_ep_dump(&s->dev);
-#endif
return 0;
+
+error:
+ usb_ep_init(&s->dev);
+ return 1;
}
/*
diff --git a/trace-events b/trace-events
index e7ce5b2..d2e7879 100644
--- a/trace-events
+++ b/trace-events
@@ -337,6 +337,12 @@ usb_host_reset(int bus, int addr) "dev %d:%d"
usb_host_auto_scan_enabled(void)
usb_host_auto_scan_disabled(void)
usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
+usb_host_parse_device(int bus, int addr, int vendor, int product) "dev %d:%d, id %04x:%04x"
+usb_host_parse_config(int bus, int addr, int value, int active) "dev %d:%d, value %d, active %d"
+usb_host_parse_interface(int bus, int addr, int num, int alt, int active) "dev %d:%d, num %d, alt %d, active %d"
+usb_host_parse_endpoint(int bus, int addr, int ep, const char *dir, const char *type, int active) "dev %d:%d, ep %d, %s, %s, active %d"
+usb_host_parse_unknown(int bus, int addr, int len, int type) "dev %d:%d, len %d, type %d"
+usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s"
# hw/scsi-bus.c
scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
commit e36a20d329b4cf52ce3b269345527e7ebcc00885
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 29 16:01:21 2012 +0200
usb: use USBDescriptor for endpoint descriptors.
Add endpoint descriptor substruct to USBDescriptor,
use it in the descriptor generator code.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 2b8febb..3c77368 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -200,21 +200,23 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
{
uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
uint8_t extralen = ep->extra ? ep->extra[0] : 0;
+ USBDescriptor *d = (void *)dest;
if (len < bLength + extralen) {
return -1;
}
- dest[0x00] = bLength;
- dest[0x01] = USB_DT_ENDPOINT;
- dest[0x02] = ep->bEndpointAddress;
- dest[0x03] = ep->bmAttributes;
- dest[0x04] = usb_lo(ep->wMaxPacketSize);
- dest[0x05] = usb_hi(ep->wMaxPacketSize);
- dest[0x06] = ep->bInterval;
+ d->bLength = bLength;
+ d->bDescriptorType = USB_DT_ENDPOINT;
+
+ d->u.endpoint.bEndpointAddress = ep->bEndpointAddress;
+ d->u.endpoint.bmAttributes = ep->bmAttributes;
+ d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep->wMaxPacketSize);
+ d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep->wMaxPacketSize);
+ d->u.endpoint.bInterval = ep->bInterval;
if (ep->is_audio) {
- dest[0x07] = ep->bRefresh;
- dest[0x08] = ep->bSynchAddress;
+ d->u.endpoint.bRefresh = ep->bRefresh;
+ d->u.endpoint.bSynchAddress = ep->bSynchAddress;
}
if (ep->extra) {
memcpy(dest + bLength, ep->extra, extralen);
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 6f42eae..d164e8f 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -54,6 +54,15 @@ typedef struct USBDescriptor {
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} interface;
+ struct {
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint8_t wMaxPacketSize_lo;
+ uint8_t wMaxPacketSize_hi;
+ uint8_t bInterval;
+ uint8_t bRefresh; /* only audio ep */
+ uint8_t bSynchAddress; /* only audio ep */
+ } endpoint;
} u;
} QEMU_PACKED USBDescriptor;
commit feafd797ee5b12d6831aaafccd41c192ad9cc8bd
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 29 12:30:33 2012 +0200
usb: use USBDescriptor for interface descriptors.
Add interface descriptor substruct to USBDescriptor,
use it in the descriptor generator code.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 3466968..2b8febb 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -159,20 +159,22 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
{
uint8_t bLength = 0x09;
int i, rc, pos = 0;
+ USBDescriptor *d = (void *)dest;
if (len < bLength) {
return -1;
}
- dest[0x00] = bLength;
- dest[0x01] = USB_DT_INTERFACE;
- dest[0x02] = iface->bInterfaceNumber;
- dest[0x03] = iface->bAlternateSetting;
- dest[0x04] = iface->bNumEndpoints;
- dest[0x05] = iface->bInterfaceClass;
- dest[0x06] = iface->bInterfaceSubClass;
- dest[0x07] = iface->bInterfaceProtocol;
- dest[0x08] = iface->iInterface;
+ d->bLength = bLength;
+ d->bDescriptorType = USB_DT_INTERFACE;
+
+ d->u.interface.bInterfaceNumber = iface->bInterfaceNumber;
+ d->u.interface.bAlternateSetting = iface->bAlternateSetting;
+ d->u.interface.bNumEndpoints = iface->bNumEndpoints;
+ d->u.interface.bInterfaceClass = iface->bInterfaceClass;
+ d->u.interface.bInterfaceSubClass = iface->bInterfaceSubClass;
+ d->u.interface.bInterfaceProtocol = iface->bInterfaceProtocol;
+ d->u.interface.iInterface = iface->iInterface;
pos += bLength;
for (i = 0; i < iface->ndesc; i++) {
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 298e050..6f42eae 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -45,6 +45,15 @@ typedef struct USBDescriptor {
uint8_t bmAttributes;
uint8_t bMaxPower;
} config;
+ struct {
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+ } interface;
} u;
} QEMU_PACKED USBDescriptor;
commit 0a263db17a59a04b8f22540b284919956751e4f8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 29 12:24:08 2012 +0200
usb: use USBDescriptor for config descriptors.
Add config descriptor substruct to USBDescriptor,
use it in the descriptor generator code.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 5cecb25..3466968 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -78,22 +78,24 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
{
uint8_t bLength = 0x09;
uint16_t wTotalLength = 0;
+ USBDescriptor *d = (void *)dest;
int i, rc;
if (len < bLength) {
return -1;
}
- dest[0x00] = bLength;
- dest[0x01] = USB_DT_CONFIG;
- dest[0x04] = conf->bNumInterfaces;
- dest[0x05] = conf->bConfigurationValue;
- dest[0x06] = conf->iConfiguration;
- dest[0x07] = conf->bmAttributes;
- dest[0x08] = conf->bMaxPower;
+ d->bLength = bLength;
+ d->bDescriptorType = USB_DT_CONFIG;
+
+ d->u.config.bNumInterfaces = conf->bNumInterfaces;
+ d->u.config.bConfigurationValue = conf->bConfigurationValue;
+ d->u.config.iConfiguration = conf->iConfiguration;
+ d->u.config.bmAttributes = conf->bmAttributes;
+ d->u.config.bMaxPower = conf->bMaxPower;
wTotalLength += bLength;
- /* handle grouped interfaces if any*/
+ /* handle grouped interfaces if any */
for (i = 0; i < conf->nif_groups; i++) {
rc = usb_desc_iface_group(&(conf->if_groups[i]),
dest + wTotalLength,
@@ -113,8 +115,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
wTotalLength += rc;
}
- dest[0x02] = usb_lo(wTotalLength);
- dest[0x03] = usb_hi(wTotalLength);
+ d->u.config.wTotalLength_lo = usb_lo(wTotalLength);
+ d->u.config.wTotalLength_hi = usb_hi(wTotalLength);
return wTotalLength;
}
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index 15d0780..298e050 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -36,6 +36,15 @@ typedef struct USBDescriptor {
uint8_t bNumConfigurations;
uint8_t bReserved;
} device_qualifier;
+ struct {
+ uint8_t wTotalLength_lo;
+ uint8_t wTotalLength_hi;
+ uint8_t bNumInterfaces;
+ uint8_t bConfigurationValue;
+ uint8_t iConfiguration;
+ uint8_t bmAttributes;
+ uint8_t bMaxPower;
+ } config;
} u;
} QEMU_PACKED USBDescriptor;
commit 3cfeee6177bb7c86db8e1fa01cd6f5d438e4c463
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 29 12:15:01 2012 +0200
usb: use USBDescriptor for device qualifier descriptors.
Add device qualifier substruct to USBDescriptor,
use it in the descriptor generator code.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index de7e204..5cecb25 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -53,22 +53,23 @@ int usb_desc_device_qualifier(const USBDescDevice *dev,
uint8_t *dest, size_t len)
{
uint8_t bLength = 0x0a;
+ USBDescriptor *d = (void *)dest;
if (len < bLength) {
return -1;
}
- dest[0x00] = bLength;
- dest[0x01] = USB_DT_DEVICE_QUALIFIER;
-
- dest[0x02] = usb_lo(dev->bcdUSB);
- dest[0x03] = usb_hi(dev->bcdUSB);
- dest[0x04] = dev->bDeviceClass;
- dest[0x05] = dev->bDeviceSubClass;
- dest[0x06] = dev->bDeviceProtocol;
- dest[0x07] = dev->bMaxPacketSize0;
- dest[0x08] = dev->bNumConfigurations;
- dest[0x09] = 0; /* reserved */
+ d->bLength = bLength;
+ d->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
+
+ d->u.device_qualifier.bcdUSB_lo = usb_lo(dev->bcdUSB);
+ d->u.device_qualifier.bcdUSB_hi = usb_hi(dev->bcdUSB);
+ d->u.device_qualifier.bDeviceClass = dev->bDeviceClass;
+ d->u.device_qualifier.bDeviceSubClass = dev->bDeviceSubClass;
+ d->u.device_qualifier.bDeviceProtocol = dev->bDeviceProtocol;
+ d->u.device_qualifier.bMaxPacketSize0 = dev->bMaxPacketSize0;
+ d->u.device_qualifier.bNumConfigurations = dev->bNumConfigurations;
+ d->u.device_qualifier.bReserved = 0;
return bLength;
}
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index c5a242e..15d0780 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -26,6 +26,16 @@ typedef struct USBDescriptor {
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} device;
+ struct {
+ uint8_t bcdUSB_lo;
+ uint8_t bcdUSB_hi;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint8_t bNumConfigurations;
+ uint8_t bReserved;
+ } device_qualifier;
} u;
} QEMU_PACKED USBDescriptor;
commit d3f904ea7b3027f58037e359cc199c2490dc5c3d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 29 12:04:54 2012 +0200
usb: add USBDescriptor, use for device descriptors.
This patch adds a new type for the binary representation of usb
descriptors. It is put into use for the descriptor generator code
where the struct replaces the hard-coded offsets.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index 9847a75..de7e204 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -18,32 +18,33 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
uint8_t *dest, size_t len)
{
uint8_t bLength = 0x12;
+ USBDescriptor *d = (void *)dest;
if (len < bLength) {
return -1;
}
- dest[0x00] = bLength;
- dest[0x01] = USB_DT_DEVICE;
+ d->bLength = bLength;
+ d->bDescriptorType = USB_DT_DEVICE;
- dest[0x02] = usb_lo(dev->bcdUSB);
- dest[0x03] = usb_hi(dev->bcdUSB);
- dest[0x04] = dev->bDeviceClass;
- dest[0x05] = dev->bDeviceSubClass;
- dest[0x06] = dev->bDeviceProtocol;
- dest[0x07] = dev->bMaxPacketSize0;
+ d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB);
+ d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB);
+ d->u.device.bDeviceClass = dev->bDeviceClass;
+ d->u.device.bDeviceSubClass = dev->bDeviceSubClass;
+ d->u.device.bDeviceProtocol = dev->bDeviceProtocol;
+ d->u.device.bMaxPacketSize0 = dev->bMaxPacketSize0;
+
+ d->u.device.idVendor_lo = usb_lo(id->idVendor);
+ d->u.device.idVendor_hi = usb_hi(id->idVendor);
+ d->u.device.idProduct_lo = usb_lo(id->idProduct);
+ d->u.device.idProduct_hi = usb_hi(id->idProduct);
+ d->u.device.bcdDevice_lo = usb_lo(id->bcdDevice);
+ d->u.device.bcdDevice_hi = usb_hi(id->bcdDevice);
+ d->u.device.iManufacturer = id->iManufacturer;
+ d->u.device.iProduct = id->iProduct;
+ d->u.device.iSerialNumber = id->iSerialNumber;
- dest[0x08] = usb_lo(id->idVendor);
- dest[0x09] = usb_hi(id->idVendor);
- dest[0x0a] = usb_lo(id->idProduct);
- dest[0x0b] = usb_hi(id->idProduct);
- dest[0x0c] = usb_lo(id->bcdDevice);
- dest[0x0d] = usb_hi(id->bcdDevice);
- dest[0x0e] = id->iManufacturer;
- dest[0x0f] = id->iProduct;
- dest[0x10] = id->iSerialNumber;
-
- dest[0x11] = dev->bNumConfigurations;
+ d->u.device.bNumConfigurations = dev->bNumConfigurations;
return bLength;
}
diff --git a/hw/usb/desc.h b/hw/usb/desc.h
index d6e07ea..c5a242e 100644
--- a/hw/usb/desc.h
+++ b/hw/usb/desc.h
@@ -3,6 +3,32 @@
#include <inttypes.h>
+/* binary representation */
+typedef struct USBDescriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ union {
+ struct {
+ uint8_t bcdUSB_lo;
+ uint8_t bcdUSB_hi;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint8_t idVendor_lo;
+ uint8_t idVendor_hi;
+ uint8_t idProduct_lo;
+ uint8_t idProduct_hi;
+ uint8_t bcdDevice_lo;
+ uint8_t bcdDevice_hi;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+ } device;
+ } u;
+} QEMU_PACKED USBDescriptor;
+
struct USBDescID {
uint16_t idVendor;
uint16_t idProduct;
commit 58ea88d87a834923b31271750b8eab6403a797be
Author: Hans de Goede <hdegoede at redhat.com>
Date: Wed Mar 28 20:47:51 2012 +0200
usb-ehci: frindex always is a 14 bits counter
frindex always is a 14 bits counter, and not a 13 bits one as we were
emulating. There are some subtle hints to this in the spec, first of all
"Table 2-12. FRINDEX - Frame Index Register" says:
"Bit 13:0 Frame Index. The value in this register increments at the end of
each time frame (e.g. micro-frame). Bits [N:3] are used for the Frame List
current index. This means that each location of the frame list is accessed
8 times (frames or micro-frames) before moving to the next index. The
following illustrates values of N based on the value of the Frame List
Size field in the USBCMD register.
USBCMD[Frame List Size] Number Elements N
00b 1024 12
01b 512 11
10b 256 10
11b Reserved"
Notice how the text talks about "Bits [N:3]" are used ..., it does
NOT say that when N == 12 (our case) the counter will wrap from 8191 to 0,
or in otherwords that it is a 13 bits counter (bits 0 - 12).
The other hint is in "Table 2-10. USBSTS USB Status Register Bit Definitions":
"Bit 3 Frame List Rollover - R/WC. The Host Controller sets this bit to a one
when the Frame List Index (see Section 2.3.4) rolls over from its maximum value
to zero. The exact value at which the rollover occurs depends on the frame
list size. For example, if the frame list size (as programmed in the Frame
List Size field of the USBCMD register) is 1024, the Frame Index Register
rolls over every time FRINDEX[13] toggles. Similarly, if the size is 512,
the Host Controller sets this bit to a one every time FRINDEX[12] toggles."
Notice how this text talks about setting bit 3 when bit 13 of frindex toggles
(when there are 1024 entries, so our case), so this indicates that frindex
has a bit 13 making it a 14 bit counter.
Besides these clear hints the real proof is in the pudding. Before this
patch I could not stream data from a USB2 webcam under Windows XP, after
this cam using a USB2 webcam under Windows XP works fine, and no regressions
with other operating systems were seen.
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 34f7538..be02308 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2149,11 +2149,15 @@ static void ehci_frame_timer(void *opaque)
if ( !(ehci->usbsts & USBSTS_HALT)) {
ehci->frindex += 8;
- if (ehci->frindex > 0x00001fff) {
- ehci->frindex = 0;
+ if (ehci->frindex == 0x00002000) {
ehci_set_interrupt(ehci, USBSTS_FLR);
}
+ if (ehci->frindex == 0x00004000) {
+ ehci_set_interrupt(ehci, USBSTS_FLR);
+ ehci->frindex = 0;
+ }
+
ehci->sofv = (ehci->frindex - 1) >> 3;
ehci->sofv &= 0x000003ff;
}
commit 088351a7e50b7f14cda9520bcb8a7896e226aa36
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Mar 23 15:43:45 2012 +0100
usb-ehci: fix ehci_child_detach
Looks like a cut+paste bug from ehci_detach. When the device itself is
detached from a ehci port (ehci_detach op) we have to clear the
device pointer for the companion port too. When a device gets removed
from a downstream port of a usb hub (ehci_child_detach op) the ehci port
where the usb hub is plugged in is not affected.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 60f9f5b..34f7538 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -797,7 +797,6 @@ static void ehci_child_detach(USBPort *port, USBDevice *child)
if (portsc & PORTSC_POWNER) {
USBPort *companion = s->companion_ports[port->index];
companion->ops->child_detach(companion, child);
- companion->dev = NULL;
return;
}
commit 529f8f9fa939b8db13bf5cd1cd549d993cf25cb8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Mar 23 15:42:58 2012 +0100
usb-hub: add tracepoints
Add tracepoints to the usb hub emulation.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index eb4e711..9c91665 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -22,11 +22,10 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
+#include "trace.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
-//#define DEBUG
-
#define NUM_PORTS 8
typedef struct USBHubPort {
@@ -157,6 +156,7 @@ static void usb_hub_attach(USBPort *port1)
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
+ trace_usb_hub_attach(s->dev.addr, port1->index + 1);
port->wPortStatus |= PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->port.dev->speed == USB_SPEED_LOW) {
@@ -172,6 +172,7 @@ static void usb_hub_detach(USBPort *port1)
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
+ trace_usb_hub_detach(s->dev.addr, port1->index + 1);
usb_wakeup(s->intr);
/* Let upstream know the device on this port is gone */
@@ -247,6 +248,7 @@ static void usb_hub_handle_reset(USBDevice *dev)
USBHubPort *port;
int i;
+ trace_usb_hub_reset(s->dev.addr);
for (i = 0; i < NUM_PORTS; i++) {
port = s->ports + i;
port->wPortStatus = PORT_STAT_POWER;
@@ -261,12 +263,39 @@ static void usb_hub_handle_reset(USBDevice *dev)
}
}
+static const char *feature_name(int feature)
+{
+ static const char *name[] = {
+ [PORT_CONNECTION] = "connection",
+ [PORT_ENABLE] = "enable",
+ [PORT_SUSPEND] = "suspend",
+ [PORT_OVERCURRENT] = "overcurrent",
+ [PORT_RESET] = "reset",
+ [PORT_POWER] = "power",
+ [PORT_LOWSPEED] = "lowspeed",
+ [PORT_HIGHSPEED] = "highspeed",
+ [PORT_C_CONNECTION] = "change connection",
+ [PORT_C_ENABLE] = "change enable",
+ [PORT_C_SUSPEND] = "change suspend",
+ [PORT_C_OVERCURRENT] = "change overcurrent",
+ [PORT_C_RESET] = "change reset",
+ [PORT_TEST] = "test",
+ [PORT_INDICATOR] = "indicator",
+ };
+ if (feature < 0 || feature >= ARRAY_SIZE(name)) {
+ return "?";
+ }
+ return name[feature] ?: "?";
+}
+
static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHubState *s = (USBHubState *)dev;
int ret;
+ trace_usb_hub_control(s->dev.addr, request, value, index, length);
+
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
@@ -295,6 +324,9 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
goto fail;
}
port = &s->ports[n];
+ trace_usb_hub_get_port_status(s->dev.addr, index,
+ port->wPortStatus,
+ port->wPortChange);
data[0] = port->wPortStatus;
data[1] = port->wPortStatus >> 8;
data[2] = port->wPortChange;
@@ -315,6 +347,10 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
unsigned int n = index - 1;
USBHubPort *port;
USBDevice *dev;
+
+ trace_usb_hub_set_port_feature(s->dev.addr, index,
+ feature_name(value));
+
if (n >= NUM_PORTS) {
goto fail;
}
@@ -345,6 +381,9 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
unsigned int n = index - 1;
USBHubPort *port;
+ trace_usb_hub_clear_port_feature(s->dev.addr, index,
+ feature_name(value));
+
if (n >= NUM_PORTS) {
goto fail;
}
diff --git a/trace-events b/trace-events
index e3b1787..e7ce5b2 100644
--- a/trace-events
+++ b/trace-events
@@ -289,7 +289,7 @@ usb_uhci_td_nextqh(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
usb_uhci_td_async(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
-# hw/usb-desc.c
+# hw/usb/desc.c
usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
@@ -301,6 +301,15 @@ usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d,
usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
+# hw/usb/dev-hub.c
+usb_hub_reset(int addr) "dev %d"
+usb_hub_control(int addr, int request, int value, int index, int length) "dev %d, req 0x%x, value %d, index %d, langth %d"
+usb_hub_get_port_status(int addr, int nr, int status, int changed) "dev %d, port %d, status 0x%x, changed 0x%x"
+usb_hub_set_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s"
+usb_hub_clear_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s"
+usb_hub_attach(int addr, int nr) "dev %d, port %d"
+usb_hub_detach(int addr, int nr) "dev %d, port %d"
+
# hw/usb/host-linux.c
usb_host_open_started(int bus, int addr) "dev %d:%d"
usb_host_open_success(int bus, int addr) "dev %d:%d"
commit f5bf14bf39ec1ca2ad70ca1ec0e38a3e1e3f252d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Mar 23 13:34:50 2012 +0100
usb_packet_set_state: handle p->ep == NULL
usb_packet_set_state can be called with p->ep = NULL. The tracepoint
there tries to log endpoint information, which leads to a segfault.
This patch makes usb_packet_set_state handle the NULL pointer properly.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/core.c b/hw/usb/core.c
index a4048fe..9a14a53 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -484,12 +484,17 @@ void usb_packet_check_state(USBPacket *p, USBPacketState expected)
void usb_packet_set_state(USBPacket *p, USBPacketState state)
{
- USBDevice *dev = p->ep->dev;
- USBBus *bus = usb_bus_from_device(dev);
-
- trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
- usb_packet_state_name(p->state),
- usb_packet_state_name(state));
+ if (p->ep) {
+ USBDevice *dev = p->ep->dev;
+ USBBus *bus = usb_bus_from_device(dev);
+ trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
+ usb_packet_state_name(p->state),
+ usb_packet_state_name(state));
+ } else {
+ trace_usb_packet_state_change(-1, "", -1, p,
+ usb_packet_state_name(p->state),
+ usb_packet_state_name(state));
+ }
p->state = state;
}
commit 39c20577009731d5e059db10ef269807b57e498d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 22 15:28:45 2012 +0100
usb-host: add property to turn off pipelining
Add a property to usb-host to disable the bulk endpoint pipelining.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 8084fd9..a382f0a 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -94,6 +94,10 @@ struct USBAutoFilter {
uint32_t product_id;
};
+enum USBHostDeviceOptions {
+ USB_HOST_OPT_PIPELINE,
+};
+
typedef struct USBHostDevice {
USBDevice dev;
int fd;
@@ -104,6 +108,7 @@ typedef struct USBHostDevice {
int descr_len;
int closing;
uint32_t iso_urb_count;
+ uint32_t options;
Notifier exit;
struct endp_data ep_in[USB_MAX_ENDPOINTS];
@@ -1203,7 +1208,8 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
USB_ENDPOINT_XFER_INVALID);
usb_ep_set_type(&s->dev, pid, ep, type);
usb_ep_set_ifnum(&s->dev, pid, ep, interface);
- if (type == USB_ENDPOINT_XFER_BULK) {
+ if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
+ (type == USB_ENDPOINT_XFER_BULK)) {
usb_ep_set_pipeline(&s->dev, pid, ep, true);
}
@@ -1431,6 +1437,8 @@ static Property usb_host_dev_properties[] = {
DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex, -1),
+ DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
+ USB_HOST_OPT_PIPELINE, true),
DEFINE_PROP_END_OF_LIST(),
};
commit 19b89252a32e53aa8bd90a8d4c3e3dcc5f8fe46d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Mar 23 12:35:55 2012 +0100
usb-host: add usb packet to request tracepoints
Add pointer to USBPacket to all tracepoints tracking requests to make it
easier to identify them when multiple requests are in flight.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 6ea59a7..8084fd9 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -375,10 +375,10 @@ static void async_complete(void *opaque)
}
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
- trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
+ trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
usb_generic_async_ctrl_complete(&s->dev, p);
} else if (!aurb->more) {
- trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
+ trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
usb_packet_complete(&s->dev, p);
}
}
@@ -392,7 +392,7 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
AsyncURB *aurb;
- trace_usb_host_req_canceled(s->bus_num, s->addr);
+ trace_usb_host_req_canceled(s->bus_num, s->addr, p);
QLIST_FOREACH(aurb, &s->aurbs, next) {
if (p != aurb->packet) {
@@ -847,12 +847,12 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
uint8_t *pbuf;
uint8_t ep;
- trace_usb_host_req_data(s->bus_num, s->addr,
+ trace_usb_host_req_data(s->bus_num, s->addr, p,
p->pid == USB_TOKEN_IN,
p->ep->nr, p->iov.size);
if (!is_valid(s, p->pid, p->ep->nr)) {
- trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
+ trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
return USB_RET_NAK;
}
@@ -867,7 +867,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
if (ret < 0) {
perror("USBDEVFS_CLEAR_HALT");
- trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
+ trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
return USB_RET_NAK;
}
clear_halt(s, p->pid, p->ep->nr);
@@ -922,11 +922,13 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
switch(errno) {
case ETIMEDOUT:
- trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
+ trace_usb_host_req_complete(s->bus_num, s->addr, p,
+ USB_RET_NAK);
return USB_RET_NAK;
case EPIPE:
default:
- trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
+ trace_usb_host_req_complete(s->bus_num, s->addr, p,
+ USB_RET_STALL);
return USB_RET_STALL;
}
}
@@ -1033,22 +1035,22 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
*/
/* Note request is (bRequestType << 8) | bRequest */
- trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
+ trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
ret = usb_host_set_address(s, value);
- trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+ trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
ret = usb_host_set_config(s, value & 0xff);
- trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+ trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
ret = usb_host_set_interface(s, index, value);
- trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+ trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
}
diff --git a/trace-events b/trace-events
index 3e8da19..e3b1787 100644
--- a/trace-events
+++ b/trace-events
@@ -312,11 +312,11 @@ usb_host_set_config(int bus, int addr, int config) "dev %d:%d, config %d"
usb_host_set_interface(int bus, int addr, int interface, int alt) "dev %d:%d, interface %d, alt %d"
usb_host_claim_interfaces(int bus, int addr, int config, int nif) "dev %d:%d, config %d, nif %d"
usb_host_release_interfaces(int bus, int addr) "dev %d:%d"
-usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%d, req 0x%x, value %d, index %d"
-usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
-usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
-usb_host_req_emulated(int bus, int addr, int status) "dev %d:%d, status %d"
-usb_host_req_canceled(int bus, int addr) "dev %d:%d"
+usb_host_req_control(int bus, int addr, void *p, int req, int value, int index) "dev %d:%d, packet %p, req 0x%x, value %d, index %d"
+usb_host_req_data(int bus, int addr, void *p, int in, int ep, int size) "dev %d:%d, packet %p, in %d, ep %d, size %d"
+usb_host_req_complete(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d"
+usb_host_req_emulated(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d"
+usb_host_req_canceled(int bus, int addr, void *p) "dev %d:%d, packet %p"
usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
usb_host_urb_canceled(int bus, int addr, void *aurb) "dev %d:%d, aurb %p"
commit 6aebe407968a0c7e0be2647391753471ed674c65
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Mar 23 12:26:59 2012 +0100
usb-host: trace canceled requests
Add tracepoints to track canceled requests.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 912ce23..6ea59a7 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -392,12 +392,14 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
AsyncURB *aurb;
+ trace_usb_host_req_canceled(s->bus_num, s->addr);
+
QLIST_FOREACH(aurb, &s->aurbs, next) {
if (p != aurb->packet) {
continue;
}
- DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
+ trace_usb_host_urb_canceled(s->bus_num, s->addr, aurb);
/* Mark it as dead (see async_complete above) */
aurb->packet = NULL;
diff --git a/trace-events b/trace-events
index 8ac1b62..3e8da19 100644
--- a/trace-events
+++ b/trace-events
@@ -316,8 +316,10 @@ usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%
usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
usb_host_req_emulated(int bus, int addr, int status) "dev %d:%d, status %d"
+usb_host_req_canceled(int bus, int addr) "dev %d:%d"
usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
+usb_host_urb_canceled(int bus, int addr, void *aurb) "dev %d:%d, aurb %p"
usb_host_ep_set_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
usb_host_ep_clear_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
usb_host_ep_start_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
commit e382e751ef7848b237be2d569815dcc4f8097306
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 22 15:10:55 2012 +0100
usb-host: trace emulated requests
Add tracepoint to track completion of emulated control requests.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 5eb6916..912ce23 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -1035,13 +1035,19 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- return usb_host_set_address(s, value);
+ ret = usb_host_set_address(s, value);
+ trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+ return ret;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- return usb_host_set_config(s, value & 0xff);
+ ret = usb_host_set_config(s, value & 0xff);
+ trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+ return ret;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- return usb_host_set_interface(s, index, value);
+ ret = usb_host_set_interface(s, index, value);
+ trace_usb_host_req_emulated(s->bus_num, s->addr, ret);
+ return ret;
}
/* The rest are asynchronous */
diff --git a/trace-events b/trace-events
index a5f276d..8ac1b62 100644
--- a/trace-events
+++ b/trace-events
@@ -315,6 +315,7 @@ usb_host_release_interfaces(int bus, int addr) "dev %d:%d"
usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%d, req 0x%x, value %d, index %d"
usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
+usb_host_req_emulated(int bus, int addr, int status) "dev %d:%d, status %d"
usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
usb_host_ep_set_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
commit 65bb3a5c11b00671c1067ee27ea364b6d7e6e2ac
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 22 10:48:03 2012 +0100
Add bootindex support to usb-host and usb-redir
When passing through a usb pendrive seabios will present it in the F12
boot menu and will happily boot from it.
This patch adds bootorder support so you can even make it the default
boot device.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 90919c2..5eb6916 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -115,6 +115,7 @@ typedef struct USBHostDevice {
int addr;
char port[MAX_PORTLEN];
struct USBAutoFilter match;
+ int32_t bootindex;
int seen, errcount;
QTAILQ_ENTRY(USBHostDevice) next;
@@ -1403,6 +1404,7 @@ static int usb_host_initfn(USBDevice *dev)
if (s->match.bus_num != 0 && s->match.port != NULL) {
usb_host_claim_port(s);
}
+ add_boot_device_path(s->bootindex, &dev->qdev, NULL);
return 0;
}
@@ -1418,6 +1420,7 @@ static Property usb_host_dev_properties[] = {
DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
+ DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 8e9f175..4288324 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -74,6 +74,7 @@ struct USBRedirDevice {
CharDriverState *cs;
uint8_t debug;
char *filter_str;
+ int32_t bootindex;
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
const uint8_t *read_buf;
int read_buf_size;
@@ -923,6 +924,7 @@ static int usbredir_initfn(USBDevice *udev)
qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
usbredir_chardev_read, usbredir_chardev_event, dev);
+ add_boot_device_path(dev->bootindex, &udev->qdev, NULL);
return 0;
}
@@ -1452,6 +1454,7 @@ static Property usbredir_properties[] = {
DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
+ DEFINE_PROP_INT32("bootindex", USBRedirDevice, bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};
commit ee008ba62673943d5cd40c5761955efdbca444cd
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu Mar 29 16:02:20 2012 +0200
usb-uhci: queuing fix
When we queue up usb packets we may happen to find a already queued
packet, which also might be finished at that point already. We don't
want continue processing the packet at this point though, so lets
just signal back we've found a in-flight packet when in queuing mode.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 2be564b..266d550 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -795,7 +795,8 @@ out:
return TD_RESULT_NEXT_QH;
}
-static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask)
+static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
+ uint32_t *int_mask, bool queuing)
{
UHCIAsync *async;
int len = 0, max_len;
@@ -814,6 +815,12 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
if (!async->done)
return TD_RESULT_ASYNC_CONT;
+ if (queuing) {
+ /* we are busy filling the queue, we are not prepared
+ to consume completed packages then, just leave them
+ in async state */
+ return TD_RESULT_ASYNC_CONT;
+ }
uhci_async_unlink(async);
goto done;
@@ -964,7 +971,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
break;
}
trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
- ret = uhci_handle_td(s, plink, &ptd, &int_mask);
+ ret = uhci_handle_td(s, plink, &ptd, &int_mask, true);
if (ret == TD_RESULT_ASYNC_CONT) {
break;
}
@@ -1048,7 +1055,7 @@ static void uhci_process_frame(UHCIState *s)
trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
old_td_ctrl = td.ctrl;
- ret = uhci_handle_td(s, link, &td, &int_mask);
+ ret = uhci_handle_td(s, link, &td, &int_mask, false);
if (old_td_ctrl != td.ctrl) {
/* update the status bits of the TD */
val = cpu_to_le32(td.ctrl);
commit 52b0fecdba217e02d7e7eef975d942b153950b2f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Wed Mar 21 18:25:25 2012 +0100
usb-uhci: stop queue filling when we find a in-flight td
Not only QHs can form rings, but TDs too. With the new
queuing/pipelining support we are following TD chains and
can actually walk in circles. An assert() prevents us from
entering an endless loop then.
Fix is easy: Just stop queuing when we figure the TD we are
about to queue up is in flight already.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index e55dad9..2be564b 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -965,6 +965,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
}
trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
ret = uhci_handle_td(s, plink, &ptd, &int_mask);
+ if (ret == TD_RESULT_ASYNC_CONT) {
+ break;
+ }
assert(ret == TD_RESULT_ASYNC_START);
assert(int_mask == 0);
plink = ptd.link;
commit eeb0cf9abf5992f35eca18c4cc63300df30521a4
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Aug 22 09:09:51 2011 +0200
usb/vmstate: add parent dev path
... to make vmstate id string truely unique with multiple host
controllers, i.e. move from "1/usb-ptr" to "0000:00:01.3/1/usb-ptr"
(usb tabled connected to piix3 uhci).
This obviously breaks migration. To handle this the usb bus
property "full-path" is added. When setting this to false old
behavior is maintained. This way current qemu will be compatible
with old versions when started using '-M pc-$oldversion'.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 907d723..6a75718 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -377,6 +377,10 @@ static QEMUMachine pc_machine_v1_1 = {
.driver = "apic",\
.property = "vapic",\
.value = "off",\
+ },{\
+ .driver = "USB",\
+ .property = "full-path",\
+ .value = "no",\
}
static QEMUMachine pc_machine_v1_0 = {
diff --git a/hw/usb.h b/hw/usb.h
index e95085f..ae7ccda 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -182,12 +182,17 @@ struct USBEndpoint {
QTAILQ_HEAD(, USBPacket) queue;
};
+enum USBDeviceFlags {
+ USB_DEV_FLAG_FULL_PATH,
+};
+
/* definition of a USB device */
struct USBDevice {
DeviceState qdev;
USBPort *port;
char *port_path;
void *opaque;
+ uint32_t flags;
/* Actual connected speed */
int speed;
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index d3f8358..2068640 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -19,6 +19,8 @@ static struct BusInfo usb_bus_info = {
.get_fw_dev_path = usb_get_fw_dev_path,
.props = (Property[]) {
DEFINE_PROP_STRING("port", USBDevice, port_path),
+ DEFINE_PROP_BIT("full-path", USBDevice, flags,
+ USB_DEV_FLAG_FULL_PATH, true),
DEFINE_PROP_END_OF_LIST()
},
};
@@ -460,7 +462,20 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
static char *usb_get_dev_path(DeviceState *qdev)
{
USBDevice *dev = USB_DEVICE(qdev);
- return g_strdup(dev->port->path);
+ DeviceState *hcd = qdev->parent_bus->parent;
+ char *id = NULL;
+
+ if ((dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) &&
+ hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) {
+ id = hcd->parent_bus->info->get_dev_path(hcd);
+ }
+ if (id) {
+ char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
+ g_free(id);
+ return ret;
+ } else {
+ return g_strdup(dev->port->path);
+ }
}
static char *usb_get_fw_dev_path(DeviceState *qdev)
More information about the Spice-commits
mailing list