Compare commits
69 Commits
master
...
stable-6.0
Author | SHA1 | Date |
---|---|---|
Michael Roth | 9654e55a74 | |
Jessica Clarke | db882c5c18 | |
Helge Deller | 62a012b0f4 | |
David Hildenbrand | 487a0956a1 | |
Xueming Li | c18bc855ad | |
Marcel Apfelbaum | 27c6f20d9d | |
Marcel Apfelbaum | 46d3c9e9f5 | |
Marcel Apfelbaum | d25db58213 | |
Li Qiang | 4787501893 | |
Li Qiang | 07daff4a9a | |
Li Qiang | 4dda63d7ed | |
Li Qiang | 457053998d | |
Li Qiang | 6ae68dfd10 | |
Li Qiang | c5300b8a94 | |
Li Qiang | 168299eb7d | |
Gerd Hoffmann | e204dca909 | |
Gerd Hoffmann | 606f618b3c | |
Gerd Hoffmann | 36403e8788 | |
David Hildenbrand | 5a964fe8d9 | |
Markus Armbruster | f22c225e23 | |
Nir Soffer | 916372e48f | |
Jason Wang | 5881d76ff4 | |
Peter Maydell | 2ae61d81a5 | |
Dr. David Alan Gilbert | 4fca33b4be | |
Philippe Mathieu-Daudé | 978c11b013 | |
Philippe Mathieu-Daudé | 21611dd0a5 | |
Pavel Pisa | 4d3cfb2f6b | |
David Hildenbrand | 7999d5b12f | |
Klaus Jensen | 6576f6ab87 | |
Klaus Jensen | bef905cd8a | |
Gollu Appalanaidu | aa99651295 | |
Igor Mammedov | 765ed56e76 | |
Igor Mammedov | b989641145 | |
Igor Mammedov | e23fe27ed9 | |
Leonardo Bras | 22de6752c1 | |
Philippe Mathieu-Daudé | 747fd3cb13 | |
Philippe Mathieu-Daudé | 43844c2fb2 | |
Philippe Mathieu-Daudé | a1c966bdf4 | |
Philippe Mathieu-Daudé | 0a7e2c99f9 | |
Philippe Mathieu-Daudé | 8d5c255a25 | |
Philippe Mathieu-Daudé | 738ff4bf07 | |
Philippe Mathieu-Daudé | 7e84d58e8b | |
Philippe Mathieu-Daudé | 072a8d3693 | |
Philippe Mathieu-Daudé | 0a579d4389 | |
Richard Henderson | 059ad82f38 | |
Richard Henderson | 1a0a1c4964 | |
Zhenzhong Duan | cdb8a71e2e | |
Kunkun Jiang | 5b55370e28 | |
Peng Liang | d1000ee07b | |
Mark Cave-Ayland | b6f5c02f5f | |
Mark Cave-Ayland | 44e5878ce3 | |
Jason Wang | 8d719825d9 | |
Paolo Bonzini | ad8c49081a | |
Kevin Wolf | fcfe1509a1 | |
Stefan Hajnoczi | 9b0ee423a1 | |
Paolo Bonzini | 5b96b36a61 | |
Paolo Bonzini | c675ba821c | |
Paolo Bonzini | 203f0ba144 | |
Paolo Bonzini | 701ff59cc4 | |
Paolo Bonzini | 4e1eef8611 | |
Max Filippov | ab33188125 | |
Paolo Bonzini | b20eff3ba4 | |
Giuseppe Musacchio | 59ac5e6d61 | |
Richard Henderson | e2258e5279 | |
Li Zhijian | fdf58b451b | |
Stefan Reiter | 318b076356 | |
Greg Kurz | c1d1c0b4c3 | |
Richard Henderson | 5d0c78455e | |
Zenghui Yu | 1513997aa2 |
59
.cirrus.yml
59
.cirrus.yml
|
@ -1,6 +1,61 @@
|
|||
env:
|
||||
CIRRUS_CLONE_DEPTH: 1
|
||||
|
||||
freebsd_12_task:
|
||||
freebsd_instance:
|
||||
image_family: freebsd-12-2
|
||||
cpu: 8
|
||||
memory: 8G
|
||||
install_script:
|
||||
- ASSUME_ALWAYS_YES=yes pkg bootstrap -f ;
|
||||
- pkg install -y bash curl cyrus-sasl git glib gmake gnutls gsed
|
||||
nettle perl5 pixman pkgconf png usbredir ninja
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
# TODO: Enable gnutls again once FreeBSD's libtasn1 got fixed
|
||||
# See: https://gitlab.com/gnutls/libtasn1/-/merge_requests/71
|
||||
- ../configure --enable-werror --disable-gnutls
|
||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake -j$(sysctl -n hw.ncpu) check V=1
|
||||
|
||||
macos_task:
|
||||
osx_instance:
|
||||
image: catalina-base
|
||||
install_script:
|
||||
- brew install pkg-config python gnu-sed glib pixman make sdl2 bash ninja
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --python=/usr/local/bin/python3 --enable-werror
|
||||
--extra-cflags='-Wno-error=deprecated-declarations'
|
||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake check-unit V=1
|
||||
- gmake check-block V=1
|
||||
- gmake check-qapi-schema V=1
|
||||
- gmake check-softfloat V=1
|
||||
- gmake check-qtest-x86_64 V=1
|
||||
|
||||
macos_xcode_task:
|
||||
osx_instance:
|
||||
# this is an alias for the latest Xcode
|
||||
image: catalina-xcode
|
||||
install_script:
|
||||
- brew install pkg-config gnu-sed glib pixman make sdl2 bash ninja
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --extra-cflags='-Wno-error=deprecated-declarations' --enable-modules
|
||||
--enable-werror --cc=clang || { cat config.log meson-logs/meson-log.txt; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake check-unit V=1
|
||||
- gmake check-block V=1
|
||||
- gmake check-qapi-schema V=1
|
||||
- gmake check-softfloat V=1
|
||||
- gmake check-qtest-x86_64 V=1
|
||||
|
||||
windows_msys2_task:
|
||||
timeout_in: 90m
|
||||
windows_container:
|
||||
|
@ -12,7 +67,7 @@ windows_msys2_task:
|
|||
CIRRUS_SHELL: powershell
|
||||
MSYS: winsymlinks:nativestrict
|
||||
MSYSTEM: MINGW64
|
||||
MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-04-19/msys2-base-x86_64-20210419.sfx.exe
|
||||
MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-01-05/msys2-base-x86_64-20210105.sfx.exe
|
||||
MSYS2_FINGERPRINT: 0
|
||||
MSYS2_PACKAGES: "
|
||||
diffutils git grep make pkg-config sed
|
||||
|
@ -75,7 +130,7 @@ windows_msys2_task:
|
|||
taskkill /F /FI "MODULES eq msys-2.0.dll"
|
||||
tasklist
|
||||
C:\tools\msys64\usr\bin\bash.exe -lc "mv -f /etc/pacman.conf.pacnew /etc/pacman.conf || true"
|
||||
C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Syuu --overwrite=*"
|
||||
C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Suu --overwrite=*"
|
||||
Write-Output "Core install time taken: $((Get-Date).Subtract($start_time))"
|
||||
$start_time = Get-Date
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
|
||||
|
||||
# Close issues and pull requests
|
||||
close: true
|
||||
|
||||
# Lock issues and pull requests
|
||||
lock: true
|
||||
|
||||
issues:
|
||||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's repostories hosted
|
||||
at https://gitlab.com/qemu-project/qemu.git.
|
||||
The project does not process issues filed on GitHub.
|
||||
|
||||
The project issues are tracked on Launchpad:
|
||||
https://bugs.launchpad.net/qemu
|
||||
|
||||
QEMU welcomes bug report contributions. You can file new ones on:
|
||||
https://bugs.launchpad.net/qemu/+filebug
|
||||
|
||||
pulls:
|
||||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's repostories hosted
|
||||
on https://gitlab.com/qemu-project/qemu.git.
|
||||
The project does not process merge requests filed on GitHub.
|
||||
|
||||
QEMU welcomes contributions of code (either fixing bugs or adding new
|
||||
functionality). However, we get a lot of patches, and so we have some
|
||||
guidelines about contributing on the project website:
|
||||
https://www.qemu.org/contribute/
|
|
@ -1,30 +0,0 @@
|
|||
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
|
||||
|
||||
name: 'Repo Lockdown'
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: opened
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/repo-lockdown@v2
|
||||
with:
|
||||
pull-comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's repostories hosted
|
||||
on https://gitlab.com/qemu-project/qemu.git.
|
||||
The project does not process merge requests filed on GitHub.
|
||||
|
||||
QEMU welcomes contributions of code (either fixing bugs or adding new
|
||||
functionality). However, we get a lot of patches, and so we have some
|
||||
guidelines about contributing on the project website:
|
||||
https://www.qemu.org/contribute/
|
||||
lock-pull: true
|
||||
close-pull: true
|
|
@ -13,5 +13,3 @@ GTAGS
|
|||
*~
|
||||
*.ast_raw
|
||||
*.depend_raw
|
||||
*.swp
|
||||
*.patch
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
.native_build_job_template:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
before_script:
|
||||
- JOBS=$(expr $(nproc) + 1)
|
||||
script:
|
||||
- if test -n "$LD_JOBS";
|
||||
then
|
||||
scripts/git-submodule.sh update meson ;
|
||||
fi
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if test -n "$TARGETS";
|
||||
then
|
||||
../configure --enable-werror --disable-docs ${LD_JOBS:+--meson=git} $CONFIGURE_ARGS --target-list="$TARGETS" ;
|
||||
else
|
||||
../configure --enable-werror --disable-docs ${LD_JOBS:+--meson=git} $CONFIGURE_ARGS ;
|
||||
fi || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- if test -n "$LD_JOBS";
|
||||
then
|
||||
../meson/meson.py configure . -Dbackend_max_links="$LD_JOBS" ;
|
||||
fi || exit 1;
|
||||
- make -j"$JOBS"
|
||||
- if test -n "$MAKE_CHECK_ARGS";
|
||||
then
|
||||
make -j"$JOBS" $MAKE_CHECK_ARGS ;
|
||||
fi
|
||||
|
||||
.native_test_job_template:
|
||||
stage: test
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
script:
|
||||
- scripts/git-submodule.sh update
|
||||
$(sed -n '/GIT_SUBMODULES=/ s/.*=// p' build/config-host.mak)
|
||||
- cd build
|
||||
- find . -type f -exec touch {} +
|
||||
# Avoid recompiling by hiding ninja with NINJA=":"
|
||||
- make NINJA=":" $MAKE_CHECK_ARGS
|
||||
|
||||
.avocado_test_job_template:
|
||||
extends: .native_test_job_template
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}-cache"
|
||||
paths:
|
||||
- ${CI_PROJECT_DIR}/avocado-cache
|
||||
policy: pull-push
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
when: on_failure
|
||||
expire_in: 7 days
|
||||
paths:
|
||||
- build/tests/results/latest/results.xml
|
||||
- build/tests/results/latest/test-results
|
||||
reports:
|
||||
junit: build/tests/results/latest/results.xml
|
||||
before_script:
|
||||
- mkdir -p ~/.config/avocado
|
||||
- echo "[datadir.paths]" > ~/.config/avocado/avocado.conf
|
||||
- echo "cache_dirs = ['${CI_PROJECT_DIR}/avocado-cache']"
|
||||
>> ~/.config/avocado/avocado.conf
|
||||
- echo -e '[job.output.testlogs]\nstatuses = ["FAIL", "INTERRUPT"]'
|
||||
>> ~/.config/avocado/avocado.conf
|
||||
- if [ -d ${CI_PROJECT_DIR}/avocado-cache ]; then
|
||||
du -chs ${CI_PROJECT_DIR}/avocado-cache ;
|
||||
fi
|
||||
- export AVOCADO_ALLOW_UNTRUSTED_CODE=1
|
||||
after_script:
|
||||
- cd build
|
||||
- du -chs ${CI_PROJECT_DIR}/avocado-cache
|
||||
rules:
|
||||
# Only run these jobs if running on the mainstream namespace,
|
||||
# or if the user set the QEMU_CI_AVOCADO_TESTING variable (either
|
||||
# in its namespace setting or via git-push option, see documentation
|
||||
# in /.gitlab-ci.yml of this repository).
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
|
||||
when: on_success
|
||||
- if: '$QEMU_CI_AVOCADO_TESTING'
|
||||
when: on_success
|
||||
# Otherwise, set to manual (the jobs are created but not run).
|
||||
- when: manual
|
||||
allow_failure: true
|
|
@ -1,672 +0,0 @@
|
|||
include:
|
||||
- local: '/.gitlab-ci.d/buildtest-template.yml'
|
||||
|
||||
build-system-alpine:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
- job: amd64-alpine-container
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
CONFIGURE_ARGS: --enable-docs --enable-trace-backends=log,simple,syslog
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- .git-submodule-status
|
||||
- build
|
||||
|
||||
check-system-alpine:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-alpine
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check-unit check-qtest
|
||||
|
||||
avocado-system-alpine:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-system-alpine
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
build-system-ubuntu:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-ubuntu:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-ubuntu
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-ubuntu:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-system-ubuntu
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
build-system-debian:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
|
||||
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-debian:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-debian:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
crash-test-debian:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
script:
|
||||
- cd build
|
||||
- scripts/device-crash-test -q ./qemu-system-i386
|
||||
|
||||
build-system-fedora:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs
|
||||
--enable-fdt=system --enable-slirp=system --enable-capstone=system
|
||||
TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu
|
||||
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-fedora:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-fedora:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
crash-test-fedora:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
script:
|
||||
- cd build
|
||||
- scripts/device-crash-test -q ./qemu-system-ppc
|
||||
- scripts/device-crash-test -q ./qemu-system-riscv32
|
||||
|
||||
build-system-centos:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-fdt=system
|
||||
--enable-modules --enable-trace-backends=dtrace --enable-docs
|
||||
TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu
|
||||
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-centos:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-centos
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-centos:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-system-centos
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
build-system-opensuse:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-opensuse-leap-container
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
CONFIGURE_ARGS: --enable-fdt=system
|
||||
TARGETS: s390x-softmmu x86_64-softmmu aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-opensuse:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-opensuse
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-system-opensuse:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-system-opensuse
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
|
||||
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by
|
||||
# the configure script. The container doesn't contain Xen headers so
|
||||
# Xen accelerator is not detected / selected. As result it build the
|
||||
# i386-softmmu and x86_64-softmmu with KVM being the single accelerator
|
||||
# available.
|
||||
# Also use a different coroutine implementation (which is only really of
|
||||
# interest to KVM users, i.e. with TCG disabled)
|
||||
build-tcg-disabled:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-tcg --audio-drv-list="" --with-coroutine=ucontext
|
||||
|| { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make -j"$JOBS"
|
||||
- make check-unit
|
||||
- make check-qapi-schema
|
||||
- cd tests/qemu-iotests/
|
||||
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
|
||||
052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163
|
||||
170 171 183 184 192 194 208 221 226 227 236 253 277 image-fleecing
|
||||
- ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122
|
||||
124 132 139 142 144 145 151 152 155 157 165 194 196 200 202
|
||||
208 209 216 218 227 234 246 247 248 250 254 255 257 258
|
||||
260 261 262 263 264 270 272 273 277 279 image-fleecing
|
||||
|
||||
build-user:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
build-user-static:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system --static
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
# Because the hexagon cross-compiler takes so long to build we don't rely
|
||||
# on the CI system to build it and hence this job has an optional dependency
|
||||
# declared. The image is manually uploaded.
|
||||
build-user-hexagon:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: hexagon-cross-container
|
||||
optional: true
|
||||
variables:
|
||||
IMAGE: debian-hexagon-cross
|
||||
TARGETS: hexagon-linux-user
|
||||
CONFIGURE_ARGS: --disable-tools --disable-docs --enable-debug-tcg
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
# Only build the softmmu targets we have check-tcg tests for
|
||||
build-some-softmmu:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --enable-debug
|
||||
TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
# We build tricore in a very minimal tricore only container
|
||||
build-tricore-softmmu:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: tricore-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-tricore-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-fdt --enable-debug
|
||||
TARGETS: tricore-softmmu
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
clang-system:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
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
|
||||
MAKE_CHECK_ARGS: check-qtest check-tcg
|
||||
|
||||
clang-user:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system
|
||||
--target-list-exclude=microblazeel-linux-user,aarch64_be-linux-user,i386-linux-user,m68k-linux-user,mipsn32el-linux-user,xtensaeb-linux-user
|
||||
--extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined
|
||||
MAKE_CHECK_ARGS: check-unit check-tcg
|
||||
|
||||
# Set LD_JOBS=1 because this requires LTO and ld consumes a large amount of memory.
|
||||
# On gitlab runners, default value sometimes end up calling 2 lds concurrently and
|
||||
# triggers an Out-Of-Memory error
|
||||
#
|
||||
# Since slirp callbacks are used in QEMU Timers, slirp needs to be compiled together
|
||||
# with QEMU and linked as a static library to avoid false positives in CFI checks.
|
||||
# This can be accomplished by using -enable-slirp=git, which avoids the use of
|
||||
# a system-wide version of the library
|
||||
#
|
||||
# Split in three sets of build/check/avocado to limit the execution time of each
|
||||
# job
|
||||
build-cfi-aarch64:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
rules:
|
||||
# FIXME: This job is often failing, likely due to out-of-memory problems in
|
||||
# the constrained containers of the shared runners. Thus this is marked as
|
||||
# manual until the situation has been solved.
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
check-cfi-aarch64:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-cfi-aarch64:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
build-cfi-ppc64-s390x:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: ppc64-softmmu s390x-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
rules:
|
||||
# FIXME: This job is often failing, likely due to out-of-memory problems in
|
||||
# the constrained containers of the shared runners. Thus this is marked as
|
||||
# manual until the situation has been solved.
|
||||
- when: manual
|
||||
allow_failure: true
|
||||
|
||||
check-cfi-ppc64-s390x:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-cfi-ppc64-s390x:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
build-cfi-x86_64:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: x86_64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-x86_64:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
avocado-cfi-x86_64:
|
||||
extends: .avocado_test_job_template
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
tsan-build:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-tsan --cc=clang-10 --cxx=clang++-10
|
||||
--enable-trace-backends=ust --enable-fdt=system --enable-slirp=system
|
||||
TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user
|
||||
MAKE_CHECK_ARGS: bench V=1
|
||||
|
||||
# These targets are on the way out
|
||||
build-deprecated:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools
|
||||
MAKE_CHECK_ARGS: build-tcg
|
||||
TARGETS: ppc64abi32-linux-user
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
# We split the check-tcg step as test failures are expected but we still
|
||||
# want to catch the build breaking.
|
||||
check-deprecated:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-deprecated
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
allow_failure: true
|
||||
|
||||
# gprof/gcov are GCC features
|
||||
build-gprof-gcov:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-gprof --enable-gcov
|
||||
TARGETS: aarch64-softmmu ppc64-softmmu s390x-softmmu x86_64-softmmu
|
||||
artifacts:
|
||||
expire_in: 1 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-gprof-gcov:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-gprof-gcov
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check
|
||||
after_script:
|
||||
- ${CI_PROJECT_DIR}/scripts/ci/coverage-summary.sh
|
||||
|
||||
build-oss-fuzz:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
script:
|
||||
- mkdir build-oss-fuzz
|
||||
- CC="clang" CXX="clang++" CFLAGS="-fsanitize=address"
|
||||
./scripts/oss-fuzz/build.sh
|
||||
- export ASAN_OPTIONS="fast_unwind_on_malloc=0"
|
||||
- for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f
|
||||
| grep -v slirp); do
|
||||
grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ;
|
||||
echo Testing ${fuzzer} ... ;
|
||||
"${fuzzer}" -runs=1 -seed=1 || exit 1 ;
|
||||
done
|
||||
# Unrelated to fuzzer: run some tests with -fsanitize=address
|
||||
- cd build-oss-fuzz && make check-qtest-i386 check-unit
|
||||
|
||||
build-tci:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
script:
|
||||
- TARGETS="aarch64 alpha arm hppa m68k microblaze ppc64 s390x x86_64"
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-tcg-interpreter
|
||||
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)" || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make -j"$JOBS"
|
||||
- make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
|
||||
- for tg in $TARGETS ; do
|
||||
export QTEST_QEMU_BINARY="./qemu-system-${tg}" ;
|
||||
./tests/qtest/boot-serial-test || exit 1 ;
|
||||
./tests/qtest/cdrom-test || exit 1 ;
|
||||
done
|
||||
- QTEST_QEMU_BINARY="./qemu-system-x86_64" ./tests/qtest/pxe-test
|
||||
- QTEST_QEMU_BINARY="./qemu-system-s390x" ./tests/qtest/pxe-test -m slow
|
||||
- make check-tcg
|
||||
|
||||
# Alternate coroutines implementations are only really of interest to KVM users
|
||||
# However we can't test against KVM on Gitlab-CI so we can only run unit tests
|
||||
build-coroutine-sigaltstack:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --with-coroutine=sigaltstack --disable-tcg
|
||||
--enable-trace-backends=ftrace
|
||||
MAKE_CHECK_ARGS: check-unit
|
||||
|
||||
# Check our reduced build configurations
|
||||
build-without-default-devices:
|
||||
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-features
|
||||
--disable-capstone
|
||||
--disable-pie
|
||||
--disable-qom-cast-debug
|
||||
--disable-slirp
|
||||
--disable-strip
|
||||
TARGETS: avr-softmmu i386-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
|
||||
|
||||
build-libvhost-user:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/fedora:latest
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
script:
|
||||
- mkdir subprojects/libvhost-user/build
|
||||
- cd subprojects/libvhost-user/build
|
||||
- meson
|
||||
- ninja
|
||||
|
||||
# No targets are built here, just tools, docs, and unit tests. This
|
||||
# also feeds into the eventual documentation deployment steps later
|
||||
build-tools-and-docs-debian:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-unit check-softfloat ctags TAGS cscope
|
||||
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
# Prepare for GitLab pages deployment. Anything copied into the
|
||||
# "public" directory will be deployed to $USER.gitlab.io/$PROJECT
|
||||
#
|
||||
# GitLab publishes from any branch that triggers a CI pipeline
|
||||
#
|
||||
# For the main repo we don't want to publish from 'staging'
|
||||
# since that content may not be pushed, nor do we wish to
|
||||
# publish from 'stable-NNN' branches as that content is outdated.
|
||||
# Thus we restrict to just the default branch
|
||||
#
|
||||
# For contributor forks we want to publish from any repo so
|
||||
# that users can see the results of their commits, regardless
|
||||
# of what topic branch they're currently using
|
||||
pages:
|
||||
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest
|
||||
stage: test
|
||||
needs:
|
||||
- job: build-tools-and-docs-debian
|
||||
script:
|
||||
- mkdir -p public
|
||||
# HTML-ised source tree
|
||||
- make gtags
|
||||
- htags -anT --tree-view=filetree -m qemu_init
|
||||
-t "Welcome to the QEMU sourcecode"
|
||||
- mv HTML public/src
|
||||
# Project documentation
|
||||
- make -C build install DESTDIR=$(pwd)/temp-install
|
||||
- mv temp-install/usr/local/share/doc/qemu/* public/
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||
when: on_success
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
|
||||
when: never
|
||||
- if: '$CI_PROJECT_NAMESPACE != "qemu-project"'
|
||||
when: on_success
|
|
@ -1,123 +0,0 @@
|
|||
# Jobs that we delegate to Cirrus CI because they require an operating
|
||||
# system other than Linux. These jobs will only run if the required
|
||||
# setup has been performed on the GitLab account.
|
||||
#
|
||||
# The Cirrus CI configuration is generated by replacing target-specific
|
||||
# variables in a generic template: some of these variables are provided
|
||||
# when the GitLab CI job is defined, others are taken from a shell
|
||||
# snippet generated using lcitool.
|
||||
#
|
||||
# Note that the $PATH environment variable has to be treated with
|
||||
# special care, because we can't just override it at the GitLab CI job
|
||||
# definition level or we risk breaking it completely.
|
||||
.cirrus_build_job:
|
||||
stage: build
|
||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
||||
needs: []
|
||||
timeout: 80m
|
||||
allow_failure: true
|
||||
script:
|
||||
- source .gitlab-ci.d/cirrus/$NAME.vars
|
||||
- sed -e "s|[@]CI_REPOSITORY_URL@|$CI_REPOSITORY_URL|g"
|
||||
-e "s|[@]CI_COMMIT_REF_NAME@|$CI_COMMIT_REF_NAME|g"
|
||||
-e "s|[@]CI_COMMIT_SHA@|$CI_COMMIT_SHA|g"
|
||||
-e "s|[@]CIRRUS_VM_INSTANCE_TYPE@|$CIRRUS_VM_INSTANCE_TYPE|g"
|
||||
-e "s|[@]CIRRUS_VM_IMAGE_SELECTOR@|$CIRRUS_VM_IMAGE_SELECTOR|g"
|
||||
-e "s|[@]CIRRUS_VM_IMAGE_NAME@|$CIRRUS_VM_IMAGE_NAME|g"
|
||||
-e "s|[@]CIRRUS_VM_CPUS@|$CIRRUS_VM_CPUS|g"
|
||||
-e "s|[@]CIRRUS_VM_RAM@|$CIRRUS_VM_RAM|g"
|
||||
-e "s|[@]UPDATE_COMMAND@|$UPDATE_COMMAND|g"
|
||||
-e "s|[@]INSTALL_COMMAND@|$INSTALL_COMMAND|g"
|
||||
-e "s|[@]PATH@|$PATH_EXTRA${PATH_EXTRA:+:}\$PATH|g"
|
||||
-e "s|[@]PKG_CONFIG_PATH@|$PKG_CONFIG_PATH|g"
|
||||
-e "s|[@]PKGS@|$PKGS|g"
|
||||
-e "s|[@]MAKE@|$MAKE|g"
|
||||
-e "s|[@]PYTHON@|$PYTHON|g"
|
||||
-e "s|[@]PIP3@|$PIP3|g"
|
||||
-e "s|[@]PYPI_PKGS@|$PYPI_PKGS|g"
|
||||
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
|
||||
-e "s|[@]TEST_TARGETS@|$TEST_TARGETS|g"
|
||||
<.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
||||
rules:
|
||||
# Allow on 'staging' branch and 'stable-X.Y-staging' branches only
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/'
|
||||
when: never
|
||||
- if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN"
|
||||
|
||||
x64-freebsd-12-build:
|
||||
extends: .cirrus_build_job
|
||||
variables:
|
||||
NAME: freebsd-12
|
||||
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
|
||||
CIRRUS_VM_IMAGE_SELECTOR: image_family
|
||||
CIRRUS_VM_IMAGE_NAME: freebsd-12-3
|
||||
CIRRUS_VM_CPUS: 8
|
||||
CIRRUS_VM_RAM: 8G
|
||||
UPDATE_COMMAND: pkg update
|
||||
INSTALL_COMMAND: pkg install -y
|
||||
TEST_TARGETS: check
|
||||
|
||||
x64-freebsd-13-build:
|
||||
extends: .cirrus_build_job
|
||||
variables:
|
||||
NAME: freebsd-13
|
||||
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
|
||||
CIRRUS_VM_IMAGE_SELECTOR: image_family
|
||||
CIRRUS_VM_IMAGE_NAME: freebsd-13-0
|
||||
CIRRUS_VM_CPUS: 8
|
||||
CIRRUS_VM_RAM: 8G
|
||||
UPDATE_COMMAND: pkg update
|
||||
INSTALL_COMMAND: pkg install -y
|
||||
TEST_TARGETS: check
|
||||
|
||||
x64-macos-11-base-build:
|
||||
extends: .cirrus_build_job
|
||||
variables:
|
||||
NAME: macos-11
|
||||
CIRRUS_VM_INSTANCE_TYPE: osx_instance
|
||||
CIRRUS_VM_IMAGE_SELECTOR: image
|
||||
CIRRUS_VM_IMAGE_NAME: big-sur-base
|
||||
CIRRUS_VM_CPUS: 12
|
||||
CIRRUS_VM_RAM: 24G
|
||||
UPDATE_COMMAND: brew update
|
||||
INSTALL_COMMAND: brew install
|
||||
PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin
|
||||
PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig
|
||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
||||
|
||||
|
||||
# The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job
|
||||
.cirrus_kvm_job:
|
||||
stage: build
|
||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
||||
needs: []
|
||||
timeout: 80m
|
||||
allow_failure: true
|
||||
script:
|
||||
- sed -e "s|[@]CI_REPOSITORY_URL@|$CI_REPOSITORY_URL|g"
|
||||
-e "s|[@]CI_COMMIT_REF_NAME@|$CI_COMMIT_REF_NAME|g"
|
||||
-e "s|[@]CI_COMMIT_SHA@|$CI_COMMIT_SHA|g"
|
||||
-e "s|[@]NAME@|$NAME|g"
|
||||
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
|
||||
-e "s|[@]TEST_TARGETS@|$TEST_TARGETS|g"
|
||||
<.gitlab-ci.d/cirrus/kvm-build.yml >.gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
||||
rules:
|
||||
- when: manual
|
||||
|
||||
x86-netbsd:
|
||||
extends: .cirrus_kvm_job
|
||||
variables:
|
||||
NAME: netbsd
|
||||
CONFIGURE_ARGS: --target-list=x86_64-softmmu,ppc64-softmmu,aarch64-softmmu
|
||||
TEST_TARGETS: check
|
||||
|
||||
x86-openbsd:
|
||||
extends: .cirrus_kvm_job
|
||||
variables:
|
||||
NAME: openbsd
|
||||
CONFIGURE_ARGS: --target-list=i386-softmmu,riscv64-softmmu,mips64-softmmu
|
||||
TEST_TARGETS: check
|
|
@ -1,54 +0,0 @@
|
|||
Cirrus CI integration
|
||||
=====================
|
||||
|
||||
GitLab CI shared runners only provide a docker environment running on Linux.
|
||||
While it is possible to provide private runners for non-Linux platforms this
|
||||
is not something most contributors/maintainers will wish to do.
|
||||
|
||||
To work around this limitation, we take advantage of `Cirrus CI`_'s free
|
||||
offering: more specifically, we use the `cirrus-run`_ script to trigger Cirrus
|
||||
CI jobs from GitLab CI jobs so that Cirrus CI job output is integrated into
|
||||
the main GitLab CI pipeline dashboard.
|
||||
|
||||
There is, however, some one-time setup required. If you want FreeBSD and macOS
|
||||
builds to happen when you push to your GitLab repository, you need to
|
||||
|
||||
* set up a GitHub repository for the project, eg. ``yourusername/qemu``.
|
||||
This repository needs to exist for cirrus-run to work, but it doesn't need to
|
||||
be kept up to date, so you can create it and then forget about it;
|
||||
|
||||
* enable the `Cirrus CI GitHub app`_ for your GitHub account;
|
||||
|
||||
* sign up for Cirrus CI. It's enough to log into the website using your GitHub
|
||||
account;
|
||||
|
||||
* grab an API token from the `Cirrus CI settings`_ page;
|
||||
|
||||
* it may be necessary to push an empty ``.cirrus.yml`` file to your github fork
|
||||
for Cirrus CI to properly recognize the project. You can check whether
|
||||
Cirrus CI knows about your project by navigating to:
|
||||
|
||||
``https://cirrus-ci.com/yourusername/qemu``
|
||||
|
||||
* in the *CI/CD / Variables* section of the settings page for your GitLab
|
||||
repository, create two new variables:
|
||||
|
||||
* ``CIRRUS_GITHUB_REPO``, containing the name of the GitHub repository
|
||||
created earlier, eg. ``yourusername/qemu``;
|
||||
|
||||
* ``CIRRUS_API_TOKEN``, containing the Cirrus CI API token generated earlier.
|
||||
This variable **must** be marked as *Masked*, because anyone with knowledge
|
||||
of it can impersonate you as far as Cirrus CI is concerned.
|
||||
|
||||
Neither of these variables should be marked as *Protected*, because in
|
||||
general you'll want to be able to trigger Cirrus CI builds from non-protected
|
||||
branches.
|
||||
|
||||
Once this one-time setup is complete, you can just keep pushing to your GitLab
|
||||
repository as usual and you'll automatically get the additional CI coverage.
|
||||
|
||||
|
||||
.. _Cirrus CI GitHub app: https://github.com/marketplace/cirrus-ci
|
||||
.. _Cirrus CI settings: https://cirrus-ci.com/settings/profile/
|
||||
.. _Cirrus CI: https://cirrus-ci.com/
|
||||
.. _cirrus-run: https://github.com/sio/cirrus-run/
|
|
@ -1,36 +0,0 @@
|
|||
@CIRRUS_VM_INSTANCE_TYPE@:
|
||||
@CIRRUS_VM_IMAGE_SELECTOR@: @CIRRUS_VM_IMAGE_NAME@
|
||||
cpu: @CIRRUS_VM_CPUS@
|
||||
memory: @CIRRUS_VM_RAM@
|
||||
|
||||
env:
|
||||
CIRRUS_CLONE_DEPTH: 1
|
||||
CI_REPOSITORY_URL: "@CI_REPOSITORY_URL@"
|
||||
CI_COMMIT_REF_NAME: "@CI_COMMIT_REF_NAME@"
|
||||
CI_COMMIT_SHA: "@CI_COMMIT_SHA@"
|
||||
PATH: "@PATH@"
|
||||
PKG_CONFIG_PATH: "@PKG_CONFIG_PATH@"
|
||||
PYTHON: "@PYTHON@"
|
||||
MAKE: "@MAKE@"
|
||||
CONFIGURE_ARGS: "@CONFIGURE_ARGS@"
|
||||
TEST_TARGETS: "@TEST_TARGETS@"
|
||||
|
||||
build_task:
|
||||
install_script:
|
||||
- @UPDATE_COMMAND@
|
||||
- @INSTALL_COMMAND@ @PKGS@
|
||||
- if test -n "@PYPI_PKGS@" ; then @PIP3@ install @PYPI_PKGS@ ; fi
|
||||
clone_script:
|
||||
- git clone --depth 100 "$CI_REPOSITORY_URL" .
|
||||
- git fetch origin "$CI_COMMIT_REF_NAME"
|
||||
- git reset --hard "$CI_COMMIT_SHA"
|
||||
build_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-werror $CONFIGURE_ARGS
|
||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
||||
- $MAKE -j$(sysctl -n hw.ncpu)
|
||||
- for TARGET in $TEST_TARGETS ;
|
||||
do
|
||||
$MAKE -j$(sysctl -n hw.ncpu) $TARGET V=1 ;
|
||||
done
|
|
@ -1,16 +0,0 @@
|
|||
# THIS FILE WAS AUTO-GENERATED
|
||||
#
|
||||
# $ lcitool variables freebsd-12 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
CCACHE='/usr/local/bin/ccache'
|
||||
CPAN_PKGS=''
|
||||
CROSS_PKGS=''
|
||||
MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PACKAGING_COMMAND='pkg'
|
||||
PIP3='/usr/local/bin/pip-3.8'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PYPI_PKGS=''
|
||||
PYTHON='/usr/local/bin/python3'
|
|
@ -1,16 +0,0 @@
|
|||
# THIS FILE WAS AUTO-GENERATED
|
||||
#
|
||||
# $ lcitool variables freebsd-13 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
CCACHE='/usr/local/bin/ccache'
|
||||
CPAN_PKGS=''
|
||||
CROSS_PKGS=''
|
||||
MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PACKAGING_COMMAND='pkg'
|
||||
PIP3='/usr/local/bin/pip-3.8'
|
||||
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils dtc gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||
PYPI_PKGS=''
|
||||
PYTHON='/usr/local/bin/python3'
|
|
@ -1,31 +0,0 @@
|
|||
container:
|
||||
image: fedora:35
|
||||
cpu: 4
|
||||
memory: 8Gb
|
||||
kvm: true
|
||||
|
||||
env:
|
||||
CIRRUS_CLONE_DEPTH: 1
|
||||
CI_REPOSITORY_URL: "@CI_REPOSITORY_URL@"
|
||||
CI_COMMIT_REF_NAME: "@CI_COMMIT_REF_NAME@"
|
||||
CI_COMMIT_SHA: "@CI_COMMIT_SHA@"
|
||||
|
||||
@NAME@_task:
|
||||
@NAME@_vm_cache:
|
||||
folder: $HOME/.cache/qemu-vm
|
||||
install_script:
|
||||
- dnf update -y
|
||||
- dnf install -y git make openssh-clients qemu-img qemu-system-x86 wget
|
||||
clone_script:
|
||||
- git clone --depth 100 "$CI_REPOSITORY_URL" .
|
||||
- git fetch origin "$CI_COMMIT_REF_NAME"
|
||||
- git reset --hard "$CI_COMMIT_SHA"
|
||||
build_script:
|
||||
- if [ -f $HOME/.cache/qemu-vm/images/@NAME@.img ]; then
|
||||
make vm-build-@NAME@ J=$(getconf _NPROCESSORS_ONLN)
|
||||
EXTRA_CONFIGURE_OPTS="@CONFIGURE_ARGS@"
|
||||
BUILD_TARGET="@TEST_TARGETS@" ;
|
||||
else
|
||||
make vm-build-@NAME@ J=$(getconf _NPROCESSORS_ONLN) BUILD_TARGET=help
|
||||
EXTRA_CONFIGURE_OPTS="--disable-system --disable-user --disable-tools" ;
|
||||
fi
|
|
@ -1,16 +0,0 @@
|
|||
# THIS FILE WAS AUTO-GENERATED
|
||||
#
|
||||
# $ lcitool variables macos-11 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
CCACHE='/usr/local/bin/ccache'
|
||||
CPAN_PKGS='Test::Harness'
|
||||
CROSS_PKGS=''
|
||||
MAKE='/usr/local/bin/gmake'
|
||||
NINJA='/usr/local/bin/ninja'
|
||||
PACKAGING_COMMAND='brew'
|
||||
PIP3='/usr/local/bin/pip3'
|
||||
PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils dtc gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb libxml2 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'
|
||||
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme virtualenv'
|
||||
PYTHON='/usr/local/bin/python3'
|
|
@ -1,17 +0,0 @@
|
|||
include:
|
||||
- local: '/.gitlab-ci.d/container-template.yml'
|
||||
|
||||
amd64-centos8-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: centos8
|
||||
|
||||
amd64-fedora-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: fedora
|
||||
|
||||
amd64-debian10-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: debian10
|
|
@ -1,193 +0,0 @@
|
|||
alpha-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-alpha-cross
|
||||
|
||||
amd64-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-amd64-cross
|
||||
|
||||
amd64-debian-user-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-all-test-cross
|
||||
|
||||
arm64-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-arm64-cross
|
||||
|
||||
arm64-test-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian11-container']
|
||||
variables:
|
||||
NAME: debian-arm64-test-cross
|
||||
|
||||
armel-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-armel-cross
|
||||
|
||||
armhf-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-armhf-cross
|
||||
|
||||
# We never want to build hexagon in the CI system and by default we
|
||||
# always want to refer to the master registry where it lives.
|
||||
hexagon-cross-container:
|
||||
image: docker:stable
|
||||
stage: containers
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
|
||||
when: never
|
||||
- when: always
|
||||
variables:
|
||||
NAME: debian-hexagon-cross
|
||||
GIT_DEPTH: 1
|
||||
services:
|
||||
- docker:dind
|
||||
before_script:
|
||||
- export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
|
||||
- export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/qemu/$NAME:latest"
|
||||
- docker info
|
||||
- docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
|
||||
script:
|
||||
- echo "TAG:$TAG"
|
||||
- echo "COMMON_TAG:$COMMON_TAG"
|
||||
- docker pull $COMMON_TAG
|
||||
- docker tag $COMMON_TAG $TAG
|
||||
- docker push "$TAG"
|
||||
after_script:
|
||||
- docker logout
|
||||
|
||||
hppa-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-hppa-cross
|
||||
|
||||
m68k-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-m68k-cross
|
||||
|
||||
mips64-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips64-cross
|
||||
|
||||
mips64el-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips64el-cross
|
||||
|
||||
mips-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips-cross
|
||||
|
||||
mipsel-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mipsel-cross
|
||||
|
||||
powerpc-test-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian11-container']
|
||||
variables:
|
||||
NAME: debian-powerpc-test-cross
|
||||
|
||||
ppc64el-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-ppc64el-cross
|
||||
|
||||
riscv64-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
# as we are currently based on 'sid/unstable' we may break so...
|
||||
allow_failure: true
|
||||
variables:
|
||||
NAME: debian-riscv64-cross
|
||||
|
||||
s390x-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-s390x-cross
|
||||
|
||||
sh4-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-sh4-cross
|
||||
|
||||
sparc64-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-sparc64-cross
|
||||
|
||||
tricore-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-tricore-cross
|
||||
|
||||
xtensa-debian-cross-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: debian-xtensa-cross
|
||||
|
||||
cris-fedora-cross-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: fedora-cris-cross
|
||||
|
||||
i386-fedora-cross-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: fedora-i386-cross
|
||||
|
||||
win32-fedora-cross-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: fedora-win32-cross
|
||||
|
||||
win64-fedora-cross-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: fedora-win64-cross
|
|
@ -1,21 +0,0 @@
|
|||
.container_job_template:
|
||||
image: docker:stable
|
||||
stage: containers
|
||||
services:
|
||||
- docker:dind
|
||||
before_script:
|
||||
- export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
|
||||
- export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest"
|
||||
- apk add python3
|
||||
- docker info
|
||||
- docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
|
||||
script:
|
||||
- echo "TAG:$TAG"
|
||||
- echo "COMMON_TAG:$COMMON_TAG"
|
||||
- ./tests/docker/docker.py --engine docker build
|
||||
-t "qemu/$NAME" -f "tests/docker/dockerfiles/$NAME.docker"
|
||||
-r $CI_REGISTRY/qemu-project/qemu
|
||||
- docker tag "qemu/$NAME" "$TAG"
|
||||
- docker push "$TAG"
|
||||
after_script:
|
||||
- docker logout
|
|
@ -1,40 +1,251 @@
|
|||
include:
|
||||
- local: '/.gitlab-ci.d/container-core.yml'
|
||||
- local: '/.gitlab-ci.d/container-cross.yml'
|
||||
.container_job_template: &container_job_definition
|
||||
image: docker:stable
|
||||
stage: containers
|
||||
services:
|
||||
- docker:dind
|
||||
before_script:
|
||||
- export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
|
||||
- export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest"
|
||||
- apk add python3
|
||||
- docker info
|
||||
- docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
|
||||
script:
|
||||
- echo "TAG:$TAG"
|
||||
- echo "COMMON_TAG:$COMMON_TAG"
|
||||
- docker pull "$TAG" || docker pull "$COMMON_TAG" || true
|
||||
- ./tests/docker/docker.py --engine docker build
|
||||
-t "qemu/$NAME" -f "tests/docker/dockerfiles/$NAME.docker"
|
||||
-r $CI_REGISTRY_IMAGE
|
||||
- docker tag "qemu/$NAME" "$TAG"
|
||||
- docker push "$TAG"
|
||||
after_script:
|
||||
- docker logout
|
||||
|
||||
amd64-alpine-container:
|
||||
extends: .container_job_template
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: alpine
|
||||
|
||||
amd64-centos7-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: centos7
|
||||
|
||||
amd64-centos8-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: centos8
|
||||
|
||||
amd64-debian10-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: debian10
|
||||
|
||||
amd64-debian11-container:
|
||||
extends: .container_job_template
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: debian11
|
||||
|
||||
alpha-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-alpha-cross
|
||||
|
||||
amd64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-amd64-cross
|
||||
|
||||
amd64-debian-user-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-all-test-cross
|
||||
|
||||
amd64-debian-container:
|
||||
extends: .container_job_template
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-amd64
|
||||
|
||||
arm64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-arm64-cross
|
||||
|
||||
arm64-test-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian11-container']
|
||||
variables:
|
||||
NAME: debian-arm64-test-cross
|
||||
|
||||
armel-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-armel-cross
|
||||
|
||||
armhf-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-armhf-cross
|
||||
|
||||
hppa-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-hppa-cross
|
||||
|
||||
m68k-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-m68k-cross
|
||||
|
||||
mips64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips64-cross
|
||||
|
||||
mips64el-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips64el-cross
|
||||
|
||||
mips-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips-cross
|
||||
|
||||
mipsel-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mipsel-cross
|
||||
|
||||
powerpc-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-powerpc-cross
|
||||
|
||||
ppc64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-ppc64-cross
|
||||
|
||||
ppc64el-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-ppc64el-cross
|
||||
|
||||
riscv64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-riscv64-cross
|
||||
|
||||
s390x-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-s390x-cross
|
||||
|
||||
sh4-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-sh4-cross
|
||||
|
||||
sparc64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-sparc64-cross
|
||||
|
||||
tricore-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-tricore-cross
|
||||
|
||||
xtensa-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: debian-xtensa-cross
|
||||
|
||||
cris-fedora-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora-cris-cross
|
||||
|
||||
amd64-fedora-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora
|
||||
|
||||
i386-fedora-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora-i386-cross
|
||||
|
||||
win32-fedora-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora-win32-cross
|
||||
|
||||
win64-fedora-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora-win64-cross
|
||||
|
||||
amd64-ubuntu1804-container:
|
||||
extends: .container_job_template
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: ubuntu1804
|
||||
|
||||
amd64-ubuntu2004-container:
|
||||
extends: .container_job_template
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: ubuntu2004
|
||||
|
||||
amd64-ubuntu-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: ubuntu
|
||||
|
||||
amd64-opensuse-leap-container:
|
||||
extends: .container_job_template
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: opensuse-leap
|
||||
|
||||
python-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: python
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
.cross_system_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
timeout: 80m
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-user --target-list-exclude="arm-softmmu cris-softmmu
|
||||
i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu
|
||||
mips64-softmmu ppc-softmmu riscv32-softmmu sh4-softmmu
|
||||
sparc-softmmu xtensa-softmmu $CROSS_SKIP_TARGETS"
|
||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||
- if grep -q "EXESUF=.exe" config-host.mak;
|
||||
then make installer;
|
||||
version="$(git describe --match v[0-9]*)";
|
||||
mv -v qemu-setup*.exe qemu-setup-${version}.exe;
|
||||
fi
|
||||
|
||||
# Job to cross-build specific accelerators.
|
||||
#
|
||||
# Set the $ACCEL variable to select the specific accelerator (default to
|
||||
# KVM), and set extra options (such disabling other accelerators) via the
|
||||
# $EXTRA_CONFIGURE_OPTS variable.
|
||||
.cross_accel_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
timeout: 30m
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-tools --enable-${ACCEL:-kvm} $EXTRA_CONFIGURE_OPTS
|
||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||
|
||||
.cross_user_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-system
|
||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
|
@ -1,5 +1,44 @@
|
|||
include:
|
||||
- local: '/.gitlab-ci.d/crossbuild-template.yml'
|
||||
.cross_system_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
timeout: 80m
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-user --target-list-exclude="arm-softmmu cris-softmmu
|
||||
i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu
|
||||
mips64-softmmu ppc-softmmu sh4-softmmu xtensa-softmmu"
|
||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||
|
||||
# Job to cross-build specific accelerators.
|
||||
#
|
||||
# Set the $ACCEL variable to select the specific accelerator (default to
|
||||
# KVM), and set extra options (such disabling other accelerators) via the
|
||||
# $ACCEL_CONFIGURE_OPTS variable.
|
||||
.cross_accel_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
timeout: 30m
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-tools --enable-${ACCEL:-kvm} $ACCEL_CONFIGURE_OPTS
|
||||
- make -j$(expr $(nproc) + 1) all check-build
|
||||
|
||||
.cross_user_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-system
|
||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||
|
||||
cross-armel-system:
|
||||
extends: .cross_system_build_job
|
||||
|
@ -59,15 +98,6 @@ cross-i386-user:
|
|||
IMAGE: fedora-i386-cross
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
cross-i386-tci:
|
||||
extends: .cross_accel_build_job
|
||||
timeout: 60m
|
||||
variables:
|
||||
IMAGE: fedora-i386-cross
|
||||
ACCEL: tcg-interpreter
|
||||
EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user
|
||||
MAKE_CHECK_ARGS: check check-tcg
|
||||
|
||||
cross-mips-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
|
@ -124,25 +154,6 @@ cross-ppc64el-user:
|
|||
variables:
|
||||
IMAGE: debian-ppc64el-cross
|
||||
|
||||
# The riscv64 cross-builds currently use a 'sid' container to get
|
||||
# compilers and libraries. Until something more stable is found we
|
||||
# allow_failure so as not to block CI.
|
||||
cross-riscv64-system:
|
||||
extends: .cross_system_build_job
|
||||
allow_failure: true
|
||||
needs:
|
||||
job: riscv64-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-riscv64-cross
|
||||
|
||||
cross-riscv64-user:
|
||||
extends: .cross_user_build_job
|
||||
allow_failure: true
|
||||
needs:
|
||||
job: riscv64-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-riscv64-cross
|
||||
|
||||
cross-s390x-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
|
@ -163,15 +174,7 @@ cross-s390x-kvm-only:
|
|||
job: s390x-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-s390x-cross
|
||||
EXTRA_CONFIGURE_OPTS: --disable-tcg
|
||||
|
||||
cross-mips64el-kvm-only:
|
||||
extends: .cross_accel_build_job
|
||||
needs:
|
||||
job: mips64el-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-mips64el-cross
|
||||
EXTRA_CONFIGURE_OPTS: --disable-tcg --target-list=mips64el-softmmu
|
||||
ACCEL_CONFIGURE_OPTS: --disable-tcg
|
||||
|
||||
cross-win32-system:
|
||||
extends: .cross_system_build_job
|
||||
|
@ -179,11 +182,6 @@ cross-win32-system:
|
|||
job: win32-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: fedora-win32-cross
|
||||
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
||||
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
||||
artifacts:
|
||||
paths:
|
||||
- build/qemu-setup*.exe
|
||||
|
||||
cross-win64-system:
|
||||
extends: .cross_system_build_job
|
||||
|
@ -191,11 +189,6 @@ cross-win64-system:
|
|||
job: win64-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: fedora-win64-cross
|
||||
CROSS_SKIP_TARGETS: or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu
|
||||
tricore-softmmu xtensaeb-softmmu
|
||||
artifacts:
|
||||
paths:
|
||||
- build/qemu-setup*.exe
|
||||
|
||||
cross-amd64-xen-only:
|
||||
extends: .cross_accel_build_job
|
||||
|
@ -204,7 +197,7 @@ cross-amd64-xen-only:
|
|||
variables:
|
||||
IMAGE: debian-amd64-cross
|
||||
ACCEL: xen
|
||||
EXTRA_CONFIGURE_OPTS: --disable-tcg --disable-kvm
|
||||
ACCEL_CONFIGURE_OPTS: --disable-tcg --disable-kvm
|
||||
|
||||
cross-arm64-xen-only:
|
||||
extends: .cross_accel_build_job
|
||||
|
@ -213,4 +206,4 @@ cross-arm64-xen-only:
|
|||
variables:
|
||||
IMAGE: debian-arm64-cross
|
||||
ACCEL: xen
|
||||
EXTRA_CONFIGURE_OPTS: --disable-tcg --disable-kvm
|
||||
ACCEL_CONFIGURE_OPTS: --disable-tcg --disable-kvm
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# The CI jobs defined here require GitLab runners installed and
|
||||
# registered on machines that match their operating system names,
|
||||
# versions and architectures. This is in contrast to the other CI
|
||||
# jobs that are intended to run on GitLab's "shared" runners.
|
||||
|
||||
# Different than the default approach on "shared" runners, based on
|
||||
# containers, the custom runners have no such *requirement*, as those
|
||||
# jobs should be capable of running on operating systems with no
|
||||
# compatible container implementation, or no support from
|
||||
# gitlab-runner. To avoid problems that gitlab-runner can cause while
|
||||
# reusing the GIT repository, let's enable the clone strategy, which
|
||||
# guarantees a fresh repository on each job run.
|
||||
variables:
|
||||
GIT_STRATEGY: clone
|
||||
|
||||
include:
|
||||
- local: '/.gitlab-ci.d/custom-runners/ubuntu-18.04-s390x.yml'
|
||||
- local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml'
|
||||
- local: '/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml'
|
|
@ -1,28 +0,0 @@
|
|||
centos-stream-8-x86_64:
|
||||
allow_failure: true
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- centos_stream_8
|
||||
- x86_64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$CENTOS_STREAM_8_x86_64_RUNNER_AVAILABLE"
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
when: on_failure
|
||||
expire_in: 7 days
|
||||
paths:
|
||||
- build/tests/results/latest/results.xml
|
||||
- build/tests/results/latest/test-results
|
||||
reports:
|
||||
junit: build/tests/results/latest/results.xml
|
||||
before_script:
|
||||
- JOBS=$(expr $(nproc) + 1)
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../scripts/ci/org.centos/stream/8/x86_64/configure
|
||||
- make -j"$JOBS"
|
||||
- make NINJA=":" check
|
||||
- ../scripts/ci/org.centos/stream/8/x86_64/test-avocado
|
|
@ -1,118 +0,0 @@
|
|||
# All ubuntu-18.04 jobs should run successfully in an environment
|
||||
# setup by the scripts/ci/setup/build-environment.yml task
|
||||
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||
|
||||
ubuntu-18.04-s390x-all-linux-static:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
- make --output-sync -j`nproc` check-tcg V=1
|
||||
|
||||
ubuntu-18.04-s390x-all:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-alldbg:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --disable-libssh
|
||||
- make clean
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-clang:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-18.04-s390x-tci:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||
- make --output-sync -j`nproc`
|
||||
|
||||
ubuntu-18.04-s390x-notcg:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_18.04
|
||||
- s390x
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$S390X_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --disable-tcg
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
|
@ -1,118 +0,0 @@
|
|||
# All ubuntu-20.04 jobs should run successfully in an environment
|
||||
# setup by the scripts/ci/setup/qemu/build-environment.yml task
|
||||
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||
|
||||
ubuntu-20.04-aarch64-all-linux-static:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
script:
|
||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
- make --output-sync -j`nproc` check-tcg V=1
|
||||
|
||||
ubuntu-20.04-aarch64-all:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-alldbg:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-debug --disable-libssh
|
||||
- make clean
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-clang:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
||||
|
||||
ubuntu-20.04-aarch64-tci:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||
- make --output-sync -j`nproc`
|
||||
|
||||
ubuntu-20.04-aarch64-notcg:
|
||||
needs: []
|
||||
stage: build
|
||||
tags:
|
||||
- ubuntu_20.04
|
||||
- aarch64
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-libssh --disable-tcg
|
||||
- make --output-sync -j`nproc`
|
||||
- make --output-sync -j`nproc` check V=1
|
|
@ -1,22 +1,10 @@
|
|||
# All jobs needing docker-edk2 must use the same rules it uses.
|
||||
.edk2_job_rules:
|
||||
rules: # Only run this job when ...
|
||||
- changes:
|
||||
# this file is modified
|
||||
- .gitlab-ci.d/edk2.yml
|
||||
# or the Dockerfile is modified
|
||||
- .gitlab-ci.d/edk2/Dockerfile
|
||||
# or roms/edk2/ is modified (submodule updated)
|
||||
- roms/edk2/*
|
||||
when: on_success
|
||||
- if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2'
|
||||
when: on_success
|
||||
- if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2'
|
||||
when: on_success
|
||||
|
||||
docker-edk2:
|
||||
extends: .edk2_job_rules
|
||||
stage: containers
|
||||
rules: # Only run this job when the Dockerfile is modified
|
||||
- changes:
|
||||
- .gitlab-ci.d/edk2.yml
|
||||
- .gitlab-ci.d/edk2/Dockerfile
|
||||
when: always
|
||||
image: docker:19.03.1
|
||||
services:
|
||||
- docker:19.03.1-dind
|
||||
|
@ -36,9 +24,16 @@ docker-edk2:
|
|||
- docker push $IMAGE_TAG
|
||||
|
||||
build-edk2:
|
||||
extends: .edk2_job_rules
|
||||
stage: build
|
||||
needs: ['docker-edk2']
|
||||
rules: # Only run this job when ...
|
||||
- changes: # ... roms/edk2/ is modified (submodule updated)
|
||||
- roms/edk2/*
|
||||
when: always
|
||||
- if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2'
|
||||
when: always
|
||||
- if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2'
|
||||
when: always
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/edk2*bz2
|
||||
|
@ -50,11 +45,7 @@ build-edk2:
|
|||
GIT_DEPTH: 3
|
||||
script: # Clone the required submodules and build EDK2
|
||||
- git submodule update --init roms/edk2
|
||||
- git -C roms/edk2 submodule update --init --
|
||||
ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
|
||||
BaseTools/Source/C/BrotliCompress/brotli
|
||||
CryptoPkg/Library/OpensslLib/openssl
|
||||
MdeModulePkg/Library/BrotliCustomDecompressLib/brotli
|
||||
- git -C roms/edk2 submodule update --init
|
||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
- make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
FROM ubuntu:16.04
|
||||
|
||||
MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
MAINTAINER Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
|
||||
# Install packages required to build EDK2
|
||||
RUN apt update \
|
||||
|
|
|
@ -1,23 +1,10 @@
|
|||
# All jobs needing docker-opensbi must use the same rules it uses.
|
||||
.opensbi_job_rules:
|
||||
rules: # Only run this job when ...
|
||||
- changes:
|
||||
# this file is modified
|
||||
- .gitlab-ci.d/opensbi.yml
|
||||
# or the Dockerfile is modified
|
||||
- .gitlab-ci.d/opensbi/Dockerfile
|
||||
when: on_success
|
||||
- changes: # or roms/opensbi/ is modified (submodule updated)
|
||||
- roms/opensbi/*
|
||||
when: on_success
|
||||
- if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi'
|
||||
when: on_success
|
||||
- if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI'
|
||||
when: on_success
|
||||
|
||||
docker-opensbi:
|
||||
extends: .opensbi_job_rules
|
||||
stage: containers
|
||||
rules: # Only run this job when the Dockerfile is modified
|
||||
- changes:
|
||||
- .gitlab-ci.d/opensbi.yml
|
||||
- .gitlab-ci.d/opensbi/Dockerfile
|
||||
when: always
|
||||
image: docker:19.03.1
|
||||
services:
|
||||
- docker:19.03.1-dind
|
||||
|
@ -37,13 +24,22 @@ docker-opensbi:
|
|||
- docker push $IMAGE_TAG
|
||||
|
||||
build-opensbi:
|
||||
extends: .opensbi_job_rules
|
||||
stage: build
|
||||
needs: ['docker-opensbi']
|
||||
rules: # Only run this job when ...
|
||||
- changes: # ... roms/opensbi/ is modified (submodule updated)
|
||||
- roms/opensbi/*
|
||||
when: always
|
||||
- if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi'
|
||||
when: always
|
||||
- if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI'
|
||||
when: always
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.elf
|
||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.elf
|
||||
- opensbi32-generic-stdout.log
|
||||
- opensbi32-generic-stderr.log
|
||||
- opensbi64-generic-stdout.log
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
# This file contains the set of jobs run by the QEMU project:
|
||||
# https://gitlab.com/qemu-project/qemu/-/pipelines
|
||||
|
||||
include:
|
||||
- local: '/.gitlab-ci.d/stages.yml'
|
||||
- local: '/.gitlab-ci.d/edk2.yml'
|
||||
- local: '/.gitlab-ci.d/opensbi.yml'
|
||||
- local: '/.gitlab-ci.d/containers.yml'
|
||||
- local: '/.gitlab-ci.d/crossbuilds.yml'
|
||||
- local: '/.gitlab-ci.d/buildtest.yml'
|
||||
- local: '/.gitlab-ci.d/static_checks.yml'
|
||||
- local: '/.gitlab-ci.d/custom-runners.yml'
|
||||
- local: '/.gitlab-ci.d/cirrus.yml'
|
||||
- local: '/.gitlab-ci.d/windows.yml'
|
|
@ -1,8 +0,0 @@
|
|||
# Currently we have two build stages after our containers are built:
|
||||
# - build (for traditional build and test or first stage build)
|
||||
# - test (for test stages, using build artefacts from a build stage)
|
||||
stages:
|
||||
- containers
|
||||
- containers-layer2
|
||||
- build
|
||||
- test
|
|
@ -1,51 +0,0 @@
|
|||
check-patch:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/centos8:latest
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
script:
|
||||
- .gitlab-ci.d/check-patch.py
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
|
||||
when: never
|
||||
- when: on_success
|
||||
allow_failure: true
|
||||
|
||||
check-dco:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/centos8:latest
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
script: .gitlab-ci.d/check-dco.py
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||
when: never
|
||||
- when: on_success
|
||||
|
||||
check-python-pipenv:
|
||||
stage: test
|
||||
image: $CI_REGISTRY_IMAGE/qemu/python:latest
|
||||
script:
|
||||
- make -C python check-pipenv
|
||||
variables:
|
||||
GIT_DEPTH: 1
|
||||
needs:
|
||||
job: python-container
|
||||
|
||||
check-python-tox:
|
||||
stage: test
|
||||
image: $CI_REGISTRY_IMAGE/qemu/python:latest
|
||||
script:
|
||||
- make -C python check-tox
|
||||
variables:
|
||||
GIT_DEPTH: 1
|
||||
QEMU_TOX_EXTRA_ARGS: --skip-missing-interpreters=false
|
||||
needs:
|
||||
job: python-container
|
||||
rules:
|
||||
- when: manual
|
||||
allow_failure: true
|
|
@ -1,98 +0,0 @@
|
|||
.shared_msys2_builder:
|
||||
tags:
|
||||
- shared-windows
|
||||
- windows
|
||||
- windows-1809
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}-cache"
|
||||
paths:
|
||||
- ${CI_PROJECT_DIR}/msys64/var/cache
|
||||
needs: []
|
||||
stage: build
|
||||
timeout: 70m
|
||||
before_script:
|
||||
- If ( !(Test-Path -Path msys64\var\cache ) ) {
|
||||
mkdir msys64\var\cache
|
||||
}
|
||||
- If ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) {
|
||||
Invoke-WebRequest
|
||||
"https://github.com/msys2/msys2-installer/releases/download/2021-07-25/msys2-base-x86_64-20210725.sfx.exe"
|
||||
-outfile "msys64\var\cache\msys2.exe"
|
||||
}
|
||||
- msys64\var\cache\msys2.exe -y
|
||||
- ((Get-Content -path .\msys64\etc\\post-install\\07-pacman-key.post -Raw)
|
||||
-replace '--refresh-keys', '--version') |
|
||||
Set-Content -Path ${CI_PROJECT_DIR}\msys64\etc\\post-install\\07-pacman-key.post
|
||||
- .\msys64\usr\bin\bash -lc "sed -i 's/^CheckSpace/#CheckSpace/g' /etc/pacman.conf"
|
||||
- .\msys64\usr\bin\bash -lc 'pacman --noconfirm -Syuu' # Core update
|
||||
- .\msys64\usr\bin\bash -lc 'pacman --noconfirm -Syuu' # Normal update
|
||||
- taskkill /F /FI "MODULES eq msys-2.0.dll"
|
||||
|
||||
msys2-64bit:
|
||||
extends: .shared_msys2_builder
|
||||
script:
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
diffutils git grep make sed
|
||||
mingw-w64-x86_64-capstone
|
||||
mingw-w64-x86_64-curl
|
||||
mingw-w64-x86_64-cyrus-sasl
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-glib2
|
||||
mingw-w64-x86_64-gnutls
|
||||
mingw-w64-x86_64-libnfs
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-libssh
|
||||
mingw-w64-x86_64-libtasn1
|
||||
mingw-w64-x86_64-libusb
|
||||
mingw-w64-x86_64-libxml2
|
||||
mingw-w64-x86_64-nettle
|
||||
mingw-w64-x86_64-ninja
|
||||
mingw-w64-x86_64-pixman
|
||||
mingw-w64-x86_64-pkgconf
|
||||
mingw-w64-x86_64-python
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-SDL2_image
|
||||
mingw-w64-x86_64-snappy
|
||||
mingw-w64-x86_64-usbredir
|
||||
mingw-w64-x86_64-zstd "
|
||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||
- $env:MSYSTEM = 'MINGW64' # Start a 64 bit Mingw environment
|
||||
- .\msys64\usr\bin\bash -lc './configure --target-list=x86_64-softmmu
|
||||
--enable-capstone=system --without-default-devices'
|
||||
- .\msys64\usr\bin\bash -lc "sed -i '/^ROMS=/d' build/config-host.mak"
|
||||
- .\msys64\usr\bin\bash -lc 'make -j2'
|
||||
- .\msys64\usr\bin\bash -lc 'make check'
|
||||
|
||||
msys2-32bit:
|
||||
extends: .shared_msys2_builder
|
||||
script:
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
diffutils git grep make sed
|
||||
mingw-w64-i686-capstone
|
||||
mingw-w64-i686-curl
|
||||
mingw-w64-i686-cyrus-sasl
|
||||
mingw-w64-i686-gcc
|
||||
mingw-w64-i686-glib2
|
||||
mingw-w64-i686-gnutls
|
||||
mingw-w64-i686-gtk3
|
||||
mingw-w64-i686-libgcrypt
|
||||
mingw-w64-i686-libjpeg-turbo
|
||||
mingw-w64-i686-libssh
|
||||
mingw-w64-i686-libtasn1
|
||||
mingw-w64-i686-libusb
|
||||
mingw-w64-i686-libxml2
|
||||
mingw-w64-i686-lzo2
|
||||
mingw-w64-i686-ninja
|
||||
mingw-w64-i686-pixman
|
||||
mingw-w64-i686-pkgconf
|
||||
mingw-w64-i686-python
|
||||
mingw-w64-i686-snappy
|
||||
mingw-w64-i686-usbredir "
|
||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||
- $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinG environment
|
||||
- mkdir output
|
||||
- cd output
|
||||
- ..\msys64\usr\bin\bash -lc "../configure --target-list=ppc64-softmmu
|
||||
--enable-capstone=system"
|
||||
- ..\msys64\usr\bin\bash -lc 'make -j2'
|
||||
- ..\msys64\usr\bin\bash -lc 'make check'
|
857
.gitlab-ci.yml
857
.gitlab-ci.yml
|
@ -1,24 +1,837 @@
|
|||
#
|
||||
# This is the GitLab CI configuration file for the mainstream QEMU
|
||||
# project: https://gitlab.com/qemu-project/qemu/-/pipelines
|
||||
#
|
||||
# !!! DO NOT ADD ANY NEW CONFIGURATION TO THIS FILE !!!
|
||||
#
|
||||
# Only documentation or comments is accepted.
|
||||
#
|
||||
# To use a different set of jobs than the mainstream QEMU project,
|
||||
# you need to set the location of your custom yml file at "custom CI/CD
|
||||
# configuration path", on your GitLab CI namespace:
|
||||
# https://docs.gitlab.com/ee/ci/pipelines/settings.html#custom-cicd-configuration-path
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# QEMU CI jobs are based on templates. Some templates provide
|
||||
# user-configurable options, modifiable via configuration variables.
|
||||
#
|
||||
# See https://qemu-project.gitlab.io/qemu/devel/ci.html#custom-ci-cd-variables
|
||||
# for more information.
|
||||
#
|
||||
# Currently we have two build stages after our containers are built:
|
||||
# - build (for traditional build and test or first stage build)
|
||||
# - test (for test stages, using build artefacts from a build stage)
|
||||
stages:
|
||||
- containers
|
||||
- containers-layer2
|
||||
- build
|
||||
- test
|
||||
|
||||
include:
|
||||
- local: '/.gitlab-ci.d/qemu-project.yml'
|
||||
- local: '/.gitlab-ci.d/edk2.yml'
|
||||
- local: '/.gitlab-ci.d/opensbi.yml'
|
||||
- local: '/.gitlab-ci.d/containers.yml'
|
||||
- local: '/.gitlab-ci.d/crossbuilds.yml'
|
||||
|
||||
.native_build_job_template: &native_build_job_definition
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
before_script:
|
||||
- JOBS=$(expr $(nproc) + 1)
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if test -n "$TARGETS";
|
||||
then
|
||||
../configure --enable-werror --disable-docs $CONFIGURE_ARGS --target-list="$TARGETS" ;
|
||||
else
|
||||
../configure --enable-werror --disable-docs $CONFIGURE_ARGS ;
|
||||
fi || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- if test -n "$LD_JOBS";
|
||||
then
|
||||
meson configure . -Dbackend_max_links="$LD_JOBS" ;
|
||||
fi || exit 1;
|
||||
- make -j"$JOBS"
|
||||
- if test -n "$MAKE_CHECK_ARGS";
|
||||
then
|
||||
make -j"$JOBS" $MAKE_CHECK_ARGS ;
|
||||
fi
|
||||
|
||||
.native_test_job_template: &native_test_job_definition
|
||||
stage: test
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
script:
|
||||
- scripts/git-submodule.sh update
|
||||
$(sed -n '/GIT_SUBMODULES=/ s/.*=// p' build/config-host.mak)
|
||||
- cd build
|
||||
- find . -type f -exec touch {} +
|
||||
# Avoid recompiling by hiding ninja with NINJA=":"
|
||||
- make NINJA=":" $MAKE_CHECK_ARGS
|
||||
|
||||
.acceptance_template: &acceptance_definition
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}-cache"
|
||||
paths:
|
||||
- ${CI_PROJECT_DIR}/avocado-cache
|
||||
policy: pull-push
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
when: always
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build/tests/results/latest/results.xml
|
||||
- build/tests/results/latest/test-results
|
||||
reports:
|
||||
junit: build/tests/results/latest/results.xml
|
||||
before_script:
|
||||
- mkdir -p ~/.config/avocado
|
||||
- echo "[datadir.paths]" > ~/.config/avocado/avocado.conf
|
||||
- echo "cache_dirs = ['${CI_PROJECT_DIR}/avocado-cache']"
|
||||
>> ~/.config/avocado/avocado.conf
|
||||
- echo -e '[job.output.testlogs]\nstatuses = ["FAIL", "INTERRUPT"]'
|
||||
>> ~/.config/avocado/avocado.conf
|
||||
- if [ -d ${CI_PROJECT_DIR}/avocado-cache ]; then
|
||||
du -chs ${CI_PROJECT_DIR}/avocado-cache ;
|
||||
fi
|
||||
- export AVOCADO_ALLOW_UNTRUSTED_CODE=1
|
||||
after_script:
|
||||
- cd build
|
||||
- du -chs ${CI_PROJECT_DIR}/avocado-cache
|
||||
|
||||
build-system-alpine:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-alpine-container
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
moxie-softmmu microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
CONFIGURE_ARGS: --enable-docs --enable-trace-backends=log,simple,syslog
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- .git-submodule-status
|
||||
- build
|
||||
|
||||
check-system-alpine:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-alpine
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-alpine:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-alpine
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-ubuntu:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
moxie-softmmu microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-ubuntu:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-ubuntu
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-ubuntu:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-ubuntu
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-debian:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
CONFIGURE_ARGS: --enable-fdt=system
|
||||
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
|
||||
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-debian:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-debian:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-fedora:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs
|
||||
--enable-fdt=system --enable-slirp=system --enable-capstone=system
|
||||
TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu
|
||||
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-fedora:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-fedora:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-centos:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-fdt=system
|
||||
--enable-modules --enable-trace-backends=dtrace
|
||||
TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu
|
||||
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-centos:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-centos
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-centos:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-centos
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-opensuse:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-opensuse-leap-container
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
CONFIGURE_ARGS: --enable-fdt=system
|
||||
TARGETS: s390x-softmmu x86_64-softmmu aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-opensuse:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-opensuse
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-opensuse:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-opensuse
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
|
||||
build-disabled:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS:
|
||||
--disable-attr
|
||||
--disable-auth-pam
|
||||
--disable-avx2
|
||||
--disable-bochs
|
||||
--disable-brlapi
|
||||
--disable-bzip2
|
||||
--disable-cap-ng
|
||||
--disable-capstone
|
||||
--disable-cloop
|
||||
--disable-coroutine-pool
|
||||
--disable-curl
|
||||
--disable-curses
|
||||
--disable-dmg
|
||||
--disable-docs
|
||||
--disable-gcrypt
|
||||
--disable-glusterfs
|
||||
--disable-gnutls
|
||||
--disable-gtk
|
||||
--disable-guest-agent
|
||||
--disable-iconv
|
||||
--disable-keyring
|
||||
--disable-kvm
|
||||
--disable-libiscsi
|
||||
--disable-libpmem
|
||||
--disable-libssh
|
||||
--disable-libudev
|
||||
--disable-libusb
|
||||
--disable-libxml2
|
||||
--disable-linux-aio
|
||||
--disable-live-block-migration
|
||||
--disable-lzo
|
||||
--disable-malloc-trim
|
||||
--disable-mpath
|
||||
--disable-nettle
|
||||
--disable-numa
|
||||
--disable-opengl
|
||||
--disable-parallels
|
||||
--disable-pie
|
||||
--disable-qcow1
|
||||
--disable-qed
|
||||
--disable-qom-cast-debug
|
||||
--disable-rbd
|
||||
--disable-rdma
|
||||
--disable-replication
|
||||
--disable-sdl
|
||||
--disable-seccomp
|
||||
--disable-sheepdog
|
||||
--disable-slirp
|
||||
--disable-smartcard
|
||||
--disable-snappy
|
||||
--disable-sparse
|
||||
--disable-spice
|
||||
--disable-strip
|
||||
--disable-tpm
|
||||
--disable-usb-redir
|
||||
--disable-vdi
|
||||
--disable-vhost-crypto
|
||||
--disable-vhost-net
|
||||
--disable-vhost-scsi
|
||||
--disable-vhost-kernel
|
||||
--disable-vhost-user
|
||||
--disable-vhost-vdpa
|
||||
--disable-vhost-vsock
|
||||
--disable-virglrenderer
|
||||
--disable-vnc
|
||||
--disable-vte
|
||||
--disable-vvfat
|
||||
--disable-xen
|
||||
--disable-zstd
|
||||
TARGETS: arm-softmmu i386-softmmu ppc64-softmmu mips64-softmmu
|
||||
s390x-softmmu i386-linux-user
|
||||
MAKE_CHECK_ARGS: check-qtest SPEED=slow
|
||||
|
||||
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by
|
||||
# the configure script. The container doesn't contain Xen headers so
|
||||
# Xen accelerator is not detected / selected. As result it build the
|
||||
# i386-softmmu and x86_64-softmmu with KVM being the single accelerator
|
||||
# available.
|
||||
# Also use a different coroutine implementation (which is only really of
|
||||
# interest to KVM users, i.e. with TCG disabled)
|
||||
build-tcg-disabled:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-tcg --audio-drv-list="" --with-coroutine=ucontext
|
||||
|| { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make -j"$JOBS"
|
||||
- make check-unit
|
||||
- make check-qapi-schema
|
||||
- cd tests/qemu-iotests/
|
||||
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
|
||||
052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163
|
||||
170 171 183 184 192 194 197 208 215 221 222 226 227 236 253 277
|
||||
- ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122
|
||||
124 132 139 142 144 145 151 152 155 157 165 194 196 197 200 202
|
||||
208 209 215 216 218 222 227 234 246 247 248 250 254 255 257 258
|
||||
260 261 262 263 264 270 272 273 277 279
|
||||
|
||||
build-user:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
build-user-static:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system --static
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
# Only build the softmmu targets we have check-tcg tests for
|
||||
build-some-softmmu:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --enable-debug
|
||||
TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
# Run check-tcg against linux-user (with plugins)
|
||||
# we skip sparc64-linux-user until it has been fixed somewhat
|
||||
# we skip cris-linux-user as it doesn't use the common run loop
|
||||
build-user-plugins:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
timeout: 1h 30m
|
||||
|
||||
build-user-centos7:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos7-container
|
||||
variables:
|
||||
IMAGE: centos7
|
||||
CONFIGURE_ARGS: --disable-system --disable-tools --disable-docs
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
build-some-softmmu-plugins:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-user --enable-plugins --enable-debug-tcg
|
||||
TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
clang-system:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
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
|
||||
MAKE_CHECK_ARGS: check-qtest check-tcg
|
||||
|
||||
clang-user:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system
|
||||
--target-list-exclude=microblazeel-linux-user,aarch64_be-linux-user,i386-linux-user,m68k-linux-user,mipsn32el-linux-user,xtensaeb-linux-user
|
||||
--extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined
|
||||
MAKE_CHECK_ARGS: check-unit check-tcg
|
||||
|
||||
# Set LD_JOBS=1 because this requires LTO and ld consumes a large amount of memory.
|
||||
# On gitlab runners, default value sometimes end up calling 2 lds concurrently and
|
||||
# triggers an Out-Of-Memory error
|
||||
#
|
||||
# Since slirp callbacks are used in QEMU Timers, slirp needs to be compiled together
|
||||
# with QEMU and linked as a static library to avoid false positives in CFI checks.
|
||||
# This can be accomplished by using -enable-slirp=git, which avoids the use of
|
||||
# a system-wide version of the library
|
||||
#
|
||||
# Split in three sets of build/check/acceptance to limit the execution time of each
|
||||
# job
|
||||
build-cfi-aarch64:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-aarch64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-aarch64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-cfi-ppc64-s390x:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: ppc64-softmmu s390x-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-ppc64-s390x:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-ppc64-s390x:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-cfi-x86_64:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: x86_64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-x86_64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-x86_64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
tsan-build:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-tsan --cc=clang-10 --cxx=clang++-10
|
||||
--enable-trace-backends=ust --enable-fdt=system --enable-slirp=system
|
||||
TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user
|
||||
MAKE_CHECK_ARGS: bench V=1
|
||||
|
||||
# These targets are on the way out
|
||||
build-deprecated:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools
|
||||
MAKE_CHECK_ARGS: build-tcg
|
||||
TARGETS: ppc64abi32-linux-user lm32-softmmu unicore32-softmmu
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
# We split the check-tcg step as test failures are expected but we still
|
||||
# want to catch the build breaking.
|
||||
check-deprecated:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-deprecated
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
allow_failure: true
|
||||
|
||||
# gprof/gcov are GCC features
|
||||
gprof-gcov:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-gprof --enable-gcov
|
||||
MAKE_CHECK_ARGS: check
|
||||
TARGETS: aarch64-softmmu ppc64-softmmu s390x-softmmu x86_64-softmmu
|
||||
timeout: 70m
|
||||
after_script:
|
||||
- ${CI_PROJECT_DIR}/scripts/ci/coverage-summary.sh
|
||||
|
||||
build-oss-fuzz:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
script:
|
||||
- mkdir build-oss-fuzz
|
||||
- CC="clang" CXX="clang++" CFLAGS="-fsanitize=address"
|
||||
./scripts/oss-fuzz/build.sh
|
||||
- export ASAN_OPTIONS="fast_unwind_on_malloc=0"
|
||||
- for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f
|
||||
| grep -v slirp); do
|
||||
grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ;
|
||||
echo Testing ${fuzzer} ... ;
|
||||
"${fuzzer}" -runs=1 -seed=1 || exit 1 ;
|
||||
done
|
||||
# Unrelated to fuzzer: run some tests with -fsanitize=address
|
||||
- cd build-oss-fuzz && make check-qtest-i386 check-unit
|
||||
|
||||
build-tci:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
script:
|
||||
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-tcg-interpreter
|
||||
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)" || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make -j"$JOBS"
|
||||
- make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
|
||||
- for tg in $TARGETS ; do
|
||||
export QTEST_QEMU_BINARY="./qemu-system-${tg}" ;
|
||||
./tests/qtest/boot-serial-test || exit 1 ;
|
||||
./tests/qtest/cdrom-test || exit 1 ;
|
||||
done
|
||||
- QTEST_QEMU_BINARY="./qemu-system-x86_64" ./tests/qtest/pxe-test
|
||||
- QTEST_QEMU_BINARY="./qemu-system-s390x" ./tests/qtest/pxe-test -m slow
|
||||
- make check-tcg
|
||||
|
||||
# Alternate coroutines implementations are only really of interest to KVM users
|
||||
# However we can't test against KVM on Gitlab-CI so we can only run unit tests
|
||||
build-coroutine-sigaltstack:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --with-coroutine=sigaltstack --disable-tcg
|
||||
--enable-trace-backends=ftrace
|
||||
MAKE_CHECK_ARGS: check-unit
|
||||
|
||||
# Most jobs test latest gcrypt or nettle builds
|
||||
#
|
||||
# These jobs test old gcrypt and nettle from RHEL7
|
||||
# which had some API differences.
|
||||
crypto-old-nettle:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos7-container
|
||||
variables:
|
||||
IMAGE: centos7
|
||||
TARGETS: x86_64-softmmu x86_64-linux-user
|
||||
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
crypto-old-gcrypt:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos7-container
|
||||
variables:
|
||||
IMAGE: centos7
|
||||
TARGETS: x86_64-softmmu x86_64-linux-user
|
||||
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
crypto-only-gnutls:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos7-container
|
||||
variables:
|
||||
IMAGE: centos7
|
||||
TARGETS: x86_64-softmmu x86_64-linux-user
|
||||
CONFIGURE_ARGS: --disable-nettle --disable-gcrypt --enable-gnutls
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
|
||||
# Check our reduced build configurations
|
||||
build-without-default-devices:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
CONFIGURE_ARGS: --without-default-devices --disable-user
|
||||
|
||||
build-without-default-features:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
CONFIGURE_ARGS: --without-default-features --disable-user
|
||||
--target-list-exclude=arm-softmmu,i386-softmmu,mipsel-softmmu,mips64-softmmu,ppc-softmmu
|
||||
MAKE_CHECK_ARGS: check-unit
|
||||
|
||||
check-patch:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/centos8:latest
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
script: .gitlab-ci.d/check-patch.py
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_NAMESPACE == 'qemu-project' && $CI_COMMIT_BRANCH == 'master'
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
allow_failure: true
|
||||
|
||||
check-dco:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/centos8:latest
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
script: .gitlab-ci.d/check-dco.py
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_NAMESPACE == 'qemu-project' && $CI_COMMIT_BRANCH == 'master'
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
|
||||
build-libvhost-user:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/fedora:latest
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
before_script:
|
||||
- dnf install -y meson ninja-build
|
||||
script:
|
||||
- mkdir subprojects/libvhost-user/build
|
||||
- cd subprojects/libvhost-user/build
|
||||
- meson
|
||||
- ninja
|
||||
|
||||
# No targets are built here, just tools, docs, and unit tests. This
|
||||
# also feeds into the eventual documentation deployment steps later
|
||||
build-tools-and-docs-debian:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-unit check-softfloat ctags TAGS cscope
|
||||
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
# Prepare for GitLab pages deployment. Anything copied into the
|
||||
# "public" directory will be deployed to $USER.gitlab.io/$PROJECT
|
||||
pages:
|
||||
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest
|
||||
stage: test
|
||||
needs:
|
||||
- job: build-tools-and-docs-debian
|
||||
script:
|
||||
- mkdir -p public
|
||||
# HTML-ised source tree
|
||||
- make gtags
|
||||
- htags -anT --tree-view=filetree -m qemu_init
|
||||
-t "Welcome to the QEMU sourcecode"
|
||||
- mv HTML public/src
|
||||
# Project documentation
|
||||
- make -C build install DESTDIR=$(pwd)/temp-install
|
||||
- mv temp-install/usr/local/share/doc/qemu/* public/
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
<!--
|
||||
This is the upstream QEMU issue tracker.
|
||||
|
||||
If you are able to, it will greatly facilitate bug triage if you attempt
|
||||
to reproduce the problem with the latest qemu.git master built from
|
||||
source. See https://www.qemu.org/download/#source for instructions on
|
||||
how to do this.
|
||||
|
||||
QEMU generally supports the last two releases advertised on
|
||||
https://www.qemu.org/. Problems with distro-packaged versions of QEMU
|
||||
older than this should be reported to the distribution instead.
|
||||
|
||||
See https://www.qemu.org/contribute/report-a-bug/ for additional
|
||||
guidance.
|
||||
|
||||
If this is a security issue, please consult
|
||||
https://www.qemu.org/contribute/security-process/
|
||||
-->
|
||||
|
||||
## Host environment
|
||||
- Operating system: (Windows 10 21H1, Fedora 34, etc.)
|
||||
- OS/kernel version: (For POSIX hosts, use `uname -a`)
|
||||
- Architecture: (x86, ARM, s390x, etc.)
|
||||
- QEMU flavor: (qemu-system-x86_64, qemu-aarch64, qemu-img, etc.)
|
||||
- QEMU version: (e.g. `qemu-system-x86_64 --version`)
|
||||
- QEMU command line:
|
||||
<!--
|
||||
Give the smallest, complete command line that exhibits the problem.
|
||||
|
||||
If you are using libvirt, virsh, or vmm, you can likely find the QEMU
|
||||
command line arguments in /var/log/libvirt/qemu/$GUEST.log.
|
||||
-->
|
||||
```
|
||||
./qemu-system-x86_64 -M q35 -m 4096 -enable-kvm -hda fedora32.qcow2
|
||||
```
|
||||
|
||||
## Emulated/Virtualized environment
|
||||
- Operating system: (Windows 10 21H1, Fedora 34, etc.)
|
||||
- OS/kernel version: (For POSIX guests, use `uname -a`.)
|
||||
- Architecture: (x86, ARM, s390x, etc.)
|
||||
|
||||
|
||||
## Description of problem
|
||||
<!-- Describe the problem, including any error/crash messages seen. -->
|
||||
|
||||
|
||||
## Steps to reproduce
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
|
||||
## Additional information
|
||||
|
||||
<!--
|
||||
Attach logs, stack traces, screenshots, etc. Compress the files if necessary.
|
||||
If using libvirt, libvirt logs and XML domain information may be relevant.
|
||||
-->
|
||||
|
||||
<!--
|
||||
The line below ensures that proper tags are added to the issue.
|
||||
Please do not remove it.
|
||||
-->
|
||||
/label ~"kind::Bug"
|
|
@ -1,32 +0,0 @@
|
|||
<!--
|
||||
This is the upstream QEMU issue tracker.
|
||||
|
||||
Please note that QEMU, like most open source projects, relies on
|
||||
contributors who have motivation, skills and available time to work on
|
||||
implementing particular features.
|
||||
|
||||
Feature requests can be helpful for determining demand and interest, but
|
||||
they are not a guarantee that a contributor will volunteer to implement
|
||||
it. We welcome and encourage even draft patches to implement a feature
|
||||
be sent to the mailing list where it can be discussed and developed
|
||||
further by the community.
|
||||
|
||||
Thank you for your interest in helping us to make QEMU better!
|
||||
-->
|
||||
|
||||
## Goal
|
||||
<!-- Describe the final result you want to achieve. Avoid design specifics. -->
|
||||
|
||||
|
||||
## Technical details
|
||||
<!-- Describe technical details, design specifics, suggestions, versions, etc. -->
|
||||
|
||||
|
||||
## Additional information
|
||||
<!-- Patch or branch references, any other useful information -->
|
||||
|
||||
<!--
|
||||
The line below ensures that proper tags are added to the issue.
|
||||
Please do not remove it.
|
||||
-->
|
||||
/label ~"kind::Feature Request"
|
|
@ -64,6 +64,3 @@
|
|||
[submodule "roms/vbootrom"]
|
||||
path = roms/vbootrom
|
||||
url = https://gitlab.com/qemu-project/vbootrom.git
|
||||
[submodule "tests/lcitool/libvirt-ci"]
|
||||
path = tests/lcitool/libvirt-ci
|
||||
url = http://gitlab.com/libvirt/libvirt-ci
|
||||
|
|
11
.mailmap
11
.mailmap
|
@ -27,10 +27,6 @@ Paul Brook <paul@codesourcery.com> pbrook <pbrook@c046a42c-6fe2-441c-8c8c-714662
|
|||
Thiemo Seufer <ths@networkno.de> ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
|
||||
malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
|
||||
|
||||
# Corrupted Author fields
|
||||
Marek Dolata <mkdolata@us.ibm.com> mkdolata@us.ibm.com <mkdolata@us.ibm.com>
|
||||
Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com>
|
||||
|
||||
# There is also a:
|
||||
# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
|
||||
# for the cvs2svn initialization commit e63c3dc74bf.
|
||||
|
@ -50,7 +46,6 @@ Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <arikalo@wavecomp.com>
|
|||
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <aleksandar.rikalo@rt-rk.com>
|
||||
Alexander Graf <agraf@csgraf.de> <agraf@suse.de>
|
||||
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
|
||||
Christian Borntraeger <borntraeger@linux.ibm.com> <borntraeger@de.ibm.com>
|
||||
Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
|
||||
Frederic Konrad <konrad@adacore.com> <fred.konrad@greensocs.com>
|
||||
Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
|
||||
|
@ -63,7 +58,6 @@ Paul Burton <paulburton@kernel.org> <paul.burton@mips.com>
|
|||
Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com>
|
||||
Paul Burton <paulburton@kernel.org> <paul@archlinuxmips.org>
|
||||
Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com>
|
||||
Philippe Mathieu-Daudé <f4bug@amsat.org> <philmd@redhat.com>
|
||||
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
|
||||
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
||||
|
||||
|
@ -71,7 +65,6 @@ Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
|||
# git author config, or had utf8/latin1 encoding issues.
|
||||
Aaron Lindsay <aaron@os.amperecomputing.com>
|
||||
Alexey Gerasimenko <x1917x@gmail.com>
|
||||
Alex Chen <alex.chen@huawei.com>
|
||||
Alex Ivanov <void@aleksoft.net>
|
||||
Andreas Färber <afaerber@suse.de>
|
||||
Bandan Das <bsd@redhat.com>
|
||||
|
@ -102,11 +95,8 @@ Gautham R. Shenoy <ego@in.ibm.com>
|
|||
Gautham R. Shenoy <ego@linux.vnet.ibm.com>
|
||||
Gonglei (Arei) <arei.gonglei@huawei.com>
|
||||
Guang Wang <wang.guang55@zte.com.cn>
|
||||
Haibin Zhang <haibinzhang@tencent.com>
|
||||
Hailiang Zhang <zhang.zhanghailiang@huawei.com>
|
||||
Hanna Reitz <hreitz@redhat.com> <mreitz@redhat.com>
|
||||
Hervé Poussineau <hpoussin@reactos.org>
|
||||
Hyman Huang <huangy81@chinatelecom.cn>
|
||||
Jakub Jermář <jakub@jermar.eu>
|
||||
Jakub Jermář <jakub.jermar@kernkonzept.com>
|
||||
Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
|
@ -140,7 +130,6 @@ Nicholas Thomas <nick@bytemark.co.uk>
|
|||
Nikunj A Dadhania <nikunj@linux.vnet.ibm.com>
|
||||
Orit Wasserman <owasserm@redhat.com>
|
||||
Paolo Bonzini <pbonzini@redhat.com>
|
||||
Pan Nengyuan <pannengyuan@huawei.com>
|
||||
Pavel Dovgaluk <dovgaluk@ispras.ru>
|
||||
Pavel Dovgaluk <pavel.dovgaluk@gmail.com>
|
||||
Pavel Dovgaluk <Pavel.Dovgaluk@ispras.ru>
|
||||
|
|
|
@ -88,7 +88,7 @@ email:
|
|||
more information:
|
||||
|
||||
{{ logtext }}
|
||||
{% elif test == "docker-mingw@fedora" or test == "docker-quick@centos8" or test == "asan" %}
|
||||
{% elif test == "docker-mingw@fedora" or test == "docker-quick@centos7" or test == "asan" %}
|
||||
Hi,
|
||||
|
||||
This series failed the {{ test }} build test. Please find the testing commands and
|
||||
|
@ -124,13 +124,13 @@ testing:
|
|||
script: |
|
||||
#!/bin/bash
|
||||
time make docker-test-debug@fedora TARGET_LIST=x86_64-softmmu J=14 NETWORK=1
|
||||
docker-quick@centos8:
|
||||
docker-quick@centos7:
|
||||
enabled: false
|
||||
requirements: docker,x86_64
|
||||
timeout: 3600
|
||||
script: |
|
||||
#!/bin/bash
|
||||
time make docker-test-quick@centos8 SHOW_ENV=1 J=14 NETWORK=1
|
||||
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
|
||||
checkpatch:
|
||||
enabled: true
|
||||
requirements: ''
|
||||
|
@ -138,6 +138,9 @@ testing:
|
|||
script: |
|
||||
#!/bin/bash
|
||||
git rev-parse base > /dev/null || exit 0
|
||||
git config --local diff.renamelimit 0
|
||||
git config --local diff.renames True
|
||||
git config --local diff.algorithm histogram
|
||||
./scripts/checkpatch.pl --mailback base..
|
||||
docker-mingw@fedora:
|
||||
enabled: true
|
||||
|
|
35
.travis.yml
35
.travis.yml
|
@ -27,7 +27,6 @@ addons:
|
|||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libcacard-dev
|
||||
- libgcc-7-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
|
@ -35,6 +34,7 @@ addons:
|
|||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
|
@ -129,7 +129,6 @@ jobs:
|
|||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcacard-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
|
@ -138,6 +137,7 @@ jobs:
|
|||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
|
@ -163,7 +163,6 @@ jobs:
|
|||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcacard-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
|
@ -172,6 +171,7 @@ jobs:
|
|||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
|
@ -196,7 +196,6 @@ jobs:
|
|||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcacard-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
|
@ -205,6 +204,7 @@ jobs:
|
|||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
|
@ -238,7 +238,6 @@ jobs:
|
|||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libcacard-dev
|
||||
- libcap-ng-dev
|
||||
- libgnutls28-dev
|
||||
- libiscsi-dev
|
||||
|
@ -246,6 +245,7 @@ jobs:
|
|||
- liblzo2-dev
|
||||
- libncurses-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libsdl2-dev
|
||||
- libsdl2-image-dev
|
||||
|
@ -281,7 +281,6 @@ jobs:
|
|||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcacard-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
|
@ -290,6 +289,7 @@ jobs:
|
|||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
|
@ -305,3 +305,26 @@ jobs:
|
|||
- CONFIG="--disable-containers --disable-tcg --enable-kvm
|
||||
--disable-tools --host-cc=clang --cxx=clang++"
|
||||
- UNRELIABLE=true
|
||||
|
||||
# Release builds
|
||||
# The make-release script expect a QEMU version, so our tag must start with a 'v'.
|
||||
# This is the case when release candidate tags are created.
|
||||
- name: "Release tarball"
|
||||
if: tag IS present AND tag =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||
env:
|
||||
# We want to build from the release tarball
|
||||
- BUILD_DIR="release/build/dir" SRC_DIR="../../.."
|
||||
- BASE_CONFIG="--prefix=$PWD/dist"
|
||||
- CONFIG="--target-list=x86_64-softmmu,aarch64-softmmu,armeb-linux-user,ppc-linux-user"
|
||||
- TEST_CMD="make install -j${JOBS}"
|
||||
- QEMU_VERSION="${TRAVIS_TAG:1}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
script:
|
||||
- make -C ${SRC_DIR} qemu-${QEMU_VERSION}.tar.bz2
|
||||
- ls -l ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2
|
||||
- tar -xf ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2 && cd qemu-${QEMU_VERSION}
|
||||
- mkdir -p release-build && cd release-build
|
||||
- ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make install
|
||||
allow_failures:
|
||||
- env: UNRELIABLE=true
|
||||
|
|
1
Kconfig
1
Kconfig
|
@ -1,6 +1,5 @@
|
|||
source Kconfig.host
|
||||
source backends/Kconfig
|
||||
source accel/Kconfig
|
||||
source target/Kconfig
|
||||
source hw/Kconfig
|
||||
source semihosting/Kconfig
|
||||
|
|
|
@ -41,7 +41,3 @@ config PVRDMA
|
|||
config MULTIPROCESS_ALLOWED
|
||||
bool
|
||||
imply MULTIPROCESS
|
||||
|
||||
config FUZZ
|
||||
bool
|
||||
select SPARSE_MEM
|
||||
|
|
725
MAINTAINERS
725
MAINTAINERS
File diff suppressed because it is too large
Load Diff
41
Makefile
41
Makefile
|
@ -14,7 +14,7 @@ SRC_PATH=.
|
|||
# we have explicit rules for everything
|
||||
MAKEFLAGS += -rR
|
||||
|
||||
SHELL = bash -o pipefail
|
||||
SHELL = /usr/bin/env bash -o pipefail
|
||||
|
||||
# Usage: $(call quiet-command,command and args,"NAME","args to print")
|
||||
# This will run "command and args", and either:
|
||||
|
@ -48,11 +48,9 @@ Makefile: .git-submodule-status
|
|||
|
||||
.PHONY: git-submodule-update
|
||||
git-submodule-update:
|
||||
ifneq ($(GIT_SUBMODULES_ACTION),ignore)
|
||||
$(call quiet-command, \
|
||||
(GIT="$(GIT)" "$(SRC_PATH)/scripts/git-submodule.sh" $(GIT_SUBMODULES_ACTION) $(GIT_SUBMODULES)), \
|
||||
"GIT","$(GIT_SUBMODULES)")
|
||||
endif
|
||||
|
||||
# 0. ensure the build tree is okay
|
||||
|
||||
|
@ -87,7 +85,7 @@ x := $(shell rm -rf meson-private meson-info meson-logs)
|
|||
endif
|
||||
|
||||
# 1. ensure config-host.mak is up-to-date
|
||||
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
|
||||
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
|
||||
@echo config-host.mak is out-of-date, running configure
|
||||
@if test -f meson-private/coredata.dat; then \
|
||||
./config.status --skip-meson; \
|
||||
|
@ -124,29 +122,20 @@ ifneq ($(MESON),)
|
|||
Makefile.mtest: build.ninja scripts/mtest2make.py
|
||||
$(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
|
||||
-include Makefile.mtest
|
||||
|
||||
.PHONY: update-buildoptions
|
||||
all update-buildoptions: $(SRC_PATH)/scripts/meson-buildoptions.sh
|
||||
$(SRC_PATH)/scripts/meson-buildoptions.sh: $(SRC_PATH)/meson_options.txt
|
||||
$(MESON) introspect --buildoptions $(SRC_PATH)/meson.build | $(PYTHON) \
|
||||
scripts/meson-buildoptions.py > $@.tmp && mv $@.tmp $@
|
||||
endif
|
||||
|
||||
# 4. Rules to bridge to other makefiles
|
||||
|
||||
ifneq ($(NINJA),)
|
||||
# Filter out long options to avoid flags like --no-print-directory which
|
||||
# may result in false positive match for MAKE.n
|
||||
MAKE.n = $(findstring n,$(firstword $(filter-out --%,$(MAKEFLAGS))))
|
||||
MAKE.k = $(findstring k,$(firstword $(filter-out --%,$(MAKEFLAGS))))
|
||||
MAKE.q = $(findstring q,$(firstword $(filter-out --%,$(MAKEFLAGS))))
|
||||
MAKE.n = $(findstring n,$(firstword $(MAKEFLAGS)))
|
||||
MAKE.k = $(findstring k,$(firstword $(MAKEFLAGS)))
|
||||
MAKE.q = $(findstring q,$(firstword $(MAKEFLAGS)))
|
||||
MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq)
|
||||
NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \
|
||||
$(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \
|
||||
|
||||
ninja-cmd-goals = $(or $(MAKECMDGOALS), all)
|
||||
ninja-cmd-goals += $(foreach t, $(.check.build-suites), $(.check-$t.deps))
|
||||
ninja-cmd-goals += $(foreach t, $(.bench.build-suites), $(.bench-$t.deps))
|
||||
ninja-cmd-goals += $(foreach t, $(.tests), $(.test.deps.$t))
|
||||
|
||||
makefile-targets := build.ninja ctags TAGS cscope dist clean uninstall
|
||||
# "ninja -t targets" also lists all prerequisites. If build system
|
||||
|
@ -206,11 +195,14 @@ recurse-clean: $(addsuffix /clean, $(ROM_DIRS))
|
|||
clean: recurse-clean
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean || :
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) clean-ctlist || :
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
find . \( -name '*.so' -o -name '*.dll' -o -name '*.[oda]' \) -type f \
|
||||
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-aarch64.a \
|
||||
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-arm.a \
|
||||
-exec rm {} +
|
||||
rm -f TAGS cscope.* *~ */*~
|
||||
rm -f TAGS cscope.* *.pod *~ */*~
|
||||
rm -f fsdev/*.pod scsi/*.pod
|
||||
|
||||
VERSION = $(shell cat $(SRC_PATH)/VERSION)
|
||||
|
||||
|
@ -221,10 +213,10 @@ qemu-%.tar.bz2:
|
|||
|
||||
distclean: clean
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || :
|
||||
rm -f config-host.mak
|
||||
rm -f config-host.mak config-host.h*
|
||||
rm -f tests/tcg/config-*.mak
|
||||
rm -f config.status
|
||||
rm -f roms/seabios/config.mak
|
||||
rm -f config-all-disas.mak config.status
|
||||
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
||||
rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
|
||||
rm -f *-config-target.h *-config-devices.mak *-config-devices.h
|
||||
rm -rf meson-private meson-logs meson-info compile_commands.json
|
||||
|
@ -233,8 +225,7 @@ distclean: clean
|
|||
rm -f linux-headers/asm
|
||||
rm -Rf .sdk
|
||||
|
||||
find-src-path = find "$(SRC_PATH)" -path "$(SRC_PATH)/meson" -prune -o \
|
||||
-type l -prune -o \( -name "*.[chsS]" -o -name "*.[ch].inc" \)
|
||||
find-src-path = find "$(SRC_PATH)/" -path "$(SRC_PATH)/meson" -prune -o \( -name "*.[chsS]" -o -name "*.[ch].inc" \)
|
||||
|
||||
.PHONY: ctags
|
||||
ctags:
|
||||
|
@ -255,7 +246,7 @@ gtags:
|
|||
"GTAGS", "Remove old $@ files")
|
||||
$(call quiet-command, \
|
||||
(cd $(SRC_PATH) && \
|
||||
$(find-src-path) -print | gtags -f -), \
|
||||
$(find-src-path) | gtags -f -), \
|
||||
"GTAGS", "Re-index $(SRC_PATH)")
|
||||
|
||||
.PHONY: TAGS
|
||||
|
@ -285,7 +276,6 @@ cscope:
|
|||
# Needed by "meson install"
|
||||
export DESTDIR
|
||||
|
||||
include $(SRC_PATH)/tests/lcitool/Makefile.include
|
||||
include $(SRC_PATH)/tests/docker/Makefile.include
|
||||
include $(SRC_PATH)/tests/vm/Makefile.include
|
||||
|
||||
|
@ -315,7 +305,6 @@ endif
|
|||
@echo 'Test targets:'
|
||||
$(call print-help,check,Run all tests (check-help for details))
|
||||
$(call print-help,bench,Run all benchmarks)
|
||||
$(call print-help,lcitool-help,Help about targets for managing build environment manifests)
|
||||
$(call print-help,docker-help,Help about targets running tests inside containers)
|
||||
$(call print-help,vm-help,Help about targets running tests inside VM)
|
||||
@echo ''
|
||||
|
|
20
README.rst
20
README.rst
|
@ -59,9 +59,9 @@ of other UNIX targets. The simple steps to build QEMU are:
|
|||
|
||||
Additional information can also be found online via the QEMU website:
|
||||
|
||||
* `<https://wiki.qemu.org/Hosts/Linux>`_
|
||||
* `<https://wiki.qemu.org/Hosts/Mac>`_
|
||||
* `<https://wiki.qemu.org/Hosts/W32>`_
|
||||
* `<https://qemu.org/Hosts/Linux>`_
|
||||
* `<https://qemu.org/Hosts/Mac>`_
|
||||
* `<https://qemu.org/Hosts/W32>`_
|
||||
|
||||
|
||||
Submitting patches
|
||||
|
@ -84,8 +84,8 @@ the Developers Guide.
|
|||
Additional information on submitting patches can be found online via
|
||||
the QEMU website
|
||||
|
||||
* `<https://wiki.qemu.org/Contribute/SubmitAPatch>`_
|
||||
* `<https://wiki.qemu.org/Contribute/TrivialPatches>`_
|
||||
* `<https://qemu.org/Contribute/SubmitAPatch>`_
|
||||
* `<https://qemu.org/Contribute/TrivialPatches>`_
|
||||
|
||||
The QEMU website is also maintained under source control.
|
||||
|
||||
|
@ -131,20 +131,20 @@ will be tagged as my-feature-v2.
|
|||
Bug reporting
|
||||
=============
|
||||
|
||||
The QEMU project uses GitLab issues to track bugs. Bugs
|
||||
The QEMU project uses Launchpad as its primary upstream bug tracker. Bugs
|
||||
found when running code built from QEMU git or upstream released sources
|
||||
should be reported via:
|
||||
|
||||
* `<https://gitlab.com/qemu-project/qemu/-/issues>`_
|
||||
* `<https://bugs.launchpad.net/qemu/>`_
|
||||
|
||||
If using QEMU via an operating system vendor pre-built binary package, it
|
||||
is preferable to report bugs to the vendor's own bug tracker first. If
|
||||
the bug is also known to affect latest upstream code, it can also be
|
||||
reported via GitLab.
|
||||
reported via launchpad.
|
||||
|
||||
For additional information on bug reporting consult:
|
||||
|
||||
* `<https://wiki.qemu.org/Contribute/ReportABug>`_
|
||||
* `<https://qemu.org/Contribute/ReportABug>`_
|
||||
|
||||
|
||||
ChangeLog
|
||||
|
@ -168,4 +168,4 @@ main methods being email and IRC
|
|||
Information on additional methods of contacting the community can be
|
||||
found online via the QEMU website:
|
||||
|
||||
* `<https://wiki.qemu.org/Contribute/StartHere>`_
|
||||
* `<https://qemu.org/Contribute/StartHere>`_
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
config WHPX
|
||||
bool
|
||||
|
||||
config NVMM
|
||||
bool
|
||||
|
||||
config HAX
|
||||
bool
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ static const TypeInfo accel_type = {
|
|||
AccelClass *accel_find(const char *opt_name)
|
||||
{
|
||||
char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
|
||||
AccelClass *ac = ACCEL_CLASS(module_object_class_by_name(class_name));
|
||||
AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name));
|
||||
g_free(class_name);
|
||||
return ac;
|
||||
}
|
||||
|
@ -54,23 +54,10 @@ static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque)
|
|||
CPUClass *cc = CPU_CLASS(klass);
|
||||
AccelCPUClass *accel_cpu = opaque;
|
||||
|
||||
/*
|
||||
* The first callback allows accel-cpu to run initializations
|
||||
* for the CPU, customizing CPU behavior according to the accelerator.
|
||||
*
|
||||
* The second one allows the CPU to customize the accel-cpu
|
||||
* behavior according to the CPU.
|
||||
*
|
||||
* The second is currently only used by TCG, to specialize the
|
||||
* TCGCPUOps depending on the CPU type.
|
||||
*/
|
||||
cc->accel_cpu = accel_cpu;
|
||||
if (accel_cpu->cpu_class_init) {
|
||||
accel_cpu->cpu_class_init(cc);
|
||||
}
|
||||
if (cc->init_accel_cpu) {
|
||||
cc->init_accel_cpu(accel_cpu, cc);
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize the arch-specific accel CpuClass interfaces */
|
||||
|
@ -102,25 +89,6 @@ void accel_init_interfaces(AccelClass *ac)
|
|||
accel_init_cpu_interfaces(ac);
|
||||
}
|
||||
|
||||
void accel_cpu_instance_init(CPUState *cpu)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (cc->accel_cpu && cc->accel_cpu->cpu_instance_init) {
|
||||
cc->accel_cpu->cpu_instance_init(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
bool accel_cpu_realizefn(CPUState *cpu, Error **errp)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (cc->accel_cpu && cc->accel_cpu->cpu_realizefn) {
|
||||
return cc->accel_cpu->cpu_realizefn(cpu, errp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const TypeInfo accel_cpu_type = {
|
||||
.name = TYPE_ACCEL_CPU,
|
||||
.parent = TYPE_OBJECT,
|
||||
|
|
|
@ -72,7 +72,7 @@ void accel_init_ops_interfaces(AccelClass *ac)
|
|||
g_assert(ac_name != NULL);
|
||||
|
||||
ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
|
||||
ops = ACCEL_OPS_CLASS(module_object_class_by_name(ops_name));
|
||||
ops = ACCEL_OPS_CLASS(object_class_by_name(ops_name));
|
||||
g_free(ops_name);
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,488 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 IBM Corporation
|
||||
* 2008 Red Hat, Inc.
|
||||
* Copyright 2011 Intel Corporation
|
||||
* Copyright 2016 Veertu, Inc.
|
||||
* Copyright 2017 The Android Open Source Project
|
||||
*
|
||||
* QEMU Hypervisor.framework support
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file contain code under public domain from the hvdos project:
|
||||
* https://github.com/mist64/hvdos
|
||||
*
|
||||
* Parts Copyright (c) 2011 NetApp, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/hvf.h"
|
||||
#include "sysemu/hvf_int.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "qemu/guest-random.h"
|
||||
|
||||
HVFState *hvf_state;
|
||||
|
||||
#ifdef __aarch64__
|
||||
#define HV_VM_DEFAULT NULL
|
||||
#endif
|
||||
|
||||
/* Memory slots */
|
||||
|
||||
hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
|
||||
{
|
||||
hvf_slot *slot;
|
||||
int x;
|
||||
for (x = 0; x < hvf_state->num_slots; ++x) {
|
||||
slot = &hvf_state->slots[x];
|
||||
if (slot->size && start < (slot->start + slot->size) &&
|
||||
(start + size) > slot->start) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mac_slot {
|
||||
int present;
|
||||
uint64_t size;
|
||||
uint64_t gpa_start;
|
||||
uint64_t gva;
|
||||
};
|
||||
|
||||
struct mac_slot mac_slots[32];
|
||||
|
||||
static int do_hvf_set_memory(hvf_slot *slot, hv_memory_flags_t flags)
|
||||
{
|
||||
struct mac_slot *macslot;
|
||||
hv_return_t ret;
|
||||
|
||||
macslot = &mac_slots[slot->slot_id];
|
||||
|
||||
if (macslot->present) {
|
||||
if (macslot->size != slot->size) {
|
||||
macslot->present = 0;
|
||||
ret = hv_vm_unmap(macslot->gpa_start, macslot->size);
|
||||
assert_hvf_ok(ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (!slot->size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
macslot->present = 1;
|
||||
macslot->gpa_start = slot->start;
|
||||
macslot->size = slot->size;
|
||||
ret = hv_vm_map(slot->mem, slot->start, slot->size, flags);
|
||||
assert_hvf_ok(ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
||||
{
|
||||
hvf_slot *mem;
|
||||
MemoryRegion *area = section->mr;
|
||||
bool writeable = !area->readonly && !area->rom_device;
|
||||
hv_memory_flags_t flags;
|
||||
uint64_t page_size = qemu_real_host_page_size;
|
||||
|
||||
if (!memory_region_is_ram(area)) {
|
||||
if (writeable) {
|
||||
return;
|
||||
} else if (!memory_region_is_romd(area)) {
|
||||
/*
|
||||
* If the memory device is not in romd_mode, then we actually want
|
||||
* to remove the hvf memory slot so all accesses will trap.
|
||||
*/
|
||||
add = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
|
||||
!QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
|
||||
/* Not page aligned, so we can not map as RAM */
|
||||
add = false;
|
||||
}
|
||||
|
||||
mem = hvf_find_overlap_slot(
|
||||
section->offset_within_address_space,
|
||||
int128_get64(section->size));
|
||||
|
||||
if (mem && add) {
|
||||
if (mem->size == int128_get64(section->size) &&
|
||||
mem->start == section->offset_within_address_space &&
|
||||
mem->mem == (memory_region_get_ram_ptr(area) +
|
||||
section->offset_within_region)) {
|
||||
return; /* Same region was attempted to register, go away. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Region needs to be reset. set the size to 0 and remap it. */
|
||||
if (mem) {
|
||||
mem->size = 0;
|
||||
if (do_hvf_set_memory(mem, 0)) {
|
||||
error_report("Failed to reset overlapping slot");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (!add) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (area->readonly ||
|
||||
(!memory_region_is_ram(area) && memory_region_is_romd(area))) {
|
||||
flags = HV_MEMORY_READ | HV_MEMORY_EXEC;
|
||||
} else {
|
||||
flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC;
|
||||
}
|
||||
|
||||
/* Now make a new slot. */
|
||||
int x;
|
||||
|
||||
for (x = 0; x < hvf_state->num_slots; ++x) {
|
||||
mem = &hvf_state->slots[x];
|
||||
if (!mem->size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x == hvf_state->num_slots) {
|
||||
error_report("No free slots");
|
||||
abort();
|
||||
}
|
||||
|
||||
mem->size = int128_get64(section->size);
|
||||
mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
|
||||
mem->start = section->offset_within_address_space;
|
||||
mem->region = area;
|
||||
|
||||
if (do_hvf_set_memory(mem, flags)) {
|
||||
error_report("Error registering new memory slot");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
||||
{
|
||||
if (!cpu->vcpu_dirty) {
|
||||
hvf_get_registers(cpu);
|
||||
cpu->vcpu_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void hvf_cpu_synchronize_state(CPUState *cpu)
|
||||
{
|
||||
if (!cpu->vcpu_dirty) {
|
||||
run_on_cpu(cpu, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_hvf_cpu_synchronize_set_dirty(CPUState *cpu,
|
||||
run_on_cpu_data arg)
|
||||
{
|
||||
/* QEMU state is the reference, push it to HVF now and on next entry */
|
||||
cpu->vcpu_dirty = true;
|
||||
}
|
||||
|
||||
static void hvf_cpu_synchronize_post_reset(CPUState *cpu)
|
||||
{
|
||||
run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
|
||||
}
|
||||
|
||||
static void hvf_cpu_synchronize_post_init(CPUState *cpu)
|
||||
{
|
||||
run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
|
||||
}
|
||||
|
||||
static void hvf_cpu_synchronize_pre_loadvm(CPUState *cpu)
|
||||
{
|
||||
run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
|
||||
}
|
||||
|
||||
static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
|
||||
{
|
||||
hvf_slot *slot;
|
||||
|
||||
slot = hvf_find_overlap_slot(
|
||||
section->offset_within_address_space,
|
||||
int128_get64(section->size));
|
||||
|
||||
/* protect region against writes; begin tracking it */
|
||||
if (on) {
|
||||
slot->flags |= HVF_SLOT_LOG;
|
||||
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
||||
HV_MEMORY_READ | HV_MEMORY_EXEC);
|
||||
/* stop tracking region*/
|
||||
} else {
|
||||
slot->flags &= ~HVF_SLOT_LOG;
|
||||
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
||||
HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
|
||||
}
|
||||
}
|
||||
|
||||
static void hvf_log_start(MemoryListener *listener,
|
||||
MemoryRegionSection *section, int old, int new)
|
||||
{
|
||||
if (old != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
hvf_set_dirty_tracking(section, 1);
|
||||
}
|
||||
|
||||
static void hvf_log_stop(MemoryListener *listener,
|
||||
MemoryRegionSection *section, int old, int new)
|
||||
{
|
||||
if (new != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
hvf_set_dirty_tracking(section, 0);
|
||||
}
|
||||
|
||||
static void hvf_log_sync(MemoryListener *listener,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
/*
|
||||
* sync of dirty pages is handled elsewhere; just make sure we keep
|
||||
* tracking the region.
|
||||
*/
|
||||
hvf_set_dirty_tracking(section, 1);
|
||||
}
|
||||
|
||||
static void hvf_region_add(MemoryListener *listener,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
hvf_set_phys_mem(section, true);
|
||||
}
|
||||
|
||||
static void hvf_region_del(MemoryListener *listener,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
hvf_set_phys_mem(section, false);
|
||||
}
|
||||
|
||||
static MemoryListener hvf_memory_listener = {
|
||||
.name = "hvf",
|
||||
.priority = 10,
|
||||
.region_add = hvf_region_add,
|
||||
.region_del = hvf_region_del,
|
||||
.log_start = hvf_log_start,
|
||||
.log_stop = hvf_log_stop,
|
||||
.log_sync = hvf_log_sync,
|
||||
};
|
||||
|
||||
static void dummy_signal(int sig)
|
||||
{
|
||||
}
|
||||
|
||||
bool hvf_allowed;
|
||||
|
||||
static int hvf_accel_init(MachineState *ms)
|
||||
{
|
||||
int x;
|
||||
hv_return_t ret;
|
||||
HVFState *s;
|
||||
|
||||
ret = hv_vm_create(HV_VM_DEFAULT);
|
||||
assert_hvf_ok(ret);
|
||||
|
||||
s = g_new0(HVFState, 1);
|
||||
|
||||
s->num_slots = ARRAY_SIZE(s->slots);
|
||||
for (x = 0; x < s->num_slots; ++x) {
|
||||
s->slots[x].size = 0;
|
||||
s->slots[x].slot_id = x;
|
||||
}
|
||||
|
||||
hvf_state = s;
|
||||
memory_listener_register(&hvf_memory_listener, &address_space_memory);
|
||||
|
||||
return hvf_arch_init();
|
||||
}
|
||||
|
||||
static void hvf_accel_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
ac->name = "HVF";
|
||||
ac->init_machine = hvf_accel_init;
|
||||
ac->allowed = &hvf_allowed;
|
||||
}
|
||||
|
||||
static const TypeInfo hvf_accel_type = {
|
||||
.name = TYPE_HVF_ACCEL,
|
||||
.parent = TYPE_ACCEL,
|
||||
.class_init = hvf_accel_class_init,
|
||||
};
|
||||
|
||||
static void hvf_type_init(void)
|
||||
{
|
||||
type_register_static(&hvf_accel_type);
|
||||
}
|
||||
|
||||
type_init(hvf_type_init);
|
||||
|
||||
static void hvf_vcpu_destroy(CPUState *cpu)
|
||||
{
|
||||
hv_return_t ret = hv_vcpu_destroy(cpu->hvf->fd);
|
||||
assert_hvf_ok(ret);
|
||||
|
||||
hvf_arch_vcpu_destroy(cpu);
|
||||
g_free(cpu->hvf);
|
||||
cpu->hvf = NULL;
|
||||
}
|
||||
|
||||
static int hvf_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
int r;
|
||||
|
||||
cpu->hvf = g_malloc0(sizeof(*cpu->hvf));
|
||||
|
||||
/* init cpu signals */
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_handler = dummy_signal;
|
||||
sigaction(SIG_IPI, &sigact, NULL);
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, NULL, &cpu->hvf->unblock_ipi_mask);
|
||||
sigdelset(&cpu->hvf->unblock_ipi_mask, SIG_IPI);
|
||||
|
||||
#ifdef __aarch64__
|
||||
r = hv_vcpu_create(&cpu->hvf->fd, (hv_vcpu_exit_t **)&cpu->hvf->exit, NULL);
|
||||
#else
|
||||
r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT);
|
||||
#endif
|
||||
cpu->vcpu_dirty = 1;
|
||||
assert_hvf_ok(r);
|
||||
|
||||
return hvf_arch_init_vcpu(cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* The HVF-specific vCPU thread function. This one should only run when the host
|
||||
* CPU supports the VMX "unrestricted guest" feature.
|
||||
*/
|
||||
static void *hvf_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
|
||||
int r;
|
||||
|
||||
assert(hvf_enabled());
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->can_do_io = 1;
|
||||
current_cpu = cpu;
|
||||
|
||||
hvf_init_vcpu(cpu);
|
||||
|
||||
/* signal CPU creation */
|
||||
cpu_thread_signal_created(cpu);
|
||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||
|
||||
do {
|
||||
if (cpu_can_run(cpu)) {
|
||||
r = hvf_vcpu_exec(cpu);
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(cpu);
|
||||
}
|
||||
}
|
||||
qemu_wait_io_event(cpu);
|
||||
} while (!cpu->unplug || cpu_can_run(cpu));
|
||||
|
||||
hvf_vcpu_destroy(cpu);
|
||||
cpu_thread_signal_destroyed(cpu);
|
||||
qemu_mutex_unlock_iothread();
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hvf_start_vcpu_thread(CPUState *cpu)
|
||||
{
|
||||
char thread_name[VCPU_THREAD_NAME_SIZE];
|
||||
|
||||
/*
|
||||
* HVF currently does not support TCG, and only runs in
|
||||
* unrestricted-guest mode.
|
||||
*/
|
||||
assert(hvf_enabled());
|
||||
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
|
||||
snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/HVF",
|
||||
cpu->cpu_index);
|
||||
qemu_thread_create(cpu->thread, thread_name, hvf_cpu_thread_fn,
|
||||
cpu, QEMU_THREAD_JOINABLE);
|
||||
}
|
||||
|
||||
static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||
|
||||
ops->create_vcpu_thread = hvf_start_vcpu_thread;
|
||||
ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
|
||||
|
||||
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
|
||||
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
|
||||
ops->synchronize_state = hvf_cpu_synchronize_state;
|
||||
ops->synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm;
|
||||
};
|
||||
static const TypeInfo hvf_accel_ops_type = {
|
||||
.name = ACCEL_OPS_NAME("hvf"),
|
||||
|
||||
.parent = TYPE_ACCEL_OPS,
|
||||
.class_init = hvf_accel_ops_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
static void hvf_accel_ops_register_types(void)
|
||||
{
|
||||
type_register_static(&hvf_accel_ops_type);
|
||||
}
|
||||
type_init(hvf_accel_ops_register_types);
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* QEMU Hypervisor.framework support
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/hvf.h"
|
||||
#include "sysemu/hvf_int.h"
|
||||
|
||||
void assert_hvf_ok(hv_return_t ret)
|
||||
{
|
||||
if (ret == HV_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case HV_ERROR:
|
||||
error_report("Error: HV_ERROR");
|
||||
break;
|
||||
case HV_BUSY:
|
||||
error_report("Error: HV_BUSY");
|
||||
break;
|
||||
case HV_BAD_ARGUMENT:
|
||||
error_report("Error: HV_BAD_ARGUMENT");
|
||||
break;
|
||||
case HV_NO_RESOURCES:
|
||||
error_report("Error: HV_NO_RESOURCES");
|
||||
break;
|
||||
case HV_NO_DEVICE:
|
||||
error_report("Error: HV_NO_DEVICE");
|
||||
break;
|
||||
case HV_UNSUPPORTED:
|
||||
error_report("Error: HV_UNSUPPORTED");
|
||||
break;
|
||||
default:
|
||||
error_report("Unknown Error");
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
hvf_ss = ss.source_set()
|
||||
hvf_ss.add(files(
|
||||
'hvf-all.c',
|
||||
'hvf-accel-ops.c',
|
||||
))
|
||||
|
||||
specific_ss.add_all(when: 'CONFIG_HVF', if_true: hvf_ss)
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <linux/kvm.h>
|
||||
|
||||
|
@ -31,9 +30,11 @@
|
|||
#include "sysemu/kvm_int.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/ram_addr.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/event_notifier.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "trace.h"
|
||||
|
@ -61,10 +62,6 @@
|
|||
#endif
|
||||
#define PAGE_SIZE qemu_real_host_page_size
|
||||
|
||||
#ifndef KVM_GUESTDBG_BLOCKIRQ
|
||||
#define KVM_GUESTDBG_BLOCKIRQ 0
|
||||
#endif
|
||||
|
||||
//#define DEBUG_KVM
|
||||
|
||||
#ifdef DEBUG_KVM
|
||||
|
@ -83,25 +80,6 @@ struct KVMParkedVcpu {
|
|||
QLIST_ENTRY(KVMParkedVcpu) node;
|
||||
};
|
||||
|
||||
enum KVMDirtyRingReaperState {
|
||||
KVM_DIRTY_RING_REAPER_NONE = 0,
|
||||
/* The reaper is sleeping */
|
||||
KVM_DIRTY_RING_REAPER_WAIT,
|
||||
/* The reaper is reaping for dirty pages */
|
||||
KVM_DIRTY_RING_REAPER_REAPING,
|
||||
};
|
||||
|
||||
/*
|
||||
* KVM reaper instance, responsible for collecting the KVM dirty bits
|
||||
* via the dirty ring.
|
||||
*/
|
||||
struct KVMDirtyRingReaper {
|
||||
/* The reaper thread */
|
||||
QemuThread reaper_thr;
|
||||
volatile uint64_t reaper_iteration; /* iteration number of reaper thr */
|
||||
volatile enum KVMDirtyRingReaperState reaper_state; /* reap thr state */
|
||||
};
|
||||
|
||||
struct KVMState
|
||||
{
|
||||
AccelState parent_obj;
|
||||
|
@ -150,9 +128,6 @@ struct KVMState
|
|||
KVMMemoryListener *ml;
|
||||
AddressSpace *as;
|
||||
} *as;
|
||||
uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */
|
||||
uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */
|
||||
struct KVMDirtyRingReaper reaper;
|
||||
};
|
||||
|
||||
KVMState *kvm_state;
|
||||
|
@ -172,8 +147,6 @@ bool kvm_vm_attributes_allowed;
|
|||
bool kvm_direct_msi_allowed;
|
||||
bool kvm_ioeventfd_any_length_allowed;
|
||||
bool kvm_msi_use_devid;
|
||||
bool kvm_has_guest_debug;
|
||||
int kvm_sstep_flags;
|
||||
static bool kvm_immediate_exit;
|
||||
static hwaddr kvm_max_slot_size = ~0;
|
||||
|
||||
|
@ -201,12 +174,8 @@ typedef struct KVMResampleFd KVMResampleFd;
|
|||
static QLIST_HEAD(, KVMResampleFd) kvm_resample_fd_list =
|
||||
QLIST_HEAD_INITIALIZER(kvm_resample_fd_list);
|
||||
|
||||
static QemuMutex kml_slots_lock;
|
||||
|
||||
#define kvm_slots_lock() qemu_mutex_lock(&kml_slots_lock)
|
||||
#define kvm_slots_unlock() qemu_mutex_unlock(&kml_slots_lock)
|
||||
|
||||
static void kvm_slot_init_dirty_bitmap(KVMSlot *mem);
|
||||
#define kvm_slots_lock(kml) qemu_mutex_lock(&(kml)->slots_lock)
|
||||
#define kvm_slots_unlock(kml) qemu_mutex_unlock(&(kml)->slots_lock)
|
||||
|
||||
static inline void kvm_resample_fd_remove(int gsi)
|
||||
{
|
||||
|
@ -272,9 +241,9 @@ bool kvm_has_free_slot(MachineState *ms)
|
|||
bool result;
|
||||
KVMMemoryListener *kml = &s->memory_listener;
|
||||
|
||||
kvm_slots_lock();
|
||||
kvm_slots_lock(kml);
|
||||
result = !!kvm_get_free_slot(kml);
|
||||
kvm_slots_unlock();
|
||||
kvm_slots_unlock(kml);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -340,7 +309,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
|
|||
KVMMemoryListener *kml = &s->memory_listener;
|
||||
int i, ret = 0;
|
||||
|
||||
kvm_slots_lock();
|
||||
kvm_slots_lock(kml);
|
||||
for (i = 0; i < s->nr_slots; i++) {
|
||||
KVMSlot *mem = &kml->slots[i];
|
||||
|
||||
|
@ -350,7 +319,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
|
|||
break;
|
||||
}
|
||||
}
|
||||
kvm_slots_unlock();
|
||||
kvm_slots_unlock(kml);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -416,13 +385,6 @@ static int do_kvm_destroy_vcpu(CPUState *cpu)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (cpu->kvm_dirty_gfns) {
|
||||
ret = munmap(cpu->kvm_dirty_gfns, s->kvm_dirty_ring_bytes);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
vcpu = g_malloc0(sizeof(*vcpu));
|
||||
vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
|
||||
vcpu->kvm_fd = cpu->kvm_fd;
|
||||
|
@ -475,7 +437,6 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
|||
cpu->kvm_fd = ret;
|
||||
cpu->kvm_state = s;
|
||||
cpu->vcpu_dirty = true;
|
||||
cpu->dirty_pages = 0;
|
||||
|
||||
mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
|
||||
if (mmap_size < 0) {
|
||||
|
@ -500,19 +461,6 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
|||
(void *)cpu->kvm_run + s->coalesced_mmio * PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (s->kvm_dirty_ring_size) {
|
||||
/* Use MAP_SHARED to share pages with the kernel */
|
||||
cpu->kvm_dirty_gfns = mmap(NULL, s->kvm_dirty_ring_bytes,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
cpu->kvm_fd,
|
||||
PAGE_SIZE * KVM_DIRTY_LOG_PAGE_OFFSET);
|
||||
if (cpu->kvm_dirty_gfns == MAP_FAILED) {
|
||||
ret = -errno;
|
||||
DPRINTF("mmap'ing vcpu dirty gfns failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = kvm_arch_init_vcpu(cpu);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret,
|
||||
|
@ -552,7 +500,6 @@ static int kvm_slot_update_flags(KVMMemoryListener *kml, KVMSlot *mem,
|
|||
return 0;
|
||||
}
|
||||
|
||||
kvm_slot_init_dirty_bitmap(mem);
|
||||
return kvm_set_user_memory_region(kml, mem, false);
|
||||
}
|
||||
|
||||
|
@ -568,7 +515,7 @@ static int kvm_section_update_flags(KVMMemoryListener *kml,
|
|||
return 0;
|
||||
}
|
||||
|
||||
kvm_slots_lock();
|
||||
kvm_slots_lock(kml);
|
||||
|
||||
while (size && !ret) {
|
||||
slot_size = MIN(kvm_max_slot_size, size);
|
||||
|
@ -584,7 +531,7 @@ static int kvm_section_update_flags(KVMMemoryListener *kml,
|
|||
}
|
||||
|
||||
out:
|
||||
kvm_slots_unlock();
|
||||
kvm_slots_unlock(kml);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -623,28 +570,22 @@ static void kvm_log_stop(MemoryListener *listener,
|
|||
}
|
||||
|
||||
/* get kvm's dirty pages bitmap and update qemu's */
|
||||
static void kvm_slot_sync_dirty_pages(KVMSlot *slot)
|
||||
static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
|
||||
unsigned long *bitmap)
|
||||
{
|
||||
ram_addr_t start = slot->ram_start_offset;
|
||||
ram_addr_t pages = slot->memory_size / qemu_real_host_page_size;
|
||||
ram_addr_t start = section->offset_within_region +
|
||||
memory_region_get_ram_addr(section->mr);
|
||||
ram_addr_t pages = int128_get64(section->size) / qemu_real_host_page_size;
|
||||
|
||||
cpu_physical_memory_set_dirty_lebitmap(slot->dirty_bmap, start, pages);
|
||||
}
|
||||
|
||||
static void kvm_slot_reset_dirty_pages(KVMSlot *slot)
|
||||
{
|
||||
memset(slot->dirty_bmap, 0, slot->dirty_bmap_size);
|
||||
cpu_physical_memory_set_dirty_lebitmap(bitmap, start, pages);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1))
|
||||
|
||||
/* Allocate the dirty bitmap for a slot */
|
||||
static void kvm_slot_init_dirty_bitmap(KVMSlot *mem)
|
||||
static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem)
|
||||
{
|
||||
if (!(mem->flags & KVM_MEM_LOG_DIRTY_PAGES) || mem->dirty_bmap) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX bad kernel interface alert
|
||||
* For dirty bitmap, kernel allocates array of size aligned to
|
||||
|
@ -665,197 +606,6 @@ static void kvm_slot_init_dirty_bitmap(KVMSlot *mem)
|
|||
hwaddr bitmap_size = ALIGN(mem->memory_size / qemu_real_host_page_size,
|
||||
/*HOST_LONG_BITS*/ 64) / 8;
|
||||
mem->dirty_bmap = g_malloc0(bitmap_size);
|
||||
mem->dirty_bmap_size = bitmap_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sync dirty bitmap from kernel to KVMSlot.dirty_bmap, return true if
|
||||
* succeeded, false otherwise
|
||||
*/
|
||||
static bool kvm_slot_get_dirty_log(KVMState *s, KVMSlot *slot)
|
||||
{
|
||||
struct kvm_dirty_log d = {};
|
||||
int ret;
|
||||
|
||||
d.dirty_bitmap = slot->dirty_bmap;
|
||||
d.slot = slot->slot | (slot->as_id << 16);
|
||||
ret = kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d);
|
||||
|
||||
if (ret == -ENOENT) {
|
||||
/* kernel does not have dirty bitmap in this slot */
|
||||
ret = 0;
|
||||
}
|
||||
if (ret) {
|
||||
error_report_once("%s: KVM_GET_DIRTY_LOG failed with %d",
|
||||
__func__, ret);
|
||||
}
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
/* Should be with all slots_lock held for the address spaces. */
|
||||
static void kvm_dirty_ring_mark_page(KVMState *s, uint32_t as_id,
|
||||
uint32_t slot_id, uint64_t offset)
|
||||
{
|
||||
KVMMemoryListener *kml;
|
||||
KVMSlot *mem;
|
||||
|
||||
if (as_id >= s->nr_as) {
|
||||
return;
|
||||
}
|
||||
|
||||
kml = s->as[as_id].ml;
|
||||
mem = &kml->slots[slot_id];
|
||||
|
||||
if (!mem->memory_size || offset >=
|
||||
(mem->memory_size / qemu_real_host_page_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(offset, mem->dirty_bmap);
|
||||
}
|
||||
|
||||
static bool dirty_gfn_is_dirtied(struct kvm_dirty_gfn *gfn)
|
||||
{
|
||||
return gfn->flags == KVM_DIRTY_GFN_F_DIRTY;
|
||||
}
|
||||
|
||||
static void dirty_gfn_set_collected(struct kvm_dirty_gfn *gfn)
|
||||
{
|
||||
gfn->flags = KVM_DIRTY_GFN_F_RESET;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be with all slots_lock held for the address spaces. It returns the
|
||||
* dirty page we've collected on this dirty ring.
|
||||
*/
|
||||
static uint32_t kvm_dirty_ring_reap_one(KVMState *s, CPUState *cpu)
|
||||
{
|
||||
struct kvm_dirty_gfn *dirty_gfns = cpu->kvm_dirty_gfns, *cur;
|
||||
uint32_t ring_size = s->kvm_dirty_ring_size;
|
||||
uint32_t count = 0, fetch = cpu->kvm_fetch_index;
|
||||
|
||||
assert(dirty_gfns && ring_size);
|
||||
trace_kvm_dirty_ring_reap_vcpu(cpu->cpu_index);
|
||||
|
||||
while (true) {
|
||||
cur = &dirty_gfns[fetch % ring_size];
|
||||
if (!dirty_gfn_is_dirtied(cur)) {
|
||||
break;
|
||||
}
|
||||
kvm_dirty_ring_mark_page(s, cur->slot >> 16, cur->slot & 0xffff,
|
||||
cur->offset);
|
||||
dirty_gfn_set_collected(cur);
|
||||
trace_kvm_dirty_ring_page(cpu->cpu_index, fetch, cur->offset);
|
||||
fetch++;
|
||||
count++;
|
||||
}
|
||||
cpu->kvm_fetch_index = fetch;
|
||||
cpu->dirty_pages += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Must be with slots_lock held */
|
||||
static uint64_t kvm_dirty_ring_reap_locked(KVMState *s)
|
||||
{
|
||||
int ret;
|
||||
CPUState *cpu;
|
||||
uint64_t total = 0;
|
||||
int64_t stamp;
|
||||
|
||||
stamp = get_clock();
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
total += kvm_dirty_ring_reap_one(s, cpu);
|
||||
}
|
||||
|
||||
if (total) {
|
||||
ret = kvm_vm_ioctl(s, KVM_RESET_DIRTY_RINGS);
|
||||
assert(ret == total);
|
||||
}
|
||||
|
||||
stamp = get_clock() - stamp;
|
||||
|
||||
if (total) {
|
||||
trace_kvm_dirty_ring_reap(total, stamp / 1000);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently for simplicity, we must hold BQL before calling this. We can
|
||||
* consider to drop the BQL if we're clear with all the race conditions.
|
||||
*/
|
||||
static uint64_t kvm_dirty_ring_reap(KVMState *s)
|
||||
{
|
||||
uint64_t total;
|
||||
|
||||
/*
|
||||
* We need to lock all kvm slots for all address spaces here,
|
||||
* because:
|
||||
*
|
||||
* (1) We need to mark dirty for dirty bitmaps in multiple slots
|
||||
* and for tons of pages, so it's better to take the lock here
|
||||
* once rather than once per page. And more importantly,
|
||||
*
|
||||
* (2) We must _NOT_ publish dirty bits to the other threads
|
||||
* (e.g., the migration thread) via the kvm memory slot dirty
|
||||
* bitmaps before correctly re-protect those dirtied pages.
|
||||
* Otherwise we can have potential risk of data corruption if
|
||||
* the page data is read in the other thread before we do
|
||||
* reset below.
|
||||
*/
|
||||
kvm_slots_lock();
|
||||
total = kvm_dirty_ring_reap_locked(s);
|
||||
kvm_slots_unlock();
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static void do_kvm_cpu_synchronize_kick(CPUState *cpu, run_on_cpu_data arg)
|
||||
{
|
||||
/* No need to do anything */
|
||||
}
|
||||
|
||||
/*
|
||||
* Kick all vcpus out in a synchronized way. When returned, we
|
||||
* guarantee that every vcpu has been kicked and at least returned to
|
||||
* userspace once.
|
||||
*/
|
||||
static void kvm_cpu_synchronize_kick_all(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
run_on_cpu(cpu, do_kvm_cpu_synchronize_kick, RUN_ON_CPU_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush all the existing dirty pages to the KVM slot buffers. When
|
||||
* this call returns, we guarantee that all the touched dirty pages
|
||||
* before calling this function have been put into the per-kvmslot
|
||||
* dirty bitmap.
|
||||
*
|
||||
* This function must be called with BQL held.
|
||||
*/
|
||||
static void kvm_dirty_ring_flush(void)
|
||||
{
|
||||
trace_kvm_dirty_ring_flush(0);
|
||||
/*
|
||||
* The function needs to be serialized. Since this function
|
||||
* should always be with BQL held, serialization is guaranteed.
|
||||
* However, let's be sure of it.
|
||||
*/
|
||||
assert(qemu_mutex_iothread_locked());
|
||||
/*
|
||||
* First make sure to flush the hardware buffers by kicking all
|
||||
* vcpus out in a synchronous way.
|
||||
*/
|
||||
kvm_cpu_synchronize_kick_all();
|
||||
kvm_dirty_ring_reap(kvm_state);
|
||||
trace_kvm_dirty_ring_flush(1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -869,28 +619,53 @@ static void kvm_dirty_ring_flush(void)
|
|||
* @kml: the KVM memory listener object
|
||||
* @section: the memory section to sync the dirty bitmap with
|
||||
*/
|
||||
static void kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
|
||||
MemoryRegionSection *section)
|
||||
static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
struct kvm_dirty_log d = {};
|
||||
KVMSlot *mem;
|
||||
hwaddr start_addr, size;
|
||||
hwaddr slot_size;
|
||||
hwaddr slot_size, slot_offset = 0;
|
||||
int ret = 0;
|
||||
|
||||
size = kvm_align_section(section, &start_addr);
|
||||
while (size) {
|
||||
MemoryRegionSection subsection = *section;
|
||||
|
||||
slot_size = MIN(kvm_max_slot_size, size);
|
||||
mem = kvm_lookup_matching_slot(kml, start_addr, slot_size);
|
||||
if (!mem) {
|
||||
/* We don't have a slot if we want to trap every access. */
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
if (kvm_slot_get_dirty_log(s, mem)) {
|
||||
kvm_slot_sync_dirty_pages(mem);
|
||||
|
||||
if (!mem->dirty_bmap) {
|
||||
/* Allocate on the first log_sync, once and for all */
|
||||
kvm_memslot_init_dirty_bitmap(mem);
|
||||
}
|
||||
|
||||
d.dirty_bitmap = mem->dirty_bmap;
|
||||
d.slot = mem->slot | (kml->as_id << 16);
|
||||
ret = kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d);
|
||||
if (ret == -ENOENT) {
|
||||
/* kernel does not have dirty bitmap in this slot */
|
||||
ret = 0;
|
||||
} else if (ret < 0) {
|
||||
error_report("ioctl KVM_GET_DIRTY_LOG failed: %d", errno);
|
||||
goto out;
|
||||
} else {
|
||||
subsection.offset_within_region += slot_offset;
|
||||
subsection.size = int128_make64(slot_size);
|
||||
kvm_get_dirty_pages_log_range(&subsection, d.dirty_bitmap);
|
||||
}
|
||||
|
||||
slot_offset += slot_size;
|
||||
start_addr += slot_size;
|
||||
size -= slot_size;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Alignment requirement for KVM_CLEAR_DIRTY_LOG - 64 pages */
|
||||
|
@ -1037,7 +812,7 @@ static int kvm_physical_log_clear(KVMMemoryListener *kml,
|
|||
return ret;
|
||||
}
|
||||
|
||||
kvm_slots_lock();
|
||||
kvm_slots_lock(kml);
|
||||
|
||||
for (i = 0; i < s->nr_slots; i++) {
|
||||
mem = &kml->slots[i];
|
||||
|
@ -1063,7 +838,7 @@ static int kvm_physical_log_clear(KVMMemoryListener *kml,
|
|||
}
|
||||
}
|
||||
|
||||
kvm_slots_unlock();
|
||||
kvm_slots_unlock(kml);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1137,7 +912,6 @@ static void kvm_coalesce_pio_del(MemoryListener *listener,
|
|||
}
|
||||
|
||||
static MemoryListener kvm_coalesced_pio_listener = {
|
||||
.name = "kvm-coalesced-pio",
|
||||
.coalesced_io_add = kvm_coalesce_pio_add,
|
||||
.coalesced_io_del = kvm_coalesce_pio_del,
|
||||
};
|
||||
|
@ -1347,8 +1121,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
|||
int err;
|
||||
MemoryRegion *mr = section->mr;
|
||||
bool writeable = !mr->readonly && !mr->rom_device;
|
||||
hwaddr start_addr, size, slot_size, mr_offset;
|
||||
ram_addr_t ram_start_offset;
|
||||
hwaddr start_addr, size, slot_size;
|
||||
void *ram;
|
||||
|
||||
if (!memory_region_is_ram(mr)) {
|
||||
|
@ -1366,15 +1139,11 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
|||
return;
|
||||
}
|
||||
|
||||
/* The offset of the kvmslot within the memory region */
|
||||
mr_offset = section->offset_within_region + start_addr -
|
||||
section->offset_within_address_space;
|
||||
/* use aligned delta to align the ram address */
|
||||
ram = memory_region_get_ram_ptr(mr) + section->offset_within_region +
|
||||
(start_addr - section->offset_within_address_space);
|
||||
|
||||
/* use aligned delta to align the ram address and offset */
|
||||
ram = memory_region_get_ram_ptr(mr) + mr_offset;
|
||||
ram_start_offset = memory_region_get_ram_addr(mr) + mr_offset;
|
||||
|
||||
kvm_slots_lock();
|
||||
kvm_slots_lock(kml);
|
||||
|
||||
if (!add) {
|
||||
do {
|
||||
|
@ -1384,25 +1153,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
|||
goto out;
|
||||
}
|
||||
if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
|
||||
/*
|
||||
* NOTE: We should be aware of the fact that here we're only
|
||||
* doing a best effort to sync dirty bits. No matter whether
|
||||
* we're using dirty log or dirty ring, we ignored two facts:
|
||||
*
|
||||
* (1) dirty bits can reside in hardware buffers (PML)
|
||||
*
|
||||
* (2) after we collected dirty bits here, pages can be dirtied
|
||||
* again before we do the final KVM_SET_USER_MEMORY_REGION to
|
||||
* remove the slot.
|
||||
*
|
||||
* Not easy. Let's cross the fingers until it's fixed.
|
||||
*/
|
||||
if (kvm_state->kvm_dirty_ring_size) {
|
||||
kvm_dirty_ring_reap_locked(kvm_state);
|
||||
} else {
|
||||
kvm_slot_get_dirty_log(kvm_state, mem);
|
||||
}
|
||||
kvm_slot_sync_dirty_pages(mem);
|
||||
kvm_physical_sync_dirty_bitmap(kml, section);
|
||||
}
|
||||
|
||||
/* unregister the slot */
|
||||
|
@ -1426,13 +1177,18 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
|||
do {
|
||||
slot_size = MIN(kvm_max_slot_size, size);
|
||||
mem = kvm_alloc_slot(kml);
|
||||
mem->as_id = kml->as_id;
|
||||
mem->memory_size = slot_size;
|
||||
mem->start_addr = start_addr;
|
||||
mem->ram_start_offset = ram_start_offset;
|
||||
mem->ram = ram;
|
||||
mem->flags = kvm_mem_flags(mr);
|
||||
kvm_slot_init_dirty_bitmap(mem);
|
||||
|
||||
if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
|
||||
/*
|
||||
* Reallocate the bmap; it means it doesn't disappear in
|
||||
* middle of a migrate.
|
||||
*/
|
||||
kvm_memslot_init_dirty_bitmap(mem);
|
||||
}
|
||||
err = kvm_set_user_memory_region(kml, mem, true);
|
||||
if (err) {
|
||||
fprintf(stderr, "%s: error registering slot: %s\n", __func__,
|
||||
|
@ -1440,58 +1196,12 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
|||
abort();
|
||||
}
|
||||
start_addr += slot_size;
|
||||
ram_start_offset += slot_size;
|
||||
ram += slot_size;
|
||||
size -= slot_size;
|
||||
} while (size);
|
||||
|
||||
out:
|
||||
kvm_slots_unlock();
|
||||
}
|
||||
|
||||
static void *kvm_dirty_ring_reaper_thread(void *data)
|
||||
{
|
||||
KVMState *s = data;
|
||||
struct KVMDirtyRingReaper *r = &s->reaper;
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
trace_kvm_dirty_ring_reaper("init");
|
||||
|
||||
while (true) {
|
||||
r->reaper_state = KVM_DIRTY_RING_REAPER_WAIT;
|
||||
trace_kvm_dirty_ring_reaper("wait");
|
||||
/*
|
||||
* TODO: provide a smarter timeout rather than a constant?
|
||||
*/
|
||||
sleep(1);
|
||||
|
||||
trace_kvm_dirty_ring_reaper("wakeup");
|
||||
r->reaper_state = KVM_DIRTY_RING_REAPER_REAPING;
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
kvm_dirty_ring_reap(s);
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
r->reaper_iteration++;
|
||||
}
|
||||
|
||||
trace_kvm_dirty_ring_reaper("exit");
|
||||
|
||||
rcu_unregister_thread();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int kvm_dirty_ring_reaper_init(KVMState *s)
|
||||
{
|
||||
struct KVMDirtyRingReaper *r = &s->reaper;
|
||||
|
||||
qemu_thread_create(&r->reaper_thr, "kvm-reaper",
|
||||
kvm_dirty_ring_reaper_thread,
|
||||
s, QEMU_THREAD_JOINABLE);
|
||||
|
||||
return 0;
|
||||
kvm_slots_unlock(kml);
|
||||
}
|
||||
|
||||
static void kvm_region_add(MemoryListener *listener,
|
||||
|
@ -1516,40 +1226,14 @@ static void kvm_log_sync(MemoryListener *listener,
|
|||
MemoryRegionSection *section)
|
||||
{
|
||||
KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener);
|
||||
int r;
|
||||
|
||||
kvm_slots_lock();
|
||||
kvm_physical_sync_dirty_bitmap(kml, section);
|
||||
kvm_slots_unlock();
|
||||
}
|
||||
|
||||
static void kvm_log_sync_global(MemoryListener *l)
|
||||
{
|
||||
KVMMemoryListener *kml = container_of(l, KVMMemoryListener, listener);
|
||||
KVMState *s = kvm_state;
|
||||
KVMSlot *mem;
|
||||
int i;
|
||||
|
||||
/* Flush all kernel dirty addresses into KVMSlot dirty bitmap */
|
||||
kvm_dirty_ring_flush();
|
||||
|
||||
/*
|
||||
* TODO: make this faster when nr_slots is big while there are
|
||||
* only a few used slots (small VMs).
|
||||
*/
|
||||
kvm_slots_lock();
|
||||
for (i = 0; i < s->nr_slots; i++) {
|
||||
mem = &kml->slots[i];
|
||||
if (mem->memory_size && mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
|
||||
kvm_slot_sync_dirty_pages(mem);
|
||||
/*
|
||||
* This is not needed by KVM_GET_DIRTY_LOG because the
|
||||
* ioctl will unconditionally overwrite the whole region.
|
||||
* However kvm dirty ring has no such side effect.
|
||||
*/
|
||||
kvm_slot_reset_dirty_pages(mem);
|
||||
}
|
||||
kvm_slots_lock(kml);
|
||||
r = kvm_physical_sync_dirty_bitmap(kml, section);
|
||||
kvm_slots_unlock(kml);
|
||||
if (r < 0) {
|
||||
abort();
|
||||
}
|
||||
kvm_slots_unlock();
|
||||
}
|
||||
|
||||
static void kvm_log_clear(MemoryListener *listener,
|
||||
|
@ -1642,10 +1326,11 @@ static void kvm_io_ioeventfd_del(MemoryListener *listener,
|
|||
}
|
||||
|
||||
void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
|
||||
AddressSpace *as, int as_id, const char *name)
|
||||
AddressSpace *as, int as_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
qemu_mutex_init(&kml->slots_lock);
|
||||
kml->slots = g_malloc0(s->nr_slots * sizeof(KVMSlot));
|
||||
kml->as_id = as_id;
|
||||
|
||||
|
@ -1657,15 +1342,9 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
|
|||
kml->listener.region_del = kvm_region_del;
|
||||
kml->listener.log_start = kvm_log_start;
|
||||
kml->listener.log_stop = kvm_log_stop;
|
||||
kml->listener.log_sync = kvm_log_sync;
|
||||
kml->listener.log_clear = kvm_log_clear;
|
||||
kml->listener.priority = 10;
|
||||
kml->listener.name = name;
|
||||
|
||||
if (s->kvm_dirty_ring_size) {
|
||||
kml->listener.log_sync_global = kvm_log_sync_global;
|
||||
} else {
|
||||
kml->listener.log_sync = kvm_log_sync;
|
||||
kml->listener.log_clear = kvm_log_clear;
|
||||
}
|
||||
|
||||
memory_listener_register(&kml->listener, as);
|
||||
|
||||
|
@ -1679,7 +1358,6 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
|
|||
}
|
||||
|
||||
static MemoryListener kvm_io_listener = {
|
||||
.name = "kvm-io",
|
||||
.eventfd_add = kvm_io_ioeventfd_add,
|
||||
.eventfd_del = kvm_io_ioeventfd_del,
|
||||
.priority = 10,
|
||||
|
@ -2304,11 +1982,6 @@ bool kvm_vcpu_id_is_valid(int vcpu_id)
|
|||
return vcpu_id >= 0 && vcpu_id < kvm_max_vcpu_id(s);
|
||||
}
|
||||
|
||||
bool kvm_dirty_ring_enabled(void)
|
||||
{
|
||||
return kvm_state->kvm_dirty_ring_size ? true : false;
|
||||
}
|
||||
|
||||
static int kvm_init(MachineState *ms)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
|
@ -2330,8 +2003,6 @@ static int kvm_init(MachineState *ms)
|
|||
int type = 0;
|
||||
uint64_t dirty_log_manual_caps;
|
||||
|
||||
qemu_mutex_init(&kml_slots_lock);
|
||||
|
||||
s = KVM_STATE(ms->accelerator);
|
||||
|
||||
/*
|
||||
|
@ -2348,6 +2019,7 @@ static int kvm_init(MachineState *ms)
|
|||
QTAILQ_INIT(&s->kvm_sw_breakpoints);
|
||||
#endif
|
||||
QLIST_INIT(&s->kvm_parked_vcpus);
|
||||
s->vmfd = -1;
|
||||
s->fd = qemu_open_old("/dev/kvm", O_RDWR);
|
||||
if (s->fd == -1) {
|
||||
fprintf(stderr, "Could not access KVM kernel module: %m\n");
|
||||
|
@ -2413,12 +2085,6 @@ static int kvm_init(MachineState *ms)
|
|||
"- for kernels supporting the vm.allocate_pgste sysctl, "
|
||||
"whether it is enabled\n");
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
if (ret == -EINVAL) {
|
||||
fprintf(stderr,
|
||||
"PPC KVM module is not loaded. Try modprobe kvm_%s.\n",
|
||||
(type == 2) ? "pr" : "hv");
|
||||
}
|
||||
#endif
|
||||
goto err;
|
||||
}
|
||||
|
@ -2461,70 +2127,20 @@ static int kvm_init(MachineState *ms)
|
|||
s->coalesced_pio = s->coalesced_mmio &&
|
||||
kvm_check_extension(s, KVM_CAP_COALESCED_PIO);
|
||||
|
||||
/*
|
||||
* Enable KVM dirty ring if supported, otherwise fall back to
|
||||
* dirty logging mode
|
||||
*/
|
||||
if (s->kvm_dirty_ring_size > 0) {
|
||||
uint64_t ring_bytes;
|
||||
|
||||
ring_bytes = s->kvm_dirty_ring_size * sizeof(struct kvm_dirty_gfn);
|
||||
|
||||
/* Read the max supported pages */
|
||||
ret = kvm_vm_check_extension(s, KVM_CAP_DIRTY_LOG_RING);
|
||||
if (ret > 0) {
|
||||
if (ring_bytes > ret) {
|
||||
error_report("KVM dirty ring size %" PRIu32 " too big "
|
||||
"(maximum is %ld). Please use a smaller value.",
|
||||
s->kvm_dirty_ring_size,
|
||||
(long)ret / sizeof(struct kvm_dirty_gfn));
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = kvm_vm_enable_cap(s, KVM_CAP_DIRTY_LOG_RING, 0, ring_bytes);
|
||||
if (ret) {
|
||||
error_report("Enabling of KVM dirty ring failed: %s. "
|
||||
"Suggested minimum value is 1024.", strerror(-ret));
|
||||
goto err;
|
||||
}
|
||||
|
||||
s->kvm_dirty_ring_bytes = ring_bytes;
|
||||
} else {
|
||||
warn_report("KVM dirty ring not available, using bitmap method");
|
||||
s->kvm_dirty_ring_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is not needed when dirty ring is
|
||||
* enabled. More importantly, KVM_DIRTY_LOG_INITIALLY_SET will assume no
|
||||
* page is wr-protected initially, which is against how kvm dirty ring is
|
||||
* usage - kvm dirty ring requires all pages are wr-protected at the very
|
||||
* beginning. Enabling this feature for dirty ring causes data corruption.
|
||||
*
|
||||
* TODO: Without KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 and kvm clear dirty log,
|
||||
* we may expect a higher stall time when starting the migration. In the
|
||||
* future we can enable KVM_CLEAR_DIRTY_LOG to work with dirty ring too:
|
||||
* instead of clearing dirty bit, it can be a way to explicitly wr-protect
|
||||
* guest pages.
|
||||
*/
|
||||
if (!s->kvm_dirty_ring_size) {
|
||||
dirty_log_manual_caps =
|
||||
kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
|
||||
dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |
|
||||
KVM_DIRTY_LOG_INITIALLY_SET);
|
||||
s->manual_dirty_log_protect = dirty_log_manual_caps;
|
||||
if (dirty_log_manual_caps) {
|
||||
ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0,
|
||||
dirty_log_manual_caps);
|
||||
if (ret) {
|
||||
warn_report("Trying to enable capability %"PRIu64" of "
|
||||
"KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. "
|
||||
"Falling back to the legacy mode. ",
|
||||
dirty_log_manual_caps);
|
||||
s->manual_dirty_log_protect = 0;
|
||||
}
|
||||
dirty_log_manual_caps =
|
||||
kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
|
||||
dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |
|
||||
KVM_DIRTY_LOG_INITIALLY_SET);
|
||||
s->manual_dirty_log_protect = dirty_log_manual_caps;
|
||||
if (dirty_log_manual_caps) {
|
||||
ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0,
|
||||
dirty_log_manual_caps);
|
||||
if (ret) {
|
||||
warn_report("Trying to enable capability %"PRIu64" of "
|
||||
"KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. "
|
||||
"Falling back to the legacy mode. ",
|
||||
dirty_log_manual_caps);
|
||||
s->manual_dirty_log_protect = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2570,25 +2186,6 @@ static int kvm_init(MachineState *ms)
|
|||
kvm_ioeventfd_any_length_allowed =
|
||||
(kvm_check_extension(s, KVM_CAP_IOEVENTFD_ANY_LENGTH) > 0);
|
||||
|
||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
||||
kvm_has_guest_debug =
|
||||
(kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0);
|
||||
#endif
|
||||
|
||||
kvm_sstep_flags = 0;
|
||||
if (kvm_has_guest_debug) {
|
||||
kvm_sstep_flags = SSTEP_ENABLE;
|
||||
|
||||
#if defined KVM_CAP_SET_GUEST_DEBUG2
|
||||
int guest_debug_flags =
|
||||
kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG2);
|
||||
|
||||
if (guest_debug_flags & KVM_GUESTDBG_BLOCKIRQ) {
|
||||
kvm_sstep_flags |= SSTEP_NOIRQ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
kvm_state = s;
|
||||
|
||||
ret = kvm_arch_init(ms, s);
|
||||
|
@ -2614,7 +2211,7 @@ static int kvm_init(MachineState *ms)
|
|||
s->memory_listener.listener.coalesced_io_del = kvm_uncoalesce_mmio_region;
|
||||
|
||||
kvm_memory_listener_register(s, &s->memory_listener,
|
||||
&address_space_memory, 0, "kvm-memory");
|
||||
&address_space_memory, 0);
|
||||
if (kvm_eventfds_allowed) {
|
||||
memory_listener_register(&kvm_io_listener,
|
||||
&address_space_io);
|
||||
|
@ -2629,14 +2226,6 @@ static int kvm_init(MachineState *ms)
|
|||
ret = ram_block_discard_disable(true);
|
||||
assert(!ret);
|
||||
}
|
||||
|
||||
if (s->kvm_dirty_ring_size) {
|
||||
ret = kvm_dirty_ring_reaper_init(s);
|
||||
if (ret) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -2680,7 +2269,7 @@ static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < run->internal.ndata; ++i) {
|
||||
fprintf(stderr, "extra data[%d]: 0x%016"PRIx64"\n",
|
||||
fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
|
||||
i, (uint64_t)run->internal.data[i]);
|
||||
}
|
||||
}
|
||||
|
@ -2949,17 +2538,6 @@ int kvm_cpu_exec(CPUState *cpu)
|
|||
case KVM_EXIT_INTERNAL_ERROR:
|
||||
ret = kvm_handle_internal_error(cpu, run);
|
||||
break;
|
||||
case KVM_EXIT_DIRTY_RING_FULL:
|
||||
/*
|
||||
* We shouldn't continue if the dirty ring of this vcpu is
|
||||
* still full. Got kicked by KVM_RESET_DIRTY_RINGS.
|
||||
*/
|
||||
trace_kvm_dirty_ring_full(cpu->cpu_index);
|
||||
qemu_mutex_lock_iothread();
|
||||
kvm_dirty_ring_reap(kvm_state);
|
||||
qemu_mutex_unlock_iothread();
|
||||
ret = 0;
|
||||
break;
|
||||
case KVM_EXIT_SYSTEM_EVENT:
|
||||
switch (run->system_event.type) {
|
||||
case KVM_SYSTEM_EVENT_SHUTDOWN:
|
||||
|
@ -3218,10 +2796,6 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
|
|||
|
||||
if (cpu->singlestep_enabled) {
|
||||
data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
|
||||
|
||||
if (cpu->singlestep_enabled & SSTEP_NOIRQ) {
|
||||
data.dbg.control |= KVM_GUESTDBG_BLOCKIRQ;
|
||||
}
|
||||
}
|
||||
kvm_arch_update_guest_debug(cpu, &data.dbg);
|
||||
|
||||
|
@ -3540,11 +3114,6 @@ static void kvm_set_kvm_shadow_mem(Object *obj, Visitor *v,
|
|||
KVMState *s = KVM_STATE(obj);
|
||||
int64_t value;
|
||||
|
||||
if (s->fd != -1) {
|
||||
error_setg(errp, "Cannot set properties after the accelerator has been initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!visit_type_int(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
|
@ -3559,11 +3128,6 @@ static void kvm_set_kernel_irqchip(Object *obj, Visitor *v,
|
|||
KVMState *s = KVM_STATE(obj);
|
||||
OnOffSplit mode;
|
||||
|
||||
if (s->fd != -1) {
|
||||
error_setg(errp, "Cannot set properties after the accelerator has been initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!visit_type_OnOffSplit(v, name, &mode, errp)) {
|
||||
return;
|
||||
}
|
||||
|
@ -3606,53 +3170,13 @@ bool kvm_kernel_irqchip_split(void)
|
|||
return kvm_state->kernel_irqchip_split == ON_OFF_AUTO_ON;
|
||||
}
|
||||
|
||||
static void kvm_get_dirty_ring_size(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
uint32_t value = s->kvm_dirty_ring_size;
|
||||
|
||||
visit_type_uint32(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void kvm_set_dirty_ring_size(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
Error *error = NULL;
|
||||
uint32_t value;
|
||||
|
||||
if (s->fd != -1) {
|
||||
error_setg(errp, "Cannot set properties after the accelerator has been initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_uint32(v, name, &value, &error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
return;
|
||||
}
|
||||
if (value & (value - 1)) {
|
||||
error_setg(errp, "dirty-ring-size must be a power of two.");
|
||||
return;
|
||||
}
|
||||
|
||||
s->kvm_dirty_ring_size = value;
|
||||
}
|
||||
|
||||
static void kvm_accel_instance_init(Object *obj)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
|
||||
s->fd = -1;
|
||||
s->vmfd = -1;
|
||||
s->kvm_shadow_mem = -1;
|
||||
s->kernel_irqchip_allowed = true;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_AUTO;
|
||||
/* KVM dirty ring is by default off */
|
||||
s->kvm_dirty_ring_size = 0;
|
||||
}
|
||||
|
||||
static void kvm_accel_class_init(ObjectClass *oc, void *data)
|
||||
|
@ -3674,12 +3198,6 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data)
|
|||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "kvm-shadow-mem",
|
||||
"KVM shadow MMU size");
|
||||
|
||||
object_class_property_add(oc, "dirty-ring-size", "uint32",
|
||||
kvm_get_dirty_ring_size, kvm_set_dirty_ring_size,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "dirty-ring-size",
|
||||
"Size of KVM dirty page ring buffer (default: 0, i.e. use bitmap)");
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_accel_type = {
|
||||
|
|
|
@ -3,5 +3,6 @@ kvm_ss.add(files(
|
|||
'kvm-all.c',
|
||||
'kvm-accel-ops.c',
|
||||
))
|
||||
kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c'))
|
||||
|
||||
specific_ss.add_all(when: 'CONFIG_KVM', if_true: kvm_ss)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* QEMU SEV stub
|
||||
*
|
||||
* Copyright Advanced Micro Devices 2018
|
||||
*
|
||||
* Authors:
|
||||
* Brijesh Singh <brijesh.singh@amd.com>
|
||||
*
|
||||
* 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 "qemu-common.h"
|
||||
#include "sysemu/sev.h"
|
||||
|
||||
int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
|
||||
{
|
||||
/* If we get here, cgs must be some non-SEV thing */
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
# See docs/devel/tracing.rst for syntax documentation.
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# kvm-all.c
|
||||
kvm_ioctl(int type, void *arg) "type 0x%x, arg %p"
|
||||
|
@ -18,11 +18,4 @@ kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t
|
|||
kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
|
||||
kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
|
||||
kvm_resample_fd_notify(int gsi) "gsi %d"
|
||||
kvm_dirty_ring_full(int id) "vcpu %d"
|
||||
kvm_dirty_ring_reap_vcpu(int id) "vcpu %d"
|
||||
kvm_dirty_ring_page(int vcpu, uint32_t slot, uint64_t offset) "vcpu %d fetch %"PRIu32" offset 0x%"PRIx64
|
||||
kvm_dirty_ring_reaper(const char *s) "%s"
|
||||
kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"PRIi64" us)"
|
||||
kvm_dirty_ring_reaper_kick(const char *reason) "%s"
|
||||
kvm_dirty_ring_flush(int finished) "%d"
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ specific_ss.add(files('accel-common.c'))
|
|||
softmmu_ss.add(files('accel-softmmu.c'))
|
||||
user_ss.add(files('accel-user.c'))
|
||||
|
||||
subdir('hvf')
|
||||
subdir('qtest')
|
||||
subdir('kvm')
|
||||
subdir('tcg')
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
qtest_module_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'],
|
||||
if_true: files('qtest.c'))
|
||||
qtest_ss = ss.source_set()
|
||||
qtest_ss.add(files(
|
||||
'qtest.c',
|
||||
))
|
||||
|
||||
specific_ss.add_all(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'], if_true: qtest_ss)
|
||||
|
|
|
@ -45,7 +45,6 @@ static const TypeInfo qtest_accel_type = {
|
|||
.parent = TYPE_ACCEL,
|
||||
.class_init = qtest_accel_class_init,
|
||||
};
|
||||
module_obj(TYPE_QTEST_ACCEL);
|
||||
|
||||
static void qtest_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
|
@ -62,7 +61,6 @@ static const TypeInfo qtest_accel_ops_type = {
|
|||
.class_init = qtest_accel_ops_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
module_obj(ACCEL_OPS_NAME("qtest"));
|
||||
|
||||
static void qtest_type_init(void)
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
@ -147,9 +148,4 @@ bool kvm_arm_supports_user_irq(void)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kvm_dirty_ring_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
void tb_flush(CPUState *cpu)
|
||||
|
|
|
@ -13,112 +13,42 @@
|
|||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
static void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static inline
|
||||
void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr, uint16_t info)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
|
||||
trace_guest_rmw_before_exec(cpu, addr, oi);
|
||||
trace_guest_mem_before_exec(cpu, addr, info);
|
||||
trace_guest_mem_before_exec(cpu, addr, info | TRACE_MEM_ST);
|
||||
}
|
||||
|
||||
static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static inline void
|
||||
atomic_trace_rmw_post(CPUArchState *env, target_ulong addr, uint16_t info)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_RW);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info | TRACE_MEM_ST);
|
||||
}
|
||||
|
||||
#if HAVE_ATOMIC128
|
||||
static void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static inline
|
||||
void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr, uint16_t info)
|
||||
{
|
||||
trace_guest_ld_before_exec(env_cpu(env), addr, oi);
|
||||
trace_guest_mem_before_exec(env_cpu(env), addr, info);
|
||||
}
|
||||
|
||||
static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static inline
|
||||
void atomic_trace_ld_post(CPUArchState *env, target_ulong addr, uint16_t info)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||
}
|
||||
|
||||
static void atomic_trace_st_pre(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static inline
|
||||
void atomic_trace_st_pre(CPUArchState *env, target_ulong addr, uint16_t info)
|
||||
{
|
||||
trace_guest_st_before_exec(env_cpu(env), addr, oi);
|
||||
trace_guest_mem_before_exec(env_cpu(env), addr, info);
|
||||
}
|
||||
|
||||
static void atomic_trace_st_post(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi)
|
||||
static inline
|
||||
void atomic_trace_st_post(CPUArchState *env, target_ulong addr, uint16_t info)
|
||||
{
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Atomic helpers callable from TCG.
|
||||
* These have a common interface and all defer to cpu_atomic_*
|
||||
* using the host return address from GETPC().
|
||||
*/
|
||||
|
||||
#define CMPXCHG_HELPER(OP, TYPE) \
|
||||
TYPE HELPER(atomic_##OP)(CPUArchState *env, target_ulong addr, \
|
||||
TYPE oldv, TYPE newv, uint32_t oi) \
|
||||
{ return cpu_atomic_##OP##_mmu(env, addr, oldv, newv, oi, GETPC()); }
|
||||
|
||||
CMPXCHG_HELPER(cmpxchgb, uint32_t)
|
||||
CMPXCHG_HELPER(cmpxchgw_be, uint32_t)
|
||||
CMPXCHG_HELPER(cmpxchgw_le, uint32_t)
|
||||
CMPXCHG_HELPER(cmpxchgl_be, uint32_t)
|
||||
CMPXCHG_HELPER(cmpxchgl_le, uint32_t)
|
||||
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
CMPXCHG_HELPER(cmpxchgq_be, uint64_t)
|
||||
CMPXCHG_HELPER(cmpxchgq_le, uint64_t)
|
||||
#endif
|
||||
|
||||
#undef CMPXCHG_HELPER
|
||||
|
||||
#define ATOMIC_HELPER(OP, TYPE) \
|
||||
TYPE HELPER(glue(atomic_,OP))(CPUArchState *env, target_ulong addr, \
|
||||
TYPE val, uint32_t oi) \
|
||||
{ return glue(glue(cpu_atomic_,OP),_mmu)(env, addr, val, oi, GETPC()); }
|
||||
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
#define GEN_ATOMIC_HELPERS(OP) \
|
||||
ATOMIC_HELPER(glue(OP,b), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,w_be), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,w_le), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,l_be), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,l_le), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,q_be), uint64_t) \
|
||||
ATOMIC_HELPER(glue(OP,q_le), uint64_t)
|
||||
#else
|
||||
#define GEN_ATOMIC_HELPERS(OP) \
|
||||
ATOMIC_HELPER(glue(OP,b), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,w_be), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,w_le), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,l_be), uint32_t) \
|
||||
ATOMIC_HELPER(glue(OP,l_le), uint32_t)
|
||||
#endif
|
||||
|
||||
GEN_ATOMIC_HELPERS(fetch_add)
|
||||
GEN_ATOMIC_HELPERS(fetch_and)
|
||||
GEN_ATOMIC_HELPERS(fetch_or)
|
||||
GEN_ATOMIC_HELPERS(fetch_xor)
|
||||
GEN_ATOMIC_HELPERS(fetch_smin)
|
||||
GEN_ATOMIC_HELPERS(fetch_umin)
|
||||
GEN_ATOMIC_HELPERS(fetch_smax)
|
||||
GEN_ATOMIC_HELPERS(fetch_umax)
|
||||
|
||||
GEN_ATOMIC_HELPERS(add_fetch)
|
||||
GEN_ATOMIC_HELPERS(and_fetch)
|
||||
GEN_ATOMIC_HELPERS(or_fetch)
|
||||
GEN_ATOMIC_HELPERS(xor_fetch)
|
||||
GEN_ATOMIC_HELPERS(smin_fetch)
|
||||
GEN_ATOMIC_HELPERS(umin_fetch)
|
||||
GEN_ATOMIC_HELPERS(smax_fetch)
|
||||
GEN_ATOMIC_HELPERS(umax_fetch)
|
||||
|
||||
GEN_ATOMIC_HELPERS(xchg)
|
||||
|
||||
#undef ATOMIC_HELPER
|
||||
#undef GEN_ATOMIC_HELPERS
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/plugin.h"
|
||||
#include "trace/mem.h"
|
||||
|
||||
#if DATA_SIZE == 16
|
||||
# define SUFFIX o
|
||||
|
@ -27,8 +28,8 @@
|
|||
# define SHIFT 4
|
||||
#elif DATA_SIZE == 8
|
||||
# define SUFFIX q
|
||||
# define DATA_TYPE aligned_uint64_t
|
||||
# define SDATA_TYPE aligned_int64_t
|
||||
# define DATA_TYPE uint64_t
|
||||
# define SDATA_TYPE int64_t
|
||||
# define BSWAP bswap64
|
||||
# define SHIFT 3
|
||||
#elif DATA_SIZE == 4
|
||||
|
@ -70,78 +71,85 @@
|
|||
#endif
|
||||
|
||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
ABI_TYPE cmpv, ABI_TYPE newv,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
#if DATA_SIZE == 16
|
||||
ret = atomic16_cmpxchg(haddr, cmpv, newv);
|
||||
#else
|
||||
ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
|
||||
#endif
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if DATA_SIZE >= 16
|
||||
#if HAVE_ATOMIC128
|
||||
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ, retaddr);
|
||||
DATA_TYPE val;
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_ld_pre(env, addr, oi);
|
||||
atomic_trace_ld_pre(env, addr, info);
|
||||
val = atomic16_read(haddr);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_ld_post(env, addr, oi);
|
||||
atomic_trace_ld_post(env, addr, info);
|
||||
return val;
|
||||
}
|
||||
|
||||
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
|
||||
ABI_TYPE val EXTRA_ARGS)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_WRITE, retaddr);
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, true,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_st_pre(env, addr, oi);
|
||||
atomic_trace_st_pre(env, addr, info);
|
||||
atomic16_set(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_st_post(env, addr, oi);
|
||||
atomic_trace_st_post(env, addr, info);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
||||
ABI_TYPE val EXTRA_ARGS)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
ret = qatomic_xchg__nocheck(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define GEN_ATOMIC_HELPER(X) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
|
||||
ABI_TYPE val EXTRA_ARGS) \
|
||||
{ \
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
DATA_TYPE ret; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
ret = qatomic_##X(haddr, val); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
|
@ -156,8 +164,7 @@ GEN_ATOMIC_HELPER(xor_fetch)
|
|||
|
||||
#undef GEN_ATOMIC_HELPER
|
||||
|
||||
/*
|
||||
* These helpers are, as a whole, full barriers. Within the helper,
|
||||
/* These helpers are, as a whole, full barriers. Within the helper,
|
||||
* the leading barrier is explicit and the trailing barrier is within
|
||||
* cmpxchg primitive.
|
||||
*
|
||||
|
@ -166,12 +173,14 @@ GEN_ATOMIC_HELPER(xor_fetch)
|
|||
*/
|
||||
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
|
||||
ABI_TYPE xval EXTRA_ARGS) \
|
||||
{ \
|
||||
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
XDATA_TYPE cmp, old, new, val = xval; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
smp_mb(); \
|
||||
cmp = qatomic_read__nocheck(haddr); \
|
||||
do { \
|
||||
|
@ -179,7 +188,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
|||
cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \
|
||||
} while (cmp != old); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return RET; \
|
||||
}
|
||||
|
||||
|
@ -209,79 +218,87 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
|
|||
#endif
|
||||
|
||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
ABI_TYPE cmpv, ABI_TYPE newv,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
#if DATA_SIZE == 16
|
||||
ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||
#else
|
||||
ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||
#endif
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return BSWAP(ret);
|
||||
}
|
||||
|
||||
#if DATA_SIZE >= 16
|
||||
#if HAVE_ATOMIC128
|
||||
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ, retaddr);
|
||||
DATA_TYPE val;
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_ld_pre(env, addr, oi);
|
||||
atomic_trace_ld_pre(env, addr, info);
|
||||
val = atomic16_read(haddr);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_ld_post(env, addr, oi);
|
||||
atomic_trace_ld_post(env, addr, info);
|
||||
return BSWAP(val);
|
||||
}
|
||||
|
||||
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
|
||||
ABI_TYPE val EXTRA_ARGS)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_WRITE, retaddr);
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_st_pre(env, addr, oi);
|
||||
val = BSWAP(val);
|
||||
atomic_trace_st_pre(env, addr, info);
|
||||
val = BSWAP(val);
|
||||
atomic16_set(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_st_post(env, addr, oi);
|
||||
atomic_trace_st_post(env, addr, info);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
||||
ABI_TYPE val EXTRA_ARGS)
|
||||
{
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||
PAGE_READ | PAGE_WRITE, retaddr);
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
ABI_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, oi);
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, oi);
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return BSWAP(ret);
|
||||
}
|
||||
|
||||
#define GEN_ATOMIC_HELPER(X) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
|
||||
ABI_TYPE val EXTRA_ARGS) \
|
||||
{ \
|
||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
DATA_TYPE ret; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \
|
||||
false, ATOMIC_MMU_IDX); \
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
ret = qatomic_##X(haddr, BSWAP(val)); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return BSWAP(ret); \
|
||||
}
|
||||
|
||||
|
@ -303,12 +320,14 @@ GEN_ATOMIC_HELPER(xor_fetch)
|
|||
*/
|
||||
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
|
||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
|
||||
ABI_TYPE xval EXTRA_ARGS) \
|
||||
{ \
|
||||
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
XDATA_TYPE ldo, ldn, old, new, val = xval; \
|
||||
atomic_trace_rmw_pre(env, addr, oi); \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \
|
||||
false, ATOMIC_MMU_IDX); \
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
smp_mb(); \
|
||||
ldn = qatomic_read__nocheck(haddr); \
|
||||
do { \
|
||||
|
@ -316,7 +335,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
|||
ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
|
||||
} while (ldo != ldn); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, oi); \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return RET; \
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
|
|
@ -20,9 +20,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "qapi/type-helpers.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
|
@ -32,6 +30,8 @@
|
|||
#include "qemu/compiler.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "exec/tb-hash.h"
|
||||
#include "exec/tb-lookup.h"
|
||||
#include "exec/log.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||
|
@ -41,10 +41,6 @@
|
|||
#include "exec/cpu-all.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "tb-hash.h"
|
||||
#include "tb-context.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* -icount align implementation. */
|
||||
|
@ -149,190 +145,6 @@ static void init_delay_params(SyncClocks *sc, const CPUState *cpu)
|
|||
}
|
||||
#endif /* CONFIG USER ONLY */
|
||||
|
||||
uint32_t curr_cflags(CPUState *cpu)
|
||||
{
|
||||
uint32_t cflags = cpu->tcg_cflags;
|
||||
|
||||
/*
|
||||
* Record gdb single-step. We should be exiting the TB by raising
|
||||
* EXCP_DEBUG, but to simplify other tests, disable chaining too.
|
||||
*
|
||||
* For singlestep and -d nochain, suppress goto_tb so that
|
||||
* we can log -d cpu,exec after every TB.
|
||||
*/
|
||||
if (unlikely(cpu->singlestep_enabled)) {
|
||||
cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | CF_SINGLE_STEP | 1;
|
||||
} else if (singlestep) {
|
||||
cflags |= CF_NO_GOTO_TB | 1;
|
||||
} else if (qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) {
|
||||
cflags |= CF_NO_GOTO_TB;
|
||||
}
|
||||
|
||||
return cflags;
|
||||
}
|
||||
|
||||
/* Might cause an exception, so have a longjmp destination ready */
|
||||
static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
|
||||
target_ulong cs_base,
|
||||
uint32_t flags, uint32_t cflags)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
uint32_t hash;
|
||||
|
||||
/* we should never be trying to look up an INVALID tb */
|
||||
tcg_debug_assert(!(cflags & CF_INVALID));
|
||||
|
||||
hash = tb_jmp_cache_hash_func(pc);
|
||||
tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash]);
|
||||
|
||||
if (likely(tb &&
|
||||
tb->pc == pc &&
|
||||
tb->cs_base == cs_base &&
|
||||
tb->flags == flags &&
|
||||
tb->trace_vcpu_dstate == *cpu->trace_dstate &&
|
||||
tb_cflags(tb) == cflags)) {
|
||||
return tb;
|
||||
}
|
||||
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
qatomic_set(&cpu->tb_jmp_cache[hash], tb);
|
||||
return tb;
|
||||
}
|
||||
|
||||
static inline void log_cpu_exec(target_ulong pc, CPUState *cpu,
|
||||
const TranslationBlock *tb)
|
||||
{
|
||||
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC))
|
||||
&& qemu_log_in_addr_range(pc)) {
|
||||
|
||||
qemu_log_mask(CPU_LOG_EXEC,
|
||||
"Trace %d: %p [" TARGET_FMT_lx
|
||||
"/" TARGET_FMT_lx "/%08x/%08x] %s\n",
|
||||
cpu->cpu_index, tb->tc.ptr, tb->cs_base, pc,
|
||||
tb->flags, tb->cflags, lookup_symbol(pc));
|
||||
|
||||
#if defined(DEBUG_DISAS)
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
|
||||
FILE *logfile = qemu_log_lock();
|
||||
int flags = 0;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
|
||||
flags |= CPU_DUMP_FPU;
|
||||
}
|
||||
#if defined(TARGET_I386)
|
||||
flags |= CPU_DUMP_CCOP;
|
||||
#endif
|
||||
log_cpu_state(cpu, flags);
|
||||
qemu_log_unlock(logfile);
|
||||
}
|
||||
#endif /* DEBUG_DISAS */
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_for_breakpoints(CPUState *cpu, target_ulong pc,
|
||||
uint32_t *cflags)
|
||||
{
|
||||
CPUBreakpoint *bp;
|
||||
bool match_page = false;
|
||||
|
||||
if (likely(QTAILQ_EMPTY(&cpu->breakpoints))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Singlestep overrides breakpoints.
|
||||
* This requirement is visible in the record-replay tests, where
|
||||
* we would fail to make forward progress in reverse-continue.
|
||||
*
|
||||
* TODO: gdb singlestep should only override gdb breakpoints,
|
||||
* so that one could (gdb) singlestep into the guest kernel's
|
||||
* architectural breakpoint handler.
|
||||
*/
|
||||
if (cpu->singlestep_enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
|
||||
/*
|
||||
* If we have an exact pc match, trigger the breakpoint.
|
||||
* Otherwise, note matches within the page.
|
||||
*/
|
||||
if (pc == bp->pc) {
|
||||
bool match_bp = false;
|
||||
|
||||
if (bp->flags & BP_GDB) {
|
||||
match_bp = true;
|
||||
} else if (bp->flags & BP_CPU) {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
g_assert_not_reached();
|
||||
#else
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
assert(cc->tcg_ops->debug_check_breakpoint);
|
||||
match_bp = cc->tcg_ops->debug_check_breakpoint(cpu);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (match_bp) {
|
||||
cpu->exception_index = EXCP_DEBUG;
|
||||
return true;
|
||||
}
|
||||
} else if (((pc ^ bp->pc) & TARGET_PAGE_MASK) == 0) {
|
||||
match_page = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Within the same page as a breakpoint, single-step,
|
||||
* returning to helper_lookup_tb_ptr after each insn looking
|
||||
* for the actual breakpoint.
|
||||
*
|
||||
* TODO: Perhaps better to record all of the TBs associated
|
||||
* with a given virtual page that contains a breakpoint, and
|
||||
* then invalidate them when a new overlapping breakpoint is
|
||||
* set on the page. Non-overlapping TBs would not be
|
||||
* invalidated, nor would any TB need to be invalidated as
|
||||
* breakpoints are removed.
|
||||
*/
|
||||
if (match_page) {
|
||||
*cflags = (*cflags & ~CF_COUNT_MASK) | CF_NO_GOTO_TB | 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* helper_lookup_tb_ptr: quick check for next tb
|
||||
* @env: current cpu state
|
||||
*
|
||||
* Look for an existing TB matching the current cpu state.
|
||||
* If found, return the code pointer. If not found, return
|
||||
* the tcg epilogue so that we return into cpu_tb_exec.
|
||||
*/
|
||||
const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags, cflags;
|
||||
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
|
||||
cflags = curr_cflags(cpu);
|
||||
if (check_for_breakpoints(cpu, pc, &cflags)) {
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
|
||||
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb == NULL) {
|
||||
return tcg_code_gen_epilogue;
|
||||
}
|
||||
|
||||
log_cpu_exec(pc, cpu, tb);
|
||||
|
||||
return tb->tc.ptr;
|
||||
}
|
||||
|
||||
/* Execute a TB, and fix up the CPU state afterwards if necessary */
|
||||
/*
|
||||
* Disable CFI checks.
|
||||
|
@ -351,7 +163,28 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
|||
TranslationBlock *last_tb;
|
||||
const void *tb_ptr = itb->tc.ptr;
|
||||
|
||||
log_cpu_exec(itb->pc, cpu, itb);
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc,
|
||||
"Trace %d: %p ["
|
||||
TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n",
|
||||
cpu->cpu_index, itb->tc.ptr,
|
||||
itb->cs_base, itb->pc, itb->flags,
|
||||
lookup_symbol(itb->pc));
|
||||
|
||||
#if defined(DEBUG_DISAS)
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)
|
||||
&& qemu_log_in_addr_range(itb->pc)) {
|
||||
FILE *logfile = qemu_log_lock();
|
||||
int flags = 0;
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
|
||||
flags |= CPU_DUMP_FPU;
|
||||
}
|
||||
#if defined(TARGET_I386)
|
||||
flags |= CPU_DUMP_CCOP;
|
||||
#endif
|
||||
log_cpu_state(cpu, flags);
|
||||
qemu_log_unlock(logfile);
|
||||
}
|
||||
#endif /* DEBUG_DISAS */
|
||||
|
||||
qemu_thread_jit_execute();
|
||||
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
||||
|
@ -387,17 +220,6 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
|||
cc->set_pc(cpu, last_tb->pc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If gdb single-step, and we haven't raised another exception,
|
||||
* raise a debug exception. Single-step with another exception
|
||||
* is handled in cpu_handle_exception.
|
||||
*/
|
||||
if (unlikely(cpu->singlestep_enabled) && cpu->exception_index == -1) {
|
||||
cpu->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
|
||||
return last_tb;
|
||||
}
|
||||
|
||||
|
@ -425,7 +247,8 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags, cflags;
|
||||
uint32_t flags;
|
||||
uint32_t cflags = (curr_cflags(cpu) & ~CF_PARALLEL) | 1;
|
||||
int tb_exit;
|
||||
|
||||
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
||||
|
@ -435,20 +258,8 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||
cpu->running = true;
|
||||
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
|
||||
cflags = curr_cflags(cpu);
|
||||
/* Execute in a serial context. */
|
||||
cflags &= ~CF_PARALLEL;
|
||||
/* After 1 insn, return and release the exclusive lock. */
|
||||
cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | 1;
|
||||
/*
|
||||
* No need to check_for_breakpoints here.
|
||||
* We only arrive in cpu_exec_step_atomic after beginning execution
|
||||
* of an insn that includes an atomic operation we can't handle.
|
||||
* Any breakpoint for this insn will have been recognized earlier.
|
||||
*/
|
||||
|
||||
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
|
||||
if (tb == NULL) {
|
||||
mmap_lock();
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
||||
|
@ -466,7 +277,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||
* memory.
|
||||
*/
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
clear_helper_retaddr();
|
||||
tcg_debug_assert(!have_mmap_lock());
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
|
@ -476,6 +286,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||
qemu_plugin_disable_mem_helpers(cpu);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* As we start the exclusive region before codegen we must still
|
||||
* be in the region if we longjump out of either the codegen or
|
||||
|
@ -601,11 +412,45 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
|||
return;
|
||||
}
|
||||
|
||||
static inline TranslationBlock *tb_find(CPUState *cpu,
|
||||
TranslationBlock *last_tb,
|
||||
int tb_exit, uint32_t cflags)
|
||||
{
|
||||
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags;
|
||||
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
|
||||
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb == NULL) {
|
||||
mmap_lock();
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
||||
mmap_unlock();
|
||||
/* We add the TB in the virtual pc hash table for the fast lookup */
|
||||
qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
|
||||
}
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* We don't take care of direct jumps when address mapping changes in
|
||||
* system emulation. So it's not safe to make a direct jump to a TB
|
||||
* spanning two pages because the mapping for the second page can change.
|
||||
*/
|
||||
if (tb->page_addr[1] != -1) {
|
||||
last_tb = NULL;
|
||||
}
|
||||
#endif
|
||||
/* See if we can patch the calling TB. */
|
||||
if (last_tb) {
|
||||
tb_add_jump(last_tb, tb_exit, tb);
|
||||
}
|
||||
return tb;
|
||||
}
|
||||
|
||||
static inline bool cpu_handle_halt(CPUState *cpu)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu->halted) {
|
||||
#if defined(TARGET_I386)
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
|
||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
|
@ -613,14 +458,13 @@ static inline bool cpu_handle_halt(CPUState *cpu)
|
|||
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
#endif /* TARGET_I386 */
|
||||
#endif
|
||||
if (!cpu_has_work(cpu)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cpu->halted = 0;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -668,8 +512,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||
loop */
|
||||
#if defined(TARGET_I386)
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
cc->tcg_ops->fake_user_interrupt(cpu);
|
||||
#endif /* TARGET_I386 */
|
||||
cc->tcg_ops->do_interrupt(cpu);
|
||||
#endif
|
||||
*ret = cpu->exception_index;
|
||||
cpu->exception_index = -1;
|
||||
return true;
|
||||
|
@ -702,7 +546,6 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/*
|
||||
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
|
||||
* "real" interrupt event later. It does not need to be recorded for
|
||||
|
@ -716,19 +559,11 @@ static inline bool need_replay_interrupt(int interrupt_request)
|
|||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
TranslationBlock **last_tb)
|
||||
{
|
||||
/*
|
||||
* If we have requested custom cflags with CF_NOIRQ we should
|
||||
* skip checking here. Any pending interrupts will get picked up
|
||||
* by the next TB we execute under normal cflags.
|
||||
*/
|
||||
if (cpu->cflags_next_tb != -1 && cpu->cflags_next_tb & CF_NOIRQ) {
|
||||
return false;
|
||||
}
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
/* Clear the interrupt flag now since we're processing
|
||||
* cpu->interrupt_request and cpu->exit_request.
|
||||
|
@ -751,7 +586,6 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
qemu_mutex_unlock_iothread();
|
||||
return true;
|
||||
}
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) {
|
||||
/* Do nothing */
|
||||
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
|
||||
|
@ -780,14 +614,12 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
qemu_mutex_unlock_iothread();
|
||||
return true;
|
||||
}
|
||||
#endif /* !TARGET_I386 */
|
||||
#endif
|
||||
/* The target hook has 3 exit conditions:
|
||||
False when the interrupt isn't processed,
|
||||
True when it is, and we should restart on a new TB,
|
||||
and via longjmp via cpu_loop_exit. */
|
||||
else {
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (cc->tcg_ops->cpu_exec_interrupt &&
|
||||
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
if (need_replay_interrupt(interrupt_request)) {
|
||||
|
@ -806,7 +638,6 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
* reload the 'interrupt_request' value */
|
||||
interrupt_request = cpu->interrupt_request;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
||||
/* ensure that no TB jump will be modified as
|
||||
|
@ -864,7 +695,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
|||
/* Ensure global icount has gone forward */
|
||||
icount_update(cpu);
|
||||
/* Refill decrementer and continue execution. */
|
||||
insns_left = MIN(0xffff, cpu->icount_budget);
|
||||
insns_left = MIN(CF_COUNT_MASK, cpu->icount_budget);
|
||||
cpu_neg(cpu)->icount_decr.u16.low = insns_left;
|
||||
cpu->icount_extra = cpu->icount_budget - insns_left;
|
||||
|
||||
|
@ -873,9 +704,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
|||
* execute we need to ensure we find/generate a TB with exactly
|
||||
* insns_left instructions in it.
|
||||
*/
|
||||
if (insns_left > 0 && insns_left < tb->icount) {
|
||||
assert(insns_left <= CF_COUNT_MASK);
|
||||
assert(cpu->icount_extra == 0);
|
||||
if (!cpu->icount_extra && insns_left > 0 && insns_left < tb->icount) {
|
||||
cpu->cflags_next_tb = (tb->cflags & ~CF_COUNT_MASK) | insns_left;
|
||||
}
|
||||
#endif
|
||||
|
@ -885,6 +714,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
|||
|
||||
int cpu_exec(CPUState *cpu)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
int ret;
|
||||
SyncClocks sc = { 0 };
|
||||
|
||||
|
@ -918,18 +748,22 @@ int cpu_exec(CPUState *cpu)
|
|||
* that we support, but is still unfixed in clang:
|
||||
* https://bugs.llvm.org/show_bug.cgi?id=21183
|
||||
*
|
||||
* Reload an essential local variable here for those compilers.
|
||||
* Reload essential local variables here for those compilers.
|
||||
* Newer versions of gcc would complain about this code (-Wclobbered),
|
||||
* so we only perform the workaround for clang.
|
||||
*/
|
||||
cpu = current_cpu;
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
#else
|
||||
/* Non-buggy compilers preserve this; assert the correct value. */
|
||||
/*
|
||||
* Non-buggy compilers preserve these locals; assert that
|
||||
* they have the correct value.
|
||||
*/
|
||||
g_assert(cpu == current_cpu);
|
||||
g_assert(cc == CPU_GET_CLASS(cpu));
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
clear_helper_retaddr();
|
||||
tcg_debug_assert(!have_mmap_lock());
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
|
@ -946,60 +780,22 @@ int cpu_exec(CPUState *cpu)
|
|||
int tb_exit = 0;
|
||||
|
||||
while (!cpu_handle_interrupt(cpu, &last_tb)) {
|
||||
uint32_t cflags = cpu->cflags_next_tb;
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags, cflags;
|
||||
|
||||
cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags);
|
||||
|
||||
/*
|
||||
* When requested, use an exact setting for cflags for the next
|
||||
* execution. This is used for icount, precise smc, and stop-
|
||||
* after-access watchpoints. Since this request should never
|
||||
* have CF_INVALID set, -1 is a convenient invalid value that
|
||||
* does not require tcg headers for cpu_common_reset.
|
||||
*/
|
||||
cflags = cpu->cflags_next_tb;
|
||||
/* When requested, use an exact setting for cflags for the next
|
||||
execution. This is used for icount, precise smc, and stop-
|
||||
after-access watchpoints. Since this request should never
|
||||
have CF_INVALID set, -1 is a convenient invalid value that
|
||||
does not require tcg headers for cpu_common_reset. */
|
||||
if (cflags == -1) {
|
||||
cflags = curr_cflags(cpu);
|
||||
} else {
|
||||
cpu->cflags_next_tb = -1;
|
||||
}
|
||||
|
||||
if (check_for_breakpoints(cpu, pc, &cflags)) {
|
||||
break;
|
||||
}
|
||||
|
||||
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb == NULL) {
|
||||
mmap_lock();
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
||||
mmap_unlock();
|
||||
/*
|
||||
* We add the TB in the virtual pc hash table
|
||||
* for the fast lookup
|
||||
*/
|
||||
qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/*
|
||||
* We don't take care of direct jumps when address mapping
|
||||
* changes in system emulation. So it's not safe to make a
|
||||
* direct jump to a TB spanning two pages because the mapping
|
||||
* for the second page can change.
|
||||
*/
|
||||
if (tb->page_addr[1] != -1) {
|
||||
last_tb = NULL;
|
||||
}
|
||||
#endif
|
||||
/* See if we can patch the calling TB. */
|
||||
if (last_tb) {
|
||||
tb_add_jump(last_tb, tb_exit, tb);
|
||||
}
|
||||
|
||||
tb = tb_find(cpu, last_tb, tb_exit, cflags);
|
||||
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit);
|
||||
|
||||
/* Try to align the host and virtual clocks
|
||||
if the guest is in advance */
|
||||
align_clocks(&sc, cpu);
|
||||
|
@ -1042,83 +838,23 @@ void tcg_exec_unrealizefn(CPUState *cpu)
|
|||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
void dump_drift_info(GString *buf)
|
||||
void dump_drift_info(void)
|
||||
{
|
||||
if (!icount_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_string_append_printf(buf, "Host - Guest clock %"PRIi64" ms\n",
|
||||
(cpu_get_clock() - icount_get()) / SCALE_MS);
|
||||
qemu_printf("Host - Guest clock %"PRIi64" ms\n",
|
||||
(cpu_get_clock() - icount_get()) / SCALE_MS);
|
||||
if (icount_align_option) {
|
||||
g_string_append_printf(buf, "Max guest delay %"PRIi64" ms\n",
|
||||
-max_delay / SCALE_MS);
|
||||
g_string_append_printf(buf, "Max guest advance %"PRIi64" ms\n",
|
||||
max_advance / SCALE_MS);
|
||||
qemu_printf("Max guest delay %"PRIi64" ms\n",
|
||||
-max_delay / SCALE_MS);
|
||||
qemu_printf("Max guest advance %"PRIi64" ms\n",
|
||||
max_advance / SCALE_MS);
|
||||
} else {
|
||||
g_string_append_printf(buf, "Max guest delay NA\n");
|
||||
g_string_append_printf(buf, "Max guest advance NA\n");
|
||||
qemu_printf("Max guest delay NA\n");
|
||||
qemu_printf("Max guest advance NA\n");
|
||||
}
|
||||
}
|
||||
|
||||
HumanReadableText *qmp_x_query_jit(Error **errp)
|
||||
{
|
||||
g_autoptr(GString) buf = g_string_new("");
|
||||
|
||||
if (!tcg_enabled()) {
|
||||
error_setg(errp, "JIT information is only available with accel=tcg");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dump_exec_info(buf);
|
||||
dump_drift_info(buf);
|
||||
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
HumanReadableText *qmp_x_query_opcount(Error **errp)
|
||||
{
|
||||
g_autoptr(GString) buf = g_string_new("");
|
||||
|
||||
if (!tcg_enabled()) {
|
||||
error_setg(errp, "Opcode count information is only available with accel=tcg");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dump_opcount_info(buf);
|
||||
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
|
||||
int64_t dev_time;
|
||||
|
||||
HumanReadableText *qmp_x_query_profile(Error **errp)
|
||||
{
|
||||
g_autoptr(GString) buf = g_string_new("");
|
||||
static int64_t last_cpu_exec_time;
|
||||
int64_t cpu_exec_time;
|
||||
int64_t delta;
|
||||
|
||||
cpu_exec_time = tcg_cpu_exec_time();
|
||||
delta = cpu_exec_time - last_cpu_exec_time;
|
||||
|
||||
g_string_append_printf(buf, "async time %" PRId64 " (%0.3f)\n",
|
||||
dev_time, dev_time / (double)NANOSECONDS_PER_SECOND);
|
||||
g_string_append_printf(buf, "qemu time %" PRId64 " (%0.3f)\n",
|
||||
delta, delta / (double)NANOSECONDS_PER_SECOND);
|
||||
last_cpu_exec_time = cpu_exec_time;
|
||||
dev_time = 0;
|
||||
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
#else
|
||||
HumanReadableText *qmp_x_query_profile(Error **errp)
|
||||
{
|
||||
error_setg(errp, "Internal profiler not compiled");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,15 +0,0 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-machine.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "sysemu/tcg.h"
|
||||
|
||||
static void hmp_tcg_register(void)
|
||||
{
|
||||
monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
|
||||
monitor_register_hmp_info_hrt("opcount", qmp_x_query_opcount);
|
||||
}
|
||||
|
||||
type_init(hmp_tcg_register);
|
|
@ -16,7 +16,5 @@ TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc,
|
|||
int cflags);
|
||||
|
||||
void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr);
|
||||
void page_init(void);
|
||||
void tb_htable_init(void);
|
||||
|
||||
#endif /* ACCEL_TCG_INTERNAL_H */
|
||||
|
|
|
@ -1,307 +0,0 @@
|
|||
/*
|
||||
* Routines common to user and system emulation of load/store.
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
|
||||
return cpu_ldb_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int8_t)cpu_ldub_mmuidx_ra(env, addr, mmu_idx, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
|
||||
return cpu_ldw_be_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_lduw_be_mmuidx_ra(env, addr, mmu_idx, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
|
||||
return cpu_ldl_be_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
|
||||
return cpu_ldq_be_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
|
||||
return cpu_ldw_le_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
|
||||
return cpu_ldl_le_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
|
||||
return cpu_ldq_le_mmu(env, addr, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
|
||||
cpu_stb_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
|
||||
cpu_stw_be_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
|
||||
cpu_stl_be_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
|
||||
cpu_stq_be_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
|
||||
cpu_stw_le_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
|
||||
cpu_stl_le_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
|
||||
cpu_stq_le_mmu(env, addr, val, oi, ra);
|
||||
}
|
||||
|
||||
/*--------------------------*/
|
||||
|
||||
uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldub_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return (int8_t)cpu_ldub_data_ra(env, addr, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_lduw_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_lduw_be_data_ra(env, addr, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldl_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldq_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_lduw_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return (int16_t)cpu_lduw_le_data_ra(env, addr, ra);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldl_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
||||
{
|
||||
return cpu_ldq_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stb_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stb_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stw_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stl_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stq_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stw_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint32_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stl_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr addr,
|
||||
uint64_t val, uintptr_t ra)
|
||||
{
|
||||
cpu_stq_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
|
||||
/*--------------------------*/
|
||||
|
||||
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldub_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsb_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return (int8_t)cpu_ldub_data(env, addr);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_lduw_be_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return (int16_t)cpu_lduw_be_data(env, addr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldl_be_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldq_be_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_lduw_le_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return (int16_t)cpu_lduw_le_data(env, addr);
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldl_le_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr addr)
|
||||
{
|
||||
return cpu_ldq_le_data_ra(env, addr, 0);
|
||||
}
|
||||
|
||||
void cpu_stb_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stb_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stw_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stw_be_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stl_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stl_be_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stq_be_data(CPUArchState *env, abi_ptr addr, uint64_t val)
|
||||
{
|
||||
cpu_stq_be_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stw_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stw_le_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stl_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
||||
{
|
||||
cpu_stl_le_data_ra(env, addr, val, 0);
|
||||
}
|
||||
|
||||
void cpu_stq_le_data(CPUArchState *env, abi_ptr addr, uint64_t val)
|
||||
{
|
||||
cpu_stq_le_data_ra(env, addr, val, 0);
|
||||
}
|
|
@ -10,17 +10,13 @@ tcg_ss.add(files(
|
|||
))
|
||||
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
|
||||
tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c'))
|
||||
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c')])
|
||||
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c'), libdl])
|
||||
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
||||
|
||||
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
||||
'cputlb.c',
|
||||
'hmp.c',
|
||||
))
|
||||
|
||||
tcg_module_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
||||
'tcg-accel-ops.c',
|
||||
'tcg-accel-ops-mttcg.c',
|
||||
'tcg-accel-ops-icount.c',
|
||||
'tcg-accel-ops-rr.c',
|
||||
'tcg-accel-ops-rr.c'
|
||||
))
|
||||
|
|
|
@ -43,8 +43,10 @@
|
|||
* CPU's index into a TCG temp, since the first callback did it already.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "trace/mem.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/plugin-gen.h"
|
||||
#include "exec/translator.h"
|
||||
|
@ -159,10 +161,15 @@ static void gen_empty_mem_helper(void)
|
|||
tcg_temp_free_ptr(ptr);
|
||||
}
|
||||
|
||||
static void gen_plugin_cb_start(enum plugin_gen_from from,
|
||||
enum plugin_gen_cb type, unsigned wr)
|
||||
static inline
|
||||
void gen_plugin_cb_start(enum plugin_gen_from from,
|
||||
enum plugin_gen_cb type, unsigned wr)
|
||||
{
|
||||
TCGOp *op;
|
||||
|
||||
tcg_gen_plugin_cb_start(from, type, wr);
|
||||
op = tcg_last_op();
|
||||
QSIMPLEQ_INSERT_TAIL(&tcg_ctx->plugin_ops, op, plugin_link);
|
||||
}
|
||||
|
||||
static void gen_wrapped(enum plugin_gen_from from,
|
||||
|
@ -173,7 +180,7 @@ static void gen_wrapped(enum plugin_gen_from from,
|
|||
tcg_gen_plugin_cb_end();
|
||||
}
|
||||
|
||||
static void plugin_gen_empty_callback(enum plugin_gen_from from)
|
||||
static inline void plugin_gen_empty_callback(enum plugin_gen_from from)
|
||||
{
|
||||
switch (from) {
|
||||
case PLUGIN_GEN_AFTER_INSN:
|
||||
|
@ -206,9 +213,9 @@ static void gen_mem_wrapped(enum plugin_gen_cb type,
|
|||
const union mem_gen_fn *f, TCGv addr,
|
||||
uint32_t info, bool is_mem)
|
||||
{
|
||||
enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
|
||||
int wr = !!(info & TRACE_MEM_ST);
|
||||
|
||||
gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, rw);
|
||||
gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, wr);
|
||||
if (is_mem) {
|
||||
f->mem_fn(addr, info);
|
||||
} else {
|
||||
|
@ -379,7 +386,7 @@ static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op)
|
|||
}
|
||||
|
||||
static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func,
|
||||
void *func, int *cb_idx)
|
||||
void *func, unsigned tcg_flags, int *cb_idx)
|
||||
{
|
||||
/* copy all ops until the call */
|
||||
do {
|
||||
|
@ -406,7 +413,7 @@ static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func,
|
|||
tcg_debug_assert(i < MAX_OPC_PARAM_ARGS);
|
||||
}
|
||||
op->args[*cb_idx] = (uintptr_t)func;
|
||||
op->args[*cb_idx + 1] = (*begin_op)->args[*cb_idx + 1];
|
||||
op->args[*cb_idx + 1] = tcg_flags;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
@ -433,7 +440,7 @@ static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
|
|||
|
||||
/* call */
|
||||
op = copy_call(&begin_op, op, HELPER(plugin_vcpu_udata_cb),
|
||||
cb->f.vcpu_udata, cb_idx);
|
||||
cb->f.vcpu_udata, cb->tcg_flags, cb_idx);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
@ -484,7 +491,7 @@ static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
|
|||
if (type == PLUGIN_GEN_CB_MEM) {
|
||||
/* call */
|
||||
op = copy_call(&begin_op, op, HELPER(plugin_vcpu_mem_cb),
|
||||
cb->f.vcpu_udata, cb_idx);
|
||||
cb->f.vcpu_udata, cb->tcg_flags, cb_idx);
|
||||
}
|
||||
|
||||
return op;
|
||||
|
@ -507,8 +514,9 @@ static bool op_rw(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
|
|||
return !!(cb->rw & (w + 1));
|
||||
}
|
||||
|
||||
static void inject_cb_type(const GArray *cbs, TCGOp *begin_op,
|
||||
inject_fn inject, op_ok_fn ok)
|
||||
static inline
|
||||
void inject_cb_type(const GArray *cbs, TCGOp *begin_op, inject_fn inject,
|
||||
op_ok_fn ok)
|
||||
{
|
||||
TCGOp *end_op;
|
||||
TCGOp *op;
|
||||
|
@ -702,6 +710,62 @@ static void plugin_gen_disable_mem_helper(const struct qemu_plugin_tb *ptb,
|
|||
inject_mem_disable_helper(insn, begin_op);
|
||||
}
|
||||
|
||||
static void plugin_inject_cb(const struct qemu_plugin_tb *ptb, TCGOp *begin_op,
|
||||
int insn_idx)
|
||||
{
|
||||
enum plugin_gen_from from = begin_op->args[0];
|
||||
enum plugin_gen_cb type = begin_op->args[1];
|
||||
|
||||
switch (from) {
|
||||
case PLUGIN_GEN_FROM_TB:
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_UDATA:
|
||||
plugin_gen_tb_udata(ptb, begin_op);
|
||||
return;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_tb_inline(ptb, begin_op);
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
case PLUGIN_GEN_FROM_INSN:
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_UDATA:
|
||||
plugin_gen_insn_udata(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_insn_inline(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
case PLUGIN_GEN_ENABLE_MEM_HELPER:
|
||||
plugin_gen_enable_mem_helper(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
case PLUGIN_GEN_FROM_MEM:
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_MEM:
|
||||
plugin_gen_mem_regular(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_mem_inline(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
case PLUGIN_GEN_AFTER_INSN:
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_DISABLE_MEM_HELPER:
|
||||
plugin_gen_disable_mem_helper(ptb, begin_op, insn_idx);
|
||||
return;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* #define DEBUG_PLUGIN_GEN_OPS */
|
||||
static void pr_ops(void)
|
||||
{
|
||||
|
@ -759,95 +823,21 @@ static void pr_ops(void)
|
|||
static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
|
||||
{
|
||||
TCGOp *op;
|
||||
int insn_idx = -1;
|
||||
int insn_idx;
|
||||
|
||||
pr_ops();
|
||||
insn_idx = -1;
|
||||
QSIMPLEQ_FOREACH(op, &tcg_ctx->plugin_ops, plugin_link) {
|
||||
enum plugin_gen_from from = op->args[0];
|
||||
enum plugin_gen_cb type = op->args[1];
|
||||
|
||||
QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
|
||||
switch (op->opc) {
|
||||
case INDEX_op_insn_start:
|
||||
tcg_debug_assert(op->opc == INDEX_op_plugin_cb_start);
|
||||
/* ENABLE_MEM_HELPER is the first callback of an instruction */
|
||||
if (from == PLUGIN_GEN_FROM_INSN &&
|
||||
type == PLUGIN_GEN_ENABLE_MEM_HELPER) {
|
||||
insn_idx++;
|
||||
break;
|
||||
case INDEX_op_plugin_cb_start:
|
||||
{
|
||||
enum plugin_gen_from from = op->args[0];
|
||||
enum plugin_gen_cb type = op->args[1];
|
||||
|
||||
switch (from) {
|
||||
case PLUGIN_GEN_FROM_TB:
|
||||
{
|
||||
g_assert(insn_idx == -1);
|
||||
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_UDATA:
|
||||
plugin_gen_tb_udata(plugin_tb, op);
|
||||
break;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_tb_inline(plugin_tb, op);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PLUGIN_GEN_FROM_INSN:
|
||||
{
|
||||
g_assert(insn_idx >= 0);
|
||||
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_UDATA:
|
||||
plugin_gen_insn_udata(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_insn_inline(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
case PLUGIN_GEN_ENABLE_MEM_HELPER:
|
||||
plugin_gen_enable_mem_helper(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PLUGIN_GEN_FROM_MEM:
|
||||
{
|
||||
g_assert(insn_idx >= 0);
|
||||
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_CB_MEM:
|
||||
plugin_gen_mem_regular(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
case PLUGIN_GEN_CB_INLINE:
|
||||
plugin_gen_mem_inline(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PLUGIN_GEN_AFTER_INSN:
|
||||
{
|
||||
g_assert(insn_idx >= 0);
|
||||
|
||||
switch (type) {
|
||||
case PLUGIN_GEN_DISABLE_MEM_HELPER:
|
||||
plugin_gen_disable_mem_helper(plugin_tb, op, insn_idx);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* plugins don't care about any other ops */
|
||||
break;
|
||||
}
|
||||
plugin_inject_cb(plugin_tb, op, insn_idx);
|
||||
}
|
||||
pr_ops();
|
||||
}
|
||||
|
@ -860,6 +850,7 @@ bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_onl
|
|||
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) {
|
||||
ret = true;
|
||||
|
||||
QSIMPLEQ_INIT(&tcg_ctx->plugin_ops);
|
||||
ptb->vaddr = tb->pc;
|
||||
ptb->vaddr2 = -1;
|
||||
get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1);
|
||||
|
@ -876,8 +867,9 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
|
|||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||
struct qemu_plugin_insn *pinsn;
|
||||
|
||||
pinsn = qemu_plugin_tb_insn_get(ptb, db->pc_next);
|
||||
pinsn = qemu_plugin_tb_insn_get(ptb);
|
||||
tcg_ctx->plugin_insn = pinsn;
|
||||
pinsn->vaddr = db->pc_next;
|
||||
plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#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)
|
||||
/* Note: no TCG flags because those are overwritten later */
|
||||
DEF_HELPER_2(plugin_vcpu_udata_cb, void, i32, ptr)
|
||||
DEF_HELPER_4(plugin_vcpu_mem_cb, void, i32, i32, i64, ptr)
|
||||
#endif
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Internal structs that QEMU exports to TCG
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_TB_CONTEXT_H
|
||||
#define QEMU_TB_CONTEXT_H
|
||||
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/qht.h"
|
||||
|
||||
#define CODE_GEN_HTABLE_BITS 15
|
||||
#define CODE_GEN_HTABLE_SIZE (1 << CODE_GEN_HTABLE_BITS)
|
||||
|
||||
typedef struct TBContext TBContext;
|
||||
|
||||
struct TBContext {
|
||||
|
||||
struct qht htable;
|
||||
|
||||
/* statistics */
|
||||
unsigned tb_flush_count;
|
||||
unsigned tb_phys_invalidate_count;
|
||||
};
|
||||
|
||||
extern TBContext tb_ctx;
|
||||
|
||||
#endif
|
|
@ -30,6 +30,7 @@
|
|||
#include "qemu/main-loop.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
#include "tcg-accel-ops.h"
|
||||
#include "tcg-accel-ops-icount.h"
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "sysemu/tcg.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/boards.h"
|
||||
|
@ -36,26 +35,6 @@
|
|||
#include "tcg-accel-ops.h"
|
||||
#include "tcg-accel-ops-mttcg.h"
|
||||
|
||||
typedef struct MttcgForceRcuNotifier {
|
||||
Notifier notifier;
|
||||
CPUState *cpu;
|
||||
} MttcgForceRcuNotifier;
|
||||
|
||||
static void do_nothing(CPUState *cpu, run_on_cpu_data d)
|
||||
{
|
||||
}
|
||||
|
||||
static void mttcg_force_rcu(Notifier *notify, void *data)
|
||||
{
|
||||
CPUState *cpu = container_of(notify, MttcgForceRcuNotifier, notifier)->cpu;
|
||||
|
||||
/*
|
||||
* Called with rcu_registry_lock held, using async_run_on_cpu() ensures
|
||||
* that there are no deadlocks.
|
||||
*/
|
||||
async_run_on_cpu(cpu, do_nothing, RUN_ON_CPU_NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the multi-threaded case each vCPU has its own thread. The TLS
|
||||
* variable current_cpu can be used deep in the code to find the
|
||||
|
@ -64,16 +43,12 @@ static void mttcg_force_rcu(Notifier *notify, void *data)
|
|||
|
||||
static void *mttcg_cpu_thread_fn(void *arg)
|
||||
{
|
||||
MttcgForceRcuNotifier force_rcu;
|
||||
CPUState *cpu = arg;
|
||||
|
||||
assert(tcg_enabled());
|
||||
g_assert(!icount_enabled());
|
||||
|
||||
rcu_register_thread();
|
||||
force_rcu.notifier.notify = mttcg_force_rcu;
|
||||
force_rcu.cpu = cpu;
|
||||
rcu_add_force_rcu_notifier(&force_rcu.notifier);
|
||||
tcg_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
|
@ -125,7 +100,6 @@ static void *mttcg_cpu_thread_fn(void *arg)
|
|||
|
||||
tcg_cpus_destroy(cpu);
|
||||
qemu_mutex_unlock_iothread();
|
||||
rcu_remove_force_rcu_notifier(&force_rcu.notifier);
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
#include "sysemu/tcg.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
#include "tcg-accel-ops.h"
|
||||
#include "tcg-accel-ops-rr.h"
|
||||
|
@ -61,6 +61,8 @@ void rr_kick_vcpu_thread(CPUState *unused)
|
|||
static QEMUTimer *rr_kick_vcpu_timer;
|
||||
static CPUState *rr_current_cpu;
|
||||
|
||||
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
|
||||
|
||||
static inline int64_t rr_next_kick_time(void)
|
||||
{
|
||||
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
|
||||
|
@ -134,11 +136,6 @@ static void rr_deal_with_unplugged_cpus(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void rr_force_rcu(Notifier *notify, void *data)
|
||||
{
|
||||
rr_kick_next_cpu();
|
||||
}
|
||||
|
||||
/*
|
||||
* In the single-threaded case each vCPU is simulated in turn. If
|
||||
* there is more than a single vCPU we create a simple timer to kick
|
||||
|
@ -149,13 +146,10 @@ static void rr_force_rcu(Notifier *notify, void *data)
|
|||
|
||||
static void *rr_cpu_thread_fn(void *arg)
|
||||
{
|
||||
Notifier force_rcu;
|
||||
CPUState *cpu = arg;
|
||||
|
||||
assert(tcg_enabled());
|
||||
rcu_register_thread();
|
||||
force_rcu.notify = rr_force_rcu;
|
||||
rcu_add_force_rcu_notifier(&force_rcu);
|
||||
tcg_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
|
@ -264,7 +258,6 @@ static void *rr_cpu_thread_fn(void *arg)
|
|||
rr_deal_with_unplugged_cpus();
|
||||
}
|
||||
|
||||
rcu_remove_force_rcu_notifier(&force_rcu);
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "qemu/main-loop.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
#include "tcg-accel-ops.h"
|
||||
#include "tcg-accel-ops-mttcg.h"
|
||||
|
@ -124,7 +125,6 @@ static const TypeInfo tcg_accel_ops_type = {
|
|||
.class_init = tcg_accel_ops_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
module_obj(ACCEL_OPS_NAME("tcg"));
|
||||
|
||||
static void tcg_accel_ops_register_types(void)
|
||||
{
|
||||
|
|
|
@ -32,11 +32,6 @@
|
|||
#include "qemu/error-report.h"
|
||||
#include "qemu/accel.h"
|
||||
#include "qapi/qapi-builtin-visit.h"
|
||||
#include "qemu/units.h"
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "hw/boards.h"
|
||||
#endif
|
||||
#include "internal.h"
|
||||
|
||||
struct TCGState {
|
||||
AccelState parent_obj;
|
||||
|
@ -110,29 +105,22 @@ static void tcg_accel_instance_init(Object *obj)
|
|||
|
||||
bool mttcg_enabled;
|
||||
|
||||
static int tcg_init_machine(MachineState *ms)
|
||||
static int tcg_init(MachineState *ms)
|
||||
{
|
||||
TCGState *s = TCG_STATE(current_accel());
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
unsigned max_cpus = 1;
|
||||
#else
|
||||
unsigned max_cpus = ms->smp.max_cpus;
|
||||
#endif
|
||||
|
||||
tcg_allowed = true;
|
||||
tcg_exec_init(s->tb_size * 1024 * 1024, s->splitwx_enabled);
|
||||
mttcg_enabled = s->mttcg_enabled;
|
||||
|
||||
page_init();
|
||||
tb_htable_init();
|
||||
tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_cpus);
|
||||
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
/*
|
||||
* There's no guest base to take into account, so go ahead and
|
||||
* initialize the prologue now.
|
||||
* Initialize TCG regions only for softmmu.
|
||||
*
|
||||
* This needs to be done later for user mode, because the prologue
|
||||
* generation needs to be delayed so that GUEST_BASE is already set.
|
||||
*/
|
||||
tcg_prologue_init(tcg_ctx);
|
||||
#endif
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_region_init();
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -212,7 +200,7 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
|||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
ac->name = "tcg";
|
||||
ac->init_machine = tcg_init_machine;
|
||||
ac->init_machine = tcg_init;
|
||||
ac->allowed = &tcg_allowed;
|
||||
|
||||
object_class_property_add_str(oc, "thread",
|
||||
|
@ -238,7 +226,6 @@ static const TypeInfo tcg_accel_type = {
|
|||
.class_init = tcg_accel_class_init,
|
||||
.instance_size = sizeof(TCGState),
|
||||
};
|
||||
module_obj(TYPE_TCG_ACCEL);
|
||||
|
||||
static void register_accel_types(void)
|
||||
{
|
||||
|
|
|
@ -1073,8 +1073,9 @@ void HELPER(gvec_ssadd32)(void *d, void *a, void *b, uint32_t desc)
|
|||
for (i = 0; i < oprsz; i += sizeof(int32_t)) {
|
||||
int32_t ai = *(int32_t *)(a + i);
|
||||
int32_t bi = *(int32_t *)(b + i);
|
||||
int32_t di;
|
||||
if (sadd32_overflow(ai, bi, &di)) {
|
||||
int32_t di = ai + bi;
|
||||
if (((di ^ ai) &~ (ai ^ bi)) < 0) {
|
||||
/* Signed overflow. */
|
||||
di = (di < 0 ? INT32_MAX : INT32_MIN);
|
||||
}
|
||||
*(int32_t *)(d + i) = di;
|
||||
|
@ -1090,8 +1091,9 @@ void HELPER(gvec_ssadd64)(void *d, void *a, void *b, uint32_t desc)
|
|||
for (i = 0; i < oprsz; i += sizeof(int64_t)) {
|
||||
int64_t ai = *(int64_t *)(a + i);
|
||||
int64_t bi = *(int64_t *)(b + i);
|
||||
int64_t di;
|
||||
if (sadd64_overflow(ai, bi, &di)) {
|
||||
int64_t di = ai + bi;
|
||||
if (((di ^ ai) &~ (ai ^ bi)) < 0) {
|
||||
/* Signed overflow. */
|
||||
di = (di < 0 ? INT64_MAX : INT64_MIN);
|
||||
}
|
||||
*(int64_t *)(d + i) = di;
|
||||
|
@ -1141,8 +1143,9 @@ void HELPER(gvec_sssub32)(void *d, void *a, void *b, uint32_t desc)
|
|||
for (i = 0; i < oprsz; i += sizeof(int32_t)) {
|
||||
int32_t ai = *(int32_t *)(a + i);
|
||||
int32_t bi = *(int32_t *)(b + i);
|
||||
int32_t di;
|
||||
if (ssub32_overflow(ai, bi, &di)) {
|
||||
int32_t di = ai - bi;
|
||||
if (((di ^ ai) & (ai ^ bi)) < 0) {
|
||||
/* Signed overflow. */
|
||||
di = (di < 0 ? INT32_MAX : INT32_MIN);
|
||||
}
|
||||
*(int32_t *)(d + i) = di;
|
||||
|
@ -1158,8 +1161,9 @@ void HELPER(gvec_sssub64)(void *d, void *a, void *b, uint32_t desc)
|
|||
for (i = 0; i < oprsz; i += sizeof(int64_t)) {
|
||||
int64_t ai = *(int64_t *)(a + i);
|
||||
int64_t bi = *(int64_t *)(b + i);
|
||||
int64_t di;
|
||||
if (ssub64_overflow(ai, bi, &di)) {
|
||||
int64_t di = ai - bi;
|
||||
if (((di ^ ai) & (ai ^ bi)) < 0) {
|
||||
/* Signed overflow. */
|
||||
di = (di < 0 ? INT64_MAX : INT64_MIN);
|
||||
}
|
||||
*(int64_t *)(d + i) = di;
|
||||
|
@ -1205,8 +1209,8 @@ void HELPER(gvec_usadd32)(void *d, void *a, void *b, uint32_t desc)
|
|||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
uint32_t ai = *(uint32_t *)(a + i);
|
||||
uint32_t bi = *(uint32_t *)(b + i);
|
||||
uint32_t di;
|
||||
if (uadd32_overflow(ai, bi, &di)) {
|
||||
uint32_t di = ai + bi;
|
||||
if (di < ai) {
|
||||
di = UINT32_MAX;
|
||||
}
|
||||
*(uint32_t *)(d + i) = di;
|
||||
|
@ -1222,8 +1226,8 @@ void HELPER(gvec_usadd64)(void *d, void *a, void *b, uint32_t desc)
|
|||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
uint64_t ai = *(uint64_t *)(a + i);
|
||||
uint64_t bi = *(uint64_t *)(b + i);
|
||||
uint64_t di;
|
||||
if (uadd64_overflow(ai, bi, &di)) {
|
||||
uint64_t di = ai + bi;
|
||||
if (di < ai) {
|
||||
di = UINT64_MAX;
|
||||
}
|
||||
*(uint64_t *)(d + i) = di;
|
||||
|
@ -1269,8 +1273,8 @@ void HELPER(gvec_ussub32)(void *d, void *a, void *b, uint32_t desc)
|
|||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
uint32_t ai = *(uint32_t *)(a + i);
|
||||
uint32_t bi = *(uint32_t *)(b + i);
|
||||
uint32_t di;
|
||||
if (usub32_overflow(ai, bi, &di)) {
|
||||
uint32_t di = ai - bi;
|
||||
if (ai < bi) {
|
||||
di = 0;
|
||||
}
|
||||
*(uint32_t *)(d + i) = di;
|
||||
|
@ -1286,8 +1290,8 @@ void HELPER(gvec_ussub64)(void *d, void *a, void *b, uint32_t desc)
|
|||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
uint64_t ai = *(uint64_t *)(a + i);
|
||||
uint64_t bi = *(uint64_t *)(b + i);
|
||||
uint64_t di;
|
||||
if (usub64_overflow(ai, bi, &di)) {
|
||||
uint64_t di = ai - bi;
|
||||
if (ai < bi) {
|
||||
di = 0;
|
||||
}
|
||||
*(uint64_t *)(d + i) = di;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "disas/disas.h"
|
||||
#include "exec/log.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "exec/tb-lookup.h"
|
||||
|
||||
/* 32-bit helpers */
|
||||
|
||||
|
@ -144,6 +145,27 @@ uint64_t HELPER(ctpop_i64)(uint64_t arg)
|
|||
return ctpop64(arg);
|
||||
}
|
||||
|
||||
const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags;
|
||||
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
|
||||
tb = tb_lookup(cpu, pc, cs_base, flags, curr_cflags(cpu));
|
||||
if (tb == NULL) {
|
||||
return tcg_code_gen_epilogue;
|
||||
}
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, pc,
|
||||
"Chain %d: %p ["
|
||||
TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n",
|
||||
cpu->cpu_index, tb->tc.ptr, cs_base, pc, flags,
|
||||
lookup_symbol(pc));
|
||||
return tb->tc.ptr;
|
||||
}
|
||||
|
||||
void HELPER(exit_atomic)(CPUArchState *env)
|
||||
{
|
||||
cpu_loop_exit_atomic(env_cpu(env), GETPC());
|
||||
|
|
|
@ -39,6 +39,8 @@ DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env)
|
|||
DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr)
|
||||
#endif /* IN_HELPER_PROTO */
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
|
||||
DEF_HELPER_FLAGS_5(atomic_cmpxchgb, TCG_CALL_NO_WG,
|
||||
i32, env, tl, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_5(atomic_cmpxchgw_be, TCG_CALL_NO_WG,
|
||||
|
@ -86,6 +88,50 @@ DEF_HELPER_FLAGS_5(atomic_cmpxchgq_le, TCG_CALL_NO_WG,
|
|||
TCG_CALL_NO_WG, i32, env, tl, i32, i32)
|
||||
#endif /* CONFIG_ATOMIC64 */
|
||||
|
||||
#else
|
||||
|
||||
DEF_HELPER_FLAGS_4(atomic_cmpxchgb, TCG_CALL_NO_WG, i32, env, tl, i32, i32)
|
||||
DEF_HELPER_FLAGS_4(atomic_cmpxchgw_be, TCG_CALL_NO_WG, i32, env, tl, i32, i32)
|
||||
DEF_HELPER_FLAGS_4(atomic_cmpxchgw_le, TCG_CALL_NO_WG, i32, env, tl, i32, i32)
|
||||
DEF_HELPER_FLAGS_4(atomic_cmpxchgl_be, TCG_CALL_NO_WG, i32, env, tl, i32, i32)
|
||||
DEF_HELPER_FLAGS_4(atomic_cmpxchgl_le, TCG_CALL_NO_WG, i32, env, tl, i32, i32)
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
DEF_HELPER_FLAGS_4(atomic_cmpxchgq_be, TCG_CALL_NO_WG, i64, env, tl, i64, i64)
|
||||
DEF_HELPER_FLAGS_4(atomic_cmpxchgq_le, TCG_CALL_NO_WG, i64, env, tl, i64, i64)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATOMIC64
|
||||
#define GEN_ATOMIC_HELPERS(NAME) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), b), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), w_le), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), w_be), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), l_le), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), l_be), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), q_le), \
|
||||
TCG_CALL_NO_WG, i64, env, tl, i64) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), q_be), \
|
||||
TCG_CALL_NO_WG, i64, env, tl, i64)
|
||||
#else
|
||||
#define GEN_ATOMIC_HELPERS(NAME) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), b), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), w_le), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), w_be), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), l_le), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32) \
|
||||
DEF_HELPER_FLAGS_3(glue(glue(atomic_, NAME), l_be), \
|
||||
TCG_CALL_NO_WG, i32, env, tl, i32)
|
||||
#endif /* CONFIG_ATOMIC64 */
|
||||
|
||||
#endif /* CONFIG_SOFTMMU */
|
||||
|
||||
GEN_ATOMIC_HELPERS(fetch_add)
|
||||
GEN_ATOMIC_HELPERS(fetch_and)
|
||||
GEN_ATOMIC_HELPERS(fetch_or)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# See docs/devel/tracing.rst for syntax documentation.
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# TCG related tracing
|
||||
# cpu-exec.c
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
#define NO_CPU_IO_DEFS
|
||||
#include "cpu.h"
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
@ -46,8 +48,10 @@
|
|||
#endif
|
||||
|
||||
#include "exec/cputlb.h"
|
||||
#include "exec/tb-hash.h"
|
||||
#include "exec/translate-all.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
@ -57,8 +61,6 @@
|
|||
#include "sysemu/tcg.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
#include "tb-hash.h"
|
||||
#include "tb-context.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* #define DEBUG_TB_INVALIDATE */
|
||||
|
@ -218,6 +220,9 @@ static int v_l2_levels;
|
|||
|
||||
static void *l1_map[V_L1_MAX_SIZE];
|
||||
|
||||
/* code generation context */
|
||||
TCGContext tcg_init_ctx;
|
||||
__thread TCGContext *tcg_ctx;
|
||||
TBContext tb_ctx;
|
||||
|
||||
static void page_table_config_init(void)
|
||||
|
@ -240,6 +245,11 @@ static void page_table_config_init(void)
|
|||
assert(v_l2_levels >= 0);
|
||||
}
|
||||
|
||||
static void cpu_gen_init(void)
|
||||
{
|
||||
tcg_context_init(&tcg_init_ctx);
|
||||
}
|
||||
|
||||
/* Encode VAL as a signed leb128 sequence at P.
|
||||
Return P incremented past the encoded value. */
|
||||
static uint8_t *encode_sleb128(uint8_t *p, target_long val)
|
||||
|
@ -378,6 +388,11 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void tb_destroy(TranslationBlock *tb)
|
||||
{
|
||||
qemu_spin_destroy(&tb->jmp_lock);
|
||||
}
|
||||
|
||||
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
||||
{
|
||||
/*
|
||||
|
@ -400,7 +415,7 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
|||
return false;
|
||||
}
|
||||
|
||||
void page_init(void)
|
||||
static void page_init(void)
|
||||
{
|
||||
page_size_init();
|
||||
page_table_config_init();
|
||||
|
@ -885,6 +900,408 @@ static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
|
|||
}
|
||||
}
|
||||
|
||||
/* Minimum size of the code gen buffer. This number is randomly chosen,
|
||||
but not so small that we can't have a fair number of TB's live. */
|
||||
#define MIN_CODE_GEN_BUFFER_SIZE (1 * MiB)
|
||||
|
||||
/* Maximum size of the code gen buffer we'd like to use. Unless otherwise
|
||||
indicated, this is constrained by the range of direct branches on the
|
||||
host cpu, as used by the TCG implementation of goto_tb. */
|
||||
#if defined(__x86_64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
#elif defined(__sparc__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
#elif defined(__powerpc64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
#elif defined(__powerpc__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB)
|
||||
#elif defined(__aarch64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
#elif defined(__s390x__)
|
||||
/* We have a +- 4GB range on the branches; leave some slop. */
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB)
|
||||
#elif defined(__mips__)
|
||||
/* We have a 256MB branch region, but leave room to make sure the
|
||||
main executable is also within that region. */
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (128 * MiB)
|
||||
#else
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||
#endif
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32 * MiB)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* For user mode on smaller 32 bit systems we may run into trouble
|
||||
* allocating big chunks of data in the right place. On these systems
|
||||
* we utilise a static code generation buffer directly in the binary.
|
||||
*/
|
||||
#define USE_STATIC_CODE_GEN_BUFFER
|
||||
#endif
|
||||
#else /* TCG_TARGET_REG_BITS == 64 */
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* As user-mode emulation typically means running multiple instances
|
||||
* of the translator don't go too nuts with our default code gen
|
||||
* buffer lest we make things too hard for the OS.
|
||||
*/
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (128 * MiB)
|
||||
#else
|
||||
/*
|
||||
* We expect most system emulation to run one or two guests per host.
|
||||
* Users running large scale system emulation may want to tweak their
|
||||
* runtime setup via the tb-size control on the command line.
|
||||
*/
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (1 * GiB)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE \
|
||||
(DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \
|
||||
? DEFAULT_CODE_GEN_BUFFER_SIZE_1 : MAX_CODE_GEN_BUFFER_SIZE)
|
||||
|
||||
static size_t size_code_gen_buffer(size_t tb_size)
|
||||
{
|
||||
/* Size the buffer. */
|
||||
if (tb_size == 0) {
|
||||
size_t phys_mem = qemu_get_host_physmem();
|
||||
if (phys_mem == 0) {
|
||||
tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
|
||||
} else {
|
||||
tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, phys_mem / 8);
|
||||
}
|
||||
}
|
||||
if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
|
||||
tb_size = MIN_CODE_GEN_BUFFER_SIZE;
|
||||
}
|
||||
if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) {
|
||||
tb_size = MAX_CODE_GEN_BUFFER_SIZE;
|
||||
}
|
||||
return tb_size;
|
||||
}
|
||||
|
||||
#ifdef __mips__
|
||||
/* In order to use J and JAL within the code_gen_buffer, we require
|
||||
that the buffer not cross a 256MB boundary. */
|
||||
static inline bool cross_256mb(void *addr, size_t size)
|
||||
{
|
||||
return ((uintptr_t)addr ^ ((uintptr_t)addr + size)) & ~0x0ffffffful;
|
||||
}
|
||||
|
||||
/* We weren't able to allocate a buffer without crossing that boundary,
|
||||
so make do with the larger portion of the buffer that doesn't cross.
|
||||
Returns the new base of the buffer, and adjusts code_gen_buffer_size. */
|
||||
static inline void *split_cross_256mb(void *buf1, size_t size1)
|
||||
{
|
||||
void *buf2 = (void *)(((uintptr_t)buf1 + size1) & ~0x0ffffffful);
|
||||
size_t size2 = buf1 + size1 - buf2;
|
||||
|
||||
size1 = buf2 - buf1;
|
||||
if (size1 < size2) {
|
||||
size1 = size2;
|
||||
buf1 = buf2;
|
||||
}
|
||||
|
||||
tcg_ctx->code_gen_buffer_size = size1;
|
||||
return buf1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_STATIC_CODE_GEN_BUFFER
|
||||
static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
|
||||
__attribute__((aligned(CODE_GEN_ALIGN)));
|
||||
|
||||
static bool alloc_code_gen_buffer(size_t tb_size, int splitwx, Error **errp)
|
||||
{
|
||||
void *buf, *end;
|
||||
size_t size;
|
||||
|
||||
if (splitwx > 0) {
|
||||
error_setg(errp, "jit split-wx not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* page-align the beginning and end of the buffer */
|
||||
buf = static_code_gen_buffer;
|
||||
end = static_code_gen_buffer + sizeof(static_code_gen_buffer);
|
||||
buf = QEMU_ALIGN_PTR_UP(buf, qemu_real_host_page_size);
|
||||
end = QEMU_ALIGN_PTR_DOWN(end, qemu_real_host_page_size);
|
||||
|
||||
size = end - buf;
|
||||
|
||||
/* Honor a command-line option limiting the size of the buffer. */
|
||||
if (size > tb_size) {
|
||||
size = QEMU_ALIGN_DOWN(tb_size, qemu_real_host_page_size);
|
||||
}
|
||||
tcg_ctx->code_gen_buffer_size = size;
|
||||
|
||||
#ifdef __mips__
|
||||
if (cross_256mb(buf, size)) {
|
||||
buf = split_cross_256mb(buf, size);
|
||||
size = tcg_ctx->code_gen_buffer_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (qemu_mprotect_rwx(buf, size)) {
|
||||
error_setg_errno(errp, errno, "mprotect of jit buffer");
|
||||
return false;
|
||||
}
|
||||
qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
|
||||
|
||||
tcg_ctx->code_gen_buffer = buf;
|
||||
return true;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
|
||||
{
|
||||
void *buf;
|
||||
|
||||
if (splitwx > 0) {
|
||||
error_setg(errp, "jit split-wx not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
buf = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
if (buf == NULL) {
|
||||
error_setg_win32(errp, GetLastError(),
|
||||
"allocate %zu bytes for jit buffer", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
tcg_ctx->code_gen_buffer = buf;
|
||||
tcg_ctx->code_gen_buffer_size = size;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static bool alloc_code_gen_buffer_anon(size_t size, int prot,
|
||||
int flags, Error **errp)
|
||||
{
|
||||
void *buf;
|
||||
|
||||
buf = mmap(NULL, size, prot, flags, -1, 0);
|
||||
if (buf == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno,
|
||||
"allocate %zu bytes for jit buffer", size);
|
||||
return false;
|
||||
}
|
||||
tcg_ctx->code_gen_buffer_size = size;
|
||||
|
||||
#ifdef __mips__
|
||||
if (cross_256mb(buf, size)) {
|
||||
/*
|
||||
* Try again, with the original still mapped, to avoid re-acquiring
|
||||
* the same 256mb crossing.
|
||||
*/
|
||||
size_t size2;
|
||||
void *buf2 = mmap(NULL, size, prot, flags, -1, 0);
|
||||
switch ((int)(buf2 != MAP_FAILED)) {
|
||||
case 1:
|
||||
if (!cross_256mb(buf2, size)) {
|
||||
/* Success! Use the new buffer. */
|
||||
munmap(buf, size);
|
||||
break;
|
||||
}
|
||||
/* Failure. Work with what we had. */
|
||||
munmap(buf2, size);
|
||||
/* fallthru */
|
||||
default:
|
||||
/* Split the original buffer. Free the smaller half. */
|
||||
buf2 = split_cross_256mb(buf, size);
|
||||
size2 = tcg_ctx->code_gen_buffer_size;
|
||||
if (buf == buf2) {
|
||||
munmap(buf + size2, size - size2);
|
||||
} else {
|
||||
munmap(buf, size - size2);
|
||||
}
|
||||
size = size2;
|
||||
break;
|
||||
}
|
||||
buf = buf2;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Request large pages for the buffer. */
|
||||
qemu_madvise(buf, size, QEMU_MADV_HUGEPAGE);
|
||||
|
||||
tcg_ctx->code_gen_buffer = buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
#ifdef CONFIG_POSIX
|
||||
#include "qemu/memfd.h"
|
||||
|
||||
static bool alloc_code_gen_buffer_splitwx_memfd(size_t size, Error **errp)
|
||||
{
|
||||
void *buf_rw = NULL, *buf_rx = MAP_FAILED;
|
||||
int fd = -1;
|
||||
|
||||
#ifdef __mips__
|
||||
/* Find space for the RX mapping, vs the 256MiB regions. */
|
||||
if (!alloc_code_gen_buffer_anon(size, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS |
|
||||
MAP_NORESERVE, errp)) {
|
||||
return false;
|
||||
}
|
||||
/* The size of the mapping may have been adjusted. */
|
||||
size = tcg_ctx->code_gen_buffer_size;
|
||||
buf_rx = tcg_ctx->code_gen_buffer;
|
||||
#endif
|
||||
|
||||
buf_rw = qemu_memfd_alloc("tcg-jit", size, 0, &fd, errp);
|
||||
if (buf_rw == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef __mips__
|
||||
void *tmp = mmap(buf_rx, size, PROT_READ | PROT_EXEC,
|
||||
MAP_SHARED | MAP_FIXED, fd, 0);
|
||||
if (tmp != buf_rx) {
|
||||
goto fail_rx;
|
||||
}
|
||||
#else
|
||||
buf_rx = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
|
||||
if (buf_rx == MAP_FAILED) {
|
||||
goto fail_rx;
|
||||
}
|
||||
#endif
|
||||
|
||||
close(fd);
|
||||
tcg_ctx->code_gen_buffer = buf_rw;
|
||||
tcg_ctx->code_gen_buffer_size = size;
|
||||
tcg_splitwx_diff = buf_rx - buf_rw;
|
||||
|
||||
/* Request large pages for the buffer and the splitwx. */
|
||||
qemu_madvise(buf_rw, size, QEMU_MADV_HUGEPAGE);
|
||||
qemu_madvise(buf_rx, size, QEMU_MADV_HUGEPAGE);
|
||||
return true;
|
||||
|
||||
fail_rx:
|
||||
error_setg_errno(errp, errno, "failed to map shared memory for execute");
|
||||
fail:
|
||||
if (buf_rx != MAP_FAILED) {
|
||||
munmap(buf_rx, size);
|
||||
}
|
||||
if (buf_rw) {
|
||||
munmap(buf_rw, size);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_POSIX */
|
||||
|
||||
#ifdef CONFIG_DARWIN
|
||||
#include <mach/mach.h>
|
||||
|
||||
extern kern_return_t mach_vm_remap(vm_map_t target_task,
|
||||
mach_vm_address_t *target_address,
|
||||
mach_vm_size_t size,
|
||||
mach_vm_offset_t mask,
|
||||
int flags,
|
||||
vm_map_t src_task,
|
||||
mach_vm_address_t src_address,
|
||||
boolean_t copy,
|
||||
vm_prot_t *cur_protection,
|
||||
vm_prot_t *max_protection,
|
||||
vm_inherit_t inheritance);
|
||||
|
||||
static bool alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
|
||||
{
|
||||
kern_return_t ret;
|
||||
mach_vm_address_t buf_rw, buf_rx;
|
||||
vm_prot_t cur_prot, max_prot;
|
||||
|
||||
/* Map the read-write portion via normal anon memory. */
|
||||
if (!alloc_code_gen_buffer_anon(size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, errp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buf_rw = (mach_vm_address_t)tcg_ctx->code_gen_buffer;
|
||||
buf_rx = 0;
|
||||
ret = mach_vm_remap(mach_task_self(),
|
||||
&buf_rx,
|
||||
size,
|
||||
0,
|
||||
VM_FLAGS_ANYWHERE,
|
||||
mach_task_self(),
|
||||
buf_rw,
|
||||
false,
|
||||
&cur_prot,
|
||||
&max_prot,
|
||||
VM_INHERIT_NONE);
|
||||
if (ret != KERN_SUCCESS) {
|
||||
/* TODO: Convert "ret" to a human readable error message. */
|
||||
error_setg(errp, "vm_remap for jit splitwx failed");
|
||||
munmap((void *)buf_rw, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mprotect((void *)buf_rx, size, PROT_READ | PROT_EXEC) != 0) {
|
||||
error_setg_errno(errp, errno, "mprotect for jit splitwx");
|
||||
munmap((void *)buf_rx, size);
|
||||
munmap((void *)buf_rw, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
tcg_splitwx_diff = buf_rx - buf_rw;
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_DARWIN */
|
||||
#endif /* CONFIG_TCG_INTERPRETER */
|
||||
|
||||
static bool alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
|
||||
{
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
# ifdef CONFIG_DARWIN
|
||||
return alloc_code_gen_buffer_splitwx_vmremap(size, errp);
|
||||
# endif
|
||||
# ifdef CONFIG_POSIX
|
||||
return alloc_code_gen_buffer_splitwx_memfd(size, errp);
|
||||
# endif
|
||||
#endif
|
||||
error_setg(errp, "jit split-wx not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool alloc_code_gen_buffer(size_t size, int splitwx, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
int prot, flags;
|
||||
|
||||
if (splitwx) {
|
||||
if (alloc_code_gen_buffer_splitwx(size, errp)) {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* If splitwx force-on (1), fail;
|
||||
* if splitwx default-on (-1), fall through to splitwx off.
|
||||
*/
|
||||
if (splitwx > 0) {
|
||||
return false;
|
||||
}
|
||||
error_free_or_abort(errp);
|
||||
}
|
||||
|
||||
prot = PROT_READ | PROT_WRITE | PROT_EXEC;
|
||||
flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
#ifdef CONFIG_TCG_INTERPRETER
|
||||
/* The tcg interpreter does not need execute permission. */
|
||||
prot = PROT_READ | PROT_WRITE;
|
||||
#elif defined(CONFIG_DARWIN)
|
||||
/* Applicable to both iOS and macOS (Apple Silicon). */
|
||||
if (!splitwx) {
|
||||
flags |= MAP_JIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
return alloc_code_gen_buffer_anon(size, prot, flags, errp);
|
||||
}
|
||||
#endif /* USE_STATIC_CODE_GEN_BUFFER, WIN32, POSIX */
|
||||
|
||||
static bool tb_cmp(const void *ap, const void *bp)
|
||||
{
|
||||
const TranslationBlock *a = ap;
|
||||
|
@ -899,13 +1316,36 @@ static bool tb_cmp(const void *ap, const void *bp)
|
|||
a->page_addr[1] == b->page_addr[1];
|
||||
}
|
||||
|
||||
void tb_htable_init(void)
|
||||
static void tb_htable_init(void)
|
||||
{
|
||||
unsigned int mode = QHT_MODE_AUTO_RESIZE;
|
||||
|
||||
qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode);
|
||||
}
|
||||
|
||||
/* Must be called before using the QEMU cpus. 'tb_size' is the size
|
||||
(in bytes) allocated to the translation buffer. Zero means default
|
||||
size. */
|
||||
void tcg_exec_init(unsigned long tb_size, int splitwx)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
tcg_allowed = true;
|
||||
cpu_gen_init();
|
||||
page_init();
|
||||
tb_htable_init();
|
||||
|
||||
ok = alloc_code_gen_buffer(size_code_gen_buffer(tb_size),
|
||||
splitwx, &error_fatal);
|
||||
assert(ok);
|
||||
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
/* There's no guest base to take into account, so go ahead and
|
||||
initialize the prologue now. */
|
||||
tcg_prologue_init(tcg_ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* call with @p->lock held */
|
||||
static inline void invalidate_page_bitmap(PageDesc *p)
|
||||
{
|
||||
|
@ -1219,8 +1659,8 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
|
|||
/* suppress any remaining jumps to this TB */
|
||||
tb_jmp_unlink(tb);
|
||||
|
||||
qatomic_set(&tb_ctx.tb_phys_invalidate_count,
|
||||
tb_ctx.tb_phys_invalidate_count + 1);
|
||||
qatomic_set(&tcg_ctx->tb_phys_invalidate_count,
|
||||
tcg_ctx->tb_phys_invalidate_count + 1);
|
||||
}
|
||||
|
||||
static void tb_phys_invalidate__locked(TranslationBlock *tb)
|
||||
|
@ -1297,8 +1737,31 @@ static inline void tb_page_add(PageDesc *p, TranslationBlock *tb,
|
|||
invalidate_page_bitmap(p);
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* translator_loop() must have made all TB pages non-writable */
|
||||
assert(!(p->flags & PAGE_WRITE));
|
||||
if (p->flags & PAGE_WRITE) {
|
||||
target_ulong addr;
|
||||
PageDesc *p2;
|
||||
int prot;
|
||||
|
||||
/* force the host page as non writable (writes will have a
|
||||
page fault + mprotect overhead) */
|
||||
page_addr &= qemu_host_page_mask;
|
||||
prot = 0;
|
||||
for (addr = page_addr; addr < page_addr + qemu_host_page_size;
|
||||
addr += TARGET_PAGE_SIZE) {
|
||||
|
||||
p2 = page_find(addr >> TARGET_PAGE_BITS);
|
||||
if (!p2) {
|
||||
continue;
|
||||
}
|
||||
prot |= p2->flags;
|
||||
p2->flags &= ~PAGE_WRITE;
|
||||
}
|
||||
mprotect(g2h_untagged(page_addr), qemu_host_page_size,
|
||||
(prot & PAGE_BITS) & ~PAGE_WRITE);
|
||||
if (DEBUG_TB_INVALIDATE_GATE) {
|
||||
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* if some code is already present, then the pages are already
|
||||
protected. So we handle the case where only the first TB is
|
||||
|
@ -1405,9 +1868,14 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||
|
||||
max_insns = cflags & CF_COUNT_MASK;
|
||||
if (max_insns == 0) {
|
||||
max_insns = CF_COUNT_MASK;
|
||||
}
|
||||
if (max_insns > TCG_MAX_INSNS) {
|
||||
max_insns = TCG_MAX_INSNS;
|
||||
}
|
||||
QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS);
|
||||
if (cpu->singlestep_enabled || singlestep) {
|
||||
max_insns = 1;
|
||||
}
|
||||
|
||||
buffer_overflow:
|
||||
tb = tcg_tb_alloc(tcg_ctx);
|
||||
|
@ -1445,7 +1913,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||
|
||||
tcg_ctx->cpu = env_cpu(env);
|
||||
gen_intermediate_code(cpu, tb, max_insns);
|
||||
assert(tb->size != 0);
|
||||
tcg_ctx->cpu = NULL;
|
||||
max_insns = tb->icount;
|
||||
|
||||
|
@ -1576,15 +2043,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||
int i;
|
||||
qemu_log(" data: [size=%d]\n", data_size);
|
||||
for (i = 0; i < data_size / sizeof(tcg_target_ulong); i++) {
|
||||
if (sizeof(tcg_target_ulong) == 8) {
|
||||
qemu_log("0x%08" PRIxPTR ": .quad 0x%016" TCG_PRIlx "\n",
|
||||
(uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]);
|
||||
} else if (sizeof(tcg_target_ulong) == 4) {
|
||||
qemu_log("0x%08" PRIxPTR ": .long 0x%08" TCG_PRIlx "\n",
|
||||
(uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]);
|
||||
} else {
|
||||
qemu_build_not_reached();
|
||||
}
|
||||
qemu_log("0x%08" PRIxPTR ": .quad 0x%" TCG_PRIlx "\n",
|
||||
(uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]);
|
||||
}
|
||||
}
|
||||
qemu_log("\n");
|
||||
|
@ -1624,13 +2084,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||
return tb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert TB into the corresponding region tree before publishing it
|
||||
* through QHT. Otherwise rewinding happened in the TB might fail to
|
||||
* lookup itself using host PC.
|
||||
*/
|
||||
tcg_tb_insert(tb);
|
||||
|
||||
/* check next page if needed */
|
||||
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
|
||||
phys_page2 = -1;
|
||||
|
@ -1648,9 +2101,10 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||
|
||||
orig_aligned -= ROUND_UP(sizeof(*tb), qemu_icache_linesize);
|
||||
qatomic_set(&tcg_ctx->code_gen_ptr, (void *)orig_aligned);
|
||||
tcg_tb_remove(tb);
|
||||
tb_destroy(tb);
|
||||
return existing_tb;
|
||||
}
|
||||
tcg_tb_insert(tb);
|
||||
return tb;
|
||||
}
|
||||
|
||||
|
@ -1738,7 +2192,7 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
|||
if (current_tb_modified) {
|
||||
page_collection_unlock(pages);
|
||||
/* Force execution of one insn next time. */
|
||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
|
||||
cpu->cflags_next_tb = 1 | curr_cflags(cpu);
|
||||
mmap_unlock();
|
||||
cpu_loop_exit_noexc(cpu);
|
||||
}
|
||||
|
@ -1906,7 +2360,7 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc)
|
|||
#ifdef TARGET_HAS_PRECISE_SMC
|
||||
if (current_tb_modified) {
|
||||
/* Force execution of one insn next time. */
|
||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
|
||||
cpu->cflags_next_tb = 1 | curr_cflags(cpu);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -1991,7 +2445,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
|||
cpu_loop_exit_noexc(cpu);
|
||||
}
|
||||
|
||||
static void print_qht_statistics(struct qht_stats hst, GString *buf)
|
||||
static void print_qht_statistics(struct qht_stats hst)
|
||||
{
|
||||
uint32_t hgram_opts;
|
||||
size_t hgram_bins;
|
||||
|
@ -2000,11 +2454,9 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
|
|||
if (!hst.head_buckets) {
|
||||
return;
|
||||
}
|
||||
g_string_append_printf(buf, "TB hash buckets %zu/%zu "
|
||||
"(%0.2f%% head buckets used)\n",
|
||||
hst.used_head_buckets, hst.head_buckets,
|
||||
(double)hst.used_head_buckets /
|
||||
hst.head_buckets * 100);
|
||||
qemu_printf("TB hash buckets %zu/%zu (%0.2f%% head buckets used)\n",
|
||||
hst.used_head_buckets, hst.head_buckets,
|
||||
(double)hst.used_head_buckets / hst.head_buckets * 100);
|
||||
|
||||
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
|
||||
hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT;
|
||||
|
@ -2012,9 +2464,8 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
|
|||
hgram_opts |= QDIST_PR_NODECIMAL;
|
||||
}
|
||||
hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
|
||||
g_string_append_printf(buf, "TB hash occupancy %0.2f%% avg chain occ. "
|
||||
"Histogram: %s\n",
|
||||
qdist_avg(&hst.occupancy) * 100, hgram);
|
||||
qemu_printf("TB hash occupancy %0.2f%% avg chain occ. Histogram: %s\n",
|
||||
qdist_avg(&hst.occupancy) * 100, hgram);
|
||||
g_free(hgram);
|
||||
|
||||
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
|
||||
|
@ -2026,9 +2477,8 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
|
|||
hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
|
||||
}
|
||||
hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
|
||||
g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. "
|
||||
"Histogram: %s\n",
|
||||
qdist_avg(&hst.chain), hgram);
|
||||
qemu_printf("TB hash avg chain %0.3f buckets. Histogram: %s\n",
|
||||
qdist_avg(&hst.chain), hgram);
|
||||
g_free(hgram);
|
||||
}
|
||||
|
||||
|
@ -2065,7 +2515,7 @@ static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
|
|||
return false;
|
||||
}
|
||||
|
||||
void dump_exec_info(GString *buf)
|
||||
void dump_exec_info(void)
|
||||
{
|
||||
struct tb_tree_stats tst = {};
|
||||
struct qht_stats hst;
|
||||
|
@ -2074,53 +2524,49 @@ void dump_exec_info(GString *buf)
|
|||
tcg_tb_foreach(tb_tree_stats_iter, &tst);
|
||||
nb_tbs = tst.nb_tbs;
|
||||
/* XXX: avoid using doubles ? */
|
||||
g_string_append_printf(buf, "Translation buffer state:\n");
|
||||
qemu_printf("Translation buffer state:\n");
|
||||
/*
|
||||
* Report total code size including the padding and TB structs;
|
||||
* otherwise users might think "-accel tcg,tb-size" is not honoured.
|
||||
* For avg host size we use the precise numbers from tb_tree_stats though.
|
||||
*/
|
||||
g_string_append_printf(buf, "gen code size %zu/%zu\n",
|
||||
tcg_code_size(), tcg_code_capacity());
|
||||
g_string_append_printf(buf, "TB count %zu\n", nb_tbs);
|
||||
g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n",
|
||||
nb_tbs ? tst.target_size / nb_tbs : 0,
|
||||
tst.max_target_size);
|
||||
g_string_append_printf(buf, "TB avg host size %zu bytes "
|
||||
"(expansion ratio: %0.1f)\n",
|
||||
nb_tbs ? tst.host_size / nb_tbs : 0,
|
||||
tst.target_size ?
|
||||
(double)tst.host_size / tst.target_size : 0);
|
||||
g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
|
||||
tst.cross_page,
|
||||
nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
|
||||
g_string_append_printf(buf, "direct jump count %zu (%zu%%) "
|
||||
"(2 jumps=%zu %zu%%)\n",
|
||||
tst.direct_jmp_count,
|
||||
nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
|
||||
tst.direct_jmp2_count,
|
||||
nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
|
||||
qemu_printf("gen code size %zu/%zu\n",
|
||||
tcg_code_size(), tcg_code_capacity());
|
||||
qemu_printf("TB count %zu\n", nb_tbs);
|
||||
qemu_printf("TB avg target size %zu max=%zu bytes\n",
|
||||
nb_tbs ? tst.target_size / nb_tbs : 0,
|
||||
tst.max_target_size);
|
||||
qemu_printf("TB avg host size %zu bytes (expansion ratio: %0.1f)\n",
|
||||
nb_tbs ? tst.host_size / nb_tbs : 0,
|
||||
tst.target_size ? (double)tst.host_size / tst.target_size : 0);
|
||||
qemu_printf("cross page TB count %zu (%zu%%)\n", tst.cross_page,
|
||||
nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
|
||||
qemu_printf("direct jump count %zu (%zu%%) (2 jumps=%zu %zu%%)\n",
|
||||
tst.direct_jmp_count,
|
||||
nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
|
||||
tst.direct_jmp2_count,
|
||||
nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
|
||||
|
||||
qht_statistics_init(&tb_ctx.htable, &hst);
|
||||
print_qht_statistics(hst, buf);
|
||||
print_qht_statistics(hst);
|
||||
qht_statistics_destroy(&hst);
|
||||
|
||||
g_string_append_printf(buf, "\nStatistics:\n");
|
||||
g_string_append_printf(buf, "TB flush count %u\n",
|
||||
qatomic_read(&tb_ctx.tb_flush_count));
|
||||
g_string_append_printf(buf, "TB invalidate count %u\n",
|
||||
qatomic_read(&tb_ctx.tb_phys_invalidate_count));
|
||||
qemu_printf("\nStatistics:\n");
|
||||
qemu_printf("TB flush count %u\n",
|
||||
qatomic_read(&tb_ctx.tb_flush_count));
|
||||
qemu_printf("TB invalidate count %zu\n",
|
||||
tcg_tb_phys_invalidate_count());
|
||||
|
||||
tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
|
||||
g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full);
|
||||
g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
|
||||
g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide);
|
||||
tcg_dump_info(buf);
|
||||
qemu_printf("TLB full flushes %zu\n", flush_full);
|
||||
qemu_printf("TLB partial flushes %zu\n", flush_part);
|
||||
qemu_printf("TLB elided flushes %zu\n", flush_elide);
|
||||
tcg_dump_info();
|
||||
}
|
||||
|
||||
void dump_opcount_info(GString *buf)
|
||||
void dump_opcount_info(void)
|
||||
{
|
||||
tcg_dump_op_count(buf);
|
||||
tcg_dump_op_count();
|
||||
}
|
||||
|
||||
#else /* CONFIG_USER_ONLY */
|
||||
|
@ -2379,38 +2825,6 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void page_protect(tb_page_addr_t page_addr)
|
||||
{
|
||||
target_ulong addr;
|
||||
PageDesc *p;
|
||||
int prot;
|
||||
|
||||
p = page_find(page_addr >> TARGET_PAGE_BITS);
|
||||
if (p && (p->flags & PAGE_WRITE)) {
|
||||
/*
|
||||
* Force the host page as non writable (writes will have a page fault +
|
||||
* mprotect overhead).
|
||||
*/
|
||||
page_addr &= qemu_host_page_mask;
|
||||
prot = 0;
|
||||
for (addr = page_addr; addr < page_addr + qemu_host_page_size;
|
||||
addr += TARGET_PAGE_SIZE) {
|
||||
|
||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
||||
if (!p) {
|
||||
continue;
|
||||
}
|
||||
prot |= p->flags;
|
||||
p->flags &= ~PAGE_WRITE;
|
||||
}
|
||||
mprotect(g2h_untagged(page_addr), qemu_host_page_size,
|
||||
(prot & PAGE_BITS) & ~PAGE_WRITE);
|
||||
if (DEBUG_TB_INVALIDATE_GATE) {
|
||||
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* called from signal handler: invalidate the code and unprotect the
|
||||
* page. Return 0 if the fault was not handled, 1 if it was handled,
|
||||
* and 2 if it was handled but the caller must cause the TB to be
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
@ -31,30 +32,10 @@ void translator_loop_temp_check(DisasContextBase *db)
|
|||
}
|
||||
}
|
||||
|
||||
bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
|
||||
{
|
||||
/* Suppress goto_tb if requested. */
|
||||
if (tb_cflags(db->tb) & CF_NO_GOTO_TB) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check for the dest on the same page as the start of the TB. */
|
||||
return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
|
||||
}
|
||||
|
||||
static inline void translator_page_protect(DisasContextBase *dcbase,
|
||||
target_ulong pc)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
dcbase->page_protect_end = pc | ~TARGET_PAGE_MASK;
|
||||
page_protect(pc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
CPUState *cpu, TranslationBlock *tb, int max_insns)
|
||||
{
|
||||
uint32_t cflags = tb_cflags(tb);
|
||||
int bp_insn = 0;
|
||||
bool plugin_enabled;
|
||||
|
||||
/* Initialize DisasContext */
|
||||
|
@ -64,8 +45,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
|||
db->is_jmp = DISAS_NEXT;
|
||||
db->num_insns = 0;
|
||||
db->max_insns = max_insns;
|
||||
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
|
||||
translator_page_protect(db, db->pc_next);
|
||||
db->singlestep_enabled = cpu->singlestep_enabled;
|
||||
|
||||
ops->init_disas_context(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
@ -78,7 +58,8 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
|||
ops->tb_start(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, tb, cflags & CF_MEMI_ONLY);
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, tb,
|
||||
tb_cflags(db->tb) & CF_MEMI_ONLY);
|
||||
|
||||
while (true) {
|
||||
db->num_insns++;
|
||||
|
@ -89,17 +70,39 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
|||
plugin_gen_insn_start(cpu, db);
|
||||
}
|
||||
|
||||
/* Pass breakpoint hits to target for further processing */
|
||||
if (!db->singlestep_enabled
|
||||
&& unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
|
||||
CPUBreakpoint *bp;
|
||||
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
|
||||
if (bp->pc == db->pc_next) {
|
||||
if (ops->breakpoint_check(db, cpu, bp)) {
|
||||
bp_insn = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* The breakpoint_check hook may use DISAS_TOO_MANY to indicate
|
||||
that only one more instruction is to be executed. Otherwise
|
||||
it should use DISAS_NORETURN when generating an exception,
|
||||
but may use a DISAS_TARGET_* value for Something Else. */
|
||||
if (db->is_jmp > DISAS_TOO_MANY) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disassemble one instruction. The translate_insn hook should
|
||||
update db->pc_next and db->is_jmp to indicate what should be
|
||||
done next -- either exiting this loop or locate the start of
|
||||
the next instruction. */
|
||||
if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
|
||||
if (db->num_insns == db->max_insns
|
||||
&& (tb_cflags(db->tb) & CF_LAST_IO)) {
|
||||
/* Accept I/O on the last instruction. */
|
||||
gen_io_start();
|
||||
ops->translate_insn(db, cpu);
|
||||
} else {
|
||||
/* we should only see CF_MEMI_ONLY for io_recompile */
|
||||
tcg_debug_assert(!(cflags & CF_MEMI_ONLY));
|
||||
tcg_debug_assert(!(tb_cflags(db->tb) & CF_MEMI_ONLY));
|
||||
ops->translate_insn(db, cpu);
|
||||
}
|
||||
|
||||
|
@ -126,7 +129,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
|||
|
||||
/* Emit code to exit the TB, as indicated by db->is_jmp. */
|
||||
ops->tb_stop(db, cpu);
|
||||
gen_tb_end(db->tb, db->num_insns);
|
||||
gen_tb_end(db->tb, db->num_insns - bp_insn);
|
||||
|
||||
if (plugin_enabled) {
|
||||
plugin_gen_tb_end(cpu);
|
||||
|
@ -147,32 +150,3 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void translator_maybe_page_protect(DisasContextBase *dcbase,
|
||||
target_ulong pc, size_t len)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
target_ulong end = pc + len - 1;
|
||||
|
||||
if (end > dcbase->page_protect_end) {
|
||||
translator_page_protect(dcbase, end);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \
|
||||
type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
|
||||
abi_ptr pc, bool do_swap) \
|
||||
{ \
|
||||
translator_maybe_page_protect(dcbase, pc, sizeof(type)); \
|
||||
type ret = load_fn(env, pc); \
|
||||
if (do_swap) { \
|
||||
ret = swap_fn(ret); \
|
||||
} \
|
||||
plugin_insn_append(pc, &ret, sizeof(ret)); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
|
||||
|
||||
#undef GEN_TRANSLATOR_LD
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
bool enable_cpu_pm = false;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -34,8 +34,6 @@
|
|||
#define AUDIO_CAP "alsa"
|
||||
#include "audio_int.h"
|
||||
|
||||
#define DEBUG_ALSA 0
|
||||
|
||||
struct pollhlp {
|
||||
snd_pcm_t *handle;
|
||||
struct pollfd *pfds;
|
||||
|
@ -589,12 +587,16 @@ static int alsa_open(bool in, struct alsa_params_req *req,
|
|||
|
||||
*handlep = handle;
|
||||
|
||||
if (DEBUG_ALSA || obtfmt != req->fmt ||
|
||||
obt->nchannels != req->nchannels || obt->freq != req->freq) {
|
||||
if (obtfmt != req->fmt ||
|
||||
obt->nchannels != req->nchannels ||
|
||||
obt->freq != req->freq) {
|
||||
dolog ("Audio parameters for %s\n", typ);
|
||||
alsa_dump_info(req, obt, obtfmt, apdo);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
alsa_dump_info(req, obt, obtfmt, apdo);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "qapi/qapi-visit-audio.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu-common.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
|
@ -705,7 +704,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
|||
|
||||
if (live == hwsamples) {
|
||||
#ifdef DEBUG_OUT
|
||||
dolog ("%s is full %zu\n", sw->name, live);
|
||||
dolog ("%s is full %d\n", sw->name, live);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -995,7 +994,7 @@ static size_t audio_get_avail (SWVoiceIn *sw)
|
|||
}
|
||||
|
||||
ldebug (
|
||||
"%s: get_avail live %zu ret %" PRId64 "\n",
|
||||
"%s: get_avail live %d ret %" PRId64 "\n",
|
||||
SW_NAME (sw),
|
||||
live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame
|
||||
);
|
||||
|
@ -1022,7 +1021,7 @@ static size_t audio_get_free(SWVoiceOut *sw)
|
|||
dead = sw->hw->mix_buf->size - live;
|
||||
|
||||
#ifdef DEBUG_OUT
|
||||
dolog ("%s: get_free live %zu dead %zu ret %" PRId64 "\n",
|
||||
dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
|
||||
SW_NAME (sw),
|
||||
live, dead, (((int64_t) dead << 32) / sw->ratio) *
|
||||
sw->info.bytes_per_frame);
|
||||
|
@ -2000,7 +1999,6 @@ void audio_create_pdos(Audiodev *dev)
|
|||
CASE(NONE, none, );
|
||||
CASE(ALSA, alsa, Alsa);
|
||||
CASE(COREAUDIO, coreaudio, Coreaudio);
|
||||
CASE(DBUS, dbus, );
|
||||
CASE(DSOUND, dsound, );
|
||||
CASE(JACK, jack, Jack);
|
||||
CASE(OSS, oss, Oss);
|
||||
|
@ -2184,14 +2182,6 @@ const char *audio_get_id(QEMUSoundCard *card)
|
|||
}
|
||||
}
|
||||
|
||||
const char *audio_application_name(void)
|
||||
{
|
||||
const char *vm_name;
|
||||
|
||||
vm_name = qemu_get_vm_name();
|
||||
return vm_name ? vm_name : "qemu";
|
||||
}
|
||||
|
||||
void audio_rate_start(RateCtl *rate)
|
||||
{
|
||||
memset(rate, 0, sizeof(RateCtl));
|
||||
|
|
|
@ -31,10 +31,6 @@
|
|||
#endif
|
||||
#include "mixeng.h"
|
||||
|
||||
#ifdef CONFIG_GIO
|
||||
#include <gio/gio.h>
|
||||
#endif
|
||||
|
||||
struct audio_pcm_ops;
|
||||
|
||||
struct audio_callback {
|
||||
|
@ -144,9 +140,6 @@ struct audio_driver {
|
|||
const char *descr;
|
||||
void *(*init) (Audiodev *);
|
||||
void (*fini) (void *);
|
||||
#ifdef CONFIG_GIO
|
||||
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager);
|
||||
#endif
|
||||
struct audio_pcm_ops *pcm_ops;
|
||||
int can_be_default;
|
||||
int max_voices_out;
|
||||
|
@ -250,8 +243,6 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size);
|
|||
|
||||
void audio_run(AudioState *s, const char *msg);
|
||||
|
||||
const char *audio_application_name(void);
|
||||
|
||||
typedef struct RateCtl {
|
||||
int64_t start_ticks;
|
||||
int64_t bytes_sent;
|
||||
|
|
|
@ -327,8 +327,6 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
|||
case AUDIODEV_DRIVER_COREAUDIO:
|
||||
return qapi_AudiodevCoreaudioPerDirectionOptions_base(
|
||||
dev->u.coreaudio.TYPE);
|
||||
case AUDIODEV_DRIVER_DBUS:
|
||||
return dev->u.dbus.TYPE;
|
||||
case AUDIODEV_DRIVER_DSOUND:
|
||||
return dev->u.dsound.TYPE;
|
||||
case AUDIODEV_DRIVER_JACK:
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <pthread.h> /* pthread_X */
|
||||
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/module.h"
|
||||
#include "audio.h"
|
||||
|
||||
|
@ -35,11 +34,12 @@
|
|||
|
||||
typedef struct coreaudioVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
pthread_mutex_t buf_mutex;
|
||||
pthread_mutex_t mutex;
|
||||
AudioDeviceID outputDeviceID;
|
||||
int frameSizeSetting;
|
||||
uint32_t bufferCount;
|
||||
UInt32 audioDevicePropertyBufferFrameSize;
|
||||
AudioStreamBasicDescription outputStreamBasicDescription;
|
||||
AudioDeviceIOProcID ioprocid;
|
||||
bool enabled;
|
||||
} coreaudioVoiceOut;
|
||||
|
@ -114,6 +114,24 @@ static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
|
|||
framesize);
|
||||
}
|
||||
|
||||
static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
|
||||
AudioStreamBasicDescription *d)
|
||||
{
|
||||
UInt32 size = sizeof(*d);
|
||||
AudioObjectPropertyAddress addr = {
|
||||
kAudioDevicePropertyStreamFormat,
|
||||
kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
return AudioObjectGetPropertyData(id,
|
||||
&addr,
|
||||
0,
|
||||
NULL,
|
||||
&size,
|
||||
d);
|
||||
}
|
||||
|
||||
static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
|
||||
AudioStreamBasicDescription *d)
|
||||
{
|
||||
|
@ -242,11 +260,11 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
|
|||
#define coreaudio_playback_logerr(status, ...) \
|
||||
coreaudio_logerr2(status, "playback", __VA_ARGS__)
|
||||
|
||||
static int coreaudio_buf_lock (coreaudioVoiceOut *core, const char *fn_name)
|
||||
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock (&core->buf_mutex);
|
||||
err = pthread_mutex_lock (&core->mutex);
|
||||
if (err) {
|
||||
dolog ("Could not lock voice for %s\nReason: %s\n",
|
||||
fn_name, strerror (err));
|
||||
|
@ -255,11 +273,11 @@ static int coreaudio_buf_lock (coreaudioVoiceOut *core, const char *fn_name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int coreaudio_buf_unlock (coreaudioVoiceOut *core, const char *fn_name)
|
||||
static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_unlock (&core->buf_mutex);
|
||||
err = pthread_mutex_unlock (&core->mutex);
|
||||
if (err) {
|
||||
dolog ("Could not unlock voice for %s\nReason: %s\n",
|
||||
fn_name, strerror (err));
|
||||
|
@ -274,13 +292,13 @@ static int coreaudio_buf_unlock (coreaudioVoiceOut *core, const char *fn_name)
|
|||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
|
||||
ret_type ret; \
|
||||
\
|
||||
if (coreaudio_buf_lock(core, "coreaudio_" #name)) { \
|
||||
if (coreaudio_lock(core, "coreaudio_" #name)) { \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
ret = glue(audio_generic_, name)args; \
|
||||
\
|
||||
coreaudio_buf_unlock(core, "coreaudio_" #name); \
|
||||
coreaudio_unlock(core, "coreaudio_" #name); \
|
||||
return ret; \
|
||||
}
|
||||
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||
|
@ -292,10 +310,7 @@ COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
|
|||
(hw, buf, size))
|
||||
#undef COREAUDIO_WRAPPER_FUNC
|
||||
|
||||
/*
|
||||
* callback to feed audiooutput buffer. called without iothread lock.
|
||||
* allowed to lock "buf_mutex", but disallowed to have any other locks.
|
||||
*/
|
||||
/* callback to feed audiooutput buffer */
|
||||
static OSStatus audioDeviceIOProc(
|
||||
AudioDeviceID inDevice,
|
||||
const AudioTimeStamp *inNow,
|
||||
|
@ -311,13 +326,13 @@ static OSStatus audioDeviceIOProc(
|
|||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
|
||||
size_t len;
|
||||
|
||||
if (coreaudio_buf_lock (core, "audioDeviceIOProc")) {
|
||||
if (coreaudio_lock (core, "audioDeviceIOProc")) {
|
||||
inInputTime = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inDevice != core->outputDeviceID) {
|
||||
coreaudio_buf_unlock (core, "audioDeviceIOProc(old device)");
|
||||
coreaudio_unlock (core, "audioDeviceIOProc(old device)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -327,7 +342,7 @@ static OSStatus audioDeviceIOProc(
|
|||
/* if there are not enough samples, set signal and return */
|
||||
if (pending_frames < frameCount) {
|
||||
inInputTime = 0;
|
||||
coreaudio_buf_unlock (core, "audioDeviceIOProc(empty)");
|
||||
coreaudio_unlock (core, "audioDeviceIOProc(empty)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -349,7 +364,7 @@ static OSStatus audioDeviceIOProc(
|
|||
out += write_len;
|
||||
}
|
||||
|
||||
coreaudio_buf_unlock (core, "audioDeviceIOProc");
|
||||
coreaudio_unlock (core, "audioDeviceIOProc");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -358,17 +373,6 @@ static OSStatus init_out_device(coreaudioVoiceOut *core)
|
|||
OSStatus status;
|
||||
AudioValueRange frameRange;
|
||||
|
||||
AudioStreamBasicDescription streamBasicDescription = {
|
||||
.mBitsPerChannel = core->hw.info.bits,
|
||||
.mBytesPerFrame = core->hw.info.bytes_per_frame,
|
||||
.mBytesPerPacket = core->hw.info.bytes_per_frame,
|
||||
.mChannelsPerFrame = core->hw.info.nchannels,
|
||||
.mFormatFlags = kLinearPCMFormatFlagIsFloat,
|
||||
.mFormatID = kAudioFormatLinearPCM,
|
||||
.mFramesPerPacket = 1,
|
||||
.mSampleRate = core->hw.info.freq
|
||||
};
|
||||
|
||||
status = coreaudio_get_voice(&core->outputDeviceID);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr (status,
|
||||
|
@ -428,30 +432,34 @@ static OSStatus init_out_device(coreaudioVoiceOut *core)
|
|||
}
|
||||
core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
|
||||
|
||||
/* get StreamFormat */
|
||||
status = coreaudio_get_streamformat(core->outputDeviceID,
|
||||
&core->outputStreamBasicDescription);
|
||||
if (status == kAudioHardwareBadObjectError) {
|
||||
return 0;
|
||||
}
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not get Device Stream properties\n");
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* set Samplerate */
|
||||
status = coreaudio_set_streamformat(core->outputDeviceID,
|
||||
&streamBasicDescription);
|
||||
&core->outputStreamBasicDescription);
|
||||
if (status == kAudioHardwareBadObjectError) {
|
||||
return 0;
|
||||
}
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not set samplerate %lf\n",
|
||||
streamBasicDescription.mSampleRate);
|
||||
core->outputStreamBasicDescription.mSampleRate);
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* set Callback.
|
||||
*
|
||||
* On macOS 11.3.1, Core Audio calls AudioDeviceIOProc after calling an
|
||||
* internal function named HALB_Mutex::Lock(), which locks a mutex in
|
||||
* HALB_IOThread::Entry(void*). HALB_Mutex::Lock() is also called in
|
||||
* AudioObjectGetPropertyData, which is called by coreaudio driver.
|
||||
* Therefore, the specified callback must be designed to avoid a deadlock
|
||||
* with the callers of AudioObjectGetPropertyData.
|
||||
*/
|
||||
/* set Callback */
|
||||
core->ioprocid = NULL;
|
||||
status = AudioDeviceCreateIOProcID(core->outputDeviceID,
|
||||
audioDeviceIOProc,
|
||||
|
@ -534,7 +542,6 @@ static void update_device_playback_state(coreaudioVoiceOut *core)
|
|||
}
|
||||
}
|
||||
|
||||
/* called without iothread lock. */
|
||||
static OSStatus handle_voice_change(
|
||||
AudioObjectID in_object_id,
|
||||
UInt32 in_number_addresses,
|
||||
|
@ -544,7 +551,9 @@ static OSStatus handle_voice_change(
|
|||
OSStatus status;
|
||||
coreaudioVoiceOut *core = in_client_data;
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
if (coreaudio_lock(core, __func__)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (core->outputDeviceID) {
|
||||
fini_out_device(core);
|
||||
|
@ -555,7 +564,7 @@ static OSStatus handle_voice_change(
|
|||
update_device_playback_state(core);
|
||||
}
|
||||
|
||||
qemu_mutex_unlock_iothread();
|
||||
coreaudio_unlock (core, __func__);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -570,10 +579,14 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
struct audsettings obt_as;
|
||||
|
||||
/* create mutex */
|
||||
err = pthread_mutex_init(&core->buf_mutex, NULL);
|
||||
err = pthread_mutex_init(&core->mutex, NULL);
|
||||
if (err) {
|
||||
dolog("Could not create mutex\nReason: %s\n", strerror (err));
|
||||
return -1;
|
||||
goto mutex_error;
|
||||
}
|
||||
|
||||
if (coreaudio_lock(core, __func__)) {
|
||||
goto lock_error;
|
||||
}
|
||||
|
||||
obt_as = *as;
|
||||
|
@ -585,6 +598,7 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
|
||||
|
||||
core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
|
||||
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
||||
|
||||
status = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
|
||||
&voice_addr, handle_voice_change,
|
||||
|
@ -592,21 +606,37 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not listen to voice property change\n");
|
||||
return -1;
|
||||
goto listener_error;
|
||||
}
|
||||
|
||||
if (init_out_device(core)) {
|
||||
status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
|
||||
&voice_addr,
|
||||
handle_voice_change,
|
||||
core);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr(status,
|
||||
"Could not remove voice property change listener\n");
|
||||
}
|
||||
goto device_error;
|
||||
}
|
||||
|
||||
coreaudio_unlock(core, __func__);
|
||||
return 0;
|
||||
|
||||
device_error:
|
||||
status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
|
||||
&voice_addr,
|
||||
handle_voice_change,
|
||||
core);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr(status,
|
||||
"Could not remove voice property change listener\n");
|
||||
}
|
||||
|
||||
listener_error:
|
||||
coreaudio_unlock(core, __func__);
|
||||
|
||||
lock_error:
|
||||
err = pthread_mutex_destroy(&core->mutex);
|
||||
if (err) {
|
||||
dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
|
||||
}
|
||||
|
||||
mutex_error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void coreaudio_fini_out (HWVoiceOut *hw)
|
||||
|
@ -615,6 +645,10 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
|
|||
int err;
|
||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||
|
||||
if (coreaudio_lock(core, __func__)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
|
||||
&voice_addr,
|
||||
handle_voice_change,
|
||||
|
@ -625,8 +659,10 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
|
|||
|
||||
fini_out_device(core);
|
||||
|
||||
coreaudio_unlock(core, __func__);
|
||||
|
||||
/* destroy mutex */
|
||||
err = pthread_mutex_destroy(&core->buf_mutex);
|
||||
err = pthread_mutex_destroy(&core->mutex);
|
||||
if (err) {
|
||||
dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
|
||||
}
|
||||
|
@ -636,8 +672,14 @@ static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
|
|||
{
|
||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||
|
||||
if (coreaudio_lock(core, __func__)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
core->enabled = enable;
|
||||
update_device_playback_state(core);
|
||||
|
||||
coreaudio_unlock(core, __func__);
|
||||
}
|
||||
|
||||
static void *coreaudio_audio_init(Audiodev *dev)
|
||||
|
|
|
@ -1,654 +0,0 @@
|
|||
/*
|
||||
* QEMU DBus audio
|
||||
*
|
||||
* Copyright (c) 2021 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/dbus.h"
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
#include "ui/dbus-display1.h"
|
||||
|
||||
#define AUDIO_CAP "dbus"
|
||||
#include "audio.h"
|
||||
#include "audio_int.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define DBUS_DISPLAY1_AUDIO_PATH DBUS_DISPLAY1_ROOT "/Audio"
|
||||
|
||||
#define DBUS_AUDIO_NSAMPLES 1024 /* could be configured? */
|
||||
|
||||
typedef struct DBusAudio {
|
||||
GDBusObjectManagerServer *server;
|
||||
GDBusObjectSkeleton *audio;
|
||||
QemuDBusDisplay1Audio *iface;
|
||||
GHashTable *out_listeners;
|
||||
GHashTable *in_listeners;
|
||||
} DBusAudio;
|
||||
|
||||
typedef struct DBusVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
bool enabled;
|
||||
RateCtl rate;
|
||||
|
||||
void *buf;
|
||||
size_t buf_pos;
|
||||
size_t buf_size;
|
||||
|
||||
bool has_volume;
|
||||
Volume volume;
|
||||
} DBusVoiceOut;
|
||||
|
||||
typedef struct DBusVoiceIn {
|
||||
HWVoiceIn hw;
|
||||
bool enabled;
|
||||
RateCtl rate;
|
||||
|
||||
bool has_volume;
|
||||
Volume volume;
|
||||
} DBusVoiceIn;
|
||||
|
||||
static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
{
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
|
||||
if (!vo->buf) {
|
||||
vo->buf_size = hw->samples * hw->info.bytes_per_frame;
|
||||
vo->buf = g_malloc(vo->buf_size);
|
||||
vo->buf_pos = 0;
|
||||
}
|
||||
|
||||
*size = MIN(vo->buf_size - vo->buf_pos, *size);
|
||||
*size = audio_rate_get_bytes(&hw->info, &vo->rate, *size);
|
||||
|
||||
return vo->buf + vo->buf_pos;
|
||||
|
||||
}
|
||||
|
||||
static size_t dbus_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
g_autoptr(GVariant) v_data = NULL;
|
||||
|
||||
assert(buf == vo->buf + vo->buf_pos && vo->buf_pos + size <= vo->buf_size);
|
||||
vo->buf_pos += size;
|
||||
|
||||
trace_dbus_audio_put_buffer_out(size);
|
||||
|
||||
if (vo->buf_pos < vo->buf_size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
bytes = g_bytes_new_take(g_steal_pointer(&vo->buf), vo->buf_size);
|
||||
v_data = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
||||
g_variant_ref_sink(v_data);
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_out_listener_call_write(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
v_data,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
#define AUDIO_HOST_BE TRUE
|
||||
#else
|
||||
#define AUDIO_HOST_BE FALSE
|
||||
#endif
|
||||
|
||||
static void
|
||||
dbus_init_out_listener(QemuDBusDisplay1AudioOutListener *listener,
|
||||
HWVoiceOut *hw)
|
||||
{
|
||||
qemu_dbus_display1_audio_out_listener_call_init(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
hw->info.bits,
|
||||
hw->info.is_signed,
|
||||
hw->info.is_float,
|
||||
hw->info.freq,
|
||||
hw->info.nchannels,
|
||||
hw->info.bytes_per_frame,
|
||||
hw->info.bytes_per_second,
|
||||
hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
dbus_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
|
||||
audio_pcm_init_info(&hw->info, as);
|
||||
hw->samples = DBUS_AUDIO_NSAMPLES;
|
||||
audio_rate_start(&vo->rate);
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
dbus_init_out_listener(listener, hw);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_fini_out(HWVoiceOut *hw)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_out_listener_call_fini(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
g_clear_pointer(&vo->buf, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_enable_out(HWVoiceOut *hw, bool enable)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
|
||||
vo->enabled = enable;
|
||||
if (enable) {
|
||||
audio_rate_start(&vo->rate);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_out_listener_call_set_enabled(
|
||||
listener, (uintptr_t)hw, enable,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_volume_out_listener(HWVoiceOut *hw,
|
||||
QemuDBusDisplay1AudioOutListener *listener)
|
||||
{
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
Volume *vol = &vo->volume;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
GVariant *v_vol = NULL;
|
||||
|
||||
if (!vo->has_volume) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(vol->channels < sizeof(vol->vol));
|
||||
bytes = g_bytes_new(vol->vol, vol->channels);
|
||||
v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
||||
qemu_dbus_display1_audio_out_listener_call_set_volume(
|
||||
listener, (uintptr_t)hw, vol->mute, v_vol,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_volume_out(HWVoiceOut *hw, Volume *vol)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
||||
|
||||
vo->has_volume = true;
|
||||
vo->volume = *vol;
|
||||
|
||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
dbus_volume_out_listener(hw, listener);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_init_in_listener(QemuDBusDisplay1AudioInListener *listener, HWVoiceIn *hw)
|
||||
{
|
||||
qemu_dbus_display1_audio_in_listener_call_init(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
hw->info.bits,
|
||||
hw->info.is_signed,
|
||||
hw->info.is_float,
|
||||
hw->info.freq,
|
||||
hw->info.nchannels,
|
||||
hw->info.bytes_per_frame,
|
||||
hw->info.bytes_per_second,
|
||||
hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
dbus_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
audio_pcm_init_info(&hw->info, as);
|
||||
hw->samples = DBUS_AUDIO_NSAMPLES;
|
||||
audio_rate_start(&vo->rate);
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
dbus_init_in_listener(listener, hw);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_fini_in(HWVoiceIn *hw)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_in_listener_call_fini(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_volume_in_listener(HWVoiceIn *hw,
|
||||
QemuDBusDisplay1AudioInListener *listener)
|
||||
{
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
Volume *vol = &vo->volume;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
GVariant *v_vol = NULL;
|
||||
|
||||
if (!vo->has_volume) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(vol->channels < sizeof(vol->vol));
|
||||
bytes = g_bytes_new(vol->vol, vol->channels);
|
||||
v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
||||
qemu_dbus_display1_audio_in_listener_call_set_volume(
|
||||
listener, (uintptr_t)hw, vol->mute, v_vol,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_volume_in(HWVoiceIn *hw, Volume *vol)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
vo->has_volume = true;
|
||||
vo->volume = *vol;
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
dbus_volume_in_listener(hw, listener);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
dbus_read(HWVoiceIn *hw, void *buf, size_t size)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
/* DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw); */
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
trace_dbus_audio_read(size);
|
||||
|
||||
/* size = audio_rate_get_bytes(&hw->info, &vo->rate, size); */
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
g_autoptr(GVariant) v_data = NULL;
|
||||
const char *data;
|
||||
gsize n = 0;
|
||||
|
||||
if (qemu_dbus_display1_audio_in_listener_call_read_sync(
|
||||
listener,
|
||||
(uintptr_t)hw,
|
||||
size,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1,
|
||||
&v_data, NULL, NULL)) {
|
||||
data = g_variant_get_fixed_array(v_data, &n, 1);
|
||||
g_warn_if_fail(n <= size);
|
||||
size = MIN(n, size);
|
||||
memcpy(buf, data, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_enable_in(HWVoiceIn *hw, bool enable)
|
||||
{
|
||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
GHashTableIter iter;
|
||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
||||
|
||||
vo->enabled = enable;
|
||||
if (enable) {
|
||||
audio_rate_start(&vo->rate);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
||||
qemu_dbus_display1_audio_in_listener_call_set_enabled(
|
||||
listener, (uintptr_t)hw, enable,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
dbus_audio_init(Audiodev *dev)
|
||||
{
|
||||
DBusAudio *da = g_new0(DBusAudio, 1);
|
||||
|
||||
da->out_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_object_unref);
|
||||
da->in_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_object_unref);
|
||||
return da;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_audio_fini(void *opaque)
|
||||
{
|
||||
DBusAudio *da = opaque;
|
||||
|
||||
if (da->server) {
|
||||
g_dbus_object_manager_server_unexport(da->server,
|
||||
DBUS_DISPLAY1_AUDIO_PATH);
|
||||
}
|
||||
g_clear_object(&da->audio);
|
||||
g_clear_object(&da->iface);
|
||||
g_clear_pointer(&da->in_listeners, g_hash_table_unref);
|
||||
g_clear_pointer(&da->out_listeners, g_hash_table_unref);
|
||||
g_clear_object(&da->server);
|
||||
g_free(da);
|
||||
}
|
||||
|
||||
static void
|
||||
listener_out_vanished_cb(GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error,
|
||||
DBusAudio *da)
|
||||
{
|
||||
char *name = g_object_get_data(G_OBJECT(connection), "name");
|
||||
|
||||
g_hash_table_remove(da->out_listeners, name);
|
||||
}
|
||||
|
||||
static void
|
||||
listener_in_vanished_cb(GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error,
|
||||
DBusAudio *da)
|
||||
{
|
||||
char *name = g_object_get_data(G_OBJECT(connection), "name");
|
||||
|
||||
g_hash_table_remove(da->in_listeners, name);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dbus_audio_register_listener(AudioState *s,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GUnixFDList *fd_list,
|
||||
GVariant *arg_listener,
|
||||
bool out)
|
||||
{
|
||||
DBusAudio *da = s->drv_opaque;
|
||||
const char *sender = g_dbus_method_invocation_get_sender(invocation);
|
||||
g_autoptr(GDBusConnection) listener_conn = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
g_autoptr(GSocket) socket = NULL;
|
||||
g_autoptr(GSocketConnection) socket_conn = NULL;
|
||||
g_autofree char *guid = g_dbus_generate_guid();
|
||||
GHashTable *listeners = out ? da->out_listeners : da->in_listeners;
|
||||
GObject *listener;
|
||||
int fd;
|
||||
|
||||
trace_dbus_audio_register(sender, out ? "out" : "in");
|
||||
|
||||
if (g_hash_table_contains(listeners, sender)) {
|
||||
g_dbus_method_invocation_return_error(invocation,
|
||||
DBUS_DISPLAY_ERROR,
|
||||
DBUS_DISPLAY_ERROR_INVALID,
|
||||
"`%s` is already registered!",
|
||||
sender);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
|
||||
if (err) {
|
||||
g_dbus_method_invocation_return_error(invocation,
|
||||
DBUS_DISPLAY_ERROR,
|
||||
DBUS_DISPLAY_ERROR_FAILED,
|
||||
"Couldn't get peer fd: %s",
|
||||
err->message);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
socket = g_socket_new_from_fd(fd, &err);
|
||||
if (err) {
|
||||
g_dbus_method_invocation_return_error(invocation,
|
||||
DBUS_DISPLAY_ERROR,
|
||||
DBUS_DISPLAY_ERROR_FAILED,
|
||||
"Couldn't make a socket: %s",
|
||||
err->message);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
socket_conn = g_socket_connection_factory_create_connection(socket);
|
||||
if (out) {
|
||||
qemu_dbus_display1_audio_complete_register_out_listener(
|
||||
da->iface, invocation, NULL);
|
||||
} else {
|
||||
qemu_dbus_display1_audio_complete_register_in_listener(
|
||||
da->iface, invocation, NULL);
|
||||
}
|
||||
|
||||
listener_conn =
|
||||
g_dbus_connection_new_sync(
|
||||
G_IO_STREAM(socket_conn),
|
||||
guid,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
|
||||
NULL, NULL, &err);
|
||||
if (err) {
|
||||
error_report("Failed to setup peer connection: %s", err->message);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
listener = out ?
|
||||
G_OBJECT(qemu_dbus_display1_audio_out_listener_proxy_new_sync(
|
||||
listener_conn,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
"/org/qemu/Display1/AudioOutListener",
|
||||
NULL,
|
||||
&err)) :
|
||||
G_OBJECT(qemu_dbus_display1_audio_in_listener_proxy_new_sync(
|
||||
listener_conn,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
"/org/qemu/Display1/AudioInListener",
|
||||
NULL,
|
||||
&err));
|
||||
if (!listener) {
|
||||
error_report("Failed to setup proxy: %s", err->message);
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
if (out) {
|
||||
HWVoiceOut *hw;
|
||||
|
||||
QLIST_FOREACH(hw, &s->hw_head_out, entries) {
|
||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
||||
QemuDBusDisplay1AudioOutListener *l =
|
||||
QEMU_DBUS_DISPLAY1_AUDIO_OUT_LISTENER(listener);
|
||||
|
||||
dbus_init_out_listener(l, hw);
|
||||
qemu_dbus_display1_audio_out_listener_call_set_enabled(
|
||||
l, (uintptr_t)hw, vo->enabled,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
} else {
|
||||
HWVoiceIn *hw;
|
||||
|
||||
QLIST_FOREACH(hw, &s->hw_head_in, entries) {
|
||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
||||
QemuDBusDisplay1AudioInListener *l =
|
||||
QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener);
|
||||
|
||||
dbus_init_in_listener(
|
||||
QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener), hw);
|
||||
qemu_dbus_display1_audio_in_listener_call_set_enabled(
|
||||
l, (uintptr_t)hw, vo->enabled,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_set_data_full(G_OBJECT(listener_conn), "name",
|
||||
g_strdup(sender), g_free);
|
||||
g_hash_table_insert(listeners, g_strdup(sender), listener);
|
||||
g_object_connect(listener_conn,
|
||||
"signal::closed",
|
||||
out ? listener_out_vanished_cb : listener_in_vanished_cb,
|
||||
da,
|
||||
NULL);
|
||||
|
||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dbus_audio_register_out_listener(AudioState *s,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GUnixFDList *fd_list,
|
||||
GVariant *arg_listener)
|
||||
{
|
||||
return dbus_audio_register_listener(s, invocation,
|
||||
fd_list, arg_listener, true);
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dbus_audio_register_in_listener(AudioState *s,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GUnixFDList *fd_list,
|
||||
GVariant *arg_listener)
|
||||
{
|
||||
return dbus_audio_register_listener(s, invocation,
|
||||
fd_list, arg_listener, false);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server)
|
||||
{
|
||||
DBusAudio *da = s->drv_opaque;
|
||||
|
||||
g_assert(da);
|
||||
g_assert(!da->server);
|
||||
|
||||
da->server = g_object_ref(server);
|
||||
|
||||
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
|
||||
da->iface = qemu_dbus_display1_audio_skeleton_new();
|
||||
g_object_connect(da->iface,
|
||||
"swapped-signal::handle-register-in-listener",
|
||||
dbus_audio_register_in_listener, s,
|
||||
"swapped-signal::handle-register-out-listener",
|
||||
dbus_audio_register_out_listener, s,
|
||||
NULL);
|
||||
|
||||
g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
|
||||
G_DBUS_INTERFACE_SKELETON(da->iface));
|
||||
g_dbus_object_manager_server_export(da->server, da->audio);
|
||||
}
|
||||
|
||||
static struct audio_pcm_ops dbus_pcm_ops = {
|
||||
.init_out = dbus_init_out,
|
||||
.fini_out = dbus_fini_out,
|
||||
.write = audio_generic_write,
|
||||
.get_buffer_out = dbus_get_buffer_out,
|
||||
.put_buffer_out = dbus_put_buffer_out,
|
||||
.enable_out = dbus_enable_out,
|
||||
.volume_out = dbus_volume_out,
|
||||
|
||||
.init_in = dbus_init_in,
|
||||
.fini_in = dbus_fini_in,
|
||||
.read = dbus_read,
|
||||
.run_buffer_in = audio_generic_run_buffer_in,
|
||||
.enable_in = dbus_enable_in,
|
||||
.volume_in = dbus_volume_in,
|
||||
};
|
||||
|
||||
static struct audio_driver dbus_audio_driver = {
|
||||
.name = "dbus",
|
||||
.descr = "Timer based audio exposed with DBus interface",
|
||||
.init = dbus_audio_init,
|
||||
.fini = dbus_audio_fini,
|
||||
.set_dbus_server = dbus_audio_set_server,
|
||||
.pcm_ops = &dbus_pcm_ops,
|
||||
.can_be_default = 1,
|
||||
.max_voices_out = INT_MAX,
|
||||
.max_voices_in = INT_MAX,
|
||||
.voice_size_out = sizeof(DBusVoiceOut),
|
||||
.voice_size_in = sizeof(DBusVoiceIn)
|
||||
};
|
||||
|
||||
static void register_audio_dbus(void)
|
||||
{
|
||||
audio_driver_register(&dbus_audio_driver);
|
||||
}
|
||||
type_init(register_audio_dbus);
|
||||
|
||||
module_dep("ui-dbus")
|
|
@ -536,12 +536,13 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
|||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
||||
HRESULT hr;
|
||||
DWORD rpos, act_size;
|
||||
DWORD cpos, rpos, act_size;
|
||||
size_t req_size;
|
||||
int err;
|
||||
void *ret;
|
||||
|
||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, NULL, &rpos);
|
||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
|
||||
dscb, &cpos, ds->first_time ? &rpos : NULL);
|
||||
if (FAILED(hr)) {
|
||||
dsound_logerr(hr, "Could not get capture buffer position\n");
|
||||
*size = 0;
|
||||
|
@ -553,7 +554,7 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
|||
ds->first_time = false;
|
||||
}
|
||||
|
||||
req_size = audio_ring_dist(rpos, hw->pos_emul, hw->size_emul);
|
||||
req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
|
||||
req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul));
|
||||
|
||||
if (req_size == 0) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "qemu/module.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
|
||||
#define AUDIO_CAP "jack"
|
||||
|
@ -411,7 +412,7 @@ static int qjack_client_init(QJackClient *c)
|
|||
|
||||
snprintf(client_name, sizeof(client_name), "%s-%s",
|
||||
c->out ? "out" : "in",
|
||||
c->opt->client_name ? c->opt->client_name : audio_application_name());
|
||||
c->opt->client_name ? c->opt->client_name : qemu_get_vm_name());
|
||||
|
||||
if (c->opt->exact_name) {
|
||||
options |= JackUseExactName;
|
||||
|
@ -622,7 +623,6 @@ static void qjack_enable_in(HWVoiceIn *hw, bool enable)
|
|||
ji->c.enabled = enable;
|
||||
}
|
||||
|
||||
#if !defined(WIN32) && defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
|
||||
static int qjack_thread_creator(jack_native_thread_t *thread,
|
||||
const pthread_attr_t *attr, void *(*function)(void *), void *arg)
|
||||
{
|
||||
|
@ -636,7 +636,6 @@ static int qjack_thread_creator(jack_native_thread_t *thread,
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void *qjack_init(Audiodev *dev)
|
||||
{
|
||||
|
@ -689,9 +688,7 @@ static void register_audio_jack(void)
|
|||
{
|
||||
qemu_mutex_init(&qjack_shutdown_lock);
|
||||
audio_driver_register(&jack_driver);
|
||||
#if !defined(WIN32) && defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
|
||||
jack_set_thread_creator(qjack_thread_creator);
|
||||
#endif
|
||||
jack_set_error_function(qjack_error);
|
||||
jack_set_info_function(qjack_info);
|
||||
}
|
||||
|
|
|
@ -7,29 +7,24 @@ softmmu_ss.add(files(
|
|||
'wavcapture.c',
|
||||
))
|
||||
|
||||
softmmu_ss.add(when: coreaudio, if_true: files('coreaudio.c'))
|
||||
softmmu_ss.add(when: dsound, if_true: files('dsoundaudio.c', 'audio_win_int.c'))
|
||||
softmmu_ss.add(when: [coreaudio, 'CONFIG_AUDIO_COREAUDIO'], if_true: files('coreaudio.c'))
|
||||
softmmu_ss.add(when: [dsound, 'CONFIG_AUDIO_DSOUND'], if_true: files('dsoundaudio.c'))
|
||||
softmmu_ss.add(when: ['CONFIG_AUDIO_WIN_INT'], if_true: files('audio_win_int.c'))
|
||||
|
||||
audio_modules = {}
|
||||
foreach m : [
|
||||
['alsa', alsa, files('alsaaudio.c')],
|
||||
['oss', oss, files('ossaudio.c')],
|
||||
['pa', pulse, files('paaudio.c')],
|
||||
['sdl', sdl, files('sdlaudio.c')],
|
||||
['jack', jack, files('jackaudio.c')],
|
||||
['spice', spice, files('spiceaudio.c')]
|
||||
['CONFIG_AUDIO_ALSA', 'alsa', alsa, 'alsaaudio.c'],
|
||||
['CONFIG_AUDIO_OSS', 'oss', oss, 'ossaudio.c'],
|
||||
['CONFIG_AUDIO_PA', 'pa', pulse, 'paaudio.c'],
|
||||
['CONFIG_AUDIO_SDL', 'sdl', sdl, 'sdlaudio.c'],
|
||||
['CONFIG_AUDIO_JACK', 'jack', jack, 'jackaudio.c'],
|
||||
['CONFIG_SPICE', 'spice', spice, 'spiceaudio.c']
|
||||
]
|
||||
if m[1].found()
|
||||
if config_host.has_key(m[0])
|
||||
module_ss = ss.source_set()
|
||||
module_ss.add(m[1], m[2])
|
||||
audio_modules += {m[0] : module_ss}
|
||||
module_ss.add(when: m[2], if_true: files(m[3]))
|
||||
audio_modules += {m[1] : module_ss}
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if dbus_display
|
||||
module_ss = ss.source_set()
|
||||
module_ss.add(when: gio, if_true: files('dbusaudio.c'))
|
||||
audio_modules += {'dbus': module_ss}
|
||||
endif
|
||||
|
||||
modules += {'audio': audio_modules}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
#include "qapi/opts-visitor.h"
|
||||
|
||||
|
@ -462,7 +463,10 @@ static pa_stream *qpa_simple_new (
|
|||
|
||||
pa_stream_set_state_callback(stream, stream_state_cb, c);
|
||||
|
||||
flags = PA_STREAM_EARLY_REQUESTS;
|
||||
flags =
|
||||
PA_STREAM_INTERPOLATE_TIMING
|
||||
| PA_STREAM_AUTO_TIMING_UPDATE
|
||||
| PA_STREAM_EARLY_REQUESTS;
|
||||
|
||||
if (dev) {
|
||||
/* don't move the stream if the user specified a sink/source */
|
||||
|
@ -752,6 +756,7 @@ static int qpa_validate_per_direction_opts(Audiodev *dev,
|
|||
/* common */
|
||||
static void *qpa_conn_init(const char *server)
|
||||
{
|
||||
const char *vm_name;
|
||||
PAConnection *c = g_malloc0(sizeof(PAConnection));
|
||||
QTAILQ_INSERT_TAIL(&pa_conns, c, list);
|
||||
|
||||
|
@ -760,8 +765,9 @@ static void *qpa_conn_init(const char *server)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
vm_name = qemu_get_vm_name();
|
||||
c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop),
|
||||
audio_application_name());
|
||||
vm_name ? vm_name : "qemu");
|
||||
if (!c->context) {
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -317,5 +317,3 @@ static void register_audio_spice(void)
|
|||
audio_driver_register(&spice_audio_driver);
|
||||
}
|
||||
type_init(register_audio_spice);
|
||||
|
||||
module_dep("ui-spice-core");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# See docs/devel/tracing.rst for syntax documentation.
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# alsaaudio.c
|
||||
alsa_revents(int revents) "revents = %d"
|
||||
|
@ -13,11 +13,6 @@ alsa_resume_out(void) "Resuming suspended output stream"
|
|||
# ossaudio.c
|
||||
oss_version(int version) "OSS version = 0x%x"
|
||||
|
||||
# dbusaudio.c
|
||||
dbus_audio_register(const char *s, const char *dir) "sender = %s, dir = %s"
|
||||
dbus_audio_put_buffer_out(size_t len) "len = %zu"
|
||||
dbus_audio_read(size_t len) "len = %zu"
|
||||
|
||||
# audio.c
|
||||
audio_timer_start(int interval) "interval %d ms"
|
||||
audio_timer_stop(void) ""
|
||||
|
|
|
@ -6,4 +6,4 @@ authz_ss.add(files(
|
|||
'simple.c',
|
||||
))
|
||||
|
||||
authz_ss.add(when: pam, if_true: files('pamacct.c'))
|
||||
authz_ss.add(when: ['CONFIG_AUTH_PAM', pam], if_true: files('pamacct.c'))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# See docs/devel/tracing.rst for syntax documentation.
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# base.c
|
||||
qauthz_is_allowed(void *authz, const char *identity, bool allowed) "AuthZ %p check identity=%s allowed=%d"
|
||||
|
|
|
@ -52,7 +52,6 @@ cryptodev_vhost_init(
|
|||
{
|
||||
int r;
|
||||
CryptoDevBackendVhost *crypto;
|
||||
Error *local_err = NULL;
|
||||
|
||||
crypto = g_new(CryptoDevBackendVhost, 1);
|
||||
crypto->dev.max_queues = 1;
|
||||
|
@ -67,10 +66,8 @@ cryptodev_vhost_init(
|
|||
/* vhost-user needs vq_index to initiate a specific queue pair */
|
||||
crypto->dev.vq_index = crypto->cc->queue_index * crypto->dev.nvqs;
|
||||
|
||||
r = vhost_dev_init(&crypto->dev, options->opaque, options->backend_type, 0,
|
||||
&local_err);
|
||||
r = vhost_dev_init(&crypto->dev, options->opaque, options->backend_type, 0);
|
||||
if (r < 0) {
|
||||
error_report_err(local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||||
<!--
|
||||
org.qemu.VMState1:
|
||||
|
||||
This interface must be implemented at the object path
|
||||
``/org/qemu/VMState1`` to support helper migration.
|
||||
-->
|
||||
<interface name="org.qemu.VMState1">
|
||||
|
||||
<!--
|
||||
Id:
|
||||
|
||||
A string that identifies the helper uniquely. (maximum 256 bytes
|
||||
including terminating NUL byte)
|
||||
|
||||
.. note::
|
||||
|
||||
The VMState helper ID namespace is its own namespace. In particular,
|
||||
it is not related to QEMU "id" used in -object/-device objects.
|
||||
-->
|
||||
<property name="Id" type="s" access="read"/>
|
||||
|
||||
<!--
|
||||
Load:
|
||||
@data: data to restore the state.
|
||||
|
||||
The method called on destination with the state to restore.
|
||||
|
||||
The helper may be initially started in a waiting state (with an
|
||||
``-incoming`` argument for example), and it may resume on success.
|
||||
|
||||
An error may be returned to the caller.
|
||||
-->
|
||||
<method name="Load">
|
||||
<arg type="ay" name="data" direction="in"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Save:
|
||||
@data: state data to save for later resume.
|
||||
|
||||
The method called on the source to get the current state to be
|
||||
migrated. The helper should continue to run normally.
|
||||
|
||||
An error may be returned to the caller.
|
||||
-->
|
||||
<method name="Save">
|
||||
<arg type="ay" name="data" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* QEMU host SGX EPC memory backend
|
||||
*
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Sean Christopherson <sean.j.christopherson@intel.com>
|
||||
*
|
||||
* 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 <sys/ioctl.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/hostmem.h"
|
||||
#include "hw/i386/hostmem-epc.h"
|
||||
|
||||
static void
|
||||
sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
{
|
||||
uint32_t ram_flags;
|
||||
char *name;
|
||||
int fd;
|
||||
|
||||
if (!backend->size) {
|
||||
error_setg(errp, "can't create backend with size 0");
|
||||
return;
|
||||
}
|
||||
|
||||
fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
|
||||
if (fd < 0) {
|
||||
error_setg_errno(errp, errno,
|
||||
"failed to open /dev/sgx_vepc to alloc SGX EPC");
|
||||
return;
|
||||
}
|
||||
|
||||
name = object_get_canonical_path(OBJECT(backend));
|
||||
ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED;
|
||||
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
|
||||
name, backend->size, ram_flags,
|
||||
fd, 0, errp);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
static void sgx_epc_backend_instance_init(Object *obj)
|
||||
{
|
||||
HostMemoryBackend *m = MEMORY_BACKEND(obj);
|
||||
|
||||
m->share = true;
|
||||
m->merge = false;
|
||||
m->dump = false;
|
||||
}
|
||||
|
||||
static void sgx_epc_backend_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
|
||||
|
||||
bc->alloc = sgx_epc_backend_memory_alloc;
|
||||
}
|
||||
|
||||
static const TypeInfo sgx_epc_backed_info = {
|
||||
.name = TYPE_MEMORY_BACKEND_EPC,
|
||||
.parent = TYPE_MEMORY_BACKEND,
|
||||
.instance_init = sgx_epc_backend_instance_init,
|
||||
.class_init = sgx_epc_backend_class_init,
|
||||
.instance_size = sizeof(HostMemoryBackendEpc),
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
|
||||
type_register_static(&sgx_epc_backed_info);
|
||||
}
|
||||
}
|
||||
|
||||
type_init(register_types);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue