Some fixes for 9.1-rc3 (build, replay, docs, plugins)
- re-enable gdbsim-r5f562n8 test - ensure updates to python deps re-trigger configure - tweak configure detection of GDB MTE support - make checkpatch emit more warnings on updating headers - allow i386 access_ptr to force slow path for plugins - fixe some replay regressions - update the replay-dump tool - better handle muxed chardev during replay - clean up TCG plugins docs to mention scoreboards - fix plugin scoreboard race condition -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAma/UJcACgkQ+9DbCVqe KkT51gf/buOo0leJnBkYDTPWOOsDupW/nUUqOlTStvpKGEVNZgmxH0V4ffdCNO8E P4xQpD8WrpFKZHu2zE7EmXJ6/wkSp2BeSPcZ8lhld8jKNY3ksBlsCwb26/D9WsWK /JaqAegdg3fwCgbcQ057dRlKJV2ojjWD/JqPWa5G9AIlSqiHEfvcTj9t33BpJKXC xV7Yt1TZExkfkCAny54Sx4O6oiDhvSgJmWCUGIVE2W39+g3jUKf2tvbggR5MEIH3 fJ/F2vmcnllmK21awiRa9/WVZ55+Cbgj6PlLf/Qh6rhzooTMy+x0G+5BkNtZwNCs 8qFu8vFkuJM9YwDw9btaz3b+nG8Mzg== =HUN1 -----END PGP SIGNATURE----- Merge tag 'pull-maintainer-9.1-rc3-160824-1' of https://gitlab.com/stsquad/qemu into staging Some fixes for 9.1-rc3 (build, replay, docs, plugins) - re-enable gdbsim-r5f562n8 test - ensure updates to python deps re-trigger configure - tweak configure detection of GDB MTE support - make checkpatch emit more warnings on updating headers - allow i386 access_ptr to force slow path for plugins - fixe some replay regressions - update the replay-dump tool - better handle muxed chardev during replay - clean up TCG plugins docs to mention scoreboards - fix plugin scoreboard race condition # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAma/UJcACgkQ+9DbCVqe # KkT51gf/buOo0leJnBkYDTPWOOsDupW/nUUqOlTStvpKGEVNZgmxH0V4ffdCNO8E # P4xQpD8WrpFKZHu2zE7EmXJ6/wkSp2BeSPcZ8lhld8jKNY3ksBlsCwb26/D9WsWK # /JaqAegdg3fwCgbcQ057dRlKJV2ojjWD/JqPWa5G9AIlSqiHEfvcTj9t33BpJKXC # xV7Yt1TZExkfkCAny54Sx4O6oiDhvSgJmWCUGIVE2W39+g3jUKf2tvbggR5MEIH3 # fJ/F2vmcnllmK21awiRa9/WVZ55+Cbgj6PlLf/Qh6rhzooTMy+x0G+5BkNtZwNCs # 8qFu8vFkuJM9YwDw9btaz3b+nG8Mzg== # =HUN1 # -----END PGP SIGNATURE----- # gpg: Signature made Fri 16 Aug 2024 11:13:59 PM AEST # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full] * tag 'pull-maintainer-9.1-rc3-160824-1' of https://gitlab.com/stsquad/qemu: (21 commits) plugins: fix race condition with scoreboards docs/devel: update tcg-plugins page docs: Fix some typos (found by typos) and grammar issues savevm: Fix load_snapshot error path crash virtio-net: Use virtual time for RSC timers virtio-net: Use replay_schedule_bh_event for bhs that affect machine state chardev: set record/replay on the base device of a muxed device tests/avocado: replay_kernel.py add x86-64 q35 machine test Revert "replay: stop us hanging in rr_wait_io_event" replay: allow runstate shutdown->running when replaying trace tests/avocado: excercise scripts/replay-dump.py in replay tests scripts/replay-dump.py: rejig decoders in event number order scripts/replay-dump.py: Update to current rr record format buildsys: Fix building without plugins on Darwin target/i386: allow access_ptr to force slow path on failed probe scripts/checkpatch: more checks on files imported from Linux configure: Fix GDB version detection for GDB_HAS_MTE configure: Avoid use of param. expansion when using gdb_version configure: Fix arch detection for GDB_HAS_MTE Makefile: trigger re-configure on updated pythondeps ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
2eefd4fcec
3
Makefile
3
Makefile
@ -78,7 +78,8 @@ x := $(shell rm -rf meson-private meson-info meson-logs)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# 1. ensure config-host.mak is up-to-date
|
# 1. ensure config-host.mak is up-to-date
|
||||||
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh $(SRC_PATH)/VERSION
|
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh \
|
||||||
|
$(SRC_PATH)/pythondeps.toml $(SRC_PATH)/VERSION
|
||||||
@echo config-host.mak is out-of-date, running configure
|
@echo config-host.mak is out-of-date, running configure
|
||||||
@if test -f meson-private/coredata.dat; then \
|
@if test -f meson-private/coredata.dat; then \
|
||||||
./config.status --skip-meson; \
|
./config.status --skip-meson; \
|
||||||
|
@ -109,7 +109,7 @@ static void rr_wait_io_event(void)
|
|||||||
{
|
{
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
|
||||||
while (all_cpu_threads_idle() && replay_can_wait()) {
|
while (all_cpu_threads_idle()) {
|
||||||
rr_stop_kick_timer();
|
rr_stop_kick_timer();
|
||||||
qemu_cond_wait_bql(first_cpu->halt_cond);
|
qemu_cond_wait_bql(first_cpu->halt_cond);
|
||||||
}
|
}
|
||||||
|
@ -615,11 +615,24 @@ ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
|
|||||||
return backend;
|
return backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
|
static void qemu_chardev_set_replay(Chardev *chr, Error **errp)
|
||||||
Error **errp)
|
{
|
||||||
|
if (replay_mode != REPLAY_MODE_NONE) {
|
||||||
|
if (CHARDEV_GET_CLASS(chr)->chr_ioctl) {
|
||||||
|
error_setg(errp, "Replay: ioctl is not supported "
|
||||||
|
"for serial devices yet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
|
||||||
|
replay_register_char_driver(chr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Chardev *__qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
|
||||||
|
bool replay, Error **errp)
|
||||||
{
|
{
|
||||||
const ChardevClass *cc;
|
const ChardevClass *cc;
|
||||||
Chardev *chr = NULL;
|
Chardev *base = NULL, *chr = NULL;
|
||||||
ChardevBackend *backend = NULL;
|
ChardevBackend *backend = NULL;
|
||||||
const char *name = qemu_opt_get(opts, "backend");
|
const char *name = qemu_opt_get(opts, "backend");
|
||||||
const char *id = qemu_opts_id(opts);
|
const char *id = qemu_opts_id(opts);
|
||||||
@ -657,11 +670,11 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
|
|||||||
chr = qemu_chardev_new(bid ? bid : id,
|
chr = qemu_chardev_new(bid ? bid : id,
|
||||||
object_class_get_name(OBJECT_CLASS(cc)),
|
object_class_get_name(OBJECT_CLASS(cc)),
|
||||||
backend, context, errp);
|
backend, context, errp);
|
||||||
|
|
||||||
if (chr == NULL) {
|
if (chr == NULL) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base = chr;
|
||||||
if (bid) {
|
if (bid) {
|
||||||
Chardev *mux;
|
Chardev *mux;
|
||||||
qapi_free_ChardevBackend(backend);
|
qapi_free_ChardevBackend(backend);
|
||||||
@ -681,11 +694,25 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
|
|||||||
out:
|
out:
|
||||||
qapi_free_ChardevBackend(backend);
|
qapi_free_ChardevBackend(backend);
|
||||||
g_free(bid);
|
g_free(bid);
|
||||||
|
|
||||||
|
if (replay && base) {
|
||||||
|
/* RR should be set on the base device, not the mux */
|
||||||
|
qemu_chardev_set_replay(base, errp);
|
||||||
|
}
|
||||||
|
|
||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
|
Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
|
||||||
bool permit_mux_mon, GMainContext *context)
|
Error **errp)
|
||||||
|
{
|
||||||
|
/* XXX: should this really not record/replay? */
|
||||||
|
return __qemu_chr_new_from_opts(opts, context, false, errp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Chardev *__qemu_chr_new(const char *label, const char *filename,
|
||||||
|
bool permit_mux_mon, GMainContext *context,
|
||||||
|
bool replay)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
Chardev *chr;
|
Chardev *chr;
|
||||||
@ -693,14 +720,22 @@ Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
|
|||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
if (strstart(filename, "chardev:", &p)) {
|
if (strstart(filename, "chardev:", &p)) {
|
||||||
return qemu_chr_find(p);
|
chr = qemu_chr_find(p);
|
||||||
|
if (replay) {
|
||||||
|
qemu_chardev_set_replay(chr, &err);
|
||||||
|
if (err) {
|
||||||
|
error_report_err(err);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = qemu_chr_parse_compat(label, filename, permit_mux_mon);
|
opts = qemu_chr_parse_compat(label, filename, permit_mux_mon);
|
||||||
if (!opts)
|
if (!opts)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
chr = qemu_chr_new_from_opts(opts, context, &err);
|
chr = __qemu_chr_new_from_opts(opts, context, replay, &err);
|
||||||
if (!chr) {
|
if (!chr) {
|
||||||
error_report_err(err);
|
error_report_err(err);
|
||||||
goto out;
|
goto out;
|
||||||
@ -722,24 +757,18 @@ out:
|
|||||||
return chr;
|
return chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
|
||||||
|
bool permit_mux_mon, GMainContext *context)
|
||||||
|
{
|
||||||
|
return __qemu_chr_new(label, filename, permit_mux_mon, context, false);
|
||||||
|
}
|
||||||
|
|
||||||
static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
|
static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
bool permit_mux_mon,
|
bool permit_mux_mon,
|
||||||
GMainContext *context)
|
GMainContext *context)
|
||||||
{
|
{
|
||||||
Chardev *chr;
|
return __qemu_chr_new(label, filename, permit_mux_mon, context, true);
|
||||||
chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon, context);
|
|
||||||
if (chr) {
|
|
||||||
if (replay_mode != REPLAY_MODE_NONE) {
|
|
||||||
qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
|
|
||||||
}
|
|
||||||
if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) {
|
|
||||||
error_report("Replay: ioctl is not supported "
|
|
||||||
"for serial devices yet");
|
|
||||||
}
|
|
||||||
replay_register_char_driver(chr);
|
|
||||||
}
|
|
||||||
return chr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Chardev *qemu_chr_new(const char *label, const char *filename,
|
Chardev *qemu_chr_new(const char *label, const char *filename,
|
||||||
|
8
configure
vendored
8
configure
vendored
@ -1103,8 +1103,10 @@ fi
|
|||||||
# gdb test
|
# gdb test
|
||||||
|
|
||||||
if test -n "$gdb_bin"; then
|
if test -n "$gdb_bin"; then
|
||||||
gdb_version=$($gdb_bin --version | head -n 1)
|
gdb_version_string=$($gdb_bin --version | head -n 1)
|
||||||
if version_ge ${gdb_version##* } 9.1; then
|
# Extract last field in the version string
|
||||||
|
gdb_version=${gdb_version_string##* }
|
||||||
|
if version_ge $gdb_version 9.1; then
|
||||||
gdb_arches=$($python "$source_path/scripts/probe-gdb-support.py" $gdb_bin)
|
gdb_arches=$($python "$source_path/scripts/probe-gdb-support.py" $gdb_bin)
|
||||||
else
|
else
|
||||||
gdb_bin=""
|
gdb_bin=""
|
||||||
@ -1673,7 +1675,7 @@ for target in $target_list; do
|
|||||||
echo "GDB=$gdb_bin" >> $config_target_mak
|
echo "GDB=$gdb_bin" >> $config_target_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "${arch}" = "aarch64" && version_ge ${gdb_version##* } 15.0; then
|
if test "${gdb_arches#*aarch64}" != "$gdb_arches" && version_ge $gdb_version 15.1; then
|
||||||
echo "GDB_HAS_MTE=y" >> $config_target_mak
|
echo "GDB_HAS_MTE=y" >> $config_target_mak
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -207,8 +207,8 @@ Once built a program can be run with multiple plugins loaded each with
|
|||||||
their own arguments::
|
their own arguments::
|
||||||
|
|
||||||
$QEMU $OTHER_QEMU_ARGS \
|
$QEMU $OTHER_QEMU_ARGS \
|
||||||
-plugin contrib/plugin/libhowvec.so,inline=on,count=hint \
|
-plugin contrib/plugins/libhowvec.so,inline=on,count=hint \
|
||||||
-plugin contrib/plugin/libhotblocks.so
|
-plugin contrib/plugins/libhotblocks.so
|
||||||
|
|
||||||
Arguments are plugin specific and can be used to modify their
|
Arguments are plugin specific and can be used to modify their
|
||||||
behaviour. In this case the howvec plugin is being asked to use inline
|
behaviour. In this case the howvec plugin is being asked to use inline
|
||||||
@ -219,6 +219,14 @@ Linux user-mode emulation also evaluates the environment variable
|
|||||||
|
|
||||||
QEMU_PLUGIN="file=contrib/plugins/libhowvec.so,inline=on,count=hint" $QEMU
|
QEMU_PLUGIN="file=contrib/plugins/libhowvec.so,inline=on,count=hint" $QEMU
|
||||||
|
|
||||||
|
QEMU plugins avoid to write directly to stdin/stderr, and use the log provided
|
||||||
|
by the API (see function ``qemu_plugin_outs``).
|
||||||
|
To show output, you may use this additional parameter::
|
||||||
|
|
||||||
|
$QEMU $OTHER_QEMU_ARGS \
|
||||||
|
-d plugin \
|
||||||
|
-plugin contrib/plugins/libhowvec.so,inline=on,count=hint
|
||||||
|
|
||||||
Example Plugins
|
Example Plugins
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -260,8 +268,7 @@ Behaviour can be tweaked with the following arguments:
|
|||||||
* - Option
|
* - Option
|
||||||
- Description
|
- Description
|
||||||
* - inline=true|false
|
* - inline=true|false
|
||||||
- Use faster inline addition of a single counter. Not per-cpu and not
|
- Use faster inline addition of a single counter.
|
||||||
thread safe.
|
|
||||||
* - idle=true|false
|
* - idle=true|false
|
||||||
- Dump the current execution stats whenever the guest vCPU idles
|
- Dump the current execution stats whenever the guest vCPU idles
|
||||||
|
|
||||||
@ -381,6 +388,15 @@ run::
|
|||||||
160 1 0
|
160 1 0
|
||||||
135 1 0
|
135 1 0
|
||||||
|
|
||||||
|
Test inline operations
|
||||||
|
......................
|
||||||
|
|
||||||
|
``tests/plugins/inline.c``
|
||||||
|
|
||||||
|
This plugin is used for testing all inline operations, conditional callbacks and
|
||||||
|
scoreboard. It prints a per-cpu summary of all events.
|
||||||
|
|
||||||
|
|
||||||
Hot Blocks
|
Hot Blocks
|
||||||
..........
|
..........
|
||||||
|
|
||||||
@ -394,9 +410,6 @@ with linux-user execution as system emulation tends to generate
|
|||||||
re-translations as blocks from different programs get swapped in and
|
re-translations as blocks from different programs get swapped in and
|
||||||
out of system memory.
|
out of system memory.
|
||||||
|
|
||||||
If your program is single-threaded you can use the ``inline`` option for
|
|
||||||
slightly faster (but not thread safe) counters.
|
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
$ qemu-aarch64 \
|
$ qemu-aarch64 \
|
||||||
@ -736,6 +749,28 @@ The plugin will log the reason of exit, for example::
|
|||||||
|
|
||||||
0xd4 reached, exiting
|
0xd4 reached, exiting
|
||||||
|
|
||||||
|
Limit instructions per second
|
||||||
|
.............................
|
||||||
|
|
||||||
|
This plugin can limit the number of Instructions Per Second that are executed::
|
||||||
|
|
||||||
|
# get number of instructions
|
||||||
|
$ num_insn=$(./build/qemu-x86_64 -plugin ./build/tests/plugin/libinsn.so -d plugin /bin/true |& grep total | sed -e 's/.*: //')
|
||||||
|
# limit speed to execute in 10 seconds
|
||||||
|
$ time ./build/qemu-x86_64 -plugin ./build/contrib/plugins/libips.so,ips=$(($num_insn/10)) /bin/true
|
||||||
|
real 10.000s
|
||||||
|
|
||||||
|
|
||||||
|
.. list-table:: IPS arguments
|
||||||
|
:widths: 20 80
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
* - Option
|
||||||
|
- Description
|
||||||
|
* - ips=N
|
||||||
|
- Maximum number of instructions per cpu that can be executed in one second.
|
||||||
|
The plugin will sleep when the given number of instructions is reached.
|
||||||
|
|
||||||
Other emulation features
|
Other emulation features
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ Make sure all these above kernel configurations are selected.
|
|||||||
|
|
||||||
Accelerator dev node permissions
|
Accelerator dev node permissions
|
||||||
--------------------------------
|
--------------------------------
|
||||||
Harware accelerators(eg: HiSilicon Kunpeng Zip accelerator) gets registered to
|
Hardware accelerators (eg: HiSilicon Kunpeng Zip accelerator) gets registered to
|
||||||
UADK and char devices are created in dev directory. In order to access resources
|
UADK and char devices are created in dev directory. In order to access resources
|
||||||
on hardware accelerator devices, write permission should be provided to user.
|
on hardware accelerator devices, write permission should be provided to user.
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ How To Use UADK Compression In QEMU Migration
|
|||||||
Set ``migrate_set_parameter multifd-compression uadk``
|
Set ``migrate_set_parameter multifd-compression uadk``
|
||||||
|
|
||||||
Since UADK uses Shared Virtual Addressing(SVA) and device access virtual memory
|
Since UADK uses Shared Virtual Addressing(SVA) and device access virtual memory
|
||||||
directly it is possible that SMMUv3 may enounter page faults while walking the
|
directly it is possible that SMMUv3 may encounter page faults while walking the
|
||||||
IO page tables. This may impact the performance. In order to mitigate this,
|
IO page tables. This may impact the performance. In order to mitigate this,
|
||||||
please make sure to specify ``-mem-prealloc`` parameter to the destination VM
|
please make sure to specify ``-mem-prealloc`` parameter to the destination VM
|
||||||
boot parameters.
|
boot parameters.
|
||||||
|
@ -61,11 +61,14 @@ translation event the plugin has an option to enumerate the
|
|||||||
instructions in a block of instructions and optionally register
|
instructions in a block of instructions and optionally register
|
||||||
callbacks to some or all instructions when they are executed.
|
callbacks to some or all instructions when they are executed.
|
||||||
|
|
||||||
There is also a facility to add an inline event where code to
|
There is also a facility to add inline instructions doing various operations,
|
||||||
increment a counter can be directly inlined with the translation.
|
like adding or storing an immediate value. It is also possible to execute a
|
||||||
Currently only a simple increment is supported. This is not atomic so
|
callback conditionally, with condition being evaluated inline. All those inline
|
||||||
can miss counts. If you want absolute precision you should use a
|
operations are associated to a ``scoreboard``, which is a thread-local storage
|
||||||
callback which can then ensure atomicity itself.
|
automatically expanded when new cores/threads are created and that can be
|
||||||
|
accessed/modified in a thread-safe way without any lock needed. Combining inline
|
||||||
|
operations and conditional callbacks offer a more efficient way to instrument
|
||||||
|
binaries, compared to classic callbacks.
|
||||||
|
|
||||||
Finally when QEMU exits all the registered *atexit* callbacks are
|
Finally when QEMU exits all the registered *atexit* callbacks are
|
||||||
invoked.
|
invoked.
|
||||||
|
@ -50,7 +50,7 @@ Options
|
|||||||
.. option:: -c, --config=PATH
|
.. option:: -c, --config=PATH
|
||||||
|
|
||||||
Configuration file path (the default is |CONFDIR|\ ``/qemu-ga.conf``,
|
Configuration file path (the default is |CONFDIR|\ ``/qemu-ga.conf``,
|
||||||
unless overriden by the QGA_CONF environment variable)
|
unless overridden by the QGA_CONF environment variable)
|
||||||
|
|
||||||
.. option:: -m, --method=METHOD
|
.. option:: -m, --method=METHOD
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ driver to advertise and monitor the power consumption or accumulated energy
|
|||||||
consumption of different power domains, such as CPU packages, DRAM, and other
|
consumption of different power domains, such as CPU packages, DRAM, and other
|
||||||
components when available.
|
components when available.
|
||||||
|
|
||||||
However those register are accesible under priviliged access (CAP_SYS_RAWIO).
|
However those registers are accessible under privileged access (CAP_SYS_RAWIO).
|
||||||
QEMU can use an external helper to access those priviliged register.
|
QEMU can use an external helper to access those privileged registers.
|
||||||
|
|
||||||
:program:`qemu-vmsr-helper` is that external helper; it creates a listener
|
:program:`qemu-vmsr-helper` is that external helper; it creates a listener
|
||||||
socket which will accept incoming connections for communication with QEMU.
|
socket which will accept incoming connections for communication with QEMU.
|
||||||
|
@ -674,7 +674,7 @@ error:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* combine S1 and S2 TLB entries into a single entry.
|
* combine S1 and S2 TLB entries into a single entry.
|
||||||
* As a result the S1 entry is overriden with combined data.
|
* As a result the S1 entry is overridden with combined data.
|
||||||
*/
|
*/
|
||||||
static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
|
static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
|
||||||
dma_addr_t iova, SMMUTransCfg *cfg)
|
dma_addr_t iova, SMMUTransCfg *cfg)
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "migration/misc.h"
|
#include "migration/misc.h"
|
||||||
#include "standard-headers/linux/ethtool.h"
|
#include "standard-headers/linux/ethtool.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "sysemu/replay.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "monitor/qdev.h"
|
#include "monitor/qdev.h"
|
||||||
#include "monitor/monitor.h"
|
#include "monitor/monitor.h"
|
||||||
@ -417,7 +418,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
|
|||||||
timer_mod(q->tx_timer,
|
timer_mod(q->tx_timer,
|
||||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
||||||
} else {
|
} else {
|
||||||
qemu_bh_schedule(q->tx_bh);
|
replay_bh_schedule_event(q->tx_bh);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (q->tx_timer) {
|
if (q->tx_timer) {
|
||||||
@ -2123,7 +2124,7 @@ static void virtio_net_rsc_purge(void *opq)
|
|||||||
chain->stat.timer++;
|
chain->stat.timer++;
|
||||||
if (!QTAILQ_EMPTY(&chain->buffers)) {
|
if (!QTAILQ_EMPTY(&chain->buffers)) {
|
||||||
timer_mod(chain->drain_timer,
|
timer_mod(chain->drain_timer,
|
||||||
qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout);
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + chain->n->rsc_timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2359,7 +2360,7 @@ static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain,
|
|||||||
chain->stat.empty_cache++;
|
chain->stat.empty_cache++;
|
||||||
virtio_net_rsc_cache_buf(chain, nc, buf, size);
|
virtio_net_rsc_cache_buf(chain, nc, buf, size);
|
||||||
timer_mod(chain->drain_timer,
|
timer_mod(chain->drain_timer,
|
||||||
qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout);
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + chain->n->rsc_timeout);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2597,7 +2598,7 @@ static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n,
|
|||||||
chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD;
|
chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD;
|
||||||
chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
|
chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
|
||||||
}
|
}
|
||||||
chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST,
|
chain->drain_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
virtio_net_rsc_purge, chain);
|
virtio_net_rsc_purge, chain);
|
||||||
memset(&chain->stat, 0, sizeof(chain->stat));
|
memset(&chain->stat, 0, sizeof(chain->stat));
|
||||||
|
|
||||||
@ -2672,7 +2673,7 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
|
|||||||
*/
|
*/
|
||||||
virtio_queue_set_notification(q->tx_vq, 0);
|
virtio_queue_set_notification(q->tx_vq, 0);
|
||||||
if (q->tx_bh) {
|
if (q->tx_bh) {
|
||||||
qemu_bh_schedule(q->tx_bh);
|
replay_bh_schedule_event(q->tx_bh);
|
||||||
} else {
|
} else {
|
||||||
timer_mod(q->tx_timer,
|
timer_mod(q->tx_timer,
|
||||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
||||||
@ -2838,7 +2839,7 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
virtio_queue_set_notification(vq, 0);
|
virtio_queue_set_notification(vq, 0);
|
||||||
qemu_bh_schedule(q->tx_bh);
|
replay_bh_schedule_event(q->tx_bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_net_tx_timer(void *opaque)
|
static void virtio_net_tx_timer(void *opaque)
|
||||||
@ -2921,7 +2922,7 @@ static void virtio_net_tx_bh(void *opaque)
|
|||||||
/* If we flush a full burst of packets, assume there are
|
/* If we flush a full burst of packets, assume there are
|
||||||
* more coming and immediately reschedule */
|
* more coming and immediately reschedule */
|
||||||
if (ret >= n->tx_burst) {
|
if (ret >= n->tx_burst) {
|
||||||
qemu_bh_schedule(q->tx_bh);
|
replay_bh_schedule_event(q->tx_bh);
|
||||||
q->tx_waiting = 1;
|
q->tx_waiting = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2935,7 +2936,7 @@ static void virtio_net_tx_bh(void *opaque)
|
|||||||
return;
|
return;
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
virtio_queue_set_notification(q->tx_vq, 0);
|
virtio_queue_set_notification(q->tx_vq, 0);
|
||||||
qemu_bh_schedule(q->tx_bh);
|
replay_bh_schedule_event(q->tx_bh);
|
||||||
q->tx_waiting = 1;
|
q->tx_waiting = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1852,7 +1852,7 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
|
|||||||
* memory_region_unregister_iommu_notifier: unregister a notifier for
|
* memory_region_unregister_iommu_notifier: unregister a notifier for
|
||||||
* changes to IOMMU translation entries.
|
* changes to IOMMU translation entries.
|
||||||
*
|
*
|
||||||
* @mr: the memory region which was observed and for which notity_stopped()
|
* @mr: the memory region which was observed and for which notify_stopped()
|
||||||
* needs to be called
|
* needs to be called
|
||||||
* @n: the notifier to be removed.
|
* @n: the notifier to be removed.
|
||||||
*/
|
*/
|
||||||
|
@ -73,11 +73,6 @@ int replay_get_instructions(void);
|
|||||||
/*! Updates instructions counter in replay mode. */
|
/*! Updates instructions counter in replay mode. */
|
||||||
void replay_account_executed_instructions(void);
|
void replay_account_executed_instructions(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* replay_can_wait: check if we should pause for wait-io
|
|
||||||
*/
|
|
||||||
bool replay_can_wait(void);
|
|
||||||
|
|
||||||
/* Processing clocks and other time sources */
|
/* Processing clocks and other time sources */
|
||||||
|
|
||||||
/*! Save the specified clock */
|
/*! Save the specified clock */
|
||||||
|
@ -9,6 +9,7 @@ void runstate_set(RunState new_state);
|
|||||||
RunState runstate_get(void);
|
RunState runstate_get(void);
|
||||||
bool runstate_is_running(void);
|
bool runstate_is_running(void);
|
||||||
bool runstate_needs_reset(void);
|
bool runstate_needs_reset(void);
|
||||||
|
void runstate_replay_enable(void);
|
||||||
|
|
||||||
typedef void VMChangeStateHandler(void *opaque, bool running, RunState state);
|
typedef void VMChangeStateHandler(void *opaque, bool running, RunState state);
|
||||||
|
|
||||||
|
@ -3288,6 +3288,7 @@ bool load_snapshot(const char *name, const char *vmstate,
|
|||||||
/* Don't even try to load empty VM states */
|
/* Don't even try to load empty VM states */
|
||||||
ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
|
ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
error_setg(errp, "Snapshot can not be found");
|
||||||
return false;
|
return false;
|
||||||
} else if (sn.vm_state_size == 0) {
|
} else if (sn.vm_state_size == 0) {
|
||||||
error_setg(errp, "This is a disk-only snapshot. Revert to it "
|
error_setg(errp, "This is a disk-only snapshot. Revert to it "
|
||||||
|
@ -214,30 +214,49 @@ CPUPluginState *qemu_plugin_create_vcpu_state(void)
|
|||||||
|
|
||||||
static void plugin_grow_scoreboards__locked(CPUState *cpu)
|
static void plugin_grow_scoreboards__locked(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (cpu->cpu_index < plugin.scoreboard_alloc_size) {
|
size_t scoreboard_size = plugin.scoreboard_alloc_size;
|
||||||
|
bool need_realloc = false;
|
||||||
|
|
||||||
|
if (cpu->cpu_index < scoreboard_size) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool need_realloc = FALSE;
|
while (cpu->cpu_index >= scoreboard_size) {
|
||||||
while (cpu->cpu_index >= plugin.scoreboard_alloc_size) {
|
scoreboard_size *= 2;
|
||||||
plugin.scoreboard_alloc_size *= 2;
|
need_realloc = true;
|
||||||
need_realloc = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!need_realloc) {
|
||||||
if (!need_realloc || QLIST_EMPTY(&plugin.scoreboards)) {
|
|
||||||
/* nothing to do, we just updated sizes for future scoreboards */
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (QLIST_EMPTY(&plugin.scoreboards)) {
|
||||||
|
/* just update size for future scoreboards */
|
||||||
|
plugin.scoreboard_alloc_size = scoreboard_size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A scoreboard creation/deletion might be in progress. If a new vcpu is
|
||||||
|
* initialized at the same time, we are safe, as the new
|
||||||
|
* plugin.scoreboard_alloc_size was not yet written.
|
||||||
|
*/
|
||||||
|
qemu_rec_mutex_unlock(&plugin.lock);
|
||||||
|
|
||||||
/* cpus must be stopped, as tb might still use an existing scoreboard. */
|
/* cpus must be stopped, as tb might still use an existing scoreboard. */
|
||||||
start_exclusive();
|
start_exclusive();
|
||||||
struct qemu_plugin_scoreboard *score;
|
/* re-acquire lock */
|
||||||
QLIST_FOREACH(score, &plugin.scoreboards, entry) {
|
qemu_rec_mutex_lock(&plugin.lock);
|
||||||
g_array_set_size(score->data, plugin.scoreboard_alloc_size);
|
/* in case another vcpu is created between unlock and exclusive section. */
|
||||||
|
if (scoreboard_size > plugin.scoreboard_alloc_size) {
|
||||||
|
struct qemu_plugin_scoreboard *score;
|
||||||
|
QLIST_FOREACH(score, &plugin.scoreboards, entry) {
|
||||||
|
g_array_set_size(score->data, scoreboard_size);
|
||||||
|
}
|
||||||
|
plugin.scoreboard_alloc_size = scoreboard_size;
|
||||||
|
/* force all tb to be flushed, as scoreboard pointers were changed. */
|
||||||
|
tb_flush(cpu);
|
||||||
}
|
}
|
||||||
/* force all tb to be flushed, as scoreboard pointers were changed. */
|
|
||||||
tb_flush(cpu);
|
|
||||||
end_exclusive();
|
end_exclusive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
if not get_option('plugins')
|
||||||
|
subdir_done()
|
||||||
|
endif
|
||||||
|
|
||||||
# Modules need more symbols than just those in plugins/qemu-plugins.symbols
|
# Modules need more symbols than just those in plugins/qemu-plugins.symbols
|
||||||
if not enable_modules
|
if not enable_modules
|
||||||
if host_os == 'darwin'
|
if host_os == 'darwin'
|
||||||
@ -12,29 +16,27 @@ if not enable_modules
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('plugins')
|
if host_os == 'windows'
|
||||||
if host_os == 'windows'
|
dlltool = find_program('dlltool', required: true)
|
||||||
dlltool = find_program('dlltool', required: true)
|
|
||||||
|
|
||||||
# Generate a .lib file for plugins to link against.
|
# Generate a .lib file for plugins to link against.
|
||||||
# First, create a .def file listing all the symbols a plugin should expect to have
|
# First, create a .def file listing all the symbols a plugin should expect to have
|
||||||
# available in qemu
|
# available in qemu
|
||||||
win32_plugin_def = configure_file(
|
win32_plugin_def = configure_file(
|
||||||
input: files('qemu-plugins.symbols'),
|
input: files('qemu-plugins.symbols'),
|
||||||
output: 'qemu_plugin_api.def',
|
output: 'qemu_plugin_api.def',
|
||||||
capture: true,
|
capture: true,
|
||||||
command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
|
command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
|
||||||
# then use dlltool to assemble a delaylib.
|
# then use dlltool to assemble a delaylib.
|
||||||
win32_qemu_plugin_api_lib = configure_file(
|
win32_qemu_plugin_api_lib = configure_file(
|
||||||
input: win32_plugin_def,
|
input: win32_plugin_def,
|
||||||
output: 'libqemu_plugin_api.a',
|
output: 'libqemu_plugin_api.a',
|
||||||
command: [dlltool, '--input-def', '@INPUT@',
|
command: [dlltool, '--input-def', '@INPUT@',
|
||||||
'--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
|
'--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
|
||||||
)
|
)
|
||||||
endif
|
|
||||||
specific_ss.add(files(
|
|
||||||
'loader.c',
|
|
||||||
'core.c',
|
|
||||||
'api.c',
|
|
||||||
))
|
|
||||||
endif
|
endif
|
||||||
|
specific_ss.add(files(
|
||||||
|
'loader.c',
|
||||||
|
'core.c',
|
||||||
|
'api.c',
|
||||||
|
))
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
##
|
##
|
||||||
# @RockerPortDuplex:
|
# @RockerPortDuplex:
|
||||||
#
|
#
|
||||||
# An eumeration of port duplex states.
|
# An enumeration of port duplex states.
|
||||||
#
|
#
|
||||||
# @half: half duplex
|
# @half: half duplex
|
||||||
#
|
#
|
||||||
@ -55,7 +55,7 @@
|
|||||||
##
|
##
|
||||||
# @RockerPortAutoneg:
|
# @RockerPortAutoneg:
|
||||||
#
|
#
|
||||||
# An eumeration of port autoneg states.
|
# An enumeration of port autoneg states.
|
||||||
#
|
#
|
||||||
# @off: autoneg is off
|
# @off: autoneg is off
|
||||||
#
|
#
|
||||||
|
@ -257,7 +257,7 @@ QEMU_COPYRIGHT "\n"
|
|||||||
"\n"
|
"\n"
|
||||||
" -c, --config=PATH configuration file path (default is\n"
|
" -c, --config=PATH configuration file path (default is\n"
|
||||||
" %s/qemu-ga.conf\n"
|
" %s/qemu-ga.conf\n"
|
||||||
" unless overriden by the QGA_CONF environment variable)\n"
|
" unless overridden by the QGA_CONF environment variable)\n"
|
||||||
" -m, --method transport method: one of unix-listen, virtio-serial,\n"
|
" -m, --method transport method: one of unix-listen, virtio-serial,\n"
|
||||||
" isa-serial, or vsock-listen (virtio-serial is the default)\n"
|
" isa-serial, or vsock-listen (virtio-serial is the default)\n"
|
||||||
" -p, --path device/socket path (the default for virtio-serial is:\n"
|
" -p, --path device/socket path (the default for virtio-serial is:\n"
|
||||||
|
@ -385,6 +385,8 @@ static void replay_enable(const char *fname, int mode)
|
|||||||
replay_fetch_data_kind();
|
replay_fetch_data_kind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runstate_replay_enable();
|
||||||
|
|
||||||
replay_init_events();
|
replay_init_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,27 +451,6 @@ void replay_start(void)
|
|||||||
replay_enable_events();
|
replay_enable_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* For none/record the answer is yes.
|
|
||||||
*/
|
|
||||||
bool replay_can_wait(void)
|
|
||||||
{
|
|
||||||
if (replay_mode == REPLAY_MODE_PLAY) {
|
|
||||||
/*
|
|
||||||
* For playback we shouldn't ever be at a point we wait. If
|
|
||||||
* the instruction count has reached zero and we have an
|
|
||||||
* unconsumed event we should go around again and consume it.
|
|
||||||
*/
|
|
||||||
if (replay_state.instruction_count == 0 && replay_state.has_unread_data) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
replay_sync_error("Playback shouldn't have to iowait");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void replay_finish(void)
|
void replay_finish(void)
|
||||||
{
|
{
|
||||||
if (replay_mode == REPLAY_MODE_NONE) {
|
if (replay_mode == REPLAY_MODE_NONE) {
|
||||||
|
@ -1374,6 +1374,9 @@ sub process {
|
|||||||
my $in_header_lines = $file ? 0 : 1;
|
my $in_header_lines = $file ? 0 : 1;
|
||||||
my $in_commit_log = 0; #Scanning lines before patch
|
my $in_commit_log = 0; #Scanning lines before patch
|
||||||
my $reported_maintainer_file = 0;
|
my $reported_maintainer_file = 0;
|
||||||
|
my $reported_mixing_imported_file = 0;
|
||||||
|
my $in_imported_file = 0;
|
||||||
|
my $in_no_imported_file = 0;
|
||||||
my $non_utf8_charset = 0;
|
my $non_utf8_charset = 0;
|
||||||
|
|
||||||
our @report = ();
|
our @report = ();
|
||||||
@ -1673,6 +1676,27 @@ sub process {
|
|||||||
# ignore non-hunk lines and lines being removed
|
# ignore non-hunk lines and lines being removed
|
||||||
next if (!$hunk_line || $line =~ /^-/);
|
next if (!$hunk_line || $line =~ /^-/);
|
||||||
|
|
||||||
|
# Check that updating imported files from Linux are not mixed with other changes
|
||||||
|
if ($realfile =~ /^(linux-headers|include\/standard-headers)\//) {
|
||||||
|
if (!$in_imported_file) {
|
||||||
|
WARN("added, moved or deleted file(s) " .
|
||||||
|
"imported from Linux, are you using " .
|
||||||
|
"scripts/update-linux-headers.sh?\n" .
|
||||||
|
$herecurr);
|
||||||
|
}
|
||||||
|
$in_imported_file = 1;
|
||||||
|
} else {
|
||||||
|
$in_no_imported_file = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$reported_mixing_imported_file &&
|
||||||
|
$in_imported_file && $in_no_imported_file) {
|
||||||
|
ERROR("headers imported from Linux should be self-" .
|
||||||
|
"contained in a patch with no other changes\n" .
|
||||||
|
$herecurr);
|
||||||
|
$reported_mixing_imported_file = 1;
|
||||||
|
}
|
||||||
|
|
||||||
# ignore files that are being periodically imported from Linux
|
# ignore files that are being periodically imported from Linux
|
||||||
next if ($realfile =~ /^(linux-headers|include\/standard-headers)\//);
|
next if ($realfile =~ /^(linux-headers|include\/standard-headers)\//);
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import struct
|
import struct
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
@ -99,7 +101,7 @@ def call_decode(table, index, dumpfile):
|
|||||||
print("Could not decode index: %d" % (index))
|
print("Could not decode index: %d" % (index))
|
||||||
print("Entry is: %s" % (decoder))
|
print("Entry is: %s" % (decoder))
|
||||||
print("Decode Table is:\n%s" % (table))
|
print("Decode Table is:\n%s" % (table))
|
||||||
return False
|
raise(Exception("unknown event"))
|
||||||
else:
|
else:
|
||||||
return decoder.fn(decoder.eid, decoder.name, dumpfile)
|
return decoder.fn(decoder.eid, decoder.name, dumpfile)
|
||||||
|
|
||||||
@ -120,7 +122,7 @@ def print_event(eid, name, string=None, event_count=None):
|
|||||||
def decode_unimp(eid, name, _unused_dumpfile):
|
def decode_unimp(eid, name, _unused_dumpfile):
|
||||||
"Unimplemented decoder, will trigger exit"
|
"Unimplemented decoder, will trigger exit"
|
||||||
print("%s not handled - will now stop" % (name))
|
print("%s not handled - will now stop" % (name))
|
||||||
return False
|
raise(Exception("unhandled event"))
|
||||||
|
|
||||||
def decode_plain(eid, name, _unused_dumpfile):
|
def decode_plain(eid, name, _unused_dumpfile):
|
||||||
"Plain events without additional data"
|
"Plain events without additional data"
|
||||||
@ -134,6 +136,30 @@ def swallow_async_qword(eid, name, dumpfile):
|
|||||||
print(" %s(%d) @ %d" % (name, eid, step_id))
|
print(" %s(%d) @ %d" % (name, eid, step_id))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def swallow_bytes(eid, name, dumpfile, nr):
|
||||||
|
"""Swallow nr bytes of data without looking at it"""
|
||||||
|
dumpfile.seek(nr, os.SEEK_CUR)
|
||||||
|
|
||||||
|
total_insns = 0
|
||||||
|
|
||||||
|
def decode_instruction(eid, name, dumpfile):
|
||||||
|
global total_insns
|
||||||
|
ins_diff = read_dword(dumpfile)
|
||||||
|
total_insns += ins_diff
|
||||||
|
print_event(eid, name, "+ %d -> %d" % (ins_diff, total_insns))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def decode_interrupt(eid, name, dumpfile):
|
||||||
|
print_event(eid, name)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def decode_exception(eid, name, dumpfile):
|
||||||
|
print_event(eid, name)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# v12 does away with the additional event byte and encodes it in the main type
|
||||||
|
# Between v8 and v9, REPLAY_ASYNC_BH_ONESHOT was added, but we don't decode
|
||||||
|
# those versions so leave it out.
|
||||||
async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword),
|
async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword),
|
||||||
Decoder(1, "REPLAY_ASYNC_INPUT", decode_unimp),
|
Decoder(1, "REPLAY_ASYNC_INPUT", decode_unimp),
|
||||||
Decoder(2, "REPLAY_ASYNC_INPUT_SYNC", decode_unimp),
|
Decoder(2, "REPLAY_ASYNC_INPUT_SYNC", decode_unimp),
|
||||||
@ -142,8 +168,8 @@ async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword),
|
|||||||
Decoder(5, "REPLAY_ASYNC_EVENT_NET", decode_unimp),
|
Decoder(5, "REPLAY_ASYNC_EVENT_NET", decode_unimp),
|
||||||
]
|
]
|
||||||
# See replay_read_events/replay_read_event
|
# See replay_read_events/replay_read_event
|
||||||
def decode_async(eid, name, dumpfile):
|
def decode_async_old(eid, name, dumpfile):
|
||||||
"""Decode an ASYNC event"""
|
"""Decode an ASYNC event (pre-v8)"""
|
||||||
|
|
||||||
print_event(eid, name)
|
print_event(eid, name)
|
||||||
|
|
||||||
@ -157,13 +183,37 @@ def decode_async(eid, name, dumpfile):
|
|||||||
|
|
||||||
return call_decode(async_decode_table, async_event_kind, dumpfile)
|
return call_decode(async_decode_table, async_event_kind, dumpfile)
|
||||||
|
|
||||||
total_insns = 0
|
def decode_async_bh(eid, name, dumpfile):
|
||||||
|
op_id = read_qword(dumpfile)
|
||||||
|
print_event(eid, name)
|
||||||
|
return True
|
||||||
|
|
||||||
def decode_instruction(eid, name, dumpfile):
|
def decode_async_bh_oneshot(eid, name, dumpfile):
|
||||||
global total_insns
|
op_id = read_qword(dumpfile)
|
||||||
ins_diff = read_dword(dumpfile)
|
print_event(eid, name)
|
||||||
total_insns += ins_diff
|
return True
|
||||||
print_event(eid, name, "+ %d -> %d" % (ins_diff, total_insns))
|
|
||||||
|
def decode_async_char_read(eid, name, dumpfile):
|
||||||
|
char_id = read_byte(dumpfile)
|
||||||
|
size = read_dword(dumpfile)
|
||||||
|
print_event(eid, name, "device:%x chars:%s" % (char_id, dumpfile.read(size)))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def decode_async_block(eid, name, dumpfile):
|
||||||
|
op_id = read_qword(dumpfile)
|
||||||
|
print_event(eid, name)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def decode_async_net(eid, name, dumpfile):
|
||||||
|
net_id = read_byte(dumpfile)
|
||||||
|
flags = read_dword(dumpfile)
|
||||||
|
size = read_dword(dumpfile)
|
||||||
|
swallow_bytes(eid, name, dumpfile, size)
|
||||||
|
print_event(eid, name, "net:%x flags:%x bytes:%d" % (net_id, flags, size))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def decode_shutdown(eid, name, dumpfile):
|
||||||
|
print_event(eid, name)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def decode_char_write(eid, name, dumpfile):
|
def decode_char_write(eid, name, dumpfile):
|
||||||
@ -177,7 +227,22 @@ def decode_audio_out(eid, name, dumpfile):
|
|||||||
print_event(eid, name, "%d" % (audio_data))
|
print_event(eid, name, "%d" % (audio_data))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def decode_checkpoint(eid, name, dumpfile):
|
def decode_random(eid, name, dumpfile):
|
||||||
|
ret = read_dword(dumpfile)
|
||||||
|
size = read_dword(dumpfile)
|
||||||
|
swallow_bytes(eid, name, dumpfile, size)
|
||||||
|
if (ret):
|
||||||
|
print_event(eid, name, "%d bytes (getrandom failed)" % (size))
|
||||||
|
else:
|
||||||
|
print_event(eid, name, "%d bytes" % (size))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def decode_clock(eid, name, dumpfile):
|
||||||
|
clock_data = read_qword(dumpfile)
|
||||||
|
print_event(eid, name, "0x%x" % (clock_data))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __decode_checkpoint(eid, name, dumpfile, old):
|
||||||
"""Decode a checkpoint.
|
"""Decode a checkpoint.
|
||||||
|
|
||||||
Checkpoints contain a series of async events with their own specific data.
|
Checkpoints contain a series of async events with their own specific data.
|
||||||
@ -189,38 +254,33 @@ def decode_checkpoint(eid, name, dumpfile):
|
|||||||
|
|
||||||
# if the next event is EVENT_ASYNC there are a bunch of
|
# if the next event is EVENT_ASYNC there are a bunch of
|
||||||
# async events to read, otherwise we are done
|
# async events to read, otherwise we are done
|
||||||
if next_event != 3:
|
if (old and next_event == 3) or (not old and next_event >= 3 and next_event <= 9):
|
||||||
print_event(eid, name, "no additional data", event_number)
|
|
||||||
else:
|
|
||||||
print_event(eid, name, "more data follows", event_number)
|
print_event(eid, name, "more data follows", event_number)
|
||||||
|
else:
|
||||||
|
print_event(eid, name, "no additional data", event_number)
|
||||||
|
|
||||||
replay_state.reuse_event(next_event)
|
replay_state.reuse_event(next_event)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def decode_checkpoint_old(eid, name, dumpfile):
|
||||||
|
return __decode_checkpoint(eid, name, dumpfile, False)
|
||||||
|
|
||||||
|
def decode_checkpoint(eid, name, dumpfile):
|
||||||
|
return __decode_checkpoint(eid, name, dumpfile, True)
|
||||||
|
|
||||||
def decode_checkpoint_init(eid, name, dumpfile):
|
def decode_checkpoint_init(eid, name, dumpfile):
|
||||||
print_event(eid, name)
|
print_event(eid, name)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def decode_interrupt(eid, name, dumpfile):
|
def decode_end(eid, name, dumpfile):
|
||||||
print_event(eid, name)
|
print_event(eid, name)
|
||||||
return True
|
return False
|
||||||
|
|
||||||
def decode_clock(eid, name, dumpfile):
|
|
||||||
clock_data = read_qword(dumpfile)
|
|
||||||
print_event(eid, name, "0x%x" % (clock_data))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def decode_random(eid, name, dumpfile):
|
|
||||||
ret = read_dword(dumpfile)
|
|
||||||
data = read_array(dumpfile)
|
|
||||||
print_event(eid, "%d bytes of random data" % len(data))
|
|
||||||
return True
|
|
||||||
|
|
||||||
# pre-MTTCG merge
|
# pre-MTTCG merge
|
||||||
v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
||||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||||
Decoder(2, "EVENT_EXCEPTION", decode_plain),
|
Decoder(2, "EVENT_EXCEPTION", decode_plain),
|
||||||
Decoder(3, "EVENT_ASYNC", decode_async),
|
Decoder(3, "EVENT_ASYNC", decode_async_old),
|
||||||
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
||||||
Decoder(5, "EVENT_CHAR_WRITE", decode_char_write),
|
Decoder(5, "EVENT_CHAR_WRITE", decode_char_write),
|
||||||
Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
|
Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
|
||||||
@ -242,7 +302,7 @@ v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
|||||||
v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
||||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||||
Decoder(2, "EVENT_EXCEPTION", decode_plain),
|
Decoder(2, "EVENT_EXCEPTION", decode_plain),
|
||||||
Decoder(3, "EVENT_ASYNC", decode_async),
|
Decoder(3, "EVENT_ASYNC", decode_async_old),
|
||||||
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
||||||
Decoder(5, "EVENT_CHAR_WRITE", decode_char_write),
|
Decoder(5, "EVENT_CHAR_WRITE", decode_char_write),
|
||||||
Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
|
Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
|
||||||
@ -266,7 +326,7 @@ v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
|||||||
v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
||||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||||
Decoder(2, "EVENT_EXCEPTION", decode_unimp),
|
Decoder(2, "EVENT_EXCEPTION", decode_unimp),
|
||||||
Decoder(3, "EVENT_ASYNC", decode_async),
|
Decoder(3, "EVENT_ASYNC", decode_async_old),
|
||||||
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
|
||||||
Decoder(5, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
|
Decoder(5, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
|
||||||
Decoder(6, "EVENT_SHUTDOWN_HOST_QMP", decode_unimp),
|
Decoder(6, "EVENT_SHUTDOWN_HOST_QMP", decode_unimp),
|
||||||
@ -296,32 +356,31 @@ v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
|||||||
|
|
||||||
v12_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
v12_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
||||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||||
Decoder(2, "EVENT_EXCEPTION", decode_plain),
|
Decoder(2, "EVENT_EXCEPTION", decode_exception),
|
||||||
Decoder(3, "EVENT_ASYNC", decode_async),
|
Decoder(3, "EVENT_ASYNC_BH", decode_async_bh),
|
||||||
Decoder(4, "EVENT_ASYNC", decode_async),
|
Decoder(4, "EVENT_ASYNC_BH_ONESHOT", decode_async_bh_oneshot),
|
||||||
Decoder(5, "EVENT_ASYNC", decode_async),
|
Decoder(5, "EVENT_ASYNC_INPUT", decode_unimp),
|
||||||
Decoder(6, "EVENT_ASYNC", decode_async),
|
Decoder(6, "EVENT_ASYNC_INPUT_SYNC", decode_unimp),
|
||||||
Decoder(6, "EVENT_ASYNC", decode_async),
|
Decoder(7, "EVENT_ASYNC_CHAR_READ", decode_async_char_read),
|
||||||
Decoder(8, "EVENT_ASYNC", decode_async),
|
Decoder(8, "EVENT_ASYNC_BLOCK", decode_async_block),
|
||||||
Decoder(9, "EVENT_ASYNC", decode_async),
|
Decoder(9, "EVENT_ASYNC_NET", decode_async_net),
|
||||||
Decoder(10, "EVENT_ASYNC", decode_async),
|
Decoder(10, "EVENT_SHUTDOWN", decode_shutdown),
|
||||||
Decoder(11, "EVENT_SHUTDOWN", decode_unimp),
|
Decoder(11, "EVENT_SHUTDOWN_HOST_ERR", decode_shutdown),
|
||||||
Decoder(12, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
|
Decoder(12, "EVENT_SHUTDOWN_HOST_QMP_QUIT", decode_shutdown),
|
||||||
Decoder(13, "EVENT_SHUTDOWN_HOST_QMP_QUIT", decode_unimp),
|
Decoder(13, "EVENT_SHUTDOWN_HOST_QMP_RESET", decode_shutdown),
|
||||||
Decoder(14, "EVENT_SHUTDOWN_HOST_QMP_RESET", decode_unimp),
|
Decoder(14, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_shutdown),
|
||||||
Decoder(14, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_unimp),
|
Decoder(15, "EVENT_SHUTDOWN_HOST_UI", decode_shutdown),
|
||||||
Decoder(15, "EVENT_SHUTDOWN_HOST_UI", decode_unimp),
|
Decoder(16, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_shutdown),
|
||||||
Decoder(16, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_unimp),
|
Decoder(17, "EVENT_SHUTDOWN_GUEST_RESET", decode_shutdown),
|
||||||
Decoder(17, "EVENT_SHUTDOWN_GUEST_RESET", decode_unimp),
|
Decoder(18, "EVENT_SHUTDOWN_GUEST_PANIC", decode_shutdown),
|
||||||
Decoder(18, "EVENT_SHUTDOWN_GUEST_PANIC", decode_unimp),
|
Decoder(19, "EVENT_SHUTDOWN_SUBSYS_RESET", decode_shutdown),
|
||||||
Decoder(19, "EVENT_SHUTDOWN_GUEST_SUBSYSTEM_RESET", decode_unimp),
|
Decoder(20, "EVENT_SHUTDOWN_SNAPSHOT_LOAD", decode_shutdown),
|
||||||
Decoder(20, "EVENT_SHUTDOWN_GUEST_SNAPSHOT_LOAD", decode_unimp),
|
Decoder(21, "EVENT_SHUTDOWN___MAX", decode_shutdown),
|
||||||
Decoder(21, "EVENT_SHUTDOWN___MAX", decode_unimp),
|
|
||||||
Decoder(22, "EVENT_CHAR_WRITE", decode_char_write),
|
Decoder(22, "EVENT_CHAR_WRITE", decode_char_write),
|
||||||
Decoder(23, "EVENT_CHAR_READ_ALL", decode_unimp),
|
Decoder(23, "EVENT_CHAR_READ_ALL", decode_unimp),
|
||||||
Decoder(24, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
|
Decoder(24, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
|
||||||
Decoder(25, "EVENT_AUDIO_IN", decode_unimp),
|
Decoder(25, "EVENT_AUDIO_OUT", decode_audio_out),
|
||||||
Decoder(26, "EVENT_AUDIO_OUT", decode_audio_out),
|
Decoder(26, "EVENT_AUDIO_IN", decode_unimp),
|
||||||
Decoder(27, "EVENT_RANDOM", decode_random),
|
Decoder(27, "EVENT_RANDOM", decode_random),
|
||||||
Decoder(28, "EVENT_CLOCK_HOST", decode_clock),
|
Decoder(28, "EVENT_CLOCK_HOST", decode_clock),
|
||||||
Decoder(29, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
|
Decoder(29, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
|
||||||
@ -334,6 +393,7 @@ v12_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
|||||||
Decoder(36, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
|
Decoder(36, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
|
||||||
Decoder(37, "EVENT_CP_INIT", decode_checkpoint_init),
|
Decoder(37, "EVENT_CP_INIT", decode_checkpoint_init),
|
||||||
Decoder(38, "EVENT_CP_RESET", decode_checkpoint),
|
Decoder(38, "EVENT_CP_RESET", decode_checkpoint),
|
||||||
|
Decoder(39, "EVENT_END", decode_end),
|
||||||
]
|
]
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
@ -375,6 +435,7 @@ def decode_file(filename):
|
|||||||
dumpfile)
|
dumpfile)
|
||||||
except Exception as inst:
|
except Exception as inst:
|
||||||
print(f"error {inst}")
|
print(f"error {inst}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
print(f"Reached {dumpfile.tell()} of {dumpsize} bytes")
|
print(f"Reached {dumpfile.tell()} of {dumpsize} bytes")
|
||||||
|
@ -181,6 +181,12 @@ static const RunStateTransition runstate_transitions_def[] = {
|
|||||||
{ RUN_STATE__MAX, RUN_STATE__MAX },
|
{ RUN_STATE__MAX, RUN_STATE__MAX },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const RunStateTransition replay_play_runstate_transitions_def[] = {
|
||||||
|
{ RUN_STATE_SHUTDOWN, RUN_STATE_RUNNING},
|
||||||
|
|
||||||
|
{ RUN_STATE__MAX, RUN_STATE__MAX },
|
||||||
|
};
|
||||||
|
|
||||||
static bool runstate_valid_transitions[RUN_STATE__MAX][RUN_STATE__MAX];
|
static bool runstate_valid_transitions[RUN_STATE__MAX][RUN_STATE__MAX];
|
||||||
|
|
||||||
bool runstate_check(RunState state)
|
bool runstate_check(RunState state)
|
||||||
@ -188,14 +194,33 @@ bool runstate_check(RunState state)
|
|||||||
return current_run_state == state;
|
return current_run_state == state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runstate_init(void)
|
static void transitions_set_valid(const RunStateTransition *rst)
|
||||||
{
|
{
|
||||||
const RunStateTransition *p;
|
const RunStateTransition *p;
|
||||||
|
|
||||||
memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
|
for (p = rst; p->from != RUN_STATE__MAX; p++) {
|
||||||
for (p = &runstate_transitions_def[0]; p->from != RUN_STATE__MAX; p++) {
|
|
||||||
runstate_valid_transitions[p->from][p->to] = true;
|
runstate_valid_transitions[p->from][p->to] = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runstate_replay_enable(void)
|
||||||
|
{
|
||||||
|
assert(replay_mode != REPLAY_MODE_NONE);
|
||||||
|
|
||||||
|
if (replay_mode == REPLAY_MODE_PLAY) {
|
||||||
|
/*
|
||||||
|
* When reverse-debugging, it is possible to move state from
|
||||||
|
* shutdown to running.
|
||||||
|
*/
|
||||||
|
transitions_set_valid(&replay_play_runstate_transitions_def[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void runstate_init(void)
|
||||||
|
{
|
||||||
|
memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
|
||||||
|
|
||||||
|
transitions_set_valid(&runstate_transitions_def[0]);
|
||||||
|
|
||||||
qemu_mutex_init(&vmstop_lock);
|
qemu_mutex_init(&vmstop_lock);
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,11 @@ static void *access_ptr(X86Access *ac, vaddr addr, unsigned len)
|
|||||||
|
|
||||||
assert(addr >= ac->vaddr);
|
assert(addr >= ac->vaddr);
|
||||||
|
|
||||||
|
/* No haddr means probe_access wants to force slow path */
|
||||||
|
if (!ac->haddr1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
assert(offset <= ac->size1 - len);
|
assert(offset <= ac->size1 - len);
|
||||||
return ac->haddr1 + offset;
|
return ac->haddr1 + offset;
|
||||||
@ -78,17 +83,11 @@ static void *access_ptr(X86Access *ac, vaddr addr, unsigned len)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
# define test_ptr(p) true
|
|
||||||
#else
|
|
||||||
# define test_ptr(p) likely(p)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t access_ldb(X86Access *ac, vaddr addr)
|
uint8_t access_ldb(X86Access *ac, vaddr addr)
|
||||||
{
|
{
|
||||||
void *p = access_ptr(ac, addr, sizeof(uint8_t));
|
void *p = access_ptr(ac, addr, sizeof(uint8_t));
|
||||||
|
|
||||||
if (test_ptr(p)) {
|
if (likely(p)) {
|
||||||
return ldub_p(p);
|
return ldub_p(p);
|
||||||
}
|
}
|
||||||
return cpu_ldub_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
|
return cpu_ldub_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
|
||||||
@ -98,7 +97,7 @@ uint16_t access_ldw(X86Access *ac, vaddr addr)
|
|||||||
{
|
{
|
||||||
void *p = access_ptr(ac, addr, sizeof(uint16_t));
|
void *p = access_ptr(ac, addr, sizeof(uint16_t));
|
||||||
|
|
||||||
if (test_ptr(p)) {
|
if (likely(p)) {
|
||||||
return lduw_le_p(p);
|
return lduw_le_p(p);
|
||||||
}
|
}
|
||||||
return cpu_lduw_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
|
return cpu_lduw_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
|
||||||
@ -108,7 +107,7 @@ uint32_t access_ldl(X86Access *ac, vaddr addr)
|
|||||||
{
|
{
|
||||||
void *p = access_ptr(ac, addr, sizeof(uint32_t));
|
void *p = access_ptr(ac, addr, sizeof(uint32_t));
|
||||||
|
|
||||||
if (test_ptr(p)) {
|
if (likely(p)) {
|
||||||
return ldl_le_p(p);
|
return ldl_le_p(p);
|
||||||
}
|
}
|
||||||
return cpu_ldl_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
|
return cpu_ldl_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
|
||||||
@ -118,7 +117,7 @@ uint64_t access_ldq(X86Access *ac, vaddr addr)
|
|||||||
{
|
{
|
||||||
void *p = access_ptr(ac, addr, sizeof(uint64_t));
|
void *p = access_ptr(ac, addr, sizeof(uint64_t));
|
||||||
|
|
||||||
if (test_ptr(p)) {
|
if (likely(p)) {
|
||||||
return ldq_le_p(p);
|
return ldq_le_p(p);
|
||||||
}
|
}
|
||||||
return cpu_ldq_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
|
return cpu_ldq_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
|
||||||
@ -128,7 +127,7 @@ void access_stb(X86Access *ac, vaddr addr, uint8_t val)
|
|||||||
{
|
{
|
||||||
void *p = access_ptr(ac, addr, sizeof(uint8_t));
|
void *p = access_ptr(ac, addr, sizeof(uint8_t));
|
||||||
|
|
||||||
if (test_ptr(p)) {
|
if (likely(p)) {
|
||||||
stb_p(p, val);
|
stb_p(p, val);
|
||||||
} else {
|
} else {
|
||||||
cpu_stb_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
cpu_stb_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
||||||
@ -139,7 +138,7 @@ void access_stw(X86Access *ac, vaddr addr, uint16_t val)
|
|||||||
{
|
{
|
||||||
void *p = access_ptr(ac, addr, sizeof(uint16_t));
|
void *p = access_ptr(ac, addr, sizeof(uint16_t));
|
||||||
|
|
||||||
if (test_ptr(p)) {
|
if (likely(p)) {
|
||||||
stw_le_p(p, val);
|
stw_le_p(p, val);
|
||||||
} else {
|
} else {
|
||||||
cpu_stw_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
cpu_stw_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
||||||
@ -150,7 +149,7 @@ void access_stl(X86Access *ac, vaddr addr, uint32_t val)
|
|||||||
{
|
{
|
||||||
void *p = access_ptr(ac, addr, sizeof(uint32_t));
|
void *p = access_ptr(ac, addr, sizeof(uint32_t));
|
||||||
|
|
||||||
if (test_ptr(p)) {
|
if (likely(p)) {
|
||||||
stl_le_p(p, val);
|
stl_le_p(p, val);
|
||||||
} else {
|
} else {
|
||||||
cpu_stl_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
cpu_stl_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
||||||
@ -161,7 +160,7 @@ void access_stq(X86Access *ac, vaddr addr, uint64_t val)
|
|||||||
{
|
{
|
||||||
void *p = access_ptr(ac, addr, sizeof(uint64_t));
|
void *p = access_ptr(ac, addr, sizeof(uint64_t));
|
||||||
|
|
||||||
if (test_ptr(p)) {
|
if (likely(p)) {
|
||||||
stq_le_p(p, val);
|
stq_le_p(p, val);
|
||||||
} else {
|
} else {
|
||||||
cpu_stq_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
cpu_stq_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
||||||
|
@ -22,8 +22,6 @@ class RxGdbSimMachine(QemuSystemTest):
|
|||||||
timeout = 30
|
timeout = 30
|
||||||
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
|
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
|
||||||
|
|
||||||
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
|
|
||||||
|
|
||||||
def test_uboot(self):
|
def test_uboot(self):
|
||||||
"""
|
"""
|
||||||
U-Boot and checks that the console is operational.
|
U-Boot and checks that the console is operational.
|
||||||
|
@ -13,6 +13,7 @@ import lzma
|
|||||||
import shutil
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from avocado import skip
|
from avocado import skip
|
||||||
from avocado import skipUnless
|
from avocado import skipUnless
|
||||||
@ -31,7 +32,7 @@ class ReplayKernelBase(LinuxKernelTest):
|
|||||||
terminates.
|
terminates.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
timeout = 120
|
timeout = 180
|
||||||
KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
|
KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
|
||||||
|
|
||||||
def run_vm(self, kernel_path, kernel_command_line, console_pattern,
|
def run_vm(self, kernel_path, kernel_command_line, console_pattern,
|
||||||
@ -63,6 +64,8 @@ class ReplayKernelBase(LinuxKernelTest):
|
|||||||
vm.shutdown()
|
vm.shutdown()
|
||||||
logger.info('finished the recording with log size %s bytes'
|
logger.info('finished the recording with log size %s bytes'
|
||||||
% os.path.getsize(replay_path))
|
% os.path.getsize(replay_path))
|
||||||
|
self.run_replay_dump(replay_path)
|
||||||
|
logger.info('successfully tested replay-dump.py')
|
||||||
else:
|
else:
|
||||||
vm.wait()
|
vm.wait()
|
||||||
logger.info('successfully finished the replay')
|
logger.info('successfully finished the replay')
|
||||||
@ -70,6 +73,14 @@ class ReplayKernelBase(LinuxKernelTest):
|
|||||||
logger.info('elapsed time %.2f sec' % elapsed)
|
logger.info('elapsed time %.2f sec' % elapsed)
|
||||||
return elapsed
|
return elapsed
|
||||||
|
|
||||||
|
def run_replay_dump(self, replay_path):
|
||||||
|
try:
|
||||||
|
subprocess.check_call(["./scripts/replay-dump.py",
|
||||||
|
"-f", replay_path],
|
||||||
|
stdout=subprocess.DEVNULL)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
self.fail('replay-dump.py failed')
|
||||||
|
|
||||||
def run_rr(self, kernel_path, kernel_command_line, console_pattern,
|
def run_rr(self, kernel_path, kernel_command_line, console_pattern,
|
||||||
shift=7, args=None):
|
shift=7, args=None):
|
||||||
replay_path = os.path.join(self.workdir, 'replay.bin')
|
replay_path = os.path.join(self.workdir, 'replay.bin')
|
||||||
@ -99,7 +110,7 @@ class ReplayKernelNormal(ReplayKernelBase):
|
|||||||
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
|
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
|
||||||
|
|
||||||
# See https://gitlab.com/qemu-project/qemu/-/issues/2094
|
# See https://gitlab.com/qemu-project/qemu/-/issues/2094
|
||||||
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test sometimes gets stuck')
|
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'pc machine is unstable with replay')
|
||||||
def test_x86_64_pc(self):
|
def test_x86_64_pc(self):
|
||||||
"""
|
"""
|
||||||
:avocado: tags=arch:x86_64
|
:avocado: tags=arch:x86_64
|
||||||
@ -117,6 +128,22 @@ class ReplayKernelNormal(ReplayKernelBase):
|
|||||||
|
|
||||||
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
|
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
|
||||||
|
|
||||||
|
def test_x86_64_q35(self):
|
||||||
|
"""
|
||||||
|
:avocado: tags=arch:x86_64
|
||||||
|
:avocado: tags=machine:q35
|
||||||
|
"""
|
||||||
|
kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
|
||||||
|
'/linux/releases/29/Everything/x86_64/os/images/pxeboot'
|
||||||
|
'/vmlinuz')
|
||||||
|
kernel_hash = '23bebd2680757891cf7adedb033532163a792495'
|
||||||
|
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
|
||||||
|
|
||||||
|
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
|
||||||
|
console_pattern = 'VFS: Cannot open root device'
|
||||||
|
|
||||||
|
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
|
||||||
|
|
||||||
def test_mips_malta(self):
|
def test_mips_malta(self):
|
||||||
"""
|
"""
|
||||||
:avocado: tags=arch:mips
|
:avocado: tags=arch:mips
|
||||||
|
@ -94,6 +94,8 @@ class ReplayLinux(LinuxTest):
|
|||||||
vm.shutdown()
|
vm.shutdown()
|
||||||
logger.info('finished the recording with log size %s bytes'
|
logger.info('finished the recording with log size %s bytes'
|
||||||
% os.path.getsize(replay_path))
|
% os.path.getsize(replay_path))
|
||||||
|
self.run_replay_dump(replay_path)
|
||||||
|
logger.info('successfully tested replay-dump.py')
|
||||||
else:
|
else:
|
||||||
vm.event_wait('SHUTDOWN', self.timeout)
|
vm.event_wait('SHUTDOWN', self.timeout)
|
||||||
vm.wait()
|
vm.wait()
|
||||||
@ -108,6 +110,14 @@ class ReplayLinux(LinuxTest):
|
|||||||
logger = logging.getLogger('replay')
|
logger = logging.getLogger('replay')
|
||||||
logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
|
logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
|
||||||
|
|
||||||
|
def run_replay_dump(self, replay_path):
|
||||||
|
try:
|
||||||
|
subprocess.check_call(["./scripts/replay-dump.py",
|
||||||
|
"-f", replay_path],
|
||||||
|
stdout=subprocess.DEVNULL)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
self.fail('replay-dump.py failed')
|
||||||
|
|
||||||
@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
|
@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
|
||||||
class ReplayLinuxX8664(ReplayLinux):
|
class ReplayLinuxX8664(ReplayLinux):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user