[PATCH 00/31] September maintainer omnibus (tests, gdbstub, plugins)

Hi, This wraps up my current testing, gdbstub and plugin trees in an attempt to do my part to reduce the qemu-devel fire hose. For testing we have a number of cleanups to configure to better handle selecting the container engine (removing the ability to dynamically switch). I had to do this as one of my build boxes has recently acquired a broken podman install. There are also some updates to avocado sbsa-ref as well as tweaks to the gitlab setup to minimise the amount of wheel spinning we do. The deprecation of CRIS is a little provocative but if we do want to keep it we need to stop relying on a rapidly dated fedora image to do it. Finally we include the swtpm package to widen the testing we do through avocado. The gdbstub updates are from Akihiko and include a bunch of clean-ups that will hopefully pave the way for another series which allows the plugins to access register values using the gdb backend to source the data. Finally the plugins has a few fixes which includes a tweak to make SH4 atomic modelling more plugin friendly. This allows for Matt's fix to deal with non-regular instruction encoding spanning pages. I also fix a number of coverity warnings. The final time control patches are still RFC and not ready for merging but I include them for completeness. The following still need review: contrib/plugins: add iops plugin example for cost modelling plugins: add time control API sysemu: generalise qtest_warp_clock as qemu_clock_advance_virtual_time qtest: use cpu interface in qtest_clock_warp (1 acks, 1 sobs, 0 tbs) contrib/plugins: fix coverity warning in hotblocks contrib/plugins: fix coverity warning in lockstep contrib/plugins: fix coverity warning in cache configure: ensure dependency for cross-compile setup configure: remove gcc version suffixes configure: allow user to override docker engine tests/docker: make docker engine choice entirely configure driven docs: mark CRIS support as deprecated tests/lcitool: add swtpm to the package list Akihiko Odaki (12): gdbstub: Fix target_xml initialization gdbstub: Fix target.xml response plugins: Check if vCPU is realized contrib/plugins: Use GRWLock in execlog gdbstub: Introduce GDBFeature structure target/arm: Move the reference to arm-core.xml hw/core/cpu: Return static value with gdb_arch_name() gdbstub: Use g_markup_printf_escaped() target/arm: Remove references to gdb_has_xml target/ppc: Remove references to gdb_has_xml gdbstub: Remove gdb_has_xml variable gdbstub: Replace gdb_regs with an array Alex Bennée (15): tests/lcitool: add swtpm to the package list gitlab: shuffle some targets and reduce avocado noise docs: mark CRIS support as deprecated tests/docker: make docker engine choice entirely configure driven configure: allow user to override docker engine configure: remove gcc version suffixes configure: ensure dependency for cross-compile setup contrib/plugins: fix coverity warning in cache contrib/plugins: fix coverity warning in lockstep contrib/plugins: fix coverity warning in hotblocks sysemu: add set_virtual_time to accel ops qtest: use cpu interface in qtest_clock_warp sysemu: generalise qtest_warp_clock as qemu_clock_advance_virtual_time plugins: add time control API contrib/plugins: add iops plugin example for cost modelling Marcin Juszkiewicz (1): tests/avocado: update firmware to enable sbsa-ref/neoverse-v1 Matt Borgerson (1): plugins: Set final instruction count in plugin_gen_tb_end Richard Henderson (2): accel/tcg: Add plugin_enabled to DisasContextBase target/sh4: Disable decode_gusa when plugins enabled MAINTAINERS | 2 +- docs/about/deprecated.rst | 11 + configure | 15 +- meson.build | 2 +- gdbstub/internals.h | 2 - include/exec/gdbstub.h | 17 +- include/exec/plugin-gen.h | 4 +- include/exec/translator.h | 2 + include/hw/core/cpu.h | 4 +- include/qemu/qemu-plugin.h | 19 ++ include/qemu/timer.h | 15 + include/sysemu/accel-ops.h | 18 +- include/sysemu/cpu-timers.h | 27 +- include/sysemu/qtest.h | 1 + target/ppc/internal.h | 2 +- accel/qtest/qtest.c | 1 + accel/tcg/plugin-gen.c | 6 +- accel/tcg/translator.c | 3 +- contrib/plugins/cache.c | 18 +- contrib/plugins/execlog.c | 16 +- contrib/plugins/hotblocks.c | 2 +- contrib/plugins/iops.c | 261 ++++++++++++++++++ contrib/plugins/lockstep.c | 13 +- gdbstub/gdbstub.c | 95 +++---- gdbstub/softmmu.c | 2 +- plugins/api.c | 28 ++ plugins/core.c | 2 +- softmmu/cpus.c | 11 + softmmu/qtest.c | 26 +- ...t-virtual-clock.c => cpus-virtual-clock.c} | 5 + stubs/gdbstub.c | 6 +- target/arm/cpu.c | 9 +- target/arm/cpu64.c | 4 +- target/arm/gdbstub.c | 32 +-- target/i386/cpu.c | 6 +- target/loongarch/cpu.c | 8 +- target/ppc/gdbstub.c | 24 +- target/riscv/cpu.c | 6 +- target/s390x/cpu.c | 4 +- target/sh4/translate.c | 41 ++- target/tricore/cpu.c | 4 +- util/qemu-timer.c | 26 ++ .gitlab-ci.d/buildtest.yml | 15 +- .gitlab-ci.d/cirrus/macos-12.vars | 2 +- contrib/plugins/Makefile | 1 + plugins/qemu-plugins.symbols | 2 + scripts/feature_to_c.py | 48 ++++ scripts/feature_to_c.sh | 69 ----- stubs/meson.build | 2 +- tests/avocado/machine_aarch64_sbsaref.py | 25 +- tests/docker/Makefile.include | 7 +- tests/docker/dockerfiles/alpine.docker | 1 + tests/docker/dockerfiles/centos8.docker | 1 + .../dockerfiles/debian-amd64-cross.docker | 1 + tests/docker/dockerfiles/debian-amd64.docker | 1 + .../dockerfiles/debian-arm64-cross.docker | 1 + .../dockerfiles/debian-armhf-cross.docker | 1 + .../dockerfiles/debian-ppc64el-cross.docker | 1 + .../dockerfiles/debian-s390x-cross.docker | 1 + .../dockerfiles/fedora-win32-cross.docker | 1 + .../dockerfiles/fedora-win64-cross.docker | 1 + tests/docker/dockerfiles/fedora.docker | 1 + tests/docker/dockerfiles/opensuse-leap.docker | 1 + tests/docker/dockerfiles/ubuntu2204.docker | 1 + tests/lcitool/libvirt-ci | 2 +- tests/lcitool/projects/qemu.yml | 1 + 66 files changed, 689 insertions(+), 298 deletions(-) create mode 100644 contrib/plugins/iops.c rename stubs/{cpus-get-virtual-clock.c => cpus-virtual-clock.c} (68%) create mode 100755 scripts/feature_to_c.py delete mode 100644 scripts/feature_to_c.sh -- 2.39.2

From: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Update prebuilt firmware images to have TF-A with Neoverse V1 support enabled. This allowed us to enable test for this cpu in sbsa-ref machine. Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Acked-by: Leif Lindholm <quic_llindhol@quicinc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230915113519.269290-1-marcin.juszkiewicz@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tests/avocado/machine_aarch64_sbsaref.py | 25 ++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/tests/avocado/machine_aarch64_sbsaref.py b/tests/avocado/machine_aarch64_sbsaref.py index a794245e7e..b39f5566d7 100644 --- a/tests/avocado/machine_aarch64_sbsaref.py +++ b/tests/avocado/machine_aarch64_sbsaref.py @@ -28,33 +28,32 @@ def fetch_firmware(self): """ Flash volumes generated using: - - Fedora GNU Toolchain version 13.1.1 20230511 (Red Hat 13.1.1-2) + - Fedora GNU Toolchain version 13.2.1 20230728 (Red Hat 13.2.1-1) - Trusted Firmware-A - https://github.com/ARM-software/arm-trusted-firmware/tree/c0d8ee38 + https://github.com/ARM-software/arm-trusted-firmware/tree/cc933e1d - Tianocore EDK II - https://github.com/tianocore/edk2/tree/0f9283429dd4 - https://github.com/tianocore/edk2-non-osi/tree/f0bb00937ad6 - https://github.com/tianocore/edk2-platforms/tree/7880b92e2a04 + https://github.com/tianocore/edk2/tree/29cce3356aec + https://github.com/tianocore/edk2-platforms/tree/fc22c0e69709 """ # Secure BootRom (TF-A code) fs0_xz_url = ( - "https://fileserver.linaro.org/s/HrYMCjP7MEccjRP/" + "https://fileserver.linaro.org/s/g4C3WzJzNBES2p2/" "download/SBSA_FLASH0.fd.xz" ) - fs0_xz_hash = "447eff64a90b84ce47703c6ec41fbfc25befaaea" + fs0_xz_hash = "374738599f7ba38c22924b2075ec5355c2b24a47" tar_xz_path = self.fetch_asset(fs0_xz_url, asset_hash=fs0_xz_hash) archive.extract(tar_xz_path, self.workdir) fs0_path = os.path.join(self.workdir, "SBSA_FLASH0.fd") # Non-secure rom (UEFI and EFI variables) fs1_xz_url = ( - "https://fileserver.linaro.org/s/t8foNnMPz74DZZy/" + "https://fileserver.linaro.org/s/scJRninsAFTwEct/" "download/SBSA_FLASH1.fd.xz" ) - fs1_xz_hash = "13a9a262953787c7fc5a9155dfaa26e703631e02" + fs1_xz_hash = "5d3f156ebd6c6374da2121e15c7c8f4ed0351dcc" tar_xz_path = self.fetch_asset(fs1_xz_url, asset_hash=fs1_xz_hash) archive.extract(tar_xz_path, self.workdir) fs1_path = os.path.join(self.workdir, "SBSA_FLASH1.fd") @@ -144,10 +143,16 @@ def test_sbsaref_alpine_linux_cortex_a57(self): def test_sbsaref_alpine_linux_neoverse_n1(self): """ - :avocado: tags=cpu:max + :avocado: tags=cpu:neoverse-n1 """ self.boot_alpine_linux("neoverse-n1") + def test_sbsaref_alpine_linux_neoverse_v1(self): + """ + :avocado: tags=cpu:neoverse-v1 + """ + self.boot_alpine_linux("neoverse-v1,pauth-impdef=on") + def test_sbsaref_alpine_linux_max(self): """ :avocado: tags=cpu:max -- 2.39.2

We need this to test some TPM stuff. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- .gitlab-ci.d/cirrus/macos-12.vars | 2 +- tests/docker/dockerfiles/alpine.docker | 1 + tests/docker/dockerfiles/centos8.docker | 1 + tests/docker/dockerfiles/debian-amd64-cross.docker | 1 + tests/docker/dockerfiles/debian-amd64.docker | 1 + tests/docker/dockerfiles/debian-arm64-cross.docker | 1 + tests/docker/dockerfiles/debian-armhf-cross.docker | 1 + tests/docker/dockerfiles/debian-ppc64el-cross.docker | 1 + tests/docker/dockerfiles/debian-s390x-cross.docker | 1 + tests/docker/dockerfiles/fedora-win32-cross.docker | 1 + tests/docker/dockerfiles/fedora-win64-cross.docker | 1 + tests/docker/dockerfiles/fedora.docker | 1 + tests/docker/dockerfiles/opensuse-leap.docker | 1 + tests/docker/dockerfiles/ubuntu2204.docker | 1 + tests/lcitool/libvirt-ci | 2 +- tests/lcitool/projects/qemu.yml | 1 + 16 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.d/cirrus/macos-12.vars b/.gitlab-ci.d/cirrus/macos-12.vars index 80eadaab29..5f3fb346d1 100644 --- a/.gitlab-ci.d/cirrus/macos-12.vars +++ b/.gitlab-ci.d/cirrus/macos-12.vars @@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake' NINJA='/opt/homebrew/bin/ninja' PACKAGING_COMMAND='brew' PIP3='/opt/homebrew/bin/pip3' -PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol tesseract usbredir vde vte3 xorriso zlib zstd' +PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd' PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli' PYTHON='/opt/homebrew/bin/python3' diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index d25649cb4f..42f6928627 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -100,6 +100,7 @@ RUN apk update && \ sparse \ spice-dev \ spice-protocol \ + swtpm \ tar \ tesseract-ocr \ usbredir-dev \ diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 68bfe606f5..d97c30e96a 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -107,6 +107,7 @@ RUN dnf distro-sync -y && \ socat \ spice-protocol \ spice-server-devel \ + swtpm \ systemd-devel \ systemtap-sdt-devel \ tar \ diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index 0991938595..00bdc06021 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index 61dbc3ff24..9b50fb2f63 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -124,6 +124,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ systemtap-sdt-dev \ tar \ tesseract-ocr \ diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 74eabb274e..2dae3777f7 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 1ebd6ebd00..180ed836e6 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index 59091fed02..d6be2f0cc5 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index 48b2f28310..ec0041d6aa 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ tar \ tesseract-ocr \ tesseract-ocr-eng \ diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index afa988574f..08799219f9 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -55,6 +55,7 @@ exec "$@"\n' > /usr/bin/nosync && \ socat \ sparse \ spice-protocol \ + swtpm \ tar \ tesseract \ tesseract-langpack-eng \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index cf93a0ca60..f8e4cb70d3 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -55,6 +55,7 @@ exec "$@"\n' > /usr/bin/nosync && \ socat \ sparse \ spice-protocol \ + swtpm \ tar \ tesseract \ tesseract-langpack-eng \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index f00e9e267c..9e9c71fa94 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -118,6 +118,7 @@ exec "$@"\n' > /usr/bin/nosync && \ sparse \ spice-protocol \ spice-server-devel \ + swtpm \ systemd-devel \ systemtap-sdt-devel \ tar \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index ed04b4d6da..dc0e36ce48 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -100,6 +100,7 @@ RUN zypper update -y && \ socat \ sparse \ spice-protocol-devel \ + swtpm \ systemd-devel \ systemtap-sdt-devel \ tar \ diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker index 94c2c16118..2ca9cff79c 100644 --- a/tests/docker/dockerfiles/ubuntu2204.docker +++ b/tests/docker/dockerfiles/ubuntu2204.docker @@ -124,6 +124,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed \ socat \ sparse \ + swtpm \ systemtap-sdt-dev \ tar \ tesseract-ocr \ diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci index e3ed1e5da1..36bc517161 160000 --- a/tests/lcitool/libvirt-ci +++ b/tests/lcitool/libvirt-ci @@ -1 +1 @@ -Subproject commit e3ed1e5da101943e53d8d89424e17b22120743f5 +Subproject commit 36bc517161c45ead20224d47f2dc4fa428af6724 diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index 6f0885170d..82092c9f17 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -110,6 +110,7 @@ packages: - spice-protocol - spice-server - ssh-client + - swtpm - systemd - tar - tesseract -- 2.39.2

On Mon, Sep 25, 2023 at 03:48:25PM +0100, Alex Bennée wrote:
We need this to test some TPM stuff.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- .gitlab-ci.d/cirrus/macos-12.vars | 2 +- tests/docker/dockerfiles/alpine.docker | 1 + tests/docker/dockerfiles/centos8.docker | 1 + tests/docker/dockerfiles/debian-amd64-cross.docker | 1 + tests/docker/dockerfiles/debian-amd64.docker | 1 + tests/docker/dockerfiles/debian-arm64-cross.docker | 1 + tests/docker/dockerfiles/debian-armhf-cross.docker | 1 + tests/docker/dockerfiles/debian-ppc64el-cross.docker | 1 + tests/docker/dockerfiles/debian-s390x-cross.docker | 1 + tests/docker/dockerfiles/fedora-win32-cross.docker | 1 + tests/docker/dockerfiles/fedora-win64-cross.docker | 1 + tests/docker/dockerfiles/fedora.docker | 1 + tests/docker/dockerfiles/opensuse-leap.docker | 1 + tests/docker/dockerfiles/ubuntu2204.docker | 1 + tests/lcitool/libvirt-ci | 2 +- tests/lcitool/projects/qemu.yml | 1 + 16 files changed, 16 insertions(+), 2 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

We move a couple of targets out of the avocado runs because there are no tests to run. Tricore already has some coverage. The cris target only really has check-tcg tests but its getting harder to find anything that packages the compiler. To reduce the noise of CANCEL messages we also set AVOCADO_TAGS appropriately so we filter down the number of tests we attempt. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- v2 - minor commit reword, no longer attempt to keep cris going --- .gitlab-ci.d/buildtest.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index aee9101507..25af1bc41e 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -30,6 +30,7 @@ avocado-system-alpine: variables: IMAGE: alpine MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:avr arch:loongarch64 arch:mips64 arch:mipsel build-system-ubuntu: extends: @@ -40,8 +41,7 @@ build-system-ubuntu: variables: IMAGE: ubuntu2204 CONFIGURE_ARGS: --enable-docs - TARGETS: alpha-softmmu cris-softmmu hppa-softmmu - microblazeel-softmmu mips64el-softmmu + TARGETS: alpha-softmmu microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build check-system-ubuntu: @@ -61,6 +61,7 @@ avocado-system-ubuntu: variables: IMAGE: ubuntu2204 MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:alpha arch:microblaze arch:mips64el build-system-debian: extends: @@ -72,7 +73,7 @@ build-system-debian: IMAGE: debian-amd64 CONFIGURE_ARGS: --with-coroutine=sigaltstack TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu - sparc-softmmu xtensaeb-softmmu + sparc-softmmu xtensa-softmmu MAKE_CHECK_ARGS: check-build check-system-debian: @@ -92,6 +93,7 @@ avocado-system-debian: variables: IMAGE: debian-amd64 MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:arm arch:i386 arch:riscv64 arch:sh4 arch:sparc arch:xtensa crash-test-debian: extends: .native_test_job_template @@ -114,7 +116,7 @@ build-system-fedora: variables: IMAGE: fedora CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs - TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu + TARGETS: microblaze-softmmu mips-softmmu xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu MAKE_CHECK_ARGS: check-build @@ -135,6 +137,8 @@ avocado-system-fedora: variables: IMAGE: fedora MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:microblaze arch:mips arch:xtensa arch:m68k + arch:riscv32 arch:ppc arch:sparc64 crash-test-fedora: extends: .native_test_job_template @@ -180,6 +184,8 @@ avocado-system-centos: variables: IMAGE: centos8 MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:ppc64 arch:or1k arch:390x arch:x86_64 arch:rx + arch:sh4 arch:nios2 build-system-opensuse: extends: @@ -209,6 +215,7 @@ avocado-system-opensuse: variables: IMAGE: opensuse-leap MAKE_CHECK_ARGS: check-avocado + AVOCADO_TAGS: arch:s390x arch:x86_64 arch:aarch64 # This jobs explicitly disable TCG (--disable-tcg), KVM is detected by -- 2.39.2

This might be premature but while streamling the avocado tests I realised the only tests we have are "check-tcg" ones. The aging fedora-criss-cross image works well enough for developers but can't be used in CI as we need supported build platforms to build QEMU. Does this mean the writing is on the wall for this architecture? Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Cc: Rabin Vincent <rabinv@axis.com> Cc: Edgar E. Iglesias <edgar.iglesias@xilinx.com> --- docs/about/deprecated.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index dc4da95329..7cfe313aa6 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -399,6 +399,17 @@ Specifying the iSCSI password in plain text on the command line using the used instead, to refer to a ``--object secret...`` instance that provides a password via a file, or encrypted. +TCG CPUs +-------- + +CRIS CPU architecture (since 8.1) +''''''''''''''''''''''''''''''''' + +The CRIS architecture was pulled from Linux in 4.17 and the compiler +is no longer packaged in any distro making it harder to run the +``check-tcg`` tests. Unless we can improve the testing situation there +is a chance the code will bitrot without anyone noticing. + Backwards compatibility ----------------------- -- 2.39.2

On Mon, Sep 25, 2023 at 03:48:27PM +0100, Alex Bennée wrote:
This might be premature but while streamling the avocado tests I realised the only tests we have are "check-tcg" ones. The aging fedora-criss-cross image works well enough for developers but can't be used in CI as we need supported build platforms to build QEMU.
Does this mean the writing is on the wall for this architecture?
It was deleted in Linux, and GCC dropped the cris-*linux target, but GCC keeps other cris targets. IOW, at very least, it has become a niche use case target. We don't need Linux/GCC support as a pre-requisite for having a target in QEMU, but it sure makes it increasingly challenging to test.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Cc: Rabin Vincent <rabinv@axis.com> Cc: Edgar E. Iglesias <edgar.iglesias@xilinx.com> --- docs/about/deprecated.rst | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index dc4da95329..7cfe313aa6 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -399,6 +399,17 @@ Specifying the iSCSI password in plain text on the command line using the used instead, to refer to a ``--object secret...`` instance that provides a password via a file, or encrypted.
+TCG CPUs +-------- + +CRIS CPU architecture (since 8.1) +''''''''''''''''''''''''''''''''' + +The CRIS architecture was pulled from Linux in 4.17 and the compiler +is no longer packaged in any distro making it harder to run the +``check-tcg`` tests. Unless we can improve the testing situation there +is a chance the code will bitrot without anyone noticing. + Backwards compatibility -----------------------
-- 2.39.2
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Mon, Sep 25, 2023 at 03:48:27PM +0100, Alex Bennée wrote:
This might be premature but while streamling the avocado tests I realised the only tests we have are "check-tcg" ones. The aging fedora-criss-cross image works well enough for developers but can't be used in CI as we need supported build platforms to build QEMU.
Does this mean the writing is on the wall for this architecture?
Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Cc: Rabin Vincent <rabinv@axis.com> Cc: Edgar E. Iglesias <edgar.iglesias@xilinx.com> --- docs/about/deprecated.rst | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index dc4da95329..7cfe313aa6 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -399,6 +399,17 @@ Specifying the iSCSI password in plain text on the command line using the used instead, to refer to a ``--object secret...`` instance that provides a password via a file, or encrypted.
+TCG CPUs +-------- + +CRIS CPU architecture (since 8.1) +''''''''''''''''''''''''''''''''' + +The CRIS architecture was pulled from Linux in 4.17 and the compiler +is no longer packaged in any distro making it harder to run the +``check-tcg`` tests. Unless we can improve the testing situation there +is a chance the code will bitrot without anyone noticing.
Deprecated is generally a warning that we intend to delete the feature. If we're just going to relegate it to untested status (what I'd call "tier 3" quality), then we should document that elsewhere. I don't mind which way we go. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Daniel P. Berrangé <berrange@redhat.com> writes:
On Mon, Sep 25, 2023 at 03:48:27PM +0100, Alex Bennée wrote:
This might be premature but while streamling the avocado tests I realised the only tests we have are "check-tcg" ones. The aging fedora-criss-cross image works well enough for developers but can't be used in CI as we need supported build platforms to build QEMU.
Does this mean the writing is on the wall for this architecture?
Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Cc: Rabin Vincent <rabinv@axis.com> Cc: Edgar E. Iglesias <edgar.iglesias@xilinx.com> --- docs/about/deprecated.rst | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index dc4da95329..7cfe313aa6 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -399,6 +399,17 @@ Specifying the iSCSI password in plain text on the command line using the used instead, to refer to a ``--object secret...`` instance that provides a password via a file, or encrypted.
+TCG CPUs +-------- + +CRIS CPU architecture (since 8.1) +''''''''''''''''''''''''''''''''' + +The CRIS architecture was pulled from Linux in 4.17 and the compiler +is no longer packaged in any distro making it harder to run the +``check-tcg`` tests. Unless we can improve the testing situation there +is a chance the code will bitrot without anyone noticing.
Deprecated is generally a warning that we intend to delete the feature. If we're just going to relegate it to untested status (what I'd call "tier 3" quality), then we should document that elsewhere. I don't mind which way we go.
We do have reasonably good coverage with tests/tcg/cris but of course without a compiler we can't build them. Both nios2 and microblaze have build-toolchain scripts which can be used to re-create containers. However my preference is having pre-built toolchains hosted by others like we do for loongarch, hexagon, xtensa and tricore. Then the docker image can simply curl them into an image. -- Alex Bennée Virtualisation Tech Lead @ Linaro

On Mon, Sep 25, 2023 at 7:00 PM Alex Bennée <alex.bennee@linaro.org> wrote:
Daniel P. Berrangé <berrange@redhat.com> writes:
This might be premature but while streamling the avocado tests I realised the only tests we have are "check-tcg" ones. The aging fedora-criss-cross image works well enough for developers but can't be used in CI as we need supported build platforms to build QEMU.
Does this mean the writing is on the wall for this architecture?
Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Cc: Rabin Vincent <rabinv@axis.com> Cc: Edgar E. Iglesias <edgar.iglesias@xilinx.com> --- docs/about/deprecated.rst | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index dc4da95329..7cfe313aa6 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -399,6 +399,17 @@ Specifying the iSCSI password in plain text on the command line using the used instead, to refer to a ``--object secret...`` instance that
On Mon, Sep 25, 2023 at 03:48:27PM +0100, Alex Bennée wrote: provides
a password via a file, or encrypted.
+TCG CPUs +-------- + +CRIS CPU architecture (since 8.1) +''''''''''''''''''''''''''''''''' + +The CRIS architecture was pulled from Linux in 4.17 and the compiler +is no longer packaged in any distro making it harder to run the +``check-tcg`` tests. Unless we can improve the testing situation there +is a chance the code will bitrot without anyone noticing.
Deprecated is generally a warning that we intend to delete the feature. If we're just going to relegate it to untested status (what I'd call "tier 3" quality), then we should document that elsewhere. I don't mind which way we go.
We do have reasonably good coverage with tests/tcg/cris but of course without a compiler we can't build them.
Both nios2 and microblaze have build-toolchain scripts which can be used to re-create containers. However my preference is having pre-built toolchains hosted by others like we do for loongarch, hexagon, xtensa and tricore. Then the docker image can simply curl them into an image.
Yeah, I guess it's time to deprecate it... Cheers, Edgar
-- Alex Bennée Virtualisation Tech Lead @ Linaro

