diff options
196 files changed, 2191 insertions, 943 deletions
diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index 69b36c148a..50fb59e147 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -6,6 +6,11 @@ # most restrictive to least restrictive # .base_job_template: + variables: + # Each script line from will be in a collapsible section in the job output + # and show the duration of each line. + FF_SCRIPT_SECTIONS: 1 + rules: ############################################################# # Stage 1: exclude scenarios where we definitely don't diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index f09a898c3e..0aa149a352 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -316,8 +316,7 @@ clang-system: IMAGE: fedora CONFIGURE_ARGS: --cc=clang --cxx=clang++ --extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined - TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu - ppc-softmmu s390x-softmmu + TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu s390x-softmmu MAKE_CHECK_ARGS: check-qtest check-tcg clang-user: @@ -511,6 +510,7 @@ build-oss-fuzz: IMAGE: fedora script: - mkdir build-oss-fuzz + - export LSAN_OPTIONS=suppressions=scripts/oss-fuzz/lsan_suppressions.txt - CC="clang" CXX="clang++" CFLAGS="-fsanitize=address" ./scripts/oss-fuzz/build.sh - export ASAN_OPTIONS="fast_unwind_on_malloc=0" @@ -558,29 +558,22 @@ build-coroutine-sigaltstack: MAKE_CHECK_ARGS: check-unit # Check our reduced build configurations -build-without-default-devices: +build-without-defaults: extends: .native_build_job_template needs: job: amd64-centos8-container variables: IMAGE: centos8 - CONFIGURE_ARGS: --without-default-devices --disable-user - -build-without-default-features: - extends: .native_build_job_template - needs: - job: amd64-fedora-container - variables: - IMAGE: fedora CONFIGURE_ARGS: + --without-default-devices --without-default-features - --disable-capstone + --disable-fdt --disable-pie --disable-qom-cast-debug --disable-strip - TARGETS: avr-softmmu i386-softmmu mips64-softmmu s390x-softmmu sh4-softmmu + TARGETS: avr-softmmu mips64-softmmu s390x-softmmu sh4-softmmu sparc64-softmmu hexagon-linux-user i386-linux-user s390x-linux-user - MAKE_CHECK_ARGS: check-unit check-qtest SPEED=slow + MAKE_CHECK_ARGS: check-unit check-qtest-avr check-qtest-mips64 build-libvhost-user: extends: .base_job_template diff --git a/.gitlab-ci.d/cirrus/freebsd-12.vars b/.gitlab-ci.d/cirrus/freebsd-12.vars index e3fc3235b9..8934e5d57f 100644 --- a/.gitlab-ci.d/cirrus/freebsd-12.vars +++ b/.gitlab-ci.d/cirrus/freebsd-12.vars @@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract usbredir virglrenderer vte3 zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars index 9f56babd9c..65ce456c48 100644 --- a/.gitlab-ci.d/cirrus/freebsd-13.vars +++ b/.gitlab-ci.d/cirrus/freebsd-13.vars @@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract usbredir virglrenderer vte3 zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/macos-12.vars b/.gitlab-ci.d/cirrus/macos-12.vars index ef9e14b373..65b78fa08f 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 ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 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 ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract usbredir vde vte3 zlib zstd' PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme' PYTHON='/opt/homebrew/bin/python3' diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index 8dbbb8f881..74d6259b90 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -187,7 +187,9 @@ cross-win64-system: job: win64-fedora-cross-container variables: IMAGE: fedora-win64-cross - CROSS_SKIP_TARGETS: or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu + CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu + m68k-softmmu microblazeel-softmmu nios2-softmmu + or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu tricore-softmmu xtensaeb-softmmu artifacts: paths: diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml index 97f99e29c2..9fdc476c48 100644 --- a/.gitlab-ci.d/custom-runners.yml +++ b/.gitlab-ci.d/custom-runners.yml @@ -13,6 +13,17 @@ variables: GIT_STRATEGY: clone +# All custom runners can extend this template to upload the testlog +# data as an artifact and also feed the junit report +.custom_artifacts_template: + artifacts: + name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" + expire_in: 7 days + paths: + - build/meson-logs/testlog.txt + reports: + junit: build/meson-logs/testlog.junit.xml + include: - local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml' - local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml' diff --git a/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml b/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml index fcaef9e5ef..f512eaeaa3 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml @@ -3,6 +3,7 @@ # "Install basic packages to build QEMU on Ubuntu 20.04/20.04" ubuntu-20.04-s390x-all-linux-static: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -19,12 +20,11 @@ ubuntu-20.04-s390x-all-linux-static: - ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` + - make --output-sync check-tcg - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; - - make --output-sync -j`nproc` check-tcg - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-all: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -41,9 +41,9 @@ ubuntu-20.04-s390x-all: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-alldbg: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -64,9 +64,9 @@ ubuntu-20.04-s390x-alldbg: - make clean - make --output-sync -j`nproc` - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-clang: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -86,7 +86,6 @@ ubuntu-20.04-s390x-clang: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-20.04-s390x-tci: needs: [] @@ -109,6 +108,7 @@ ubuntu-20.04-s390x-tci: - make --output-sync -j`nproc` ubuntu-20.04-s390x-notcg: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -128,4 +128,3 @@ ubuntu-20.04-s390x-notcg: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc` - make --output-sync -j`nproc` check - || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml index 2c386fa3e9..42137aaf2a 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml @@ -3,6 +3,7 @@ # "Install basic packages to build QEMU on Ubuntu 20.04" ubuntu-22.04-aarch32-all: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -22,4 +23,3 @@ ubuntu-22.04-aarch32-all: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml index abeb33eaff..8ba85be440 100644 --- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml +++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml @@ -3,6 +3,7 @@ # "Install basic packages to build QEMU on Ubuntu 20.04" ubuntu-22.04-aarch64-all-linux-static: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -19,12 +20,11 @@ ubuntu-22.04-aarch64-all-linux-static: - ../configure --enable-debug --static --disable-system --disable-pie || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` + - make check-tcg - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; - - make --output-sync -j`nproc --ignore=40` check-tcg - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-22.04-aarch64-all: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -44,9 +44,9 @@ ubuntu-22.04-aarch64-all: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-22.04-aarch64-alldbg: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -63,9 +63,9 @@ ubuntu-22.04-aarch64-alldbg: - make clean - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-22.04-aarch64-clang: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -81,11 +81,10 @@ ubuntu-22.04-aarch64-clang: script: - mkdir build - cd build - - ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers + - ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; ubuntu-22.04-aarch64-tci: needs: [] @@ -108,6 +107,7 @@ ubuntu-22.04-aarch64-tci: - make --output-sync -j`nproc --ignore=40` ubuntu-22.04-aarch64-notcg: + extends: .custom_artifacts_template needs: [] stage: build tags: @@ -127,4 +127,3 @@ ubuntu-22.04-aarch64-notcg: || { cat config.log meson-logs/meson-log.txt; exit 1; } - make --output-sync -j`nproc --ignore=40` - make --output-sync -j`nproc --ignore=40` check - || { cat meson-logs/testlog.txt; exit 1; } ; diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index a1d5790580..cf445b77f6 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -71,7 +71,7 @@ msys2-64bit: # for the msys2 64-bit job, due to the build could not complete within # the project timeout. - ..\msys64\usr\bin\bash -lc '../configure --target-list=x86_64-softmmu - --without-default-devices --disable-opengl' + --without-default-devices' - ..\msys64\usr\bin\bash -lc 'make' # qTests don't run successfully with "--without-default-devices", # so let's exclude the qtests from CI for now. @@ -113,8 +113,7 @@ msys2-32bit: - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink - mkdir output - cd output - - ..\msys64\usr\bin\bash -lc '../configure --target-list=ppc64-softmmu - --disable-opengl' + - ..\msys64\usr\bin\bash -lc '../configure --target-list=ppc64-softmmu' - ..\msys64\usr\bin\bash -lc 'make' - ..\msys64\usr\bin\bash -lc 'make check MTESTARGS=\"--no-suite qtest\" || { cat meson-logs/testlog.txt; exit 1; }' diff --git a/.travis.yml b/.travis.yml index fb3baabca9..cf088ba4cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,43 +16,6 @@ cache: - $HOME/avocado/data/cache -addons: - apt: - packages: - # Build dependencies - - libaio-dev - - libattr1-dev - - libbrlapi-dev - - libcap-ng-dev - - libcacard-dev - - libgcc-7-dev - - libgnutls28-dev - - libgtk-3-dev - - libiscsi-dev - - liblttng-ust-dev - - libncurses5-dev - - libnfs-dev - - libpixman-1-dev - - libpng-dev - - librados-dev - - libsdl2-dev - - libsdl2-image-dev - - libseccomp-dev - - libspice-protocol-dev - - libspice-server-dev - - libssh-dev - - liburcu-dev - - libusb-1.0-0-dev - - libvdeplug-dev - - libvte-2.91-dev - - libzstd-dev - - ninja-build - - sparse - - uuid-dev - # Tests dependencies - - genisoimage - - # The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu # to prevent IRC notifications from forks. This was created using: # $ travis encrypt -r "qemu/qemu" "irc.oftc.net#qemu" @@ -128,6 +91,7 @@ jobs: - libbrlapi-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgcrypt20-dev - libgnutls28-dev - libgtk-3-dev @@ -149,7 +113,8 @@ jobs: - genisoimage env: - TEST_CMD="make check check-tcg V=1" - - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS} --cxx=/bin/false" + - CONFIG="--disable-containers --enable-fdt=system + --target-list=${MAIN_SOFTMMU_TARGETS} --cxx=/bin/false" - UNRELIABLE=true - name: "[ppc64] GCC check-tcg" @@ -162,6 +127,7 @@ jobs: - libbrlapi-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgcrypt20-dev - libgnutls28-dev - libgtk-3-dev @@ -183,7 +149,8 @@ jobs: - genisoimage env: - TEST_CMD="make check check-tcg V=1" - - CONFIG="--disable-containers --target-list=ppc64-softmmu,ppc64le-linux-user" + - CONFIG="--disable-containers --enable-fdt=system + --target-list=ppc64-softmmu,ppc64le-linux-user" - name: "[s390x] GCC check-tcg" arch: s390x @@ -195,6 +162,7 @@ jobs: - libbrlapi-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgcrypt20-dev - libgnutls28-dev - libgtk-3-dev @@ -216,7 +184,8 @@ jobs: - genisoimage env: - TEST_CMD="make check check-tcg V=1" - - CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user" + - CONFIG="--disable-containers --enable-fdt=system + --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user" - UNRELIABLE=true script: - BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$? @@ -237,6 +206,7 @@ jobs: - libattr1-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgnutls28-dev - libiscsi-dev - liblttng-ust-dev @@ -255,8 +225,8 @@ jobs: # Tests dependencies - genisoimage env: - - CONFIG="--disable-containers --audio-drv-list=sdl --disable-user - --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" + - CONFIG="--disable-containers --enable-fdt=system --audio-drv-list=sdl + --disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" - name: "[s390x] GCC (user)" arch: s390x @@ -281,6 +251,7 @@ jobs: - libbrlapi-dev - libcacard-dev - libcap-ng-dev + - libfdt-dev - libgcrypt20-dev - libgnutls28-dev - libgtk-3-dev @@ -300,6 +271,6 @@ jobs: - ninja-build env: - TEST_CMD="make check-unit" - - CONFIG="--disable-containers --disable-tcg --enable-kvm - --disable-tools --host-cc=clang --cxx=clang++" + - CONFIG="--disable-containers --disable-tcg --enable-kvm --disable-tools + --enable-fdt=system --host-cc=clang --cxx=clang++" - UNRELIABLE=true diff --git a/MAINTAINERS b/MAINTAINERS index c581c11a64..5765f1b130 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -240,7 +240,6 @@ F: target/microblaze/ F: hw/microblaze/ F: disas/microblaze.c F: tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh -F: tests/tcg/nios2/Makefile.target MIPS TCG CPUs M: Philippe Mathieu-Daudé <philmd@linaro.org> @@ -262,6 +261,7 @@ F: hw/nios2/ F: disas/nios2.c F: configs/devices/nios2-softmmu/default.mak F: tests/docker/dockerfiles/debian-nios2-cross.d/build-toolchain.sh +F: tests/tcg/nios2/ OpenRISC TCG CPUs M: Stafford Horne <shorne@gmail.com> @@ -500,10 +500,7 @@ F: stubs/xen-hw-stub.c Guest CPU Cores (HAXM) --------------------- X86 HAXM CPUs -M: Wenchao Wang <wenchao.wang@intel.com> -L: haxm-team@intel.com -W: https://github.com/intel/haxm/issues -S: Maintained +S: Orphan F: accel/stubs/hax-stub.c F: include/sysemu/hax.h F: target/i386/hax/ diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 04cd1f3092..9c857eeb07 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -504,6 +504,7 @@ static void cpu_exec_exit(CPUState *cpu) if (cc->tcg_ops->cpu_exec_exit) { cc->tcg_ops->cpu_exec_exit(cpu); } + QEMU_PLUGIN_ASSERT(cpu->plugin_mem_cbs == NULL); } void cpu_exec_step_atomic(CPUState *cpu) @@ -980,6 +981,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) cpu_loop_exec_tb(cpu, tb, pc, &last_tb, &tb_exit); + QEMU_PLUGIN_ASSERT(cpu->plugin_mem_cbs == NULL); /* Try to align the host and virtual clocks if the guest is in advance */ align_clocks(sc, cpu); @@ -1064,13 +1066,12 @@ void tcg_exec_realizefn(CPUState *cpu, Error **errp) /* undo the initializations in reverse order */ void tcg_exec_unrealizefn(CPUState *cpu) { - qemu_plugin_vcpu_exit_hook(cpu); #ifndef CONFIG_USER_ONLY tcg_iommu_free_notifier_list(cpu); #endif /* !CONFIG_USER_ONLY */ tlb_destroy(cpu); - g_free(cpu->tb_jmp_cache); + g_free_rcu(cpu->tb_jmp_cache, rcu); } #ifndef CONFIG_USER_ONLY diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index c7d6514840..17a686bd9e 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -579,7 +579,8 @@ static void inject_mem_helper(TCGOp *begin_op, GArray *arr) * is possible that the code we generate after the instruction is * dead, we also add checks before generating tb_exit etc. */ -static void inject_mem_enable_helper(struct qemu_plugin_insn *plugin_insn, +static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb, + struct qemu_plugin_insn *plugin_insn, TCGOp *begin_op) { GArray *cbs[2]; @@ -599,6 +600,7 @@ static void inject_mem_enable_helper(struct qemu_plugin_insn *plugin_insn, rm_ops(begin_op); return; } + ptb->mem_helper = true; arr = g_array_sized_new(false, false, sizeof(struct qemu_plugin_dyn_cb), n_cbs); @@ -626,15 +628,22 @@ void plugin_gen_disable_mem_helpers(void) { TCGv_ptr ptr; - if (likely(tcg_ctx->plugin_insn == NULL || - !tcg_ctx->plugin_insn->mem_helper)) { + /* + * We could emit the clearing unconditionally and be done. However, this can + * be wasteful if for instance plugins don't track memory accesses, or if + * most TBs don't use helpers. Instead, emit the clearing iff the TB calls + * helpers that might access guest memory. + * + * Note: we do not reset plugin_tb->mem_helper here; a TB might have several + * exit points, and we want to emit the clearing from all of them. + */ + if (!tcg_ctx->plugin_tb->mem_helper) { return; } ptr = tcg_const_ptr(NULL); tcg_gen_st_ptr(ptr, cpu_env, offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env)); tcg_temp_free_ptr(ptr); - tcg_ctx->plugin_insn->mem_helper = false; } static void plugin_gen_tb_udata(const struct qemu_plugin_tb *ptb, @@ -682,14 +691,14 @@ static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb, inject_inline_cb(cbs, begin_op, op_rw); } -static void plugin_gen_enable_mem_helper(const struct qemu_plugin_tb *ptb, +static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb, TCGOp *begin_op, int insn_idx) { struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx); - inject_mem_enable_helper(insn, begin_op); + inject_mem_enable_helper(ptb, insn, begin_op); } -static void plugin_gen_disable_mem_helper(const struct qemu_plugin_tb *ptb, +static void plugin_gen_disable_mem_helper(struct qemu_plugin_tb *ptb, TCGOp *begin_op, int insn_idx) { struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx); @@ -750,7 +759,7 @@ static void pr_ops(void) #endif } -static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb) +static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb) { TCGOp *op; int insn_idx = -1; @@ -870,6 +879,7 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db, ptb->haddr1 = db->host_addr[0]; ptb->haddr2 = NULL; ptb->mem_only = mem_only; + ptb->mem_helper = false; plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB); } diff --git a/accel/tcg/plugin-helpers.h b/accel/tcg/plugin-helpers.h index 9829abe4a9..8e685e0654 100644 --- a/accel/tcg/plugin-helpers.h +++ b/accel/tcg/plugin-helpers.h @@ -1,4 +1,4 @@ #ifdef CONFIG_PLUGIN -DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb, TCG_CALL_NO_RWG, void, i32, ptr) -DEF_HELPER_FLAGS_4(plugin_vcpu_mem_cb, TCG_CALL_NO_RWG, void, i32, i32, i64, ptr) +DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, ptr) +DEF_HELPER_FLAGS_4(plugin_vcpu_mem_cb, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, i32, i64, ptr) #endif diff --git a/accel/tcg/tb-jmp-cache.h b/accel/tcg/tb-jmp-cache.h index ff5ffc8fc2..b3f6e78835 100644 --- a/accel/tcg/tb-jmp-cache.h +++ b/accel/tcg/tb-jmp-cache.h @@ -18,6 +18,7 @@ * a load_acquire/store_release to 'tb'. */ struct CPUJumpCache { + struct rcu_head rcu; struct { TranslationBlock *tb; #if TARGET_TB_PCREL diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 061519691f..ef5193c67e 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -100,19 +100,24 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns, ops->translate_insn(db, cpu); } - /* Stop translation if translate_insn so indicated. */ - if (db->is_jmp != DISAS_NEXT) { - break; - } - /* * We can't instrument after instructions that change control * flow although this only really affects post-load operations. + * + * Calling plugin_gen_insn_end() before we possibly stop translation + * is important. Even if this ends up as dead code, plugin generation + * needs to see a matching plugin_gen_insn_{start,end}() pair in order + * to accurately track instrumented helpers that might access memory. */ if (plugin_enabled) { plugin_gen_insn_end(); } + /* Stop translation if translate_insn so indicated. */ + if (db->is_jmp != DISAS_NEXT) { + break; + } + /* Stop translation if the output buffer is full, or we have executed all of the allowed instructions. */ if (tcg_op_buf_full() || db->num_insns >= db->max_insns) { diff --git a/audio/audio.c b/audio/audio.c index d849a94a81..4290309d18 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -28,8 +28,10 @@ #include "monitor/monitor.h" #include "qemu/timer.h" #include "qapi/error.h" +#include "qapi/clone-visitor.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qapi-visit-audio.h" +#include "qapi/qapi-commands-audio.h" #include "qemu/cutils.h" #include "qemu/module.h" #include "qemu/help_option.h" @@ -2046,16 +2048,36 @@ void audio_create_pdos(Audiodev *dev) break CASE(NONE, none, ); +#ifdef CONFIG_AUDIO_ALSA CASE(ALSA, alsa, Alsa); +#endif +#ifdef CONFIG_AUDIO_COREAUDIO CASE(COREAUDIO, coreaudio, Coreaudio); +#endif +#ifdef CONFIG_DBUS_DISPLAY CASE(DBUS, dbus, ); +#endif +#ifdef CONFIG_AUDIO_DSOUND CASE(DSOUND, dsound, ); +#endif +#ifdef CONFIG_AUDIO_JACK CASE(JACK, jack, Jack); +#endif +#ifdef CONFIG_AUDIO_OSS CASE(OSS, oss, Oss); +#endif +#ifdef CONFIG_AUDIO_PA CASE(PA, pa, Pa); +#endif +#ifdef CONFIG_AUDIO_SDL CASE(SDL, sdl, Sdl); +#endif +#ifdef CONFIG_AUDIO_SNDIO CASE(SNDIO, sndio, ); +#endif +#ifdef CONFIG_SPICE CASE(SPICE, spice, ); +#endif CASE(WAV, wav, ); case AUDIODEV_DRIVER__MAX: @@ -2311,3 +2333,13 @@ size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info, return bytes; } + +AudiodevList *qmp_query_audiodevs(Error **errp) +{ + AudiodevList *ret = NULL; + AudiodevListEntry *e; + QSIMPLEQ_FOREACH(e, &audiodevs, next) { + QAPI_LIST_PREPEND(ret, QAPI_CLONE(Audiodev, e->dev)); + } + return ret; +} diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c index 18a89ffffb..b848001ff7 100644 --- a/audio/audio_legacy.c +++ b/audio/audio_legacy.c @@ -90,6 +90,7 @@ static void get_fmt(const char *env, AudioFormat *dst, bool *has_dst) } +#if defined(CONFIG_AUDIO_ALSA) || defined(CONFIG_AUDIO_DSOUND) static void get_millis_to_usecs(const char *env, uint32_t *dst, bool *has_dst) { const char *val = getenv(env); @@ -98,15 +99,20 @@ static void get_millis_to_usecs(const char *env, uint32_t *dst, bool *has_dst) *has_dst = true; } } +#endif +#if defined(CONFIG_AUDIO_ALSA) || defined(CONFIG_AUDIO_COREAUDIO) || \ + defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) || \ + defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) static uint32_t frames_to_usecs(uint32_t frames, AudiodevPerDirectionOptions *pdo) { uint32_t freq = pdo->has_frequency ? pdo->frequency : 44100; return (frames * 1000000 + freq / 2) / freq; } +#endif - +#ifdef CONFIG_AUDIO_COREAUDIO static void get_frames_to_usecs(const char *env, uint32_t *dst, bool *has_dst, AudiodevPerDirectionOptions *pdo) { @@ -116,14 +122,19 @@ static void get_frames_to_usecs(const char *env, uint32_t *dst, bool *has_dst, *has_dst = true; } } +#endif +#if defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) || \ + defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) static uint32_t samples_to_usecs(uint32_t samples, AudiodevPerDirectionOptions *pdo) { uint32_t channels = pdo->has_channels ? pdo->channels : 2; return frames_to_usecs(samples / channels, pdo); } +#endif +#if defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst, AudiodevPerDirectionOptions *pdo) { @@ -133,7 +144,9 @@ static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst, *has_dst = true; } } +#endif +#if defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS) static uint32_t bytes_to_usecs(uint32_t bytes, AudiodevPerDirectionOptions *pdo) { AudioFormat fmt = pdo->has_format ? pdo->format : AUDIO_FORMAT_S16; @@ -150,8 +163,11 @@ static void get_bytes_to_usecs(const char *env, uint32_t *dst, bool *has_dst, *has_dst = true; } } +#endif /* backend specific functions */ + +#ifdef CONFIG_AUDIO_ALSA /* ALSA */ static void handle_alsa_per_direction( AudiodevAlsaPerDirectionOptions *apdo, const char *prefix) @@ -197,7 +213,9 @@ static void handle_alsa(Audiodev *dev) get_millis_to_usecs("QEMU_ALSA_THRESHOLD", &aopt->threshold, &aopt->has_threshold); } +#endif +#ifdef CONFIG_AUDIO_COREAUDIO /* coreaudio */ static void handle_coreaudio(Audiodev *dev) { @@ -210,7 +228,9 @@ static void handle_coreaudio(Audiodev *dev) &dev->u.coreaudio.out->buffer_count, &dev->u.coreaudio.out->has_buffer_count); } +#endif +#ifdef CONFIG_AUDIO_DSOUND /* dsound */ static void handle_dsound(Audiodev *dev) { @@ -225,7 +245,9 @@ static void handle_dsound(Audiodev *dev) &dev->u.dsound.in->has_buffer_length, dev->u.dsound.in); } +#endif +#ifdef CONFIG_AUDIO_OSS /* OSS */ static void handle_oss_per_direction( AudiodevOssPerDirectionOptions *opdo, const char *try_poll_env, @@ -253,7 +275,9 @@ static void handle_oss(Audiodev *dev) get_bool("QEMU_OSS_EXCLUSIVE", &oopt->exclusive, &oopt->has_exclusive); get_int("QEMU_OSS_POLICY", &oopt->dsp_policy, &oopt->has_dsp_policy); } +#endif +#ifdef CONFIG_AUDIO_PA /* pulseaudio */ static void handle_pa_per_direction( AudiodevPaPerDirectionOptions *ppdo, const char *env) @@ -277,7 +301,9 @@ static void handle_pa(Audiodev *dev) get_str("QEMU_PA_SERVER", &dev->u.pa.server); } +#endif +#ifdef CONFIG_AUDIO_SDL /* SDL */ static void handle_sdl(Audiodev *dev) { @@ -286,6 +312,7 @@ static void handle_sdl(Audiodev *dev) &dev->u.sdl.out->has_buffer_length, qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.out)); } +#endif /* wav */ static void handle_wav(Audiodev *dev) @@ -345,29 +372,41 @@ static AudiodevListEntry *legacy_opt(const char *drvname) } switch (e->dev->driver) { +#ifdef CONFIG_AUDIO_ALSA case AUDIODEV_DRIVER_ALSA: handle_alsa(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_COREAUDIO case AUDIODEV_DRIVER_COREAUDIO: handle_coreaudio(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_DSOUND case AUDIODEV_DRIVER_DSOUND: handle_dsound(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_OSS case AUDIODEV_DRIVER_OSS: handle_oss(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_PA case AUDIODEV_DRIVER_PA: handle_pa(e->dev); break; +#endif +#ifdef CONFIG_AUDIO_SDL case AUDIODEV_DRIVER_SDL: handle_sdl(e->dev); break; +#endif case AUDIODEV_DRIVER_WAV: handle_wav(e->dev); diff --git a/audio/audio_template.h b/audio/audio_template.h index 720a32e57e..42b4712acb 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -326,27 +326,47 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev) switch (dev->driver) { case AUDIODEV_DRIVER_NONE: return dev->u.none.TYPE; +#ifdef CONFIG_AUDIO_ALSA case AUDIODEV_DRIVER_ALSA: return qapi_AudiodevAlsaPerDirectionOptions_base(dev->u.alsa.TYPE); +#endif +#ifdef CONFIG_AUDIO_COREAUDIO case AUDIODEV_DRIVER_COREAUDIO: return qapi_AudiodevCoreaudioPerDirectionOptions_base( dev->u.coreaudio.TYPE); +#endif +#ifdef CONFIG_DBUS_DISPLAY case AUDIODEV_DRIVER_DBUS: return dev->u.dbus.TYPE; +#endif +#ifdef CONFIG_AUDIO_DSOUND case AUDIODEV_DRIVER_DSOUND: return dev->u.dsound.TYPE; +#endif +#ifdef CONFIG_AUDIO_JACK case AUDIODEV_DRIVER_JACK: return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE); +#endif +#ifdef CONFIG_AUDIO_OSS case AUDIODEV_DRIVER_OSS: return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE); +#endif +#ifdef CONFIG_AUDIO_PA case AUDIODEV_DRIVER_PA: return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE); +#endif +#ifdef CONFIG_AUDIO_SDL case AUDIODEV_DRIVER_SDL: return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE); +#endif +#ifdef CONFIG_AUDIO_SNDIO case AUDIODEV_DRIVER_SNDIO: return dev->u.sndio.TYPE; +#endif +#ifdef CONFIG_SPICE case AUDIODEV_DRIVER_SPICE: return dev->u.spice.TYPE; +#endif case AUDIODEV_DRIVER_WAV: return dev->u.wav.TYPE; diff --git a/block/blkio.c b/block/blkio.c index 5eae3adfaf..6ad86b23d1 100644 --- a/block/blkio.c +++ b/block/blkio.c @@ -19,6 +19,8 @@ #include "qemu/module.h" #include "exec/memory.h" /* for ram_block_discard_disable() */ +#include "block/block-io.h" + /* * Keep the QEMU BlockDriver names identical to the libblkio driver names. * Using macros instead of typing out the string literals avoids typos. diff --git a/configs/targets/nios2-softmmu.mak b/configs/targets/nios2-softmmu.mak index 1e93b54cd1..5823fc02c8 100644 --- a/configs/targets/nios2-softmmu.mak +++ b/configs/targets/nios2-softmmu.mak @@ -1,2 +1,3 @@ TARGET_ARCH=nios2 TARGET_ALIGNED_ONLY=y +TARGET_NEED_FDT=y diff --git a/configure b/configure index 9e407ce2e3..64960c6000 100755 --- a/configure +++ b/configure @@ -2483,7 +2483,11 @@ for target in $target_list; do tcg_tests_targets="$tcg_tests_targets $target" fi done -echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> config-host.mak) + +if test "$tcg" = "enabled"; then + echo "TCG_TESTS_TARGETS=$tcg_tests_targets" >> config-host.mak +fi +) if test "$skip_meson" = no; then cross="config-meson.cross.new" diff --git a/cpu.c b/cpu.c index 4a7d865427..21cf809614 100644 --- a/cpu.c +++ b/cpu.c @@ -176,11 +176,20 @@ void cpu_exec_unrealizefn(CPUState *cpu) vmstate_unregister(NULL, &vmstate_cpu_common, cpu); } #endif + + /* Call the plugin hook before clearing cpu->cpu_index in cpu_list_remove */ if (tcg_enabled()) { - tcg_exec_unrealizefn(cpu); + qemu_plugin_vcpu_exit_hook(cpu); } cpu_list_remove(cpu); + /* + * Now that the vCPU has been removed from the RCU list, we can call + * tcg_exec_unrealizefn, which may free fields using call_rcu. + */ + if (tcg_enabled()) { + tcg_exec_unrealizefn(cpu); + } } /* diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 9f1bbc495d..da2e6fe63d 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -87,18 +87,18 @@ as short-form boolean values, and passed to plugins as ``arg_name=on``. However, short-form booleans are deprecated and full explicit ``arg_name=on`` form is preferred. -``-drive if=none`` for the sifive_u OTP device (since 6.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Using ``-drive if=none`` to configure the OTP device of the sifive_u -RISC-V machine is deprecated. Use ``-drive if=pflash`` instead. - ``-no-hpet`` (since 8.0) '''''''''''''''''''''''' The HPET setting has been turned into a machine property. Use ``-machine hpet=off`` instead. +``-accel hax`` (since 8.0) +'''''''''''''''''''''''''' + +The HAXM project has been retired (see https://github.com/intel/haxm#status). +Use "whpx" (on Windows) or "hvf" (on macOS) instead. + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst new file mode 100644 index 0000000000..b510a54418 --- /dev/null +++ b/docs/about/emulation.rst @@ -0,0 +1,190 @@ +Emulation +========= + +QEMU's Tiny Code Generator (TCG) provides the ability to emulate a +number of CPU architectures on any supported host platform. Both +:ref:`System Emulation` and :ref:`User Mode Emulation` are supported +depending on the guest architecture. + +.. list-table:: Supported Guest Architectures for Emulation + :widths: 30 10 10 50 + :header-rows: 1 + + * - Architecture (qemu name) + - System + - User + - Notes + * - Alpha + - Yes + - Yes + - Legacy 64 bit RISC ISA developed by DEC + * - Arm (arm, aarch64) + - :ref:`Yes<ARM-System-emulator>` + - Yes + - Wide range of features, see :ref:`Arm Emulation` for details + * - AVR + - :ref:`Yes<AVR-System-emulator>` + - No + - 8 bit micro controller, often used in maker projects + * - Cris + - Yes + - Yes + - Embedded RISC chip developed by AXIS + * - Hexagon + - No + - Yes + - Family of DSPs by Qualcomm + * - PA-RISC (hppa) + - Yes + - Yes + - A legacy RISC system used in HP's old minicomputers + * - x86 (i386, x86_64) + - :ref:`Yes<QEMU-PC-System-emulator>` + - Yes + - The ubiquitous desktop PC CPU architecture, 32 and 64 bit. + * - Loongarch + - Yes + - Yes + - A MIPS-like 64bit RISC architecture developed in China + * - m68k + - :ref:`Yes<ColdFire-System-emulator>` + - Yes + - Motorola 68000 variants and ColdFire + * - Microblaze + - Yes + - Yes + - RISC based soft-core by Xilinx + * - MIPS (mips*) + - :ref:`Yes<MIPS-System-emulator>` + - Yes + - Venerable RISC architecture originally out of Stanford University + * - Nios2 + - Yes + - Yes + - 32 bit embedded soft-core by Altera + * - OpenRISC + - :ref:`Yes<OpenRISC-System-emulator>` + - Yes + - Open source RISC architecture developed by the OpenRISC community + * - Power (ppc, ppc64) + - :ref:`Yes<PowerPC-System-emulator>` + - Yes + - A general purpose RISC architecture now managed by IBM + * - RISC-V + - :ref:`Yes<RISC-V-System-emulator>` + - Yes + - An open standard RISC ISA maintained by RISC-V International + * - RX + - :ref:`Yes<RX-System-emulator>` + - No + - A 32 bit micro controller developed by Renesas + * - s390x + - :ref:`Yes<s390x-System-emulator>` + - Yes + - A 64 bit CPU found in IBM's System Z mainframes + * - sh4 + - Yes + - Yes + - A 32 bit RISC embedded CPU developed by Hitachi + * - SPARC (sparc, sparc64) + - :ref:`Yes<Sparc32-System-emulator>` + - Yes + - A RISC ISA originally developed by Sun Microsystems + * - Tricore + - Yes + - No + - A 32 bit RISC/uController/DSP developed by Infineon + * - Xtensa + - :ref:`Yes<Xtensa-System-emulator>` + - Yes + - A configurable 32 bit soft core now owned by Cadence + +A number of features are are only available when running under +emulation including :ref:`Record/Replay<replay>` and :ref:`TCG Plugins`. + +.. _Semihosting: + +Semihosting +----------- + +Semihosting is a feature defined by the owner of the architecture to +allow programs to interact with a debugging host system. On real +hardware this is usually provided by an In-circuit emulator (ICE) +hooked directly to the board. QEMU's implementation allows for +semihosting calls to be passed to the host system or via the +``gdbstub``. + +Generally semihosting makes it easier to bring up low level code before a +more fully functional operating system has been enabled. On QEMU it +also allows for embedded micro-controller code which typically doesn't +have a full libc to be run as "bare-metal" code under QEMU's user-mode +emulation. It is also useful for writing test cases and indeed a +number of compiler suites as well as QEMU itself use semihosting calls +to exit test code while reporting the success state. + +Semihosting is only available using TCG emulation. This is because the +instructions to trigger a semihosting call are typically reserved +causing most hypervisors to trap and fault on them. + +.. warning:: + Semihosting inherently bypasses any isolation there may be between + the guest and the host. As a result a program using semihosting can + happily trash your host system. You should only ever run trusted + code with semihosting enabled. + +Redirection +~~~~~~~~~~~ + +Semihosting calls can be re-directed to a (potentially remote) gdb +during debugging via the :ref:`gdbstub<GDB usage>`. Output to the +semihosting console is configured as a ``chardev`` so can be +redirected to a file, pipe or socket like any other ``chardev`` +device. + +Supported Targets +~~~~~~~~~~~~~~~~~ + +Most targets offer similar semihosting implementations with some +minor changes to define the appropriate instruction to encode the +semihosting call and which registers hold the parameters. They tend to +presents a simple POSIX-like API which allows your program to read and +write files, access the console and some other basic interactions. + +For full details of the ABI for a particular target, and the set of +calls it provides, you should consult the semihosting specification +for that architecture. + +.. note:: + QEMU makes an implementation decision to implement all file + access in ``O_BINARY`` mode. The user-visible effect of this is + regardless of the text/binary mode the program sets QEMU will + always select a binary mode ensuring no line-terminator conversion + is performed on input or output. This is because gdb semihosting + support doesn't make the distinction between the modes and + magically processing line endings can be confusing. + +.. list-table:: Guest Architectures supporting Semihosting + :widths: 10 10 80 + :header-rows: 1 + + * - Architecture + - Modes + - Specification + * - Arm + - System and User-mode + - https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst + * - m68k + - System + - https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=libgloss/m68k/m68k-semi.txt;hb=HEAD + * - MIPS + - System + - Unified Hosting Interface (MD01069) + * - Nios II + - System + - https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=libgloss/nios2/nios2-semi.txt;hb=HEAD + * - RISC-V + - System and User-mode + - https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc + * - Xtensa + - System + - Tensilica ISS SIMCALL diff --git a/docs/about/index.rst b/docs/about/index.rst index 5bea653c07..b00b584b31 100644 --- a/docs/about/index.rst +++ b/docs/about/index.rst @@ -5,24 +5,25 @@ About QEMU QEMU is a generic and open source machine emulator and virtualizer. QEMU can be used in several different ways. The most common is for -"system emulation", where it provides a virtual model of an +:ref:`System Emulation`, where it provides a virtual model of an entire machine (CPU, memory and emulated devices) to run a guest OS. -In this mode the CPU may be fully emulated, or it may work with -a hypervisor such as KVM, Xen, Hax or Hypervisor.Framework to -allow the guest to run directly on the host CPU. +In this mode the CPU may be fully emulated, or it may work with a +hypervisor such as KVM, Xen, Hax or Hypervisor.Framework to allow the +guest to run directly on the host CPU. -The second supported way to use QEMU is "user mode emulation", +The second supported way to use QEMU is :ref:`User Mode Emulation`, where QEMU can launch processes compiled for one CPU on another CPU. In this mode the CPU is always emulated. -QEMU also provides a number of standalone commandline utilities, -such as the ``qemu-img`` disk image utility that allows you to create, -convert and modify disk images. +QEMU also provides a number of standalone :ref:`command line +utilities<Tools>`, such as the ``qemu-img`` disk image utility that +allows you to create, convert and modify disk images. .. toctree:: :maxdepth: 2 build-platforms + emulation deprecated removed-features license diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 6c3aa5097f..a17d0554d6 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -422,6 +422,13 @@ the value is hexadecimal. That is, '0x20M' should be written either as ``tty`` and ``parport`` used to be aliases for ``serial`` and ``parallel`` respectively. The actual backend names should be used instead. +``-drive if=none`` for the sifive_u OTP device (removed in 8.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Use ``-drive if=pflash`` to configure the OTP device of the sifive_u +RISC-V machine instead. + + QEMU Machine Protocol (QMP) commands ------------------------------------ diff --git a/docs/conf.py b/docs/conf.py index e33cf3d381..73a287a4f2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -297,19 +297,6 @@ man_pages = [ ] man_make_section_directory = False -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'QEMU', u'QEMU Documentation', - author, 'QEMU', 'One line description of project.', - 'Miscellaneous'), -] - - - # We use paths starting from qemu_docdir here so that you can run # sphinx-build from anywhere and the kerneldoc extension can still # find everything. diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst index 9740a70406..81dcd43a61 100644 --- a/docs/devel/tcg-plugins.rst +++ b/docs/devel/tcg-plugins.rst @@ -3,6 +3,8 @@ Copyright (c) 2019, Linaro Limited Written by Emilio Cota and Alex Bennée +.. _TCG Plugins: + QEMU TCG Plugins ================ diff --git a/docs/interop/live-block-operations.rst b/docs/interop/live-block-operations.rst index 135784ab33..691429c7af 100644 --- a/docs/interop/live-block-operations.rst +++ b/docs/interop/live-block-operations.rst @@ -4,6 +4,8 @@ This work is licensed under the terms of the GNU GPL, version 2 or later. See the COPYING file in the top-level directory. +.. _Live Block Operations: + ============================ Live Block Device Operations ============================ diff --git a/docs/interop/qemu-qmp-ref.rst b/docs/interop/qemu-qmp-ref.rst index 357effd64f..f94614a0b2 100644 --- a/docs/interop/qemu-qmp-ref.rst +++ b/docs/interop/qemu-qmp-ref.rst @@ -1,3 +1,5 @@ +.. _QMP Ref: + QEMU QMP Reference Manual ========================= diff --git a/docs/pcie.txt b/docs/pcie.txt index 89e3502075..df49178311 100644 --- a/docs/pcie.txt +++ b/docs/pcie.txt @@ -48,8 +48,8 @@ Place only the following kinds of devices directly on the Root Complex: strangely when PCI Express devices are integrated with the Root Complex. - (2) PCI Express Root Ports (ioh3420), for starting exclusively PCI Express - hierarchies. + (2) PCI Express Root Ports (pcie-root-port), for starting exclusively + PCI Express hierarchies. (3) PCI Express to PCI Bridge (pcie-pci-bridge), for starting legacy PCI hierarchies. @@ -70,7 +70,7 @@ Place only the following kinds of devices directly on the Root Complex: -device pxb-pcie,id=pcie.1,bus_nr=x[,numa_node=y][,addr=z] PCI Express Root Ports and PCI Express to PCI bridges can be connected to the pcie.1 bus: - -device ioh3420,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \ + -device pcie-root-port,id=root_port1[,bus=pcie.1][,chassis=x][,slot=y][,addr=z] \ -device pcie-pci-bridge,id=pcie_pci_bridge1,bus=pcie.1 @@ -112,14 +112,14 @@ Plug only PCI Express devices into PCI Express Ports. ------------ 2.2.1 Plugging a PCI Express device into a PCI Express Root Port: - -device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ + -device pcie-root-port,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ -device <dev>,bus=root_port1 2.2.2 Using multi-function PCI Express Root Ports: - -device ioh3420,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \ - -device ioh3420,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \ - -device ioh3420,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \ + -device pcie-root-port,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \ + -device pcie-root-port,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \ + -device pcie-root-port,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \ 2.2.3 Plugging a PCI Express device into a Switch: - -device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ + -device pcie-root-port,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \ -device x3130-upstream,id=upstream_port1,bus=root_port1[,addr=x] \ -device xio3130-downstream,id=downstream_port1,bus=upstream_port1,chassis=x1,slot=y1[,addr=z1]] \ -device <dev>,bus=downstream_port1 diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index b33d7c28dc..b87e064d9d 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -1,3 +1,5 @@ +.. _Arm Emulation: + A-profile CPU architecture support ================================== diff --git a/docs/system/index.rst b/docs/system/index.rst index e3695649c5..3605bbe1ce 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -1,3 +1,5 @@ +.. _System Emulation: + ---------------- System Emulation ---------------- @@ -10,7 +12,7 @@ or Hypervisor.Framework. .. toctree:: :maxdepth: 3 - quickstart + introduction invocation device-emulation keys diff --git a/docs/system/introduction.rst b/docs/system/introduction.rst new file mode 100644 index 0000000000..c8a9fe6c1d --- /dev/null +++ b/docs/system/introduction.rst @@ -0,0 +1,220 @@ +Introduction +============ + +Virtualisation Accelerators +--------------------------- + +QEMU's system emulation provides a virtual model of a machine (CPU, +memory and emulated devices) to run a guest OS. It supports a number +of hypervisors (known as accelerators) as well as a JIT known as the +Tiny Code Generator (TCG) capable of emulating many CPUs. + +.. list-table:: Supported Accelerators + :header-rows: 1 + + * - Accelerator + - Host OS + - Host Architectures + * - KVM + - Linux + - Arm (64 bit only), MIPS, PPC, RISC-V, s390x, x86 + * - Xen + - Linux (as dom0) + - Arm, x86 + * - Intel HAXM (hax) + - Linux, Windows + - x86 + * - Hypervisor Framework (hvf) + - MacOS + - x86 (64 bit only), Arm (64 bit only) + * - Windows Hypervisor Platform (wphx) + - Windows + - x86 + * - NetBSD Virtual Machine Monitor (nvmm) + - NetBSD + - x86 + * - Tiny Code Generator (tcg) + - Linux, other POSIX, Windows, MacOS + - Arm, x86, Loongarch64, MIPS, PPC, s390x, Sparc64 + +Feature Overview +---------------- + +System emulation provides a wide range of device models to emulate +various hardware components you may want to add to your machine. This +includes a wide number of VirtIO devices which are specifically tuned +for efficient operation under virtualisation. Some of the device +emulation can be offloaded from the main QEMU process using either +vhost-user (for VirtIO) or :ref:`Multi-process QEMU`. If the platform +supports it QEMU also supports directly passing devices through to +guest VMs to eliminate the device emulation overhead. See +:ref:`device-emulation` for more details. + +There is a full :ref:`featured block layer<Live Block Operations>` +which allows for construction of complex storage topology which can be +stacked across multiple layers supporting redirection, networking, +snapshots and migration support. + +The flexible ``chardev`` system allows for handling IO from character +like devices using stdio, files, unix sockets and TCP networking. + +QEMU provides a number of management interfaces including a line based +:ref:`Human Monitor Protocol (HMP)<QEMU monitor>` that allows you to +dynamically add and remove devices as well as introspect the system +state. The :ref:`QEMU Monitor Protocol<QMP Ref>` (QMP) is a well +defined, versioned, machine usable API that presents a rich interface +to other tools to create, control and manage Virtual Machines. This is +the interface used by higher level tools interfaces such as `Virt +Manager <https://virt-manager.org/>`_ using the `libvirt framework +<https://libvirt.org>`_. + +For the common accelerators QEMU, supported debugging with its +:ref:`gdbstub<GDB usage>` which allows users to connect GDB and debug +system software images. + +Running +------- + +QEMU provides a rich and complex API which can be overwhelming to +understand. While some architectures can boot something with just a +disk image, those examples elide a lot of details with defaults that +may not be optimal for modern systems. + +For a non-x86 system where we emulate a broad range of machine types, +the command lines are generally more explicit in defining the machine +and boot behaviour. You will find often find example command lines in +the :ref:`system-targets-ref` section of the manual. + +While the project doesn't want to discourage users from using the +command line to launch VMs, we do want to highlight that there are a +number of projects dedicated to providing a more user friendly +experience. Those built around the ``libvirt`` framework can make use +of feature probing to build modern VM images tailored to run on the +hardware you have. + +That said, the general form of a QEMU command line can be expressed +as: + +.. parsed-literal:: + + $ |qemu_system| [machine opts] \\ + [cpu opts] \\ + [accelerator opts] \\ + [device opts] \\ + [backend opts] \\ + [interface opts] \\ + [boot opts] + +Most options will generate some help information. So for example: + +.. parsed-literal:: + + $ |qemu_system| -M help + +will list the machine types supported by that QEMU binary. ``help`` +can also be passed as an argument to another option. For example: + +.. parsed-literal:: + + $ |qemu_system| -device scsi-hd,help + +will list the arguments and their default values of additional options +that can control the behaviour of the ``scsi-hd`` device. + +.. list-table:: Options Overview + :header-rows: 1 + :widths: 10, 90 + + * - Options + - + * - Machine + - Define the machine type, amount of memory etc + * - CPU + - Type and number/topology of vCPUs. Most accelerators offer + a ``host`` cpu option which simply passes through your host CPU + configuration without filtering out any features. + * - Accelerator + - This will depend on the hypervisor you run. Note that the + default is TCG, which is purely emulated, so you must specify an + accelerator type to take advantage of hardware virtualization. + * - Devices + - Additional devices that are not defined by default with the + machine type. + * - Backends + - Backends are how QEMU deals with the guest's data, for example + how a block device is stored, how network devices see the + network or how a serial device is directed to the outside world. + * - Interfaces + - How the system is displayed, how it is managed and controlled or + debugged. + * - Boot + - How the system boots, via firmware or direct kernel boot. + +In the following example we first define a ``virt`` machine which is a +general purpose platform for running Aarch64 guests. We enable +virtualisation so we can use KVM inside the emulated guest. As the +``virt`` machine comes with some built in pflash devices we give them +names so we can override the defaults later. + +.. code:: + + $ qemu-system-aarch64 \ + -machine type=virt,virtualization=on,pflash0=rom,pflash1=efivars \ + -m 4096 \ + +We then define the 4 vCPUs using the ``max`` option which gives us all +the Arm features QEMU is capable of emulating. We enable a more +emulation friendly implementation of Arm's pointer authentication +algorithm. We explicitly specify TCG acceleration even though QEMU +would default to it anyway. + +.. code:: + + -cpu max,pauth-impdef=on \ + -smp 4 \ + -accel tcg \ + +As the ``virt`` platform doesn't have any default network or storage +devices we need to define them. We give them ids so we can link them +with the backend later on. + +.. code:: + + -device virtio-net-pci,netdev=unet \ + -device virtio-scsi-pci \ + -device scsi-hd,drive=hd \ + +We connect the user-mode networking to our network device. As +user-mode networking isn't directly accessible from the outside world +we forward localhost port 2222 to the ssh port on the guest. + +.. code:: + + -netdev user,id=unet,hostfwd=tcp::2222-:22 \ + +We connect the guest visible block device to an LVM partition we have +set aside for our guest. + +.. code:: + + -blockdev driver=raw,node-name=hd,file.driver=host_device,file.filename=/dev/lvm-disk/debian-bullseye-arm64 \ + +We then tell QEMU to multiplex the :ref:`QEMU monitor` with the serial +port output (we can switch between the two using :ref:`keys in the +character backend multiplexer`). As there is no default graphical +device we disable the display as we can work entirely in the terminal. + +.. code:: + + -serial mon:stdio \ + -display none \ + +Finally we override the default firmware to ensure we have some +storage for EFI to persist its configuration. That firmware is +responsible for finding the disk, booting grub and eventually running +our system. + +.. code:: + + -blockdev node-name=rom,driver=file,filename=(pwd)/pc-bios/edk2-aarch64-code.fd,read-only=true \ + -blockdev node-name=efivars,driver=file,filename=$HOME/images/qemu-arm64-efivars diff --git a/docs/system/multi-process.rst b/docs/system/multi-process.rst index 210531ee17..16f0352416 100644 --- a/docs/system/multi-process.rst +++ b/docs/system/multi-process.rst @@ -1,3 +1,5 @@ +.. _Multi-process QEMU: + Multi-process QEMU ================== diff --git a/docs/system/quickstart.rst b/docs/system/quickstart.rst deleted file mode 100644 index 681678c86e..0000000000 --- a/docs/system/quickstart.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _pcsys_005fquickstart: - -Quick Start ------------ - -Download and uncompress a PC hard disk image with Linux installed (e.g. -``linux.img``) and type: - -.. parsed-literal:: - - |qemu_system| linux.img - -Linux should boot and give you a prompt. - -Users should be aware the above example elides a lot of the complexity -of setting up a VM with x86_64 specific defaults and assumes the -first non switch argument is a PC compatible disk image with a boot -sector. For a non-x86 system where we emulate a broad range of machine -types, the command lines are generally more explicit in defining the -machine and boot behaviour. You will find more example command lines -in the :ref:`system-targets-ref` section of the manual. diff --git a/docs/system/s390x/pcidevices.rst b/docs/system/s390x/pcidevices.rst new file mode 100644 index 0000000000..628effa2f4 --- /dev/null +++ b/docs/system/s390x/pcidevices.rst @@ -0,0 +1,41 @@ +PCI devices on s390x +==================== + +PCI devices on s390x work differently than on other architectures and need to +be configured in a slightly different way. + +Every PCI device is linked with an additional ``zpci`` device. +While the ``zpci`` device will be autogenerated if not specified, it is +recommended to specify it explicitly so that you can pass s390-specific +PCI configuration. + +For example, in order to pass a PCI device ``0000:00:00.0`` through to the +guest, you would specify:: + + qemu-system-s390x ... \ + -device zpci,uid=1,fid=0,target=hostdev0,id=zpci1 \ + -device vfio-pci,host=0000:00:00.0,id=hostdev0 + +Here, the zpci device is joined with the PCI device via the ``target`` property. + +Note that we don't set bus, slot or function here for the guest as is common in +other PCI implementations. Topology information is not available on s390x, and +the guest will not see any of the bus, slot or function information specified +on the command line. + +Instead, ``uid`` and ``fid`` determine how the device is presented to the guest +operating system. + +In case of Linux, ``uid`` will be used in the ``domain`` part of the PCI +identifier, and ``fid`` identifies the physical slot, i.e.:: + + qemu-system-s390x ... \ + -device zpci,uid=7,fid=8,target=hostdev0,id=zpci1 \ + ... + +will be presented in the guest as:: + + # lspci -v + 0007:00:00.0 ... + Physical Slot: 00000008 + ... diff --git a/docs/system/target-s390x.rst b/docs/system/target-s390x.rst index c636f64113..f6f11433c7 100644 --- a/docs/system/target-s390x.rst +++ b/docs/system/target-s390x.rst @@ -26,6 +26,7 @@ or vfio-ap is also available. s390x/css s390x/3270 s390x/vfio-ccw + s390x/pcidevices Architectural features ====================== diff --git a/docs/tools/index.rst b/docs/tools/index.rst index 1edd5a8054..2151adcf78 100644 --- a/docs/tools/index.rst +++ b/docs/tools/index.rst @@ -1,3 +1,5 @@ +.. _Tools: + ----- Tools ----- diff --git a/docs/user/index.rst b/docs/user/index.rst index 2c4e29f3db..782d27cda2 100644 --- a/docs/user/index.rst +++ b/docs/user/index.rst @@ -1,3 +1,5 @@ +.. _User Mode Emulation: + ------------------- User Mode Emulation ------------------- diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 1f7803fdab..e07d3204eb 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -39,6 +39,10 @@ config ACPI_PCIHP bool depends on ACPI +config ACPI_PCI_BRIDGE + bool + depends on ACPI && PCI && ACPI_PCIHP + config ACPI_HMAT bool depends on ACPI diff --git a/hw/acpi/acpi-x86-stub.c b/hw/acpi/acpi-x86-stub.c index 3df1e090f4..d0d399d26b 100644 --- a/hw/acpi/acpi-x86-stub.c +++ b/hw/acpi/acpi-x86-stub.c @@ -2,9 +2,8 @@ #include "hw/i386/pc.h" #include "hw/i386/acpi-build.h" -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, - bool force_enabled) +void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled) { } diff --git a/hw/acpi/acpi_interface.c b/hw/acpi/acpi_interface.c index c668d361f6..8637ff18fc 100644 --- a/hw/acpi/acpi_interface.c +++ b/hw/acpi/acpi_interface.c @@ -2,6 +2,7 @@ #include "hw/acpi/acpi_dev_interface.h" #include "hw/acpi/acpi_aml_interface.h" #include "qemu/module.h" +#include "qemu/queue.h" void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event) { @@ -12,6 +13,15 @@ void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event) } } +void qbus_build_aml(BusState *bus, Aml *scope) +{ + BusChild *kid; + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + call_dev_aml_func(DEVICE(kid->child), scope); + } +} + static void register_types(void) { static const TypeInfo acpi_dev_if_info = { diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index 4e580959a2..19c154d78f 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -355,7 +355,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root); Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); - AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); cpu_ctrl_dev = aml_device("%s", cphp_res_path); { @@ -666,7 +665,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, /* build _MAT object */ assert(adevc && adevc->madt_cpu); - adevc->madt_cpu(adev, i, arch_ids, madt_buf, + adevc->madt_cpu(i, arch_ids, madt_buf, true); /* set enabled flag */ aml_append(dev, aml_name_decl("_MAT", aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data))); diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 30054a8cdc..50b73129b4 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -19,6 +19,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device acpi_ss.add(when: 'CONFIG_ACPI_HMAT', if_true: files('hmat.c')) acpi_ss.add(when: 'CONFIG_ACPI_APEI', if_true: files('ghes.c'), if_false: files('ghes-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_PIIX4', if_true: files('piix4.c')) +acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c')) @@ -30,9 +31,10 @@ if have_tpm acpi_ss.add(files('tpm.c')) endif softmmu_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c')) +softmmu_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-stub.c')) softmmu_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c', 'aml-build-stub.c', 'acpi-x86-stub.c', 'ipmi-stub.c', 'ghes-stub.c', 'acpi-mem-hotplug-stub.c', 'acpi-cpu-hotplug-stub.c', 'acpi-pci-hotplug-stub.c', 'acpi-nvdimm-stub.c', - 'cxl-stub.c')) + 'cxl-stub.c', 'pci-bridge-stub.c')) diff --git a/hw/acpi/pci-bridge-stub.c b/hw/acpi/pci-bridge-stub.c new file mode 100644 index 0000000000..9d78638c48 --- /dev/null +++ b/hw/acpi/pci-bridge-stub.c @@ -0,0 +1,20 @@ +/* + * QEMU ACPI PCI bridge stub + * + * Copyright (c) 2023 Red Hat, Inc. + * + * Author: + * Igor Mammedov <imammedo@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/acpi/pci.h" + +void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope) +{ +} diff --git a/hw/acpi/pci-bridge.c b/hw/acpi/pci-bridge.c new file mode 100644 index 0000000000..5f3ee5157f --- /dev/null +++ b/hw/acpi/pci-bridge.c @@ -0,0 +1,27 @@ +/* + * QEMU ACPI PCI bridge + * + * Copyright (c) 2023 Red Hat, Inc. + * + * Author: + * Igor Mammedov <imammedo@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/acpi/pci.h" +#include "hw/pci/pci_bridge.h" +#include "hw/acpi/pcihp.h" + +void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope) +{ + PCIBridge *br = PCI_BRIDGE(adev); + + if (object_property_find(OBJECT(&br->sec_bus), ACPI_PCIHP_PROP_BSEL)) { + build_append_pci_bus_devices(scope, pci_bridge_get_sec_bus(br)); + } +} diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index 99a898d9ae..5dc7377411 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -85,31 +85,40 @@ static int acpi_pcihp_get_bsel(PCIBus *bus) } } -/* Assign BSEL property to all buses. In the future, this can be changed - * to only assign to buses that support hotplug. - */ +typedef struct { + unsigned bsel_alloc; + bool has_bridge_hotplug; +} BSELInfo; + +/* Assign BSEL property only to buses that support hotplug. */ static void *acpi_set_bsel(PCIBus *bus, void *opaque) { - unsigned *bsel_alloc = opaque; + BSELInfo *info = opaque; unsigned *bus_bsel; + DeviceState *br = bus->qbus.parent; + bool is_bridge = IS_PCI_BRIDGE(br); + /* hotplugged bridges can't be described in ACPI ignore them */ if (qbus_is_hotpluggable(BUS(bus))) { - bus_bsel = g_malloc(sizeof *bus_bsel); + if (!is_bridge || (!br->hotplugged && info->has_bridge_hotplug)) { + bus_bsel = g_malloc(sizeof *bus_bsel); - *bus_bsel = (*bsel_alloc)++; - object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, - bus_bsel, OBJ_PROP_FLAG_READ); + *bus_bsel = info->bsel_alloc++; + object_property_add_uint32_ptr(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, + bus_bsel, OBJ_PROP_FLAG_READ); + } } - return bsel_alloc; + return info; } -static void acpi_set_pci_info(void) +static void acpi_set_pci_info(bool has_bridge_hotplug) { static bool bsel_is_set; Object *host = acpi_get_i386_pci_host(); PCIBus *bus; - unsigned bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT; + BSELInfo info = { .bsel_alloc = ACPI_PCIHP_BSEL_DEFAULT, + .has_bridge_hotplug = has_bridge_hotplug }; if (bsel_is_set) { return; @@ -123,7 +132,7 @@ static void acpi_set_pci_info(void) bus = PCI_HOST_BRIDGE(host)->bus; if (bus) { /* Scan all PCI buses. Set property to enable acpi based hotplug. */ - pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &bsel_alloc); + pci_for_each_bus_depth_first(bus, acpi_set_bsel, NULL, &info); } } @@ -287,7 +296,7 @@ void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off) if (acpihp_root_off) { acpi_pcihp_disable_root_bus(); } - acpi_set_pci_info(); + acpi_set_pci_info(!s->legacy_piix); acpi_pcihp_update(s); } diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 0a81f1ad93..724294b378 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "hw/i386/pc.h" -#include "hw/southbridge/piix.h" #include "hw/irq.h" #include "hw/isa/apm.h" #include "hw/i2c/pm_smbus.h" @@ -305,7 +304,9 @@ static void piix4_pm_reset(DeviceState *dev) acpi_update_sci(&s->ar, s->irq); pm_io_space_update(s); - acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug); + if (s->use_acpi_hotplug_bridge || s->use_acpi_root_pci_hotplug) { + acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug); + } } static void piix4_pm_powerdown_req(Notifier *n, void *opaque) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 54186f31cb..733c964778 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -535,7 +535,8 @@ static void smmu_base_reset_hold(Object *obj) static Property smmu_dev_properties[] = { DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0), - DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, "PCI", PCIBus *), + DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, + TYPE_PCI_BUS, PCIBus *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 26f965cabc..b28d81737e 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -237,9 +237,6 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) goto fail_aio_context; } - /* Process queued requests before the ones in vring */ - virtio_blk_process_queued_requests(vblk, false); - /* Kick right away to begin processing requests already in vring */ for (i = 0; i < nvqs; i++) { VirtQueue *vq = virtio_get_queue(s->vdev, i); @@ -272,11 +269,6 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) fail_host_notifiers: k->set_guest_notifiers(qbus->parent, nvqs, false); fail_guest_notifiers: - /* - * If we failed to set up the guest notifiers queued requests will be - * processed on the main context. - */ - virtio_blk_process_queued_requests(vblk, false); vblk->dataplane_disabled = true; s->starting = false; vblk->dataplane_started = true; @@ -325,8 +317,13 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev) aio_context_acquire(s->ctx); aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s); - /* Drain and try to switch bs back to the QEMU main loop. If other users - * keep the BlockBackend in the iothread, that's ok */ + /* Wait for virtio_blk_dma_restart_bh() and in flight I/O to complete */ + blk_drain(s->conf->conf.blk); + + /* + * Try to switch bs back to the QEMU main loop. If other users keep the + * BlockBackend in the iothread, that's ok + */ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context(), NULL); aio_context_release(s->ctx); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index f717550fdc..1762517878 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -806,8 +806,10 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) virtio_blk_handle_vq(s, vq); } -void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) +static void virtio_blk_dma_restart_bh(void *opaque) { + VirtIOBlock *s = opaque; + VirtIOBlockReq *req = s->rq; MultiReqBuffer mrb = {}; @@ -834,43 +836,27 @@ void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh) if (mrb.num_reqs) { virtio_blk_submit_multireq(s, &mrb); } - if (is_bh) { - blk_dec_in_flight(s->conf.conf.blk); - } - aio_context_release(blk_get_aio_context(s->conf.conf.blk)); -} - -static void virtio_blk_dma_restart_bh(void *opaque) -{ - VirtIOBlock *s = opaque; - qemu_bh_delete(s->bh); - s->bh = NULL; + /* Paired with inc in virtio_blk_dma_restart_cb() */ + blk_dec_in_flight(s->conf.conf.blk); - virtio_blk_process_queued_requests(s, true); + aio_context_release(blk_get_aio_context(s->conf.conf.blk)); } static void virtio_blk_dma_restart_cb(void *opaque, bool running, RunState state) { VirtIOBlock *s = opaque; - BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); - VirtioBusState *bus = VIRTIO_BUS(qbus); if (!running) { return; } - /* - * If ioeventfd is enabled, don't schedule the BH here as queued - * requests will be processed while starting the data plane. - */ - if (!s->bh && !virtio_bus_ioeventfd_enabled(bus)) { - s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk), - virtio_blk_dma_restart_bh, s); - blk_inc_in_flight(s->conf.conf.blk); - qemu_bh_schedule(s->bh); - } + /* Paired with dec in virtio_blk_dma_restart_bh() */ + blk_inc_in_flight(s->conf.conf.blk); + + aio_bh_schedule_oneshot(blk_get_aio_context(s->conf.conf.blk), + virtio_blk_dma_restart_bh, s); } static void virtio_blk_reset(VirtIODevice *vdev) @@ -1213,7 +1199,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) return; } - s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); + /* + * This must be after virtio_init() so virtio_blk_dma_restart_cb() gets + * called after ->start_ioeventfd() has already set blk's AioContext. + */ + s->change = + qdev_add_vm_change_state_handler(dev, virtio_blk_dma_restart_cb, s); + blk_ram_registrar_init(&s->blk_ram_registrar, s->blk); blk_set_dev_ops(s->blk, &virtio_block_ops, s); diff --git a/hw/core/machine.c b/hw/core/machine.c index 616f3a207c..f7761baab5 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -46,6 +46,7 @@ const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2); GlobalProperty hw_compat_7_1[] = { { "virtio-device", "queue_reset", "false" }, + { "virtio-rng-pci", "vectors", "0" }, }; const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1); diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index ee50ba1f2c..52ba77f3fc 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -97,13 +97,10 @@ static void ich9_smbus_realize(PCIDevice *d, Error **errp) static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope) { - BusChild *kid; ICH9SMBState *s = ICH9_SMB_DEVICE(adev); BusState *bus = BUS(s->smb.smbus); - QTAILQ_FOREACH(kid, &bus->children, sibling) { - call_dev_aml_func(DEVICE(kid->child), scope); - } + qbus_build_aml(bus, scope); } static void ich9_smb_class_init(ObjectClass *klass, void *data) diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index c4fb5b49bd..1bf47b0b0b 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -58,6 +58,7 @@ config PC_ACPI select ACPI_X86 select ACPI_CPU_HOTPLUG select ACPI_MEMORY_HOTPLUG + select ACPI_PCI_BRIDGE select ACPI_VIOT select SMBUS_EEPROM select PFLASH_CFI01 diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 127c4e2d50..145389aa58 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -117,8 +117,6 @@ typedef struct AcpiMiscInfo { #ifdef CONFIG_TPM TPMVersion tpm_version; #endif - const unsigned char *dsdt_code; - unsigned dsdt_size; } AcpiMiscInfo; typedef struct FwCfgTPMConfig { @@ -385,151 +383,185 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot) aml_append(method, if_ctx); } -static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, - bool pcihp_bridge_en) +static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus) { - Aml *dev, *notify_method = NULL, *method; - QObject *bsel; - PCIBus *sec; - int devfn; + const PCIDevice *pdev = bus->devices[devfn]; - bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); - if (bsel) { - uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); + if (PCI_FUNC(devfn)) { + if (IS_PCI_BRIDGE(pdev)) { + /* + * Ignore only hotplugged PCI bridges on !0 functions, but + * allow describing cold plugged bridges on all functions + */ + if (DEVICE(pdev)->hotplugged) { + return true; + } + } else if (!get_dev_aml_func(DEVICE(pdev))) { + /* + * Ignore all other devices on !0 functions unless they + * have AML description (i.e have get_dev_aml_func() != 0) + */ + return true; + } + } + return false; +} - aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); - notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); +static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus) +{ + PCIDevice *pdev = bus->devices[devfn]; + if (pdev) { + return is_devfn_ignored_generic(devfn, bus) || + !DEVICE_GET_CLASS(pdev)->hotpluggable || + /* Cold plugged bridges aren't themselves hot-pluggable */ + (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged); + } else { /* non populated slots */ + /* + * hotplug is supported only for non-multifunction device + * so generate device description only for function 0 + */ + if (PCI_FUNC(devfn) || + (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) { + return true; + } } + return false; +} - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - DeviceClass *dc; - PCIDevice *pdev = bus->devices[devfn]; - int slot = PCI_SLOT(devfn); - int func = PCI_FUNC(devfn); - /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ - int adr = slot << 16 | func; - bool hotpluggbale_slot = false; - bool bridge_in_acpi = false; - bool cold_plugged_bridge = false; +static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus, + QObject *bsel) +{ + int devfn; + Aml *dev, *notify_method = NULL, *method; + uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - if (pdev) { - dc = DEVICE_GET_CLASS(pdev); + aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); + notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); - /* - * Cold plugged bridges aren't themselves hot-pluggable. - * Hotplugged bridges *are* hot-pluggable. - */ - cold_plugged_bridge = IS_PCI_BRIDGE(pdev) && - !DEVICE(pdev)->hotplugged; - bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + int slot = PCI_SLOT(devfn); + int adr = slot << 16 | PCI_FUNC(devfn); - hotpluggbale_slot = bsel && dc->hotpluggable && - !cold_plugged_bridge; + if (is_devfn_ignored_hotplug(devfn, bus)) { + continue; + } - /* - * allow describing coldplugged bridges in ACPI even if they are not - * on function 0, as they are not unpluggable, for all other devices - * generate description only for function 0 per slot, and for other - * functions if device on function provides its own AML - */ - if (func && !bridge_in_acpi && !get_dev_aml_func(DEVICE(pdev))) { - continue; - } + if (bus->devices[devfn]) { + dev = aml_scope("S%.02X", devfn); } else { - /* - * hotplug is supported only for non-multifunction device - * so generate device description only for function 0 - */ - if (bsel && !func) { - if (pci_bus_is_express(bus) && slot > 0) { - break; - } - /* mark it as empty hotpluggable slot */ - hotpluggbale_slot = true; - } else { - continue; - } + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); } - /* start to compose PCI device descriptor */ - dev = aml_device("S%.02X", devfn); - aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); + /* + * Can't declare _SUN here for every device as it changes 'slot' + * enumeration order in linux kernel, so use another variable for it + */ + aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); + aml_append(dev, aml_pci_device_dsm()); - if (bsel) { - /* - * Can't declare _SUN here for every device as it changes 'slot' - * enumeration order in linux kernel, so use another variable for it - */ - aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); - aml_append(dev, aml_pci_device_dsm()); - } + aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); + /* add _EJ0 to make slot hotpluggable */ + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); + aml_append(method, + aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) + ); + aml_append(dev, method); - call_dev_aml_func(DEVICE(pdev), dev); + build_append_pcihp_notify_entry(notify_method, slot); - bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; - if (bridge_in_acpi) { - /* - * device is coldplugged bridge, - * add child device descriptions into its scope - */ - PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); + /* device descriptor has been composed, add it into parent context */ + aml_append(parent_scope, dev); + } + aml_append(parent_scope, notify_method); +} - build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en); - } +void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) +{ + QObject *bsel; + int devfn; + Aml *dev; - if (hotpluggbale_slot) { - aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); - /* add _EJ0 to make slot hotpluggable */ - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - aml_append(method, - aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) - ); - aml_append(dev, method); + bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); - build_append_pcihp_notify_entry(notify_method, slot); + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ + int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn); + PCIDevice *pdev = bus->devices[devfn]; + + if (!pdev || is_devfn_ignored_generic(devfn, bus)) { + continue; } + /* start to compose PCI device descriptor */ + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); + + call_dev_aml_func(DEVICE(bus->devices[devfn]), dev); + /* device descriptor has been composed, add it into parent context */ aml_append(parent_scope, dev); } if (bsel) { - aml_append(parent_scope, notify_method); + build_append_pcihp_slots(parent_scope, bus, bsel); } - /* Append PCNT method to notify about events on local and child buses. - * Add this method for root bus only when hotplug is enabled since DSDT - * expects it. - */ - if (bsel || pcihp_bridge_en) { - method = aml_method("PCNT", 0, AML_NOTSERIALIZED); - - /* If bus supports hotplug select it and notify about local events */ - if (bsel) { - uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - - aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); - aml_append(method, aml_call2("DVNT", aml_name("PCIU"), - aml_int(1))); /* Device Check */ - aml_append(method, aml_call2("DVNT", aml_name("PCID"), - aml_int(3))); /* Eject Request */ + qobject_unref(bsel); +} + +static bool build_append_notfication_callback(Aml *parent_scope, + const PCIBus *bus) +{ + Aml *method; + PCIBus *sec; + QObject *bsel; + int nr_notifiers = 0; + + QLIST_FOREACH(sec, &bus->child, sibling) { + Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn); + if (pci_bus_is_root(sec) || + !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { + continue; } + nr_notifiers = nr_notifiers + + build_append_notfication_callback(br_scope, sec); + aml_append(parent_scope, br_scope); + } - /* Notify about child bus events in any case */ - if (pcihp_bridge_en) { - QLIST_FOREACH(sec, &bus->child, sibling) { - if (pci_bus_is_root(sec)) { - continue; - } + /* + * Append PCNT method to notify about events on local and child buses. + * ps: hostbridge might not have hotplug (bsel) enabled but might have + * child bridges that do have bsel. + */ + method = aml_method("PCNT", 0, AML_NOTSERIALIZED); - aml_append(method, aml_name("^S%.02X.PCNT", - sec->parent_dev->devfn)); - } + /* If bus supports hotplug select it and notify about local events */ + bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); + if (bsel) { + uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); + + aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); + aml_append(method, aml_call2("DVNT", aml_name("PCIU"), + aml_int(1))); /* Device Check */ + aml_append(method, aml_call2("DVNT", aml_name("PCID"), + aml_int(3))); /* Eject Request */ + nr_notifiers++; + } + + /* Notify about child bus events in any case */ + QLIST_FOREACH(sec, &bus->child, sibling) { + if (pci_bus_is_root(sec) || + !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { + continue; } - aml_append(parent_scope, method); + aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn)); } + + aml_append(parent_scope, method); qobject_unref(bsel); + return !!nr_notifiers; } static Aml *aml_pci_pdsm(void) @@ -1678,7 +1710,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; Aml *scope = aml_scope("PCI0"); /* Scan all PCI buses. Generate tables to support hotplug. */ - build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); + build_append_pci_bus_devices(scope, bus); aml_append(sb_scope, scope); } } @@ -1728,13 +1760,26 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { + bool has_pcnt; + + Object *pci_host = acpi_get_i386_pci_host(); + PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; + + scope = aml_scope("\\_SB.PCI0"); + has_pcnt = build_append_notfication_callback(scope, bus); + if (has_pcnt) { + aml_append(dsdt, scope); + } + scope = aml_scope("_GPE"); { method = aml_method("_E01", 0, AML_NOTSERIALIZED); - aml_append(method, - aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); - aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); - aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + if (has_pcnt) { + aml_append(method, + aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); + aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); + aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + } aml_append(scope, method); } aml_append(dsdt, scope); diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 4aaafbdd7b..52e5c1439a 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -33,9 +33,8 @@ #include "acpi-build.h" #include "acpi-common.h" -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, - bool force_enabled) +void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled) { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ @@ -112,7 +111,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ for (i = 0; i < apic_ids->len; i++) { - adevc->madt_cpu(adev, i, apic_ids, table_data, false); + adevc->madt_cpu(i, apic_ids, table_data, false); if (apic_ids->cpus[i].arch_id > 254) { x2apic_mode = true; } diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index fb09185cbd..a075360d85 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -26,6 +26,7 @@ #include "exec/memory.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/generic_event_device.h" @@ -129,7 +130,7 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker, sb_scope = aml_scope("_SB"); fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg); - isa_build_aml(ISA_BUS(isabus), sb_scope); + qbus_build_aml(BUS(isabus), sb_scope); build_ged_aml(sb_scope, GED_DEVICE, x86ms->acpi_dev, GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE); acpi_dsdt_add_power_button(sb_scope); diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 170a331e3f..29f30dd6d3 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -378,7 +378,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) MicrovmMachineState *mms = MICROVM_MACHINE(machine); BusState *bus; BusChild *kid; - char *cmdline; + char *cmdline, *existing_cmdline; + size_t len; /* * Find MMIO transports with attached devices, and add them to the kernel @@ -387,7 +388,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) * Yes, this is a hack, but one that heavily improves the UX without * introducing any significant issues. */ - cmdline = g_strdup(machine->kernel_cmdline); + existing_cmdline = fw_cfg_read_bytes_ptr(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA); + cmdline = g_strdup(existing_cmdline); bus = sysbus_get_default(); QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; @@ -411,9 +413,12 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) } } - fw_cfg_modify_i32(x86ms->fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(cmdline) + 1); - fw_cfg_modify_string(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA, cmdline); - + len = strlen(cmdline); + if (len > VIRTIO_CMDLINE_TOTAL_MAX_LEN + strlen(existing_cmdline)) { + fprintf(stderr, "qemu: virtio mmio cmdline too large, skipping\n"); + } else { + memcpy(existing_cmdline, cmdline, len + 1); + } g_free(cmdline); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 83c57c6eb1..66cd718b70 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -257,8 +257,9 @@ static void pc_q35_init(MachineState *machine) NULL); if (!keep_pci_slot_hpc && acpi_pcihp) { - object_register_sugar_prop(TYPE_PCIE_SLOT, "x-native-hotplug", - "false", true); + object_register_sugar_prop(TYPE_PCIE_SLOT, + "x-do-not-expose-native-hotplug-cap", + "true", true); } /* irq lines */ diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 78cc131926..eaff4227bd 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -50,6 +50,7 @@ #include "hw/intc/i8259.h" #include "hw/rtc/mc146818rtc.h" #include "target/i386/sev.h" +#include "hw/i386/microvm.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/irq.h" @@ -813,12 +814,18 @@ void x86_load_linux(X86MachineState *x86ms, const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; const char *dtb_filename = machine->dtb; - const char *kernel_cmdline = machine->kernel_cmdline; + char *kernel_cmdline; SevKernelLoaderContext sev_load_ctx = {}; enum { RNG_SEED_LENGTH = 32 }; - /* Align to 16 bytes as a paranoia measure */ - cmdline_size = (strlen(kernel_cmdline) + 16) & ~15; + /* + * Add the NUL terminator, some padding for the microvm cmdline fiddling + * hack, and then align to 16 bytes as a paranoia measure + */ + cmdline_size = (strlen(machine->kernel_cmdline) + 1 + + VIRTIO_CMDLINE_TOTAL_MAX_LEN + 16) & ~15; + /* Make a copy, since we might append arbitrary bytes to it later. */ + kernel_cmdline = g_strndup(machine->kernel_cmdline, cmdline_size); /* load the kernel header */ f = fopen(kernel_filename, "rb"); @@ -959,12 +966,6 @@ void x86_load_linux(X86MachineState *x86ms, initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1; } - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); - sev_load_ctx.cmdline_data = (char *)kernel_cmdline; - sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1; - if (protocol >= 0x202) { stl_p(header + 0x228, cmdline_addr); } else { @@ -1091,27 +1092,24 @@ void x86_load_linux(X86MachineState *x86ms, exit(1); } - setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(SetupData) + dtb_size; - kernel = g_realloc(kernel, kernel_size); - - - setup_data = (SetupData *)(kernel + setup_data_offset); + setup_data_offset = cmdline_size; + cmdline_size += sizeof(SetupData) + dtb_size; + kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size); + setup_data = (void *)kernel_cmdline + setup_data_offset; setup_data->next = cpu_to_le64(first_setup_data); - first_setup_data = prot_addr + setup_data_offset; + first_setup_data = cmdline_addr + setup_data_offset; setup_data->type = cpu_to_le32(SETUP_DTB); setup_data->len = cpu_to_le32(dtb_size); - load_image_size(dtb_filename, setup_data->data, dtb_size); } - if (!legacy_no_rng_seed) { - setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(SetupData) + RNG_SEED_LENGTH; - kernel = g_realloc(kernel, kernel_size); - setup_data = (SetupData *)(kernel + setup_data_offset); + if (!legacy_no_rng_seed && protocol >= 0x209) { + setup_data_offset = cmdline_size; + cmdline_size += sizeof(SetupData) + RNG_SEED_LENGTH; + kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size); + setup_data = (void *)kernel_cmdline + setup_data_offset; setup_data->next = cpu_to_le64(first_setup_data); - first_setup_data = prot_addr + setup_data_offset; + first_setup_data = cmdline_addr + setup_data_offset; setup_data->type = cpu_to_le32(SETUP_RNG_SEED); setup_data->len = cpu_to_le32(RNG_SEED_LENGTH); qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH); @@ -1122,6 +1120,12 @@ void x86_load_linux(X86MachineState *x86ms, fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); } + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, cmdline_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline, cmdline_size); + sev_load_ctx.cmdline_data = (char *)kernel_cmdline; + sev_load_ctx.cmdline_size = cmdline_size; + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); sev_load_ctx.kernel_data = (char *)kernel; @@ -1134,7 +1138,7 @@ void x86_load_linux(X86MachineState *x86ms, * kernel on the other side of the fw_cfg interface matches the hash of the * file the user passed in. */ - if (!sev_enabled()) { + if (!sev_enabled() && first_setup_data) { SetupDataFixup *fixup = g_malloc(sizeof(*fixup)); memcpy(setup, header, MIN(sizeof(header), setup_size)); diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 1bee1a47f1..f155b80010 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -24,7 +24,6 @@ #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "hw/isa/isa.h" -#include "hw/acpi/acpi_aml_interface.h" static ISABus *isabus; @@ -188,15 +187,6 @@ ISADevice *isa_vga_init(ISABus *bus) } } -void isa_build_aml(ISABus *bus, Aml *scope) -{ - BusChild *kid; - - QTAILQ_FOREACH(kid, &bus->parent_obj.children, sibling) { - call_dev_aml_func(DEVICE(kid->child), scope); - } -} - static void isabus_bridge_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 8d541e2b54..1fba3c210c 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -813,7 +813,6 @@ static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope) { Aml *field; - BusChild *kid; ICH9LPCState *s = ICH9_LPC_DEVICE(adev); BusState *bus = BUS(s->isa_bus); Aml *sb_scope = aml_scope("\\_SB"); @@ -835,9 +834,7 @@ static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope) aml_append(sb_scope, field); aml_append(scope, sb_scope); - QTAILQ_FOREACH(kid, &bus->children, sibling) { - call_dev_aml_func(DEVICE(kid->child), scope); - } + qbus_build_aml(bus, scope); } static void ich9_lpc_class_init(ObjectClass *klass, void *data) diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index 283b971ec4..a9cb39bf21 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -306,7 +306,6 @@ static void pci_piix3_realize(PCIDevice *dev, Error **errp) static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) { Aml *field; - BusChild *kid; Aml *sb_scope = aml_scope("\\_SB"); BusState *bus = qdev_get_child_bus(DEVICE(adev), "isa.0"); @@ -322,9 +321,7 @@ static void build_pci_isa_aml(AcpiDevAmlIf *adev, Aml *scope) aml_append(sb_scope, field); aml_append(scope, sb_scope); - QTAILQ_FOREACH(kid, &bus->children, sibling) { - call_dev_aml_func(DEVICE(kid->child), scope); - } + qbus_build_aml(bus, scope); } static void pci_piix3_class_init(ObjectClass *klass, void *data) diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index 6d7fdb040a..8965f5c22a 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -210,13 +210,6 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); dinfo = drive_get(IF_PFLASH, 0, 0); - if (!dinfo) { - dinfo = drive_get(IF_NONE, 0, 0); - if (dinfo) { - warn_report("using \"-drive if=none\" for the OTP is deprecated, " - "use \"-drive if=pflash\" instead."); - } - } if (dinfo) { int ret; uint64_t perm; diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index a00881bc64..432754eda4 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -741,6 +741,15 @@ void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) fw_cfg_add_bytes_callback(s, key, NULL, NULL, NULL, data, len, true); } +void *fw_cfg_read_bytes_ptr(FWCfgState *s, uint16_t key) +{ + int arch = !!(key & FW_CFG_ARCH_LOCAL); + + key &= FW_CFG_ENTRY_MASK; + assert(key < fw_cfg_max_entry(s)); + return s->entries[arch][key].data; +} + void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) { size_t sz = strlen(value) + 1; diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index 20099a8ae3..1ce4e7beba 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -87,7 +87,12 @@ static void gen_rp_realize(DeviceState *dev, Error **errp) return; } - if (grp->res_reserve.io == -1 && s->hotplug && !s->native_hotplug) { + /* + * reserving IO space led to worse issues in 6.1, when this hunk was + * introduced. (see commit: 211afe5c69b59). Keep this broken for 6.1 + * machine type ABI compatibility only + */ + if (s->hide_native_hotplug_cap && grp->res_reserve.io == -1 && s->hotplug) { grp->res_reserve.io = GEN_PCIE_ROOT_DEFAULT_IO_RANGE; } int rc = pci_bridge_qemu_reserve_cap_init(d, 0, diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 3435df8d73..4b2696ea7f 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -186,7 +186,6 @@ static Property pci_bridge_dev_properties[] = { res_reserve.mem_pref_32, -1), DEFINE_PROP_SIZE("pref64-reserve", PCIBridgeDev, res_reserve.mem_pref_64, -1), - DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index 8cf318cb80..8e589ff2c9 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -91,7 +91,7 @@ static void grackle_init(Object *obj) static void grackle_pci_realize(PCIDevice *d, Error **errp) { - d->config[0x09] = 0x01; + d->config[PCI_CLASS_PROG] = 0x01; } static void grackle_pci_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c index 5b00b4e462..cdfb62ac2e 100644 --- a/hw/pci-host/raven.c +++ b/hw/pci-host/raven.c @@ -330,9 +330,9 @@ static void raven_realize(PCIDevice *d, Error **errp) char *filename; int bios_size = -1; - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x34] = 0x00; // capabilities_pointer + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; + d->config[PCI_CAPABILITY_LIST] = 0x00; memory_region_init_rom_nomigrate(&s->bios, OBJECT(s), "bios", BIOS_SIZE, &error_fatal); diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index e3abe3c0f9..e4c1abd871 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -276,12 +276,9 @@ static void pci_unin_internal_init(Object *obj) static void unin_main_pci_host_realize(PCIDevice *d, Error **errp) { - /* cache_line_size */ - d->config[0x0C] = 0x08; - /* latency_timer */ - d->config[0x0D] = 0x10; - /* capabilities_pointer */ - d->config[0x34] = 0x00; + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; + d->config[PCI_CAPABILITY_LIST] = 0x00; /* * Set kMacRISCPCIAddressSelect (0x48) register to indicate PCI @@ -296,30 +293,22 @@ static void unin_main_pci_host_realize(PCIDevice *d, Error **errp) static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp) { - /* cache_line_size */ - d->config[0x0C] = 0x08; - /* latency_timer */ - d->config[0x0D] = 0x10; - /* capabilities_pointer - d->config[0x34] = 0x80; */ + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; + /* d->config[PCI_CAPABILITY_LIST] = 0x80; */ } static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp) { - /* cache line size */ - d->config[0x0C] = 0x08; - /* latency timer */ - d->config[0x0D] = 0x10; + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; } static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp) { - /* cache_line_size */ - d->config[0x0C] = 0x08; - /* latency_timer */ - d->config[0x0D] = 0x10; - /* capabilities_pointer */ - d->config[0x34] = 0x00; + d->config[PCI_CACHE_LINE_SIZE] = 0x08; + d->config[PCI_LATENCY_TIMER] = 0x10; + d->config[PCI_CAPABILITY_LIST] = 0x00; } static void unin_main_pci_host_class_init(ObjectClass *klass, void *data) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 39a7bb32aa..208c16f450 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -483,7 +483,7 @@ static void pci_bus_uninit(PCIBus *bus) pci_host_bus_unregister(BUS(bus)->parent); } -bool pci_bus_is_express(PCIBus *bus) +bool pci_bus_is_express(const PCIBus *bus) { return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); } diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index b2b180edd6..dd5af508f9 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -36,6 +36,8 @@ #include "qemu/module.h" #include "qemu/range.h" #include "qapi/error.h" +#include "hw/acpi/acpi_aml_interface.h" +#include "hw/acpi/pci.h" /* PCI bridge subsystem vendor ID helper functions */ #define PCI_SSVID_SIZEOF 8 @@ -467,11 +469,23 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, return 0; } +static void pci_bridge_class_init(ObjectClass *klass, void *data) +{ + AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); + + adevc->build_dev_aml = build_pci_bridge_aml; +} + static const TypeInfo pci_bridge_type_info = { .name = TYPE_PCI_BRIDGE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBridge), + .class_init = pci_bridge_class_init, .abstract = true, + .interfaces = (InterfaceInfo[]) { + { TYPE_ACPI_DEV_AML_IF }, + { }, + }, }; static void pci_bridge_register_types(void) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 68a62da0b5..924fdabd15 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -611,11 +611,11 @@ void pcie_cap_slot_init(PCIDevice *dev, PCIESlot *s) PCI_EXP_SLTCAP_ABP); /* - * Enable native hot-plug on all hot-plugged bridges unless - * hot-plug is disabled on the slot. + * Expose native hot-plug on all bridges if hot-plug is enabled on the slot. + * (unless broken 6.1 ABI is enforced for compat reasons) */ if (s->hotplug && - (s->native_hotplug || DEVICE(dev)->hotplugged)) { + (!s->hide_native_hotplug_cap || DEVICE(dev)->hotplugged)) { pci_long_test_and_set_mask(dev->config + pos + PCI_EXP_SLTCAP, PCI_EXP_SLTCAP_HPS | PCI_EXP_SLTCAP_HPC); diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index 687e4e763a..65a397ad23 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -173,7 +173,8 @@ static Property pcie_slot_props[] = { DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true), - DEFINE_PROP_BOOL("x-native-hotplug", PCIESlot, native_hotplug, true), + DEFINE_PROP_BOOL("x-do-not-expose-native-hotplug-cap", PCIESlot, + hide_native_hotplug_cap, false), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index e71f3a7483..fca7f6691a 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -568,6 +568,13 @@ void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev, state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK); led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK); + + if (led == SHPC_LED_BLINK) { + error_setg(errp, "Hot-unplug failed: " + "guest is busy (power indicator blinking)"); + return; + } + if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) { shpc_free_devices_in_slot(shpc, slot); shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN); diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index d9ce0501b2..e68daa35d4 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -48,7 +48,7 @@ * hardware plaform. */ #if defined(TARGET_X86) || defined(TARGET_X86_64) || \ - defined(TARGET_ARM) || defined(TARGET_ARM_64) + defined(TARGET_ARM) || defined(TARGET_AARCH64) #include "hw/acpi/acpi.h" #define VHOST_USER_MAX_RAM_SLOTS ACPI_MAX_RAM_SLOTS @@ -305,19 +305,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) return 0; } -struct vhost_user_read_cb_data { - struct vhost_dev *dev; - VhostUserMsg *msg; - GMainLoop *loop; - int ret; -}; - -static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, - gpointer opaque) +static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) { - struct vhost_user_read_cb_data *data = opaque; - struct vhost_dev *dev = data->dev; - VhostUserMsg *msg = data->msg; struct vhost_user *u = dev->opaque; CharBackend *chr = u->user->chr; uint8_t *p = (uint8_t *) msg; @@ -325,8 +314,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, r = vhost_user_read_header(dev, msg); if (r < 0) { - data->ret = r; - goto end; + return r; } /* validate message size is sane */ @@ -334,8 +322,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, error_report("Failed to read msg header." " Size %d exceeds the maximum %zu.", msg->hdr.size, VHOST_USER_PAYLOAD_SIZE); - data->ret = -EPROTO; - goto end; + return -EPROTO; } if (msg->hdr.size) { @@ -346,84 +333,11 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, int saved_errno = errno; error_report("Failed to read msg payload." " Read %d instead of %d.", r, msg->hdr.size); - data->ret = r < 0 ? -saved_errno : -EIO; - goto end; + return r < 0 ? -saved_errno : -EIO; } } -end: - g_main_loop_quit(data->loop); - return G_SOURCE_REMOVE; -} - -static gboolean slave_read(QIOChannel *ioc, GIOCondition condition, - gpointer opaque); - -/* - * This updates the read handler to use a new event loop context. - * Event sources are removed from the previous context : this ensures - * that events detected in the previous context are purged. They will - * be re-detected and processed in the new context. - */ -static void slave_update_read_handler(struct vhost_dev *dev, - GMainContext *ctxt) -{ - struct vhost_user *u = dev->opaque; - - if (!u->slave_ioc) { - return; - } - - if (u->slave_src) { - g_source_destroy(u->slave_src); - g_source_unref(u->slave_src); - } - - u->slave_src = qio_channel_add_watch_source(u->slave_ioc, - G_IO_IN | G_IO_HUP, - slave_read, dev, NULL, - ctxt); -} - -static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) -{ - struct vhost_user *u = dev->opaque; - CharBackend *chr = u->user->chr; - GMainContext *prev_ctxt = chr->chr->gcontext; - GMainContext *ctxt = g_main_context_new(); - GMainLoop *loop = g_main_loop_new(ctxt, FALSE); - struct vhost_user_read_cb_data data = { - .dev = dev, - .loop = loop, - .msg = msg, - .ret = 0 - }; - - /* - * We want to be able to monitor the slave channel fd while waiting - * for chr I/O. This requires an event loop, but we can't nest the - * one to which chr is currently attached : its fd handlers might not - * be prepared for re-entrancy. So we create a new one and switch chr - * to use it. - */ - slave_update_read_handler(dev, ctxt); - qemu_chr_be_update_read_handlers(chr->chr, ctxt); - qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data); - - g_main_loop_run(loop); - - /* - * Restore the previous event loop context. This also destroys/recreates - * event sources : this guarantees that all pending events in the original - * context that have been processed by the nested loop are purged. - */ - qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt); - slave_update_read_handler(dev, NULL); - - g_main_loop_unref(loop); - g_main_context_unref(ctxt); - - return data.ret; + return 0; } static int process_message_reply(struct vhost_dev *dev, @@ -459,6 +373,8 @@ static bool vhost_user_one_time_request(VhostUserRequest request) case VHOST_USER_SET_MEM_TABLE: case VHOST_USER_GET_QUEUE_NUM: case VHOST_USER_NET_SET_MTU: + case VHOST_USER_ADD_MEM_REG: + case VHOST_USER_REM_MEM_REG: return true; default: return false; @@ -1807,7 +1723,9 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev) return -ECONNREFUSED; } u->slave_ioc = ioc; - slave_update_read_handler(dev, NULL); + u->slave_src = qio_channel_add_watch_source(u->slave_ioc, + G_IO_IN | G_IO_HUP, + slave_read, dev, NULL, NULL); if (reply_supported) { msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 23c470977e..1cd258135d 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -1366,7 +1366,8 @@ static const VMStateDescription vmstate_virtio_iommu = { }; static Property virtio_iommu_properties[] = { - DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *), + DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, + TYPE_PCI_BUS, PCIBus *), DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/exec/memory.h b/include/exec/memory.h index c37ffdbcd1..2e602a2fad 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -129,6 +129,32 @@ struct IOMMUTLBEntry { /* * Bitmap for different IOMMUNotifier capabilities. Each notifier can * register with one or multiple IOMMU Notifier capability bit(s). + * + * Normally there're two use cases for the notifiers: + * + * (1) When the device needs accurate synchronizations of the vIOMMU page + * tables, it needs to register with both MAP|UNMAP notifies (which + * is defined as IOMMU_NOTIFIER_IOTLB_EVENTS below). + * + * Regarding to accurate synchronization, it's when the notified + * device maintains a shadow page table and must be notified on each + * guest MAP (page table entry creation) and UNMAP (invalidation) + * events (e.g. VFIO). Both notifications must be accurate so that + * the shadow page table is fully in sync with the guest view. + * + * (2) When the device doesn't need accurate synchronizations of the + * vIOMMU page tables, it needs to register only with UNMAP or + * DEVIOTLB_UNMAP notifies. + * + * It's when the device maintains a cache of IOMMU translations + * (IOTLB) and is able to fill that cache by requesting translations + * from the vIOMMU through a protocol similar to ATS (Address + * Translation Service). + * + * Note that in this mode the vIOMMU will not maintain a shadowed + * page table for the address space, and the UNMAP messages can cover + * more than the pages that used to get mapped. The IOMMU notifiee + * should be able to take care of over-sized invalidations. */ typedef enum { IOMMU_NOTIFIER_NONE = 0, diff --git a/include/hw/acpi/acpi_aml_interface.h b/include/hw/acpi/acpi_aml_interface.h index 436da069d6..11748a8866 100644 --- a/include/hw/acpi/acpi_aml_interface.h +++ b/include/hw/acpi/acpi_aml_interface.h @@ -3,6 +3,7 @@ #include "qom/object.h" #include "hw/acpi/aml-build.h" +#include "hw/qdev-core.h" #define TYPE_ACPI_DEV_AML_IF "acpi-dev-aml-interface" typedef struct AcpiDevAmlIfClass AcpiDevAmlIfClass; @@ -46,4 +47,6 @@ static inline void call_dev_aml_func(DeviceState *dev, Aml *scope) } } +void qbus_build_aml(BusState *bus, Aml *scope); + #endif diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h index ea6056ab92..a1648220ff 100644 --- a/include/hw/acpi/acpi_dev_interface.h +++ b/include/hw/acpi/acpi_dev_interface.h @@ -52,8 +52,7 @@ struct AcpiDeviceIfClass { /* <public> */ void (*ospm_status)(AcpiDeviceIf *adev, ACPIOSTInfoList ***list); void (*send_event)(AcpiDeviceIf *adev, AcpiEventStatusBits ev); - void (*madt_cpu)(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, + void (*madt_cpu)(int uid, const CPUArchIdList *apic_ids, GArray *entry, bool force_enabled); }; #endif diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h index b5deee0a9d..467a99461c 100644 --- a/include/hw/acpi/pci.h +++ b/include/hw/acpi/pci.h @@ -27,6 +27,7 @@ #define HW_ACPI_PCI_H #include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/acpi_aml_interface.h" typedef struct AcpiMcfgInfo { uint64_t base; @@ -36,4 +37,7 @@ typedef struct AcpiMcfgInfo { void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info, const char *oem_id, const char *oem_table_id); Aml *aml_pci_device_dsm(void); + +void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus); +void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope); #endif diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h index 46d973e629..89dcbc5e1e 100644 --- a/include/hw/i386/intel_iommu.h +++ b/include/hw/i386/intel_iommu.h @@ -109,7 +109,43 @@ struct VTDAddressSpace { QLIST_ENTRY(VTDAddressSpace) next; /* Superset of notifier flags that this address space has */ IOMMUNotifierFlag notifier_flags; - IOVATree *iova_tree; /* Traces mapped IOVA ranges */ + /* + * @iova_tree traces mapped IOVA ranges. + * + * The tree is not needed if no MAP notifier is registered with current + * VTD address space, because all guest invalidate commands can be + * directly passed to the IOMMU UNMAP notifiers without any further + * reshuffling. + * + * The tree OTOH is required for MAP typed iommu notifiers for a few + * reasons. + * + * Firstly, there's no way to identify whether an PSI (Page Selective + * Invalidations) or DSI (Domain Selective Invalidations) event is an + * MAP or UNMAP event within the message itself. Without having prior + * knowledge of existing state vIOMMU doesn't know whether it should + * notify MAP or UNMAP for a PSI message it received when caching mode + * is enabled (for MAP notifiers). + * + * Secondly, PSI messages received from guest driver can be enlarged in + * range, covers but not limited to what the guest driver wanted to + * invalidate. When the range to invalidates gets bigger than the + * limit of a PSI message, it can even become a DSI which will + * invalidate the whole domain. If the vIOMMU directly notifies the + * registered device with the unmodified range, it may confuse the + * registered drivers (e.g. vfio-pci) on either: + * + * (1) Trying to map the same region more than once (for + * VFIO_IOMMU_MAP_DMA, -EEXIST will trigger), or, + * + * (2) Trying to UNMAP a range that is still partially mapped. + * + * That accuracy is not required for UNMAP-only notifiers, but it is a + * must-to-have for notifiers registered with MAP events, because the + * vIOMMU needs to make sure the shadow page table is always in sync + * with the guest IOMMU pgtables for a device. + */ + IOVATree *iova_tree; }; struct VTDIOTLBEntry { diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h index fad97a891d..e8af61f194 100644 --- a/include/hw/i386/microvm.h +++ b/include/hw/i386/microvm.h @@ -50,8 +50,9 @@ */ /* Platform virtio definitions */ -#define VIRTIO_MMIO_BASE 0xfeb00000 -#define VIRTIO_CMDLINE_MAXLEN 64 +#define VIRTIO_MMIO_BASE 0xfeb00000 +#define VIRTIO_CMDLINE_MAXLEN 64 +#define VIRTIO_CMDLINE_TOTAL_MAX_LEN ((VIRTIO_CMDLINE_MAXLEN + 1) * 16) #define GED_MMIO_BASE 0xfea00000 #define GED_MMIO_BASE_MEMHP (GED_MMIO_BASE + 0x100) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 88a120bc23..66e3d059ef 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -9,7 +9,6 @@ #include "hw/block/flash.h" #include "hw/i386/x86.h" -#include "hw/acpi/acpi_dev_interface.h" #include "hw/hotplug.h" #include "qom/object.h" #include "hw/i386/sgx-epc.h" @@ -193,9 +192,8 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size); /* hw/i386/acpi-common.c */ -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, - bool force_enabled); +void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled); /* sgx.c */ void pc_machine_init_sgx_epc(PCMachineState *pcms); diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 6c8a8a92cb..25acd5c34c 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -86,7 +86,6 @@ bool isa_realize_and_unref(ISADevice *dev, ISABus *bus, Error **errp); ISADevice *isa_create_simple(ISABus *bus, const char *name); ISADevice *isa_vga_init(ISABus *bus); -void isa_build_aml(ISABus *bus, Aml *scope); /** * isa_register_ioport: Install an I/O port region on the ISA bus. diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 2e503904dc..990dcdbb2e 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -140,6 +140,15 @@ void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key, bool read_only); /** + * fw_cfg_read_bytes_ptr: + * @s: fw_cfg device being modified + * @key: selector key value for new fw_cfg item + * + * Reads an existing fw_cfg data pointer. + */ +void *fw_cfg_read_bytes_ptr(FWCfgState *s, uint16_t key); + +/** * fw_cfg_add_string: * @s: fw_cfg device being modified * @key: selector key value for new fw_cfg item diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 85ee458cd2..d5a40cd058 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -270,7 +270,7 @@ typedef void (*pci_bus_dev_fn)(PCIBus *b, PCIDevice *d, void *opaque); typedef void (*pci_bus_fn)(PCIBus *b, void *opaque); typedef void *(*pci_bus_ret_fn)(PCIBus *b, void *opaque); -bool pci_bus_is_express(PCIBus *bus); +bool pci_bus_is_express(const PCIBus *bus); void pci_root_bus_init(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index fd484afb30..6c40e3733f 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -63,7 +63,8 @@ struct PCIESlot { /* Indicates whether any type of hot-plug is allowed on the slot */ bool hotplug; - bool native_hotplug; + /* broken ACPI hotplug compat knob to preserve 6.1 ABI intact */ + bool hide_native_hotplug_cap; QLIST_ENTRY(PCIESlot) next; }; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 7f589b4146..dafec432ce 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -55,7 +55,6 @@ struct VirtIOBlock { VirtIODevice parent_obj; BlockBackend *blk; void *rq; - QEMUBH *bh; VirtIOBlkConf conf; unsigned short sector_mask; bool original_wce; @@ -93,6 +92,5 @@ typedef struct MultiReqBuffer { } MultiReqBuffer; void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); -void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh); #endif diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 346d05f2aa..3cbe52246b 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -1,97 +1,44 @@ #ifndef BSWAP_H #define BSWAP_H -#ifdef CONFIG_MACHINE_BSWAP_H -# include <sys/endian.h> -# include <machine/bswap.h> -#elif defined(__FreeBSD__) -# include <sys/endian.h> -#elif defined(__HAIKU__) -# include <endian.h> -#elif defined(CONFIG_BYTESWAP_H) -# include <byteswap.h> -#define BSWAP_FROM_BYTESWAP -# else -#define BSWAP_FROM_FALLBACKS -#endif /* ! CONFIG_MACHINE_BSWAP_H */ - #ifdef __cplusplus extern "C" { #endif -#ifdef BSWAP_FROM_BYTESWAP -static inline uint16_t bswap16(uint16_t x) -{ - return bswap_16(x); -} - -static inline uint32_t bswap32(uint32_t x) -{ - return bswap_32(x); -} - -static inline uint64_t bswap64(uint64_t x) -{ - return bswap_64(x); -} -#endif - -#ifdef BSWAP_FROM_FALLBACKS -static inline uint16_t bswap16(uint16_t x) -{ - return (((x & 0x00ff) << 8) | - ((x & 0xff00) >> 8)); -} - -static inline uint32_t bswap32(uint32_t x) -{ - return (((x & 0x000000ffU) << 24) | - ((x & 0x0000ff00U) << 8) | - ((x & 0x00ff0000U) >> 8) | - ((x & 0xff000000U) >> 24)); -} - -static inline uint64_t bswap64(uint64_t x) -{ - return (((x & 0x00000000000000ffULL) << 56) | - ((x & 0x000000000000ff00ULL) << 40) | - ((x & 0x0000000000ff0000ULL) << 24) | - ((x & 0x00000000ff000000ULL) << 8) | - ((x & 0x000000ff00000000ULL) >> 8) | - ((x & 0x0000ff0000000000ULL) >> 24) | - ((x & 0x00ff000000000000ULL) >> 40) | - ((x & 0xff00000000000000ULL) >> 56)); -} -#endif - -#undef BSWAP_FROM_BYTESWAP -#undef BSWAP_FROM_FALLBACKS +#undef bswap16 +#define bswap16(_x) __builtin_bswap16(_x) +#undef bswap32 +#define bswap32(_x) __builtin_bswap32(_x) +#undef bswap64 +#define bswap64(_x) __builtin_bswap64(_x) static inline void bswap16s(uint16_t *s) { - *s = bswap16(*s); + *s = __builtin_bswap16(*s); } static inline void bswap32s(uint32_t *s) { - *s = bswap32(*s); + *s = __builtin_bswap32(*s); } static inline void bswap64s(uint64_t *s) { - *s = bswap64(*s); + *s = __builtin_bswap64(*s); } #if HOST_BIG_ENDIAN #define be_bswap(v, size) (v) -#define le_bswap(v, size) glue(bswap, size)(v) +#define le_bswap(v, size) glue(__builtin_bswap, size)(v) #define be_bswaps(v, size) -#define le_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0) +#define le_bswaps(p, size) \ + do { *p = glue(__builtin_bswap, size)(*p); } while (0) #else #define le_bswap(v, size) (v) -#define be_bswap(v, size) glue(bswap, size)(v) +#define be_bswap(v, size) glue(__builtin_bswap, size)(v) #define le_bswaps(v, size) -#define be_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0) +#define be_bswaps(p, size) \ + do { *p = glue(__builtin_bswap, size)(*p); } while (0) #endif /** diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index a772e14193..fb338ba576 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -59,6 +59,8 @@ get_plugin_meminfo_rw(qemu_plugin_meminfo_t i) #ifdef CONFIG_PLUGIN extern QemuOptsList qemu_plugin_opts; +#define QEMU_PLUGIN_ASSERT(cond) g_assert(cond) + static inline void qemu_plugin_add_opts(void) { qemu_add_opts(&qemu_plugin_opts); @@ -118,7 +120,10 @@ struct qemu_plugin_insn { void *haddr; GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES]; bool calls_helpers; + + /* if set, the instruction calls helpers that might access guest memory */ bool mem_helper; + bool mem_only; }; @@ -158,6 +163,10 @@ struct qemu_plugin_tb { void *haddr1; void *haddr2; bool mem_only; + + /* if set, the TB calls helpers that might access guest memory */ + bool mem_helper; + GArray *cbs[PLUGIN_N_CB_SUBTYPES]; }; @@ -243,6 +252,8 @@ void qemu_plugin_user_postfork(bool is_child); #else /* !CONFIG_PLUGIN */ +#define QEMU_PLUGIN_ASSERT(cond) + static inline void qemu_plugin_add_opts(void) { } diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 7c6703bce3..7841084199 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -237,11 +237,10 @@ static inline void qemu_spin_init(QemuSpin *spin) #endif } -/* const parameter because the only purpose here is the TSAN annotation */ -static inline void qemu_spin_destroy(const QemuSpin *spin) +static inline void qemu_spin_destroy(QemuSpin *spin) { #ifdef CONFIG_TSAN - __tsan_mutex_destroy((void *)spin, __tsan_mutex_not_static); + __tsan_mutex_destroy(spin, __tsan_mutex_not_static); #endif } diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 9a0ae7d20b..c5112da0ef 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -398,6 +398,8 @@ typedef TCGv_ptr TCGv_env; #define TCG_CALL_NO_SIDE_EFFECTS 0x0004 /* Helper is G_NORETURN. */ #define TCG_CALL_NO_RETURN 0x0008 +/* Helper is part of Plugins. */ +#define TCG_CALL_PLUGIN 0x0010 /* convenience version of most used call flags */ #define TCG_CALL_NO_RWG TCG_CALL_NO_READ_GLOBALS diff --git a/meson.build b/meson.build index 6d3b665629..b4c384013d 100644 --- a/meson.build +++ b/meson.build @@ -2013,8 +2013,6 @@ if rdma.found() endif # has_header_symbol -config_host_data.set('CONFIG_BYTESWAP_H', - cc.has_header_symbol('byteswap.h', 'bswap_32')) config_host_data.set('CONFIG_EPOLL_CREATE1', cc.has_header_symbol('sys/epoll.h', 'epoll_create1')) config_host_data.set('CONFIG_FALLOCATE_PUNCH_HOLE', @@ -2032,10 +2030,6 @@ config_host_data.set('CONFIG_INOTIFY', cc.has_header_symbol('sys/inotify.h', 'inotify_init')) config_host_data.set('CONFIG_INOTIFY1', cc.has_header_symbol('sys/inotify.h', 'inotify_init1')) -config_host_data.set('CONFIG_MACHINE_BSWAP_H', - cc.has_header_symbol('machine/bswap.h', 'bswap32', - prefix: '''#include <sys/endian.h> - #include <sys/types.h>''')) config_host_data.set('CONFIG_PRCTL_PR_SET_TIMERSLACK', cc.has_header_symbol('sys/prctl.h', 'PR_SET_TIMERSLACK')) config_host_data.set('CONFIG_RTNETLINK', @@ -2779,7 +2773,7 @@ config_host_data.set('CONFIG_SLIRP', slirp.found()) genh += configure_file(output: 'config-host.h', configuration: config_host_data) hxtool = find_program('scripts/hxtool') -shaderinclude = find_program('scripts/shaderinclude.pl') +shaderinclude = find_program('scripts/shaderinclude.py') qapi_gen = find_program('scripts/qapi-gen.py') qapi_gen_depends = [ meson.current_source_dir() / 'scripts/qapi/__init__.py', meson.current_source_dir() / 'scripts/qapi/commands.py', diff --git a/plugins/core.c b/plugins/core.c index ccb770a485..e04ffa1ba4 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -500,26 +500,33 @@ void qemu_plugin_user_exit(void) enum qemu_plugin_event ev; CPUState *cpu; - QEMU_LOCK_GUARD(&plugin.lock); - + /* + * Locking order: we must acquire locks in an order that is consistent + * with the one in fork_start(). That is: + * - start_exclusive(), which acquires qemu_cpu_list_lock, + * must be called before acquiring plugin.lock. + * - tb_flush(), which acquires mmap_lock(), must be called + * while plugin.lock is not held. + */ start_exclusive(); + qemu_rec_mutex_lock(&plugin.lock); /* un-register all callbacks except the final AT_EXIT one */ for (ev = 0; ev < QEMU_PLUGIN_EV_MAX; ev++) { if (ev != QEMU_PLUGIN_EV_ATEXIT) { - struct qemu_plugin_ctx *ctx; - QTAILQ_FOREACH(ctx, &plugin.ctxs, entry) { - plugin_unregister_cb__locked(ctx, ev); + struct qemu_plugin_cb *cb, *next; + + QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { + plugin_unregister_cb__locked(cb->ctx, ev); } } } - - tb_flush(current_cpu); - CPU_FOREACH(cpu) { qemu_plugin_disable_mem_helpers(cpu); } + qemu_rec_mutex_unlock(&plugin.lock); + tb_flush(current_cpu); end_exclusive(); /* now it's safe to handle the exit case */ diff --git a/python/qemu/machine/console_socket.py b/python/qemu/machine/console_socket.py index 8c4ff598ad..4e28ba9bb2 100644 --- a/python/qemu/machine/console_socket.py +++ b/python/qemu/machine/console_socket.py @@ -68,7 +68,7 @@ class ConsoleSocket(socket.socket): """Kick off a thread to drain the socket.""" # Configure socket to not block and timeout. # This allows our drain thread to not block - # on recieve and exit smoothly. + # on receive and exit smoothly. socket.socket.setblocking(self, False) socket.socket.settimeout(self, 1) drain_thread = threading.Thread(target=self._drain_fn) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 748a0d807c..e57c254484 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -131,7 +131,7 @@ class QEMUMachine: drain_console: bool = False, console_log: Optional[str] = None, log_dir: Optional[str] = None, - qmp_timer: Optional[float] = None): + qmp_timer: Optional[float] = 30): ''' Initialize a QEMUMachine @@ -157,18 +157,14 @@ class QEMUMachine: self._wrapper = wrapper self._qmp_timer = qmp_timer - self._name = name or f"qemu-{os.getpid()}-{id(self):02x}" + self._name = name or f"{id(self):x}" + self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None self._temp_dir: Optional[str] = None self._base_temp_dir = base_temp_dir self._sock_dir = sock_dir self._log_dir = log_dir - if monitor_address is not None: - self._monitor_address = monitor_address - else: - self._monitor_address = os.path.join( - self.sock_dir, f"{self._name}-monitor.sock" - ) + self._monitor_address = monitor_address self._console_log_path = console_log if self._console_log_path: @@ -192,7 +188,7 @@ class QEMUMachine: self._console_set = False self._console_device_type: Optional[str] = None self._console_address = os.path.join( - self.sock_dir, f"{self._name}-console.sock" + self.sock_dir, f"{self._name}.con" ) self._console_socket: Optional[socket.socket] = None self._remove_files: List[str] = [] @@ -303,7 +299,11 @@ class QEMUMachine: args = ['-display', 'none', '-vga', 'none'] if self._qmp_set: - if isinstance(self._monitor_address, tuple): + if self._sock_pair: + fd = self._sock_pair[0].fileno() + os.set_inheritable(fd, True) + moncdev = f"socket,id=mon,fd={fd}" + elif isinstance(self._monitor_address, tuple): moncdev = "socket,id=mon,host={},port={}".format( *self._monitor_address ) @@ -337,10 +337,17 @@ class QEMUMachine: self._remove_files.append(self._console_address) if self._qmp_set: + monitor_address = None + sock = None + if self._monitor_address is None: + self._sock_pair = socket.socketpair() + sock = self._sock_pair[1] if isinstance(self._monitor_address, str): self._remove_files.append(self._monitor_address) + monitor_address = self._monitor_address self._qmp_connection = QEMUMonitorProtocol( - self._monitor_address, + address=monitor_address, + sock=sock, server=True, nickname=self._name ) @@ -360,6 +367,8 @@ class QEMUMachine: )) def _post_launch(self) -> None: + if self._sock_pair: + self._sock_pair[0].close() if self._qmp_connection: self._qmp.accept(self._qmp_timer) diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py index 1a1fc6c9b0..1c46138bd0 100644 --- a/python/qemu/machine/qtest.py +++ b/python/qemu/machine/qtest.py @@ -42,7 +42,7 @@ class QEMUQtestProtocol: :raise socket.error: on socket connection errors .. note:: - No conection is estabalished by __init__(), this is done + No connection is established by __init__(), this is done by the connect() or accept() methods. """ def __init__(self, address: SocketAddrT, diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py index 1951754455..8b09ee7dbb 100644 --- a/python/qemu/qmp/legacy.py +++ b/python/qemu/qmp/legacy.py @@ -22,6 +22,7 @@ old interface. # import asyncio +import socket from types import TracebackType from typing import ( Any, @@ -69,22 +70,32 @@ class QEMUMonitorProtocol: :param address: QEMU address, can be either a unix socket path (string) or a tuple in the form ( address, port ) for a TCP - connection + connection or None + :param sock: a socket or None :param server: Act as the socket server. (See 'accept') :param nickname: Optional nickname used for logging. """ - def __init__(self, address: SocketAddrT, + def __init__(self, + address: Optional[SocketAddrT] = None, + sock: Optional[socket.socket] = None, server: bool = False, nickname: Optional[str] = None): + assert address or sock self._qmp = QMPClient(nickname) self._aloop = asyncio.get_event_loop() self._address = address + self._sock = sock self._timeout: Optional[float] = None if server: - self._sync(self._qmp.start_server(self._address)) + if sock: + assert self._sock is not None + self._sync(self._qmp.open_with_socket(self._sock)) + else: + assert self._address is not None + self._sync(self._qmp.start_server(self._address)) _T = TypeVar('_T') @@ -139,6 +150,7 @@ class QEMUMonitorProtocol: :return: QMP greeting dict, or None if negotiate is false :raise ConnectError: on connection errors """ + assert self._address is not None self._qmp.await_greeting = negotiate self._qmp.negotiate = negotiate diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py index 6ea86650ad..6d3d739daa 100644 --- a/python/qemu/qmp/protocol.py +++ b/python/qemu/qmp/protocol.py @@ -18,6 +18,7 @@ from asyncio import StreamReader, StreamWriter from enum import Enum from functools import wraps import logging +import socket from ssl import SSLContext from typing import ( Any, @@ -298,6 +299,19 @@ class AsyncProtocol(Generic[T]): @upper_half @require(Runstate.IDLE) + async def open_with_socket(self, sock: socket.socket) -> None: + """ + Start connection with given socket. + + :param sock: A socket. + + :raise StateError: When the `Runstate` is not `IDLE`. + """ + self._reader, self._writer = await asyncio.open_connection(sock=sock) + self._set_state(Runstate.CONNECTING) + + @upper_half + @require(Runstate.IDLE) async def start_server(self, address: SocketAddrT, ssl: Optional[SSLContext] = None) -> None: """ @@ -343,11 +357,12 @@ class AsyncProtocol(Generic[T]): protocol-level failure occurs while establishing a new session, the wrapped error may also be an `QMPError`. """ - if self._accepted is None: - raise QMPError("Cannot call accept() before start_server().") - await self._session_guard( - self._do_accept(), - 'Failed to establish connection') + if not self._reader: + if self._accepted is None: + raise QMPError("Cannot call accept() before start_server().") + await self._session_guard( + self._do_accept(), + 'Failed to establish connection') await self._session_guard( self._establish_session(), 'Failed to establish session') @@ -812,7 +827,7 @@ class AsyncProtocol(Generic[T]): @bottom_half async def _bh_close_stream(self, error_pathway: bool = False) -> None: - # NB: Closing the writer also implcitly closes the reader. + # NB: Closing the writer also implicitly closes the reader. if not self._writer: return diff --git a/python/qemu/qmp/qmp_client.py b/python/qemu/qmp/qmp_client.py index 5dcda04a75..b5772e7f32 100644 --- a/python/qemu/qmp/qmp_client.py +++ b/python/qemu/qmp/qmp_client.py @@ -197,8 +197,8 @@ class QMPClient(AsyncProtocol[Message], Events): #: Logger object used for debugging messages. logger = logging.getLogger(__name__) - # Read buffer limit; large enough to accept query-qmp-schema - _limit = (256 * 1024) + # Read buffer limit; 10MB like libvirt default + _limit = (10 * 1024 * 1024) # Type alias for pending execute() result items _PendingT = Union[Message, ExecInterruptedError] diff --git a/python/qemu/qmp/qmp_tui.py b/python/qemu/qmp/qmp_tui.py index ce239d8979..8369144723 100644 --- a/python/qemu/qmp/qmp_tui.py +++ b/python/qemu/qmp/qmp_tui.py @@ -71,7 +71,7 @@ def format_json(msg: str) -> str: due to an decoding error then a simple string manipulation is done to achieve a single line JSON string. - Converting into single line is more asthetically pleasing when looking + Converting into single line is more aesthetically pleasing when looking along with error messages. Eg: @@ -91,7 +91,7 @@ def format_json(msg: str) -> str: [1, true, 3]: QMP message is not a JSON object. - The single line mode is more asthetically pleasing. + The single line mode is more aesthetically pleasing. :param msg: The message to formatted into single line. @@ -498,7 +498,7 @@ class EditorWidget(urwid.Filler): class HistoryBox(urwid.ListBox): """ This widget is modelled using the ListBox widget, contains the list of - all messages both QMP messages and log messsages to be shown in the TUI. + all messages both QMP messages and log messages to be shown in the TUI. The messages are urwid.Text widgets. On every append of a message, the focus is shifted to the last appended message. diff --git a/qapi/audio.json b/qapi/audio.json index 1e0a24bdfc..4e54c00f51 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -408,8 +408,18 @@ # Since: 4.0 ## { 'enum': 'AudiodevDriver', - 'data': [ 'none', 'alsa', 'coreaudio', 'dbus', 'dsound', 'jack', 'oss', 'pa', - 'sdl', 'sndio', 'spice', 'wav' ] } + 'data': [ 'none', + { 'name': 'alsa', 'if': 'CONFIG_AUDIO_ALSA' }, + { 'name': 'coreaudio', 'if': 'CONFIG_AUDIO_COREAUDIO' }, + { 'name': 'dbus', 'if': 'CONFIG_DBUS_DISPLAY' }, + { 'name': 'dsound', 'if': 'CONFIG_AUDIO_DSOUND' }, + { 'name': 'jack', 'if': 'CONFIG_AUDIO_JACK' }, + { 'name': 'oss', 'if': 'CONFIG_AUDIO_OSS' }, + { 'name': 'pa', 'if': 'CONFIG_AUDIO_PA' }, + { 'name': 'sdl', 'if': 'CONFIG_AUDIO_SDL' }, + { 'name': 'sndio', 'if': 'CONFIG_AUDIO_SNDIO' }, + { 'name': 'spice', 'if': 'CONFIG_SPICE' }, + 'wav' ] } ## # @Audiodev: @@ -432,14 +442,37 @@ 'discriminator': 'driver', 'data': { 'none': 'AudiodevGenericOptions', - 'alsa': 'AudiodevAlsaOptions', - 'coreaudio': 'AudiodevCoreaudioOptions', - 'dbus': 'AudiodevGenericOptions', - 'dsound': 'AudiodevDsoundOptions', - 'jack': 'AudiodevJackOptions', - 'oss': 'AudiodevOssOptions', - 'pa': 'AudiodevPaOptions', - 'sdl': 'AudiodevSdlOptions', - 'sndio': 'AudiodevSndioOptions', - 'spice': 'AudiodevGenericOptions', + 'alsa': { 'type': 'AudiodevAlsaOptions', + 'if': 'CONFIG_AUDIO_ALSA' }, + 'coreaudio': { 'type': 'AudiodevCoreaudioOptions', + 'if': 'CONFIG_AUDIO_COREAUDIO' }, + 'dbus': { 'type': 'AudiodevGenericOptions', + 'if': 'CONFIG_DBUS_DISPLAY' }, + 'dsound': { 'type': 'AudiodevDsoundOptions', + 'if': 'CONFIG_AUDIO_DSOUND' }, + 'jack': { 'type': 'AudiodevJackOptions', + 'if': 'CONFIG_AUDIO_JACK' }, + 'oss': { 'type': 'AudiodevOssOptions', + 'if': 'CONFIG_AUDIO_OSS' }, + 'pa': { 'type': 'AudiodevPaOptions', + 'if': 'CONFIG_AUDIO_PA' }, + 'sdl': { 'type': 'AudiodevSdlOptions', + 'if': 'CONFIG_AUDIO_SDL' }, + 'sndio': { 'type': 'AudiodevSndioOptions', + 'if': 'CONFIG_AUDIO_SNDIO' }, + 'spice': { 'type': 'AudiodevGenericOptions', + 'if': 'CONFIG_SPICE' }, 'wav': 'AudiodevWavOptions' } } + +## +# @query-audiodevs: +# +# Returns information about audiodev configuration +# +# Returns: array of @Audiodev +# +# Since: 8.0 +# +## +{ 'command': 'query-audiodevs', + 'returns': ['Audiodev'] } diff --git a/qemu-options.hx b/qemu-options.hx index d59d19704b..88e93c6103 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4633,10 +4633,11 @@ DEF("semihosting", 0, QEMU_OPTION_semihosting, QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting`` - Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). + Enable :ref:`Semihosting` mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). - Note that this allows guest direct access to the host filesystem, so - should only be used with a trusted guest OS. + .. warning:: + Note that this allows guest direct access to the host filesystem, so + should only be used with a trusted guest OS. See the -semihosting-config option documentation for further information about the facilities this enables. @@ -4648,22 +4649,12 @@ QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]`` - Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V + Enable and configure :ref:`Semihosting` (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). - Note that this allows guest direct access to the host filesystem, so - should only be used with a trusted guest OS. - - On Arm this implements the standard semihosting API, version 2.0. - - On M68K this implements the "ColdFire GDB" interface used by - libgloss. - - Xtensa semihosting provides basic file IO calls, such as - open/read/write/seek/select. Tensilica baremetal libc for ISS and - linux platform "sim" use this interface. - - On RISC-V this implements the standard semihosting API, version 0.2. + .. warning:: + Note that this allows guest direct access to the host filesystem, so + should only be used with a trusted guest OS. ``target=native|gdb|auto`` Defines where the semihosting calls will be addressed, to QEMU diff --git a/scripts/ci/setup/build-environment.yml b/scripts/ci/setup/build-environment.yml index b04c2b7cee..58438008ee 100644 --- a/scripts/ci/setup/build-environment.yml +++ b/scripts/ci/setup/build-environment.yml @@ -155,7 +155,6 @@ - nettle-devel - ninja-build - nmap-ncat - - perl-Test-Harness - pixman-devel - python36 - rdma-core-devel diff --git a/scripts/ci/setup/gitlab-runner.yml b/scripts/ci/setup/gitlab-runner.yml index 33128be85d..95d4199c03 100644 --- a/scripts/ci/setup/gitlab-runner.yml +++ b/scripts/ci/setup/gitlab-runner.yml @@ -50,60 +50,30 @@ - name: Download the matching gitlab-runner get_url: - dest: /usr/local/bin/gitlab-runner - url: "https://s3.amazonaws.com/gitlab-runner-downloads/v{{ gitlab_runner_version }}/binaries/gitlab-runner-{{ gitlab_runner_os }}-{{ gitlab_runner_arch }}" - owner: gitlab-runner - group: gitlab-runner - mode: u=rwx,g=rwx,o=rx - - - name: Register the gitlab-runner - command: "/usr/local/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list {{ ansible_facts[\"architecture\"] }},{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" - - - name: Install the gitlab-runner service using its own functionality - command: /usr/local/bin/gitlab-runner install --user gitlab-runner --working-directory /home/gitlab-runner - register: gitlab_runner_install_service_result - failed_when: "gitlab_runner_install_service_result.rc != 0 and \"already exists\" not in gitlab_runner_install_service_result.stderr" + dest: "/root/" + url: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_{{ gitlab_runner_arch }}.deb" - - name: Enable the gitlab-runner service - service: - name: gitlab-runner - state: started - enabled: yes + - name: Install gitlab-runner via package manager + apt: deb="/root/gitlab-runner_{{ gitlab_runner_arch }}.deb" - - name: Download secondary gitlab-runner - get_url: - dest: /usr/local/bin/gitlab-runner-arm - url: "https://s3.amazonaws.com/gitlab-runner-downloads/v{{ gitlab_runner_version }}/binaries/gitlab-runner-{{ gitlab_runner_os }}-arm" - owner: gitlab-runner - group: gitlab-runner - mode: u=rwx,g=rwx,o=rx - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '20.04' + - name: Register the gitlab-runner + command: "/usr/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list {{ ansible_facts[\"architecture\"] }},{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" + # The secondary runner will still run under the single gitlab-runner service - name: Register secondary gitlab-runner - command: "/usr/local/bin/gitlab-runner-arm register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list aarch32,{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" + command: "/usr/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list aarch32,{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'" when: - ansible_facts['distribution'] == 'Ubuntu' - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '20.04' + - ansible_facts['distribution_version'] == '22.04' - - name: Install the secondary gitlab-runner service using its own functionality - command: /usr/local/bin/gitlab-runner-arm install --user gitlab-runner --working-directory /home/gitlab-runner/arm -n gitlab-runner-arm + - name: Install the gitlab-runner service using its own functionality + command: "/usr/bin/gitlab-runner install --user gitlab-runner --working-directory /home/gitlab-runner" register: gitlab_runner_install_service_result failed_when: "gitlab_runner_install_service_result.rc != 0 and \"already exists\" not in gitlab_runner_install_service_result.stderr" - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '20.04' - - name: Enable the secondary gitlab-runner service + - name: Enable the gitlab-runner service service: - name: gitlab-runner-arm + name: gitlab-runner state: started enabled: yes - when: - - ansible_facts['distribution'] == 'Ubuntu' - - ansible_facts['architecture'] == 'aarch64' - - ansible_facts['distribution_version'] == '20.04' diff --git a/scripts/ci/setup/vars.yml.template b/scripts/ci/setup/vars.yml.template index e48089761f..4b355fb80f 100644 --- a/scripts/ci/setup/vars.yml.template +++ b/scripts/ci/setup/vars.yml.template @@ -1,5 +1,3 @@ -# The version of the gitlab-runner to use -gitlab_runner_version: 13.12.0 # The URL of the gitlab server to use, usually https://gitlab.com unless you're # using a private GitLab instance gitlab_runner_server_url: https://gitlab.com diff --git a/scripts/oss-fuzz/lsan_suppressions.txt b/scripts/oss-fuzz/lsan_suppressions.txt new file mode 100644 index 0000000000..02ec0a6ed5 --- /dev/null +++ b/scripts/oss-fuzz/lsan_suppressions.txt @@ -0,0 +1,2 @@ +# The tcmalloc on Fedora37 confuses things +leak:/lib64/libtcmalloc_minimal.so.4 diff --git a/scripts/shaderinclude.pl b/scripts/shaderinclude.pl deleted file mode 100644 index cd3bb40b12..0000000000 --- a/scripts/shaderinclude.pl +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; - -my $file = shift; -open FILE, "<", $file or die "open $file: $!"; -my $name = $file; -$name =~ s|.*/||; -$name =~ s/[-.]/_/g; -print "static GLchar ${name}_src[] =\n"; -while (<FILE>) { - chomp; - printf " \"%s\\n\"\n", $_; -} -print " \"\\n\";\n"; -close FILE; diff --git a/scripts/shaderinclude.py b/scripts/shaderinclude.py new file mode 100644 index 0000000000..ab2aade2cd --- /dev/null +++ b/scripts/shaderinclude.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 Red Hat, Inc. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import sys +import os + + +def main(args): + file_path = args[1] + basename = os.path.basename(file_path) + varname = basename.replace('-', '_').replace('.', '_') + + with os.fdopen(sys.stdout.fileno(), "wt", closefd=False, newline='\n') as stdout: + with open(file_path, "r", encoding='utf-8') as file: + print(f'static GLchar {varname}_src[] =', file=stdout) + for line in file: + line = line.rstrip() + print(f' "{line}\\n"', file=stdout) + print(' "\\n";', file=stdout) + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c index 5893c760c5..e89992cf90 100644 --- a/semihosting/syscalls.c +++ b/semihosting/syscalls.c @@ -253,7 +253,7 @@ static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, { CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; char *p; - int ret, host_flags; + int ret, host_flags = O_BINARY; ret = validate_lock_user_string(&p, cs, fname, fname_len); if (ret < 0) { @@ -262,11 +262,11 @@ static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, } if (gdb_flags & GDB_O_WRONLY) { - host_flags = O_WRONLY; + host_flags |= O_WRONLY; } else if (gdb_flags & GDB_O_RDWR) { - host_flags = O_RDWR; + host_flags |= O_RDWR; } else { - host_flags = O_RDONLY; + host_flags |= O_RDONLY; } if (gdb_flags & GDB_O_CREAT) { host_flags |= O_CREAT; @@ -319,11 +319,11 @@ static void host_read(CPUState *cs, gdb_syscall_complete_cb complete, } ret = RETRY_ON_EINTR(read(gf->hostfd, ptr, len)); if (ret == -1) { - complete(cs, -1, errno); unlock_user(ptr, buf, 0); + complete(cs, -1, errno); } else { - complete(cs, ret, 0); unlock_user(ptr, buf, ret); + complete(cs, ret, 0); } } @@ -339,8 +339,8 @@ static void host_write(CPUState *cs, gdb_syscall_complete_cb complete, return; } ret = write(gf->hostfd, ptr, len); - complete(cs, ret, ret == -1 ? errno : 0); unlock_user(ptr, buf, 0); + complete(cs, ret, ret == -1 ? errno : 0); } static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete, @@ -426,8 +426,8 @@ static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete, ret = -1; } } - complete(cs, ret, err); unlock_user(name, fname, 0); + complete(cs, ret, err); } static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete, @@ -444,8 +444,8 @@ static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete, } ret = remove(p); - complete(cs, ret, ret ? errno : 0); unlock_user(p, fname, 0); + complete(cs, ret, ret ? errno : 0); } static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete, @@ -469,9 +469,9 @@ static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete, } ret = rename(ostr, nstr); - complete(cs, ret, ret ? errno : 0); unlock_user(ostr, oname, 0); unlock_user(nstr, nname, 0); + complete(cs, ret, ret ? errno : 0); } static void host_system(CPUState *cs, gdb_syscall_complete_cb complete, @@ -488,8 +488,8 @@ static void host_system(CPUState *cs, gdb_syscall_complete_cb complete, } ret = system(p); - complete(cs, ret, ret == -1 ? errno : 0); unlock_user(p, cmd, 0); + complete(cs, ret, ret == -1 ? errno : 0); } static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, @@ -554,8 +554,8 @@ static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete, } memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len); gf->staticfile.off += len; - complete(cs, len, 0); unlock_user(ptr, buf, len); + complete(cs, len, 0); } static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete, @@ -608,8 +608,8 @@ static void console_read(CPUState *cs, gdb_syscall_complete_cb complete, return; } ret = qemu_semihosting_console_read(cs, ptr, len); - complete(cs, ret, 0); unlock_user(ptr, buf, ret); + complete(cs, ret, 0); } static void console_write(CPUState *cs, gdb_syscall_complete_cb complete, @@ -624,8 +624,8 @@ static void console_write(CPUState *cs, gdb_syscall_complete_cb complete, return; } ret = qemu_semihosting_console_write(ptr, len); - complete(cs, ret ? ret : -1, ret ? 0 : EIO); unlock_user(ptr, buf, 0); + complete(cs, ret ? ret : -1, ret ? 0 : EIO); } static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete, diff --git a/target/i386/hax/hax-all.c b/target/i386/hax/hax-all.c index b7fb5385b2..3e5992a63b 100644 --- a/target/i386/hax/hax-all.c +++ b/target/i386/hax/hax-all.c @@ -357,6 +357,9 @@ static int hax_accel_init(MachineState *ms) fprintf(stdout, "HAX is %s and emulator runs in %s mode.\n", !ret ? "working" : "not working", !ret ? "fast virt" : "emulation"); + fprintf(stdout, + "NOTE: HAX is deprecated and will be removed in a future release.\n" + " Use 'whpx' (on Windows) or 'hvf' (on macOS) instead.\n"); } return ret; } diff --git a/tcg/tcg.c b/tcg/tcg.c index d502327be2..fd557d55d3 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1674,8 +1674,10 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) op = tcg_op_alloc(INDEX_op_call, total_args); #ifdef CONFIG_PLUGIN - /* detect non-plugin helpers */ - if (tcg_ctx->plugin_insn && unlikely(strncmp(info->name, "plugin_", 7))) { + /* Flag helpers that may affect guest state */ + if (tcg_ctx->plugin_insn && + !(info->flags & TCG_CALL_PLUGIN) && + !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) { tcg_ctx->plugin_insn->calls_helpers = true; } #endif diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py index 910f3ba1ea..25a546842f 100644 --- a/tests/avocado/avocado_qemu/__init__.py +++ b/tests/avocado/avocado_qemu/__init__.py @@ -306,7 +306,7 @@ class QemuSystemTest(QemuBaseTest): self.cancel('no support for user networking') def _new_vm(self, name, *args): - self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_") + self._sd = tempfile.TemporaryDirectory(prefix="qemu_") vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, sock_dir=self._sd.name, log_dir=self.logdir) self.log.debug('QEMUMachine "%s" created', name) diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT index b688686dc3..0b475fb5a9 100644 --- a/tests/data/acpi/pc/DSDT +++ b/tests/data/acpi/pc/DSDT Binary files differdiff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst index 86259be9d1..17ef7caeb6 100644 --- a/tests/data/acpi/pc/DSDT.acpierst +++ b/tests/data/acpi/pc/DSDT.acpierst Binary files differdiff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat index e2cc2a6fc9..675b674eaa 100644 --- a/tests/data/acpi/pc/DSDT.acpihmat +++ b/tests/data/acpi/pc/DSDT.acpihmat Binary files differdiff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge index 75016fd4b7..c1ce061366 100644 --- a/tests/data/acpi/pc/DSDT.bridge +++ b/tests/data/acpi/pc/DSDT.bridge Binary files differdiff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp index 53eb0dd7d4..754ab854dc 100644 --- a/tests/data/acpi/pc/DSDT.cphp +++ b/tests/data/acpi/pc/DSDT.cphp Binary files differdiff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm index 9089d994e0..170503336b 100644 --- a/tests/data/acpi/pc/DSDT.dimmpxm +++ b/tests/data/acpi/pc/DSDT.dimmpxm Binary files differdiff --git a/tests/data/acpi/pc/DSDT.hpbridge b/tests/data/acpi/pc/DSDT.hpbridge index 86259be9d1..834c27002e 100644 --- a/tests/data/acpi/pc/DSDT.hpbridge +++ b/tests/data/acpi/pc/DSDT.hpbridge Binary files differdiff --git a/tests/data/acpi/pc/DSDT.hpbrroot b/tests/data/acpi/pc/DSDT.hpbrroot index 578468f4f0..a71ed4fbaa 100644 --- a/tests/data/acpi/pc/DSDT.hpbrroot +++ b/tests/data/acpi/pc/DSDT.hpbrroot Binary files differdiff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs index 39427103aa..dd71356027 100644 --- a/tests/data/acpi/pc/DSDT.ipmikcs +++ b/tests/data/acpi/pc/DSDT.ipmikcs Binary files differdiff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp index 987a263339..2f895e9b38 100644 --- a/tests/data/acpi/pc/DSDT.memhp +++ b/tests/data/acpi/pc/DSDT.memhp Binary files differdiff --git a/tests/data/acpi/pc/DSDT.nohpet b/tests/data/acpi/pc/DSDT.nohpet index fc7598b762..c012b63ace 100644 --- a/tests/data/acpi/pc/DSDT.nohpet +++ b/tests/data/acpi/pc/DSDT.nohpet Binary files differdiff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem index 85af400cdb..f2ef4b9729 100644 --- a/tests/data/acpi/pc/DSDT.numamem +++ b/tests/data/acpi/pc/DSDT.numamem Binary files differdiff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp index 545512adfa..657c8263f0 100644 --- a/tests/data/acpi/pc/DSDT.roothp +++ b/tests/data/acpi/pc/DSDT.roothp Binary files differdiff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT index 2771bcea89..d68c472b46 100644 --- a/tests/data/acpi/q35/DSDT +++ b/tests/data/acpi/q35/DSDT Binary files differdiff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst index b45abca7c2..de7ae27125 100644 --- a/tests/data/acpi/q35/DSDT.acpierst +++ b/tests/data/acpi/q35/DSDT.acpierst Binary files differdiff --git a/tests/data/acpi/q35/DSDT.acpihmat b/tests/data/acpi/q35/DSDT.acpihmat index d90fd4723a..48e2862257 100644 --- a/tests/data/acpi/q35/DSDT.acpihmat +++ b/tests/data/acpi/q35/DSDT.acpihmat Binary files differdiff --git a/tests/data/acpi/q35/DSDT.acpihmat-noinitiator b/tests/data/acpi/q35/DSDT.acpihmat-noinitiator index 279fafa821..30a4aa2ec8 100644 --- a/tests/data/acpi/q35/DSDT.acpihmat-noinitiator +++ b/tests/data/acpi/q35/DSDT.acpihmat-noinitiator Binary files differdiff --git a/tests/data/acpi/q35/DSDT.applesmc b/tests/data/acpi/q35/DSDT.applesmc index fdf6d14428..84e2b5cbc4 100644 --- a/tests/data/acpi/q35/DSDT.applesmc +++ b/tests/data/acpi/q35/DSDT.applesmc Binary files differdiff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge index b41a4dddc0..e411d40fd1 100644 --- a/tests/data/acpi/q35/DSDT.bridge +++ b/tests/data/acpi/q35/DSDT.bridge Binary files differdiff --git a/tests/data/acpi/q35/DSDT.core-count2 b/tests/data/acpi/q35/DSDT.core-count2 index 375aceed6b..0603db8cc6 100644 --- a/tests/data/acpi/q35/DSDT.core-count2 +++ b/tests/data/acpi/q35/DSDT.core-count2 Binary files differdiff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp index a0ecafc36c..beeb83c33b 100644 --- a/tests/data/acpi/q35/DSDT.cphp +++ b/tests/data/acpi/q35/DSDT.cphp Binary files differdiff --git a/tests/data/acpi/q35/DSDT.cxl b/tests/data/acpi/q35/DSDT.cxl index f9c6dd4ee0..3d18b9672d 100644 --- a/tests/data/acpi/q35/DSDT.cxl +++ b/tests/data/acpi/q35/DSDT.cxl Binary files differdiff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm index f0659716e3..99a93e12a7 100644 --- a/tests/data/acpi/q35/DSDT.dimmpxm +++ b/tests/data/acpi/q35/DSDT.dimmpxm Binary files differdiff --git a/tests/data/acpi/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt index 9c52529919..7f7601dbff 100644 --- a/tests/data/acpi/q35/DSDT.ipmibt +++ b/tests/data/acpi/q35/DSDT.ipmibt Binary files differdiff --git a/tests/data/acpi/q35/DSDT.ipmismbus b/tests/data/acpi/q35/DSDT.ipmismbus index 3f32dffdbf..6c5d1afe44 100644 --- a/tests/data/acpi/q35/DSDT.ipmismbus +++ b/tests/data/acpi/q35/DSDT.ipmismbus Binary files differdiff --git a/tests/data/acpi/q35/DSDT.ivrs b/tests/data/acpi/q35/DSDT.ivrs index b45abca7c2..de7ae27125 100644 --- a/tests/data/acpi/q35/DSDT.ivrs +++ b/tests/data/acpi/q35/DSDT.ivrs Binary files differdiff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp index 28a192c69a..79bce5c8f0 100644 --- a/tests/data/acpi/q35/DSDT.memhp +++ b/tests/data/acpi/q35/DSDT.memhp Binary files differdiff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64 index 8fda921296..c249929add 100644 --- a/tests/data/acpi/q35/DSDT.mmio64 +++ b/tests/data/acpi/q35/DSDT.mmio64 Binary files differdiff --git a/tests/data/acpi/q35/DSDT.multi-bridge b/tests/data/acpi/q35/DSDT.multi-bridge index 3dba4d8436..66b39be294 100644 --- a/tests/data/acpi/q35/DSDT.multi-bridge +++ b/tests/data/acpi/q35/DSDT.multi-bridge Binary files differdiff --git a/tests/data/acpi/q35/DSDT.nohpet b/tests/data/acpi/q35/DSDT.nohpet index b116947dac..9ff9983a80 100644 --- a/tests/data/acpi/q35/DSDT.nohpet +++ b/tests/data/acpi/q35/DSDT.nohpet Binary files differdiff --git a/tests/data/acpi/q35/DSDT.numamem b/tests/data/acpi/q35/DSDT.numamem index 5eb6159d5f..1e7c45ef3c 100644 --- a/tests/data/acpi/q35/DSDT.numamem +++ b/tests/data/acpi/q35/DSDT.numamem Binary files differdiff --git a/tests/data/acpi/q35/DSDT.pvpanic-isa b/tests/data/acpi/q35/DSDT.pvpanic-isa index 908e7b6606..ed47451c44 100644 --- a/tests/data/acpi/q35/DSDT.pvpanic-isa +++ b/tests/data/acpi/q35/DSDT.pvpanic-isa Binary files differdiff --git a/tests/data/acpi/q35/DSDT.tis.tpm12 b/tests/data/acpi/q35/DSDT.tis.tpm12 index ce2c2c29c2..efc2efc19f 100644 --- a/tests/data/acpi/q35/DSDT.tis.tpm12 +++ b/tests/data/acpi/q35/DSDT.tis.tpm12 Binary files differdiff --git a/tests/data/acpi/q35/DSDT.tis.tpm2 b/tests/data/acpi/q35/DSDT.tis.tpm2 index e9e4b7f6ed..675339715f 100644 --- a/tests/data/acpi/q35/DSDT.tis.tpm2 +++ b/tests/data/acpi/q35/DSDT.tis.tpm2 Binary files differdiff --git a/tests/data/acpi/q35/DSDT.viot b/tests/data/acpi/q35/DSDT.viot index 6b436f9cd9..eeb40b360f 100644 --- a/tests/data/acpi/q35/DSDT.viot +++ b/tests/data/acpi/q35/DSDT.viot Binary files differdiff --git a/tests/data/acpi/q35/DSDT.xapic b/tests/data/acpi/q35/DSDT.xapic index f47f091222..3aa86f0724 100644 --- a/tests/data/acpi/q35/DSDT.xapic +++ b/tests/data/acpi/q35/DSDT.xapic Binary files differdiff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 665ddde518..bfb0dcac21 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -128,7 +128,6 @@ DOCKER_PARTIAL_IMAGES += debian-mips-cross DOCKER_PARTIAL_IMAGES += debian-nios2-cross DOCKER_PARTIAL_IMAGES += debian-riscv64-test-cross DOCKER_PARTIAL_IMAGES += debian-sh4-cross debian-sparc64-cross -DOCKER_PARTIAL_IMAGES += debian-tricore-cross DOCKER_PARTIAL_IMAGES += debian-xtensa-cross DOCKER_PARTIAL_IMAGES += fedora-cris-cross diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index 094f66f4eb..4a569d82f6 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -77,7 +77,6 @@ RUN apk update && \ numactl-dev \ openssh-client \ pcre-dev \ - perl \ pixman-dev \ pkgconf \ pulseaudio-dev \ @@ -100,7 +99,6 @@ RUN apk update && \ spice-protocol \ tar \ tesseract-ocr \ - texinfo \ usbredir-dev \ util-linux \ vde2-dev \ diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index 1f70d41aeb..fbc953c6dc 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -91,7 +91,6 @@ RUN dnf distro-sync -y && \ openssh-clients \ pam-devel \ pcre-static \ - perl \ pixman-devel \ pkgconfig \ pulseaudio-libs-devel \ @@ -111,7 +110,6 @@ RUN dnf distro-sync -y && \ systemd-devel \ systemtap-sdt-devel \ tar \ - texinfo \ usbredir-devel \ util-linux \ virglrenderer-devel \ diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index 5e57309361..5175095a85 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -56,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index bfeab01ee3..b61f664ea2 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -108,7 +108,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ nettle-dev \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -126,7 +125,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ tar \ tesseract-ocr \ tesseract-ocr-eng \ - texinfo \ xfslibs-dev \ zlib1g-dev && \ eatmydata apt-get autoremove -y && \ diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 98885bd0ee..b69958c69f 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -56,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index d5c08714e4..96b524fab6 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -56,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 471444fcf4..08a75cebdb 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -56,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index 15b0224b76..5930e6fa5d 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -56,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index a5d3ca6e2f..c65d9830e7 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -56,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index d2954e61f6..2ae56c978e 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -56,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index 9715791e0b..3daf93968a 100644 --- a/tests/docker/dockerfiles/debian-riscv64-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker @@ -42,6 +42,7 @@ RUN apt update && \ apt install -y --no-install-recommends \ gcc-riscv64-linux-gnu \ libc6-dev-riscv64-cross \ + libfdt-dev:riscv64 \ libffi-dev:riscv64 \ libglib2.0-dev:riscv64 \ libpixman-1-dev:riscv64 diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index d43ce16317..0db86a0fcd 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -40,7 +40,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ncat \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -56,8 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sparse \ tar \ tesseract-ocr \ - tesseract-ocr-eng \ - texinfo && \ + tesseract-ocr-eng && \ eatmydata apt-get autoremove -y && \ eatmydata apt-get autoclean -y && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ diff --git a/tests/docker/dockerfiles/debian-toolchain.docker b/tests/docker/dockerfiles/debian-toolchain.docker index d3d4d3344e..6c73408b34 100644 --- a/tests/docker/dockerfiles/debian-toolchain.docker +++ b/tests/docker/dockerfiles/debian-toolchain.docker @@ -21,7 +21,6 @@ RUN apt update && \ libmpc-dev \ libmpfr-dev \ rsync \ - texinfo \ wget && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt build-dep -yy --arch-only gcc glibc diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker index b573b9ded2..5ae58efa09 100644 --- a/tests/docker/dockerfiles/debian-tricore-cross.docker +++ b/tests/docker/dockerfiles/debian-tricore-cross.docker @@ -20,6 +20,7 @@ RUN apt update && \ bzip2 \ ca-certificates \ ccache \ + flex \ g++ \ gcc \ git \ @@ -28,7 +29,6 @@ RUN apt update && \ locales \ make \ ninja-build \ - perl-base \ pkgconf \ python3-pip \ python3-setuptools \ diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker index 7eec648d2d..f58b64dc3e 100644 --- a/tests/docker/dockerfiles/fedora-i386-cross.docker +++ b/tests/docker/dockerfiles/fedora-i386-cross.docker @@ -9,6 +9,7 @@ ENV PACKAGES \ findutils \ gcc \ git \ + libfdt-devel.i686 \ libffi-devel.i686 \ libselinux-devel.i686 \ libtasn1-devel.i686 \ diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index 75383ba185..b659c0b8a8 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -1,10 +1,10 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross mingw32 fedora-35 qemu +# $ lcitool dockerfile --layers all --cross mingw32 fedora-37 qemu # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.fedoraproject.org/fedora:35 +FROM registry.fedoraproject.org/fedora:37 RUN dnf install -y nosync && \ echo -e '#!/bin/sh\n\ @@ -42,7 +42,6 @@ exec "$@"' > /usr/bin/nosync && \ nmap-ncat \ openssh-clients \ pcre-static \ - perl-base \ python3 \ python3-PyYAML \ python3-numpy \ @@ -58,7 +57,6 @@ exec "$@"' > /usr/bin/nosync && \ tar \ tesseract \ tesseract-langpack-eng \ - texinfo \ util-linux \ which && \ nosync dnf autoremove -y && \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index 98c03dc13b..0a404c15bf 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -1,10 +1,10 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross mingw64 fedora-35 qemu +# $ lcitool dockerfile --layers all --cross mingw64 fedora-37 qemu # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.fedoraproject.org/fedora:35 +FROM registry.fedoraproject.org/fedora:37 RUN dnf install -y nosync && \ echo -e '#!/bin/sh\n\ @@ -42,7 +42,6 @@ exec "$@"' > /usr/bin/nosync && \ nmap-ncat \ openssh-clients \ pcre-static \ - perl-base \ python3 \ python3-PyYAML \ python3-numpy \ @@ -58,7 +57,6 @@ exec "$@"' > /usr/bin/nosync && \ tar \ tesseract \ tesseract-langpack-eng \ - texinfo \ util-linux \ which && \ nosync dnf autoremove -y && \ diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index d200c7fc10..5d60a96141 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -1,10 +1,10 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all fedora-35 qemu +# $ lcitool dockerfile --layers all fedora-37 qemu # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.fedoraproject.org/fedora:35 +FROM registry.fedoraproject.org/fedora:37 RUN dnf install -y nosync && \ echo -e '#!/bin/sh\n\ @@ -98,7 +98,6 @@ exec "$@"' > /usr/bin/nosync && \ openssh-clients \ pam-devel \ pcre-static \ - perl-base \ pixman-devel \ pkgconfig \ pulseaudio-libs-devel \ @@ -122,7 +121,6 @@ exec "$@"' > /usr/bin/nosync && \ tar \ tesseract \ tesseract-langpack-eng \ - texinfo \ usbredir-devel \ util-linux \ virglrenderer-devel \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index 4361b01464..4b2c02d6ab 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -88,7 +88,6 @@ RUN zypper update -y && \ openssh \ pam-devel \ pcre-devel-static \ - perl-base \ pkgconfig \ python3-Pillow \ python3-PyYAML \ @@ -112,7 +111,6 @@ RUN zypper update -y && \ tar \ tesseract-ocr \ tesseract-ocr-traineddata-english \ - texinfo \ usbredir-devel \ util-linux \ virglrenderer-devel \ diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 9417bca2fa..13ab0b6887 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -105,7 +105,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ nettle-dev \ ninja-build \ openssh-client \ - perl-base \ pkgconf \ python3 \ python3-numpy \ @@ -125,7 +124,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ tar \ tesseract-ocr \ tesseract-ocr-eng \ - texinfo \ xfslibs-dev \ zlib1g-dev && \ eatmydata apt-get autoremove -y && \ diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci -Subproject e3eb28cf2e17fbcf7fe7e19505ee432b8ec5bbb +Subproject 319a534c220f53fc8670254cac25d6f662c8211 diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index c62dbc00f9..6467bcf08a 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -83,7 +83,6 @@ packages: - ncursesw - pam - pcre-static - - perl - pixman - pkg-config - pulseaudio @@ -110,7 +109,6 @@ packages: - tar - tesseract - tesseract-eng - - texinfo - usbredir - virglrenderer - vte diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index fa966e4009..a5ea0efc3b 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -111,7 +111,7 @@ try: generate_dockerfile("centos8", "centos-stream-8") generate_dockerfile("debian-amd64", "debian-11", trailer="".join(debian11_extras)) - generate_dockerfile("fedora", "fedora-35") + generate_dockerfile("fedora", "fedora-37") generate_dockerfile("opensuse-leap", "opensuse-leap-153") generate_dockerfile("ubuntu2004", "ubuntu-2004", trailer="".join(ubuntu2004_tsanhack)) @@ -161,12 +161,12 @@ try: trailer=cross_build("s390x-linux-gnu-", "s390x-softmmu,s390x-linux-user")) - generate_dockerfile("fedora-win32-cross", "fedora-35", + generate_dockerfile("fedora-win32-cross", "fedora-37", cross="mingw32", trailer=cross_build("i686-w64-mingw32-", "i386-softmmu")) - generate_dockerfile("fedora-win64-cross", "fedora-35", + generate_dockerfile("fedora-win64-cross", "fedora-37", cross="mingw64", trailer=cross_build("x86_64-w64-mingw32-", "x86_64-softmmu")) diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index 9dfe98bc9a..d85b14f28c 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -259,22 +259,23 @@ if build_docs # Fix possible inconsistency in line endings in generated output and # in the golden reference (which could otherwise cause test failures # on Windows hosts). Unfortunately diff --strip-trailing-cr - # is GNU-diff only. The odd-looking perl is because we must avoid + # is GNU-diff only. The odd-looking python is because we must avoid # using an explicit '\' character in the command arguments to # a custom_target(), as Meson will unhelpfully replace it with a '/' # (https://github.com/mesonbuild/meson/issues/1564) + remove_cr = [python, '-c', 'import sys;[sys.stdout.write(line.replace(chr(13), "")) for line in sys.stdin]'] qapi_doc_out_nocr = custom_target('QAPI rST doc newline-sanitized', output: ['doc-good.txt.nocr'], input: qapi_doc_out[0], build_by_default: true, - command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'], + command: [remove_cr, '@INPUT@'], capture: true) qapi_doc_ref_nocr = custom_target('QAPI rST doc reference newline-sanitized', output: ['doc-good.ref.nocr'], input: files('doc-good.txt'), build_by_default: true, - command: ['perl', '-pe', '$x = chr 13; s/$x$//', '@INPUT@'], + command: [remove_cr, '@INPUT@'], capture: true) test('QAPI rST doc', diff, args: ['-u', qapi_doc_ref_nocr[0], qapi_doc_out_nocr[0]], diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 8608408213..d8c8cda58e 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -24,7 +24,7 @@ * You will also notice that tests/qtest/bios-tables-test-allowed-diff.h lists * a bunch of files. This is your hint that you need to do the below: * 4. Run - * make check V=1 + * make check V=2 * this will produce a bunch of warnings about differences * beween actual and expected ACPI tables. If you have IASL installed, * they will also be disassembled so you can look at the disassembled @@ -108,6 +108,8 @@ static const char *iasl = CONFIG_IASL; static const char *iasl; #endif +static int verbosity_level; + static bool compare_signature(const AcpiSdtTable *sdt, const char *signature) { return !memcmp(sdt->aml, signature, 4); @@ -368,7 +370,7 @@ static GArray *load_expected_aml(test_data *data) gsize aml_len; GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable)); - if (getenv("V")) { + if (verbosity_level >= 2) { fputc('\n', stderr); } for (i = 0; i < data->tables->len; ++i) { @@ -383,7 +385,7 @@ static GArray *load_expected_aml(test_data *data) try_again: aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine, sdt->aml, ext); - if (getenv("V")) { + if (verbosity_level >= 2) { fprintf(stderr, "Looking for expected file '%s'\n", aml_file); } if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) { @@ -395,7 +397,7 @@ try_again: goto try_again; } g_assert(exp_sdt.aml_file); - if (getenv("V")) { + if (verbosity_level >= 2) { fprintf(stderr, "Using expected file '%s'\n", aml_file); } ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml, @@ -503,7 +505,7 @@ static void test_acpi_asl(test_data *data) exp_sdt->aml, sdt->asl_file, sdt->aml_file, exp_sdt->asl_file, exp_sdt->aml_file); fflush(stderr); - if (getenv("V")) { + if (verbosity_level >= 1) { const char *diff_env = getenv("DIFF"); const char *diff_cmd = diff_env ? diff_env : "diff -U 16"; char *diff = g_strdup_printf("%s %s %s", diff_cmd, @@ -748,9 +750,9 @@ static void test_smbios_structs(test_data *data, SmbiosEntryPointType ep_type) } } -static void test_acpi_load_tables(test_data *data, bool use_uefi) +static void test_acpi_load_tables(test_data *data) { - if (use_uefi) { + if (data->uefi_fl1 && data->uefi_fl2) { /* use UEFI */ g_assert(data->scan_len); data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts, data->ram_start, data->scan_len); @@ -766,12 +768,11 @@ static void test_acpi_load_tables(test_data *data, bool use_uefi) test_acpi_fadt_table(data); } -static char *test_acpi_create_args(test_data *data, const char *params, - bool use_uefi) +static char *test_acpi_create_args(test_data *data, const char *params) { char *args; - if (use_uefi) { + if (data->uefi_fl1 && data->uefi_fl2) { /* use UEFI */ /* * TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3) * when arm/virt boad starts to support it. @@ -806,14 +807,16 @@ static char *test_acpi_create_args(test_data *data, const char *params, return args; } -static void test_acpi_one(const char *params, test_data *data) +static void test_vm_prepare(const char *params, test_data *data) { - char *args; - bool use_uefi = data->uefi_fl1 && data->uefi_fl2; - - args = test_acpi_create_args(data, params, use_uefi); + char *args = test_acpi_create_args(data, params); data->qts = qtest_init(args); - test_acpi_load_tables(data, use_uefi); + g_free(args); +} + +static void process_acpi_tables_noexit(test_data *data) +{ + test_acpi_load_tables(data); if (getenv(ACPI_REBUILD_EXPECTED_AML)) { dump_aml_files(data, true); @@ -826,13 +829,22 @@ static void test_acpi_one(const char *params, test_data *data) * Bug on uefi-test-tools to provide entry point: * https://bugs.launchpad.net/qemu/+bug/1821884 */ - if (!use_uefi) { + if (!(data->uefi_fl1 && data->uefi_fl2)) { SmbiosEntryPointType ep_type = test_smbios_entry_point(data); test_smbios_structs(data, ep_type); } +} +static void process_acpi_tables(test_data *data) +{ + process_acpi_tables_noexit(data); qtest_quit(data->qts); - g_free(args); +} + +static void test_acpi_one(const char *params, test_data *data) +{ + test_vm_prepare(params, data); + process_acpi_tables(data); } static uint8_t base_required_struct_types[] = { @@ -863,7 +875,32 @@ static void test_acpi_piix4_tcg_bridge(void) data.variant = ".bridge"; data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - test_acpi_one("-device pci-bridge,chassis_nr=1", &data); + test_vm_prepare("-S" + " -device pci-bridge,chassis_nr=1" + " -device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2" + " -device pci-testdev,bus=pci.0,addr=5.0" + " -device pci-testdev,bus=pci.1", &data); + + /* hotplugged bridges section */ + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr", + "{'bus': 'pci.1', 'addr': '2.0', 'chassis_nr': 3 }"); + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr_multifunc", + "{'bus': 'pci.1', 'addr': '0xf.1', 'chassis_nr': 4 }"); + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbrhost", + "{'bus': 'pci.0', 'addr': '4.0', 'chassis_nr': 5 }"); + qtest_qmp_device_add(data.qts, "pci-testdev", "d1", "{'bus': 'pci.0' }"); + qtest_qmp_device_add(data.qts, "pci-testdev", "d2", "{'bus': 'pci.1' }"); + qtest_qmp_device_add(data.qts, "pci-testdev", "d3", "{'bus': 'hpbr', " + "'addr': '1.0' }"); + qtest_qmp_send(data.qts, "{'execute':'cont' }"); + qtest_qmp_eventwait(data.qts, "RESUME"); + + process_acpi_tables_noexit(&data); + free_test_data(&data); + + /* check that reboot/reset doesn't change any ACPI tables */ + qtest_qmp_send(data.qts, "{'execute':'system_reset' }"); + process_acpi_tables(&data); free_test_data(&data); } @@ -877,7 +914,10 @@ static void test_acpi_piix4_no_root_hotplug(void) data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off " - "-device pci-bridge,chassis_nr=1", &data); + "-device pci-bridge,chassis_nr=1 " + "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 " + "-device pci-testdev,bus=pci.0 " + "-device pci-testdev,bus=pci.1", &data); free_test_data(&data); } @@ -891,7 +931,10 @@ static void test_acpi_piix4_no_bridge_hotplug(void) data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_acpi_one("-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off " - "-device pci-bridge,chassis_nr=1", &data); + "-device pci-bridge,chassis_nr=1 " + "-device pci-bridge,bus=pci.1,addr=1.0,chassis_nr=2 " + "-device pci-testdev,bus=pci.0 " + "-device pci-testdev,bus=pci.1,addr=2.0", &data); free_test_data(&data); } @@ -906,7 +949,9 @@ static void test_acpi_piix4_no_acpi_pci_hotplug(void) data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off " "-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off " - "-device pci-bridge,chassis_nr=1", &data); + "-device pci-bridge,chassis_nr=1 " + "-device pci-testdev,bus=pci.0 " + "-device pci-testdev,bus=pci.1", &data); free_test_data(&data); } @@ -951,8 +996,9 @@ static void test_acpi_q35_tcg_bridge(void) data.variant = ".bridge"; data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - test_acpi_one("-device pci-bridge,chassis_nr=1", - &data); + test_acpi_one("-device pci-bridge,chassis_nr=1,id=br1" + " -device pci-testdev,bus=pcie.0" + " -device pci-testdev,bus=br1", &data); free_test_data(&data); } @@ -962,14 +1008,41 @@ static void test_acpi_q35_multif_bridge(void) .machine = MACHINE_Q35, .variant = ".multi-bridge", }; - test_acpi_one("-device pcie-root-port,id=pcie-root-port-0," - "multifunction=on," - "port=0x0,chassis=1,addr=0x2,bus=pcie.0 " - "-device pcie-root-port,id=pcie-root-port-1," - "port=0x1,chassis=2,addr=0x3.0x1,bus=pcie.0 " - "-device virtio-balloon,id=balloon0," - "bus=pcie.0,addr=0x4.0x2", - &data); + test_vm_prepare("-S" + " -device virtio-balloon,id=balloon0,addr=0x4.0x2" + " -device pcie-root-port,id=rp0,multifunction=on," + "port=0x0,chassis=1,addr=0x2" + " -device pcie-root-port,id=rp1,port=0x1,chassis=2,addr=0x3.0x1" + " -device pcie-root-port,id=rp2,port=0x0,chassis=3,bus=rp1,addr=0.0" + " -device pci-bridge,bus=rp2,chassis_nr=4,id=br1" + " -device pcie-root-port,id=rphptgt1,port=0x0,chassis=5,addr=2.1" + " -device pcie-root-port,id=rphptgt2,port=0x0,chassis=6,addr=2.2" + " -device pcie-root-port,id=rphptgt3,port=0x0,chassis=7,addr=2.3" + " -device pci-testdev,bus=pcie.0,addr=2.4" + " -device pci-testdev,bus=pcie.0,addr=5.0" + " -device pci-testdev,bus=rp0,addr=0.0" + " -device pci-testdev,bus=br1", &data); + + /* hotplugged bridges section */ + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr1", + "{'bus': 'br1', 'addr': '6.0', 'chassis_nr': 128 }"); + qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr2-multiif", + "{ 'bus': 'br1', 'addr': '2.2', 'chassis_nr': 129 }"); + qtest_qmp_device_add(data.qts, "pcie-pci-bridge", "hpbr3", + "{'bus': 'rphptgt1', 'addr': '0.0' }"); + qtest_qmp_device_add(data.qts, "pcie-root-port", "hprp", + "{'bus': 'rphptgt2', 'addr': '0.0' }"); + qtest_qmp_device_add(data.qts, "pci-testdev", "hpnic", + "{'bus': 'rphptgt3', 'addr': '0.0' }"); + qtest_qmp_send(data.qts, "{'execute':'cont' }"); + qtest_qmp_eventwait(data.qts, "RESUME"); + + process_acpi_tables_noexit(&data); + free_test_data(&data); + + /* check that reboot/reset doesn't change any ACPI tables */ + qtest_qmp_send(data.qts, "{'execute':'system_reset' }"); + process_acpi_tables(&data); free_test_data(&data); } @@ -1898,10 +1971,9 @@ static void test_acpi_piix4_oem_fields(void) data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - args = test_acpi_create_args(&data, - OEM_TEST_ARGS, false); + args = test_acpi_create_args(&data, OEM_TEST_ARGS); data.qts = qtest_init(args); - test_acpi_load_tables(&data, false); + test_acpi_load_tables(&data); test_oem_fields(&data); qtest_quit(data.qts); free_test_data(&data); @@ -1918,10 +1990,9 @@ static void test_acpi_q35_oem_fields(void) data.required_struct_types = base_required_struct_types; data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types); - args = test_acpi_create_args(&data, - OEM_TEST_ARGS, false); + args = test_acpi_create_args(&data, OEM_TEST_ARGS); data.qts = qtest_init(args); - test_acpi_load_tables(&data, false); + test_acpi_load_tables(&data); test_oem_fields(&data); qtest_quit(data.qts); free_test_data(&data); @@ -1936,9 +2007,9 @@ static void test_acpi_microvm_oem_fields(void) test_acpi_microvm_prepare(&data); args = test_acpi_create_args(&data, - OEM_TEST_ARGS",acpi=on", false); + OEM_TEST_ARGS",acpi=on"); data.qts = qtest_init(args); - test_acpi_load_tables(&data, false); + test_acpi_load_tables(&data); test_oem_fields(&data); qtest_quit(data.qts); free_test_data(&data); @@ -1958,10 +2029,9 @@ static void test_acpi_virt_oem_fields(void) }; char *args; - args = test_acpi_create_args(&data, - "-cpu cortex-a57 "OEM_TEST_ARGS, true); + args = test_acpi_create_args(&data, "-cpu cortex-a57 "OEM_TEST_ARGS); data.qts = qtest_init(args); - test_acpi_load_tables(&data, true); + test_acpi_load_tables(&data); test_oem_fields(&data); qtest_quit(data.qts); free_test_data(&data); @@ -1974,8 +2044,13 @@ int main(int argc, char *argv[]) const char *arch = qtest_get_arch(); const bool has_kvm = qtest_has_accel("kvm"); const bool has_tcg = qtest_has_accel("tcg"); + char *v_env = getenv("V"); int ret; + if (v_env) { + verbosity_level = atoi(v_env); + } + g_test_init(&argc, &argv, NULL); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { diff --git a/tests/qtest/boot-sector.c b/tests/qtest/boot-sector.c index 44a109abd8..679ee17e2a 100644 --- a/tests/qtest/boot-sector.c +++ b/tests/qtest/boot-sector.c @@ -153,6 +153,8 @@ void boot_sector_test(QTestState *qts) signature_high = qtest_readb(qts, SIGNATURE_ADDR + 1); signature = (signature_high << 8) | signature_low; if (signature == SIGNATURE) { + /* wipe signature */ + qtest_writeb(qts, SIGNATURE_ADDR, 0x00); break; } @@ -160,7 +162,9 @@ void boot_sector_test(QTestState *qts) qrsp = qtest_qmp(qts, "{ 'execute': 'query-status' }"); qret = qdict_get_qdict(qrsp, "return"); g_assert_nonnull(qret); - g_assert_cmpstr(qdict_get_try_str(qret, "status"), ==, "running"); + if (qdict_get_try_str(qret, "status")) { + g_assert_cmpstr(qdict_get_try_str(qret, "status"), ==, "running"); + } qobject_unref(qrsp); g_usleep(TEST_DELAY); diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c index b216519b62..3aef3a97a9 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -139,7 +139,7 @@ typedef struct testdef { const uint8_t *bios; /* Set in case we use our own mini bios */ } testdef_t; -static testdef_t tests[] = { +static const testdef_t tests[] = { { "alpha", "clipper", "", "PCI:" }, { "avr", "arduino-duemilanove", "", "T", sizeof(bios_avr), NULL, bios_avr }, { "avr", "arduino-mega-2560-v3", "", "T", sizeof(bios_avr), NULL, bios_avr}, diff --git a/tests/qtest/display-vga-test.c b/tests/qtest/display-vga-test.c index ace3bb28e0..75b341a9c6 100644 --- a/tests/qtest/display-vga-test.c +++ b/tests/qtest/display-vga-test.c @@ -8,61 +8,46 @@ */ #include "qemu/osdep.h" -#include "libqtest-single.h" - -static void pci_cirrus(void) -{ - qtest_start("-vga none -device cirrus-vga"); - qtest_end(); -} - -static void pci_stdvga(void) -{ - qtest_start("-vga none -device VGA"); - qtest_end(); -} - -static void pci_secondary(void) -{ - qtest_start("-vga none -device secondary-vga"); - qtest_end(); -} +#include "libqtest.h" static void pci_multihead(void) { - qtest_start("-vga none -device VGA -device secondary-vga"); - qtest_end(); -} + QTestState *qts; -static void pci_virtio_gpu(void) -{ - qtest_start("-vga none -device virtio-gpu-pci"); - qtest_end(); + qts = qtest_init("-vga none -device VGA -device secondary-vga"); + qtest_quit(qts); } -static void pci_virtio_vga(void) +static void test_vga(gconstpointer data) { - qtest_start("-vga none -device virtio-vga"); - qtest_end(); + QTestState *qts; + + qts = qtest_initf("-vga none -device %s", (const char *)data); + qtest_quit(qts); } int main(int argc, char **argv) { - const char *arch = qtest_get_arch(); + static const char *devices[] = { + "cirrus-vga", + "VGA", + "secondary-vga", + "virtio-gpu-pci", + "virtio-vga" + }; g_test_init(&argc, &argv, NULL); - if (strcmp(arch, "alpha") == 0 || strcmp(arch, "i386") == 0 || - strcmp(arch, "mips") == 0 || strcmp(arch, "x86_64") == 0) { - qtest_add_func("/display/pci/cirrus", pci_cirrus); + for (int i = 0; i < ARRAY_SIZE(devices); i++) { + if (qtest_has_device(devices[i])) { + char *testpath = g_strdup_printf("/display/pci/%s", devices[i]); + qtest_add_data_func(testpath, devices[i], test_vga); + g_free(testpath); + } } - qtest_add_func("/display/pci/stdvga", pci_stdvga); - qtest_add_func("/display/pci/secondary", pci_secondary); - qtest_add_func("/display/pci/multihead", pci_multihead); - qtest_add_func("/display/pci/virtio-gpu", pci_virtio_gpu); - if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") || - g_str_equal(arch, "hppa") || g_str_equal(arch, "ppc64")) { - qtest_add_func("/display/pci/virtio-vga", pci_virtio_vga); + + if (qtest_has_device("secondary-vga")) { + qtest_add_func("/display/pci/multihead", pci_multihead); } return g_test_run(); diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 6b2216cb20..d658222a19 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -1435,6 +1435,10 @@ void qtest_qmp_device_add_qdict(QTestState *qts, const char *drv, resp = qtest_qmp(qts, "{'execute': 'device_add', 'arguments': %p}", args); g_assert(resp); g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */ + if (qdict_haskey(resp, "error")) { + fprintf(stderr, "error: %s\n", + qdict_get_str(qdict_get_qdict(resp, "error"), "desc")); + } g_assert(!qdict_haskey(resp, "error")); qobject_unref(resp); } diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 1af63f8bd2..e97616d327 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -21,6 +21,7 @@ qtests_generic = [ 'test-hmp', 'qos-test', 'readconfig-test', + 'netdev-socket', ] if config_host.has_key('CONFIG_MODULES') qtests_generic += [ 'modules-test' ] @@ -298,6 +299,7 @@ qtests = { 'tpm-tis-device-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'], 'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'], 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'), + 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), } gvnc = dependency('gvnc-1.0', required: false) diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c new file mode 100644 index 0000000000..6ba256e173 --- /dev/null +++ b/tests/qtest/netdev-socket.c @@ -0,0 +1,448 @@ +/* + * QTest testcase for netdev stream and dgram + * + * Copyright (c) 2022 Red Hat, Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/sockets.h" +#include <glib/gstdio.h> +#include "../unit/socket-helpers.h" +#include "libqtest.h" + +#define CONNECTION_TIMEOUT 5 + +#define EXPECT_STATE(q, e, t) \ +do { \ + char *resp = NULL; \ + g_test_timer_start(); \ + do { \ + g_free(resp); \ + resp = qtest_hmp(q, "info network"); \ + if (t) { \ + strrchr(resp, t)[0] = 0; \ + } \ + if (g_str_equal(resp, e)) { \ + break; \ + } \ + } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \ + g_assert_cmpstr(resp, ==, e); \ + g_free(resp); \ +} while (0) + +static gchar *tmpdir; + +static int inet_get_free_port_socket_ipv4(int sock) +{ + struct sockaddr_in addr; + socklen_t len; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = 0; + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return -1; + } + + len = sizeof(addr); + if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) { + return -1; + } + + return ntohs(addr.sin_port); +} + +static int inet_get_free_port_socket_ipv6(int sock) +{ + struct sockaddr_in6 addr; + socklen_t len; + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = 0; + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return -1; + } + + len = sizeof(addr); + if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) { + return -1; + } + + return ntohs(addr.sin6_port); +} + +static int inet_get_free_port_multiple(int nb, int *port, bool ipv6) +{ + int sock[nb]; + int i; + + for (i = 0; i < nb; i++) { + sock[i] = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); + if (sock[i] < 0) { + break; + } + port[i] = ipv6 ? inet_get_free_port_socket_ipv6(sock[i]) : + inet_get_free_port_socket_ipv4(sock[i]); + if (port[i] == -1) { + break; + } + } + + nb = i; + for (i = 0; i < nb; i++) { + closesocket(sock[i]); + } + + return nb; +} + +static int inet_get_free_port(bool ipv6) +{ + int nb, port; + + nb = inet_get_free_port_multiple(1, &port, ipv6); + g_assert_cmpint(nb, ==, 1); + + return port; +} + +static void test_stream_inet_ipv4(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port; + + port = inet_get_free_port(false); + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off," + "addr.host=127.0.0.1,addr.port=%d", port); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,server=false,id=st0,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off," + "addr.host=127.0.0.1,addr.port=%d", port); + + expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n", + port); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + /* the port is unknown, check only the address */ + EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':'); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_stream_inet_ipv6(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port; + + port = inet_get_free_port(true); + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true,addr.type=inet," + "addr.ipv4=off,addr.ipv6=on," + "addr.host=::1,addr.port=%d", port); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,server=false,id=st0,addr.type=inet," + "addr.ipv4=off,addr.ipv6=on," + "addr.host=::1,addr.port=%d", port); + + expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n", + port); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + /* the port is unknown, check only the address */ + EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':'); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_stream_unix(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path; + + path = g_strconcat(tmpdir, "/stream_unix", NULL); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true," + "addr.type=unix,addr.path=%s,", + path); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=false," + "addr.type=unix,addr.path=%s", + path); + + expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); + EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + g_free(path); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +#ifdef CONFIG_LINUX +static void test_stream_unix_abstract(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path; + + path = g_strconcat(tmpdir, "/stream_unix_abstract", NULL); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=true," + "addr.type=unix,addr.path=%s," + "addr.abstract=on", + path); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,server=false," + "addr.type=unix,addr.path=%s,addr.abstract=on", + path); + + expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); + EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + g_free(path); + + qtest_quit(qts1); + qtest_quit(qts0); +} +#endif + +#ifndef _WIN32 +static void test_stream_fd(void) +{ + QTestState *qts0, *qts1; + int sock[2]; + int ret; + + ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, sock); + g_assert_true(ret == 0); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,addr.type=fd,addr.str=%d", + sock[0]); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev stream,id=st0,addr.type=fd,addr.str=%d", + sock[1]); + + EXPECT_STATE(qts1, "st0: index=0,type=stream,unix:\r\n", 0); + EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0); + + qtest_quit(qts1); + qtest_quit(qts0); + + closesocket(sock[0]); + closesocket(sock[1]); +} +#endif + +static void test_dgram_inet(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port[2]; + int nb; + + nb = inet_get_free_port_multiple(2, port, false); + g_assert_cmpint(nb, ==, 2); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0," + "local.type=inet,local.host=127.0.0.1,local.port=%d," + "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", + port[0], port[1]); + + expect = g_strdup_printf("st0: index=0,type=dgram," + "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + port[0], port[1]); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0," + "local.type=inet,local.host=127.0.0.1,local.port=%d," + "remote.type=inet,remote.host=127.0.0.1,remote.port=%d", + port[1], port[0]); + + expect = g_strdup_printf("st0: index=0,type=dgram," + "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + port[1], port[0]); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +#ifndef _WIN32 +static void test_dgram_mcast(void) +{ + QTestState *qts; + + qts = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0," + "remote.type=inet,remote.host=230.0.0.1,remote.port=1234"); + + EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0); + + qtest_quit(qts); +} + +static void test_dgram_unix(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path0, *path1; + + path0 = g_strconcat(tmpdir, "/dgram_unix0", NULL); + path1 = g_strconcat(tmpdir, "/dgram_unix1", NULL); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0,local.type=unix,local.path=%s," + "remote.type=unix,remote.path=%s", + path0, path1); + + expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", + path0, path1); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0,local.type=unix,local.path=%s," + "remote.type=unix,remote.path=%s", + path1, path0); + + + expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", + path1, path0); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + unlink(path0); + g_free(path0); + unlink(path1); + g_free(path1); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_dgram_fd(void) +{ + QTestState *qts0, *qts1; + char *expect; + int ret; + int sv[2]; + + ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, sv); + g_assert_cmpint(ret, !=, -1); + + qts0 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0,local.type=fd,local.str=%d", + sv[0]); + + expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults -M none " + "-netdev dgram,id=st0,local.type=fd,local.str=%d", + sv[1]); + + + expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + qtest_quit(qts1); + qtest_quit(qts0); + + closesocket(sv[0]); + closesocket(sv[1]); +} +#endif + +int main(int argc, char **argv) +{ + int ret; + bool has_ipv4, has_ipv6, has_afunix; + g_autoptr(GError) err = NULL; + + socket_init(); + g_test_init(&argc, &argv, NULL); + + if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { + g_error("socket_check_protocol_support() failed\n"); + } + + tmpdir = g_dir_make_tmp("netdev-socket.XXXXXX", &err); + if (tmpdir == NULL) { + g_error("Can't create temporary directory in %s: %s", + g_get_tmp_dir(), err->message); + } + + if (has_ipv4) { + qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4); + qtest_add_func("/netdev/dgram/inet", test_dgram_inet); +#ifndef _WIN32 + qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast); +#endif + } + if (has_ipv6) { + qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6); + } + + socket_check_afunix_support(&has_afunix); + if (has_afunix) { +#ifndef _WIN32 + qtest_add_func("/netdev/dgram/unix", test_dgram_unix); +#endif + qtest_add_func("/netdev/stream/unix", test_stream_unix); +#ifdef CONFIG_LINUX + qtest_add_func("/netdev/stream/unix/abstract", + test_stream_unix_abstract); +#endif +#ifndef _WIN32 + qtest_add_func("/netdev/stream/fd", test_stream_fd); + qtest_add_func("/netdev/dgram/fd", test_dgram_fd); +#endif + } + + ret = g_test_run(); + + g_rmdir(tmpdir); + g_free(tmpdir); + + return ret; +} diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c index d380261f8f..d677f87c8e 100644 --- a/tests/qtest/qom-test.c +++ b/tests/qtest/qom-test.c @@ -14,7 +14,7 @@ #include "qemu/cutils.h" #include "libqtest.h" -static bool verbose; +static int verbosity_level; static void test_properties(QTestState *qts, const char *path, bool recurse) { @@ -24,7 +24,9 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) QListEntry *entry; GSList *children = NULL, *links = NULL; - g_test_message("Obtaining properties of %s", path); + if (verbosity_level >= 2) { + g_test_message("Obtaining properties of %s", path); + } response = qtest_qmp(qts, "{ 'execute': 'qom-list'," " 'arguments': { 'path': %s } }", path); g_assert(response); @@ -51,7 +53,7 @@ static void test_properties(QTestState *qts, const char *path, bool recurse) } } else { const char *prop = qdict_get_str(tuple, "name"); - if (verbose) { + if (verbosity_level >= 3) { g_test_message("-> %s", prop); } tmp = qtest_qmp(qts, @@ -109,8 +111,8 @@ int main(int argc, char **argv) { char *v_env = getenv("V"); - if (v_env && atoi(v_env) >= 2) { - verbose = true; + if (v_env) { + verbosity_level = atoi(v_env); } g_test_init(&argc, &argv, NULL); diff --git a/tests/qtest/vnc-display-test.c b/tests/qtest/vnc-display-test.c index e2a9d682bb..e52a4326ec 100644 --- a/tests/qtest/vnc-display-test.c +++ b/tests/qtest/vnc-display-test.c @@ -19,6 +19,8 @@ typedef struct Test { GMainLoop *loop; } Test; +#if !defined(WIN32) && !defined(CONFIG_DARWIN) + static void on_vnc_error(VncConnection* self, const char* msg) { @@ -31,16 +33,21 @@ static void on_vnc_auth_failure(VncConnection *self, g_error("vnc-auth-failure: %s", msg); } +#endif + static bool test_setup(Test *test) { #ifdef WIN32 g_test_skip("Not supported on Windows yet"); return false; +#elif defined(CONFIG_DARWIN) + g_test_skip("Broken on Darwin"); + return false; #else int pair[2]; - test->qts = qtest_init("-vnc none -name vnc-test"); + test->qts = qtest_init("-M none -vnc none -name vnc-test"); g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0); diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index 14bc013181..a3b0aaf8af 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -54,10 +54,10 @@ cc-option = if $(call cc-test, $1); then \ # $1 = test name, $2 = cmd, $3 = desc ifeq ($(filter %-softmmu, $(TARGET)),) -run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2 > $1.out, \ +run-test = $(call quiet-command, timeout -s KILL --foreground $(TIMEOUT) $2 > $1.out, \ TEST,$(or $3, $*, $<) on $(TARGET_NAME)) else -run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2, \ +run-test = $(call quiet-command, timeout -s KILL --foreground $(TIMEOUT) $2, \ TEST,$(or $3, $*, $<) on $(TARGET_NAME)) endif diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target index a1368905f5..df9747bae8 100644 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ b/tests/tcg/aarch64/Makefile.softmmu-target @@ -36,6 +36,13 @@ config-cc.mak: Makefile memory: CFLAGS+=-DCHECK_UNALIGNED=1 +memory-sve: memory.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) + +memory-sve: CFLAGS+=-DCHECK_UNALIGNED=1 -march=armv8.1-a+sve -O3 -fno-tree-loop-distribute-patterns + +TESTS+=memory-sve + # Running QEMU_BASE_MACHINE=-M virt -cpu max -display none QEMU_OPTS+=$(QEMU_BASE_MACHINE) -semihosting-config enable=on,target=native,chardev=output -kernel diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S index e190b1efa6..f136363d2a 100644 --- a/tests/tcg/aarch64/system/boot.S +++ b/tests/tcg/aarch64/system/boot.S @@ -179,12 +179,13 @@ __start: isb /* - * Enable FP registers. The standard C pre-amble will be + * Enable FP/SVE registers. The standard C pre-amble will be * saving these and A-profile compilers will use AdvSIMD * registers unless we tell it not to. */ mrs x0, cpacr_el1 orr x0, x0, #(3 << 20) + orr x0, x0, #(3 << 16) msr cpacr_el1, x0 /* Setup some stack space and enter the test code. diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index e7213af492..ae8b3d7268 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -42,6 +42,15 @@ munmap-pthread: LDFLAGS+=-pthread vma-pthread: CFLAGS+=-pthread vma-pthread: LDFLAGS+=-pthread +# The vma-pthread seems very sensitive on gitlab and we currently +# don't know if its exposing a real bug or the test is flaky. +ifneq ($(GITLAB_CI),) +run-vma-pthread: vma-pthread + $(call skip-test, $<, "flaky on CI?") +run-plugin-vma-pthread-with-%: vma-pthread + $(call skip-test, $<, "flaky on CI?") +endif + # We define the runner for test-mmap after the individual # architectures have defined their supported pages sizes. If no # additional page sizes are defined we only run the default test. diff --git a/tests/unit/test-io-channel-command.c b/tests/unit/test-io-channel-command.c index 19f72eab96..425e2f5594 100644 --- a/tests/unit/test-io-channel-command.c +++ b/tests/unit/test-io-channel-command.c @@ -20,6 +20,8 @@ #include "qemu/osdep.h" #include <glib/gstdio.h> +#include <sys/types.h> +#include <sys/stat.h> #include "io/channel-command.h" #include "io-channel-helpers.h" #include "qapi/error.h" @@ -29,6 +31,7 @@ static char *socat = NULL; +#ifndef _WIN32 static void test_io_channel_command_fifo(bool async) { g_autofree gchar *tmpdir = g_dir_make_tmp("qemu-test-io-channel.XXXXXX", NULL); @@ -40,12 +43,13 @@ static void test_io_channel_command_fifo(bool async) QIOChannel *src, *dst; QIOChannelTest *test; + if (mkfifo(fifo, 0600)) { + g_error("mkfifo: %s", strerror(errno)); + } + src = QIO_CHANNEL(qio_channel_command_new_spawn((const char **) srcargv, O_WRONLY, &error_abort)); - /* try to avoid a race to create the socket */ - g_usleep(1000); - dst = QIO_CHANNEL(qio_channel_command_new_spawn((const char **) dstargv, O_RDONLY, &error_abort)); @@ -60,7 +64,6 @@ static void test_io_channel_command_fifo(bool async) g_rmdir(tmpdir); } - static void test_io_channel_command_fifo_async(void) { if (!socat) { @@ -80,6 +83,7 @@ static void test_io_channel_command_fifo_sync(void) test_io_channel_command_fifo(false); } +#endif static void test_io_channel_command_echo(bool async) @@ -124,10 +128,12 @@ int main(int argc, char **argv) socat = g_find_program_in_path("socat"); +#ifndef _WIN32 g_test_add_func("/io/channel/command/fifo/sync", test_io_channel_command_fifo_sync); g_test_add_func("/io/channel/command/fifo/async", test_io_channel_command_fifo_async); +#endif g_test_add_func("/io/channel/command/echo/sync", test_io_channel_command_echo_sync); g_test_add_func("/io/channel/command/echo/async", diff --git a/tests/vm/centos.aarch64 b/tests/vm/centos.aarch64 index 2de7ef6992..3f58de1e64 100755 --- a/tests/vm/centos.aarch64 +++ b/tests/vm/centos.aarch64 @@ -28,7 +28,7 @@ DEFAULT_CONFIG = { "dnf config-manager --set-enabled powertools, " "dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo, " "dnf install -y make ninja-build git python38 gcc gcc-c++ flex bison "\ - "glib2-devel perl pixman-devel zlib-devel docker-ce.aarch64, " + "glib2-devel pixman-devel zlib-devel docker-ce.aarch64, " "systemctl enable docker, " ), # We increase beyond the default time since during boot diff --git a/util/aio-posix.c b/util/aio-posix.c index 731f3826c0..6cc6256d53 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -585,18 +585,16 @@ static bool try_poll_mode(AioContext *ctx, AioHandlerList *ready_list, max_ns = qemu_soonest_timeout(*timeout, ctx->poll_ns); if (max_ns && !ctx->fdmon_ops->need_wait(ctx)) { + /* + * Enable poll mode. It pairs with the poll_set_started() in + * aio_poll() which disables poll mode. + */ poll_set_started(ctx, ready_list, true); if (run_poll_handlers(ctx, ready_list, max_ns, timeout)) { return true; } } - - if (poll_set_started(ctx, ready_list, false)) { - *timeout = 0; - return true; - } - return false; } @@ -657,6 +655,17 @@ bool aio_poll(AioContext *ctx, bool blocking) * system call---a single round of run_poll_handlers_once suffices. */ if (timeout || ctx->fdmon_ops->need_wait(ctx)) { + /* + * Disable poll mode. poll mode should be disabled before the call + * of ctx->fdmon_ops->wait() so that guest's notification can wake + * up IO threads when some work becomes pending. It is essential to + * avoid hangs or unnecessary latency. + */ + if (poll_set_started(ctx, &ready_list, false)) { + timeout = 0; + progress = true; + } + ctx->fdmon_ops->wait(ctx, &ready_list, timeout); } diff --git a/util/qht.c b/util/qht.c index 065fc501f4..92c6b78759 100644 --- a/util/qht.c +++ b/util/qht.c @@ -151,6 +151,22 @@ struct qht_bucket { QEMU_BUILD_BUG_ON(sizeof(struct qht_bucket) > QHT_BUCKET_ALIGN); +/* + * Under TSAN, we use striped locks instead of one lock per bucket chain. + * This avoids crashing under TSAN, since TSAN aborts the program if more than + * 64 locks are held (this is a hardcoded limit in TSAN). + * When resizing a QHT we grab all the buckets' locks, which can easily + * go over TSAN's limit. By using striped locks, we avoid this problem. + * + * Note: this number must be a power of two for easy index computation. + */ +#define QHT_TSAN_BUCKET_LOCKS_BITS 4 +#define QHT_TSAN_BUCKET_LOCKS (1 << QHT_TSAN_BUCKET_LOCKS_BITS) + +struct qht_tsan_lock { + QemuSpin lock; +} QEMU_ALIGNED(QHT_BUCKET_ALIGN); + /** * struct qht_map - structure to track an array of buckets * @rcu: used by RCU. Keep it as the top field in the struct to help valgrind @@ -160,6 +176,7 @@ QEMU_BUILD_BUG_ON(sizeof(struct qht_bucket) > QHT_BUCKET_ALIGN); * @n_added_buckets: number of added (i.e. "non-head") buckets * @n_added_buckets_threshold: threshold to trigger an upward resize once the * number of added buckets surpasses it. + * @tsan_bucket_locks: Array of striped locks to be used only under TSAN. * * Buckets are tracked in what we call a "map", i.e. this structure. */ @@ -169,6 +186,9 @@ struct qht_map { size_t n_buckets; size_t n_added_buckets; size_t n_added_buckets_threshold; +#ifdef CONFIG_TSAN + struct qht_tsan_lock tsan_bucket_locks[QHT_TSAN_BUCKET_LOCKS]; +#endif }; /* trigger a resize when n_added_buckets > n_buckets / div */ @@ -229,10 +249,56 @@ static inline size_t qht_elems_to_buckets(size_t n_elems) return pow2ceil(n_elems / QHT_BUCKET_ENTRIES); } -static inline void qht_head_init(struct qht_bucket *b) +/* + * When using striped locks (i.e. under TSAN), we have to be careful not + * to operate on the same lock twice (e.g. when iterating through all buckets). + * We achieve this by operating only on each stripe's first matching lock. + */ +static inline void qht_do_if_first_in_stripe(struct qht_map *map, + struct qht_bucket *b, + void (*func)(QemuSpin *spin)) +{ +#ifdef CONFIG_TSAN + unsigned long bucket_idx = b - map->buckets; + bool is_first_in_stripe = (bucket_idx >> QHT_TSAN_BUCKET_LOCKS_BITS) == 0; + if (is_first_in_stripe) { + unsigned long lock_idx = bucket_idx & (QHT_TSAN_BUCKET_LOCKS - 1); + func(&map->tsan_bucket_locks[lock_idx].lock); + } +#else + func(&b->lock); +#endif +} + +static inline void qht_bucket_lock_do(struct qht_map *map, + struct qht_bucket *b, + void (*func)(QemuSpin *lock)) +{ +#ifdef CONFIG_TSAN + unsigned long bucket_idx = b - map->buckets; + unsigned long lock_idx = bucket_idx & (QHT_TSAN_BUCKET_LOCKS - 1); + func(&map->tsan_bucket_locks[lock_idx].lock); +#else + func(&b->lock); +#endif +} + +static inline void qht_bucket_lock(struct qht_map *map, + struct qht_bucket *b) +{ + qht_bucket_lock_do(map, b, qemu_spin_lock); +} + +static inline void qht_bucket_unlock(struct qht_map *map, + struct qht_bucket *b) +{ + qht_bucket_lock_do(map, b, qemu_spin_unlock); +} + +static inline void qht_head_init(struct qht_map *map, struct qht_bucket *b) { memset(b, 0, sizeof(*b)); - qemu_spin_init(&b->lock); + qht_do_if_first_in_stripe(map, b, qemu_spin_init); seqlock_init(&b->sequence); } @@ -250,7 +316,7 @@ static void qht_map_lock_buckets(struct qht_map *map) for (i = 0; i < map->n_buckets; i++) { struct qht_bucket *b = &map->buckets[i]; - qemu_spin_lock(&b->lock); + qht_do_if_first_in_stripe(map, b, qemu_spin_lock); } } @@ -261,7 +327,7 @@ static void qht_map_unlock_buckets(struct qht_map *map) for (i = 0; i < map->n_buckets; i++) { struct qht_bucket *b = &map->buckets[i]; - qemu_spin_unlock(&b->lock); + qht_do_if_first_in_stripe(map, b, qemu_spin_unlock); } } @@ -308,7 +374,7 @@ void qht_map_lock_buckets__no_stale(struct qht *ht, struct qht_map **pmap) * Get a head bucket and lock it, making sure its parent map is not stale. * @pmap is filled with a pointer to the bucket's parent map. * - * Unlock with qemu_spin_unlock(&b->lock). + * Unlock with qht_bucket_unlock. * * Note: callers cannot have ht->lock held. */ @@ -322,18 +388,18 @@ struct qht_bucket *qht_bucket_lock__no_stale(struct qht *ht, uint32_t hash, map = qatomic_rcu_read(&ht->map); b = qht_map_to_bucket(map, hash); - qemu_spin_lock(&b->lock); + qht_bucket_lock(map, b); if (likely(!qht_map_is_stale__locked(ht, map))) { *pmap = map; return b; } - qemu_spin_unlock(&b->lock); + qht_bucket_unlock(map, b); /* we raced with a resize; acquire ht->lock to see the updated ht->map */ qht_lock(ht); map = ht->map; b = qht_map_to_bucket(map, hash); - qemu_spin_lock(&b->lock); + qht_bucket_lock(map, b); qht_unlock(ht); *pmap = map; return b; @@ -345,12 +411,13 @@ static inline bool qht_map_needs_resize(const struct qht_map *map) map->n_added_buckets_threshold; } -static inline void qht_chain_destroy(const struct qht_bucket *head) +static inline void qht_chain_destroy(struct qht_map *map, + struct qht_bucket *head) { struct qht_bucket *curr = head->next; struct qht_bucket *prev; - qemu_spin_destroy(&head->lock); + qht_do_if_first_in_stripe(map, head, qemu_spin_destroy); while (curr) { prev = curr; curr = curr->next; @@ -364,7 +431,7 @@ static void qht_map_destroy(struct qht_map *map) size_t i; for (i = 0; i < map->n_buckets; i++) { - qht_chain_destroy(&map->buckets[i]); + qht_chain_destroy(map, &map->buckets[i]); } qemu_vfree(map->buckets); g_free(map); @@ -390,7 +457,7 @@ static struct qht_map *qht_map_create(size_t n_buckets) map->buckets = qemu_memalign(QHT_BUCKET_ALIGN, sizeof(*map->buckets) * n_buckets); for (i = 0; i < n_buckets; i++) { - qht_head_init(&map->buckets[i]); + qht_head_init(map, &map->buckets[i]); } return map; } @@ -638,7 +705,7 @@ bool qht_insert(struct qht *ht, void *p, uint32_t hash, void **existing) b = qht_bucket_lock__no_stale(ht, hash, &map); prev = qht_insert__locked(ht, map, b, p, hash, &needs_resize); qht_bucket_debug__locked(b); - qemu_spin_unlock(&b->lock); + qht_bucket_unlock(map, b); if (unlikely(needs_resize) && ht->mode & QHT_MODE_AUTO_RESIZE) { qht_grow_maybe(ht); @@ -688,7 +755,7 @@ static inline void qht_bucket_remove_entry(struct qht_bucket *orig, int pos) int i; if (qht_entry_is_last(orig, pos)) { - orig->hashes[pos] = 0; + qatomic_set(&orig->hashes[pos], 0); qatomic_set(&orig->pointers[pos], NULL); return; } @@ -749,7 +816,7 @@ bool qht_remove(struct qht *ht, const void *p, uint32_t hash) b = qht_bucket_lock__no_stale(ht, hash, &map); ret = qht_remove__locked(b, p, hash); qht_bucket_debug__locked(b); - qemu_spin_unlock(&b->lock); + qht_bucket_unlock(map, b); return ret; } |