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:
		
							
								
								
									
										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): | ||||
|     """ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user