Since 0b1a649047 (tests/docker: use direct RUNC call to build containers) we ended up with the potential for the remaining docker.py script calls to deviate from the direct RUNC calls. Fix this by dropping the use of ENGINE in the makefile and rely entirely on what we detect at configure time. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 1 - tests/docker/Makefile.include | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/configure b/configure index e08127045d..707132a3ae 100755 --- a/configure +++ b/configure @@ -1694,7 +1694,6 @@ if test -n "$gdb_bin"; then fi if test "$container" != no; then - echo "ENGINE=$container" >> $config_host_mak echo "RUNC=$runc" >> $config_host_mak fi echo "SUBDIRS=$subdirs" >> $config_host_mak diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index dfabafab92..035d272be9 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -17,8 +17,7 @@ endif DOCKER_REGISTRY := $(if $(REGISTRY),$(REGISTRY),$(DOCKER_DEFAULT_REGISTRY)) RUNC ?= docker -ENGINE ?= auto -DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(ENGINE) +DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(RUNC) CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$) DOCKER_SRC_COPY := $(BUILD_DIR)/docker-src.$(CUR_TIME) @@ -158,7 +157,7 @@ $(foreach i,$(filter-out $(DOCKER_PARTIAL_IMAGES),$(DOCKER_IMAGES)), \ ) docker: - @echo 'Build QEMU and run tests inside Docker or Podman containers' + @echo 'Build QEMU and run tests inside $(RUNC) containers' @echo @echo 'Available targets:' @echo @@ -198,8 +197,6 @@ docker: @echo ' EXECUTABLE=<path> Include executable in image.' @echo ' EXTRA_FILES="<path> [... <path>]"' @echo ' Include extra files in image.' - @echo ' ENGINE=auto/docker/podman' - @echo ' Specify which container engine to run.' @echo ' REGISTRY=url Cache builds from registry (default:$(DOCKER_REGISTRY))' docker-help: docker -- 2.39.2

On 9/25/23 16:48, Alex Bennée wrote:
Since 0b1a649047 (tests/docker: use direct RUNC call to build containers) we ended up with the potential for the remaining docker.py script calls to deviate from the direct RUNC calls. Fix this by dropping the use of ENGINE in the makefile and rely entirely on what we detect at configure time.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 1 - tests/docker/Makefile.include | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/configure b/configure index e08127045d..707132a3ae 100755 --- a/configure +++ b/configure @@ -1694,7 +1694,6 @@ if test -n "$gdb_bin"; then fi
if test "$container" != no; then - echo "ENGINE=$container" >> $config_host_mak echo "RUNC=$runc" >> $config_host_mak fi echo "SUBDIRS=$subdirs" >> $config_host_mak diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index dfabafab92..035d272be9 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -17,8 +17,7 @@ endif DOCKER_REGISTRY := $(if $(REGISTRY),$(REGISTRY),$(DOCKER_DEFAULT_REGISTRY))
RUNC ?= docker -ENGINE ?= auto
This was used when using docker-* from the source directory. What about changing it to: RUNC ?= $(if $(shell command -v docker), docker, podman) No complaint on removing ENGINE= though. Paolo
-DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(ENGINE) +DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(RUNC)
CUR_TIME := $(shell date +%Y-%m-%d-%H.%M.%S.$$$$) DOCKER_SRC_COPY := $(BUILD_DIR)/docker-src.$(CUR_TIME) @@ -158,7 +157,7 @@ $(foreach i,$(filter-out $(DOCKER_PARTIAL_IMAGES),$(DOCKER_IMAGES)), \ )
docker: - @echo 'Build QEMU and run tests inside Docker or Podman containers' + @echo 'Build QEMU and run tests inside $(RUNC) containers' @echo @echo 'Available targets:' @echo @@ -198,8 +197,6 @@ docker: @echo ' EXECUTABLE=<path> Include executable in image.' @echo ' EXTRA_FILES="<path> [... <path>]"' @echo ' Include extra files in image.' - @echo ' ENGINE=auto/docker/podman' - @echo ' Specify which container engine to run.' @echo ' REGISTRY=url Cache builds from registry (default:$(DOCKER_REGISTRY))'
docker-help: docker

If you have both engines installed but one is broken you are stuck with the automagic. Allow the user to override the engine for this case. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 707132a3ae..ebad155d9e 100755 --- a/configure +++ b/configure @@ -180,6 +180,7 @@ fi # some defaults, based on the host environment # default parameters +container_engine="auto" cpu="" cross_compile="no" cross_prefix="" @@ -787,6 +788,8 @@ for opt do ;; --disable-containers) use_containers="no" ;; + --container-engine=*) container_engine="$optarg" + ;; --gdb=*) gdb_bin="$optarg" ;; # everything else has the same name in configure and meson @@ -921,6 +924,7 @@ Advanced options (experts only): --enable-plugins enable plugins via shared library loading --disable-containers don't use containers for cross-building + --container-engine=TYPE which container engine to use [$container_engine] --gdb=GDB-path gdb to use for gdbstub tests [$gdb_bin] EOF meson_options_help @@ -1195,14 +1199,14 @@ fi container="no" runc="" if test $use_containers = "yes" && (has "docker" || has "podman"); then - case $($python "$source_path"/tests/docker/docker.py probe) in + case $($python "$source_path"/tests/docker/docker.py --engine "$container_engine" probe) in *docker) container=docker ;; podman) container=podman ;; no) container=no ;; esac if test "$container" != "no"; then docker_py="$python $source_path/tests/docker/docker.py --engine $container" - runc=$($python "$source_path"/tests/docker/docker.py probe) + runc=$container fi fi -- 2.39.2

