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:
Richard Henderson 2024-08-17 16:46:45 +10:00
commit 2eefd4fcec
27 changed files with 407 additions and 193 deletions

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
*/ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)\//);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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