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
|
||||
|
||||
# 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
|
||||
@if test -f meson-private/coredata.dat; then \
|
||||
./config.status --skip-meson; \
|
||||
|
@ -109,7 +109,7 @@ static void rr_wait_io_event(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
while (all_cpu_threads_idle() && replay_can_wait()) {
|
||||
while (all_cpu_threads_idle()) {
|
||||
rr_stop_kick_timer();
|
||||
qemu_cond_wait_bql(first_cpu->halt_cond);
|
||||
}
|
||||
|
@ -615,11 +615,24 @@ ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
|
||||
return backend;
|
||||
}
|
||||
|
||||
Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
|
||||
Error **errp)
|
||||
static void qemu_chardev_set_replay(Chardev *chr, 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;
|
||||
Chardev *chr = NULL;
|
||||
Chardev *base = NULL, *chr = NULL;
|
||||
ChardevBackend *backend = NULL;
|
||||
const char *name = qemu_opt_get(opts, "backend");
|
||||
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,
|
||||
object_class_get_name(OBJECT_CLASS(cc)),
|
||||
backend, context, errp);
|
||||
|
||||
if (chr == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
base = chr;
|
||||
if (bid) {
|
||||
Chardev *mux;
|
||||
qapi_free_ChardevBackend(backend);
|
||||
@ -681,11 +694,25 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
|
||||
out:
|
||||
qapi_free_ChardevBackend(backend);
|
||||
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;
|
||||
}
|
||||
|
||||
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
|
||||
bool permit_mux_mon, GMainContext *context)
|
||||
Chardev *qemu_chr_new_from_opts(QemuOpts *opts, 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;
|
||||
Chardev *chr;
|
||||
@ -693,14 +720,22 @@ Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
|
||||
Error *err = NULL;
|
||||
|
||||
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);
|
||||
if (!opts)
|
||||
return NULL;
|
||||
|
||||
chr = qemu_chr_new_from_opts(opts, context, &err);
|
||||
chr = __qemu_chr_new_from_opts(opts, context, replay, &err);
|
||||
if (!chr) {
|
||||
error_report_err(err);
|
||||
goto out;
|
||||
@ -722,24 +757,18 @@ out:
|
||||
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,
|
||||
const char *filename,
|
||||
bool permit_mux_mon,
|
||||
GMainContext *context)
|
||||
{
|
||||
Chardev *chr;
|
||||
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;
|
||||
return __qemu_chr_new(label, filename, permit_mux_mon, context, true);
|
||||
}
|
||||
|
||||
Chardev *qemu_chr_new(const char *label, const char *filename,
|
||||
|
8
configure
vendored
8
configure
vendored
@ -1103,8 +1103,10 @@ fi
|
||||
# gdb test
|
||||
|
||||
if test -n "$gdb_bin"; then
|
||||
gdb_version=$($gdb_bin --version | head -n 1)
|
||||
if version_ge ${gdb_version##* } 9.1; then
|
||||
gdb_version_string=$($gdb_bin --version | head -n 1)
|
||||
# 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)
|
||||
else
|
||||
gdb_bin=""
|
||||
@ -1673,7 +1675,7 @@ for target in $target_list; do
|
||||
echo "GDB=$gdb_bin" >> $config_target_mak
|
||||
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
|
||||
fi
|
||||
|
||||
|
@ -207,8 +207,8 @@ Once built a program can be run with multiple plugins loaded each with
|
||||
their own arguments::
|
||||
|
||||
$QEMU $OTHER_QEMU_ARGS \
|
||||
-plugin contrib/plugin/libhowvec.so,inline=on,count=hint \
|
||||
-plugin contrib/plugin/libhotblocks.so
|
||||
-plugin contrib/plugins/libhowvec.so,inline=on,count=hint \
|
||||
-plugin contrib/plugins/libhotblocks.so
|
||||
|
||||
Arguments are plugin specific and can be used to modify their
|
||||
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 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
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
@ -260,8 +268,7 @@ Behaviour can be tweaked with the following arguments:
|
||||
* - Option
|
||||
- Description
|
||||
* - inline=true|false
|
||||
- Use faster inline addition of a single counter. Not per-cpu and not
|
||||
thread safe.
|
||||
- Use faster inline addition of a single counter.
|
||||
* - idle=true|false
|
||||
- Dump the current execution stats whenever the guest vCPU idles
|
||||
|
||||
@ -381,6 +388,15 @@ run::
|
||||
160 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
|
||||
..........
|
||||
|
||||
@ -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
|
||||
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::
|
||||
|
||||
$ qemu-aarch64 \
|
||||
@ -736,6 +749,28 @@ The plugin will log the reason of exit, for example::
|
||||
|
||||
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
|
||||
------------------------
|
||||
|
||||
|
@ -114,7 +114,7 @@ Make sure all these above kernel configurations are selected.
|
||||
|
||||
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
|
||||
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``
|
||||
|
||||
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,
|
||||
please make sure to specify ``-mem-prealloc`` parameter to the destination VM
|
||||
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
|
||||
callbacks to some or all instructions when they are executed.
|
||||
|
||||
There is also a facility to add an inline event where code to
|
||||
increment a counter can be directly inlined with the translation.
|
||||
Currently only a simple increment is supported. This is not atomic so
|
||||
can miss counts. If you want absolute precision you should use a
|
||||
callback which can then ensure atomicity itself.
|
||||
There is also a facility to add inline instructions doing various operations,
|
||||
like adding or storing an immediate value. It is also possible to execute a
|
||||
callback conditionally, with condition being evaluated inline. All those inline
|
||||
operations are associated to a ``scoreboard``, which is a thread-local storage
|
||||
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
|
||||
invoked.
|
||||
|
@ -50,7 +50,7 @@ Options
|
||||
.. option:: -c, --config=PATH
|
||||
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
components when available.
|
||||
|
||||
However those register are accesible under priviliged access (CAP_SYS_RAWIO).
|
||||
QEMU can use an external helper to access those priviliged register.
|
||||
However those registers are accessible under privileged access (CAP_SYS_RAWIO).
|
||||
QEMU can use an external helper to access those privileged registers.
|
||||
|
||||
:program:`qemu-vmsr-helper` is that external helper; it creates a listener
|
||||
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.
|
||||
* 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,
|
||||
dma_addr_t iova, SMMUTransCfg *cfg)
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "migration/misc.h"
|
||||
#include "standard-headers/linux/ethtool.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "trace.h"
|
||||
#include "monitor/qdev.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,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
||||
} else {
|
||||
qemu_bh_schedule(q->tx_bh);
|
||||
replay_bh_schedule_event(q->tx_bh);
|
||||
}
|
||||
} else {
|
||||
if (q->tx_timer) {
|
||||
@ -2123,7 +2124,7 @@ static void virtio_net_rsc_purge(void *opq)
|
||||
chain->stat.timer++;
|
||||
if (!QTAILQ_EMPTY(&chain->buffers)) {
|
||||
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++;
|
||||
virtio_net_rsc_cache_buf(chain, nc, buf, size);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2597,7 +2598,7 @@ static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n,
|
||||
chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD;
|
||||
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);
|
||||
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);
|
||||
if (q->tx_bh) {
|
||||
qemu_bh_schedule(q->tx_bh);
|
||||
replay_bh_schedule_event(q->tx_bh);
|
||||
} else {
|
||||
timer_mod(q->tx_timer,
|
||||
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;
|
||||
}
|
||||
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)
|
||||
@ -2921,7 +2922,7 @@ static void virtio_net_tx_bh(void *opaque)
|
||||
/* If we flush a full burst of packets, assume there are
|
||||
* more coming and immediately reschedule */
|
||||
if (ret >= n->tx_burst) {
|
||||
qemu_bh_schedule(q->tx_bh);
|
||||
replay_bh_schedule_event(q->tx_bh);
|
||||
q->tx_waiting = 1;
|
||||
return;
|
||||
}
|
||||
@ -2935,7 +2936,7 @@ static void virtio_net_tx_bh(void *opaque)
|
||||
return;
|
||||
} else if (ret > 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;
|
||||
}
|
||||
}
|
||||
|
@ -1852,7 +1852,7 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
|
||||
* memory_region_unregister_iommu_notifier: unregister a notifier for
|
||||
* 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
|
||||
* @n: the notifier to be removed.
|
||||
*/
|
||||
|
@ -73,11 +73,6 @@ int replay_get_instructions(void);
|
||||
/*! Updates instructions counter in replay mode. */
|
||||
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 */
|
||||
|
||||
/*! Save the specified clock */
|
||||
|
@ -9,6 +9,7 @@ void runstate_set(RunState new_state);
|
||||
RunState runstate_get(void);
|
||||
bool runstate_is_running(void);
|
||||
bool runstate_needs_reset(void);
|
||||
void runstate_replay_enable(void);
|
||||
|
||||
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 */
|
||||
ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Snapshot can not be found");
|
||||
return false;
|
||||
} else if (sn.vm_state_size == 0) {
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool need_realloc = FALSE;
|
||||
while (cpu->cpu_index >= plugin.scoreboard_alloc_size) {
|
||||
plugin.scoreboard_alloc_size *= 2;
|
||||
need_realloc = TRUE;
|
||||
while (cpu->cpu_index >= scoreboard_size) {
|
||||
scoreboard_size *= 2;
|
||||
need_realloc = true;
|
||||
}
|
||||
|
||||
|
||||
if (!need_realloc || QLIST_EMPTY(&plugin.scoreboards)) {
|
||||
/* nothing to do, we just updated sizes for future scoreboards */
|
||||
if (!need_realloc) {
|
||||
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. */
|
||||
start_exclusive();
|
||||
struct qemu_plugin_scoreboard *score;
|
||||
QLIST_FOREACH(score, &plugin.scoreboards, entry) {
|
||||
g_array_set_size(score->data, plugin.scoreboard_alloc_size);
|
||||
/* re-acquire lock */
|
||||
qemu_rec_mutex_lock(&plugin.lock);
|
||||
/* 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();
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
if not get_option('plugins')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
# Modules need more symbols than just those in plugins/qemu-plugins.symbols
|
||||
if not enable_modules
|
||||
if host_os == 'darwin'
|
||||
@ -12,29 +16,27 @@ if not enable_modules
|
||||
endif
|
||||
endif
|
||||
|
||||
if get_option('plugins')
|
||||
if host_os == 'windows'
|
||||
dlltool = find_program('dlltool', required: true)
|
||||
if host_os == 'windows'
|
||||
dlltool = find_program('dlltool', required: true)
|
||||
|
||||
# Generate a .lib file for plugins to link against.
|
||||
# First, create a .def file listing all the symbols a plugin should expect to have
|
||||
# available in qemu
|
||||
win32_plugin_def = configure_file(
|
||||
input: files('qemu-plugins.symbols'),
|
||||
output: 'qemu_plugin_api.def',
|
||||
capture: true,
|
||||
command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
|
||||
# then use dlltool to assemble a delaylib.
|
||||
win32_qemu_plugin_api_lib = configure_file(
|
||||
input: win32_plugin_def,
|
||||
output: 'libqemu_plugin_api.a',
|
||||
command: [dlltool, '--input-def', '@INPUT@',
|
||||
'--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
|
||||
)
|
||||
endif
|
||||
specific_ss.add(files(
|
||||
'loader.c',
|
||||
'core.c',
|
||||
'api.c',
|
||||
))
|
||||
# Generate a .lib file for plugins to link against.
|
||||
# First, create a .def file listing all the symbols a plugin should expect to have
|
||||
# available in qemu
|
||||
win32_plugin_def = configure_file(
|
||||
input: files('qemu-plugins.symbols'),
|
||||
output: 'qemu_plugin_api.def',
|
||||
capture: true,
|
||||
command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
|
||||
# then use dlltool to assemble a delaylib.
|
||||
win32_qemu_plugin_api_lib = configure_file(
|
||||
input: win32_plugin_def,
|
||||
output: 'libqemu_plugin_api.a',
|
||||
command: [dlltool, '--input-def', '@INPUT@',
|
||||
'--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
|
||||
)
|
||||
endif
|
||||
specific_ss.add(files(
|
||||
'loader.c',
|
||||
'core.c',
|
||||
'api.c',
|
||||
))
|
||||
|
@ -42,7 +42,7 @@
|
||||
##
|
||||
# @RockerPortDuplex:
|
||||
#
|
||||
# An eumeration of port duplex states.
|
||||
# An enumeration of port duplex states.
|
||||
#
|
||||
# @half: half duplex
|
||||
#
|
||||
@ -55,7 +55,7 @@
|
||||
##
|
||||
# @RockerPortAutoneg:
|
||||
#
|
||||
# An eumeration of port autoneg states.
|
||||
# An enumeration of port autoneg states.
|
||||
#
|
||||
# @off: autoneg is off
|
||||
#
|
||||
|
@ -257,7 +257,7 @@ QEMU_COPYRIGHT "\n"
|
||||
"\n"
|
||||
" -c, --config=PATH configuration file path (default is\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"
|
||||
" isa-serial, or vsock-listen (virtio-serial is the default)\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();
|
||||
}
|
||||
|
||||
runstate_replay_enable();
|
||||
|
||||
replay_init_events();
|
||||
}
|
||||
|
||||
@ -449,27 +451,6 @@ void replay_start(void)
|
||||
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)
|
||||
{
|
||||
if (replay_mode == REPLAY_MODE_NONE) {
|
||||
|
@ -1374,6 +1374,9 @@ sub process {
|
||||
my $in_header_lines = $file ? 0 : 1;
|
||||
my $in_commit_log = 0; #Scanning lines before patch
|
||||
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;
|
||||
|
||||
our @report = ();
|
||||
@ -1673,6 +1676,27 @@ sub process {
|
||||
# ignore non-hunk lines and lines being removed
|
||||
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
|
||||
next if ($realfile =~ /^(linux-headers|include\/standard-headers)\//);
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
import argparse
|
||||
import struct
|
||||
import os
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from os import path
|
||||
|
||||
@ -99,7 +101,7 @@ def call_decode(table, index, dumpfile):
|
||||
print("Could not decode index: %d" % (index))
|
||||
print("Entry is: %s" % (decoder))
|
||||
print("Decode Table is:\n%s" % (table))
|
||||
return False
|
||||
raise(Exception("unknown event"))
|
||||
else:
|
||||
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):
|
||||
"Unimplemented decoder, will trigger exit"
|
||||
print("%s not handled - will now stop" % (name))
|
||||
return False
|
||||
raise(Exception("unhandled event"))
|
||||
|
||||
def decode_plain(eid, name, _unused_dumpfile):
|
||||
"Plain events without additional data"
|
||||
@ -134,6 +136,30 @@ def swallow_async_qword(eid, name, dumpfile):
|
||||
print(" %s(%d) @ %d" % (name, eid, step_id))
|
||||
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),
|
||||
Decoder(1, "REPLAY_ASYNC_INPUT", 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),
|
||||
]
|
||||
# See replay_read_events/replay_read_event
|
||||
def decode_async(eid, name, dumpfile):
|
||||
"""Decode an ASYNC event"""
|
||||
def decode_async_old(eid, name, dumpfile):
|
||||
"""Decode an ASYNC event (pre-v8)"""
|
||||
|
||||
print_event(eid, name)
|
||||
|
||||
@ -157,13 +183,37 @@ def decode_async(eid, name, 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):
|
||||
global total_insns
|
||||
ins_diff = read_dword(dumpfile)
|
||||
total_insns += ins_diff
|
||||
print_event(eid, name, "+ %d -> %d" % (ins_diff, total_insns))
|
||||
def decode_async_bh_oneshot(eid, name, dumpfile):
|
||||
op_id = read_qword(dumpfile)
|
||||
print_event(eid, name)
|
||||
return True
|
||||
|
||||
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
|
||||
|
||||
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))
|
||||
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.
|
||||
|
||||
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
|
||||
# async events to read, otherwise we are done
|
||||
if next_event != 3:
|
||||
print_event(eid, name, "no additional data", event_number)
|
||||
else:
|
||||
if (old and next_event == 3) or (not old and next_event >= 3 and next_event <= 9):
|
||||
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)
|
||||
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):
|
||||
print_event(eid, name)
|
||||
return True
|
||||
|
||||
def decode_interrupt(eid, name, dumpfile):
|
||||
def decode_end(eid, name, dumpfile):
|
||||
print_event(eid, name)
|
||||
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_random(eid, name, dumpfile):
|
||||
ret = read_dword(dumpfile)
|
||||
data = read_array(dumpfile)
|
||||
print_event(eid, "%d bytes of random data" % len(data))
|
||||
return True
|
||||
return False
|
||||
|
||||
# pre-MTTCG merge
|
||||
v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
|
||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||
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(5, "EVENT_CHAR_WRITE", decode_char_write),
|
||||
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),
|
||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||
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(5, "EVENT_CHAR_WRITE", decode_char_write),
|
||||
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),
|
||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||
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(5, "EVENT_SHUTDOWN_HOST_ERR", 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),
|
||||
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
|
||||
Decoder(2, "EVENT_EXCEPTION", decode_plain),
|
||||
Decoder(3, "EVENT_ASYNC", decode_async),
|
||||
Decoder(4, "EVENT_ASYNC", decode_async),
|
||||
Decoder(5, "EVENT_ASYNC", decode_async),
|
||||
Decoder(6, "EVENT_ASYNC", decode_async),
|
||||
Decoder(6, "EVENT_ASYNC", decode_async),
|
||||
Decoder(8, "EVENT_ASYNC", decode_async),
|
||||
Decoder(9, "EVENT_ASYNC", decode_async),
|
||||
Decoder(10, "EVENT_ASYNC", decode_async),
|
||||
Decoder(11, "EVENT_SHUTDOWN", decode_unimp),
|
||||
Decoder(12, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
|
||||
Decoder(13, "EVENT_SHUTDOWN_HOST_QMP_QUIT", decode_unimp),
|
||||
Decoder(14, "EVENT_SHUTDOWN_HOST_QMP_RESET", decode_unimp),
|
||||
Decoder(14, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_unimp),
|
||||
Decoder(15, "EVENT_SHUTDOWN_HOST_UI", decode_unimp),
|
||||
Decoder(16, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_unimp),
|
||||
Decoder(17, "EVENT_SHUTDOWN_GUEST_RESET", decode_unimp),
|
||||
Decoder(18, "EVENT_SHUTDOWN_GUEST_PANIC", decode_unimp),
|
||||
Decoder(19, "EVENT_SHUTDOWN_GUEST_SUBSYSTEM_RESET", decode_unimp),
|
||||
Decoder(20, "EVENT_SHUTDOWN_GUEST_SNAPSHOT_LOAD", decode_unimp),
|
||||
Decoder(21, "EVENT_SHUTDOWN___MAX", decode_unimp),
|
||||
Decoder(2, "EVENT_EXCEPTION", decode_exception),
|
||||
Decoder(3, "EVENT_ASYNC_BH", decode_async_bh),
|
||||
Decoder(4, "EVENT_ASYNC_BH_ONESHOT", decode_async_bh_oneshot),
|
||||
Decoder(5, "EVENT_ASYNC_INPUT", decode_unimp),
|
||||
Decoder(6, "EVENT_ASYNC_INPUT_SYNC", decode_unimp),
|
||||
Decoder(7, "EVENT_ASYNC_CHAR_READ", decode_async_char_read),
|
||||
Decoder(8, "EVENT_ASYNC_BLOCK", decode_async_block),
|
||||
Decoder(9, "EVENT_ASYNC_NET", decode_async_net),
|
||||
Decoder(10, "EVENT_SHUTDOWN", decode_shutdown),
|
||||
Decoder(11, "EVENT_SHUTDOWN_HOST_ERR", decode_shutdown),
|
||||
Decoder(12, "EVENT_SHUTDOWN_HOST_QMP_QUIT", decode_shutdown),
|
||||
Decoder(13, "EVENT_SHUTDOWN_HOST_QMP_RESET", decode_shutdown),
|
||||
Decoder(14, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_shutdown),
|
||||
Decoder(15, "EVENT_SHUTDOWN_HOST_UI", decode_shutdown),
|
||||
Decoder(16, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_shutdown),
|
||||
Decoder(17, "EVENT_SHUTDOWN_GUEST_RESET", decode_shutdown),
|
||||
Decoder(18, "EVENT_SHUTDOWN_GUEST_PANIC", decode_shutdown),
|
||||
Decoder(19, "EVENT_SHUTDOWN_SUBSYS_RESET", decode_shutdown),
|
||||
Decoder(20, "EVENT_SHUTDOWN_SNAPSHOT_LOAD", decode_shutdown),
|
||||
Decoder(21, "EVENT_SHUTDOWN___MAX", decode_shutdown),
|
||||
Decoder(22, "EVENT_CHAR_WRITE", decode_char_write),
|
||||
Decoder(23, "EVENT_CHAR_READ_ALL", decode_unimp),
|
||||
Decoder(24, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
|
||||
Decoder(25, "EVENT_AUDIO_IN", decode_unimp),
|
||||
Decoder(26, "EVENT_AUDIO_OUT", decode_audio_out),
|
||||
Decoder(25, "EVENT_AUDIO_OUT", decode_audio_out),
|
||||
Decoder(26, "EVENT_AUDIO_IN", decode_unimp),
|
||||
Decoder(27, "EVENT_RANDOM", decode_random),
|
||||
Decoder(28, "EVENT_CLOCK_HOST", 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(37, "EVENT_CP_INIT", decode_checkpoint_init),
|
||||
Decoder(38, "EVENT_CP_RESET", decode_checkpoint),
|
||||
Decoder(39, "EVENT_END", decode_end),
|
||||
]
|
||||
|
||||
def parse_arguments():
|
||||
@ -375,6 +435,7 @@ def decode_file(filename):
|
||||
dumpfile)
|
||||
except Exception as inst:
|
||||
print(f"error {inst}")
|
||||
sys.exit(1)
|
||||
|
||||
finally:
|
||||
print(f"Reached {dumpfile.tell()} of {dumpsize} bytes")
|
||||
|
@ -181,6 +181,12 @@ static const RunStateTransition runstate_transitions_def[] = {
|
||||
{ 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];
|
||||
|
||||
bool runstate_check(RunState state)
|
||||
@ -188,14 +194,33 @@ bool runstate_check(RunState state)
|
||||
return current_run_state == state;
|
||||
}
|
||||
|
||||
static void runstate_init(void)
|
||||
static void transitions_set_valid(const RunStateTransition *rst)
|
||||
{
|
||||
const RunStateTransition *p;
|
||||
|
||||
memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
|
||||
for (p = &runstate_transitions_def[0]; p->from != RUN_STATE__MAX; p++) {
|
||||
for (p = rst; p->from != RUN_STATE__MAX; p++) {
|
||||
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);
|
||||
}
|
||||
|
@ -58,6 +58,11 @@ static void *access_ptr(X86Access *ac, vaddr addr, unsigned len)
|
||||
|
||||
assert(addr >= ac->vaddr);
|
||||
|
||||
/* No haddr means probe_access wants to force slow path */
|
||||
if (!ac->haddr1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
assert(offset <= ac->size1 - len);
|
||||
return ac->haddr1 + offset;
|
||||
@ -78,17 +83,11 @@ static void *access_ptr(X86Access *ac, vaddr addr, unsigned len)
|
||||
#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)
|
||||
{
|
||||
void *p = access_ptr(ac, addr, sizeof(uint8_t));
|
||||
|
||||
if (test_ptr(p)) {
|
||||
if (likely(p)) {
|
||||
return ldub_p(p);
|
||||
}
|
||||
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));
|
||||
|
||||
if (test_ptr(p)) {
|
||||
if (likely(p)) {
|
||||
return lduw_le_p(p);
|
||||
}
|
||||
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));
|
||||
|
||||
if (test_ptr(p)) {
|
||||
if (likely(p)) {
|
||||
return ldl_le_p(p);
|
||||
}
|
||||
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));
|
||||
|
||||
if (test_ptr(p)) {
|
||||
if (likely(p)) {
|
||||
return ldq_le_p(p);
|
||||
}
|
||||
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));
|
||||
|
||||
if (test_ptr(p)) {
|
||||
if (likely(p)) {
|
||||
stb_p(p, val);
|
||||
} else {
|
||||
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));
|
||||
|
||||
if (test_ptr(p)) {
|
||||
if (likely(p)) {
|
||||
stw_le_p(p, val);
|
||||
} else {
|
||||
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));
|
||||
|
||||
if (test_ptr(p)) {
|
||||
if (likely(p)) {
|
||||
stl_le_p(p, val);
|
||||
} else {
|
||||
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));
|
||||
|
||||
if (test_ptr(p)) {
|
||||
if (likely(p)) {
|
||||
stq_le_p(p, val);
|
||||
} else {
|
||||
cpu_stq_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
|
||||
|
@ -22,8 +22,6 @@ class RxGdbSimMachine(QemuSystemTest):
|
||||
timeout = 30
|
||||
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
|
||||
|
||||
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
|
||||
|
||||
def test_uboot(self):
|
||||
"""
|
||||
U-Boot and checks that the console is operational.
|
||||
|
@ -13,6 +13,7 @@ import lzma
|
||||
import shutil
|
||||
import logging
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
from avocado import skip
|
||||
from avocado import skipUnless
|
||||
@ -31,7 +32,7 @@ class ReplayKernelBase(LinuxKernelTest):
|
||||
terminates.
|
||||
"""
|
||||
|
||||
timeout = 120
|
||||
timeout = 180
|
||||
KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
|
||||
|
||||
def run_vm(self, kernel_path, kernel_command_line, console_pattern,
|
||||
@ -63,6 +64,8 @@ class ReplayKernelBase(LinuxKernelTest):
|
||||
vm.shutdown()
|
||||
logger.info('finished the recording with log size %s bytes'
|
||||
% os.path.getsize(replay_path))
|
||||
self.run_replay_dump(replay_path)
|
||||
logger.info('successfully tested replay-dump.py')
|
||||
else:
|
||||
vm.wait()
|
||||
logger.info('successfully finished the replay')
|
||||
@ -70,6 +73,14 @@ class ReplayKernelBase(LinuxKernelTest):
|
||||
logger.info('elapsed time %.2f sec' % 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,
|
||||
shift=7, args=None):
|
||||
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)
|
||||
|
||||
# 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):
|
||||
"""
|
||||
:avocado: tags=arch:x86_64
|
||||
@ -117,6 +128,22 @@ class ReplayKernelNormal(ReplayKernelBase):
|
||||
|
||||
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):
|
||||
"""
|
||||
:avocado: tags=arch:mips
|
||||
|
@ -94,6 +94,8 @@ class ReplayLinux(LinuxTest):
|
||||
vm.shutdown()
|
||||
logger.info('finished the recording with log size %s bytes'
|
||||
% os.path.getsize(replay_path))
|
||||
self.run_replay_dump(replay_path)
|
||||
logger.info('successfully tested replay-dump.py')
|
||||
else:
|
||||
vm.event_wait('SHUTDOWN', self.timeout)
|
||||
vm.wait()
|
||||
@ -108,6 +110,14 @@ class ReplayLinux(LinuxTest):
|
||||
logger = logging.getLogger('replay')
|
||||
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')
|
||||
class ReplayLinuxX8664(ReplayLinux):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user