The modern packaging of cross GCC's doesn't need the explicit version number at the end. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index ebad155d9e..e83872571d 100755 --- a/configure +++ b/configure @@ -1334,7 +1334,7 @@ probe_target_compiler() { # We don't have any bigendian build tools so we only use this for AArch64 container_image=debian-arm64-cross container_cross_prefix=aarch64-linux-gnu- - container_cross_cc=${container_cross_prefix}gcc-10 + container_cross_cc=${container_cross_prefix}gcc ;; alpha) container_image=debian-alpha-cross @@ -1397,7 +1397,7 @@ probe_target_compiler() { ppc) container_image=debian-powerpc-test-cross container_cross_prefix=powerpc-linux-gnu- - container_cross_cc=${container_cross_prefix}gcc-10 + container_cross_cc=${container_cross_prefix}gcc ;; ppc64|ppc64le) container_image=debian-powerpc-test-cross -- 2.39.2

If we update configure we should make sure we regenerate all the compiler details. We should also ensure those details are upto date before building the TCG tests. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index e83872571d..a95e0f5767 100755 --- a/configure +++ b/configure @@ -1788,6 +1788,8 @@ for target in $target_list; do echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak" fi + echo "$config_target_mak: configure" >> Makefile.prereqs + echo "build-tcg-tests-$target: $config_target_mak" >> Makefile.prereqs echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs tcg_tests_targets="$tcg_tests_targets $target" fi -- 2.39.2

On 9/25/23 16:48, Alex Bennée wrote:
If we update configure we should make sure we regenerate all the compiler details. We should also ensure those details are upto date before building the TCG tests.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configure b/configure index e83872571d..a95e0f5767 100755 --- a/configure +++ b/configure @@ -1788,6 +1788,8 @@ for target in $target_list; do echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak" fi
+ echo "$config_target_mak: configure" >> Makefile.prereqs
This in practice is not adding anything; if "configure" changes then Makefile's dependency on config-host.mak will trigger a configure rerun anyway. If you want to add it, you should also add it for other config-*.mak files. However, I'd remove this line and just change -# 1. ensure config-host.mak is up-to-date +# 1. ensure config-host.mak is up-to-date. All other config-*.mak +# files for subdirectories will be updated as well. in the Makefile. Paolo

Paolo Bonzini <pbonzini@redhat.com> writes:
On 9/25/23 16:48, Alex Bennée wrote:
If we update configure we should make sure we regenerate all the compiler details. We should also ensure those details are upto date before building the TCG tests. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index e83872571d..a95e0f5767 100755 --- a/configure +++ b/configure @@ -1788,6 +1788,8 @@ for target in $target_list; do echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak" fi + echo "$config_target_mak: configure" >> Makefile.prereqs
This in practice is not adding anything; if "configure" changes then Makefile's dependency on config-host.mak will trigger a configure rerun anyway.
If you want to add it, you should also add it for other config-*.mak files. However, I'd remove this line and just change
-# 1. ensure config-host.mak is up-to-date +# 1. ensure config-host.mak is up-to-date. All other config-*.mak +# files for subdirectories will be updated as well.
Peter ran into a mismatch between config-host.mak and tests/tcg/foo/config-target.mak in his build system so it didn't get picked up at one point.
in the Makefile.
Paolo
-- Alex Bennée Virtualisation Tech Lead @ Linaro

Il lun 25 set 2023, 18:45 Alex Bennée <alex.bennee@linaro.org> ha scritto:
Paolo Bonzini <pbonzini@redhat.com> writes:
On 9/25/23 16:48, Alex Bennée wrote:
echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak" fi + echo "$config_target_mak: configure" >> Makefile.prereqs
This in practice is not adding anything; if "configure" changes then Makefile's dependency on config-host.mak will trigger a configure rerun anyway.
If you want to add it, you should also add it for other config-*.mak files. However, I'd remove this line and just change
-# 1. ensure config-host.mak is up-to-date +# 1. ensure config-host.mak is up-to-date. All other config-*.mak +# files for subdirectories will be updated as well.
Peter ran into a mismatch between config-host.mak and tests/tcg/foo/config-target.mak in his build system so it didn't get picked up at one point.
But what is the rule that the new dependency is going to trigger? As far as I can see there is no rule to regenerate the $config_target_mak files, and also no rule to regenerate configure; the only effect of a change to configure will be rerunning the script, but that's triggered by the existing config-host.mak rule. Paolo
in the Makefile.
Paolo
-- Alex Bennée Virtualisation Tech Lead @ Linaro

On Mon, 25 Sept 2023 at 17:45, Alex Bennée <alex.bennee@linaro.org> wrote:
Paolo Bonzini <pbonzini@redhat.com> writes:
On 9/25/23 16:48, Alex Bennée wrote:
If we update configure we should make sure we regenerate all the compiler details. We should also ensure those details are upto date before building the TCG tests. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index e83872571d..a95e0f5767 100755 --- a/configure +++ b/configure @@ -1788,6 +1788,8 @@ for target in $target_list; do echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak" fi + echo "$config_target_mak: configure" >> Makefile.prereqs
This in practice is not adding anything; if "configure" changes then Makefile's dependency on config-host.mak will trigger a configure rerun anyway.
If you want to add it, you should also add it for other config-*.mak files. However, I'd remove this line and just change
-# 1. ensure config-host.mak is up-to-date +# 1. ensure config-host.mak is up-to-date. All other config-*.mak +# files for subdirectories will be updated as well.
Peter ran into a mismatch between config-host.mak and tests/tcg/foo/config-target.mak in his build system so it didn't get picked up at one point.
I did, but looking at the timestamps on the two files, the problem wasn't that one file got updated and not the other: $ grep CONFIG_PLUGIN build/x86/config-host.h #undef CONFIG_PLUGIN $ grep CONFIG_PLUGIN build/x86/tests/tcg/config-host.mak CONFIG_PLUGIN=y e104462:jammy:qemu$ ls -l build/x86/config-host.mak build/x86/tests/tcg/config-host.mak -rw-r--r-- 1 petmay01 petmay01 549 Sep 22 16:38 build/x86/config-host.mak -rw-r--r-- 1 petmay01 petmay01 159 Sep 22 16:38 build/x86/tests/tcg/config-host.mak (both newer than 'configure' itself by about 10 days.) -- PMM

From: Akihiko Odaki <akihiko.odaki@daynix.com> target_xml is no longer a fixed-length array but a pointer to a variable-length memory. Fixes: 56e534bd11 ("gdbstub: refactor get_feature_xml") Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20230912224107.29669-2-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- gdbstub/softmmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdbstub/softmmu.c b/gdbstub/softmmu.c index 9f0b8b5497..42645d2220 100644 --- a/gdbstub/softmmu.c +++ b/gdbstub/softmmu.c @@ -292,7 +292,7 @@ static int find_cpu_clusters(Object *child, void *opaque) assert(cluster->cluster_id != UINT32_MAX); process->pid = cluster->cluster_id + 1; process->attached = false; - process->target_xml[0] = '\0'; + process->target_xml = NULL; return 0; } -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> It was failing to return target.xml after the first request. Fixes: 56e534bd11 ("gdbstub: refactor get_feature_xml") Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Message-Id: <20230912224107.29669-3-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 349d348c7b..384191bcb0 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -396,8 +396,8 @@ static const char *get_feature_xml(const char *p, const char **newp, g_string_append(xml, "</target>"); process->target_xml = g_string_free(xml, false); - return process->target_xml; } + return process->target_xml; } /* Is it dynamically generated by the target? */ if (cc->gdb_get_dynamic_xml) { -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> The created member of CPUState tells if the vCPU thread is started, and will be always false for the user space emulation that manages threads independently. Use the realized member of DeviceState, which is valid for both of the system and user space emulation. Fixes: 54cb65d858 ("plugin: add core code") Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Message-Id: <20230912224107.29669-4-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- plugins/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/core.c b/plugins/core.c index 3c4e26c7ed..fcd33a2bff 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -64,7 +64,7 @@ static void plugin_cpu_update__locked(gpointer k, gpointer v, gpointer udata) CPUState *cpu = container_of(k, CPUState, cpu_index); run_on_cpu_data mask = RUN_ON_CPU_HOST_ULONG(*plugin.mask); - if (cpu->created) { + if (DEVICE(cpu)->realized) { async_run_on_cpu(cpu, plugin_cpu_update__async, mask); } else { plugin_cpu_update__async(cpu, mask); -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> execlog had the following comment:
As we could have multiple threads trying to do this we need to serialise the expansion under a lock. Threads accessing already created entries can continue without issue even if the ptr array gets reallocated during resize.
However, when the ptr array gets reallocated, the other threads may have a stale reference to the old buffer. This results in use-after-free. Use GRWLock to properly fix this issue. Fixes: 3d7caf145e ("contrib/plugins: add execlog to log instruction execution and memory access") Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20230912224107.29669-5-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- contrib/plugins/execlog.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c index 7129d526f8..82dc2f584e 100644 --- a/contrib/plugins/execlog.c +++ b/contrib/plugins/execlog.c @@ -19,7 +19,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; /* Store last executed instruction on each vCPU as a GString */ static GPtrArray *last_exec; -static GMutex expand_array_lock; +static GRWLock expand_array_lock; static GPtrArray *imatches; static GArray *amatches; @@ -28,18 +28,16 @@ static GArray *amatches; * Expand last_exec array. * * As we could have multiple threads trying to do this we need to - * serialise the expansion under a lock. Threads accessing already - * created entries can continue without issue even if the ptr array - * gets reallocated during resize. + * serialise the expansion under a lock. */ static void expand_last_exec(int cpu_index) { - g_mutex_lock(&expand_array_lock); + g_rw_lock_writer_lock(&expand_array_lock); while (cpu_index >= last_exec->len) { GString *s = g_string_new(NULL); g_ptr_array_add(last_exec, s); } - g_mutex_unlock(&expand_array_lock); + g_rw_lock_writer_unlock(&expand_array_lock); } /** @@ -51,8 +49,10 @@ static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info, GString *s; /* Find vCPU in array */ + g_rw_lock_reader_lock(&expand_array_lock); g_assert(cpu_index < last_exec->len); s = g_ptr_array_index(last_exec, cpu_index); + g_rw_lock_reader_unlock(&expand_array_lock); /* Indicate type of memory access */ if (qemu_plugin_mem_is_store(info)) { @@ -80,10 +80,14 @@ static void vcpu_insn_exec(unsigned int cpu_index, void *udata) GString *s; /* Find or create vCPU in array */ + g_rw_lock_reader_lock(&expand_array_lock); if (cpu_index >= last_exec->len) { + g_rw_lock_reader_unlock(&expand_array_lock); expand_last_exec(cpu_index); + g_rw_lock_reader_lock(&expand_array_lock); } s = g_ptr_array_index(last_exec, cpu_index); + g_rw_lock_reader_unlock(&expand_array_lock); /* Print previous instruction in cache */ if (s->len) { -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> Before this change, the information from a XML file was stored in an array that is not descriptive. Introduce a dedicated structure type to make it easier to understand and to extend with more fields. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230912224107.29669-6-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- MAINTAINERS | 2 +- meson.build | 2 +- include/exec/gdbstub.h | 9 ++++-- gdbstub/gdbstub.c | 6 ++-- stubs/gdbstub.c | 6 ++-- scripts/feature_to_c.py | 48 ++++++++++++++++++++++++++++ scripts/feature_to_c.sh | 69 ----------------------------------------- 7 files changed, 63 insertions(+), 79 deletions(-) create mode 100755 scripts/feature_to_c.py delete mode 100644 scripts/feature_to_c.sh diff --git a/MAINTAINERS b/MAINTAINERS index 355b1960ce..8ccd978811 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2829,7 +2829,7 @@ F: include/exec/gdbstub.h F: include/gdbstub/* F: gdb-xml/ F: tests/tcg/multiarch/gdbstub/ -F: scripts/feature_to_c.sh +F: scripts/feature_to_c.py F: scripts/probe-gdb-support.py Memory API diff --git a/meson.build b/meson.build index f426861d90..98a65c7df9 100644 --- a/meson.build +++ b/meson.build @@ -3702,7 +3702,7 @@ common_all = static_library('common', dependencies: common_all.dependencies(), name_suffix: 'fa') -feature_to_c = find_program('scripts/feature_to_c.sh') +feature_to_c = find_program('scripts/feature_to_c.py') if targetos == 'darwin' entitlement = find_program('scripts/entitlement.sh') diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 16a139043f..705be2c5d7 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -10,6 +10,11 @@ #define GDB_WATCHPOINT_READ 3 #define GDB_WATCHPOINT_ACCESS 4 +typedef struct GDBFeature { + const char *xmlname; + const char *xml; +} GDBFeature; + /* Get or set a register. Returns the size of the register. */ typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg); @@ -48,7 +53,7 @@ void gdb_set_stop_cpu(CPUState *cpu); */ bool gdb_has_xml(void); -/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ -extern const char *const xml_builtin[][2]; +/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */ +extern const GDBFeature gdb_static_features[]; #endif diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 384191bcb0..12f4d07046 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -408,11 +408,11 @@ static const char *get_feature_xml(const char *p, const char **newp, } } /* Is it one of the encoded gdb-xml/ files? */ - for (int i = 0; xml_builtin[i][0]; i++) { - const char *name = xml_builtin[i][0]; + for (int i = 0; gdb_static_features[i].xmlname; i++) { + const char *name = gdb_static_features[i].xmlname; if ((strncmp(name, p, len) == 0) && strlen(name) == len) { - return xml_builtin[i][1]; + return gdb_static_features[i].xml; } } diff --git a/stubs/gdbstub.c b/stubs/gdbstub.c index 2b7aee50d3..580e20702b 100644 --- a/stubs/gdbstub.c +++ b/stubs/gdbstub.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" -#include "exec/gdbstub.h" /* xml_builtin */ +#include "exec/gdbstub.h" /* gdb_static_features */ -const char *const xml_builtin[][2] = { - { NULL, NULL } +const GDBFeature gdb_static_features[] = { + { NULL } }; diff --git a/scripts/feature_to_c.py b/scripts/feature_to_c.py new file mode 100755 index 0000000000..bcbcb83beb --- /dev/null +++ b/scripts/feature_to_c.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +import os, sys + +def writeliteral(indent, bytes): + sys.stdout.write(' ' * indent) + sys.stdout.write('"') + quoted = True + + for c in bytes: + if not quoted: + sys.stdout.write('\n') + sys.stdout.write(' ' * indent) + sys.stdout.write('"') + quoted = True + + if c == b'"'[0]: + sys.stdout.write('\\"') + elif c == b'\\'[0]: + sys.stdout.write('\\\\') + elif c == b'\n'[0]: + sys.stdout.write('\\n"') + quoted = False + elif c >= 32 and c < 127: + sys.stdout.write(c.to_bytes(1, 'big').decode()) + else: + sys.stdout.write(f'\{c:03o}') + + if quoted: + sys.stdout.write('"') + +sys.stdout.write('#include "qemu/osdep.h"\n' \ + '#include "exec/gdbstub.h"\n' \ + '\n' + 'const GDBFeature gdb_static_features[] = {\n') + +for input in sys.argv[1:]: + with open(input, 'rb') as file: + read = file.read() + + sys.stdout.write(' {\n') + writeliteral(8, bytes(os.path.basename(input), 'utf-8')) + sys.stdout.write(',\n') + writeliteral(8, read) + sys.stdout.write('\n },\n') + +sys.stdout.write(' { NULL }\n};\n') diff --git a/scripts/feature_to_c.sh b/scripts/feature_to_c.sh deleted file mode 100644 index c1f67c8f6a..0000000000 --- a/scripts/feature_to_c.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/sh - -# Convert text files to compilable C arrays. -# -# Copyright (C) 2007 Free Software Foundation, Inc. -# -# This file is part of GDB. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see <http://www.gnu.org/licenses/>. - -if test -z "$1"; then - echo "Usage: $0 INPUTFILE..." - exit 1 -fi - -for input; do - arrayname=xml_feature_$(echo $input | sed 's,.*/,,; s/[-.]/_/g') - - ${AWK:-awk} 'BEGIN { n = 0 - printf "#include \"qemu/osdep.h\"\n" - print "static const char '$arrayname'[] = {" - for (i = 0; i < 255; i++) - _ord_[sprintf("%c", i)] = i - } { - split($0, line, ""); - printf " " - for (i = 1; i <= length($0); i++) { - c = line[i] - if (c == "'\''") { - printf "'\''\\'\'''\'', " - } else if (c == "\\") { - printf "'\''\\\\'\'', " - } else if (_ord_[c] >= 32 && _ord_[c] < 127) { - printf "'\''%s'\'', ", c - } else { - printf "'\''\\%03o'\'', ", _ord_[c] - } - if (i % 10 == 0) - printf "\n " - } - printf "'\''\\n'\'', \n" - } END { - print " 0 };" - }' < $input -done - -echo -echo '#include "exec/gdbstub.h"' -echo "const char *const xml_builtin[][2] = {" - -for input; do - basename=$(echo $input | sed 's,.*/,,') - arrayname=xml_feature_$(echo $input | sed 's,.*/,,; s/[-.]/_/g') - echo " { \"$basename\", $arrayname }," -done - -echo " { (char *)0, (char *)0 }" -echo "};" -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> Some subclasses overwrite gdb_core_xml_file member but others don't. Always initialize the member in the subclasses for consistency. This especially helps for AArch64; in a following change, the file specified by gdb_core_xml_file is always looked up even if it's going to be overwritten later. Looking up arm-core.xml results in an error as it will not be embedded in the AArch64 build. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230912224107.29669-7-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- target/arm/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index b9e09a702d..10fcc61701 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2393,7 +2393,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->sysemu_ops = &arm_sysemu_ops; #endif cc->gdb_num_core_regs = 26; - cc->gdb_core_xml_file = "arm-core.xml"; cc->gdb_arch_name = arm_gdb_arch_name; cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml; cc->gdb_stop_before_watchpoint = true; @@ -2415,8 +2414,10 @@ static void arm_cpu_instance_init(Object *obj) static void cpu_register_class_init(ObjectClass *oc, void *data) { ARMCPUClass *acc = ARM_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(acc); acc->info = data; + cc->gdb_core_xml_file = "arm-core.xml"; } void arm_cpu_register(const ARMCPUInfo *info) -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> All implementations of gdb_arch_name() returns dynamic duplicates of static strings. It's also unlikely that there will be an implementation of gdb_arch_name() that returns a truly dynamic value due to the nature of the function returning a well-known identifiers. Qualify the value gdb_arch_name() with const and make all of its implementations return static strings. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20230912224107.29669-8-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- include/hw/core/cpu.h | 2 +- target/ppc/internal.h | 2 +- gdbstub/gdbstub.c | 3 +-- target/arm/cpu.c | 6 +++--- target/arm/cpu64.c | 4 ++-- target/i386/cpu.c | 6 +++--- target/loongarch/cpu.c | 8 ++++---- target/ppc/gdbstub.c | 6 +++--- target/riscv/cpu.c | 6 +++--- target/s390x/cpu.c | 4 ++-- target/tricore/cpu.c | 4 ++-- 11 files changed, 25 insertions(+), 26 deletions(-) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 648b5b3586..5ae479a961 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -164,7 +164,7 @@ struct CPUClass { vaddr (*gdb_adjust_breakpoint)(CPUState *cpu, vaddr addr); const char *gdb_core_xml_file; - gchar * (*gdb_arch_name)(CPUState *cpu); + const gchar * (*gdb_arch_name)(CPUState *cpu); const char * (*gdb_get_dynamic_xml)(CPUState *cpu, const char *xmlname); void (*disas_set_info)(CPUState *cpu, disassemble_info *info); diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 15803bc313..c881c67a8b 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -221,7 +221,7 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu); /* gdbstub.c */ void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc); -gchar *ppc_gdb_arch_name(CPUState *cs); +const gchar *ppc_gdb_arch_name(CPUState *cs); /** * prot_for_access_type: diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 12f4d07046..9db4af41c1 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -380,10 +380,9 @@ static const char *get_feature_xml(const char *p, const char **newp, "<target>"); if (cc->gdb_arch_name) { - g_autofree gchar *arch = cc->gdb_arch_name(cpu); g_string_append_printf(xml, "<architecture>%s</architecture>", - arch); + cc->gdb_arch_name(cpu)); } g_string_append(xml, "<xi:include href=\""); g_string_append(xml, cc->gdb_core_xml_file); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 10fcc61701..408af17bf2 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2320,15 +2320,15 @@ static Property arm_cpu_properties[] = { DEFINE_PROP_END_OF_LIST() }; -static gchar *arm_gdb_arch_name(CPUState *cs) +static const gchar *arm_gdb_arch_name(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; if (arm_feature(env, ARM_FEATURE_IWMMXT)) { - return g_strdup("iwmmxt"); + return "iwmmxt"; } - return g_strdup("arm"); + return "arm"; } #ifndef CONFIG_USER_ONLY diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index f3d87e001f..8a8cde7c05 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -781,9 +781,9 @@ static void aarch64_cpu_finalizefn(Object *obj) { } -static gchar *aarch64_gdb_arch_name(CPUState *cs) +static const gchar *aarch64_gdb_arch_name(CPUState *cs) { - return g_strdup("aarch64"); + return "aarch64"; } static void aarch64_cpu_class_init(ObjectClass *oc, void *data) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 2589c8e929..993ebc21f6 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5914,12 +5914,12 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) memset(&env->user_features, 0, sizeof(env->user_features)); } -static gchar *x86_gdb_arch_name(CPUState *cs) +static const gchar *x86_gdb_arch_name(CPUState *cs) { #ifdef TARGET_X86_64 - return g_strdup("i386:x86-64"); + return "i386:x86-64"; #else - return g_strdup("i386"); + return "i386"; #endif } diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index fc7f70fbe5..3cc9b2a89d 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -768,9 +768,9 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) #endif } -static gchar *loongarch32_gdb_arch_name(CPUState *cs) +static const gchar *loongarch32_gdb_arch_name(CPUState *cs) { - return g_strdup("loongarch32"); + return "loongarch32"; } static void loongarch32_cpu_class_init(ObjectClass *c, void *data) @@ -782,9 +782,9 @@ static void loongarch32_cpu_class_init(ObjectClass *c, void *data) cc->gdb_arch_name = loongarch32_gdb_arch_name; } -static gchar *loongarch64_gdb_arch_name(CPUState *cs) +static const gchar *loongarch64_gdb_arch_name(CPUState *cs) { - return g_strdup("loongarch64"); + return "loongarch64"; } static void loongarch64_cpu_class_init(ObjectClass *c, void *data) diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 2ad11510bf..778ef73bd7 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -589,12 +589,12 @@ static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n) return 0; } -gchar *ppc_gdb_arch_name(CPUState *cs) +const gchar *ppc_gdb_arch_name(CPUState *cs) { #if defined(TARGET_PPC64) - return g_strdup("powerpc:common64"); + return "powerpc:common64"; #else - return g_strdup("powerpc:common"); + return "powerpc:common"; #endif } diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f227c7664e..ce35e95f14 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -2008,17 +2008,17 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static gchar *riscv_gdb_arch_name(CPUState *cs) +static const gchar *riscv_gdb_arch_name(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; switch (riscv_cpu_mxl(env)) { case MXL_RV32: - return g_strdup("riscv:rv32"); + return "riscv:rv32"; case MXL_RV64: case MXL_RV128: - return g_strdup("riscv:rv64"); + return "riscv:rv64"; default: g_assert_not_reached(); } diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index df167493c3..cf4b5e43f2 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -284,9 +284,9 @@ static void s390_cpu_initfn(Object *obj) #endif } -static gchar *s390_gdb_arch_name(CPUState *cs) +static const gchar *s390_gdb_arch_name(CPUState *cs) { - return g_strdup("s390:64-bit"); + return "s390:64-bit"; } static Property s390x_cpu_properties[] = { diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 133a9ac70e..44e3ba6f0e 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -29,9 +29,9 @@ static inline void set_feature(CPUTriCoreState *env, int feature) env->features |= 1ULL << feature; } -static gchar *tricore_gdb_arch_name(CPUState *cs) +static const gchar *tricore_gdb_arch_name(CPUState *cs) { - return g_strdup("tricore"); + return "tricore"; } static void tricore_cpu_set_pc(CPUState *cs, vaddr value) -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> g_markup_printf_escaped() is a safer alternative to simple printf() as it automatically escapes values. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Message-Id: <20230912224107.29669-9-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 9db4af41c1..a4f2bf3723 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -373,28 +373,34 @@ static const char *get_feature_xml(const char *p, const char **newp, if (strncmp(p, "target.xml", len) == 0) { if (!process->target_xml) { GDBRegisterState *r; - GString *xml = g_string_new("<?xml version=\"1.0\"?>"); + g_autoptr(GPtrArray) xml = g_ptr_array_new_with_free_func(g_free); - g_string_append(xml, - "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">" - "<target>"); + g_ptr_array_add( + xml, + g_strdup("<?xml version=\"1.0\"?>" + "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">" + "<target>")); if (cc->gdb_arch_name) { - g_string_append_printf(xml, - "<architecture>%s</architecture>", - cc->gdb_arch_name(cpu)); + g_ptr_array_add( + xml, + g_markup_printf_escaped("<architecture>%s</architecture>", + cc->gdb_arch_name(cpu))); } - g_string_append(xml, "<xi:include href=\""); - g_string_append(xml, cc->gdb_core_xml_file); - g_string_append(xml, "\"/>"); + g_ptr_array_add( + xml, + g_markup_printf_escaped("<xi:include href=\"%s\"/>", + cc->gdb_core_xml_file)); for (r = cpu->gdb_regs; r; r = r->next) { - g_string_append(xml, "<xi:include href=\""); - g_string_append(xml, r->xml); - g_string_append(xml, "\"/>"); + g_ptr_array_add( + xml, + g_markup_printf_escaped("<xi:include href=\"%s\"/>", + r->xml)); } - g_string_append(xml, "</target>"); + g_ptr_array_add(xml, g_strdup("</target>")); + g_ptr_array_add(xml, NULL); - process->target_xml = g_string_free(xml, false); + process->target_xml = g_strjoinv(NULL, (void *)xml->pdata); } return process->target_xml; } -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> GDB has XML support since 6.7 which was released in 2007. It's time to remove support for old GDB versions without XML support. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Acked-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20230912224107.29669-10-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- target/arm/gdbstub.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 8fc8351df7..b7ace24bfc 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -46,21 +46,7 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) /* Core integer register. */ return gdb_get_reg32(mem_buf, env->regs[n]); } - if (n < 24) { - /* FPA registers. */ - if (gdb_has_xml()) { - return 0; - } - return gdb_get_zeroes(mem_buf, 12); - } - switch (n) { - case 24: - /* FPA status register. */ - if (gdb_has_xml()) { - return 0; - } - return gdb_get_reg32(mem_buf, 0); - case 25: + if (n == 25) { /* CPSR, or XPSR for M-profile */ if (arm_feature(env, ARM_FEATURE_M)) { return gdb_get_reg32(mem_buf, xpsr_read(env)); @@ -100,21 +86,7 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->regs[n] = tmp; return 4; } - if (n < 24) { /* 16-23 */ - /* FPA registers (ignored). */ - if (gdb_has_xml()) { - return 0; - } - return 12; - } - switch (n) { - case 24: - /* FPA status register (ignored). */ - if (gdb_has_xml()) { - return 0; - } - return 4; - case 25: + if (n == 25) { /* CPSR, or XPSR for M-profile */ if (arm_feature(env, ARM_FEATURE_M)) { /* -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> GDB has XML support since 6.7 which was released in 2007. It's time to remove support for old GDB versions without XML support. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Message-Id: <20230912224107.29669-11-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- target/ppc/gdbstub.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 778ef73bd7..ec5731e5d6 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -54,12 +54,6 @@ static int ppc_gdb_register_len(int n) case 0 ... 31: /* gprs */ return sizeof(target_ulong); - case 32 ... 63: - /* fprs */ - if (gdb_has_xml()) { - return 0; - } - return 8; case 66: /* cr */ case 69: @@ -74,12 +68,6 @@ static int ppc_gdb_register_len(int n) case 68: /* ctr */ return sizeof(target_ulong); - case 70: - /* fpscr */ - if (gdb_has_xml()) { - return 0; - } - return sizeof(target_ulong); default: return 0; } @@ -132,9 +120,6 @@ int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n) if (n < 32) { /* gprs */ gdb_get_regl(buf, env->gpr[n]); - } else if (n < 64) { - /* fprs */ - gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32)); } else { switch (n) { case 64: @@ -158,9 +143,6 @@ int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n) case 69: gdb_get_reg32(buf, cpu_read_xer(env)); break; - case 70: - gdb_get_reg32(buf, env->fpscr); - break; } } mem_buf = buf->data + buf->len - r; -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> GDB has XML support since 6.7 which was released in 2007. It's time to remove support for old GDB versions without XML support. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Message-Id: <20230912224107.29669-12-akihiko.odaki@daynix.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- gdbstub/internals.h | 2 -- include/exec/gdbstub.h | 8 -------- gdbstub/gdbstub.c | 15 --------------- 3 files changed, 25 deletions(-) diff --git a/gdbstub/internals.h b/gdbstub/internals.h index fee243081f..7128c4aa85 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -32,8 +32,6 @@ enum { typedef struct GDBProcess { uint32_t pid; bool attached; - - /* If gdb sends qXfer:features:read:target.xml this will be populated */ char *target_xml; } GDBProcess; diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 705be2c5d7..1a01c35f8e 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -45,14 +45,6 @@ int gdbserver_start(const char *port_or_device); void gdb_set_stop_cpu(CPUState *cpu); -/** - * gdb_has_xml() - report of gdb supports modern target descriptions - * - * This will report true if the gdb negotiated qXfer:features:read - * target descriptions. - */ -bool gdb_has_xml(void); - /* in gdbstub-xml.c, generated by scripts/feature_to_c.py */ extern const GDBFeature gdb_static_features[]; diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index a4f2bf3723..177dce9ba2 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -349,11 +349,6 @@ static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid) } } -bool gdb_has_xml(void) -{ - return !!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml; -} - static const char *get_feature_xml(const char *p, const char **newp, GDBProcess *process) { @@ -1086,11 +1081,6 @@ static void handle_set_reg(GArray *params, void *user_ctx) { int reg_size; - if (!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml) { - gdb_put_packet(""); - return; - } - if (params->len != 2) { gdb_put_packet("E22"); return; @@ -1107,11 +1097,6 @@ static void handle_get_reg(GArray *params, void *user_ctx) { int reg_size; - if (!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml) { - gdb_put_packet(""); - return; - } - if (!params->len) { gdb_put_packet("E14"); return; -- 2.39.2

From: Akihiko Odaki <akihiko.odaki@daynix.com> An array is a more appropriate data structure than a list for gdb_regs since it is initialized only with append operation and read-only after initialization. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Message-Id: <20230912224107.29669-13-akihiko.odaki@daynix.com> [AJB: fixed a checkpatch violation] Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- include/hw/core/cpu.h | 2 +- gdbstub/gdbstub.c | 35 +++++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 5ae479a961..0338640e3d 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -364,7 +364,7 @@ struct CPUState { CPUJumpCache *tb_jmp_cache; - struct GDBRegisterState *gdb_regs; + GArray *gdb_regs; int gdb_num_regs; int gdb_num_g_regs; QTAILQ_ENTRY(CPUState) node; diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 177dce9ba2..a041b1c0aa 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -51,7 +51,6 @@ typedef struct GDBRegisterState { gdb_get_reg_cb get_reg; gdb_set_reg_cb set_reg; const char *xml; - struct GDBRegisterState *next; } GDBRegisterState; GDBState gdbserver_state; @@ -386,7 +385,8 @@ static const char *get_feature_xml(const char *p, const char **newp, xml, g_markup_printf_escaped("<xi:include href=\"%s\"/>", cc->gdb_core_xml_file)); - for (r = cpu->gdb_regs; r; r = r->next) { + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); g_ptr_array_add( xml, g_markup_printf_escaped("<xi:include href=\"%s\"/>", @@ -430,7 +430,8 @@ static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) return cc->gdb_read_register(cpu, buf, reg); } - for (r = cpu->gdb_regs; r; r = r->next) { + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { return r->get_reg(env, buf, reg - r->base_reg); } @@ -448,7 +449,8 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) return cc->gdb_write_register(cpu, mem_buf, reg); } - for (r = cpu->gdb_regs; r; r = r->next) { + for (guint i = 0; i < cpu->gdb_regs->len; i++) { + r = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) { return r->set_reg(env, mem_buf, reg - r->base_reg); } @@ -461,17 +463,23 @@ void gdb_register_coprocessor(CPUState *cpu, int num_regs, const char *xml, int g_pos) { GDBRegisterState *s; - GDBRegisterState **p; - - p = &cpu->gdb_regs; - while (*p) { - /* Check for duplicates. */ - if (strcmp((*p)->xml, xml) == 0) - return; - p = &(*p)->next; + guint i; + + if (cpu->gdb_regs) { + for (i = 0; i < cpu->gdb_regs->len; i++) { + /* Check for duplicates. */ + s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); + if (strcmp(s->xml, xml) == 0) { + return; + } + } + } else { + cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState)); + i = 0; } - s = g_new0(GDBRegisterState, 1); + g_array_set_size(cpu->gdb_regs, i + 1); + s = &g_array_index(cpu->gdb_regs, GDBRegisterState, i); s->base_reg = cpu->gdb_num_regs; s->num_regs = num_regs; s->get_reg = get_reg; @@ -480,7 +488,6 @@ void gdb_register_coprocessor(CPUState *cpu, /* Add to end of list. */ cpu->gdb_num_regs += num_regs; - *p = s; if (g_pos) { if (g_pos != s->base_reg) { error_report("Error: Bad gdb register numbering for '%s', " -- 2.39.2

From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230824181233.1568795-2-richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- include/exec/translator.h | 2 ++ accel/tcg/translator.c | 1 + 2 files changed, 3 insertions(+) diff --git a/include/exec/translator.h b/include/exec/translator.h index 4e17c4f401..bf5bac260a 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -72,6 +72,7 @@ typedef enum DisasJumpType { * @num_insns: Number of translated instructions (including current). * @max_insns: Maximum number of instructions to be translated in this TB. * @singlestep_enabled: "Hardware" single stepping enabled. + * @plugin_enabled: TCG plugin enabled in this TB. * * Architecture-agnostic disassembly context. */ @@ -83,6 +84,7 @@ typedef struct DisasContextBase { int num_insns; int max_insns; bool singlestep_enabled; + bool plugin_enabled; void *host_addr[2]; } DisasContextBase; diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 1a6a5448c8..37f8dadbbd 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -156,6 +156,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY); + db->plugin_enabled = plugin_enabled; while (true) { *max_insns = ++db->num_insns; -- 2.39.2

From: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230824181233.1568795-3-richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- target/sh4/translate.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index c1e590feb3..b4dee34c9a 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1816,6 +1816,18 @@ static void decode_opc(DisasContext * ctx) } #ifdef CONFIG_USER_ONLY +/* + * Restart with the EXCLUSIVE bit set, within a TB run via + * cpu_exec_step_atomic holding the exclusive lock. + */ +static void gen_restart_exclusive(DisasContext *ctx) +{ + ctx->envflags |= TB_FLAG_GUSA_EXCLUSIVE; + gen_save_cpu_state(ctx, false); + gen_helper_exclusive(cpu_env); + ctx->base.is_jmp = DISAS_NORETURN; +} + /* For uniprocessors, SH4 uses optimistic restartable atomic sequences. Upon an interrupt, a real kernel would simply notice magic values in the registers and reset the PC to the start of the sequence. @@ -2149,12 +2161,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) qemu_log_mask(LOG_UNIMP, "Unrecognized gUSA sequence %08x-%08x\n", pc, pc_end); - /* Restart with the EXCLUSIVE bit set, within a TB run via - cpu_exec_step_atomic holding the exclusive lock. */ - ctx->envflags |= TB_FLAG_GUSA_EXCLUSIVE; - gen_save_cpu_state(ctx, false); - gen_helper_exclusive(cpu_env); - ctx->base.is_jmp = DISAS_NORETURN; + gen_restart_exclusive(ctx); /* We're not executing an instruction, but we must report one for the purposes of accounting within the TB. We might as well report the @@ -2242,12 +2249,22 @@ static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) #ifdef CONFIG_USER_ONLY if (unlikely(ctx->envflags & TB_FLAG_GUSA_MASK) && !(ctx->envflags & TB_FLAG_GUSA_EXCLUSIVE)) { - /* We're in an gUSA region, and we have not already fallen - back on using an exclusive region. Attempt to parse the - region into a single supported atomic operation. Failure - is handled within the parser by raising an exception to - retry using an exclusive region. */ - decode_gusa(ctx, env); + /* + * We're in an gUSA region, and we have not already fallen + * back on using an exclusive region. Attempt to parse the + * region into a single supported atomic operation. Failure + * is handled within the parser by raising an exception to + * retry using an exclusive region. + * + * Parsing the region in one block conflicts with plugins, + * so always use exclusive mode if plugins enabled. + */ + if (ctx->base.plugin_enabled) { + gen_restart_exclusive(ctx); + ctx->base.pc_next += 2; + } else { + decode_gusa(ctx, env); + } return; } #endif -- 2.39.2

From: Matt Borgerson <contact@mborgerson.com> Translation logic may partially decode an instruction, then abort and remove the instruction from the TB. This can happen for example when an instruction spans two pages. In this case, plugins may get an incorrect result when calling qemu_plugin_tb_n_insns to query for the number of instructions in the TB. This patch updates plugin_gen_tb_end to set the final instruction count. Signed-off-by: Matt Borgerson <contact@mborgerson.com> [AJB: added g_assert to defed API] Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <CADc=-s5RwGViNTR-h5cq3np673W3RRFfhr4vCGJp0EoDUxvhog@mail.gmail.com> --- include/exec/plugin-gen.h | 4 ++-- accel/tcg/plugin-gen.c | 6 +++++- accel/tcg/translator.c | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h index 52828781bc..c4552b5061 100644 --- a/include/exec/plugin-gen.h +++ b/include/exec/plugin-gen.h @@ -20,7 +20,7 @@ struct DisasContextBase; bool plugin_gen_tb_start(CPUState *cpu, const struct DisasContextBase *db, bool supress); -void plugin_gen_tb_end(CPUState *cpu); +void plugin_gen_tb_end(CPUState *cpu, size_t num_insns); void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db); void plugin_gen_insn_end(void); @@ -42,7 +42,7 @@ void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db) static inline void plugin_gen_insn_end(void) { } -static inline void plugin_gen_tb_end(CPUState *cpu) +static inline void plugin_gen_tb_end(CPUState *cpu, size_t num_insns) { } static inline void plugin_gen_disable_mem_helpers(void) diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index 5c13615112..c0adc9f4b7 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -866,10 +866,14 @@ void plugin_gen_insn_end(void) * do any clean-up here and make sure things are reset in * plugin_gen_tb_start. */ -void plugin_gen_tb_end(CPUState *cpu) +void plugin_gen_tb_end(CPUState *cpu, size_t num_insns) { struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb; + /* translator may have removed instructions, update final count */ + g_assert(num_insns <= ptb->n); + ptb->n = num_insns; + /* collect instrumentation requests */ qemu_plugin_tb_trans_cb(cpu, ptb); diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 37f8dadbbd..ff84282fe5 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -212,7 +212,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, gen_tb_end(tb, cflags, icount_start_insn, db->num_insns); if (plugin_enabled) { - plugin_gen_tb_end(cpu); + plugin_gen_tb_end(cpu, db->num_insns); } /* The disas_log hook may use these values rather than recompute. */ -- 2.39.2

Coverity complains that appends_stats_line can be fed a 0 leading to the undefined behaviour of a divide by 0. Fixes: CID 1519044 Fixes: CID 1519047 Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- contrib/plugins/cache.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index 4fca3edd07..9e7ade3b37 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -535,15 +535,13 @@ static void caches_free(Cache **caches) } } -static void append_stats_line(GString *line, uint64_t l1_daccess, - uint64_t l1_dmisses, uint64_t l1_iaccess, - uint64_t l1_imisses, uint64_t l2_access, - uint64_t l2_misses) +static void append_stats_line(GString *line, + uint64_t l1_daccess, uint64_t l1_dmisses, + uint64_t l1_iaccess, uint64_t l1_imisses, + uint64_t l2_access, uint64_t l2_misses) { - double l1_dmiss_rate, l1_imiss_rate, l2_miss_rate; - - l1_dmiss_rate = ((double) l1_dmisses) / (l1_daccess) * 100.0; - l1_imiss_rate = ((double) l1_imisses) / (l1_iaccess) * 100.0; + double l1_dmiss_rate = ((double) l1_dmisses) / (l1_daccess) * 100.0; + double l1_imiss_rate = ((double) l1_imisses) / (l1_iaccess) * 100.0; g_string_append_printf(line, "%-14" PRIu64 " %-12" PRIu64 " %9.4lf%%" " %-14" PRIu64 " %-12" PRIu64 " %9.4lf%%", @@ -554,8 +552,8 @@ static void append_stats_line(GString *line, uint64_t l1_daccess, l1_imisses, l1_iaccess ? l1_imiss_rate : 0.0); - if (use_l2) { - l2_miss_rate = ((double) l2_misses) / (l2_access) * 100.0; + if (l2_access && l2_misses) { + double l2_miss_rate = ((double) l2_misses) / (l2_access) * 100.0; g_string_append_printf(line, " %-12" PRIu64 " %-11" PRIu64 " %10.4lf%%", l2_access, -- 2.39.2

Coverity complains that e don't check for a truncation when copying in the path. Bail if we can't copy the whole path into sockaddr. Fixes: CID 1519045 Fixes: CID 1519046 Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- contrib/plugins/lockstep.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/plugins/lockstep.c b/contrib/plugins/lockstep.c index 682b11feb2..f0cb8792c6 100644 --- a/contrib/plugins/lockstep.c +++ b/contrib/plugins/lockstep.c @@ -245,6 +245,7 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) static bool setup_socket(const char *path) { struct sockaddr_un sockaddr; + const gsize pathlen = sizeof(sockaddr.sun_path) - 1; int fd; fd = socket(AF_UNIX, SOCK_STREAM, 0); @@ -254,7 +255,11 @@ static bool setup_socket(const char *path) } sockaddr.sun_family = AF_UNIX; - g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); + if (g_strlcpy(sockaddr.sun_path, path, pathlen) >= pathlen) { + perror("bad path"); + return false; + } + if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { perror("bind socket"); close(fd); @@ -287,6 +292,7 @@ static bool connect_socket(const char *path) { int fd; struct sockaddr_un sockaddr; + const gsize pathlen = sizeof(sockaddr.sun_path) - 1; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { @@ -295,7 +301,10 @@ static bool connect_socket(const char *path) } sockaddr.sun_family = AF_UNIX; - g_strlcpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); + if (g_strlcpy(sockaddr.sun_path, path, pathlen) >= pathlen) { + perror("bad path"); + return false; + } if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { perror("failed to connect"); -- 2.39.2

Coverity complains that we have an unbalance use of mutex leading to potential deadlocks. Fixes: CID 1519048 Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- contrib/plugins/hotblocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c index 6b74d25fea..4de1b13494 100644 --- a/contrib/plugins/hotblocks.c +++ b/contrib/plugins/hotblocks.c @@ -69,8 +69,8 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) } g_list_free(it); - g_mutex_unlock(&lock); } + g_mutex_unlock(&lock); qemu_plugin_outs(report->str); } -- 2.39.2

We are about to remove direct calls to individual accelerators for this information and will need a central point for plugins to hook into time changes. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20230519170454.2353945-5-alex.bennee@linaro.org> --- v2 - more kerneldoc annotations --- include/sysemu/accel-ops.h | 18 ++++++++++++- include/sysemu/cpu-timers.h | 27 ++++++++++++++++++- softmmu/cpus.c | 11 ++++++++ ...t-virtual-clock.c => cpus-virtual-clock.c} | 5 ++++ stubs/meson.build | 2 +- 5 files changed, 60 insertions(+), 3 deletions(-) rename stubs/{cpus-get-virtual-clock.c => cpus-virtual-clock.c} (68%) diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h index 3c1fab4b1e..224e85a649 100644 --- a/include/sysemu/accel-ops.h +++ b/include/sysemu/accel-ops.h @@ -20,7 +20,12 @@ typedef struct AccelOpsClass AccelOpsClass; DECLARE_CLASS_CHECKERS(AccelOpsClass, ACCEL_OPS, TYPE_ACCEL_OPS) -/* cpus.c operations interface */ +/** + * struct AccelOpsClass - accelerator interfaces + * + * This structure is used to abstract accelerator differences from the + * core CPU code. Not all have to be implemented. + */ struct AccelOpsClass { /*< private >*/ ObjectClass parent_class; @@ -43,7 +48,18 @@ struct AccelOpsClass { void (*handle_interrupt)(CPUState *cpu, int mask); + /** + * @get_virtual_clock: fetch virtual clock + * @set_virtual_clock: set virtual clock + * + * These allow the timer subsystem to defer to the accelerator to + * fetch time. The set function is needed if the accelerator wants + * to track the changes to time as the timer is warped through + * various timer events. + */ int64_t (*get_virtual_clock)(void); + void (*set_virtual_clock)(int64_t time); + int64_t (*get_elapsed_ticks)(void); /* gdbstub hooks */ diff --git a/include/sysemu/cpu-timers.h b/include/sysemu/cpu-timers.h index 2e786fe7fb..31ab2bbd4e 100644 --- a/include/sysemu/cpu-timers.h +++ b/include/sysemu/cpu-timers.h @@ -84,8 +84,33 @@ int64_t cpu_get_clock(void); void qemu_timer_notify_cb(void *opaque, QEMUClockType type); -/* get the VIRTUAL clock and VM elapsed ticks via the cpus accel interface */ +/** + * cpus_get_virtual_clock() - return current virtual clock. + * + * This is a wrapper around accelerator specific get_virtual_clock() + * + * Returns: ns of virtual time + */ int64_t cpus_get_virtual_clock(void); + +/** + * cpus_set_virtual_clock() - set the virtual clock + * @new_time: new value in ns + * + * This is a wrapper around accelerator specific set_virtual_clock() + */ +void cpus_set_virtual_clock(int64_t new_time); + +/** + * cpus_get_elapsed_ticks() - get elapsed host time + * + * This is usually the current value of the host tick counter (i.e. + * not taking into account guest pauses). However some accelerators + * which want to keep elapsed time in sync with virtual time will + * return the virtual clock. + * + * Returns: ticks of elapsed host time (usually ns) + */ int64_t cpus_get_elapsed_ticks(void); #endif /* SYSEMU_CPU_TIMERS_H */ diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 0848e0dbdb..b645c462e1 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -221,6 +221,17 @@ int64_t cpus_get_virtual_clock(void) return cpu_get_clock(); } +/* + * Signal the new virtual time to the accelerator. This is only needed + * by accelerators that need to track the changes as we warp time. + */ +void cpus_set_virtual_clock(int64_t new_time) +{ + if (cpus_accel && cpus_accel->set_virtual_clock) { + cpus_accel->set_virtual_clock(new_time); + } +} + /* * return the time elapsed in VM between vm_start and vm_stop. Unless * icount is active, cpus_get_elapsed_ticks() uses units of the host CPU cycle diff --git a/stubs/cpus-get-virtual-clock.c b/stubs/cpus-virtual-clock.c similarity index 68% rename from stubs/cpus-get-virtual-clock.c rename to stubs/cpus-virtual-clock.c index fd447d53f3..af7c1a1d40 100644 --- a/stubs/cpus-get-virtual-clock.c +++ b/stubs/cpus-virtual-clock.c @@ -6,3 +6,8 @@ int64_t cpus_get_virtual_clock(void) { return cpu_get_clock(); } + +void cpus_set_virtual_clock(int64_t new_time) +{ + /* do nothing */ +} diff --git a/stubs/meson.build b/stubs/meson.build index ef6e39a64d..2ea43ee076 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -5,7 +5,7 @@ stub_ss.add(files('blockdev-close-all-bdrv-states.c')) stub_ss.add(files('change-state-handler.c')) stub_ss.add(files('cmos.c')) stub_ss.add(files('cpu-get-clock.c')) -stub_ss.add(files('cpus-get-virtual-clock.c')) +stub_ss.add(files('cpus-virtual-clock.c')) stub_ss.add(files('qemu-timer-notify-cb.c')) stub_ss.add(files('icount.c')) stub_ss.add(files('dump.c')) -- 2.39.2

This generalises the qtest_clock_warp code to use the AccelOps handlers for updating its own sense of time. This will make the next patch which moves the warp code closer to pure code motion. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Acked-by: Thomas Huth <thuth@redhat.com> Message-Id: <20230519170454.2353945-6-alex.bennee@linaro.org> --- include/sysemu/qtest.h | 1 + accel/qtest/qtest.c | 1 + softmmu/qtest.c | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h index 85f05b0e46..e1f69783d6 100644 --- a/include/sysemu/qtest.h +++ b/include/sysemu/qtest.h @@ -35,5 +35,6 @@ void qtest_server_set_send_handler(void (*send)(void *, const char *), void qtest_server_inproc_recv(void *opaque, const char *buf); int64_t qtest_get_virtual_clock(void); +void qtest_set_virtual_clock(int64_t count); #endif diff --git a/accel/qtest/qtest.c b/accel/qtest/qtest.c index f6056ac836..53182e6c2a 100644 --- a/accel/qtest/qtest.c +++ b/accel/qtest/qtest.c @@ -52,6 +52,7 @@ static void qtest_accel_ops_class_init(ObjectClass *oc, void *data) ops->create_vcpu_thread = dummy_start_vcpu_thread; ops->get_virtual_clock = qtest_get_virtual_clock; + ops->set_virtual_clock = qtest_set_virtual_clock; }; static const TypeInfo qtest_accel_ops_type = { diff --git a/softmmu/qtest.c b/softmmu/qtest.c index 35b643a274..bac1962efb 100644 --- a/softmmu/qtest.c +++ b/softmmu/qtest.c @@ -331,14 +331,14 @@ int64_t qtest_get_virtual_clock(void) return qatomic_read_i64(&qtest_clock_counter); } -static void qtest_set_virtual_clock(int64_t count) +void qtest_set_virtual_clock(int64_t count) { qatomic_set_i64(&qtest_clock_counter, count); } static void qtest_clock_warp(int64_t dest) { - int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t clock = cpus_get_virtual_clock(); AioContext *aio_context; assert(qtest_enabled()); aio_context = qemu_get_aio_context(); @@ -347,7 +347,7 @@ static void qtest_clock_warp(int64_t dest) QEMU_TIMER_ATTR_ALL); int64_t warp = qemu_soonest_timeout(dest - clock, deadline); - qtest_set_virtual_clock(qtest_get_virtual_clock() + warp); + cpus_set_virtual_clock(cpus_get_virtual_clock() + warp); qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]); -- 2.39.2

Move the key functionality of moving time forward into the clock sub-system itself. This will allow us to plumb in time control into plugins. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20230519170454.2353945-7-alex.bennee@linaro.org> --- v2 - rename arg to target_ns --- include/qemu/timer.h | 15 +++++++++++++++ softmmu/qtest.c | 24 ++---------------------- util/qemu-timer.c | 26 ++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 9a91cb1248..aa30f693b0 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -245,6 +245,21 @@ bool qemu_clock_run_timers(QEMUClockType type); */ bool qemu_clock_run_all_timers(void); +/** + * qemu_clock_advance_virtual_time(): advance the virtual time tick + * @target_ns: target time in nanoseconds + * + * This function is used where the control of the flow of time has + * been delegated to outside the clock subsystem (be it qtest, icount + * or some other external source). You can ask the clock system to + * return @early at the first expired timer. + * + * Time can only move forward, attempts to reverse time would lead to + * an error. + * + * Returns: new virtual time. + */ +int64_t qemu_clock_advance_virtual_time(int64_t target_ns); /* * QEMUTimerList diff --git a/softmmu/qtest.c b/softmmu/qtest.c index bac1962efb..72a2ee7a31 100644 --- a/softmmu/qtest.c +++ b/softmmu/qtest.c @@ -336,26 +336,6 @@ void qtest_set_virtual_clock(int64_t count) qatomic_set_i64(&qtest_clock_counter, count); } -static void qtest_clock_warp(int64_t dest) -{ - int64_t clock = cpus_get_virtual_clock(); - AioContext *aio_context; - assert(qtest_enabled()); - aio_context = qemu_get_aio_context(); - while (clock < dest) { - int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, - QEMU_TIMER_ATTR_ALL); - int64_t warp = qemu_soonest_timeout(dest - clock, deadline); - - cpus_set_virtual_clock(cpus_get_virtual_clock() + warp); - - qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); - timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]); - clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - } - qemu_clock_notify(QEMU_CLOCK_VIRTUAL); -} - static bool (*process_command_cb)(CharBackend *chr, gchar **words); void qtest_set_command_cb(bool (*pc_cb)(CharBackend *chr, gchar **words)) @@ -754,7 +734,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words) ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, QEMU_TIMER_ATTR_ALL); } - qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns); + qemu_clock_advance_virtual_time(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns); qtest_send_prefix(chr); qtest_sendf(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); @@ -780,7 +760,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words) g_assert(words[1]); ret = qemu_strtoi64(words[1], NULL, 0, &ns); g_assert(ret == 0); - qtest_clock_warp(ns); + qemu_clock_advance_virtual_time(ns); qtest_send_prefix(chr); qtest_sendf(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 6a0de33dd2..213114be68 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -645,6 +645,11 @@ int64_t qemu_clock_get_ns(QEMUClockType type) } } +static void qemu_virtual_clock_set_ns(int64_t time) +{ + return cpus_set_virtual_clock(time); +} + void init_clocks(QEMUTimerListNotifyCB *notify_cb) { QEMUClockType type; @@ -675,3 +680,24 @@ bool qemu_clock_run_all_timers(void) return progress; } + +int64_t qemu_clock_advance_virtual_time(int64_t dest) +{ + int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + AioContext *aio_context; + aio_context = qemu_get_aio_context(); + while (clock < dest) { + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + QEMU_TIMER_ATTR_ALL); + int64_t warp = qemu_soonest_timeout(dest - clock, deadline); + + qemu_virtual_clock_set_ns(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + warp); + + qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); + timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]); + clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + } + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + + return clock; +} -- 2.39.2

Expose the ability to control time through the plugin API. Only one plugin can control time so it has to request control when loaded. There are probably more corner cases to catch here. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20230519170454.2353945-8-alex.bennee@linaro.org> --- v2 - ifdef for SOFTMMU only - fix checkpatch warnings --- include/qemu/qemu-plugin.h | 19 +++++++++++++++++++ plugins/api.c | 28 ++++++++++++++++++++++++++++ plugins/qemu-plugins.symbols | 2 ++ 3 files changed, 49 insertions(+) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 50a9957279..898385d92d 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -536,7 +536,26 @@ void qemu_plugin_register_vcpu_mem_inline(struct qemu_plugin_insn *insn, enum qemu_plugin_op op, void *ptr, uint64_t imm); +/** + * qemu_plugin_request_time_control() - request the ability to control time + * + * This grants the plugin the ability to control system time. Only one + * plugin can control time so if multiple plugins request the ability + * all but the first will fail. + * + * Returns an opaque handle or NULL if fails + */ +const void *qemu_plugin_request_time_control(void); +/** + * qemu_plugin_update_ns() - update system emulation time + * @handle: opaque handle returned by qemu_plugin_request_time_control() + * @new_time_ns: time in nanoseconds + * + * This allows an appropriately authorised plugin (i.e. holding the + * time control handle) to move system time forward to @new_time_ns. + */ +void qemu_plugin_update_ns(const void *handle, int64_t new_time_ns); typedef void (*qemu_plugin_vcpu_syscall_cb_t)(qemu_plugin_id_t id, unsigned int vcpu_index, diff --git a/plugins/api.c b/plugins/api.c index 5521b0ad36..a1d413dc2d 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -37,6 +37,7 @@ #include "qemu/osdep.h" #include "qemu/plugin.h" #include "qemu/log.h" +#include "qemu/timer.h" #include "tcg/tcg.h" #include "exec/exec-all.h" #include "exec/ram_addr.h" @@ -427,3 +428,30 @@ uint64_t qemu_plugin_entry_code(void) #endif return entry; } + +/* + * Time control + */ +#ifdef CONFIG_SOFTMMU +static bool has_control; +#endif + +const void *qemu_plugin_request_time_control(void) +{ +#ifdef CONFIG_SOFTMMU + if (!has_control) { + has_control = true; + return &has_control; + } +#endif + return NULL; +} + +void qemu_plugin_update_ns(const void *handle, int64_t new_time) +{ +#ifdef CONFIG_SOFTMMU + if (handle == &has_control) { + qemu_clock_advance_virtual_time(new_time); + } +#endif +} diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols index 71f6c90549..91b882fecc 100644 --- a/plugins/qemu-plugins.symbols +++ b/plugins/qemu-plugins.symbols @@ -35,11 +35,13 @@ qemu_plugin_register_vcpu_tb_exec_cb; qemu_plugin_register_vcpu_tb_exec_inline; qemu_plugin_register_vcpu_tb_trans_cb; + qemu_plugin_request_time_control; qemu_plugin_reset; qemu_plugin_start_code; qemu_plugin_tb_get_insn; qemu_plugin_tb_n_insns; qemu_plugin_tb_vaddr; qemu_plugin_uninstall; + qemu_plugin_update_ns; qemu_plugin_vcpu_for_each; }; -- 2.39.2

This plugin uses the new time control interface to make decisions about the state of time during the emulation. The algorithm is currently very simple. The user specifies an iops rate which applies per core. If the core runs ahead of its allocated execution time the plugin sleeps for a bit to let real time catch up. Either way time as updated for the emulation as a function of total executed instructions with some adjustments for cores that idle. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20230519170454.2353945-9-alex.bennee@linaro.org> --- v2 - fix various style issues --- contrib/plugins/iops.c | 261 +++++++++++++++++++++++++++++++++++++++ contrib/plugins/Makefile | 1 + 2 files changed, 262 insertions(+) create mode 100644 contrib/plugins/iops.c diff --git a/contrib/plugins/iops.c b/contrib/plugins/iops.c new file mode 100644 index 0000000000..6f8baca6f7 --- /dev/null +++ b/contrib/plugins/iops.c @@ -0,0 +1,261 @@ +/* + * iops rate limiting plugin. + * + * This plugin can be used to restrict the execution of a system to a + * particular number of Instructions Per Second (IOPS). This controls + * time as seen by the guest so while wall-clock time may be longer + * from the guests point of view time will pass at the normal rate. + * + * This uses the new plugin API which allows the plugin to control + * system time. + * + * Copyright (c) 2023 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include <stdio.h> +#include <glib.h> +#include <qemu-plugin.h> + +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + +#define SLICES 10 /* the number of slices per second we compute delay */ + +static GMutex global_state_lock; + +static uint64_t iops = 1000000; /* iops rate, per core, per second */ +static uint64_t current_ticks; /* current global ticks */ +static uint64_t next_check; /* the next checkpoint for time */ +static bool precise_execution; /* count every instruction */ + +static int64_t systime_at_start; /* time we started the first vCPU */ + +static const uint64_t nsec_per_sec = 1000000000; +static const void *time_handle; + +/* + * We need to track the number of instructions each vCPU has executed + * as well as what its current state is. We need to account for time + * passing while a vCPU is idle. + */ + +typedef enum { + UNKNOWN = 0, + CREATED, + EXECUTING, + IDLE, + FINISHED +} vCPUState; + +typedef struct { + /* pointer to vcpu counter entry */ + uint64_t *counter; + vCPUState state; + /* timestamp when vCPU entered state */ + uint64_t state_time; + /* number of ns vCPU was idle */ + uint64_t total_idle; +} vCPUTime; + +GArray *vcpus; +uint64_t *vcpu_counters; + +/* + * Get the vcpu structure for this vCPU. We don't do any locking here + * as only one vCPU will ever access its own structure. + */ +static vCPUTime *get_vcpu(int cpu_index) +{ + return &g_array_index(vcpus, vCPUTime, cpu_index); +} + +/* + * When emulation is running faster than real time this is the point + * we can throttle the execution of a given vCPU. Either way we can + * now tell the system to move time forward. + */ +static void update_system_time(int64_t vcpu_ticks) +{ + int64_t now = g_get_real_time(); + int64_t real_runtime_ns = now - systime_at_start; + + g_mutex_lock(&global_state_lock); + /* now we have the lock double check we are fastest */ + if (vcpu_ticks > next_check) { + + int64_t tick_runtime_ns = (vcpu_ticks / iops) * nsec_per_sec; + if (tick_runtime_ns > real_runtime_ns) { + int64_t sleep_us = (tick_runtime_ns - real_runtime_ns) / 1000; + g_usleep(sleep_us); + } + + /* Having slept we can now move the clocks forward */ + qemu_plugin_update_ns(time_handle, vcpu_ticks); + current_ticks = vcpu_ticks; + next_check = iops / SLICES; + } + g_mutex_unlock(&global_state_lock); +} + +/* + * State tracking + */ +static void vcpu_init(qemu_plugin_id_t id, unsigned int cpu_index) +{ + vCPUTime *vcpu = get_vcpu(cpu_index); + vcpu->state = CREATED; + vcpu->state_time = *vcpu->counter; + + g_mutex_lock(&global_state_lock); + if (!systime_at_start) { + systime_at_start = g_get_real_time(); + } + g_mutex_unlock(&global_state_lock); +} + +static void vcpu_idle(qemu_plugin_id_t id, unsigned int cpu_index) +{ + vCPUTime *vcpu = get_vcpu(cpu_index); + vcpu->state = IDLE; + vcpu->state_time = *vcpu->counter; + + /* handle when we are the last vcpu to sleep here */ +} + +static void vcpu_resume(qemu_plugin_id_t id, unsigned int cpu_index) +{ + vCPUTime *vcpu = get_vcpu(cpu_index); + + /* + * Now we need to reset counter to something approximating the + * current time, however we only update current_ticks when a block + * exceeds next_check. If the vCPU has been asleep for awhile this + * will probably do, otherwise lets pick somewhere between + * current_ticks and the next_check value. + */ + if (vcpu->state_time < current_ticks) { + *vcpu->counter = current_ticks; + } else { + int64_t window = next_check - vcpu->state_time; + *vcpu->counter = next_check - (window / 2); + } + + vcpu->state = EXECUTING; + vcpu->state_time = *vcpu->counter; +} + +static void vcpu_exit(qemu_plugin_id_t id, unsigned int cpu_index) +{ + vCPUTime *vcpu = get_vcpu(cpu_index); + vcpu->state = FINISHED; + vcpu->state_time = *vcpu->counter; +} + +/* + * tb exec + */ +static void vcpu_tb_exec(unsigned int cpu_index, void *udata) +{ + vCPUTime *vcpu = get_vcpu(cpu_index); + uint64_t count = *vcpu->counter; + + count += GPOINTER_TO_UINT(udata); + + if (count >= next_check) { + update_system_time(count); + } +} + +/* + * We have two choices at translation time. In imprecise mode we just + * install a tb execution callback with the total number of + * instructions in the block. This ignores any partial execution + * effects but it reasonably fast. In precise mode we increment a + * per-vCPU counter for every execution. + */ + +static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) +{ + size_t n_insns = qemu_plugin_tb_n_insns(tb); + qemu_plugin_register_vcpu_tb_exec_cb(tb, vcpu_tb_exec, + QEMU_PLUGIN_CB_NO_REGS, + GUINT_TO_POINTER(n_insns)); +} + +/** + * Install the plugin + */ +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, + const qemu_info_t *info, int argc, + char **argv) +{ + /* This plugin only makes sense for system emulation */ + if (!info->system_emulation) { + fprintf(stderr, "iops plugin only works with system emulation\n"); + return -1; + } + + for (int i = 0; i < argc; i++) { + char *opt = argv[i]; + g_auto(GStrv) tokens = g_strsplit(opt, "=", 2); + if (g_strcmp0(tokens[0], "iops") == 0) { + iops = g_ascii_strtoull(tokens[1], NULL, 10); + if (!iops && errno) { + fprintf(stderr, "%s: couldn't parse %s (%s)\n", + __func__, tokens[1], g_strerror(errno)); + return -1; + } + + } else if (g_strcmp0(tokens[0], "precise") == 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], + &precise_execution)) { + fprintf(stderr, "boolean argument parsing failed: %s\n", opt); + return -1; + } + } else { + fprintf(stderr, "option parsing failed: %s\n", opt); + return -1; + } + } + + /* + * Setup the tracking information we need to run. + */ + vcpus = g_array_new(true, true, sizeof(vCPUTime)); + g_array_set_size(vcpus, info->system.max_vcpus); + vcpu_counters = g_malloc0_n(info->system.max_vcpus, sizeof(uint64_t)); + for (int i = 0; i < info->system.max_vcpus; i++) { + vCPUTime *vcpu = get_vcpu(i); + vcpu->counter = &vcpu_counters[i]; + } + + /* + * We are going to check the state of time every slice so set the + * first check at t0 + iops/SLICES + */ + next_check = iops / SLICES; + + /* + * Only one plugin can request time control, if we don't get the + * handle there isn't much we can do. + */ + time_handle = qemu_plugin_request_time_control(); + if (!time_handle) { + fprintf(stderr, "%s: not given permission to control time\n", __func__); + return -1; + } + + /* + * To track time we need to measure how many instructions each + * core is executing as well as when each vcpu enters/leaves the + */ + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); + + qemu_plugin_register_vcpu_init_cb(id, vcpu_init); + qemu_plugin_register_vcpu_idle_cb(id, vcpu_idle); + qemu_plugin_register_vcpu_resume_cb(id, vcpu_resume); + qemu_plugin_register_vcpu_exit_cb(id, vcpu_exit); + + return 0; +} diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile index 8ba78c7a32..3f45a46a03 100644 --- a/contrib/plugins/Makefile +++ b/contrib/plugins/Makefile @@ -21,6 +21,7 @@ NAMES += lockstep NAMES += hwprofile NAMES += cache NAMES += drcov +NAMES += iops SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) -- 2.39.2
participants (5)
-
Alex Bennée
-
Daniel P. Berrangé
-
Edgar E. Iglesias
-
Paolo Bonzini
-
Peter Maydell