From 8580eee820f21a743fa4c5edddac6f3f0fce8b7b Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Mon, 2 Dec 2024 19:42:05 +0000 Subject: [PATCH] [RFC PATCH v3 00/11] tcg-plugins: add hooks for discontinuities https://lore.kernel.org/qemu-devel/cover.1733063076.git.neither@nut.email --- From: Julian Ganz To: qemu-devel@nongnu.org Cc: Julian Ganz Subject: [RFC PATCH v3 00/11] tcg-plugins: add hooks for discontinuities Date: Mon, 2 Dec 2024 20:26:41 +0100 Message-ID: X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Rspamd-Bar: - X-Rspamd-Report: MID_CONTAINS_FROM(1) BAYES_HAM(-3) MIME_GOOD(-0.1) R_MISSING_CHARSET(0.5) X-Rspamd-Score: -1.6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=nut.email; s=uberspace; h=from:to:cc:subject:date; bh=lhp/MzIhcQwQgKNSdC0sX2veCqSwD9bp274LH0tKfMo=; b=C+hLkkvZSYegywm++I5e4yctqswLk6sFQPI6z+7ebske4ee+HnD0d5tgbVAjQElL4f8LLFGGwE bL0Hn9yc9wYy++k8J4RGbD5YW2ZsWjhu+vAE90s2yd8UlMglpQJPdcl2QqlqCfB9LqS3kii29SPp VYrPYb4KYXmp5IYlTuZeBtynLViye83kdVd6OVjIGsiOVmg+hg4nQBd2PJEio0M3AVRUQ0zf0wEQ RO8Cl1FMElhPk9FpltLEU+vo8e6de+zx3g4EJiSYcsd0fdtoaZP16NwLud9kjigY2ED8m5ffnPQ4 B3VTxo/6oHvR1c3X50pMUdRDPr5IvhK+4zuUKFFL9hyV6ddWPOGvqrDGlVkTaCcaM0XOyZ9a/E6B ULNQ8ZgH5VaD8vVgtygwZDOn87dbCbX6KKgrvkYFTddGTt+zyWK9keS2e/unZtRhLi3p0sB3HAF9 X05KYn48624+OXnUeIXbI4Xq1DXUCP0LAB2Wi8Z1yyU6sSpV/X44x8feenYG1WYkfrHJ0nBiVrc9 l/5Dsfw5qtRi+9IRcd5ySczAVhgCyuhF1jervJiCk571g2CTTtEqGkRFkqFjqAzT0owzRM90qwHF CyJ5in4adhTFOtd3XhaBLsuT5YO6bgVkXfrQZIhxiuktV/jHMY3QE+cGiWBQfFGL5yiBw8lscafg U= Received-SPF: pass client-ip=2a00:d0c0:200:0:1c7b:a6ff:fee0:8ea4; envelope-from=neither@nut.email; helo=mailgate02.uberspace.is X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Some analysis greatly benefits, or depends on, information about certain types of dicontinuities such as interrupts. For example, we may need to handle the execution of a new translation block differently if it is not the result of normal program flow but of an interrupt. Even with the existing interfaces, it is more or less possible to discern these situations, e.g. as done by the cflow plugin. However, this process poses a considerable overhead to the core analysis one may intend to perform. These changes introduce a generic and easy-to-use interface for plugin authors in the form of a callback for discontinuities. Patch 1 defines an enumeration of some trap-related discontinuities including somewhat narrow definitions of the discontinuity evetns and a callback type. Patch 2 defines the callback registration function. Patch 3 adds some hooks for triggering the callbacks. Patch 4 adds an example plugin showcasing the new API. Patches 5 through 6 call the hooks for a selection of architectures, mapping architecture specific events to the three categories defined in patch 1. Future non-RFC patchsets will call these hooks for all architectures (that have some concept of trap or interrupt). Finally, patch 11 supplies a test plugin asserting that the next PC provided to the plugin points to the next instruction executed. Sidenote: I'm likely doing something wrong for one architecture or the other. These patches are untested for most of them. Since v2 (tcg-plugins: add hooks for interrupts, exceptions and traps): - Switched from traps as core concept to more generic discontinuities - Switched from semihosting to hostcall as term for emulated traps - Added enumeration of events and dedicated callback type - Make callback receive event type as well as origin and target PC (as requested by Pierrick Bouvier) - Combined registration functions for different traps into a single one for all types of discontinuities (as requested by Pierrick Bouvier) - Migrated records in example plugin from fully pre-allocated to a scoreboard (as suggested by Pierrick Bouvier) - Handle PSCI calls as hostcall (as pointed out by Peter Maydell) - Added hooks for ARM Cortex M arches (as pointed out by Peter Maydell) - Added hooks for Alpha targets - Added hooks for MIPS targets - Added a plugin for testing some of the interface behaviour Since v1: - Split the one callback into multiple callbacks - Added a target-agnostic definition of the relevant event(s) - Call hooks from architecture-code rather than accel/tcg/cpu-exec.c - Added a plugin showcasing API usage Julian Ganz (11): plugins: add types for callbacks related to certain discontinuities plugins: add API for registering discontinuity callbacks plugins: add hooks for new discontinuity related callbacks contrib/plugins: add plugin showcasing new dicontinuity related API target/alpha: call plugin trap callbacks target/arm: call plugin trap callbacks target/avr: call plugin trap callbacks target/mips: call plugin trap callbacks target/riscv: call plugin trap callbacks target/sparc: call plugin trap callbacks tests: add plugin asserting correctness of discon event's to_pc contrib/plugins/meson.build | 3 +- contrib/plugins/traps.c | 96 +++++++++++++++++++++++++++++ include/qemu/plugin-event.h | 3 + include/qemu/plugin.h | 13 ++++ include/qemu/qemu-plugin.h | 58 +++++++++++++++++ plugins/core.c | 67 ++++++++++++++++++++ target/alpha/helper.c | 12 ++++ target/arm/helper.c | 25 ++++++++ target/arm/tcg/m_helper.c | 18 ++++++ target/avr/helper.c | 3 + target/mips/tcg/sysemu/tlb_helper.c | 11 ++++ target/riscv/cpu_helper.c | 9 +++ target/sparc/int32_helper.c | 7 +++ target/sparc/int64_helper.c | 10 +++ tests/tcg/plugins/discons.c | 95 ++++++++++++++++++++++++++++ tests/tcg/plugins/meson.build | 2 +- 16 files changed, 430 insertions(+), 2 deletions(-) create mode 100644 contrib/plugins/traps.c create mode 100644 tests/tcg/plugins/discons.c -- 2.45.2 Signed-off-by: GitHub Actions Bot --- .github/workflows/build.yml | 307 ++++++++++++++++++++++ .github/workflows/containers.yml | 54 ++++ .github/workflows/new_series.yml | 40 +++ .github/workflows/upstream.yml | 32 +++ contrib/plugins/meson.build | 2 +- docs/devel/style.rst | 20 ++ include/qemu/compiler.h | 7 +- meson.build | 6 +- plugins/meson.build | 24 +- precache_tests.sh | 53 ++++ push_new_series.sh | 150 +++++++++++ scripts/cocci-macro-file.h | 6 +- subprojects/libvhost-user/libvhost-user.h | 6 +- tests/avocado/kvm_xen_guest.py | 22 +- tests/avocado/replay_kernel.py | 35 +-- tests/functional/meson.build | 8 +- tests/qtest/meson.build | 15 +- tests/tcg/multiarch/signals.c | 4 +- tests/tcg/multiarch/vma-pthread.c | 207 --------------- tests/tcg/plugins/meson.build | 3 +- 20 files changed, 729 insertions(+), 272 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/containers.yml create mode 100644 .github/workflows/new_series.yml create mode 100644 .github/workflows/upstream.yml create mode 100755 precache_tests.sh create mode 100755 push_new_series.sh delete mode 100644 tests/tcg/multiarch/vma-pthread.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000000..3daf8110207c9 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,307 @@ +on: push + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + checkapply: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + # to debug container live from GitHub + # - uses: mxschmitt/action-tmate@v3 + - run: bash -c '[ ! -f shazam.log ] || { cat shazam.log; exit 1; }' + + checkpatch-ignore-signoff: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: git fetch -a origin --unshallow || true + - run: git remote add upstream -f https://gitlab.com/qemu-project/qemu + - run: ./scripts/checkpatch.pl --no-signoff $(git merge-base upstream/master HEAD)..HEAD + + checkpatch-with-signoff: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: git fetch -a origin --unshallow || true + - run: git remote add upstream -f https://gitlab.com/qemu-project/qemu + - run: ./scripts/checkpatch.pl $(git merge-base upstream/master HEAD)..HEAD + + # use docker-run to not rebuild images + # images are built daily and pushed on pbolinaro/qemu-ci:* + build-cross: + needs: checkapply + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + container: [alpine,centos9,debian,debian-all-test-cross,debian-amd64-cross,debian-arm64-cross,debian-armhf-cross,debian-hexagon-cross,debian-i686-cross,debian-legacy-test-cross,debian-loongarch-cross,debian-mips64el-cross,debian-mipsel-cross,debian-ppc64el-cross,debian-riscv64-cross,debian-s390x-cross,debian-tricore-cross,fedora,fedora-rust-nightly,opensuse-leap,ubuntu2204] + steps: + - uses: actions/checkout@v4 + - run: pip install meson + - run: make docker-run J=$(nproc) RUNC=podman TEST=test-build IMAGE=docker.io/pbolinaro/qemu-ci:${{matrix.container}} + + build: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure && ninja -C build install' + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + ./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin + + build-cross-mingw64: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:fedora-win64-cross + bash -cx './configure $QEMU_CONFIGURE_OPTS && ninja -C build install' + + build-windows: + needs: checkapply + runs-on: windows-2022 + strategy: + fail-fast: false + matrix: + sys: [UCRT64, CLANG64, MINGW64] + defaults: + run: + shell: msys2 {0} + steps: + - uses: msys2/setup-msys2@v2 + with: + update: true + msystem: ${{matrix.sys}} + - run: pacman -S --noconfirm curl git + - uses: actions/checkout@v4 + - run: > + pacman -S --noconfirm + base-devel binutils bison diffutils flex git grep make sed + ${MINGW_PACKAGE_PREFIX}-toolchain + ${MINGW_PACKAGE_PREFIX}-glib2 + ${MINGW_PACKAGE_PREFIX}-gtk3 + ${MINGW_PACKAGE_PREFIX}-libnfs + ${MINGW_PACKAGE_PREFIX}-libssh + ${MINGW_PACKAGE_PREFIX}-ninja + ${MINGW_PACKAGE_PREFIX}-pixman + ${MINGW_PACKAGE_PREFIX}-pkgconf + ${MINGW_PACKAGE_PREFIX}-python + ${MINGW_PACKAGE_PREFIX}-SDL2 + ${MINGW_PACKAGE_PREFIX}-zstd + - run: ./configure && ninja -C build + - run: ./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin + + build-macos-x86_64: + needs: checkapply + runs-on: macos-13 + steps: + - uses: actions/checkout@v4 + - run: brew install --quiet $(brew deps --include-build qemu) || true + # on macos, werror is not on by default + - run: ./configure --enable-werror && ninja -C build + - run: ./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin + + build-macos-aarch64: + needs: checkapply + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + - run: brew install --quiet $(brew deps --include-build qemu) || true + # on macos, werror is not on by default + - run: ./configure --enable-werror && ninja -C build + - run: ./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin + + build-misc: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --disable-user --disable-system --enable-docs --enable-tools && ninja -C build install' + + build-32bits: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian-i686-cross + bash -cx './configure $QEMU_CONFIGURE_OPTS && ninja -C build install' + + build-big-endian: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian-s390x-cross + bash -cx './configure $QEMU_CONFIGURE_OPTS && ninja -C build install' + + build-debug: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --enable-debug --enable-asan --enable-ubsan && ninja -C build install' + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + ./build/qemu-system-x86_64 -nographic -plugin ./build/contrib/plugins/libstoptrigger,icount=1000000 -plugin ./build/tests/tcg/plugins/libinsn -d plugin + + build-static: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --disable-system --disable-tools --disable-guest-agent --disable-docs --static && ninja -C build install' + + build-tsan: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --enable-tsan && ninja -C build install' + + build-clang: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --cxx=clang++ --cc=clang --host-cc=clang && ninja -C build install' + + build-clang-latest: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx 'LLVM_VERSION=19 && apt update && apt install -y lsb-release wget software-properties-common gnupg && wget https://apt.llvm.org/llvm.sh && bash llvm.sh ${LLVM_VERSION} && ./configure --cxx=clang++-${LLVM_VERSION} --cc=clang-${LLVM_VERSION} --host-cc=clang-${LLVM_VERSION} && ninja -C build install' + + build-rust: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:fedora-rust-nightly + bash -cx './configure $QEMU_CONFIGURE_OPTS --enable-rust && ninja -C build install' + + build-disable-tcg: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --disable-tcg && ninja -C build install' + + build-disable-kvm: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --disable-kvm && ninja -C build install' + + build-disable-tcg-kvm-for-xen: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --disable-tcg --disable-kvm && ninja -C build install' + + build-minimal: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian + bash -cx './configure --without-default-features --without-default-devices --disable-kvm --disable-tcg && ninja -C build install' + + check-tcg: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian-all-test-cross + bash -cx './configure $QEMU_CONFIGURE_OPTS --enable-debug-tcg && ninja -C build' + - run: > + podman run --init --privileged --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian-all-test-cross + bash -cx "make -k check-tcg" + + # run all meson tests, including functional. Run -j1 to avoid sporadic issues. + check: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + # we use image with download cache filled. Solves servers flakiness. + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian-precache-tests + bash -cx './configure --enable-debug-tcg && ninja -C build' + - run: sudo chown $USER:$USER /dev/kvm + - run: > + podman run --init --privileged --rm -it -v /dev/kvm:/dev/kvm -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian-precache-tests + bash -cx "make -k check SPEED=thorough TIMEOUT_MULTIPLIER=5" + + check-avocado: + needs: checkapply + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + # add more time for all tests + - run: sed -i -e 's/timeout = .*/timeout = 3600/' $(find tests/avocado/ -type f) + # we use image with download cache filled. Solves servers flakiness. + - run: > + podman run --init --rm -it -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian-precache-tests + bash -cx './configure --enable-debug-tcg && ninja -C build' + - run: sudo chown $USER:$USER /dev/kvm + - run: > + podman run --init --privileged --rm -it -v /dev/kvm:/dev/kvm -v $(pwd):$(pwd) -w $(pwd) + docker.io/pbolinaro/qemu-ci:debian-precache-tests + bash -cx "make -k check-avocado" diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml new file mode 100644 index 0000000000000..c9a8e3b9cd591 --- /dev/null +++ b/.github/workflows/containers.yml @@ -0,0 +1,54 @@ +on: + schedule: + - cron: '0 6 * * *' + workflow_dispatch: + +permissions: write-all + +jobs: + build_container: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # cd tests/docker/dockerfiles/ + # ls *docker | sed -e 's/.docker//' | tr '\n' ',' + # remove: debian-bootstrap,debian-toolchain + container: [alpine,centos9,debian-all-test-cross,debian-amd64-cross,debian-arm64-cross,debian-armhf-cross,debian,debian-hexagon-cross,debian-i686-cross,debian-legacy-test-cross,debian-loongarch-cross,debian-mips64el-cross,debian-mipsel-cross,debian-ppc64el-cross,debian-riscv64-cross,debian-s390x-cross,debian-tricore-cross,debian-xtensa-cross,fedora,fedora-rust-nightly,fedora-win64-cross,opensuse-leap,python,ubuntu2204] + steps: + - uses: actions/checkout@v4 + - run: make docker-image-${{matrix.container}} RUNC=podman V=1 + - run: podman tag qemu/${{matrix.container}} docker.io/pbolinaro/qemu-ci:${{matrix.container}} + - run: podman login -u pbolinaro -p ${{secrets.DOCKERHUB_PASSWORD}} + - run: podman push docker.io/pbolinaro/qemu-ci:${{matrix.container}} + + build_container_debian-precache-tests: + runs-on: ubuntu-latest + steps: + # we clean up runner first, to get more disk space + - run: docker system prune -af && sudo rm -rf /opt/* + - uses: actions/checkout@v4 + - run: make docker-image-debian RUNC=podman V=1 + # fill download cache for functional and check-avocado + # running check-avocado without any qemu binary will only download data + # in /root/avocado + - run: > + podman run -it -v $(pwd):$(pwd) -w $(pwd) qemu/debian + ./precache_tests.sh + # commit result as a new image. Cache will be in /root/.cache and /root/avocado + - run: podman commit "$(podman ps -aq)" docker.io/pbolinaro/qemu-ci:debian-precache-tests + - run: podman login -u pbolinaro -p ${{secrets.DOCKERHUB_PASSWORD}} + - run: podman push docker.io/pbolinaro/qemu-ci:debian-precache-tests + + keepalive-job: + name: Keepalive Workflow + if: ${{ always() }} + needs: build_container + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - uses: gautamkrishnar/keepalive-workflow@v2 + with: + use_api: false diff --git a/.github/workflows/new_series.yml b/.github/workflows/new_series.yml new file mode 100644 index 0000000000000..ce11d047d1b11 --- /dev/null +++ b/.github/workflows/new_series.yml @@ -0,0 +1,40 @@ +on: + schedule: + - cron: '*/10 * * * *' + workflow_dispatch: + +permissions: write-all + +jobs: + push_new_series: + runs-on: ubuntu-latest + concurrency: + group: push_new_series + cancel-in-progress: true + steps: + - name: checkout + uses: actions/checkout@v3 + with: + # a PAT must be generated with workflow permission, else it's not + # possible to push any change for those files + # https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/triggering-a-workflow#triggering-a-workflow-from-a-workflow + token: ${{ secrets.WORKFLOW_COMMIT_TOKEN }} + - run: git fetch -a origin --unshallow || true + - run: git config user.name "GitHub Actions Bot" + - run: git config user.email "" + - run: git config advice.detachedHead false + - run: sudo pip install b4 + - run: ./push_new_series.sh + + keepalive-job: + name: Keepalive Workflow + if: ${{ always() }} + needs: push_new_series + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - uses: gautamkrishnar/keepalive-workflow@v2 + with: + use_api: false diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml new file mode 100644 index 0000000000000..8225a0a0f4f80 --- /dev/null +++ b/.github/workflows/upstream.yml @@ -0,0 +1,32 @@ +on: + schedule: + - cron: '0 */2 * * *' + workflow_dispatch: + +permissions: write-all + +jobs: + push_upstream: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: git fetch -a origin --unshallow || true + - run: git config user.name "GitHub Actions Bot" + - run: git config user.email "" + - run: git checkout ci + - run: git remote add upstream -f https://gitlab.com/qemu-project/qemu + - run: git rebase upstream/master + - run: git push -f --set-upstream origin "ci:upstream" + + keepalive-job: + name: Keepalive Workflow + if: ${{ always() }} + needs: push_upstream + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - uses: gautamkrishnar/keepalive-workflow@v2 + with: + use_api: false diff --git a/contrib/plugins/meson.build b/contrib/plugins/meson.build index 9a3015e1c1bf1..c4f5061a7b3c0 100644 --- a/contrib/plugins/meson.build +++ b/contrib/plugins/meson.build @@ -13,7 +13,7 @@ if get_option('plugins') t += shared_module(i, files(i + '.c') + 'win32_linker.c', include_directories: '../../include/qemu', link_depends: [win32_qemu_plugin_api_lib], - link_args: ['-Lplugins', '-lqemu_plugin_api'], + link_args: win32_qemu_plugin_api_link_flags, dependencies: glib) else t += shared_module(i, files(i + '.c'), diff --git a/docs/devel/style.rst b/docs/devel/style.rst index 2f68b500798cb..2d73e6a8f7a11 100644 --- a/docs/devel/style.rst +++ b/docs/devel/style.rst @@ -416,6 +416,26 @@ definitions instead of typedefs in headers and function prototypes; this avoids problems with duplicated typedefs and reduces the need to include headers from other headers. +Bitfields +--------- + +C bitfields can be a cause of non-portability issues, especially under windows +where `MSVC has a different way to lay them out than gcc +`_, and on big and +little endian hosts. + +For this reason, we disallow usage of bitfields in packed structures and in any +structures which are supposed to exactly match a specific layout in guest +memory. Some existing code may use it, and we carefully ensured the layout was +the one expected. + +We also suggest avoiding bitfields even in structures where the exact +layout does not matter, unless you can show that they provide a significant +memory usage or usability benefit. + +We encourage the usage of ``include/hw/registerfields.h`` as a safe replacement +for bitfields. + Reserved namespaces in C and POSIX ---------------------------------- diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index c06954ccb4161..d904408e5ed9b 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -22,12 +22,7 @@ #define QEMU_EXTERN_C extern #endif -#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) -# define QEMU_PACKED __attribute__((gcc_struct, packed)) -#else -# define QEMU_PACKED __attribute__((packed)) -#endif - +#define QEMU_PACKED __attribute__((packed)) #define QEMU_ALIGNED(X) __attribute__((aligned(X))) #ifndef glue diff --git a/meson.build b/meson.build index a290dbfa33119..f286fb4f4a008 100644 --- a/meson.build +++ b/meson.build @@ -355,9 +355,9 @@ elif host_os == 'sunos' elif host_os == 'haiku' qemu_common_flags += ['-DB_USE_POSITIVE_POSIX_ERRORS', '-D_BSD_SOURCE', '-fPIC'] elif host_os == 'windows' - if not compiler.compiles('struct x { int y; } __attribute__((gcc_struct));', - args: '-Werror') - error('Your compiler does not support __attribute__((gcc_struct)) - please use GCC instead of Clang') + # plugins use delaylib, and clang needs to be used with lld to make it work. + if compiler.get_id() == 'clang' and compiler.get_linker_id() != 'ld.lld' + error('On windows, you need to use lld with clang - use msys2 clang64/clangarm64 env') endif endif diff --git a/plugins/meson.build b/plugins/meson.build index 98542e926f8c5..d60be2a4d6d06 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -17,14 +17,15 @@ if not enable_modules capture: true, command: ['sed', '-ne', 's/^[[:space:]]*\\(qemu_.*\\);/_\\1/p', '@INPUT@']) emulator_link_args += ['-Wl,-exported_symbols_list,plugins/qemu-plugins-ld64.symbols'] + elif host_os == 'windows' and meson.get_compiler('c').get_id() == 'clang' + # LLVM/lld does not support exporting specific symbols. However, it works + # out of the box with dllexport/dllimport attribute we set in the code. else emulator_link_args += ['-Xlinker', '--dynamic-list=' + qemu_plugin_symbols.full_path()] endif endif if host_os == 'windows' - dlltool = find_program('dlltool', required: true) - # Generate a .lib file for plugins to link against. # First, create a .def file listing all the symbols a plugin should expect to have # available in qemu @@ -33,12 +34,27 @@ if host_os == 'windows' output: 'qemu_plugin_api.def', capture: true, command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@']) + # then use dlltool to assemble a delaylib. + # The delaylib will have an "imaginary" name (qemu.exe), that is used by the + # linker file we add with plugins (win32_linker.c) to identify that we want + # to find missing symbols in current program. + win32_qemu_plugin_api_link_flags = ['-Lplugins', '-lqemu_plugin_api'] + if meson.get_compiler('c').get_id() == 'clang' + # With LLVM/lld, delaylib is specified at link time (-delayload) + dlltool = find_program('llvm-dlltool', required: true) + dlltool_cmd = [dlltool, '-d', '@INPUT@', '-l', '@OUTPUT@', '-D', 'qemu.exe'] + win32_qemu_plugin_api_link_flags += ['-Wl,-delayload=qemu.exe'] + else + # With gcc/ld, delay lib is built with a specific delay parameter. + dlltool = find_program('dlltool', required: true) + dlltool_cmd = [dlltool, '--input-def', '@INPUT@', + '--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe'] + endif win32_qemu_plugin_api_lib = configure_file( input: win32_plugin_def, output: 'libqemu_plugin_api.a', - command: [dlltool, '--input-def', '@INPUT@', - '--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe'] + command: dlltool_cmd ) endif specific_ss.add(files( diff --git a/precache_tests.sh b/precache_tests.sh new file mode 100755 index 0000000000000..d6e8e0eb4eda4 --- /dev/null +++ b/precache_tests.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +set -euo pipefail + +check_avocado_cache() +{ + # avocado will keep in cache incomplete images, and there is no way to force + # it to redownload it... So we do this checking ourselves here. + + if [ ! -d $HOME/avocado ]; then + echo "missing $HOME/avocado" + return 1 + fi + + err=0 + for expected in $(find $HOME/avocado -type f | grep CHECKSUM | sort); do + file=$(echo $expected | sed -e 's/-CHECKSUM//') + hash_type=$(cat $expected | cut -f 1 -d ' ') + if [ ! -f "$file" ]; then + echo $file is missing + err=1 + continue + fi + hash=$(${hash_type}sum $file | cut -f 1 -d ' ') + if ! diff <(cat $expected) <(echo $hash_type $hash); then + echo $file has hash mismatch - delete + rm -rf "$(dirname "$file")" + err=1 + fi + done + return $err +} + +./configure +ninja -C build precache-functional || ninja -C build precache-functional + +# avocado fetch assets will sometimes fail with exception, but without any error +# code. In this case, either an item is missing, or it's in the cache but with a +# bad hash. In the second case, avocado does not redownload it... :( +while true; do + make -C build check-avocado SPEED=slow |& tee avocado.log + echo ----------------------------------------- + if ! check_avocado_cache; then + echo "avocado cache has missing items" + continue + fi + if grep -A 20 -i Traceback avocado.log; then + echo "exception while running avocado" + continue + fi + echo "avocado cache is now ready" + break +done diff --git a/push_new_series.sh b/push_new_series.sh new file mode 100755 index 0000000000000..3a757e659d5a7 --- /dev/null +++ b/push_new_series.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash + +set -euo pipefail + +die() +{ + echo 1>&2 "$@" + exit 1 +} + +# return URL for mailboxes for previous, current and next month. This way, we +# don't miss any email, even with different timezones. +mailbox_archives() +{ + current_date=$1 + + current_month=$(date +%m --date "$current_date") + current_year=$(date +%Y --date "$current_date") + previous_year=$current_year + next_year=$current_year + previous_month=$(printf "%02d" $((current_month - 1))) + next_month=$(printf "%02d" $((current_month + 1))) + + if [ $current_month == "01" ]; then + previous_month=12 + previous_year=$((current_year - 1)) + elif [ $current_month == "12" ]; then + next_month=01 + next_year=$((current_year + 1)) + fi + + qemu_archive="https://lists.gnu.org/archive/mbox/qemu-devel/" + echo $qemu_archive$previous_year-$previous_month \ + $qemu_archive$current_year-$current_month \ + $qemu_archive$next_year-$next_month +} + +# download all emails for previous, current and next month. +fetch_mails() +{ + out=$1 + rm -rf $out + mkdir -p $out + mkdir -p $out.mailbox + pushd $out.mailbox + archives=$(mailbox_archives "$(date)") + # we can have missing current or next mailbox depending on timezone + wget --no-verbose --no-clobber $archives || true + popd + git mailsplit -o$out $out.mailbox/* +} + +find_series() +{ + mail_dir=$1 + # find all message id, for mails without a reference (i.e. first in series). + grep -Lri '^References: .' $mail_dir | sort | while read m + do + # skip messages replying to thread + if grep -qi '^In-Reply-to: .' $m; then + continue + fi + msg_id=$(grep -i '^message-id: ' $m | head -n1 | + sed -e 's/.*$//') + date=$(grep -i '^date: ' $m | head -n1 | sed -e 's/^date: //I') + echo "$msg_id|$date" + done +} + +fetch_repositories() +{ + git remote remove upstream || true + git remote add upstream -f https://gitlab.com/qemu-project/qemu + git fetch -a origin -p +} + +push_one_series() +{ + s="$1"; shift + apply_revision="$1"; shift + echo "-----------------------------------------------------------------" + msg_id=$(echo "$s" | cut -f 1 -d '|') + date=$(echo "$s" | cut -f 2 -d '|') + echo "$msg_id | $date" + if git rev-parse "remotes/origin/$msg_id" >& /dev/null; then + return + fi + + # find git commit on master close to date of series + base_git_revision=$(git log -n1 --format=format:%H --before="$date" \ + --first-parent upstream/master) + echo "push this new series, applied from $base_git_revision" + git checkout "$base_git_revision" >& /dev/null + git branch -D new_series >& /dev/null || true + git checkout -b new_series + + # apply series + if ! b4 shazam --allow-unicode-control-chars $msg_id |& tee shazam.log; then + git am --abort || true + git add shazam.log + git commit -m 'b4 shazam failed' + fi + + if grep -qi 'message-id is not known' shazam.log; then + echo "no thread found for: $msg_id" + return + fi + + if grep -qi 'no patches found' shazam.log; then + echo "no patches found in series: $msg_id" + return + fi + + rm -f ./*.mbx + b4 mbox "$msg_id" --single-message + subject=$(grep -i '^Subject:' *.mbx | sed -e 's/Subject:\s*//') + + if echo "$subject" | grep -i "^Re:"; then + echo "this message has no reference but is an answer: $msg_id" + return + fi + + git push --set-upstream origin "new_series:$msg_id" + cat > commit_msg << EOF +$subject + +https://lore.kernel.org/qemu-devel/$msg_id + +--- + +$(grep -A 100000 -i '^From:' *.mbx) +EOF + # apply a specific patch + if [ "$apply_revision" != "" ]; then + git cherry-pick "$apply_revision" --no-commit + git commit -a -F commit_msg --signoff + fi + # let some time to GitHub to order branches + sleep 5 + git push --set-upstream origin "new_series:${msg_id}_ci" +} + +fetch_repositories +apply_range=$(git merge-base origin/ci upstream/master) +[ "$apply_range" != "" ] || die "can't find revisions to apply to series" +# apply all commits on ci branch +apply_range=$apply_range..origin/ci + +fetch_mails mails +find_series mails | while read s; do push_one_series "$s" "$apply_range"; done diff --git a/scripts/cocci-macro-file.h b/scripts/cocci-macro-file.h index d247a5086e91d..c64831d540829 100644 --- a/scripts/cocci-macro-file.h +++ b/scripts/cocci-macro-file.h @@ -23,11 +23,7 @@ #define G_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #define G_GNUC_NULL_TERMINATED __attribute__((sentinel)) -#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) -# define QEMU_PACKED __attribute__((gcc_struct, packed)) -#else -# define QEMU_PACKED __attribute__((packed)) -#endif +#define QEMU_PACKED __attribute__((packed)) #define cat(x,y) x ## y #define cat2(x,y) cat(x,y) diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvhost-user/libvhost-user.h index deb40e77b3fd6..2ffc58c11b142 100644 --- a/subprojects/libvhost-user/libvhost-user.h +++ b/subprojects/libvhost-user/libvhost-user.h @@ -186,11 +186,7 @@ typedef struct VhostUserShared { unsigned char uuid[UUID_LEN]; } VhostUserShared; -#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) -# define VU_PACKED __attribute__((gcc_struct, packed)) -#else -# define VU_PACKED __attribute__((packed)) -#endif +#define VU_PACKED __attribute__((packed)) typedef struct VhostUserMsg { int request; diff --git a/tests/avocado/kvm_xen_guest.py b/tests/avocado/kvm_xen_guest.py index f8cb458d5db93..910e7b075b22e 100644 --- a/tests/avocado/kvm_xen_guest.py +++ b/tests/avocado/kvm_xen_guest.py @@ -158,14 +158,14 @@ def test_kvm_xen_guest_novector_nomsi(self): self.run_and_check() self.ssh_command('grep xen-platform-pci /proc/interrupts') - def test_kvm_xen_guest_novector_noapic(self): - """ - :avocado: tags=kvm_xen_guest_novector_noapic - """ - - self.common_vm_setup() - self.kernel_params = (self.KERNEL_DEFAULT + - ' xen_emul_unplug=ide-disks' + - ' xen_no_vector_callback noapic') - self.run_and_check() - self.ssh_command('grep xen-platform-pci /proc/interrupts') + #def test_kvm_xen_guest_novector_noapic(self): + # """ + # :avocado: tags=kvm_xen_guest_novector_noapic + # """ + + # self.common_vm_setup() + # self.kernel_params = (self.KERNEL_DEFAULT + + # ' xen_emul_unplug=ide-disks' + + # ' xen_no_vector_callback noapic') + # self.run_and_check() + # self.ssh_command('grep xen-platform-pci /proc/interrupts') diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py index e22c200a36886..64d63a00fa17e 100644 --- a/tests/avocado/replay_kernel.py +++ b/tests/avocado/replay_kernel.py @@ -320,23 +320,24 @@ def test_ppc64_powernv(self): console_pattern = 'VFS: Cannot open root device' self.run_rr(kernel_path, kernel_command_line, console_pattern) - def test_m68k_q800(self): - """ - :avocado: tags=arch:m68k - :avocado: tags=machine:q800 - """ - deb_url = ('https://snapshot.debian.org/archive/debian-ports' - '/20191021T083923Z/pool-m68k/main' - '/l/linux/kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb') - deb_hash = '044954bb9be4160a3ce81f8bc1b5e856b75cccd1' - deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash) - kernel_path = self.extract_from_deb(deb_path, - '/boot/vmlinux-5.3.0-1-m68k') - - kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + - 'console=ttyS0 vga=off') - console_pattern = 'No filesystem could mount root' - self.run_rr(kernel_path, kernel_command_line, console_pattern) + # This test needs a sound card available, but we can't get one on GitHub. + #def test_m68k_q800(self): + # """ + # :avocado: tags=arch:m68k + # :avocado: tags=machine:q800 + # """ + # deb_url = ('https://snapshot.debian.org/archive/debian-ports' + # '/20191021T083923Z/pool-m68k/main' + # '/l/linux/kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb') + # deb_hash = '044954bb9be4160a3ce81f8bc1b5e856b75cccd1' + # deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash) + # kernel_path = self.extract_from_deb(deb_path, + # '/boot/vmlinux-5.3.0-1-m68k') + + # kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + # 'console=ttyS0 vga=off') + # console_pattern = 'No filesystem could mount root' + # self.run_rr(kernel_path, kernel_command_line, console_pattern) def do_test_advcal_2018(self, file_path, kernel_name, args=None): archive.extract(file_path, self.workdir) diff --git a/tests/functional/meson.build b/tests/functional/meson.build index d6d2c0196c763..5c048cfac6d70 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -23,7 +23,7 @@ test_timeouts = { 'arm_collie' : 180, 'arm_orangepi' : 540, 'arm_raspi2' : 120, - 'arm_tuxrun' : 240, + # 'arm_tuxrun' : 240, # flaky functional test 'arm_sx1' : 360, 'mips_malta' : 120, 'netdev_ethtool' : 180, @@ -74,7 +74,7 @@ tests_arm_system_thorough = [ 'arm_raspi2', 'arm_sx1', 'arm_vexpress', - 'arm_tuxrun', + # 'arm_tuxrun', # flaky functional test ] tests_arm_linuxuser_thorough = [ @@ -90,13 +90,13 @@ tests_i386_system_thorough = [ ] tests_loongarch64_system_thorough = [ - 'loongarch64_virt', + # 'loongarch64_virt', # flaky functional test ] tests_m68k_system_thorough = [ 'm68k_mcf5208evb', 'm68k_nextcube', - 'm68k_q800', + # 'm68k_q800', # this test needs a soundcard, not available on GitHub ] tests_microblaze_system_thorough = [ diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index f2f35367ae7c1..c76225f87acff 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -5,7 +5,7 @@ slow_qtests = { 'cdrom-test' : 610, 'device-introspect-test' : 720, 'ide-test' : 120, - 'migration-test' : 480, + # 'migration-test' : 480, 'npcm7xx_pwm-test': 300, 'npcm7xx_watchdog_timer-test': 120, 'qmp-cmd-test' : 120, @@ -111,7 +111,7 @@ qtests_i386 = \ 'device-plug-test', 'drive_del-test', 'cpu-plug-test', - 'migration-test', + # 'migration-test', ] if dbus_display and config_all_devices.has_key('CONFIG_VGA') @@ -185,7 +185,8 @@ qtests_ppc64 = \ (slirp.found() ? ['pxe-test'] : []) + \ (config_all_devices.has_key('CONFIG_USB_UHCI') ? ['usb-hcd-uhci-test'] : []) + \ (config_all_devices.has_key('CONFIG_USB_XHCI_NEC') ? ['usb-hcd-xhci-test'] : []) + \ - qtests_pci + ['migration-test', 'cpu-plug-test', 'drive_del-test'] + qtests_pci + ['cpu-plug-test', 'drive_del-test'] + #qtests_pci + ['migration-test', 'cpu-plug-test', 'drive_del-test'] qtests_sh4 = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) qtests_sh4eb = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) @@ -258,7 +259,8 @@ qtests_aarch64 = \ ['arm-cpu-features', 'numa-test', 'boot-serial-test', - 'migration-test'] + ] + #'migration-test'] qtests_s390x = \ qtests_filter + \ @@ -267,7 +269,8 @@ qtests_s390x = \ 'device-plug-test', 'virtio-ccw-test', 'cpu-plug-test', - 'migration-test'] + ] + #'migration-test'] qtests_riscv32 = \ (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? ['sifive-e-aon-watchdog-test'] : []) @@ -346,7 +349,7 @@ qtests = { 'dbus-vmstate-test': files('migration-helpers.c') + dbus_vmstate1, 'erst-test': files('erst-test.c'), 'ivshmem-test': [rt, '../../contrib/ivshmem-server/ivshmem-server.c'], - 'migration-test': migration_files, + #'migration-test': migration_files, 'pxe-test': files('boot-sector.c'), 'pnv-xive2-test': files('pnv-xive2-common.c', 'pnv-xive2-flush-sync.c'), 'qos-test': [chardev, io, qos_test_ss.apply({}).sources()], diff --git a/tests/tcg/multiarch/signals.c b/tests/tcg/multiarch/signals.c index 998c8fdefd6f1..07b2f5e8a642e 100644 --- a/tests/tcg/multiarch/signals.c +++ b/tests/tcg/multiarch/signals.c @@ -144,6 +144,8 @@ static void test_signals(void) int main(int argc, char **argv) { - test_signals(); + if (0) { /* flaky on some architectures */ + test_signals(); + } return 0; } diff --git a/tests/tcg/multiarch/vma-pthread.c b/tests/tcg/multiarch/vma-pthread.c deleted file mode 100644 index 7045da08fc439..0000000000000 --- a/tests/tcg/multiarch/vma-pthread.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Test that VMA updates do not race. - * - * SPDX-License-Identifier: GPL-2.0-or-later - * - * Map a contiguous chunk of RWX memory. Split it into 8 equally sized - * regions, each of which is guaranteed to have a certain combination of - * protection bits set. - * - * Reader, writer and executor threads perform the respective operations on - * pages, which are guaranteed to have the respective protection bit set. - * Two mutator threads change the non-fixed protection bits randomly. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nop_func.h" - -#define PAGE_IDX_BITS 10 -#define PAGE_COUNT (1 << PAGE_IDX_BITS) -#define PAGE_IDX_MASK (PAGE_COUNT - 1) -#define REGION_IDX_BITS 3 -#define PAGE_IDX_R_MASK (1 << 7) -#define PAGE_IDX_W_MASK (1 << 8) -#define PAGE_IDX_X_MASK (1 << 9) -#define REGION_MASK (PAGE_IDX_R_MASK | PAGE_IDX_W_MASK | PAGE_IDX_X_MASK) -#define PAGES_PER_REGION (1 << (PAGE_IDX_BITS - REGION_IDX_BITS)) - -struct context { - int pagesize; - char *ptr; - int dev_null_fd; - volatile int mutator_count; -}; - -static void *thread_read(void *arg) -{ - struct context *ctx = arg; - ssize_t sret; - size_t i, j; - int ret; - - for (i = 0; ctx->mutator_count; i++) { - char *p; - - j = (i & PAGE_IDX_MASK) | PAGE_IDX_R_MASK; - p = &ctx->ptr[j * ctx->pagesize]; - - /* Read directly. */ - ret = memcmp(p, nop_func, sizeof(nop_func)); - if (ret != 0) { - fprintf(stderr, "fail direct read %p\n", p); - abort(); - } - - /* Read indirectly. */ - sret = write(ctx->dev_null_fd, p, 1); - if (sret != 1) { - if (sret < 0) { - fprintf(stderr, "fail indirect read %p (%m)\n", p); - } else { - fprintf(stderr, "fail indirect read %p (%zd)\n", p, sret); - } - abort(); - } - } - - return NULL; -} - -static void *thread_write(void *arg) -{ - struct context *ctx = arg; - struct timespec *ts; - size_t i, j; - int ret; - - for (i = 0; ctx->mutator_count; i++) { - j = (i & PAGE_IDX_MASK) | PAGE_IDX_W_MASK; - - /* Write directly. */ - memcpy(&ctx->ptr[j * ctx->pagesize], nop_func, sizeof(nop_func)); - - /* Write using a syscall. */ - ts = (struct timespec *)(&ctx->ptr[(j + 1) * ctx->pagesize] - - sizeof(struct timespec)); - ret = clock_gettime(CLOCK_REALTIME, ts); - if (ret != 0) { - fprintf(stderr, "fail indirect write %p (%m)\n", ts); - abort(); - } - } - - return NULL; -} - -static void *thread_execute(void *arg) -{ - struct context *ctx = arg; - size_t i, j; - - for (i = 0; ctx->mutator_count; i++) { - j = (i & PAGE_IDX_MASK) | PAGE_IDX_X_MASK; - ((void(*)(void))&ctx->ptr[j * ctx->pagesize])(); - } - - return NULL; -} - -static void *thread_mutate(void *arg) -{ - size_t i, start_idx, end_idx, page_idx, tmp; - struct context *ctx = arg; - unsigned int seed; - int prot, ret; - - seed = (unsigned int)time(NULL); - for (i = 0; i < 10000; i++) { - start_idx = rand_r(&seed) & PAGE_IDX_MASK; - end_idx = rand_r(&seed) & PAGE_IDX_MASK; - if (start_idx > end_idx) { - tmp = start_idx; - start_idx = end_idx; - end_idx = tmp; - } - prot = rand_r(&seed) & (PROT_READ | PROT_WRITE | PROT_EXEC); - for (page_idx = start_idx & REGION_MASK; page_idx <= end_idx; - page_idx += PAGES_PER_REGION) { - if (page_idx & PAGE_IDX_R_MASK) { - prot |= PROT_READ; - } - if (page_idx & PAGE_IDX_W_MASK) { - /* FIXME: qemu syscalls check for both read+write. */ - prot |= PROT_WRITE | PROT_READ; - } - if (page_idx & PAGE_IDX_X_MASK) { - prot |= PROT_EXEC; - } - } - ret = mprotect(&ctx->ptr[start_idx * ctx->pagesize], - (end_idx - start_idx + 1) * ctx->pagesize, prot); - assert(ret == 0); - } - - __atomic_fetch_sub(&ctx->mutator_count, 1, __ATOMIC_SEQ_CST); - - return NULL; -} - -int main(void) -{ - pthread_t threads[5]; - struct context ctx; - size_t i; - int ret; - - /* Without a template, nothing to test. */ - if (sizeof(nop_func) == 0) { - return EXIT_SUCCESS; - } - - /* Initialize memory chunk. */ - ctx.pagesize = getpagesize(); - ctx.ptr = mmap(NULL, PAGE_COUNT * ctx.pagesize, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - assert(ctx.ptr != MAP_FAILED); - for (i = 0; i < PAGE_COUNT; i++) { - memcpy(&ctx.ptr[i * ctx.pagesize], nop_func, sizeof(nop_func)); - } - ctx.dev_null_fd = open("/dev/null", O_WRONLY); - assert(ctx.dev_null_fd >= 0); - ctx.mutator_count = 2; - - /* Start threads. */ - ret = pthread_create(&threads[0], NULL, thread_read, &ctx); - assert(ret == 0); - ret = pthread_create(&threads[1], NULL, thread_write, &ctx); - assert(ret == 0); - ret = pthread_create(&threads[2], NULL, thread_execute, &ctx); - assert(ret == 0); - for (i = 3; i <= 4; i++) { - ret = pthread_create(&threads[i], NULL, thread_mutate, &ctx); - assert(ret == 0); - } - - /* Wait for threads to stop. */ - for (i = 0; i < sizeof(threads) / sizeof(threads[0]); i++) { - ret = pthread_join(threads[i], NULL); - assert(ret == 0); - } - - /* Destroy memory chunk. */ - ret = close(ctx.dev_null_fd); - assert(ret == 0); - ret = munmap(ctx.ptr, PAGE_COUNT * ctx.pagesize); - assert(ret == 0); - - return EXIT_SUCCESS; -} diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build index f847849b1b77b..87a17d67bd450 100644 --- a/tests/tcg/plugins/meson.build +++ b/tests/tcg/plugins/meson.build @@ -5,9 +5,8 @@ if get_option('plugins') t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c', include_directories: '../../../include/qemu', link_depends: [win32_qemu_plugin_api_lib], - link_args: ['-Lplugins', '-lqemu_plugin_api'], + link_args: win32_qemu_plugin_api_link_flags, dependencies: glib) - else t += shared_module(i, files(i + '.c'), include_directories: '../../../include/qemu',