Fix conflicts

This commit is contained in:
Andrea Fioraldi 2021-08-24 15:20:50 +02:00
commit f3b17f95ac
598 changed files with 14823 additions and 8645 deletions

View File

@ -1,61 +1,6 @@
env: env:
CIRRUS_CLONE_DEPTH: 1 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: windows_msys2_task:
timeout_in: 90m timeout_in: 90m
windows_container: windows_container:

2
.gitignore vendored
View File

@ -15,3 +15,5 @@ GTAGS
*~ *~
*.ast_raw *.ast_raw
*.depend_raw *.depend_raw
*.swp
*.patch

View File

@ -73,9 +73,9 @@
# in its namespace setting or via git-push option, see documentation # in its namespace setting or via git-push option, see documentation
# in /.gitlab-ci.yml of this repository). # in /.gitlab-ci.yml of this repository).
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
when: always when: on_success
- if: '$QEMU_CI_AVOCADO_TESTING' - if: '$QEMU_CI_AVOCADO_TESTING'
when: always when: on_success
# Otherwise, set to manual (the jobs are created but not run). # Otherwise, set to manual (the jobs are created but not run).
- when: manual - when: manual
allow_failure: true allow_failure: true

View File

@ -305,10 +305,10 @@ build-tcg-disabled:
- cd tests/qemu-iotests/ - cd tests/qemu-iotests/
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048 - ./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 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 170 171 183 184 192 194 208 221 222 226 227 236 253 277
- ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122 - ./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 124 132 139 142 144 145 151 152 155 157 165 194 196 200 202
208 209 215 216 218 222 227 234 246 247 248 250 254 255 257 258 208 209 216 218 222 227 234 246 247 248 250 254 255 257 258
260 261 262 263 264 270 272 273 277 279 260 261 262 263 264 270 272 273 277 279
build-user: build-user:
@ -354,27 +354,15 @@ build-some-softmmu:
TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu
MAKE_CHECK_ARGS: check-tcg MAKE_CHECK_ARGS: check-tcg
# Run check-tcg against linux-user (with plugins) # We build tricore in a very minimal tricore only container
# we skip sparc64-linux-user until it has been fixed somewhat build-tricore-softmmu:
# we skip cris-linux-user as it doesn't use the common run loop
build-user-plugins:
extends: .native_build_job_template extends: .native_build_job_template
needs: needs:
job: amd64-debian-user-cross-container job: tricore-debian-cross-container
variables: variables:
IMAGE: debian-all-test-cross IMAGE: debian-tricore-cross
CONFIGURE_ARGS: --disable-tools --disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user CONFIGURE_ARGS: --disable-tools --disable-fdt --enable-debug
MAKE_CHECK_ARGS: check-tcg TARGETS: tricore-softmmu
timeout: 1h 30m
build-some-softmmu-plugins:
extends: .native_build_job_template
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 MAKE_CHECK_ARGS: check-tcg
clang-system: clang-system:
@ -428,6 +416,12 @@ build-cfi-aarch64:
expire_in: 2 days expire_in: 2 days
paths: paths:
- build - 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: check-cfi-aarch64:
extends: .native_test_job_template extends: .native_test_job_template
@ -464,6 +458,12 @@ build-cfi-ppc64-s390x:
expire_in: 2 days expire_in: 2 days
paths: paths:
- build - 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: check-cfi-ppc64-s390x:
extends: .native_test_job_template extends: .native_test_job_template
@ -686,6 +686,17 @@ build-tools-and-docs-debian:
# Prepare for GitLab pages deployment. Anything copied into the # Prepare for GitLab pages deployment. Anything copied into the
# "public" directory will be deployed to $USER.gitlab.io/$PROJECT # "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: pages:
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest
stage: test stage: test
@ -704,3 +715,10 @@ pages:
artifacts: artifacts:
paths: paths:
- public - 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

87
.gitlab-ci.d/cirrus.yml Normal file
View File

@ -0,0 +1,87 @@
# 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: []
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_TARGETSS@|$TEST_TARGETSS|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:
- 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-2
CIRRUS_VM_CPUS: 8
CIRRUS_VM_RAM: 8G
UPDATE_COMMAND: pkg update
INSTALL_COMMAND: pkg install -y
# TODO: Enable gnutls again once FreeBSD's libtasn1 got fixed
# See: https://gitlab.com/gnutls/libtasn1/-/merge_requests/71
CONFIGURE_ARGS: --disable-gnutls
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

View File

@ -0,0 +1,54 @@
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/

View File

@ -0,0 +1,35 @@
@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@"
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

View File

@ -0,0 +1,13 @@
# THIS FILE WAS AUTO-GENERATED
#
# $ lcitool variables freebsd-12 qemu
#
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
PACKAGING_COMMAND='pkg'
CCACHE='/usr/local/bin/ccache'
MAKE='/usr/local/bin/gmake'
NINJA='/usr/local/bin/ninja'
PYTHON='/usr/local/bin/python3'
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 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'

View File

@ -0,0 +1,13 @@
# THIS FILE WAS AUTO-GENERATED
#
# $ lcitool variables freebsd-13 qemu
#
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
PACKAGING_COMMAND='pkg'
CCACHE='/usr/local/bin/ccache'
MAKE='/usr/local/bin/gmake'
NINJA='/usr/local/bin/ninja'
PYTHON='/usr/local/bin/python3'
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 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'

View File

@ -0,0 +1,15 @@
# THIS FILE WAS AUTO-GENERATED
#
# $ lcitool variables macos-11 qemu
#
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
PACKAGING_COMMAND='brew'
CCACHE='/usr/local/bin/ccache'
MAKE='/usr/local/bin/gmake'
NINJA='/usr/local/bin/ninja'
PYTHON='/usr/local/bin/python3'
PIP3='/usr/local/bin/pip3'
PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils 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'
CPAN_PKGS='Test::Harness'

View File

@ -9,8 +9,14 @@
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
--disable-user --target-list-exclude="arm-softmmu cris-softmmu --disable-user --target-list-exclude="arm-softmmu cris-softmmu
i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu
mips64-softmmu ppc-softmmu sh4-softmmu xtensa-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 - 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. # Job to cross-build specific accelerators.
# #

View File

@ -160,6 +160,11 @@ cross-win32-system:
job: win32-fedora-cross-container job: win32-fedora-cross-container
variables: variables:
IMAGE: fedora-win32-cross 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: cross-win64-system:
extends: .cross_system_build_job extends: .cross_system_build_job
@ -167,6 +172,11 @@ cross-win64-system:
job: win64-fedora-cross-container job: win64-fedora-cross-container
variables: variables:
IMAGE: fedora-win64-cross 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: cross-amd64-xen-only:
extends: .cross_accel_build_job extends: .cross_accel_build_job

View File

@ -0,0 +1,238 @@
# 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
# 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:
allow_failure: true
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:
allow_failure: true
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:
allow_failure: true
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 --enable-debug --disable-libssh
- make clean
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-18.04-s390x-clang:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
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:
allow_failure: true
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 --enable-tcg-interpreter
- make --output-sync -j`nproc`
ubuntu-18.04-s390x-notcg:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
script:
- mkdir build
- cd build
- ../configure --disable-libssh --disable-tcg
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
# 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:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
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-20.04-aarch64-all:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
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-20.04-aarch64-alldbg:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_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:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
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:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --disable-libssh --enable-tcg-interpreter
- make --output-sync -j`nproc`
ubuntu-20.04-aarch64-notcg:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
script:
- mkdir build
- cd build
- ../configure --disable-libssh --disable-tcg
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1

View File

@ -1,10 +1,22 @@
docker-edk2: # All jobs needing docker-edk2 must use the same rules it uses.
stage: containers .edk2_job_rules:
rules: # Only run this job when the Dockerfile is modified rules: # Only run this job when ...
- changes: - changes:
# this file is modified
- .gitlab-ci.d/edk2.yml - .gitlab-ci.d/edk2.yml
# or the Dockerfile is modified
- .gitlab-ci.d/edk2/Dockerfile - .gitlab-ci.d/edk2/Dockerfile
when: always # 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
image: docker:19.03.1 image: docker:19.03.1
services: services:
- docker:19.03.1-dind - docker:19.03.1-dind
@ -24,16 +36,9 @@ docker-edk2:
- docker push $IMAGE_TAG - docker push $IMAGE_TAG
build-edk2: build-edk2:
extends: .edk2_job_rules
stage: build stage: build
needs: ['docker-edk2'] 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: artifacts:
paths: # 'artifacts.zip' will contains the following files: paths: # 'artifacts.zip' will contains the following files:
- pc-bios/edk2*bz2 - pc-bios/edk2*bz2

View File

@ -1,10 +1,23 @@
docker-opensbi: # All jobs needing docker-opensbi must use the same rules it uses.
stage: containers .opensbi_job_rules:
rules: # Only run this job when the Dockerfile is modified rules: # Only run this job when ...
- changes: - changes:
# this file is modified
- .gitlab-ci.d/opensbi.yml - .gitlab-ci.d/opensbi.yml
# or the Dockerfile is modified
- .gitlab-ci.d/opensbi/Dockerfile - .gitlab-ci.d/opensbi/Dockerfile
when: always 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
image: docker:19.03.1 image: docker:19.03.1
services: services:
- docker:19.03.1-dind - docker:19.03.1-dind
@ -24,16 +37,9 @@ docker-opensbi:
- docker push $IMAGE_TAG - docker push $IMAGE_TAG
build-opensbi: build-opensbi:
extends: .opensbi_job_rules
stage: build stage: build
needs: ['docker-opensbi'] 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: artifacts:
paths: # 'artifacts.zip' will contains the following files: paths: # 'artifacts.zip' will contains the following files:
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin - pc-bios/opensbi-riscv32-generic-fw_dynamic.bin

View File

@ -9,3 +9,5 @@ include:
- local: '/.gitlab-ci.d/crossbuilds.yml' - local: '/.gitlab-ci.d/crossbuilds.yml'
- local: '/.gitlab-ci.d/buildtest.yml' - local: '/.gitlab-ci.d/buildtest.yml'
- local: '/.gitlab-ci.d/static_checks.yml' - local: '/.gitlab-ci.d/static_checks.yml'
- local: '/.gitlab-ci.d/custom-runners.yml'
- local: '/.gitlab-ci.d/cirrus.yml'

View File

@ -43,6 +43,7 @@ check-python-tox:
- make -C python check-tox - make -C python check-tox
variables: variables:
GIT_DEPTH: 1 GIT_DEPTH: 1
QEMU_TOX_EXTRA_ARGS: --skip-missing-interpreters=false
needs: needs:
job: python-container job: python-container
allow_failure: true allow_failure: true

View File

@ -16,24 +16,9 @@
# QEMU CI jobs are based on templates. Some templates provide # QEMU CI jobs are based on templates. Some templates provide
# user-configurable options, modifiable via configuration variables. # user-configurable options, modifiable via configuration variables.
# #
# These variables can be set globally in the user's CI namespace # See https://qemu-project.gitlab.io/qemu/devel/ci.html#custom-ci-cd-variables
# setting: # for more information.
# https://docs.gitlab.com/ee/ci/variables/#create-a-custom-variable-in-the-ui
# or set manually each time a branch/tag is pushed, as a git-push
# command line argument:
# https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd
# #
# Example setting the QEMU_CI_EXAMPLE_VAR variable:
#
# git push -o ci.variable="QEMU_CI_EXAMPLE_VAR=value" myrepo mybranch
#
# ----------------------------------------------------------------------
#
# List of environment variables that can be use to modify the set
# of jobs selected:
#
# - QEMU_CI_AVOCADO_TESTING
# If set, tests using the Avocado framework will be run
include: include:
- local: '/.gitlab-ci.d/qemu-project.yml' - local: '/.gitlab-ci.d/qemu-project.yml'

View File

@ -27,6 +27,10 @@ Paul Brook <paul@codesourcery.com> pbrook <pbrook@c046a42c-6fe2-441c-8c8c-714662
Thiemo Seufer <ths@networkno.de> ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> Thiemo Seufer <ths@networkno.de> ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
malc <av1474@comtv.ru> malc <malc@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: # There is also a:
# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162> # (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
# for the cvs2svn initialization commit e63c3dc74bf. # for the cvs2svn initialization commit e63c3dc74bf.
@ -96,6 +100,7 @@ Gautham R. Shenoy <ego@linux.vnet.ibm.com>
Gonglei (Arei) <arei.gonglei@huawei.com> Gonglei (Arei) <arei.gonglei@huawei.com>
Guang Wang <wang.guang55@zte.com.cn> Guang Wang <wang.guang55@zte.com.cn>
Hailiang Zhang <zhang.zhanghailiang@huawei.com> Hailiang Zhang <zhang.zhanghailiang@huawei.com>
Hanna Reitz <hreitz@redhat.com> <mreitz@redhat.com>
Hervé Poussineau <hpoussin@reactos.org> Hervé Poussineau <hpoussin@reactos.org>
Jakub Jermář <jakub@jermar.eu> Jakub Jermář <jakub@jermar.eu>
Jakub Jermář <jakub.jermar@kernkonzept.com> Jakub Jermář <jakub.jermar@kernkonzept.com>

View File

@ -27,6 +27,7 @@ addons:
- libattr1-dev - libattr1-dev
- libbrlapi-dev - libbrlapi-dev
- libcap-ng-dev - libcap-ng-dev
- libcacard-dev
- libgcc-7-dev - libgcc-7-dev
- libgnutls28-dev - libgnutls28-dev
- libgtk-3-dev - libgtk-3-dev
@ -34,7 +35,6 @@ addons:
- liblttng-ust-dev - liblttng-ust-dev
- libncurses5-dev - libncurses5-dev
- libnfs-dev - libnfs-dev
- libnss3-dev
- libpixman-1-dev - libpixman-1-dev
- libpng-dev - libpng-dev
- librados-dev - librados-dev
@ -129,6 +129,7 @@ jobs:
- libaio-dev - libaio-dev
- libattr1-dev - libattr1-dev
- libbrlapi-dev - libbrlapi-dev
- libcacard-dev
- libcap-ng-dev - libcap-ng-dev
- libgcrypt20-dev - libgcrypt20-dev
- libgnutls28-dev - libgnutls28-dev
@ -137,7 +138,6 @@ jobs:
- liblttng-ust-dev - liblttng-ust-dev
- libncurses5-dev - libncurses5-dev
- libnfs-dev - libnfs-dev
- libnss3-dev
- libpixman-1-dev - libpixman-1-dev
- libpng-dev - libpng-dev
- librados-dev - librados-dev
@ -163,6 +163,7 @@ jobs:
- libaio-dev - libaio-dev
- libattr1-dev - libattr1-dev
- libbrlapi-dev - libbrlapi-dev
- libcacard-dev
- libcap-ng-dev - libcap-ng-dev
- libgcrypt20-dev - libgcrypt20-dev
- libgnutls28-dev - libgnutls28-dev
@ -171,7 +172,6 @@ jobs:
- liblttng-ust-dev - liblttng-ust-dev
- libncurses5-dev - libncurses5-dev
- libnfs-dev - libnfs-dev
- libnss3-dev
- libpixman-1-dev - libpixman-1-dev
- libpng-dev - libpng-dev
- librados-dev - librados-dev
@ -196,6 +196,7 @@ jobs:
- libaio-dev - libaio-dev
- libattr1-dev - libattr1-dev
- libbrlapi-dev - libbrlapi-dev
- libcacard-dev
- libcap-ng-dev - libcap-ng-dev
- libgcrypt20-dev - libgcrypt20-dev
- libgnutls28-dev - libgnutls28-dev
@ -204,7 +205,6 @@ jobs:
- liblttng-ust-dev - liblttng-ust-dev
- libncurses5-dev - libncurses5-dev
- libnfs-dev - libnfs-dev
- libnss3-dev
- libpixman-1-dev - libpixman-1-dev
- libpng-dev - libpng-dev
- librados-dev - librados-dev
@ -238,6 +238,7 @@ jobs:
apt_packages: apt_packages:
- libaio-dev - libaio-dev
- libattr1-dev - libattr1-dev
- libcacard-dev
- libcap-ng-dev - libcap-ng-dev
- libgnutls28-dev - libgnutls28-dev
- libiscsi-dev - libiscsi-dev
@ -245,7 +246,6 @@ jobs:
- liblzo2-dev - liblzo2-dev
- libncurses-dev - libncurses-dev
- libnfs-dev - libnfs-dev
- libnss3-dev
- libpixman-1-dev - libpixman-1-dev
- libsdl2-dev - libsdl2-dev
- libsdl2-image-dev - libsdl2-image-dev
@ -281,6 +281,7 @@ jobs:
- libaio-dev - libaio-dev
- libattr1-dev - libattr1-dev
- libbrlapi-dev - libbrlapi-dev
- libcacard-dev
- libcap-ng-dev - libcap-ng-dev
- libgcrypt20-dev - libgcrypt20-dev
- libgnutls28-dev - libgnutls28-dev
@ -289,7 +290,6 @@ jobs:
- liblttng-ust-dev - liblttng-ust-dev
- libncurses5-dev - libncurses5-dev
- libnfs-dev - libnfs-dev
- libnss3-dev
- libpixman-1-dev - libpixman-1-dev
- libpng-dev - libpng-dev
- librados-dev - librados-dev

View File

@ -171,6 +171,7 @@ L: qemu-arm@nongnu.org
S: Maintained S: Maintained
F: hw/arm/smmu* F: hw/arm/smmu*
F: include/hw/arm/smmu* F: include/hw/arm/smmu*
F: tests/acceptance/smmu.py
AVR TCG CPUs AVR TCG CPUs
M: Michael Rolnik <mrolnik@gmail.com> M: Michael Rolnik <mrolnik@gmail.com>
@ -559,6 +560,7 @@ S: Odd Fixes
F: hw/*/allwinner* F: hw/*/allwinner*
F: include/hw/*/allwinner* F: include/hw/*/allwinner*
F: hw/arm/cubieboard.c F: hw/arm/cubieboard.c
F: docs/system/arm/cubieboard.rst
Allwinner-h3 Allwinner-h3
M: Niek Linnenbank <nieklinnenbank@gmail.com> M: Niek Linnenbank <nieklinnenbank@gmail.com>
@ -641,6 +643,7 @@ L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/arm/highbank.c F: hw/arm/highbank.c
F: hw/net/xgmac.c F: hw/net/xgmac.c
F: docs/system/arm/highbank.rst
Canon DIGIC Canon DIGIC
M: Antony Pavlov <antonynpavlov@gmail.com> M: Antony Pavlov <antonynpavlov@gmail.com>
@ -681,6 +684,7 @@ F: hw/watchdog/wdt_imx2.c
F: include/hw/arm/fsl-imx25.h F: include/hw/arm/fsl-imx25.h
F: include/hw/misc/imx25_ccm.h F: include/hw/misc/imx25_ccm.h
F: include/hw/watchdog/wdt_imx2.h F: include/hw/watchdog/wdt_imx2.h
F: docs/system/arm/imx25-pdk.rst
i.MX31 (kzm) i.MX31 (kzm)
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
@ -691,6 +695,7 @@ F: hw/*/imx_*
F: hw/*/*imx31* F: hw/*/*imx31*
F: include/hw/*/imx_* F: include/hw/*/imx_*
F: include/hw/*/*imx31* F: include/hw/*/*imx31*
F: docs/system/arm/kzm.rst
Integrator CP Integrator CP
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
@ -783,7 +788,6 @@ F: roms/vbootrom
F: docs/system/arm/nuvoton.rst F: docs/system/arm/nuvoton.rst
nSeries nSeries
M: Andrzej Zaborowski <balrogg@gmail.com>
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
@ -801,7 +805,6 @@ F: tests/acceptance/machine_arm_n8x0.py
F: docs/system/arm/nseries.rst F: docs/system/arm/nseries.rst
Palm Palm
M: Andrzej Zaborowski <balrogg@gmail.com>
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
@ -834,7 +837,6 @@ F: include/hw/intc/realview_gic.h
F: docs/system/arm/realview.rst F: docs/system/arm/realview.rst
PXA2XX PXA2XX
M: Andrzej Zaborowski <balrogg@gmail.com>
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
@ -853,6 +855,7 @@ F: include/hw/arm/pxa.h
F: include/hw/arm/sharpsl.h F: include/hw/arm/sharpsl.h
F: include/hw/display/tc6393xb.h F: include/hw/display/tc6393xb.h
F: docs/system/arm/xscale.rst F: docs/system/arm/xscale.rst
F: docs/system/arm/mainstone.rst
SABRELITE / i.MX6 SABRELITE / i.MX6
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
@ -1022,6 +1025,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Maintained S: Maintained
F: hw/arm/msf2-som.c F: hw/arm/msf2-som.c
F: docs/system/arm/emcraft-sf2.rst
ASPEED BMCs ASPEED BMCs
M: Cédric Le Goater <clg@kaod.org> M: Cédric Le Goater <clg@kaod.org>
@ -1828,17 +1832,16 @@ F: tests/qtest/sdhci-test.c
USB USB
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained S: Odd Fixes
F: hw/usb/* F: hw/usb/*
F: stubs/usb-dev-stub.c F: stubs/usb-dev-stub.c
F: tests/qtest/usb-*-test.c F: tests/qtest/usb-*-test.c
F: docs/usb2.txt F: docs/system/devices/usb.rst
F: docs/usb-storage.txt
F: include/hw/usb.h F: include/hw/usb.h
F: include/hw/usb/ F: include/hw/usb/
USB (serial adapter) USB (serial adapter)
M: Gerd Hoffmann <kraxel@redhat.com> R: Gerd Hoffmann <kraxel@redhat.com>
M: Samuel Thibault <samuel.thibault@ens-lyon.org> M: Samuel Thibault <samuel.thibault@ens-lyon.org>
S: Maintained S: Maintained
F: hw/usb/dev-serial.c F: hw/usb/dev-serial.c
@ -1948,7 +1951,7 @@ L: virtio-fs@redhat.com
virtio-input virtio-input
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained S: Odd Fixes
F: hw/input/vhost-user-input.c F: hw/input/vhost-user-input.c
F: hw/input/virtio-input*.c F: hw/input/virtio-input*.c
F: include/hw/virtio/virtio-input.h F: include/hw/virtio/virtio-input.h
@ -2154,7 +2157,7 @@ F: include/hw/display/ramfb.h
virtio-gpu virtio-gpu
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained S: Odd Fixes
F: hw/display/virtio-gpu* F: hw/display/virtio-gpu*
F: hw/display/virtio-vga.* F: hw/display/virtio-vga.*
F: include/hw/virtio/virtio-gpu.h F: include/hw/virtio/virtio-gpu.h
@ -2173,7 +2176,7 @@ F: include/hw/virtio/vhost-user-scsi.h
vhost-user-gpu vhost-user-gpu
M: Marc-André Lureau <marcandre.lureau@redhat.com> M: Marc-André Lureau <marcandre.lureau@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com> R: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained S: Maintained
F: docs/interop/vhost-user-gpu.rst F: docs/interop/vhost-user-gpu.rst
F: contrib/vhost-user-gpu F: contrib/vhost-user-gpu
@ -2201,7 +2204,6 @@ F: include/hw/southbridge/piix.h
Firmware configuration (fw_cfg) Firmware configuration (fw_cfg)
M: Philippe Mathieu-Daudé <philmd@redhat.com> M: Philippe Mathieu-Daudé <philmd@redhat.com>
R: Laszlo Ersek <lersek@redhat.com>
R: Gerd Hoffmann <kraxel@redhat.com> R: Gerd Hoffmann <kraxel@redhat.com>
S: Supported S: Supported
F: docs/specs/fw_cfg.txt F: docs/specs/fw_cfg.txt
@ -2256,7 +2258,7 @@ Subsystems
---------- ----------
Audio Audio
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained S: Odd Fixes
F: audio/ F: audio/
F: hw/audio/ F: hw/audio/
F: include/hw/audio/ F: include/hw/audio/
@ -2268,7 +2270,7 @@ F: tests/qtest/fuzz-sb16-test.c
Block layer core Block layer core
M: Kevin Wolf <kwolf@redhat.com> M: Kevin Wolf <kwolf@redhat.com>
M: Max Reitz <mreitz@redhat.com> M: Hanna Reitz <hreitz@redhat.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Supported S: Supported
F: block* F: block*
@ -2449,22 +2451,26 @@ F: tests/tcg/multiarch/gdbstub/
Memory API Memory API
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
M: Peter Xu <peterx@redhat.com>
M: David Hildenbrand <david@redhat.com>
S: Supported S: Supported
F: include/exec/ioport.h F: include/exec/ioport.h
F: include/exec/memop.h F: include/exec/memop.h
F: include/exec/memory.h F: include/exec/memory.h
F: include/exec/ram_addr.h F: include/exec/ram_addr.h
F: include/exec/ramblock.h F: include/exec/ramblock.h
F: include/sysemu/memory_mapping.h
F: softmmu/dma-helpers.c F: softmmu/dma-helpers.c
F: softmmu/ioport.c F: softmmu/ioport.c
F: softmmu/memory.c F: softmmu/memory.c
F: softmmu/memory_mapping.c
F: softmmu/physmem.c F: softmmu/physmem.c
F: include/exec/memory-internal.h F: include/exec/memory-internal.h
F: scripts/coccinelle/memory-region-housekeeping.cocci F: scripts/coccinelle/memory-region-housekeeping.cocci
SPICE SPICE
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Supported S: Odd Fixes
F: include/ui/qemu-spice.h F: include/ui/qemu-spice.h
F: include/ui/spice-display.h F: include/ui/spice-display.h
F: ui/spice-*.c F: ui/spice-*.c
@ -2544,7 +2550,7 @@ S: Maintained
F: net/netmap.c F: net/netmap.c
Host Memory Backends Host Memory Backends
M: Eduardo Habkost <ehabkost@redhat.com> M: David Hildenbrand <david@redhat.com>
M: Igor Mammedov <imammedo@redhat.com> M: Igor Mammedov <imammedo@redhat.com>
S: Maintained S: Maintained
F: backends/hostmem*.c F: backends/hostmem*.c
@ -2837,7 +2843,6 @@ F: tests/unit/test-authz-*
Sockets Sockets
M: Daniel P. Berrange <berrange@redhat.com> M: Daniel P. Berrange <berrange@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained S: Maintained
F: include/qemu/sockets.h F: include/qemu/sockets.h
F: util/qemu-sockets.c F: util/qemu-sockets.c
@ -2933,7 +2938,6 @@ F: include/hw/i2c/smbus_slave.h
F: include/hw/i2c/smbus_eeprom.h F: include/hw/i2c/smbus_eeprom.h
Firmware schema specifications Firmware schema specifications
M: Laszlo Ersek <lersek@redhat.com>
M: Philippe Mathieu-Daudé <philmd@redhat.com> M: Philippe Mathieu-Daudé <philmd@redhat.com>
R: Daniel P. Berrange <berrange@redhat.com> R: Daniel P. Berrange <berrange@redhat.com>
R: Kashyap Chamarthy <kchamart@redhat.com> R: Kashyap Chamarthy <kchamart@redhat.com>
@ -2941,9 +2945,10 @@ S: Maintained
F: docs/interop/firmware.json F: docs/interop/firmware.json
EDK2 Firmware EDK2 Firmware
M: Laszlo Ersek <lersek@redhat.com>
M: Philippe Mathieu-Daudé <philmd@redhat.com> M: Philippe Mathieu-Daudé <philmd@redhat.com>
R: Gerd Hoffmann <kraxel@redhat.com>
S: Supported S: Supported
F: hw/i386/*ovmf*
F: pc-bios/descriptors/??-edk2-*.json F: pc-bios/descriptors/??-edk2-*.json
F: pc-bios/edk2-* F: pc-bios/edk2-*
F: roms/Makefile.edk2 F: roms/Makefile.edk2
@ -3017,6 +3022,8 @@ F: include/tcg/
TCG Plugins TCG Plugins
M: Alex Bennée <alex.bennee@linaro.org> M: Alex Bennée <alex.bennee@linaro.org>
R: Alexandre Iooss <erdnaxe@crans.org>
R: Mahmoud Mandour <ma.mandourr@gmail.com>
S: Maintained S: Maintained
F: docs/devel/tcg-plugins.rst F: docs/devel/tcg-plugins.rst
F: plugins/ F: plugins/
@ -3033,7 +3040,7 @@ F: disas/arm-a64.cc
F: disas/libvixl/ F: disas/libvixl/
ARM TCG target ARM TCG target
M: Andrzej Zaborowski <balrogg@gmail.com> M: Richard Henderson <richard.henderson@linaro.org>
S: Maintained S: Maintained
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
F: tcg/arm/ F: tcg/arm/
@ -3170,6 +3177,7 @@ F: block/null.c
NVMe Block Driver NVMe Block Driver
M: Stefan Hajnoczi <stefanha@redhat.com> M: Stefan Hajnoczi <stefanha@redhat.com>
R: Fam Zheng <fam@euphon.net> R: Fam Zheng <fam@euphon.net>
R: Philippe Mathieu-Daudé <philmd@redhat.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Supported S: Supported
F: block/nvme* F: block/nvme*
@ -3249,6 +3257,7 @@ Linux io_uring
M: Aarushi Mehta <mehta.aaru20@gmail.com> M: Aarushi Mehta <mehta.aaru20@gmail.com>
M: Julia Suvorova <jusual@redhat.com> M: Julia Suvorova <jusual@redhat.com>
M: Stefan Hajnoczi <stefanha@redhat.com> M: Stefan Hajnoczi <stefanha@redhat.com>
R: Stefano Garzarella <sgarzare@redhat.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Maintained S: Maintained
F: block/io_uring.c F: block/io_uring.c
@ -3256,7 +3265,7 @@ F: stubs/io_uring.c
qcow2 qcow2
M: Kevin Wolf <kwolf@redhat.com> M: Kevin Wolf <kwolf@redhat.com>
M: Max Reitz <mreitz@redhat.com> M: Hanna Reitz <hreitz@redhat.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Supported S: Supported
F: block/qcow2* F: block/qcow2*
@ -3270,7 +3279,7 @@ F: block/qcow.c
blkdebug blkdebug
M: Kevin Wolf <kwolf@redhat.com> M: Kevin Wolf <kwolf@redhat.com>
M: Max Reitz <mreitz@redhat.com> M: Hanna Reitz <hreitz@redhat.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Supported S: Supported
F: block/blkdebug.c F: block/blkdebug.c
@ -3305,7 +3314,7 @@ F: tests/qtest/vhost-user-blk-test.c
F: util/vhost-user-server.c F: util/vhost-user-server.c
FUSE block device exports FUSE block device exports
M: Max Reitz <mreitz@redhat.com> M: Hanna Reitz <hreitz@redhat.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Supported S: Supported
F: block/export/fuse.c F: block/export/fuse.c
@ -3431,7 +3440,7 @@ F: contrib/gitdm/*
Incompatible changes Incompatible changes
R: libvir-list@redhat.com R: libvir-list@redhat.com
F: docs/system/deprecated.rst F: docs/about/deprecated.rst
Build System Build System
------------ ------------
@ -3450,6 +3459,7 @@ S: Maintained
F: docs/conf.py F: docs/conf.py
F: docs/*/conf.py F: docs/*/conf.py
F: docs/sphinx/ F: docs/sphinx/
F: docs/_templates/
Miscellaneous Miscellaneous
------------- -------------

View File

@ -129,9 +129,11 @@ endif
# 4. Rules to bridge to other makefiles # 4. Rules to bridge to other makefiles
ifneq ($(NINJA),) ifneq ($(NINJA),)
MAKE.n = $(findstring n,$(firstword $(MAKEFLAGS))) # Filter out long options to avoid flags like --no-print-directory which
MAKE.k = $(findstring k,$(firstword $(MAKEFLAGS))) # may result in false positive match for MAKE.n
MAKE.q = $(findstring q,$(firstword $(MAKEFLAGS))) 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.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq) MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq)
NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \ NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \
$(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \ $(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \

View File

@ -1 +1 @@
6.0.50 6.0.94

View File

@ -2397,6 +2397,12 @@ static int kvm_init(MachineState *ms)
"- for kernels supporting the vm.allocate_pgste sysctl, " "- for kernels supporting the vm.allocate_pgste sysctl, "
"whether it is enabled\n"); "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 #endif
goto err; goto err;
} }

View File

@ -13,42 +13,125 @@
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
static inline static uint16_t atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr,
void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr, uint16_t info) TCGMemOpIdx oi)
{ {
CPUState *cpu = env_cpu(env); CPUState *cpu = env_cpu(env);
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false);
trace_guest_mem_before_exec(cpu, addr, info); trace_guest_mem_before_exec(cpu, addr, info);
trace_guest_mem_before_exec(cpu, addr, info | TRACE_MEM_ST); trace_guest_mem_before_exec(cpu, addr, info | TRACE_MEM_ST);
return info;
} }
static inline void static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr,
atomic_trace_rmw_post(CPUArchState *env, target_ulong addr, uint16_t info) uint16_t info)
{ {
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info | TRACE_MEM_ST); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info | TRACE_MEM_ST);
} }
static inline #if HAVE_ATOMIC128
void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr, uint16_t info) static uint16_t atomic_trace_ld_pre(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi)
{ {
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false);
trace_guest_mem_before_exec(env_cpu(env), addr, info); trace_guest_mem_before_exec(env_cpu(env), addr, info);
return info;
} }
static inline static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr,
void atomic_trace_ld_post(CPUArchState *env, target_ulong addr, uint16_t info) uint16_t info)
{ {
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
} }
static inline static uint16_t atomic_trace_st_pre(CPUArchState *env, target_ulong addr,
void atomic_trace_st_pre(CPUArchState *env, target_ulong addr, uint16_t info) TCGMemOpIdx oi)
{ {
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), true);
trace_guest_mem_before_exec(env_cpu(env), addr, info); trace_guest_mem_before_exec(env_cpu(env), addr, info);
return info;
} }
static inline static void atomic_trace_st_post(CPUArchState *env, target_ulong addr,
void atomic_trace_st_post(CPUArchState *env, target_ulong addr, uint16_t info) uint16_t info)
{ {
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info); 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

View File

@ -28,8 +28,8 @@
# define SHIFT 4 # define SHIFT 4
#elif DATA_SIZE == 8 #elif DATA_SIZE == 8
# define SUFFIX q # define SUFFIX q
# define DATA_TYPE uint64_t # define DATA_TYPE aligned_uint64_t
# define SDATA_TYPE int64_t # define SDATA_TYPE aligned_int64_t
# define BSWAP bswap64 # define BSWAP bswap64
# define SHIFT 3 # define SHIFT 3
#elif DATA_SIZE == 4 #elif DATA_SIZE == 4
@ -71,15 +71,14 @@
#endif #endif
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) ABI_TYPE cmpv, ABI_TYPE newv,
TCGMemOpIdx oi, uintptr_t retaddr)
{ {
ATOMIC_MMU_DECLS; DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; PAGE_READ | PAGE_WRITE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
ATOMIC_MMU_IDX);
atomic_trace_rmw_pre(env, addr, info);
#if DATA_SIZE == 16 #if DATA_SIZE == 16
ret = atomic16_cmpxchg(haddr, cmpv, newv); ret = atomic16_cmpxchg(haddr, cmpv, newv);
#else #else
@ -92,45 +91,41 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
#if DATA_SIZE >= 16 #if DATA_SIZE >= 16
#if HAVE_ATOMIC128 #if HAVE_ATOMIC128
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{ {
ATOMIC_MMU_DECLS; DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; PAGE_READ, retaddr);
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, DATA_TYPE val;
ATOMIC_MMU_IDX); uint16_t info = atomic_trace_ld_pre(env, addr, oi);
atomic_trace_ld_pre(env, addr, info);
val = atomic16_read(haddr); val = atomic16_read(haddr);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_ld_post(env, addr, info); atomic_trace_ld_post(env, addr, info);
return val; return val;
} }
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
ABI_TYPE val EXTRA_ARGS) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
ATOMIC_MMU_DECLS; DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; PAGE_WRITE, retaddr);
uint16_t info = trace_mem_build_info(SHIFT, false, 0, true, uint16_t info = atomic_trace_st_pre(env, addr, oi);
ATOMIC_MMU_IDX);
atomic_trace_st_pre(env, addr, info);
atomic16_set(haddr, val); atomic16_set(haddr, val);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_st_post(env, addr, info); atomic_trace_st_post(env, addr, info);
} }
#endif #endif
#else #else
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
ABI_TYPE val EXTRA_ARGS) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
ATOMIC_MMU_DECLS; DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; PAGE_READ | PAGE_WRITE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
ATOMIC_MMU_IDX);
atomic_trace_rmw_pre(env, addr, info);
ret = qatomic_xchg__nocheck(haddr, val); ret = qatomic_xchg__nocheck(haddr, val);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_rmw_post(env, addr, info); atomic_trace_rmw_post(env, addr, info);
@ -139,14 +134,12 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
#define GEN_ATOMIC_HELPER(X) \ #define GEN_ATOMIC_HELPER(X) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ABI_TYPE val EXTRA_ARGS) \ ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
{ \ { \
ATOMIC_MMU_DECLS; \ DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ PAGE_READ | PAGE_WRITE, retaddr); \
DATA_TYPE ret; \ DATA_TYPE ret; \
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
ATOMIC_MMU_IDX); \
atomic_trace_rmw_pre(env, addr, info); \
ret = qatomic_##X(haddr, val); \ ret = qatomic_##X(haddr, val); \
ATOMIC_MMU_CLEANUP; \ ATOMIC_MMU_CLEANUP; \
atomic_trace_rmw_post(env, addr, info); \ atomic_trace_rmw_post(env, addr, info); \
@ -164,7 +157,8 @@ GEN_ATOMIC_HELPER(xor_fetch)
#undef GEN_ATOMIC_HELPER #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 * the leading barrier is explicit and the trailing barrier is within
* cmpxchg primitive. * cmpxchg primitive.
* *
@ -173,14 +167,12 @@ GEN_ATOMIC_HELPER(xor_fetch)
*/ */
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ABI_TYPE xval EXTRA_ARGS) \ ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
{ \ { \
ATOMIC_MMU_DECLS; \ XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ PAGE_READ | PAGE_WRITE, retaddr); \
XDATA_TYPE cmp, old, new, val = xval; \ XDATA_TYPE cmp, old, new, val = xval; \
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
ATOMIC_MMU_IDX); \
atomic_trace_rmw_pre(env, addr, info); \
smp_mb(); \ smp_mb(); \
cmp = qatomic_read__nocheck(haddr); \ cmp = qatomic_read__nocheck(haddr); \
do { \ do { \
@ -218,15 +210,14 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
#endif #endif
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) ABI_TYPE cmpv, ABI_TYPE newv,
TCGMemOpIdx oi, uintptr_t retaddr)
{ {
ATOMIC_MMU_DECLS; DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; PAGE_READ | PAGE_WRITE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
ATOMIC_MMU_IDX);
atomic_trace_rmw_pre(env, addr, info);
#if DATA_SIZE == 16 #if DATA_SIZE == 16
ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
#else #else
@ -239,30 +230,27 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
#if DATA_SIZE >= 16 #if DATA_SIZE >= 16
#if HAVE_ATOMIC128 #if HAVE_ATOMIC128
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{ {
ATOMIC_MMU_DECLS; DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R; PAGE_READ, retaddr);
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, DATA_TYPE val;
ATOMIC_MMU_IDX); uint16_t info = atomic_trace_ld_pre(env, addr, oi);
atomic_trace_ld_pre(env, addr, info);
val = atomic16_read(haddr); val = atomic16_read(haddr);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_ld_post(env, addr, info); atomic_trace_ld_post(env, addr, info);
return BSWAP(val); return BSWAP(val);
} }
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
ABI_TYPE val EXTRA_ARGS) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
ATOMIC_MMU_DECLS; DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W; PAGE_WRITE, retaddr);
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true, uint16_t info = atomic_trace_st_pre(env, addr, oi);
ATOMIC_MMU_IDX);
val = BSWAP(val);
atomic_trace_st_pre(env, addr, info);
val = BSWAP(val); val = BSWAP(val);
atomic16_set(haddr, val); atomic16_set(haddr, val);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
@ -270,16 +258,14 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
} }
#endif #endif
#else #else
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
ABI_TYPE val EXTRA_ARGS) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
ATOMIC_MMU_DECLS; DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; PAGE_READ | PAGE_WRITE, retaddr);
ABI_TYPE ret; ABI_TYPE ret;
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
ATOMIC_MMU_IDX);
atomic_trace_rmw_pre(env, addr, info);
ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_rmw_post(env, addr, info); atomic_trace_rmw_post(env, addr, info);
@ -288,14 +274,12 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
#define GEN_ATOMIC_HELPER(X) \ #define GEN_ATOMIC_HELPER(X) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ABI_TYPE val EXTRA_ARGS) \ ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
{ \ { \
ATOMIC_MMU_DECLS; \ DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ PAGE_READ | PAGE_WRITE, retaddr); \
DATA_TYPE ret; \ DATA_TYPE ret; \
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
false, ATOMIC_MMU_IDX); \
atomic_trace_rmw_pre(env, addr, info); \
ret = qatomic_##X(haddr, BSWAP(val)); \ ret = qatomic_##X(haddr, BSWAP(val)); \
ATOMIC_MMU_CLEANUP; \ ATOMIC_MMU_CLEANUP; \
atomic_trace_rmw_post(env, addr, info); \ atomic_trace_rmw_post(env, addr, info); \
@ -320,14 +304,12 @@ GEN_ATOMIC_HELPER(xor_fetch)
*/ */
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ABI_TYPE xval EXTRA_ARGS) \ ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
{ \ { \
ATOMIC_MMU_DECLS; \ XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW; \ PAGE_READ | PAGE_WRITE, retaddr); \
XDATA_TYPE ldo, ldn, old, new, val = xval; \ XDATA_TYPE ldo, ldn, old, new, val = xval; \
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
false, ATOMIC_MMU_IDX); \
atomic_trace_rmw_pre(env, addr, info); \
smp_mb(); \ smp_mb(); \
ldn = qatomic_read__nocheck(haddr); \ ldn = qatomic_read__nocheck(haddr); \
do { \ do { \

View File

@ -145,6 +145,28 @@ static void init_delay_params(SyncClocks *sc, const CPUState *cpu)
} }
#endif /* CONFIG USER ONLY */ #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 */ /* Might cause an exception, so have a longjmp destination ready */
static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc, static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
target_ulong cs_base, target_ulong cs_base,
@ -205,6 +227,76 @@ static inline void log_cpu_exec(target_ulong pc, CPUState *cpu,
} }
} }
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 * helper_lookup_tb_ptr: quick check for next tb
* @env: current cpu state * @env: current cpu state
@ -218,11 +310,16 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
CPUState *cpu = env_cpu(env); CPUState *cpu = env_cpu(env);
TranslationBlock *tb; TranslationBlock *tb;
target_ulong cs_base, pc; target_ulong cs_base, pc;
uint32_t flags; uint32_t flags, cflags;
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
tb = tb_lookup(cpu, pc, cs_base, flags, curr_cflags(cpu)); 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) { if (tb == NULL) {
return tcg_code_gen_epilogue; return tcg_code_gen_epilogue;
} }
@ -313,8 +410,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
CPUArchState *env = (CPUArchState *)cpu->env_ptr; CPUArchState *env = (CPUArchState *)cpu->env_ptr;
TranslationBlock *tb; TranslationBlock *tb;
target_ulong cs_base, pc; target_ulong cs_base, pc;
uint32_t flags; uint32_t flags, cflags;
uint32_t cflags = (curr_cflags(cpu) & ~CF_PARALLEL) | 1;
int tb_exit; int tb_exit;
if (sigsetjmp(cpu->jmp_env, 0) == 0) { if (sigsetjmp(cpu->jmp_env, 0) == 0) {
@ -324,8 +420,20 @@ void cpu_exec_step_atomic(CPUState *cpu)
cpu->running = true; cpu->running = true;
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
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) { if (tb == NULL) {
mmap_lock(); mmap_lock();
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags); tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
@ -478,70 +586,6 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
return; return;
} }
//// --- Begin LibAFL code ---
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong dst_block, target_ulong cs_base,
uint32_t flags, int cflags);
//// --- End LibAFL code ---
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);
//// --- Begin LibAFL code ---
if (last_tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
mmap_lock();
TranslationBlock *edge = libafl_gen_edge(cpu, last_tb->pc, tb->pc,
cs_base, flags, cflags);
mmap_unlock();
if (edge) {
tb_add_jump(last_tb, tb_exit, edge);
tb_add_jump(edge, 0, tb);
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
//// --- End LibAFL code ---
}
return tb;
}
static inline bool cpu_handle_halt(CPUState *cpu) static inline bool cpu_handle_halt(CPUState *cpu)
{ {
if (cpu->halted) { if (cpu->halted) {
@ -802,7 +846,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
/* Ensure global icount has gone forward */ /* Ensure global icount has gone forward */
icount_update(cpu); icount_update(cpu);
/* Refill decrementer and continue execution. */ /* Refill decrementer and continue execution. */
insns_left = MIN(CF_COUNT_MASK, cpu->icount_budget); insns_left = MIN(0xffff, cpu->icount_budget);
cpu_neg(cpu)->icount_decr.u16.low = insns_left; cpu_neg(cpu)->icount_decr.u16.low = insns_left;
cpu->icount_extra = cpu->icount_budget - insns_left; cpu->icount_extra = cpu->icount_budget - insns_left;
@ -811,17 +855,26 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
* execute we need to ensure we find/generate a TB with exactly * execute we need to ensure we find/generate a TB with exactly
* insns_left instructions in it. * insns_left instructions in it.
*/ */
if (!cpu->icount_extra && insns_left > 0 && insns_left < tb->icount) { if (insns_left > 0 && insns_left < tb->icount) {
assert(insns_left <= CF_COUNT_MASK);
assert(cpu->icount_extra == 0);
cpu->cflags_next_tb = (tb->cflags & ~CF_COUNT_MASK) | insns_left; cpu->cflags_next_tb = (tb->cflags & ~CF_COUNT_MASK) | insns_left;
} }
#endif #endif
} }
//// --- Begin LibAFL code ---
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong dst_block, target_ulong cs_base,
uint32_t flags, int cflags);
//// --- End LibAFL code ---
/* main execution loop */ /* main execution loop */
int cpu_exec(CPUState *cpu) int cpu_exec(CPUState *cpu)
{ {
CPUClass *cc = CPU_GET_CLASS(cpu);
int ret; int ret;
SyncClocks sc = { 0 }; SyncClocks sc = { 0 };
@ -855,19 +908,14 @@ int cpu_exec(CPUState *cpu)
* that we support, but is still unfixed in clang: * that we support, but is still unfixed in clang:
* https://bugs.llvm.org/show_bug.cgi?id=21183 * https://bugs.llvm.org/show_bug.cgi?id=21183
* *
* Reload essential local variables here for those compilers. * Reload an essential local variable here for those compilers.
* Newer versions of gcc would complain about this code (-Wclobbered), * Newer versions of gcc would complain about this code (-Wclobbered),
* so we only perform the workaround for clang. * so we only perform the workaround for clang.
*/ */
cpu = current_cpu; cpu = current_cpu;
cc = CPU_GET_CLASS(cpu);
#else #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(cpu == current_cpu);
g_assert(cc == CPU_GET_CLASS(cpu));
#endif #endif
#ifndef CONFIG_SOFTMMU #ifndef CONFIG_SOFTMMU
@ -887,22 +935,80 @@ int cpu_exec(CPUState *cpu)
int tb_exit = 0; int tb_exit = 0;
while (!cpu_handle_interrupt(cpu, &last_tb)) { while (!cpu_handle_interrupt(cpu, &last_tb)) {
uint32_t cflags = cpu->cflags_next_tb;
TranslationBlock *tb; TranslationBlock *tb;
target_ulong cs_base, pc;
uint32_t flags, cflags;
/* When requested, use an exact setting for cflags for the next cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags);
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 * When requested, use an exact setting for cflags for the next
does not require tcg headers for cpu_common_reset. */ * 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;
if (cflags == -1) { if (cflags == -1) {
cflags = curr_cflags(cpu); cflags = curr_cflags(cpu);
} else { } else {
cpu->cflags_next_tb = -1; cpu->cflags_next_tb = -1;
} }
tb = tb_find(cpu, last_tb, tb_exit, cflags); 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);
//// --- Begin LibAFL code ---
if (last_tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
mmap_lock();
TranslationBlock *edge = libafl_gen_edge(cpu, last_tb->pc, tb->pc,
cs_base, flags, cflags);
mmap_unlock();
if (edge) {
tb_add_jump(last_tb, tb_exit, edge);
tb_add_jump(edge, 0, tb);
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
//// --- End LibAFL code ---
}
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit); cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit);
/* Try to align the host and virtual clocks /* Try to align the host and virtual clocks
if the guest is in advance */ if the guest is in advance */
align_clocks(&sc, cpu); align_clocks(&sc, cpu);

View File

@ -1728,7 +1728,7 @@ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
data->v.io.offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; data->v.io.offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr;
} else { } else {
data->is_io = false; data->is_io = false;
data->v.ram.hostaddr = addr + tlbe->addend; data->v.ram.hostaddr = (void *)((uintptr_t)addr + tlbe->addend);
} }
return true; return true;
} else { } else {
@ -2686,19 +2686,14 @@ void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val)
cpu_stq_le_data_ra(env, ptr, val, 0); cpu_stq_le_data_ra(env, ptr, val, 0);
} }
/* First set of helpers allows passing in of OI and RETADDR. This makes /*
them callable from other helpers. */ * First set of functions passes in OI and RETADDR.
* This makes them callable from other helpers.
*/
#define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr
#define ATOMIC_NAME(X) \ #define ATOMIC_NAME(X) \
HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu)) glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu)
#define ATOMIC_MMU_DECLS
#define ATOMIC_MMU_LOOKUP_RW \
atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr)
#define ATOMIC_MMU_LOOKUP_R \
atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ, retaddr)
#define ATOMIC_MMU_LOOKUP_W \
atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_WRITE, retaddr)
#define ATOMIC_MMU_CLEANUP #define ATOMIC_MMU_CLEANUP
#define ATOMIC_MMU_IDX get_mmuidx(oi) #define ATOMIC_MMU_IDX get_mmuidx(oi)
@ -2723,38 +2718,6 @@ void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val)
#include "atomic_template.h" #include "atomic_template.h"
#endif #endif
/* Second set of helpers are directly callable from TCG as helpers. */
#undef EXTRA_ARGS
#undef ATOMIC_NAME
#undef ATOMIC_MMU_LOOKUP_RW
#undef ATOMIC_MMU_LOOKUP_R
#undef ATOMIC_MMU_LOOKUP_W
#define EXTRA_ARGS , TCGMemOpIdx oi
#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END))
#define ATOMIC_MMU_LOOKUP_RW \
atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, GETPC())
#define ATOMIC_MMU_LOOKUP_R \
atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ, GETPC())
#define ATOMIC_MMU_LOOKUP_W \
atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_WRITE, GETPC())
#define DATA_SIZE 1
#include "atomic_template.h"
#define DATA_SIZE 2
#include "atomic_template.h"
#define DATA_SIZE 4
#include "atomic_template.h"
#ifdef CONFIG_ATOMIC64
#define DATA_SIZE 8
#include "atomic_template.h"
#endif
#undef ATOMIC_MMU_IDX
/* Code access functions. */ /* Code access functions. */
static uint64_t full_ldub_code(CPUArchState *env, target_ulong addr, static uint64_t full_ldub_code(CPUArchState *env, target_ulong addr,

View File

@ -39,8 +39,6 @@ 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) DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr)
#endif /* IN_HELPER_PROTO */ #endif /* IN_HELPER_PROTO */
#ifdef CONFIG_SOFTMMU
DEF_HELPER_FLAGS_5(atomic_cmpxchgb, TCG_CALL_NO_WG, DEF_HELPER_FLAGS_5(atomic_cmpxchgb, TCG_CALL_NO_WG,
i32, env, tl, i32, i32, i32) i32, env, tl, i32, i32, i32)
DEF_HELPER_FLAGS_5(atomic_cmpxchgw_be, TCG_CALL_NO_WG, DEF_HELPER_FLAGS_5(atomic_cmpxchgw_be, TCG_CALL_NO_WG,
@ -88,50 +86,6 @@ DEF_HELPER_FLAGS_5(atomic_cmpxchgq_le, TCG_CALL_NO_WG,
TCG_CALL_NO_WG, i32, env, tl, i32, i32) TCG_CALL_NO_WG, i32, env, tl, i32, i32)
#endif /* CONFIG_ATOMIC64 */ #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_add)
GEN_ATOMIC_HELPERS(fetch_and) GEN_ATOMIC_HELPERS(fetch_and)
GEN_ATOMIC_HELPERS(fetch_or) GEN_ATOMIC_HELPERS(fetch_or)

View File

@ -1841,14 +1841,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
max_insns = cflags & CF_COUNT_MASK; max_insns = cflags & CF_COUNT_MASK;
if (max_insns == 0) { if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
}
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS; max_insns = TCG_MAX_INSNS;
} }
if (cpu->singlestep_enabled || singlestep) { QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS);
max_insns = 1;
}
buffer_overflow: buffer_overflow:
tb = tcg_tb_alloc(tcg_ctx); tb = tcg_tb_alloc(tcg_ctx);

View File

@ -44,8 +44,8 @@ void translator_loop_temp_check(DisasContextBase *db)
bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
{ {
/* Suppress goto_tb in the case of single-steping. */ /* Suppress goto_tb if requested. */
if (db->singlestep_enabled || singlestep) { if (tb_cflags(db->tb) & CF_NO_GOTO_TB) {
return false; return false;
} }
@ -56,7 +56,7 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
void translator_loop(const TranslatorOps *ops, DisasContextBase *db, void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
CPUState *cpu, TranslationBlock *tb, int max_insns) CPUState *cpu, TranslationBlock *tb, int max_insns)
{ {
int bp_insn = 0; uint32_t cflags = tb_cflags(tb);
bool plugin_enabled; bool plugin_enabled;
/* Initialize DisasContext */ /* Initialize DisasContext */
@ -66,7 +66,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
db->is_jmp = DISAS_NEXT; db->is_jmp = DISAS_NEXT;
db->num_insns = 0; db->num_insns = 0;
db->max_insns = max_insns; db->max_insns = max_insns;
db->singlestep_enabled = cpu->singlestep_enabled; db->singlestep_enabled = cflags & CF_SINGLE_STEP;
ops->init_disas_context(db, cpu); ops->init_disas_context(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
@ -79,8 +79,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
ops->tb_start(db, cpu); ops->tb_start(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
plugin_enabled = plugin_gen_tb_start(cpu, tb, plugin_enabled = plugin_gen_tb_start(cpu, tb, cflags & CF_MEMI_ONLY);
tb_cflags(db->tb) & CF_MEMI_ONLY);
while (true) { while (true) {
db->num_insns++; db->num_insns++;
@ -91,27 +90,6 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
plugin_gen_insn_start(cpu, 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;
}
}
//// --- Begin LibAFL code --- //// --- Begin LibAFL code ---
struct libafl_breakpoint* bp = libafl_qemu_breakpoints; struct libafl_breakpoint* bp = libafl_qemu_breakpoints;
@ -128,14 +106,13 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
update db->pc_next and db->is_jmp to indicate what should be update db->pc_next and db->is_jmp to indicate what should be
done next -- either exiting this loop or locate the start of done next -- either exiting this loop or locate the start of
the next instruction. */ the next instruction. */
if (db->num_insns == db->max_insns if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
&& (tb_cflags(db->tb) & CF_LAST_IO)) {
/* Accept I/O on the last instruction. */ /* Accept I/O on the last instruction. */
gen_io_start(); gen_io_start();
ops->translate_insn(db, cpu); ops->translate_insn(db, cpu);
} else { } else {
/* we should only see CF_MEMI_ONLY for io_recompile */ /* we should only see CF_MEMI_ONLY for io_recompile */
tcg_debug_assert(!(tb_cflags(db->tb) & CF_MEMI_ONLY)); tcg_debug_assert(!(cflags & CF_MEMI_ONLY));
ops->translate_insn(db, cpu); ops->translate_insn(db, cpu);
} }
@ -162,7 +139,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
/* Emit code to exit the TB, as indicated by db->is_jmp. */ /* Emit code to exit the TB, as indicated by db->is_jmp. */
ops->tb_stop(db, cpu); ops->tb_stop(db, cpu);
gen_tb_end(db->tb, db->num_insns - bp_insn); gen_tb_end(db->tb, db->num_insns);
if (plugin_enabled) { if (plugin_enabled) {
plugin_gen_tb_end(cpu); plugin_gen_tb_end(cpu);

View File

@ -1221,9 +1221,14 @@ uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr)
return ret; return ret;
} }
/* Do not allow unaligned operations to proceed. Return the host address. */ /*
* Do not allow unaligned operations to proceed. Return the host address.
*
* @prot may be PAGE_READ, PAGE_WRITE, or PAGE_READ|PAGE_WRITE.
*/
static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
int size, uintptr_t retaddr) TCGMemOpIdx oi, int size, int prot,
uintptr_t retaddr)
{ {
/* Enforce qemu required alignment. */ /* Enforce qemu required alignment. */
if (unlikely(addr & (size - 1))) { if (unlikely(addr & (size - 1))) {
@ -1234,19 +1239,18 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
return ret; return ret;
} }
/* Macro to call the above, with local variables from the use context. */ #include "atomic_common.c.inc"
#define ATOMIC_MMU_DECLS do {} while (0)
#define ATOMIC_MMU_LOOKUP_RW atomic_mmu_lookup(env, addr, DATA_SIZE, GETPC()) /*
#define ATOMIC_MMU_LOOKUP_R ATOMIC_MMU_LOOKUP_RW * First set of functions passes in OI and RETADDR.
#define ATOMIC_MMU_LOOKUP_W ATOMIC_MMU_LOOKUP_RW * This makes them callable from other helpers.
*/
#define ATOMIC_NAME(X) \
glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu)
#define ATOMIC_MMU_CLEANUP do { clear_helper_retaddr(); } while (0) #define ATOMIC_MMU_CLEANUP do { clear_helper_retaddr(); } while (0)
#define ATOMIC_MMU_IDX MMU_USER_IDX #define ATOMIC_MMU_IDX MMU_USER_IDX
#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END))
#define EXTRA_ARGS
#include "atomic_common.c.inc"
#define DATA_SIZE 1 #define DATA_SIZE 1
#include "atomic_template.h" #include "atomic_template.h"
@ -1261,20 +1265,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
#include "atomic_template.h" #include "atomic_template.h"
#endif #endif
/* The following is only callable from other helpers, and matches up
with the softmmu version. */
#if HAVE_ATOMIC128 || HAVE_CMPXCHG128 #if HAVE_ATOMIC128 || HAVE_CMPXCHG128
#undef EXTRA_ARGS
#undef ATOMIC_NAME
#undef ATOMIC_MMU_LOOKUP_RW
#define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr
#define ATOMIC_NAME(X) \
HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu))
#define ATOMIC_MMU_LOOKUP_RW atomic_mmu_lookup(env, addr, DATA_SIZE, retaddr)
#define DATA_SIZE 16 #define DATA_SIZE 16
#include "atomic_template.h" #include "atomic_template.h"
#endif #endif

View File

@ -1622,10 +1622,20 @@ void audio_cleanup(void)
} }
} }
static bool vmstate_audio_needed(void *opaque)
{
/*
* Never needed, this vmstate only exists in case
* an old qemu sends it to us.
*/
return false;
}
static const VMStateDescription vmstate_audio = { static const VMStateDescription vmstate_audio = {
.name = "audio", .name = "audio",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.needed = vmstate_audio_needed,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }

View File

@ -6162,6 +6162,9 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
void bdrv_init(void) void bdrv_init(void)
{ {
#ifdef CONFIG_BDRV_WHITELIST_TOOLS
use_bdrv_whitelist = 1;
#endif
module_call_init(MODULE_INIT_BLOCK); module_call_init(MODULE_INIT_BLOCK);
} }

View File

@ -38,25 +38,27 @@
#include "qapi/qobject-input-visitor.h" #include "qapi/qobject-input-visitor.h"
#include "sysemu/qtest.h" #include "sysemu/qtest.h"
/* All APIs are thread-safe */
typedef struct BDRVBlkdebugState { typedef struct BDRVBlkdebugState {
int state; /* IN: initialized in blkdebug_open() and never changed */
int new_state;
uint64_t align; uint64_t align;
uint64_t max_transfer; uint64_t max_transfer;
uint64_t opt_write_zero; uint64_t opt_write_zero;
uint64_t max_write_zero; uint64_t max_write_zero;
uint64_t opt_discard; uint64_t opt_discard;
uint64_t max_discard; uint64_t max_discard;
char *config_file; /* For blkdebug_refresh_filename() */
/* initialized in blkdebug_parse_perms() */
uint64_t take_child_perms; uint64_t take_child_perms;
uint64_t unshare_child_perms; uint64_t unshare_child_perms;
/* For blkdebug_refresh_filename() */ /* State. Protected by lock */
char *config_file; int state;
QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX]; QLIST_HEAD(, BlkdebugRule) rules[BLKDBG__MAX];
QSIMPLEQ_HEAD(, BlkdebugRule) active_rules; QSIMPLEQ_HEAD(, BlkdebugRule) active_rules;
QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs; QLIST_HEAD(, BlkdebugSuspendedReq) suspended_reqs;
QemuMutex lock;
} BDRVBlkdebugState; } BDRVBlkdebugState;
typedef struct BlkdebugAIOCB { typedef struct BlkdebugAIOCB {
@ -65,8 +67,11 @@ typedef struct BlkdebugAIOCB {
} BlkdebugAIOCB; } BlkdebugAIOCB;
typedef struct BlkdebugSuspendedReq { typedef struct BlkdebugSuspendedReq {
/* IN: initialized in suspend_request() */
Coroutine *co; Coroutine *co;
char *tag; char *tag;
/* List entry protected BDRVBlkdebugState's lock */
QLIST_ENTRY(BlkdebugSuspendedReq) next; QLIST_ENTRY(BlkdebugSuspendedReq) next;
} BlkdebugSuspendedReq; } BlkdebugSuspendedReq;
@ -74,9 +79,11 @@ enum {
ACTION_INJECT_ERROR, ACTION_INJECT_ERROR,
ACTION_SET_STATE, ACTION_SET_STATE,
ACTION_SUSPEND, ACTION_SUSPEND,
ACTION__MAX,
}; };
typedef struct BlkdebugRule { typedef struct BlkdebugRule {
/* IN: initialized in add_rule() or blkdebug_debug_breakpoint() */
BlkdebugEvent event; BlkdebugEvent event;
int action; int action;
int state; int state;
@ -95,6 +102,8 @@ typedef struct BlkdebugRule {
char *tag; char *tag;
} suspend; } suspend;
} options; } options;
/* List entries protected BDRVBlkdebugState's lock */
QLIST_ENTRY(BlkdebugRule) next; QLIST_ENTRY(BlkdebugRule) next;
QSIMPLEQ_ENTRY(BlkdebugRule) active_next; QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
} BlkdebugRule; } BlkdebugRule;
@ -244,11 +253,14 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
}; };
/* Add the rule */ /* Add the rule */
qemu_mutex_lock(&s->lock);
QLIST_INSERT_HEAD(&s->rules[event], rule, next); QLIST_INSERT_HEAD(&s->rules[event], rule, next);
qemu_mutex_unlock(&s->lock);
return 0; return 0;
} }
/* Called with lock held or from .bdrv_close */
static void remove_rule(BlkdebugRule *rule) static void remove_rule(BlkdebugRule *rule)
{ {
switch (rule->action) { switch (rule->action) {
@ -467,6 +479,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
uint64_t align; uint64_t align;
qemu_mutex_init(&s->lock);
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
if (!qemu_opts_absorb_qdict(opts, options, errp)) { if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL; ret = -EINVAL;
@ -567,6 +580,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
ret = 0; ret = 0;
out: out:
if (ret < 0) { if (ret < 0) {
qemu_mutex_destroy(&s->lock);
g_free(s->config_file); g_free(s->config_file);
} }
qemu_opts_del(opts); qemu_opts_del(opts);
@ -581,6 +595,7 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
int error; int error;
bool immediately; bool immediately;
qemu_mutex_lock(&s->lock);
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
uint64_t inject_offset = rule->options.inject.offset; uint64_t inject_offset = rule->options.inject.offset;
@ -594,6 +609,7 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
} }
if (!rule || !rule->options.inject.error) { if (!rule || !rule->options.inject.error) {
qemu_mutex_unlock(&s->lock);
return 0; return 0;
} }
@ -605,6 +621,7 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
remove_rule(rule); remove_rule(rule);
} }
qemu_mutex_unlock(&s->lock);
if (!immediately) { if (!immediately) {
aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self()); aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
qemu_coroutine_yield(); qemu_coroutine_yield();
@ -770,78 +787,80 @@ static void blkdebug_close(BlockDriverState *bs)
} }
g_free(s->config_file); g_free(s->config_file);
qemu_mutex_destroy(&s->lock);
} }
/* Called with lock held. */
static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule) static void suspend_request(BlockDriverState *bs, BlkdebugRule *rule)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
BlkdebugSuspendedReq r; BlkdebugSuspendedReq *r;
r = (BlkdebugSuspendedReq) { r = g_new(BlkdebugSuspendedReq, 1);
.co = qemu_coroutine_self(),
.tag = g_strdup(rule->options.suspend.tag), r->co = qemu_coroutine_self();
}; r->tag = g_strdup(rule->options.suspend.tag);
remove_rule(rule); remove_rule(rule);
QLIST_INSERT_HEAD(&s->suspended_reqs, &r, next); QLIST_INSERT_HEAD(&s->suspended_reqs, r, next);
if (!qtest_enabled()) { if (!qtest_enabled()) {
printf("blkdebug: Suspended request '%s'\n", r.tag); printf("blkdebug: Suspended request '%s'\n", r->tag);
} }
qemu_coroutine_yield();
if (!qtest_enabled()) {
printf("blkdebug: Resuming request '%s'\n", r.tag);
} }
QLIST_REMOVE(&r, next); /* Called with lock held. */
g_free(r.tag); static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
} int *action_count, int *new_state)
static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
bool injected)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
/* Only process rules for the current state */ /* Only process rules for the current state */
if (rule->state && rule->state != s->state) { if (rule->state && rule->state != s->state) {
return injected; return;
} }
/* Take the action */ /* Take the action */
action_count[rule->action]++;
switch (rule->action) { switch (rule->action) {
case ACTION_INJECT_ERROR: case ACTION_INJECT_ERROR:
if (!injected) { if (action_count[ACTION_INJECT_ERROR] == 1) {
QSIMPLEQ_INIT(&s->active_rules); QSIMPLEQ_INIT(&s->active_rules);
injected = true;
} }
QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next); QSIMPLEQ_INSERT_HEAD(&s->active_rules, rule, active_next);
break; break;
case ACTION_SET_STATE: case ACTION_SET_STATE:
s->new_state = rule->options.set_state.new_state; *new_state = rule->options.set_state.new_state;
break; break;
case ACTION_SUSPEND: case ACTION_SUSPEND:
suspend_request(bs, rule); suspend_request(bs, rule);
break; break;
} }
return injected;
} }
static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event) static void blkdebug_debug_event(BlockDriverState *bs, BlkdebugEvent event)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
struct BlkdebugRule *rule, *next; struct BlkdebugRule *rule, *next;
bool injected; int new_state;
int actions_count[ACTION__MAX] = { 0 };
assert((int)event >= 0 && event < BLKDBG__MAX); assert((int)event >= 0 && event < BLKDBG__MAX);
injected = false; WITH_QEMU_LOCK_GUARD(&s->lock) {
s->new_state = s->state; new_state = s->state;
QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) { QLIST_FOREACH_SAFE(rule, &s->rules[event], next, next) {
injected = process_rule(bs, rule, injected); process_rule(bs, rule, actions_count, &new_state);
}
s->state = new_state;
}
while (actions_count[ACTION_SUSPEND] > 0) {
qemu_coroutine_yield();
actions_count[ACTION_SUSPEND]--;
} }
s->state = s->new_state;
} }
static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event, static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
@ -864,33 +883,64 @@ static int blkdebug_debug_breakpoint(BlockDriverState *bs, const char *event,
.options.suspend.tag = g_strdup(tag), .options.suspend.tag = g_strdup(tag),
}; };
qemu_mutex_lock(&s->lock);
QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next); QLIST_INSERT_HEAD(&s->rules[blkdebug_event], rule, next);
qemu_mutex_unlock(&s->lock);
return 0; return 0;
} }
static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag) /* Called with lock held. May temporarily release lock. */
static int resume_req_by_tag(BDRVBlkdebugState *s, const char *tag, bool all)
{ {
BDRVBlkdebugState *s = bs->opaque; BlkdebugSuspendedReq *r;
BlkdebugSuspendedReq *r, *next;
QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, next) { retry:
/*
* No need for _SAFE, since a different coroutine can remove another node
* (not the current one) in this list, and when the current one is removed
* the iteration starts back from beginning anyways.
*/
QLIST_FOREACH(r, &s->suspended_reqs, next) {
if (!strcmp(r->tag, tag)) { if (!strcmp(r->tag, tag)) {
qemu_coroutine_enter(r->co); Coroutine *co = r->co;
if (!qtest_enabled()) {
printf("blkdebug: Resuming request '%s'\n", r->tag);
}
QLIST_REMOVE(r, next);
g_free(r->tag);
g_free(r);
qemu_mutex_unlock(&s->lock);
qemu_coroutine_enter(co);
qemu_mutex_lock(&s->lock);
if (all) {
goto retry;
}
return 0; return 0;
} }
} }
return -ENOENT; return -ENOENT;
} }
static int blkdebug_debug_resume(BlockDriverState *bs, const char *tag)
{
BDRVBlkdebugState *s = bs->opaque;
QEMU_LOCK_GUARD(&s->lock);
return resume_req_by_tag(s, tag, false);
}
static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs, static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
const char *tag) const char *tag)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
BlkdebugSuspendedReq *r, *r_next;
BlkdebugRule *rule, *next; BlkdebugRule *rule, *next;
int i, ret = -ENOENT; int i, ret = -ENOENT;
QEMU_LOCK_GUARD(&s->lock);
for (i = 0; i < BLKDBG__MAX; i++) { for (i = 0; i < BLKDBG__MAX; i++) {
QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) { QLIST_FOREACH_SAFE(rule, &s->rules[i], next, next) {
if (rule->action == ACTION_SUSPEND && if (rule->action == ACTION_SUSPEND &&
@ -900,12 +950,9 @@ static int blkdebug_debug_remove_breakpoint(BlockDriverState *bs,
} }
} }
} }
QLIST_FOREACH_SAFE(r, &s->suspended_reqs, next, r_next) { if (resume_req_by_tag(s, tag, true) == 0) {
if (!strcmp(r->tag, tag)) {
qemu_coroutine_enter(r->co);
ret = 0; ret = 0;
} }
}
return ret; return ret;
} }
@ -914,6 +961,7 @@ static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
BlkdebugSuspendedReq *r; BlkdebugSuspendedReq *r;
QEMU_LOCK_GUARD(&s->lock);
QLIST_FOREACH(r, &s->suspended_reqs, next) { QLIST_FOREACH(r, &s->suspended_reqs, next) {
if (!strcmp(r->tag, tag)) { if (!strcmp(r->tag, tag)) {
return true; return true;

View File

@ -193,7 +193,7 @@ int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags,
error_setg(errp, "Bitmap '%s' is inconsistent and cannot be used", error_setg(errp, "Bitmap '%s' is inconsistent and cannot be used",
bitmap->name); bitmap->name);
error_append_hint(errp, "Try block-dirty-bitmap-remove to delete" error_append_hint(errp, "Try block-dirty-bitmap-remove to delete"
" this bitmap from disk"); " this bitmap from disk\n");
return -1; return -1;
} }

View File

@ -111,6 +111,7 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
if (export->has_iothread) { if (export->has_iothread) {
IOThread *iothread; IOThread *iothread;
AioContext *new_ctx; AioContext *new_ctx;
Error **set_context_errp;
iothread = iothread_by_id(export->iothread); iothread = iothread_by_id(export->iothread);
if (!iothread) { if (!iothread) {
@ -120,7 +121,9 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
new_ctx = iothread_get_aio_context(iothread); new_ctx = iothread_get_aio_context(iothread);
ret = bdrv_try_set_aio_context(bs, new_ctx, errp); /* Ignore errors with fixed-iothread=false */
set_context_errp = fixed_iothread ? errp : NULL;
ret = bdrv_try_set_aio_context(bs, new_ctx, set_context_errp);
if (ret == 0) { if (ret == 0) {
aio_context_release(ctx); aio_context_release(ctx);
aio_context_acquire(new_ctx); aio_context_acquire(new_ctx);

View File

@ -635,7 +635,9 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
offset += size; offset += size;
length -= size; length -= size;
} while (ret == 0 && length > 0); } while (ret == 0 && length > 0);
} else if (mode & FALLOC_FL_ZERO_RANGE) { }
#ifdef CONFIG_FALLOCATE_ZERO_RANGE
else if (mode & FALLOC_FL_ZERO_RANGE) {
if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + length > blk_len) { if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + length > blk_len) {
/* No need for zeroes, we are going to write them ourselves */ /* No need for zeroes, we are going to write them ourselves */
ret = fuse_do_truncate(exp, offset + length, false, ret = fuse_do_truncate(exp, offset + length, false,
@ -654,7 +656,9 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
offset += size; offset += size;
length -= size; length -= size;
} while (ret == 0 && length > 0); } while (ret == 0 && length > 0);
} else if (!mode) { }
#endif /* CONFIG_FALLOCATE_ZERO_RANGE */
else if (!mode) {
/* We can only fallocate at the EOF with a truncate */ /* We can only fallocate at the EOF with a truncate */
if (offset < blk_len) { if (offset < blk_len) {
fuse_reply_err(req, EOPNOTSUPP); fuse_reply_err(req, EOPNOTSUPP);

View File

@ -1841,7 +1841,7 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
ret = bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad, ret = bdrv_pad_request(bs, &qiov, &qiov_offset, &offset, &bytes, &pad,
NULL); NULL);
if (ret < 0) { if (ret < 0) {
return ret; goto fail;
} }
tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ); tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_READ);
@ -1849,10 +1849,11 @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
bs->bl.request_alignment, bs->bl.request_alignment,
qiov, qiov_offset, flags); qiov, qiov_offset, flags);
tracked_request_end(&req); tracked_request_end(&req);
bdrv_dec_in_flight(bs);
bdrv_padding_destroy(&pad); bdrv_padding_destroy(&pad);
fail:
bdrv_dec_in_flight(bs);
return ret; return ret;
} }

View File

@ -165,7 +165,21 @@ static void luring_process_completions(LuringState *s)
total_bytes = ret + luringcb->total_read; total_bytes = ret + luringcb->total_read;
if (ret < 0) { if (ret < 0) {
if (ret == -EINTR) { /*
* Only writev/readv/fsync requests on regular files or host block
* devices are submitted. Therefore -EAGAIN is not expected but it's
* known to happen sometimes with Linux SCSI. Submit again and hope
* the request completes successfully.
*
* For more information, see:
* https://lore.kernel.org/io-uring/20210727165811.284510-3-axboe@kernel.dk/T/#u
*
* If the code is changed to submit other types of requests in the
* future, then this workaround may need to be extended to deal with
* genuine -EAGAIN results that should not be resubmitted
* immediately.
*/
if (ret == -EINTR || ret == -EAGAIN) {
luring_resubmit(s, luringcb); luring_resubmit(s, luringcb);
continue; continue;
} }

View File

@ -28,6 +28,9 @@
*/ */
#define MAX_EVENTS 1024 #define MAX_EVENTS 1024
/* Maximum number of requests in a batch. (default value) */
#define DEFAULT_MAX_BATCH 32
struct qemu_laiocb { struct qemu_laiocb {
Coroutine *co; Coroutine *co;
LinuxAioState *ctx; LinuxAioState *ctx;
@ -351,6 +354,10 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
LinuxAioState *s = laiocb->ctx; LinuxAioState *s = laiocb->ctx;
struct iocb *iocbs = &laiocb->iocb; struct iocb *iocbs = &laiocb->iocb;
QEMUIOVector *qiov = laiocb->qiov; QEMUIOVector *qiov = laiocb->qiov;
int64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH;
/* limit the batch with the number of available events */
max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch);
switch (type) { switch (type) {
case QEMU_AIO_WRITE: case QEMU_AIO_WRITE:
@ -371,7 +378,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
s->io_q.in_queue++; s->io_q.in_queue++;
if (!s->io_q.blocked && if (!s->io_q.blocked &&
(!s->io_q.plugged || (!s->io_q.plugged ||
s->io_q.in_flight + s->io_q.in_queue >= MAX_EVENTS)) { s->io_q.in_queue >= max_batch)) {
ioq_submit(s); ioq_submit(s);
} }

View File

@ -107,6 +107,7 @@ struct MirrorOp {
bool is_in_flight; bool is_in_flight;
CoQueue waiting_requests; CoQueue waiting_requests;
Coroutine *co; Coroutine *co;
MirrorOp *waiting_for_op;
QTAILQ_ENTRY(MirrorOp) next; QTAILQ_ENTRY(MirrorOp) next;
}; };
@ -159,7 +160,18 @@ static void coroutine_fn mirror_wait_on_conflicts(MirrorOp *self,
if (ranges_overlap(self_start_chunk, self_nb_chunks, if (ranges_overlap(self_start_chunk, self_nb_chunks,
op_start_chunk, op_nb_chunks)) op_start_chunk, op_nb_chunks))
{ {
/*
* If the operation is already (indirectly) waiting for us, or
* will wait for us as soon as it wakes up, then just go on
* (instead of producing a deadlock in the former case).
*/
if (op->waiting_for_op) {
continue;
}
self->waiting_for_op = op;
qemu_co_queue_wait(&op->waiting_requests, NULL); qemu_co_queue_wait(&op->waiting_requests, NULL);
self->waiting_for_op = NULL;
break; break;
} }
} }
@ -1343,6 +1355,7 @@ static MirrorOp *coroutine_fn active_write_prepare(MirrorBlockJob *s,
.bytes = bytes, .bytes = bytes,
.is_active_write = true, .is_active_write = true,
.is_in_flight = true, .is_in_flight = true,
.co = qemu_coroutine_self(),
}; };
qemu_co_queue_init(&op->waiting_requests); qemu_co_queue_init(&op->waiting_requests);
QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next); QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next);

View File

@ -371,6 +371,9 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs,
return -ECONNREFUSED; return -ECONNREFUSED;
} }
yank_register_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name), nbd_yank,
bs);
ret = nbd_handle_updated_info(s->bs, NULL); ret = nbd_handle_updated_info(s->bs, NULL);
if (ret < 0) { if (ret < 0) {
/* /*
@ -381,6 +384,8 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs,
nbd_send_request(s->ioc, &request); nbd_send_request(s->ioc, &request);
yank_unregister_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name),
nbd_yank, bs);
object_unref(OBJECT(s->ioc)); object_unref(OBJECT(s->ioc));
s->ioc = NULL; s->ioc = NULL;
@ -390,9 +395,6 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs,
qio_channel_set_blocking(s->ioc, false, NULL); qio_channel_set_blocking(s->ioc, false, NULL);
qio_channel_attach_aio_context(s->ioc, bdrv_get_aio_context(bs)); qio_channel_attach_aio_context(s->ioc, bdrv_get_aio_context(bs));
yank_register_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name), nbd_yank,
bs);
/* successfully connected */ /* successfully connected */
s->state = NBD_CLIENT_CONNECTED; s->state = NBD_CLIENT_CONNECTED;
qemu_co_queue_restart_all(&s->free_sema); qemu_co_queue_restart_all(&s->free_sema);

View File

@ -1030,7 +1030,29 @@ try_map:
r = qemu_vfio_dma_map(s->vfio, r = qemu_vfio_dma_map(s->vfio,
qiov->iov[i].iov_base, qiov->iov[i].iov_base,
len, true, &iova); len, true, &iova);
if (r == -ENOSPC) {
/*
* In addition to the -ENOMEM error, the VFIO_IOMMU_MAP_DMA
* ioctl returns -ENOSPC to signal the user exhausted the DMA
* mappings available for a container since Linux kernel commit
* 492855939bdb ("vfio/type1: Limit DMA mappings per container",
* April 2019, see CVE-2019-3882).
*
* This block driver already handles this error path by checking
* for the -ENOMEM error, so we directly replace -ENOSPC by
* -ENOMEM. Beside, -ENOSPC has a specific meaning for blockdev
* coroutines: it triggers BLOCKDEV_ON_ERROR_ENOSPC and
* BLOCK_ERROR_ACTION_STOP which stops the VM, asking the operator
* to add more storage to the blockdev. Not something we can do
* easily with an IOMMU :)
*/
r = -ENOMEM;
}
if (r == -ENOMEM && retry) { if (r == -ENOMEM && retry) {
/*
* We exhausted the DMA mappings available for our container:
* recycle the volatile IOVA mappings.
*/
retry = false; retry = false;
trace_nvme_dma_flush_queue_wait(s); trace_nvme_dma_flush_queue_wait(s);
if (s->dma_map_count) { if (s->dma_map_count) {

View File

@ -35,7 +35,6 @@ typedef enum {
typedef struct BDRVReplicationState { typedef struct BDRVReplicationState {
ReplicationMode mode; ReplicationMode mode;
ReplicationStage stage; ReplicationStage stage;
BdrvChild *active_disk;
BlockJob *commit_job; BlockJob *commit_job;
BdrvChild *hidden_disk; BdrvChild *hidden_disk;
BdrvChild *secondary_disk; BdrvChild *secondary_disk;
@ -166,7 +165,12 @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c,
uint64_t perm, uint64_t shared, uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared) uint64_t *nperm, uint64_t *nshared)
{ {
if (role & BDRV_CHILD_PRIMARY) {
*nperm = BLK_PERM_CONSISTENT_READ; *nperm = BLK_PERM_CONSISTENT_READ;
} else {
*nperm = 0;
}
if ((bs->open_flags & (BDRV_O_INACTIVE | BDRV_O_RDWR)) == BDRV_O_RDWR) { if ((bs->open_flags & (BDRV_O_INACTIVE | BDRV_O_RDWR)) == BDRV_O_RDWR) {
*nperm |= BLK_PERM_WRITE; *nperm |= BLK_PERM_WRITE;
} }
@ -307,8 +311,10 @@ out:
return ret; return ret;
} }
static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp) static void secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
{ {
BDRVReplicationState *s = bs->opaque;
BdrvChild *active_disk = bs->file;
Error *local_err = NULL; Error *local_err = NULL;
int ret; int ret;
@ -323,13 +329,13 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
return; return;
} }
if (!s->active_disk->bs->drv) { if (!active_disk->bs->drv) {
error_setg(errp, "Active disk %s is ejected", error_setg(errp, "Active disk %s is ejected",
s->active_disk->bs->node_name); active_disk->bs->node_name);
return; return;
} }
ret = bdrv_make_empty(s->active_disk, errp); ret = bdrv_make_empty(active_disk, errp);
if (ret < 0) { if (ret < 0) {
return; return;
} }
@ -340,17 +346,7 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
return; return;
} }
BlockBackend *blk = blk_new(qemu_get_current_aio_context(), ret = bdrv_make_empty(s->hidden_disk, errp);
BLK_PERM_WRITE, BLK_PERM_ALL);
blk_insert_bs(blk, s->hidden_disk->bs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
blk_unref(blk);
return;
}
ret = blk_make_empty(blk, errp);
blk_unref(blk);
if (ret < 0) { if (ret < 0) {
return; return;
} }
@ -365,27 +361,35 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
Error **errp) Error **errp)
{ {
BDRVReplicationState *s = bs->opaque; BDRVReplicationState *s = bs->opaque;
BdrvChild *hidden_disk, *secondary_disk;
BlockReopenQueue *reopen_queue = NULL; BlockReopenQueue *reopen_queue = NULL;
/*
* s->hidden_disk and s->secondary_disk may not be set yet, as they will
* only be set after the children are writable.
*/
hidden_disk = bs->file->bs->backing;
secondary_disk = hidden_disk->bs->backing;
if (writable) { if (writable) {
s->orig_hidden_read_only = bdrv_is_read_only(s->hidden_disk->bs); s->orig_hidden_read_only = bdrv_is_read_only(hidden_disk->bs);
s->orig_secondary_read_only = bdrv_is_read_only(s->secondary_disk->bs); s->orig_secondary_read_only = bdrv_is_read_only(secondary_disk->bs);
} }
bdrv_subtree_drained_begin(s->hidden_disk->bs); bdrv_subtree_drained_begin(hidden_disk->bs);
bdrv_subtree_drained_begin(s->secondary_disk->bs); bdrv_subtree_drained_begin(secondary_disk->bs);
if (s->orig_hidden_read_only) { if (s->orig_hidden_read_only) {
QDict *opts = qdict_new(); QDict *opts = qdict_new();
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable); qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, reopen_queue = bdrv_reopen_queue(reopen_queue, hidden_disk->bs,
opts, true); opts, true);
} }
if (s->orig_secondary_read_only) { if (s->orig_secondary_read_only) {
QDict *opts = qdict_new(); QDict *opts = qdict_new();
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable); qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs, reopen_queue = bdrv_reopen_queue(reopen_queue, secondary_disk->bs,
opts, true); opts, true);
} }
@ -400,8 +404,8 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
} }
} }
bdrv_subtree_drained_end(s->hidden_disk->bs); bdrv_subtree_drained_end(hidden_disk->bs);
bdrv_subtree_drained_end(s->secondary_disk->bs); bdrv_subtree_drained_end(secondary_disk->bs);
} }
static void backup_job_cleanup(BlockDriverState *bs) static void backup_job_cleanup(BlockDriverState *bs)
@ -458,6 +462,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
BlockDriverState *bs = rs->opaque; BlockDriverState *bs = rs->opaque;
BDRVReplicationState *s; BDRVReplicationState *s;
BlockDriverState *top_bs; BlockDriverState *top_bs;
BdrvChild *active_disk, *hidden_disk, *secondary_disk;
int64_t active_length, hidden_length, disk_length; int64_t active_length, hidden_length, disk_length;
AioContext *aio_context; AioContext *aio_context;
Error *local_err = NULL; Error *local_err = NULL;
@ -495,32 +500,31 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
case REPLICATION_MODE_PRIMARY: case REPLICATION_MODE_PRIMARY:
break; break;
case REPLICATION_MODE_SECONDARY: case REPLICATION_MODE_SECONDARY:
s->active_disk = bs->file; active_disk = bs->file;
if (!s->active_disk || !s->active_disk->bs || if (!active_disk || !active_disk->bs || !active_disk->bs->backing) {
!s->active_disk->bs->backing) {
error_setg(errp, "Active disk doesn't have backing file"); error_setg(errp, "Active disk doesn't have backing file");
aio_context_release(aio_context); aio_context_release(aio_context);
return; return;
} }
s->hidden_disk = s->active_disk->bs->backing; hidden_disk = active_disk->bs->backing;
if (!s->hidden_disk->bs || !s->hidden_disk->bs->backing) { if (!hidden_disk->bs || !hidden_disk->bs->backing) {
error_setg(errp, "Hidden disk doesn't have backing file"); error_setg(errp, "Hidden disk doesn't have backing file");
aio_context_release(aio_context); aio_context_release(aio_context);
return; return;
} }
s->secondary_disk = s->hidden_disk->bs->backing; secondary_disk = hidden_disk->bs->backing;
if (!s->secondary_disk->bs || !bdrv_has_blk(s->secondary_disk->bs)) { if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) {
error_setg(errp, "The secondary disk doesn't have block backend"); error_setg(errp, "The secondary disk doesn't have block backend");
aio_context_release(aio_context); aio_context_release(aio_context);
return; return;
} }
/* verify the length */ /* verify the length */
active_length = bdrv_getlength(s->active_disk->bs); active_length = bdrv_getlength(active_disk->bs);
hidden_length = bdrv_getlength(s->hidden_disk->bs); hidden_length = bdrv_getlength(hidden_disk->bs);
disk_length = bdrv_getlength(s->secondary_disk->bs); disk_length = bdrv_getlength(secondary_disk->bs);
if (active_length < 0 || hidden_length < 0 || disk_length < 0 || if (active_length < 0 || hidden_length < 0 || disk_length < 0 ||
active_length != hidden_length || hidden_length != disk_length) { active_length != hidden_length || hidden_length != disk_length) {
error_setg(errp, "Active disk, hidden disk, secondary disk's length" error_setg(errp, "Active disk, hidden disk, secondary disk's length"
@ -530,10 +534,10 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
} }
/* Must be true, or the bdrv_getlength() calls would have failed */ /* Must be true, or the bdrv_getlength() calls would have failed */
assert(s->active_disk->bs->drv && s->hidden_disk->bs->drv); assert(active_disk->bs->drv && hidden_disk->bs->drv);
if (!s->active_disk->bs->drv->bdrv_make_empty || if (!active_disk->bs->drv->bdrv_make_empty ||
!s->hidden_disk->bs->drv->bdrv_make_empty) { !hidden_disk->bs->drv->bdrv_make_empty) {
error_setg(errp, error_setg(errp,
"Active disk or hidden disk doesn't support make_empty"); "Active disk or hidden disk doesn't support make_empty");
aio_context_release(aio_context); aio_context_release(aio_context);
@ -548,6 +552,26 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
return; return;
} }
bdrv_ref(hidden_disk->bs);
s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk",
&child_of_bds, BDRV_CHILD_DATA,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
aio_context_release(aio_context);
return;
}
bdrv_ref(secondary_disk->bs);
s->secondary_disk = bdrv_attach_child(bs, secondary_disk->bs,
"secondary disk", &child_of_bds,
BDRV_CHILD_DATA, &local_err);
if (local_err) {
error_propagate(errp, local_err);
aio_context_release(aio_context);
return;
}
/* start backup job now */ /* start backup job now */
error_setg(&s->blocker, error_setg(&s->blocker,
"Block device is in use by internal backup job"); "Block device is in use by internal backup job");
@ -586,7 +610,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
s->stage = BLOCK_REPLICATION_RUNNING; s->stage = BLOCK_REPLICATION_RUNNING;
if (s->mode == REPLICATION_MODE_SECONDARY) { if (s->mode == REPLICATION_MODE_SECONDARY) {
secondary_do_checkpoint(s, errp); secondary_do_checkpoint(bs, errp);
} }
s->error = 0; s->error = 0;
@ -615,7 +639,7 @@ static void replication_do_checkpoint(ReplicationState *rs, Error **errp)
} }
if (s->mode == REPLICATION_MODE_SECONDARY) { if (s->mode == REPLICATION_MODE_SECONDARY) {
secondary_do_checkpoint(s, errp); secondary_do_checkpoint(bs, errp);
} }
aio_context_release(aio_context); aio_context_release(aio_context);
} }
@ -652,8 +676,9 @@ static void replication_done(void *opaque, int ret)
if (ret == 0) { if (ret == 0) {
s->stage = BLOCK_REPLICATION_DONE; s->stage = BLOCK_REPLICATION_DONE;
s->active_disk = NULL; bdrv_unref_child(bs, s->secondary_disk);
s->secondary_disk = NULL; s->secondary_disk = NULL;
bdrv_unref_child(bs, s->hidden_disk);
s->hidden_disk = NULL; s->hidden_disk = NULL;
s->error = 0; s->error = 0;
} else { } else {
@ -705,7 +730,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
} }
if (!failover) { if (!failover) {
secondary_do_checkpoint(s, errp); secondary_do_checkpoint(bs, errp);
s->stage = BLOCK_REPLICATION_DONE; s->stage = BLOCK_REPLICATION_DONE;
aio_context_release(aio_context); aio_context_release(aio_context);
return; return;
@ -713,7 +738,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
s->stage = BLOCK_REPLICATION_FAILOVER; s->stage = BLOCK_REPLICATION_FAILOVER;
s->commit_job = commit_active_start( s->commit_job = commit_active_start(
NULL, s->active_disk->bs, s->secondary_disk->bs, NULL, bs->file->bs, s->secondary_disk->bs,
JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
NULL, replication_done, bs, true, errp); NULL, replication_done, bs, true, errp);
break; break;

View File

@ -3098,26 +3098,6 @@ static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs,
return BDRV_BLOCK_DATA; return BDRV_BLOCK_DATA;
} }
static int coroutine_fn
write_target_commit(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
int ret;
BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque);
qemu_co_mutex_lock(&s->lock);
ret = try_commit(s);
qemu_co_mutex_unlock(&s->lock);
return ret;
}
static BlockDriver vvfat_write_target = {
.format_name = "vvfat_write_target",
.instance_size = sizeof(void*),
.bdrv_co_pwritev = write_target_commit,
};
static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format, static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format,
int *child_flags, QDict *child_options, int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options) int parent_flags, QDict *parent_options)
@ -3133,7 +3113,6 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
{ {
BDRVVVFATState *s = bs->opaque; BDRVVVFATState *s = bs->opaque;
BlockDriver *bdrv_qcow = NULL; BlockDriver *bdrv_qcow = NULL;
BlockDriverState *backing;
QemuOpts *opts = NULL; QemuOpts *opts = NULL;
int ret; int ret;
int size = sector2cluster(s, s->sector_count); int size = sector2cluster(s, s->sector_count);
@ -3184,13 +3163,6 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
unlink(s->qcow_filename); unlink(s->qcow_filename);
#endif #endif
backing = bdrv_new_open_driver(&vvfat_write_target, NULL, BDRV_O_ALLOW_RDWR,
&error_abort);
*(void**) backing->opaque = s;
bdrv_set_backing_hd(s->bs, backing, &error_abort);
bdrv_unref(backing);
return 0; return 0;
err: err:
@ -3205,17 +3177,10 @@ static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c,
uint64_t perm, uint64_t shared, uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared) uint64_t *nperm, uint64_t *nshared)
{ {
if (role & BDRV_CHILD_DATA) { assert(role & BDRV_CHILD_DATA);
/* This is a private node, nobody should try to attach to it */ /* This is a private node, nobody should try to attach to it */
*nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
*nshared = BLK_PERM_WRITE_UNCHANGED; *nshared = BLK_PERM_WRITE_UNCHANGED;
} else {
assert(role & BDRV_CHILD_COW);
/* The backing file is there so 'commit' can use it. vvfat doesn't
* access it in any way. */
*nperm = 0;
*nshared = BLK_PERM_ALL;
}
} }
static void vvfat_close(BlockDriverState *bs) static void vvfat_close(BlockDriverState *bs)

View File

@ -335,7 +335,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
_mcleanup(); _mcleanup();
#endif #endif
gdb_exit(arg1); gdb_exit(arg1);
qemu_plugin_atexit_cb(); qemu_plugin_user_exit();
/* XXX: should free thread stack and CPU env */ /* XXX: should free thread stack and CPU env */
_exit(arg1); _exit(arg1);
ret = 0; /* avoid warning */ ret = 0; /* avoid warning */
@ -437,7 +437,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
_mcleanup(); _mcleanup();
#endif #endif
gdb_exit(arg1); gdb_exit(arg1);
qemu_plugin_atexit_cb(); qemu_plugin_user_exit();
/* XXX: should free thread stack and CPU env */ /* XXX: should free thread stack and CPU env */
_exit(arg1); _exit(arg1);
ret = 0; /* avoid warning */ ret = 0; /* avoid warning */
@ -516,7 +516,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
_mcleanup(); _mcleanup();
#endif #endif
gdb_exit(arg1); gdb_exit(arg1);
qemu_plugin_atexit_cb(); qemu_plugin_user_exit();
/* XXX: should free thread stack and CPU env */ /* XXX: should free thread stack and CPU env */
_exit(arg1); _exit(arg1);
ret = 0; /* avoid warning */ ret = 0; /* avoid warning */

View File

@ -28,6 +28,7 @@
#include "qemu/sockets.h" #include "qemu/sockets.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "chardev/char.h" #include "chardev/char.h"
#include "chardev/char-fe.h"
#include "io/channel-file.h" #include "io/channel-file.h"
#include "chardev/char-fd.h" #include "chardev/char-fd.h"
@ -38,6 +39,10 @@ static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
{ {
FDChardev *s = FD_CHARDEV(chr); FDChardev *s = FD_CHARDEV(chr);
if (!s->ioc_out) {
return -1;
}
return io_channel_send(s->ioc_out, buf, len); return io_channel_send(s->ioc_out, buf, len);
} }
@ -80,10 +85,85 @@ static int fd_chr_read_poll(void *opaque)
return s->max_size; return s->max_size;
} }
typedef struct FDSource {
GSource parent;
GIOCondition cond;
} FDSource;
static gboolean
fd_source_prepare(GSource *source,
gint *timeout_)
{
FDSource *src = (FDSource *)source;
return src->cond != 0;
}
static gboolean
fd_source_check(GSource *source)
{
FDSource *src = (FDSource *)source;
return src->cond != 0;
}
static gboolean
fd_source_dispatch(GSource *source, GSourceFunc callback,
gpointer user_data)
{
FDSource *src = (FDSource *)source;
FEWatchFunc func = (FEWatchFunc)callback;
gboolean ret = G_SOURCE_CONTINUE;
if (src->cond) {
ret = func(NULL, src->cond, user_data);
src->cond = 0;
}
return ret;
}
static GSourceFuncs fd_source_funcs = {
fd_source_prepare,
fd_source_check,
fd_source_dispatch,
NULL, NULL, NULL
};
static GSource *fd_source_new(FDChardev *chr)
{
return g_source_new(&fd_source_funcs, sizeof(FDSource));
}
static gboolean child_func(GIOChannel *source,
GIOCondition condition,
gpointer data)
{
FDSource *parent = data;
parent->cond |= condition;
return G_SOURCE_CONTINUE;
}
static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond) static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
{ {
FDChardev *s = FD_CHARDEV(chr); FDChardev *s = FD_CHARDEV(chr);
return qio_channel_create_watch(s->ioc_out, cond); g_autoptr(GSource) source = fd_source_new(s);
if (s->ioc_out) {
g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_out, cond & ~G_IO_IN);
g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
g_source_add_child_source(source, child);
}
if (s->ioc_in) {
g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_in, cond & ~G_IO_OUT);
g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
g_source_add_child_source(source, child);
}
return g_steal_pointer(&source);
} }
static void fd_chr_update_read_handler(Chardev *chr) static void fd_chr_update_read_handler(Chardev *chr)
@ -131,17 +211,32 @@ void qemu_chr_open_fd(Chardev *chr,
int fd_in, int fd_out) int fd_in, int fd_out)
{ {
FDChardev *s = FD_CHARDEV(chr); FDChardev *s = FD_CHARDEV(chr);
char *name; g_autofree char *name = NULL;
if (fd_out >= 0) {
qemu_set_nonblock(fd_out);
}
if (fd_out == fd_in && fd_in >= 0) {
s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
name = g_strdup_printf("chardev-file-%s", chr->label);
qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
s->ioc_out = QIO_CHANNEL(object_ref(s->ioc_in));
return;
}
if (fd_in >= 0) {
s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in)); s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
name = g_strdup_printf("chardev-file-in-%s", chr->label); name = g_strdup_printf("chardev-file-in-%s", chr->label);
qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name); qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
g_free(name); }
if (fd_out >= 0) {
s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out)); s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
g_free(name);
name = g_strdup_printf("chardev-file-out-%s", chr->label); name = g_strdup_printf("chardev-file-out-%s", chr->label);
qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name); qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
g_free(name); }
qemu_set_nonblock(fd_out);
} }
static void char_fd_class_init(ObjectClass *oc, void *data) static void char_fd_class_init(ObjectClass *oc, void *data)

View File

@ -354,7 +354,7 @@ void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
} }
guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond, guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
GIOFunc func, void *user_data) FEWatchFunc func, void *user_data)
{ {
Chardev *s = be->chr; Chardev *s = be->chr;
GSource *src; GSource *src;

View File

@ -468,9 +468,9 @@ static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix)
#ifdef CONFIG_LINUX #ifdef CONFIG_LINUX
if (sa->has_abstract && sa->abstract) { if (sa->has_abstract && sa->abstract) {
abstract = ",abstract"; abstract = ",abstract=on";
if (sa->has_tight && sa->tight) { if (sa->has_tight && sa->tight) {
tight = ",tight"; tight = ",tight=on";
} }
} }
#endif #endif

View File

@ -1031,27 +1031,31 @@ Chardev *qemu_chardev_new(const char *id, const char *typename,
ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
Error **errp) Error **errp)
{ {
ERRP_GUARD();
const ChardevClass *cc; const ChardevClass *cc;
ChardevReturn *ret; ChardevReturn *ret;
Chardev *chr; g_autoptr(Chardev) chr = NULL;
if (qemu_chr_find(id)) {
error_setg(errp, "Chardev with id '%s' already exists", id);
return NULL;
}
cc = char_get_class(ChardevBackendKind_str(backend->type), errp); cc = char_get_class(ChardevBackendKind_str(backend->type), errp);
if (!cc) { if (!cc) {
return NULL; goto err;
} }
chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)), chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
backend, NULL, false, errp); backend, NULL, false, errp);
if (!chr) { if (!chr) {
return NULL; goto err;
} }
if (!object_property_try_add_child(get_chardevs_root(), id, OBJECT(chr), if (!object_property_try_add_child(get_chardevs_root(), id, OBJECT(chr),
errp)) { errp)) {
object_unref(OBJECT(chr)); goto err;
return NULL;
} }
object_unref(OBJECT(chr));
ret = g_new0(ChardevReturn, 1); ret = g_new0(ChardevReturn, 1);
if (CHARDEV_IS_PTY(chr)) { if (CHARDEV_IS_PTY(chr)) {
@ -1060,6 +1064,10 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
} }
return ret; return ret;
err:
error_prepend(errp, "Failed to add chardev '%s': ", id);
return NULL;
} }
ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend,

View File

@ -382,6 +382,7 @@ static const TypeInfo char_spicevmc_type_info = {
.parent = TYPE_CHARDEV_SPICE, .parent = TYPE_CHARDEV_SPICE,
.class_init = char_spicevmc_class_init, .class_init = char_spicevmc_class_init,
}; };
module_obj(TYPE_CHARDEV_SPICEVMC);
static void char_spiceport_class_init(ObjectClass *oc, void *data) static void char_spiceport_class_init(ObjectClass *oc, void *data)
{ {

View File

@ -8,8 +8,4 @@ CONFIG_ATI_VGA=y
CONFIG_RTL8139_PCI=y CONFIG_RTL8139_PCI=y
CONFIG_JAZZ=y CONFIG_JAZZ=y
CONFIG_VT82C686=y CONFIG_VT82C686=y
CONFIG_AHCI=y
CONFIG_MIPS_BOSTON=y CONFIG_MIPS_BOSTON=y
CONFIG_FITLOADER=y
CONFIG_PCI_EXPRESS=y
CONFIG_PCI_EXPRESS_XILINX=y

View File

@ -1,7 +1,6 @@
# Default configuration for ppc-softmmu # Default configuration for ppc-softmmu
# For embedded PPCs: # For embedded PPCs:
CONFIG_DS1338=y
CONFIG_E500=y CONFIG_E500=y
CONFIG_PPC405=y CONFIG_PPC405=y
CONFIG_PPC440=y CONFIG_PPC440=y

View File

@ -1 +1,2 @@
CONFIG_TRICORE_TESTBOARD=y
CONFIG_TRIBOARD=y CONFIG_TRIBOARD=y

223
configure vendored
View File

@ -243,6 +243,7 @@ cross_prefix=""
audio_drv_list="" audio_drv_list=""
block_drv_rw_whitelist="" block_drv_rw_whitelist=""
block_drv_ro_whitelist="" block_drv_ro_whitelist=""
block_drv_whitelist_tools="no"
host_cc="cc" host_cc="cc"
audio_win_int="" audio_win_int=""
libs_qga="" libs_qga=""
@ -304,14 +305,14 @@ virtiofsd="auto"
virtfs="auto" virtfs="auto"
libudev="auto" libudev="auto"
mpath="auto" mpath="auto"
vnc="enabled" vnc="auto"
sparse="auto" sparse="auto"
vde="$default_feature" vde="$default_feature"
vnc_sasl="auto" vnc_sasl="auto"
vnc_jpeg="auto" vnc_jpeg="auto"
vnc_png="auto" vnc_png="auto"
xkbcommon="auto" xkbcommon="auto"
xen="$default_feature" xen=${default_feature:+disabled}
xen_ctrl_version="$default_feature" xen_ctrl_version="$default_feature"
xen_pci_passthrough="auto" xen_pci_passthrough="auto"
linux_aio="$default_feature" linux_aio="$default_feature"
@ -321,6 +322,7 @@ attr="auto"
xfs="$default_feature" xfs="$default_feature"
tcg="enabled" tcg="enabled"
membarrier="$default_feature" membarrier="$default_feature"
vhost_kernel="$default_feature"
vhost_net="$default_feature" vhost_net="$default_feature"
vhost_crypto="$default_feature" vhost_crypto="$default_feature"
vhost_scsi="$default_feature" vhost_scsi="$default_feature"
@ -328,6 +330,7 @@ vhost_vsock="$default_feature"
vhost_user="no" vhost_user="no"
vhost_user_blk_server="auto" vhost_user_blk_server="auto"
vhost_user_fs="$default_feature" vhost_user_fs="$default_feature"
vhost_vdpa="$default_feature"
bpf="auto" bpf="auto"
kvm="auto" kvm="auto"
hax="auto" hax="auto"
@ -429,7 +432,7 @@ libxml2="auto"
debug_mutex="no" debug_mutex="no"
libpmem="auto" libpmem="auto"
default_devices="true" default_devices="true"
plugins="no" plugins="$default_feature"
fuzzing="no" fuzzing="no"
rng_none="no" rng_none="no"
secret_keyring="$default_feature" secret_keyring="$default_feature"
@ -710,6 +713,7 @@ MINGW32*)
audio_drv_list="" audio_drv_list=""
fi fi
supported_os="yes" supported_os="yes"
plugins="no"
pie="no" pie="no"
;; ;;
GNU/kFreeBSD) GNU/kFreeBSD)
@ -768,7 +772,8 @@ SunOS)
;; ;;
Haiku) Haiku)
haiku="yes" haiku="yes"
QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS -D_BSD_SOURCE $QEMU_CFLAGS" pie="no"
QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS -D_BSD_SOURCE -fPIC $QEMU_CFLAGS"
;; ;;
Linux) Linux)
audio_drv_list="try-pa oss" audio_drv_list="try-pa oss"
@ -1017,6 +1022,10 @@ for opt do
;; ;;
--block-drv-ro-whitelist=*) block_drv_ro_whitelist=$(echo "$optarg" | sed -e 's/,/ /g') --block-drv-ro-whitelist=*) block_drv_ro_whitelist=$(echo "$optarg" | sed -e 's/,/ /g')
;; ;;
--enable-block-drv-whitelist-in-tools) block_drv_whitelist_tools="yes"
;;
--disable-block-drv-whitelist-in-tools) block_drv_whitelist_tools="no"
;;
--enable-debug-tcg) debug_tcg="yes" --enable-debug-tcg) debug_tcg="yes"
;; ;;
--disable-debug-tcg) debug_tcg="no" --disable-debug-tcg) debug_tcg="no"
@ -1112,6 +1121,7 @@ for opt do
--enable-cap-ng) cap_ng="enabled" --enable-cap-ng) cap_ng="enabled"
;; ;;
--disable-tcg) tcg="disabled" --disable-tcg) tcg="disabled"
plugins="no"
;; ;;
--enable-tcg) tcg="enabled" --enable-tcg) tcg="enabled"
;; ;;
@ -1523,7 +1533,11 @@ for opt do
;; ;;
--disable-xkbcommon) xkbcommon="disabled" --disable-xkbcommon) xkbcommon="disabled"
;; ;;
--enable-plugins) plugins="yes" --enable-plugins) if test "$mingw32" = "yes"; then
error_exit "TCG plugins not currently supported on Windows platforms"
else
plugins="yes"
fi
;; ;;
--disable-plugins) plugins="no" --disable-plugins) plugins="no"
;; ;;
@ -1584,6 +1598,11 @@ for opt do
esac esac
done done
# test for any invalid configuration combinations
if test "$plugins" = "yes" -a "$tcg" = "disabled"; then
error_exit "Can't enable plugins on non-TCG builds"
fi
case $git_submodules_action in case $git_submodules_action in
update|validate) update|validate)
if test ! -e "$source_path/.git"; then if test ! -e "$source_path/.git"; then
@ -1798,10 +1817,12 @@ Advanced options (experts only):
--block-drv-whitelist=L Same as --block-drv-rw-whitelist=L --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L
--block-drv-rw-whitelist=L --block-drv-rw-whitelist=L
set block driver read-write whitelist set block driver read-write whitelist
(affects only QEMU, not qemu-img) (by default affects only QEMU, not tools like qemu-img)
--block-drv-ro-whitelist=L --block-drv-ro-whitelist=L
set block driver read-only whitelist set block driver read-only whitelist
(affects only QEMU, not qemu-img) (by default affects only QEMU, not tools like qemu-img)
--enable-block-drv-whitelist-in-tools
use block whitelist also in tools instead of only QEMU
--enable-trace-backends=B Set trace backend --enable-trace-backends=B Set trace backend
Available backends: $trace_backend_list Available backends: $trace_backend_list
--with-trace-file=NAME Full PATH,NAME of file to store traces --with-trace-file=NAME Full PATH,NAME of file to store traces
@ -2200,11 +2221,16 @@ if test "$modules" = "no" && test "$module_upgrades" = "yes" ; then
error_exit "Can't enable module-upgrades as Modules are not enabled" error_exit "Can't enable module-upgrades as Modules are not enabled"
fi fi
# Static linking is not possible with modules or PIE # Static linking is not possible with plugins, modules or PIE
if test "$static" = "yes" ; then if test "$static" = "yes" ; then
if test "$modules" = "yes" ; then if test "$modules" = "yes" ; then
error_exit "static and modules are mutually incompatible" error_exit "static and modules are mutually incompatible"
fi fi
if test "$plugins" = "yes"; then
error_exit "static and plugins are mutually incompatible"
else
plugins="no"
fi
fi fi
# Unconditional check for compiler __thread support # Unconditional check for compiler __thread support
@ -2358,24 +2384,27 @@ feature_not_found() {
# --- # ---
# big/little endian test # big/little endian test
cat > $TMPC << EOF cat > $TMPC << EOF
#include <stdio.h>
short big_endian[] = { 0x4269, 0x4765, 0x4e64, 0x4961, 0x4e00, 0, }; short big_endian[] = { 0x4269, 0x4765, 0x4e64, 0x4961, 0x4e00, 0, };
short little_endian[] = { 0x694c, 0x7454, 0x654c, 0x6e45, 0x6944, 0x6e41, 0, }; short little_endian[] = { 0x694c, 0x7454, 0x654c, 0x6e45, 0x6944, 0x6e41, 0, };
extern int foo(short *, short *); int main(int argc, char *argv[])
int main(int argc, char *argv[]) { {
return foo(big_endian, little_endian); return printf("%s %s\n", (char *)big_endian, (char *)little_endian);
} }
EOF EOF
if compile_object ; then if compile_prog ; then
if strings -a $TMPO | grep -q BiGeNdIaN ; then if strings -a $TMPE | grep -q BiGeNdIaN ; then
bigendian="yes" bigendian="yes"
elif strings -a $TMPO | grep -q LiTtLeEnDiAn ; then elif strings -a $TMPE | grep -q LiTtLeEnDiAn ; then
bigendian="no" bigendian="no"
else else
echo big/little test failed echo big/little test failed
exit 1
fi fi
else else
echo big/little test failed echo big/little test failed
exit 1
fi fi
########################################## ##########################################
@ -3097,6 +3126,69 @@ for drv in $audio_drv_list; do
esac esac
done done
##########################################
# plugin linker support probe
if test "$plugins" != "no"; then
#########################################
# See if --dynamic-list is supported by the linker
ld_dynamic_list="no"
cat > $TMPTXT <<EOF
{
foo;
};
EOF
cat > $TMPC <<EOF
#include <stdio.h>
void foo(void);
void foo(void)
{
printf("foo\n");
}
int main(void)
{
foo();
return 0;
}
EOF
if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then
ld_dynamic_list="yes"
fi
#########################################
# See if -exported_symbols_list is supported by the linker
ld_exported_symbols_list="no"
cat > $TMPTXT <<EOF
_foo
EOF
if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then
ld_exported_symbols_list="yes"
fi
if test "$ld_dynamic_list" = "no" &&
test "$ld_exported_symbols_list" = "no" ; then
if test "$plugins" = "yes"; then
error_exit \
"Plugin support requires dynamic linking and specifying a set of symbols " \
"that are exported to plugins. Unfortunately your linker doesn't " \
"support the flag (--dynamic-list or -exported_symbols_list) used " \
"for this purpose."
else
plugins="no"
fi
else
plugins="yes"
fi
fi
########################################## ##########################################
# glib support probe # glib support probe
@ -3105,7 +3197,7 @@ glib_modules=gthread-2.0
if test "$modules" = yes; then if test "$modules" = yes; then
glib_modules="$glib_modules gmodule-export-2.0" glib_modules="$glib_modules gmodule-export-2.0"
fi fi
if test "$plugins" = yes; then if test "$plugins" = "yes"; then
glib_modules="$glib_modules gmodule-2.0" glib_modules="$glib_modules gmodule-2.0"
fi fi
@ -3193,18 +3285,6 @@ if ! compile_prog "$glib_cflags" "$glib_libs" ; then
"build target" "build target"
fi fi
# Silence clang 3.5.0 warnings about glib attribute __alloc_size__ usage
cat > $TMPC << EOF
#include <glib.h>
int main(void) { return 0; }
EOF
if ! compile_prog "$glib_cflags -Werror" "$glib_libs" ; then
if cc_has_warning_flag "-Wno-unknown-attributes"; then
glib_cflags="-Wno-unknown-attributes $glib_cflags"
CONFIGURE_CFLAGS="-Wno-unknown-attributes $CONFIGURE_CFLAGS"
fi
fi
# Silence clang warnings triggered by glib < 2.57.2 # Silence clang warnings triggered by glib < 2.57.2
cat > $TMPC << EOF cat > $TMPC << EOF
#include <glib.h> #include <glib.h>
@ -3615,21 +3695,8 @@ fi
########################################## ##########################################
# For 'ust' backend, test if ust headers are present # For 'ust' backend, test if ust headers are present
if have_backend "ust"; then if have_backend "ust"; then
cat > $TMPC << EOF
#include <lttng/tracepoint.h>
int main(void) { return 0; }
EOF
if compile_prog "" "-Wl,--no-as-needed -ldl" ; then
if $pkg_config lttng-ust --exists; then if $pkg_config lttng-ust --exists; then
lttng_ust_libs=$($pkg_config --libs lttng-ust) lttng_ust_libs=$($pkg_config --libs lttng-ust)
else
lttng_ust_libs="-llttng-ust -ldl"
fi
if $pkg_config liburcu-bp --exists; then
urcu_bp_libs=$($pkg_config --libs liburcu-bp)
else
urcu_bp_libs="-lurcu-bp"
fi
else else
error_exit "Trace backend 'ust' missing lttng-ust header files" error_exit "Trace backend 'ust' missing lttng-ust header files"
fi fi
@ -3824,7 +3891,7 @@ static int bar(void *a) {
} }
int main(int argc, char *argv[]) { return bar(argv[0]); } int main(int argc, char *argv[]) { return bar(argv[0]); }
EOF EOF
if compile_object "" ; then if compile_object "-Werror" ; then
avx2_opt="yes" avx2_opt="yes"
else else
avx2_opt="no" avx2_opt="no"
@ -3854,7 +3921,7 @@ int main(int argc, char *argv[])
return bar(argv[0]); return bar(argv[0]);
} }
EOF EOF
if ! compile_object "" ; then if ! compile_object "-Werror" ; then
avx512f_opt="no" avx512f_opt="no"
fi fi
else else
@ -3924,18 +3991,11 @@ cat > $TMPC << EOF
int main(void) int main(void)
{ {
uint64_t x = 0, y = 0; uint64_t x = 0, y = 0;
#ifdef __ATOMIC_RELAXED
y = __atomic_load_n(&x, __ATOMIC_RELAXED); y = __atomic_load_n(&x, __ATOMIC_RELAXED);
__atomic_store_n(&x, y, __ATOMIC_RELAXED); __atomic_store_n(&x, y, __ATOMIC_RELAXED);
__atomic_compare_exchange_n(&x, &y, x, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); __atomic_compare_exchange_n(&x, &y, x, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
__atomic_exchange_n(&x, y, __ATOMIC_RELAXED); __atomic_exchange_n(&x, y, __ATOMIC_RELAXED);
__atomic_fetch_add(&x, y, __ATOMIC_RELAXED); __atomic_fetch_add(&x, y, __ATOMIC_RELAXED);
#else
typedef char is_host64[sizeof(void *) >= sizeof(uint64_t) ? 1 : -1];
__sync_lock_test_and_set(&x, y);
__sync_val_compare_and_swap(&x, y, 0);
__sync_fetch_and_add(&x, y);
#endif
return 0; return 0;
} }
EOF EOF
@ -3943,61 +4003,6 @@ if compile_prog "" "" ; then
atomic64=yes atomic64=yes
fi fi
#########################################
# See if --dynamic-list is supported by the linker
ld_dynamic_list="no"
if test "$static" = "no" ; then
cat > $TMPTXT <<EOF
{
foo;
};
EOF
cat > $TMPC <<EOF
#include <stdio.h>
void foo(void);
void foo(void)
{
printf("foo\n");
}
int main(void)
{
foo();
return 0;
}
EOF
if compile_prog "" "-Wl,--dynamic-list=$TMPTXT" ; then
ld_dynamic_list="yes"
fi
fi
#########################################
# See if -exported_symbols_list is supported by the linker
ld_exported_symbols_list="no"
if test "$static" = "no" ; then
cat > $TMPTXT <<EOF
_foo
EOF
if compile_prog "" "-Wl,-exported_symbols_list,$TMPTXT" ; then
ld_exported_symbols_list="yes"
fi
fi
if test "$plugins" = "yes" &&
test "$ld_dynamic_list" = "no" &&
test "$ld_exported_symbols_list" = "no" ; then
error_exit \
"Plugin support requires dynamic linking and specifying a set of symbols " \
"that are exported to plugins. Unfortunately your linker doesn't " \
"support the flag (--dynamic-list or -exported_symbols_list) used " \
"for this purpose. You can't build with --static."
fi
######################################## ########################################
# check if getauxval is available. # check if getauxval is available.
@ -4578,6 +4583,9 @@ if test "$audio_win_int" = "yes" ; then
fi fi
echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak
echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak
if test "$block_drv_whitelist_tools" = "yes" ; then
echo "CONFIG_BDRV_WHITELIST_TOOLS=y" >> $config_host_mak
fi
if test "$xfs" = "yes" ; then if test "$xfs" = "yes" ; then
echo "CONFIG_XFS=y" >> $config_host_mak echo "CONFIG_XFS=y" >> $config_host_mak
fi fi
@ -4782,7 +4790,6 @@ fi
if have_backend "ust"; then if have_backend "ust"; then
echo "CONFIG_TRACE_UST=y" >> $config_host_mak echo "CONFIG_TRACE_UST=y" >> $config_host_mak
echo "LTTNG_UST_LIBS=$lttng_ust_libs" >> $config_host_mak echo "LTTNG_UST_LIBS=$lttng_ust_libs" >> $config_host_mak
echo "URCU_BP_LIBS=$urcu_bp_libs" >> $config_host_mak
fi fi
if have_backend "dtrace"; then if have_backend "dtrace"; then
echo "CONFIG_TRACE_DTRACE=y" >> $config_host_mak echo "CONFIG_TRACE_DTRACE=y" >> $config_host_mak
@ -5106,12 +5113,10 @@ if test "$skip_meson" = no; then
echo "[properties]" >> $cross echo "[properties]" >> $cross
# unroll any custom device configs # unroll any custom device configs
if test -n "$device_archs"; then
for a in $device_archs; do for a in $device_archs; do
eval "c=\$devices_${a}" eval "c=\$devices_${a}"
echo "${a}-softmmu = '$c'" >> $cross echo "${a}-softmmu = '$c'" >> $cross
done done
fi
test -z "$cxx" && echo "link_language = 'c'" >> $cross test -z "$cxx" && echo "link_language = 'c'" >> $cross
echo "[built-in options]" >> $cross echo "[built-in options]" >> $cross
@ -5214,7 +5219,7 @@ if test "$skip_meson" = no; then
-Ddocs=$docs -Dsphinx_build=$sphinx_build -Dinstall_blobs=$blobs \ -Ddocs=$docs -Dsphinx_build=$sphinx_build -Dinstall_blobs=$blobs \
-Dvhost_user_blk_server=$vhost_user_blk_server -Dmultiprocess=$multiprocess \ -Dvhost_user_blk_server=$vhost_user_blk_server -Dmultiprocess=$multiprocess \
-Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi -Dbpf=$bpf\ -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi -Dbpf=$bpf\
$(if test "$default_features" = no; then echo "-Dauto_features=disabled"; fi) \ $(if test "$default_feature" = no; then echo "-Dauto_features=disabled"; fi) \
-Dtcg_interpreter=$tcg_interpreter \ -Dtcg_interpreter=$tcg_interpreter \
$cross_arg \ $cross_arg \
"$PWD" "$source_path" "$PWD" "$source_path"
@ -5235,7 +5240,7 @@ fi
if test -n "${deprecated_features}"; then if test -n "${deprecated_features}"; then
echo "Warning, deprecated features enabled." echo "Warning, deprecated features enabled."
echo "Please see docs/system/deprecated.rst" echo "Please see docs/about/deprecated.rst"
echo " features: ${deprecated_features}" echo " features: ${deprecated_features}"
fi fi

View File

@ -31,6 +31,12 @@ pbrook@c046a42c-6fe2-441c-8c8c-71466251a162 paul@codesourcery.com
ths@c046a42c-6fe2-441c-8c8c-71466251a162 ths@networkno.de ths@c046a42c-6fe2-441c-8c8c-71466251a162 ths@networkno.de
malc@c046a42c-6fe2-441c-8c8c-71466251a162 av1474@comtv.ru malc@c046a42c-6fe2-441c-8c8c-71466251a162 av1474@comtv.ru
# canonical emails
liq3ea@163.com liq3ea@gmail.com
# some broken tags
yuval.shaia.ml.gmail.com yuval.shaia.ml@gmail.com
# There is also a: # There is also a:
# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162> # (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
# for the cvs2svn initialization commit e63c3dc74bf. # for the cvs2svn initialization commit e63c3dc74bf.

View File

@ -9,6 +9,8 @@ baidu.com Baidu
bytedance.com ByteDance bytedance.com ByteDance
cmss.chinamobile.com China Mobile cmss.chinamobile.com China Mobile
citrix.com Citrix citrix.com Citrix
crudebyte.com Crudebyte
eldorado.org.br Instituto de Pesquisas Eldorado
fujitsu.com Fujitsu fujitsu.com Fujitsu
google.com Google google.com Google
greensocs.com GreenSocs greensocs.com GreenSocs
@ -17,20 +19,25 @@ ibm.com IBM
igalia.com Igalia igalia.com Igalia
intel.com Intel intel.com Intel
linaro.org Linaro linaro.org Linaro
lwn.net LWN
microsoft.com Microsoft microsoft.com Microsoft
mvista.com MontaVista
nokia.com Nokia nokia.com Nokia
nuviainc.com NUVIA nuviainc.com NUVIA
nvidia.com NVIDIA
oracle.com Oracle oracle.com Oracle
proxmox.com Proxmox proxmox.com Proxmox
quicinc.com Qualcomm Innovation Center quicinc.com Qualcomm Innovation Center
redhat.com Red Hat redhat.com Red Hat
rt-rk.com RT-RK rt-rk.com RT-RK
samsung.com Samsung
siemens.com Siemens siemens.com Siemens
sifive.com SiFive sifive.com SiFive
suse.com SUSE suse.com SUSE
suse.de SUSE suse.de SUSE
virtuozzo.com Virtuozzo virtuozzo.com Virtuozzo
wdc.com Western Digital wdc.com Western Digital
windriver.com Wind River
xilinx.com Xilinx xilinx.com Xilinx
yadro.com YADRO yadro.com YADRO
yandex-team.ru Yandex yandex-team.ru Yandex

View File

@ -16,3 +16,6 @@ cota@braap.org
uni-paderborn.de uni-paderborn.de
edu edu
edu.cn edu.cn
# Boston University
bu.edu

View File

@ -29,3 +29,8 @@ mrolnik@gmail.com
huth@tuxfamily.org huth@tuxfamily.org
jhogan@kernel.org jhogan@kernel.org
atar4qemu@gmail.com atar4qemu@gmail.com
minwoo.im.dev@gmail.com
bmeng.cn@gmail.com
liq3ea@gmail.com
chetan4windows@gmail.com
akihiko.odaki@gmail.com

View File

@ -0,0 +1,13 @@
#
# Group together everyone working as an intern via one of the various
# outreach programs.
#
# GSoC 2020 Virtual FIDO/U2F security key
cesar.belley@lse.epita.fr
# GSoC 2020 TCG performance
ahmedkhaledkaraman@gmail.com
# GSoC 2021 TCG plugins
ma.mandourr@gmail.com

View File

@ -0,0 +1,5 @@
#
# Netflix contributors using their personal emails
#
imp@bsdimp.com

View File

@ -0,0 +1,7 @@
#
# There are various automatic robots that occasionally scan and report
# bugs. Let's group them together here.
#
# Euler Robot
euler.robot@huawei.com

View File

@ -13,18 +13,20 @@ include $(BUILD_DIR)/config-host.mak
VPATH += $(SRC_PATH)/contrib/plugins VPATH += $(SRC_PATH)/contrib/plugins
NAMES := NAMES :=
NAMES += execlog
NAMES += hotblocks NAMES += hotblocks
NAMES += hotpages NAMES += hotpages
NAMES += howvec NAMES += howvec
NAMES += lockstep NAMES += lockstep
NAMES += hwprofile NAMES += hwprofile
NAMES += cache
SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
# The main QEMU uses Glib extensively so it's perfectly fine to use it # The main QEMU uses Glib extensively so it's perfectly fine to use it
# in plugins (which many example do). # in plugins (which many example do).
CFLAGS = $(GLIB_CFLAGS) CFLAGS = $(GLIB_CFLAGS)
CFLAGS += -fPIC CFLAGS += -fPIC -Wall $(filter -W%, $(QEMU_CFLAGS))
CFLAGS += $(if $(findstring no-psabi,$(QEMU_CFLAGS)),-Wpsabi) CFLAGS += $(if $(findstring no-psabi,$(QEMU_CFLAGS)),-Wpsabi)
CFLAGS += -I$(SRC_PATH)/include/qemu CFLAGS += -I$(SRC_PATH)/include/qemu

640
contrib/plugins/cache.c Normal file
View File

@ -0,0 +1,640 @@
/*
* Copyright (C) 2021, Mahmoud Mandour <ma.mandourr@gmail.com>
*
* License: GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <inttypes.h>
#include <stdio.h>
#include <glib.h>
#include <qemu-plugin.h>
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
static GHashTable *miss_ht;
static GMutex mtx;
static GRand *rng;
static int limit;
static bool sys;
static uint64_t dmem_accesses;
static uint64_t dmisses;
static uint64_t imem_accesses;
static uint64_t imisses;
enum EvictionPolicy {
LRU,
FIFO,
RAND,
};
enum EvictionPolicy policy;
/*
* A CacheSet is a set of cache blocks. A memory block that maps to a set can be
* put in any of the blocks inside the set. The number of block per set is
* called the associativity (assoc).
*
* Each block contains the the stored tag and a valid bit. Since this is not
* a functional simulator, the data itself is not stored. We only identify
* whether a block is in the cache or not by searching for its tag.
*
* In order to search for memory data in the cache, the set identifier and tag
* are extracted from the address and the set is probed to see whether a tag
* match occur.
*
* An address is logically divided into three portions: The block offset,
* the set number, and the tag.
*
* The set number is used to identify the set in which the block may exist.
* The tag is compared against all the tags of a set to search for a match. If a
* match is found, then the access is a hit.
*
* The CacheSet also contains bookkeaping information about eviction details.
*/
typedef struct {
uint64_t tag;
bool valid;
} CacheBlock;
typedef struct {
CacheBlock *blocks;
uint64_t *lru_priorities;
uint64_t lru_gen_counter;
GQueue *fifo_queue;
} CacheSet;
typedef struct {
CacheSet *sets;
int num_sets;
int cachesize;
int assoc;
int blksize_shift;
uint64_t set_mask;
uint64_t tag_mask;
} Cache;
typedef struct {
char *disas_str;
const char *symbol;
uint64_t addr;
uint64_t dmisses;
uint64_t imisses;
} InsnData;
void (*update_hit)(Cache *cache, int set, int blk);
void (*update_miss)(Cache *cache, int set, int blk);
void (*metadata_init)(Cache *cache);
void (*metadata_destroy)(Cache *cache);
Cache *dcache, *icache;
static int pow_of_two(int num)
{
g_assert((num & (num - 1)) == 0);
int ret = 0;
while (num /= 2) {
ret++;
}
return ret;
}
/*
* LRU evection policy: For each set, a generation counter is maintained
* alongside a priority array.
*
* On each set access, the generation counter is incremented.
*
* On a cache hit: The hit-block is assigned the current generation counter,
* indicating that it is the most recently used block.
*
* On a cache miss: The block with the least priority is searched and replaced
* with the newly-cached block, of which the priority is set to the current
* generation number.
*/
static void lru_priorities_init(Cache *cache)
{
int i;
for (i = 0; i < cache->num_sets; i++) {
cache->sets[i].lru_priorities = g_new0(uint64_t, cache->assoc);
cache->sets[i].lru_gen_counter = 0;
}
}
static void lru_update_blk(Cache *cache, int set_idx, int blk_idx)
{
CacheSet *set = &cache->sets[set_idx];
set->lru_priorities[blk_idx] = cache->sets[set_idx].lru_gen_counter;
set->lru_gen_counter++;
}
static int lru_get_lru_block(Cache *cache, int set_idx)
{
int i, min_idx, min_priority;
min_priority = cache->sets[set_idx].lru_priorities[0];
min_idx = 0;
for (i = 1; i < cache->assoc; i++) {
if (cache->sets[set_idx].lru_priorities[i] < min_priority) {
min_priority = cache->sets[set_idx].lru_priorities[i];
min_idx = i;
}
}
return min_idx;
}
static void lru_priorities_destroy(Cache *cache)
{
int i;
for (i = 0; i < cache->num_sets; i++) {
g_free(cache->sets[i].lru_priorities);
}
}
/*
* FIFO eviction policy: a FIFO queue is maintained for each CacheSet that
* stores accesses to the cache.
*
* On a compulsory miss: The block index is enqueued to the fifo_queue to
* indicate that it's the latest cached block.
*
* On a conflict miss: The first-in block is removed from the cache and the new
* block is put in its place and enqueued to the FIFO queue.
*/
static void fifo_init(Cache *cache)
{
int i;
for (i = 0; i < cache->num_sets; i++) {
cache->sets[i].fifo_queue = g_queue_new();
}
}
static int fifo_get_first_block(Cache *cache, int set)
{
GQueue *q = cache->sets[set].fifo_queue;
return GPOINTER_TO_INT(g_queue_pop_tail(q));
}
static void fifo_update_on_miss(Cache *cache, int set, int blk_idx)
{
GQueue *q = cache->sets[set].fifo_queue;
g_queue_push_head(q, GINT_TO_POINTER(blk_idx));
}
static void fifo_destroy(Cache *cache)
{
int i;
for (i = 0; i < cache->num_sets; i++) {
g_queue_free(cache->sets[i].fifo_queue);
}
}
static inline uint64_t extract_tag(Cache *cache, uint64_t addr)
{
return addr & cache->tag_mask;
}
static inline uint64_t extract_set(Cache *cache, uint64_t addr)
{
return (addr & cache->set_mask) >> cache->blksize_shift;
}
static const char *cache_config_error(int blksize, int assoc, int cachesize)
{
if (cachesize % blksize != 0) {
return "cache size must be divisible by block size";
} else if (cachesize % (blksize * assoc) != 0) {
return "cache size must be divisible by set size (assoc * block size)";
} else {
return NULL;
}
}
static bool bad_cache_params(int blksize, int assoc, int cachesize)
{
return (cachesize % blksize) != 0 || (cachesize % (blksize * assoc) != 0);
}
static Cache *cache_init(int blksize, int assoc, int cachesize)
{
if (bad_cache_params(blksize, assoc, cachesize)) {
return NULL;
}
Cache *cache;
int i;
uint64_t blk_mask;
cache = g_new(Cache, 1);
cache->assoc = assoc;
cache->cachesize = cachesize;
cache->num_sets = cachesize / (blksize * assoc);
cache->sets = g_new(CacheSet, cache->num_sets);
cache->blksize_shift = pow_of_two(blksize);
for (i = 0; i < cache->num_sets; i++) {
cache->sets[i].blocks = g_new0(CacheBlock, assoc);
}
blk_mask = blksize - 1;
cache->set_mask = ((cache->num_sets - 1) << cache->blksize_shift);
cache->tag_mask = ~(cache->set_mask | blk_mask);
if (metadata_init) {
metadata_init(cache);
}
return cache;
}
static int get_invalid_block(Cache *cache, uint64_t set)
{
int i;
for (i = 0; i < cache->assoc; i++) {
if (!cache->sets[set].blocks[i].valid) {
return i;
}
}
return -1;
}
static int get_replaced_block(Cache *cache, int set)
{
switch (policy) {
case RAND:
return g_rand_int_range(rng, 0, cache->assoc);
case LRU:
return lru_get_lru_block(cache, set);
case FIFO:
return fifo_get_first_block(cache, set);
default:
g_assert_not_reached();
}
}
static int in_cache(Cache *cache, uint64_t addr)
{
int i;
uint64_t tag, set;
tag = extract_tag(cache, addr);
set = extract_set(cache, addr);
for (i = 0; i < cache->assoc; i++) {
if (cache->sets[set].blocks[i].tag == tag &&
cache->sets[set].blocks[i].valid) {
return i;
}
}
return -1;
}
/**
* access_cache(): Simulate a cache access
* @cache: The cache under simulation
* @addr: The address of the requested memory location
*
* Returns true if the requsted data is hit in the cache and false when missed.
* The cache is updated on miss for the next access.
*/
static bool access_cache(Cache *cache, uint64_t addr)
{
int hit_blk, replaced_blk;
uint64_t tag, set;
tag = extract_tag(cache, addr);
set = extract_set(cache, addr);
hit_blk = in_cache(cache, addr);
if (hit_blk != -1) {
if (update_hit) {
update_hit(cache, set, hit_blk);
}
return true;
}
replaced_blk = get_invalid_block(cache, set);
if (replaced_blk == -1) {
replaced_blk = get_replaced_block(cache, set);
}
if (update_miss) {
update_miss(cache, set, replaced_blk);
}
cache->sets[set].blocks[replaced_blk].tag = tag;
cache->sets[set].blocks[replaced_blk].valid = true;
return false;
}
static void vcpu_mem_access(unsigned int vcpu_index, qemu_plugin_meminfo_t info,
uint64_t vaddr, void *userdata)
{
uint64_t effective_addr;
struct qemu_plugin_hwaddr *hwaddr;
InsnData *insn;
hwaddr = qemu_plugin_get_hwaddr(info, vaddr);
if (hwaddr && qemu_plugin_hwaddr_is_io(hwaddr)) {
return;
}
effective_addr = hwaddr ? qemu_plugin_hwaddr_phys_addr(hwaddr) : vaddr;
g_mutex_lock(&mtx);
if (!access_cache(dcache, effective_addr)) {
insn = (InsnData *) userdata;
insn->dmisses++;
dmisses++;
}
dmem_accesses++;
g_mutex_unlock(&mtx);
}
static void vcpu_insn_exec(unsigned int vcpu_index, void *userdata)
{
uint64_t insn_addr;
InsnData *insn;
g_mutex_lock(&mtx);
insn_addr = ((InsnData *) userdata)->addr;
if (!access_cache(icache, insn_addr)) {
insn = (InsnData *) userdata;
insn->imisses++;
imisses++;
}
imem_accesses++;
g_mutex_unlock(&mtx);
}
static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
{
size_t n_insns;
size_t i;
InsnData *data;
n_insns = qemu_plugin_tb_n_insns(tb);
for (i = 0; i < n_insns; i++) {
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
uint64_t effective_addr;
if (sys) {
effective_addr = (uint64_t) qemu_plugin_insn_haddr(insn);
} else {
effective_addr = (uint64_t) qemu_plugin_insn_vaddr(insn);
}
/*
* Instructions might get translated multiple times, we do not create
* new entries for those instructions. Instead, we fetch the same
* entry from the hash table and register it for the callback again.
*/
g_mutex_lock(&mtx);
data = g_hash_table_lookup(miss_ht, GUINT_TO_POINTER(effective_addr));
if (data == NULL) {
data = g_new0(InsnData, 1);
data->disas_str = qemu_plugin_insn_disas(insn);
data->symbol = qemu_plugin_insn_symbol(insn);
data->addr = effective_addr;
g_hash_table_insert(miss_ht, GUINT_TO_POINTER(effective_addr),
(gpointer) data);
}
g_mutex_unlock(&mtx);
qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem_access,
QEMU_PLUGIN_CB_NO_REGS,
rw, data);
qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec,
QEMU_PLUGIN_CB_NO_REGS, data);
}
}
static void insn_free(gpointer data)
{
InsnData *insn = (InsnData *) data;
g_free(insn->disas_str);
g_free(insn);
}
static void cache_free(Cache *cache)
{
for (int i = 0; i < cache->num_sets; i++) {
g_free(cache->sets[i].blocks);
}
if (metadata_destroy) {
metadata_destroy(cache);
}
g_free(cache->sets);
g_free(cache);
}
static int dcmp(gconstpointer a, gconstpointer b)
{
InsnData *insn_a = (InsnData *) a;
InsnData *insn_b = (InsnData *) b;
return insn_a->dmisses < insn_b->dmisses ? 1 : -1;
}
static int icmp(gconstpointer a, gconstpointer b)
{
InsnData *insn_a = (InsnData *) a;
InsnData *insn_b = (InsnData *) b;
return insn_a->imisses < insn_b->imisses ? 1 : -1;
}
static void log_stats(void)
{
g_autoptr(GString) rep = g_string_new("");
g_string_append_printf(rep,
"Data accesses: %lu, Misses: %lu\nMiss rate: %lf%%\n\n",
dmem_accesses,
dmisses,
((double) dmisses / (double) dmem_accesses) * 100.0);
g_string_append_printf(rep,
"Instruction accesses: %lu, Misses: %lu\nMiss rate: %lf%%\n\n",
imem_accesses,
imisses,
((double) imisses / (double) imem_accesses) * 100.0);
qemu_plugin_outs(rep->str);
}
static void log_top_insns(void)
{
int i;
GList *curr, *miss_insns;
InsnData *insn;
miss_insns = g_hash_table_get_values(miss_ht);
miss_insns = g_list_sort(miss_insns, dcmp);
g_autoptr(GString) rep = g_string_new("");
g_string_append_printf(rep, "%s", "address, data misses, instruction\n");
for (curr = miss_insns, i = 0; curr && i < limit; i++, curr = curr->next) {
insn = (InsnData *) curr->data;
g_string_append_printf(rep, "0x%" PRIx64, insn->addr);
if (insn->symbol) {
g_string_append_printf(rep, " (%s)", insn->symbol);
}
g_string_append_printf(rep, ", %ld, %s\n", insn->dmisses,
insn->disas_str);
}
miss_insns = g_list_sort(miss_insns, icmp);
g_string_append_printf(rep, "%s", "\naddress, fetch misses, instruction\n");
for (curr = miss_insns, i = 0; curr && i < limit; i++, curr = curr->next) {
insn = (InsnData *) curr->data;
g_string_append_printf(rep, "0x%" PRIx64, insn->addr);
if (insn->symbol) {
g_string_append_printf(rep, " (%s)", insn->symbol);
}
g_string_append_printf(rep, ", %ld, %s\n", insn->imisses,
insn->disas_str);
}
qemu_plugin_outs(rep->str);
g_list_free(miss_insns);
}
static void plugin_exit(qemu_plugin_id_t id, void *p)
{
log_stats();
log_top_insns();
cache_free(dcache);
cache_free(icache);
g_hash_table_destroy(miss_ht);
}
static void policy_init(void)
{
switch (policy) {
case LRU:
update_hit = lru_update_blk;
update_miss = lru_update_blk;
metadata_init = lru_priorities_init;
metadata_destroy = lru_priorities_destroy;
break;
case FIFO:
update_miss = fifo_update_on_miss;
metadata_init = fifo_init;
metadata_destroy = fifo_destroy;
break;
case RAND:
rng = g_rand_new();
break;
default:
g_assert_not_reached();
}
}
QEMU_PLUGIN_EXPORT
int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
int argc, char **argv)
{
int i;
int iassoc, iblksize, icachesize;
int dassoc, dblksize, dcachesize;
limit = 32;
sys = info->system_emulation;
dassoc = 8;
dblksize = 64;
dcachesize = dblksize * dassoc * 32;
iassoc = 8;
iblksize = 64;
icachesize = iblksize * iassoc * 32;
policy = LRU;
for (i = 0; i < argc; i++) {
char *opt = argv[i];
if (g_str_has_prefix(opt, "iblksize=")) {
iblksize = g_ascii_strtoll(opt + 9, NULL, 10);
} else if (g_str_has_prefix(opt, "iassoc=")) {
iassoc = g_ascii_strtoll(opt + 7, NULL, 10);
} else if (g_str_has_prefix(opt, "icachesize=")) {
icachesize = g_ascii_strtoll(opt + 11, NULL, 10);
} else if (g_str_has_prefix(opt, "dblksize=")) {
dblksize = g_ascii_strtoll(opt + 9, NULL, 10);
} else if (g_str_has_prefix(opt, "dassoc=")) {
dassoc = g_ascii_strtoll(opt + 7, NULL, 10);
} else if (g_str_has_prefix(opt, "dcachesize=")) {
dcachesize = g_ascii_strtoll(opt + 11, NULL, 10);
} else if (g_str_has_prefix(opt, "limit=")) {
limit = g_ascii_strtoll(opt + 6, NULL, 10);
} else if (g_str_has_prefix(opt, "evict=")) {
gchar *p = opt + 6;
if (g_strcmp0(p, "rand") == 0) {
policy = RAND;
} else if (g_strcmp0(p, "lru") == 0) {
policy = LRU;
} else if (g_strcmp0(p, "fifo") == 0) {
policy = FIFO;
} else {
fprintf(stderr, "invalid eviction policy: %s\n", opt);
return -1;
}
} else {
fprintf(stderr, "option parsing failed: %s\n", opt);
return -1;
}
}
policy_init();
dcache = cache_init(dblksize, dassoc, dcachesize);
if (!dcache) {
const char *err = cache_config_error(dblksize, dassoc, dcachesize);
fprintf(stderr, "dcache cannot be constructed from given parameters\n");
fprintf(stderr, "%s\n", err);
return -1;
}
icache = cache_init(iblksize, iassoc, icachesize);
if (!icache) {
const char *err = cache_config_error(iblksize, iassoc, icachesize);
fprintf(stderr, "icache cannot be constructed from given parameters\n");
fprintf(stderr, "%s\n", err);
return -1;
}
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
miss_ht = g_hash_table_new_full(NULL, g_direct_equal, NULL, insn_free);
return 0;
}

153
contrib/plugins/execlog.c Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2021, Alexandre Iooss <erdnaxe@crans.org>
*
* Log instruction execution with memory access.
*
* License: GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <glib.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <qemu-plugin.h>
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
/* Store last executed instruction on each vCPU as a GString */
GArray *last_exec;
/**
* Add memory read or write information to current instruction log
*/
static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info,
uint64_t vaddr, void *udata)
{
GString *s;
/* Find vCPU in array */
g_assert(cpu_index < last_exec->len);
s = g_array_index(last_exec, GString *, cpu_index);
/* Indicate type of memory access */
if (qemu_plugin_mem_is_store(info)) {
g_string_append(s, ", store");
} else {
g_string_append(s, ", load");
}
/* If full system emulation log physical address and device name */
struct qemu_plugin_hwaddr *hwaddr = qemu_plugin_get_hwaddr(info, vaddr);
if (hwaddr) {
uint64_t addr = qemu_plugin_hwaddr_phys_addr(hwaddr);
const char *name = qemu_plugin_hwaddr_device_name(hwaddr);
g_string_append_printf(s, ", 0x%08"PRIx64", %s", addr, name);
} else {
g_string_append_printf(s, ", 0x%08"PRIx64, vaddr);
}
}
/**
* Log instruction execution
*/
static void vcpu_insn_exec(unsigned int cpu_index, void *udata)
{
GString *s;
/* Find or create vCPU in array */
while (cpu_index >= last_exec->len) {
s = g_string_new(NULL);
g_array_append_val(last_exec, s);
}
s = g_array_index(last_exec, GString *, cpu_index);
/* Print previous instruction in cache */
if (s->len) {
qemu_plugin_outs(s->str);
qemu_plugin_outs("s\n");
}
/* Store new instruction in cache */
/* vcpu_mem will add memory access information to last_exec */
g_string_printf(s, "%u, ", cpu_index);
g_string_append(s, (char *)udata);
}
/**
* On translation block new translation
*
* QEMU convert code by translation block (TB). By hooking here we can then hook
* a callback on each instruction and memory access.
*/
static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
{
struct qemu_plugin_insn *insn;
uint64_t insn_vaddr;
uint32_t insn_opcode;
char *insn_disas;
size_t n = qemu_plugin_tb_n_insns(tb);
for (size_t i = 0; i < n; i++) {
/*
* `insn` is shared between translations in QEMU, copy needed data here.
* `output` is never freed as it might be used multiple times during
* the emulation lifetime.
* We only consider the first 32 bits of the instruction, this may be
* a limitation for CISC architectures.
*/
insn = qemu_plugin_tb_get_insn(tb, i);
insn_vaddr = qemu_plugin_insn_vaddr(insn);
insn_opcode = *((uint32_t *)qemu_plugin_insn_data(insn));
insn_disas = qemu_plugin_insn_disas(insn);
char *output = g_strdup_printf("0x%"PRIx64", 0x%"PRIx32", \"%s\"",
insn_vaddr, insn_opcode, insn_disas);
/* Register callback on memory read or write */
qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem,
QEMU_PLUGIN_CB_NO_REGS,
QEMU_PLUGIN_MEM_RW, NULL);
/* Register callback on instruction */
qemu_plugin_register_vcpu_insn_exec_cb(insn, vcpu_insn_exec,
QEMU_PLUGIN_CB_NO_REGS, output);
}
}
/**
* On plugin exit, print last instruction in cache
*/
static void plugin_exit(qemu_plugin_id_t id, void *p)
{
guint i;
GString *s;
for (i = 0; i < last_exec->len; i++) {
s = g_array_index(last_exec, GString *, i);
if (s->str) {
qemu_plugin_outs(s->str);
qemu_plugin_outs("\n");
}
}
}
/**
* Install the plugin
*/
QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
const qemu_info_t *info, int argc,
char **argv)
{
/*
* Initialize dynamic array to cache vCPU instruction. In user mode
* we don't know the size before emulation.
*/
last_exec = g_array_new(FALSE, FALSE, sizeof(GString *));
/* Register translation block and exit callbacks */
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
return 0;
}

34
cpu.c
View File

@ -330,11 +330,6 @@ void tb_invalidate_phys_addr(target_ulong addr)
tb_invalidate_phys_page_range(addr, addr + 1); tb_invalidate_phys_page_range(addr, addr + 1);
mmap_unlock(); mmap_unlock();
} }
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
tb_invalidate_phys_addr(pc);
}
#else #else
void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs) void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
{ {
@ -355,25 +350,19 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
ram_addr = memory_region_get_ram_addr(mr) + addr; ram_addr = memory_region_get_ram_addr(mr) + addr;
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1); tb_invalidate_phys_page_range(ram_addr, ram_addr + 1);
} }
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
/*
* There may not be a virtual to physical translation for the pc
* right now, but there may exist cached TB for this pc.
* Flush the whole TB cache to force re-translation of such TBs.
* This is heavyweight, but we're debugging anyway.
*/
tb_flush(cpu);
}
#endif #endif
/* Add a breakpoint. */ /* Add a breakpoint. */
int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags, int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
CPUBreakpoint **breakpoint) CPUBreakpoint **breakpoint)
{ {
CPUClass *cc = CPU_GET_CLASS(cpu);
CPUBreakpoint *bp; CPUBreakpoint *bp;
if (cc->gdb_adjust_breakpoint) {
pc = cc->gdb_adjust_breakpoint(cpu, pc);
}
bp = g_malloc(sizeof(*bp)); bp = g_malloc(sizeof(*bp));
bp->pc = pc; bp->pc = pc;
@ -386,8 +375,6 @@ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
QTAILQ_INSERT_TAIL(&cpu->breakpoints, bp, entry); QTAILQ_INSERT_TAIL(&cpu->breakpoints, bp, entry);
} }
breakpoint_invalidate(cpu, pc);
if (breakpoint) { if (breakpoint) {
*breakpoint = bp; *breakpoint = bp;
} }
@ -399,8 +386,13 @@ int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
/* Remove a specific breakpoint. */ /* Remove a specific breakpoint. */
int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags) int cpu_breakpoint_remove(CPUState *cpu, vaddr pc, int flags)
{ {
CPUClass *cc = CPU_GET_CLASS(cpu);
CPUBreakpoint *bp; CPUBreakpoint *bp;
if (cc->gdb_adjust_breakpoint) {
pc = cc->gdb_adjust_breakpoint(cpu, pc);
}
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
if (bp->pc == pc && bp->flags == flags) { if (bp->pc == pc && bp->flags == flags) {
cpu_breakpoint_remove_by_ref(cpu, bp); cpu_breakpoint_remove_by_ref(cpu, bp);
@ -415,8 +407,6 @@ void cpu_breakpoint_remove_by_ref(CPUState *cpu, CPUBreakpoint *bp)
{ {
QTAILQ_REMOVE(&cpu->breakpoints, bp, entry); QTAILQ_REMOVE(&cpu->breakpoints, bp, entry);
breakpoint_invalidate(cpu, bp->pc);
trace_breakpoint_remove(cpu->cpu_index, bp->pc, bp->flags); trace_breakpoint_remove(cpu->cpu_index, bp->pc, bp->flags);
g_free(bp); g_free(bp);
} }
@ -441,10 +431,6 @@ void cpu_single_step(CPUState *cpu, int enabled)
cpu->singlestep_enabled = enabled; cpu->singlestep_enabled = enabled;
if (kvm_enabled()) { if (kvm_enabled()) {
kvm_update_guest_debug(cpu, 0); kvm_update_guest_debug(cpu, 0);
} else {
/* must flush all the translated code to avoid inconsistencies */
/* XXX: only flush what is necessary */
tb_flush(cpu);
} }
trace_breakpoint_singlestep(cpu->cpu_index, enabled); trace_breakpoint_singlestep(cpu->cpu_index, enabled);
} }

View File

@ -19,8 +19,6 @@
*/ */
#include "crypto/aes.h" #include "crypto/aes.h"
#include "crypto/desrfb.h"
#include "crypto/xts.h"
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext; typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
struct QCryptoCipherBuiltinAESContext { struct QCryptoCipherBuiltinAESContext {
@ -32,7 +30,6 @@ typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
struct QCryptoCipherBuiltinAES { struct QCryptoCipherBuiltinAES {
QCryptoCipher base; QCryptoCipher base;
QCryptoCipherBuiltinAESContext key; QCryptoCipherBuiltinAESContext key;
QCryptoCipherBuiltinAESContext key_tweak;
uint8_t iv[AES_BLOCK_SIZE]; uint8_t iv[AES_BLOCK_SIZE];
}; };
@ -194,39 +191,6 @@ static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher,
return 0; return 0;
} }
static int qcrypto_cipher_aes_encrypt_xts(QCryptoCipher *cipher,
const void *in, void *out,
size_t len, Error **errp)
{
QCryptoCipherBuiltinAES *ctx
= container_of(cipher, QCryptoCipherBuiltinAES, base);
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
return -1;
}
xts_encrypt(&ctx->key, &ctx->key_tweak,
do_aes_encrypt_ecb, do_aes_decrypt_ecb,
ctx->iv, len, out, in);
return 0;
}
static int qcrypto_cipher_aes_decrypt_xts(QCryptoCipher *cipher,
const void *in, void *out,
size_t len, Error **errp)
{
QCryptoCipherBuiltinAES *ctx
= container_of(cipher, QCryptoCipherBuiltinAES, base);
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
return -1;
}
xts_decrypt(&ctx->key, &ctx->key_tweak,
do_aes_encrypt_ecb, do_aes_decrypt_ecb,
ctx->iv, len, out, in);
return 0;
}
static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv, static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv,
size_t niv, Error **errp) size_t niv, Error **errp)
{ {
@ -257,84 +221,16 @@ static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = {
.cipher_free = qcrypto_cipher_ctx_free, .cipher_free = qcrypto_cipher_ctx_free,
}; };
static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_xts = {
.cipher_encrypt = qcrypto_cipher_aes_encrypt_xts,
.cipher_decrypt = qcrypto_cipher_aes_decrypt_xts,
.cipher_setiv = qcrypto_cipher_aes_setiv,
.cipher_free = qcrypto_cipher_ctx_free,
};
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
struct QCryptoCipherBuiltinDESRFB {
QCryptoCipher base;
/* C.f. alg_key_len[QCRYPTO_CIPHER_ALG_DES_RFB] */
uint8_t key[8];
};
static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher,
const void *in, void *out,
size_t len, Error **errp)
{
QCryptoCipherBuiltinDESRFB *ctx
= container_of(cipher, QCryptoCipherBuiltinDESRFB, base);
size_t i;
if (!qcrypto_length_check(len, 8, errp)) {
return -1;
}
deskey(ctx->key, EN0);
for (i = 0; i < len; i += 8) {
des((void *)in + i, out + i);
}
return 0;
}
static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher,
const void *in, void *out,
size_t len, Error **errp)
{
QCryptoCipherBuiltinDESRFB *ctx
= container_of(cipher, QCryptoCipherBuiltinDESRFB, base);
size_t i;
if (!qcrypto_length_check(len, 8, errp)) {
return -1;
}
deskey(ctx->key, DE1);
for (i = 0; i < len; i += 8) {
des((void *)in + i, out + i);
}
return 0;
}
static const struct QCryptoCipherDriver qcrypto_cipher_des_rfb_driver = {
.cipher_encrypt = qcrypto_cipher_encrypt_des_rfb,
.cipher_decrypt = qcrypto_cipher_decrypt_des_rfb,
.cipher_setiv = qcrypto_cipher_no_setiv,
.cipher_free = qcrypto_cipher_ctx_free,
};
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode) QCryptoCipherMode mode)
{ {
switch (alg) { switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
return mode == QCRYPTO_CIPHER_MODE_ECB;
case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256: case QCRYPTO_CIPHER_ALG_AES_256:
switch (mode) { switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB: case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC: case QCRYPTO_CIPHER_MODE_CBC:
case QCRYPTO_CIPHER_MODE_XTS:
return true; return true;
default: default:
return false; return false;
@ -356,18 +252,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
} }
switch (alg) { switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB:
if (mode == QCRYPTO_CIPHER_MODE_ECB) {
QCryptoCipherBuiltinDESRFB *ctx;
ctx = g_new0(QCryptoCipherBuiltinDESRFB, 1);
ctx->base.driver = &qcrypto_cipher_des_rfb_driver;
memcpy(ctx->key, key, sizeof(ctx->key));
return &ctx->base;
}
goto bad_mode;
case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256: case QCRYPTO_CIPHER_ALG_AES_256:
@ -382,9 +266,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_CBC: case QCRYPTO_CIPHER_MODE_CBC:
drv = &qcrypto_cipher_aes_driver_cbc; drv = &qcrypto_cipher_aes_driver_cbc;
break; break;
case QCRYPTO_CIPHER_MODE_XTS:
drv = &qcrypto_cipher_aes_driver_xts;
break;
default: default:
goto bad_mode; goto bad_mode;
} }
@ -392,19 +273,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
ctx = g_new0(QCryptoCipherBuiltinAES, 1); ctx = g_new0(QCryptoCipherBuiltinAES, 1);
ctx->base.driver = drv; ctx->base.driver = drv;
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
nkey /= 2;
if (AES_set_encrypt_key(key + nkey, nkey * 8,
&ctx->key_tweak.enc)) {
error_setg(errp, "Failed to set encryption key");
goto error;
}
if (AES_set_decrypt_key(key + nkey, nkey * 8,
&ctx->key_tweak.dec)) {
error_setg(errp, "Failed to set decryption key");
goto error;
}
}
if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) { if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) {
error_setg(errp, "Failed to set encryption key"); error_setg(errp, "Failed to set encryption key");
goto error; goto error;

View File

@ -18,17 +18,13 @@
* *
*/ */
#ifdef CONFIG_QEMU_PRIVATE_XTS
#include "crypto/xts.h"
#endif
#include <gcrypt.h> #include <gcrypt.h>
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode) QCryptoCipherMode mode)
{ {
switch (alg) { switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB: case QCRYPTO_CIPHER_ALG_DES:
case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_3DES:
case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_192:
@ -59,10 +55,6 @@ typedef struct QCryptoCipherGcrypt {
QCryptoCipher base; QCryptoCipher base;
gcry_cipher_hd_t handle; gcry_cipher_hd_t handle;
size_t blocksize; size_t blocksize;
#ifdef CONFIG_QEMU_PRIVATE_XTS
gcry_cipher_hd_t tweakhandle;
uint8_t iv[XTS_BLOCK_SIZE];
#endif
} QCryptoCipherGcrypt; } QCryptoCipherGcrypt;
@ -178,90 +170,6 @@ static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
.cipher_free = qcrypto_gcrypt_ctx_free, .cipher_free = qcrypto_gcrypt_ctx_free,
}; };
#ifdef CONFIG_QEMU_PRIVATE_XTS
static void qcrypto_gcrypt_xts_ctx_free(QCryptoCipher *cipher)
{
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
gcry_cipher_close(ctx->tweakhandle);
qcrypto_gcrypt_ctx_free(cipher);
}
static void qcrypto_gcrypt_xts_wrape(const void *ctx, size_t length,
uint8_t *dst, const uint8_t *src)
{
gcry_error_t err;
err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
g_assert(err == 0);
}
static void qcrypto_gcrypt_xts_wrapd(const void *ctx, size_t length,
uint8_t *dst, const uint8_t *src)
{
gcry_error_t err;
err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
g_assert(err == 0);
}
static int qcrypto_gcrypt_xts_encrypt(QCryptoCipher *cipher, const void *in,
void *out, size_t len, Error **errp)
{
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
if (len & (ctx->blocksize - 1)) {
error_setg(errp, "Length %zu must be a multiple of block size %zu",
len, ctx->blocksize);
return -1;
}
xts_encrypt(ctx->handle, ctx->tweakhandle,
qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd,
ctx->iv, len, out, in);
return 0;
}
static int qcrypto_gcrypt_xts_decrypt(QCryptoCipher *cipher, const void *in,
void *out, size_t len, Error **errp)
{
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
if (len & (ctx->blocksize - 1)) {
error_setg(errp, "Length %zu must be a multiple of block size %zu",
len, ctx->blocksize);
return -1;
}
xts_decrypt(ctx->handle, ctx->tweakhandle,
qcrypto_gcrypt_xts_wrape, qcrypto_gcrypt_xts_wrapd,
ctx->iv, len, out, in);
return 0;
}
static int qcrypto_gcrypt_xts_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
if (niv != ctx->blocksize) {
error_setg(errp, "Expected IV size %zu not %zu",
ctx->blocksize, niv);
return -1;
}
memcpy(ctx->iv, iv, niv);
return 0;
}
static const struct QCryptoCipherDriver qcrypto_gcrypt_xts_driver = {
.cipher_encrypt = qcrypto_gcrypt_xts_encrypt,
.cipher_decrypt = qcrypto_gcrypt_xts_decrypt,
.cipher_setiv = qcrypto_gcrypt_xts_setiv,
.cipher_free = qcrypto_gcrypt_xts_ctx_free,
};
#endif /* CONFIG_QEMU_PRIVATE_XTS */
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode, QCryptoCipherMode mode,
const uint8_t *key, const uint8_t *key,
@ -278,7 +186,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
} }
switch (alg) { switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB: case QCRYPTO_CIPHER_ALG_DES:
gcryalg = GCRY_CIPHER_DES; gcryalg = GCRY_CIPHER_DES;
break; break;
case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_3DES:
@ -323,12 +231,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
gcrymode = GCRY_CIPHER_MODE_ECB; gcrymode = GCRY_CIPHER_MODE_ECB;
break; break;
case QCRYPTO_CIPHER_MODE_XTS: case QCRYPTO_CIPHER_MODE_XTS:
#ifdef CONFIG_QEMU_PRIVATE_XTS
drv = &qcrypto_gcrypt_xts_driver;
gcrymode = GCRY_CIPHER_MODE_ECB;
#else
gcrymode = GCRY_CIPHER_MODE_XTS; gcrymode = GCRY_CIPHER_MODE_XTS;
#endif
break; break;
case QCRYPTO_CIPHER_MODE_CBC: case QCRYPTO_CIPHER_MODE_CBC:
gcrymode = GCRY_CIPHER_MODE_CBC; gcrymode = GCRY_CIPHER_MODE_CBC;
@ -354,44 +257,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
} }
ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg); ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
#ifdef CONFIG_QEMU_PRIVATE_XTS
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
if (ctx->blocksize != XTS_BLOCK_SIZE) {
error_setg(errp,
"Cipher block size %zu must equal XTS block size %d",
ctx->blocksize, XTS_BLOCK_SIZE);
goto error;
}
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gcry_strerror(err));
goto error;
}
}
#endif
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
/* We're using standard DES cipher from gcrypt, so we need
* to munge the key so that the results are the same as the
* bizarre RFB variant of DES :-)
*/
uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
g_free(rfbkey);
} else {
#ifdef CONFIG_QEMU_PRIVATE_XTS
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
nkey /= 2;
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
if (err != 0) {
error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
goto error;
}
}
#endif
err = gcry_cipher_setkey(ctx->handle, key, nkey); err = gcry_cipher_setkey(ctx->handle, key, nkey);
}
if (err != 0) { if (err != 0) {
error_setg(errp, "Cannot set key: %s", gcry_strerror(err)); error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
goto error; goto error;
@ -400,9 +266,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base; return &ctx->base;
error: error:
#ifdef CONFIG_QEMU_PRIVATE_XTS
gcry_cipher_close(ctx->tweakhandle);
#endif
gcry_cipher_close(ctx->handle); gcry_cipher_close(ctx->handle);
g_free(ctx); g_free(ctx);
return NULL; return NULL;

335
crypto/cipher-gnutls.c.inc Normal file
View File

@ -0,0 +1,335 @@
/*
* QEMU Crypto cipher gnutls algorithms
*
* Copyright (c) 2021 Red Hat, Inc.
*
* 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/>.
*
*/
#include "qemu/osdep.h"
#include "cipherpriv.h"
#include <gnutls/crypto.h>
#if GNUTLS_VERSION_NUMBER >= 0x030608
#define QEMU_GNUTLS_XTS
#endif
bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode)
{
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
switch (alg) {
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192:
case QCRYPTO_CIPHER_ALG_AES_256:
case QCRYPTO_CIPHER_ALG_DES:
case QCRYPTO_CIPHER_ALG_3DES:
return true;
default:
return false;
}
#ifdef QEMU_GNUTLS_XTS
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_256:
return true;
default:
return false;
}
#endif
default:
return false;
}
}
typedef struct QCryptoCipherGnutls QCryptoCipherGnutls;
struct QCryptoCipherGnutls {
QCryptoCipher base;
gnutls_cipher_hd_t handle; /* XTS & CBC mode */
gnutls_cipher_algorithm_t galg; /* ECB mode */
guint8 *key; /* ECB mode */
size_t nkey; /* ECB mode */
size_t blocksize;
};
static void
qcrypto_gnutls_cipher_free(QCryptoCipher *cipher)
{
QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
g_free(ctx->key);
if (ctx->handle) {
gnutls_cipher_deinit(ctx->handle);
}
g_free(ctx);
}
static int
qcrypto_gnutls_cipher_encrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
int err;
if (len % ctx->blocksize) {
error_setg(errp, "Length %zu must be a multiple of block size %zu",
len, ctx->blocksize);
return -1;
}
if (ctx->handle) { /* CBC / XTS mode */
err = gnutls_cipher_encrypt2(ctx->handle,
in, len,
out, len);
if (err != 0) {
error_setg(errp, "Cannot encrypt data: %s",
gnutls_strerror(err));
return -1;
}
} else { /* ECB mode very inefficiently faked with CBC */
g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
while (len) {
gnutls_cipher_hd_t handle;
gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey };
int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gnutls_strerror(err));
return -1;
}
gnutls_cipher_set_iv(handle, iv, ctx->blocksize);
err = gnutls_cipher_encrypt2(handle,
in, ctx->blocksize,
out, ctx->blocksize);
if (err != 0) {
gnutls_cipher_deinit(handle);
error_setg(errp, "Cannot encrypt data: %s",
gnutls_strerror(err));
return -1;
}
gnutls_cipher_deinit(handle);
len -= ctx->blocksize;
in += ctx->blocksize;
out += ctx->blocksize;
}
}
return 0;
}
static int
qcrypto_gnutls_cipher_decrypt(QCryptoCipher *cipher,
const void *in,
void *out,
size_t len,
Error **errp)
{
QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
int err;
if (len % ctx->blocksize) {
error_setg(errp, "Length %zu must be a multiple of block size %zu",
len, ctx->blocksize);
return -1;
}
if (ctx->handle) { /* CBC / XTS mode */
err = gnutls_cipher_decrypt2(ctx->handle,
in, len,
out, len);
if (err != 0) {
error_setg(errp, "Cannot decrypt data: %s",
gnutls_strerror(err));
return -1;
}
} else { /* ECB mode very inefficiently faked with CBC */
g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
while (len) {
gnutls_cipher_hd_t handle;
gnutls_datum_t gkey = { (unsigned char *)ctx->key, ctx->nkey };
int err = gnutls_cipher_init(&handle, ctx->galg, &gkey, NULL);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gnutls_strerror(err));
return -1;
}
gnutls_cipher_set_iv(handle, iv, ctx->blocksize);
err = gnutls_cipher_decrypt2(handle,
in, ctx->blocksize,
out, ctx->blocksize);
if (err != 0) {
gnutls_cipher_deinit(handle);
error_setg(errp, "Cannot encrypt data: %s",
gnutls_strerror(err));
return -1;
}
gnutls_cipher_deinit(handle);
len -= ctx->blocksize;
in += ctx->blocksize;
out += ctx->blocksize;
}
}
return 0;
}
static int
qcrypto_gnutls_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv, size_t niv,
Error **errp)
{
QCryptoCipherGnutls *ctx = container_of(cipher, QCryptoCipherGnutls, base);
if (niv != ctx->blocksize) {
error_setg(errp, "Expected IV size %zu not %zu",
ctx->blocksize, niv);
return -1;
}
gnutls_cipher_set_iv(ctx->handle, (unsigned char *)iv, niv);
return 0;
}
static struct QCryptoCipherDriver gnutls_driver = {
.cipher_encrypt = qcrypto_gnutls_cipher_encrypt,
.cipher_decrypt = qcrypto_gnutls_cipher_decrypt,
.cipher_setiv = qcrypto_gnutls_cipher_setiv,
.cipher_free = qcrypto_gnutls_cipher_free,
};
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey,
Error **errp)
{
QCryptoCipherGnutls *ctx;
gnutls_datum_t gkey = { (unsigned char *)key, nkey };
gnutls_cipher_algorithm_t galg = GNUTLS_CIPHER_UNKNOWN;
int err;
switch (mode) {
#ifdef QEMU_GNUTLS_XTS
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
case QCRYPTO_CIPHER_ALG_AES_128:
galg = GNUTLS_CIPHER_AES_128_XTS;
break;
case QCRYPTO_CIPHER_ALG_AES_256:
galg = GNUTLS_CIPHER_AES_256_XTS;
break;
default:
break;
}
break;
#endif
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
switch (alg) {
case QCRYPTO_CIPHER_ALG_AES_128:
galg = GNUTLS_CIPHER_AES_128_CBC;
break;
case QCRYPTO_CIPHER_ALG_AES_192:
galg = GNUTLS_CIPHER_AES_192_CBC;
break;
case QCRYPTO_CIPHER_ALG_AES_256:
galg = GNUTLS_CIPHER_AES_256_CBC;
break;
case QCRYPTO_CIPHER_ALG_DES:
galg = GNUTLS_CIPHER_DES_CBC;
break;
case QCRYPTO_CIPHER_ALG_3DES:
galg = GNUTLS_CIPHER_3DES_CBC;
break;
default:
break;
}
break;
default:
break;
}
if (galg == GNUTLS_CIPHER_UNKNOWN) {
error_setg(errp, "Unsupported cipher algorithm %s with %s mode",
QCryptoCipherAlgorithm_str(alg),
QCryptoCipherMode_str(mode));
return NULL;
}
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
return NULL;
}
ctx = g_new0(QCryptoCipherGnutls, 1);
ctx->base.driver = &gnutls_driver;
if (mode == QCRYPTO_CIPHER_MODE_ECB) {
ctx->key = g_new0(guint8, nkey);
memcpy(ctx->key, key, nkey);
ctx->nkey = nkey;
ctx->galg = galg;
} else {
err = gnutls_cipher_init(&ctx->handle, galg, &gkey, NULL);
if (err != 0) {
error_setg(errp, "Cannot initialize cipher: %s",
gnutls_strerror(err));
goto error;
}
}
if (alg == QCRYPTO_CIPHER_ALG_DES ||
alg == QCRYPTO_CIPHER_ALG_3DES)
ctx->blocksize = 8;
else
ctx->blocksize = 16;
/*
* Our API contract for requires iv to be optional
* but nettle gets unhappy when called by gnutls
* in this case, so we just force set a default
* all-zeros IV, to match behaviour of other backends.
*/
if (mode != QCRYPTO_CIPHER_MODE_ECB) {
g_autofree unsigned char *iv = g_new0(unsigned char, ctx->blocksize);
gnutls_cipher_set_iv(ctx->handle, iv, ctx->blocksize);
}
return &ctx->base;
error:
qcrypto_gnutls_cipher_free(&ctx->base);
return NULL;
}

View File

@ -235,11 +235,11 @@ static const struct QCryptoCipherDriver NAME##_driver_xts = { \
DEFINE_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) DEFINE_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT)
typedef struct QCryptoNettleDESRFB { typedef struct QCryptoNettleDES {
QCryptoCipher base; QCryptoCipher base;
struct des_ctx key; struct des_ctx key;
uint8_t iv[DES_BLOCK_SIZE]; uint8_t iv[DES_BLOCK_SIZE];
} QCryptoNettleDESRFB; } QCryptoNettleDES;
static void des_encrypt_native(const void *ctx, size_t length, static void des_encrypt_native(const void *ctx, size_t length,
uint8_t *dst, const uint8_t *src) uint8_t *dst, const uint8_t *src)
@ -253,7 +253,7 @@ static void des_decrypt_native(const void *ctx, size_t length,
des_decrypt(ctx, length, dst, src); des_decrypt(ctx, length, dst, src);
} }
DEFINE_ECB_CBC_CTR(qcrypto_nettle_des_rfb, QCryptoNettleDESRFB, DEFINE_ECB_CBC_CTR(qcrypto_nettle_des, QCryptoNettleDES,
DES_BLOCK_SIZE, des_encrypt_native, des_decrypt_native) DES_BLOCK_SIZE, des_encrypt_native, des_decrypt_native)
@ -431,7 +431,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode) QCryptoCipherMode mode)
{ {
switch (alg) { switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB: case QCRYPTO_CIPHER_ALG_DES:
case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_3DES:
case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_128:
case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_192:
@ -480,32 +480,28 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
} }
switch (alg) { switch (alg) {
case QCRYPTO_CIPHER_ALG_DES_RFB: case QCRYPTO_CIPHER_ALG_DES:
{ {
QCryptoNettleDESRFB *ctx; QCryptoNettleDES *ctx;
const QCryptoCipherDriver *drv; const QCryptoCipherDriver *drv;
uint8_t *rfbkey;
switch (mode) { switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB: case QCRYPTO_CIPHER_MODE_ECB:
drv = &qcrypto_nettle_des_rfb_driver_ecb; drv = &qcrypto_nettle_des_driver_ecb;
break; break;
case QCRYPTO_CIPHER_MODE_CBC: case QCRYPTO_CIPHER_MODE_CBC:
drv = &qcrypto_nettle_des_rfb_driver_cbc; drv = &qcrypto_nettle_des_driver_cbc;
break; break;
case QCRYPTO_CIPHER_MODE_CTR: case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_nettle_des_rfb_driver_ctr; drv = &qcrypto_nettle_des_driver_ctr;
break; break;
default: default:
goto bad_cipher_mode; goto bad_cipher_mode;
} }
ctx = g_new0(QCryptoNettleDESRFB, 1); ctx = g_new0(QCryptoNettleDES, 1);
ctx->base.driver = drv; ctx->base.driver = drv;
des_set_key(&ctx->key, key);
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
des_set_key(&ctx->key, rfbkey);
g_free(rfbkey);
return &ctx->base; return &ctx->base;
} }

View File

@ -29,7 +29,7 @@ static const size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
[QCRYPTO_CIPHER_ALG_AES_128] = 16, [QCRYPTO_CIPHER_ALG_AES_128] = 16,
[QCRYPTO_CIPHER_ALG_AES_192] = 24, [QCRYPTO_CIPHER_ALG_AES_192] = 24,
[QCRYPTO_CIPHER_ALG_AES_256] = 32, [QCRYPTO_CIPHER_ALG_AES_256] = 32,
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8, [QCRYPTO_CIPHER_ALG_DES] = 8,
[QCRYPTO_CIPHER_ALG_3DES] = 24, [QCRYPTO_CIPHER_ALG_3DES] = 24,
[QCRYPTO_CIPHER_ALG_CAST5_128] = 16, [QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
@ -44,7 +44,7 @@ static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
[QCRYPTO_CIPHER_ALG_AES_128] = 16, [QCRYPTO_CIPHER_ALG_AES_128] = 16,
[QCRYPTO_CIPHER_ALG_AES_192] = 16, [QCRYPTO_CIPHER_ALG_AES_192] = 16,
[QCRYPTO_CIPHER_ALG_AES_256] = 16, [QCRYPTO_CIPHER_ALG_AES_256] = 16,
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8, [QCRYPTO_CIPHER_ALG_DES] = 8,
[QCRYPTO_CIPHER_ALG_3DES] = 8, [QCRYPTO_CIPHER_ALG_3DES] = 8,
[QCRYPTO_CIPHER_ALG_CAST5_128] = 8, [QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
@ -107,9 +107,9 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
} }
if (mode == QCRYPTO_CIPHER_MODE_XTS) { if (mode == QCRYPTO_CIPHER_MODE_XTS) {
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB if (alg == QCRYPTO_CIPHER_ALG_DES ||
|| alg == QCRYPTO_CIPHER_ALG_3DES) { alg == QCRYPTO_CIPHER_ALG_3DES) {
error_setg(errp, "XTS mode not compatible with DES-RFB/3DES"); error_setg(errp, "XTS mode not compatible with DES/3DES");
return false; return false;
} }
if (nkey % 2) { if (nkey % 2) {
@ -132,28 +132,12 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
return true; return true;
} }
#if defined(CONFIG_GCRYPT) || defined(CONFIG_NETTLE)
static uint8_t *
qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
size_t nkey)
{
uint8_t *ret = g_new0(uint8_t, nkey);
size_t i;
for (i = 0; i < nkey; i++) {
uint8_t r = key[i];
r = (r & 0xf0) >> 4 | (r & 0x0f) << 4;
r = (r & 0xcc) >> 2 | (r & 0x33) << 2;
r = (r & 0xaa) >> 1 | (r & 0x55) << 1;
ret[i] = r;
}
return ret;
}
#endif /* CONFIG_GCRYPT || CONFIG_NETTLE */
#ifdef CONFIG_GCRYPT #ifdef CONFIG_GCRYPT
#include "cipher-gcrypt.c.inc" #include "cipher-gcrypt.c.inc"
#elif defined CONFIG_NETTLE #elif defined CONFIG_NETTLE
#include "cipher-nettle.c.inc" #include "cipher-nettle.c.inc"
#elif defined CONFIG_GNUTLS_CRYPTO
#include "cipher-gnutls.c.inc"
#else #else
#include "cipher-builtin.c.inc" #include "cipher-builtin.c.inc"
#endif #endif

View File

@ -1,416 +0,0 @@
/*
* This is D3DES (V5.09) by Richard Outerbridge with the double and
* triple-length support removed for use in VNC. Also the bytebit[] array
* has been reversed so that the most significant bit in each byte of the
* key is ignored, not the least significant.
*
* These changes are:
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
*
* This software 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.
*/
/* D3DES (V5.09) -
*
* A portable, public domain, version of the Data Encryption Standard.
*
* Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
* Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
* code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
* Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
* for humouring me on.
*
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
*/
#include "qemu/osdep.h"
#include "crypto/desrfb.h"
static void scrunch(unsigned char *, unsigned long *);
static void unscrun(unsigned long *, unsigned char *);
static void desfunc(unsigned long *, unsigned long *);
static void cookey(unsigned long *);
static unsigned long KnL[32] = { 0L };
static const unsigned short bytebit[8] = {
01, 02, 04, 010, 020, 040, 0100, 0200 };
static const unsigned long bigbyte[24] = {
0x800000L, 0x400000L, 0x200000L, 0x100000L,
0x80000L, 0x40000L, 0x20000L, 0x10000L,
0x8000L, 0x4000L, 0x2000L, 0x1000L,
0x800L, 0x400L, 0x200L, 0x100L,
0x80L, 0x40L, 0x20L, 0x10L,
0x8L, 0x4L, 0x2L, 0x1L };
/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
static const unsigned char pc1[56] = {
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
static const unsigned char totrot[16] = {
1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 };
static const unsigned char pc2[48] = {
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
/* Thanks to James Gillogly & Phil Karn! */
void deskey(unsigned char *key, int edf)
{
register int i, j, l, m, n;
unsigned char pc1m[56], pcr[56];
unsigned long kn[32];
for ( j = 0; j < 56; j++ ) {
l = pc1[j];
m = l & 07;
pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
}
for( i = 0; i < 16; i++ ) {
if( edf == DE1 ) m = (15 - i) << 1;
else m = i << 1;
n = m + 1;
kn[m] = kn[n] = 0L;
for( j = 0; j < 28; j++ ) {
l = j + totrot[i];
if( l < 28 ) pcr[j] = pc1m[l];
else pcr[j] = pc1m[l - 28];
}
for( j = 28; j < 56; j++ ) {
l = j + totrot[i];
if( l < 56 ) pcr[j] = pc1m[l];
else pcr[j] = pc1m[l - 28];
}
for( j = 0; j < 24; j++ ) {
if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
if( pcr[pc2[j + 24]] ) kn[n] |= bigbyte[j];
}
}
cookey(kn);
return;
}
static void cookey(register unsigned long *raw1)
{
register unsigned long *cook, *raw0;
unsigned long dough[32];
register int i;
cook = dough;
for( i = 0; i < 16; i++, raw1++ ) {
raw0 = raw1++;
*cook = (*raw0 & 0x00fc0000L) << 6;
*cook |= (*raw0 & 0x00000fc0L) << 10;
*cook |= (*raw1 & 0x00fc0000L) >> 10;
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
*cook = (*raw0 & 0x0003f000L) << 12;
*cook |= (*raw0 & 0x0000003fL) << 16;
*cook |= (*raw1 & 0x0003f000L) >> 4;
*cook++ |= (*raw1 & 0x0000003fL);
}
usekey(dough);
return;
}
void usekey(register unsigned long *from)
{
register unsigned long *to, *endp;
to = KnL, endp = &KnL[32];
while( to < endp ) *to++ = *from++;
return;
}
void des(unsigned char *inblock, unsigned char *outblock)
{
unsigned long work[2];
scrunch(inblock, work);
desfunc(work, KnL);
unscrun(work, outblock);
return;
}
static void scrunch(register unsigned char *outof, register unsigned long *into)
{
*into = (*outof++ & 0xffL) << 24;
*into |= (*outof++ & 0xffL) << 16;
*into |= (*outof++ & 0xffL) << 8;
*into++ |= (*outof++ & 0xffL);
*into = (*outof++ & 0xffL) << 24;
*into |= (*outof++ & 0xffL) << 16;
*into |= (*outof++ & 0xffL) << 8;
*into |= (*outof & 0xffL);
return;
}
static void unscrun(register unsigned long *outof, register unsigned char *into)
{
*into++ = (unsigned char)((*outof >> 24) & 0xffL);
*into++ = (unsigned char)((*outof >> 16) & 0xffL);
*into++ = (unsigned char)((*outof >> 8) & 0xffL);
*into++ = (unsigned char)(*outof++ & 0xffL);
*into++ = (unsigned char)((*outof >> 24) & 0xffL);
*into++ = (unsigned char)((*outof >> 16) & 0xffL);
*into++ = (unsigned char)((*outof >> 8) & 0xffL);
*into = (unsigned char)(*outof & 0xffL);
return;
}
static const unsigned long SP1[64] = {
0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
static const unsigned long SP2[64] = {
0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
static const unsigned long SP3[64] = {
0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
static const unsigned long SP4[64] = {
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
static const unsigned long SP5[64] = {
0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
static const unsigned long SP6[64] = {
0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
static const unsigned long SP7[64] = {
0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
static const unsigned long SP8[64] = {
0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
static void desfunc(register unsigned long *block, register unsigned long *keys)
{
register unsigned long fval, work, right, leftt;
register int round;
leftt = block[0];
right = block[1];
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
right ^= work;
leftt ^= (work << 4);
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
right ^= work;
leftt ^= (work << 16);
work = ((right >> 2) ^ leftt) & 0x33333333L;
leftt ^= work;
right ^= (work << 2);
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
leftt ^= work;
right ^= (work << 8);
right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
for( round = 0; round < 8; round++ ) {
work = (right << 28) | (right >> 4);
work ^= *keys++;
fval = SP7[ work & 0x3fL];
fval |= SP5[(work >> 8) & 0x3fL];
fval |= SP3[(work >> 16) & 0x3fL];
fval |= SP1[(work >> 24) & 0x3fL];
work = right ^ *keys++;
fval |= SP8[ work & 0x3fL];
fval |= SP6[(work >> 8) & 0x3fL];
fval |= SP4[(work >> 16) & 0x3fL];
fval |= SP2[(work >> 24) & 0x3fL];
leftt ^= fval;
work = (leftt << 28) | (leftt >> 4);
work ^= *keys++;
fval = SP7[ work & 0x3fL];
fval |= SP5[(work >> 8) & 0x3fL];
fval |= SP3[(work >> 16) & 0x3fL];
fval |= SP1[(work >> 24) & 0x3fL];
work = leftt ^ *keys++;
fval |= SP8[ work & 0x3fL];
fval |= SP6[(work >> 8) & 0x3fL];
fval |= SP4[(work >> 16) & 0x3fL];
fval |= SP2[(work >> 24) & 0x3fL];
right ^= fval;
}
right = (right << 31) | (right >> 1);
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = (leftt << 31) | (leftt >> 1);
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
right ^= work;
leftt ^= (work << 8);
work = ((leftt >> 2) ^ right) & 0x33333333L;
right ^= work;
leftt ^= (work << 2);
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
leftt ^= work;
right ^= (work << 16);
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
leftt ^= work;
right ^= (work << 4);
*block++ = right;
*block = leftt;
return;
}
/* Validation sets:
*
* Single-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef
* Plain : 0123 4567 89ab cde7
* Cipher : c957 4425 6a5e d31d
*
* Double-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cde7
* Cipher : 7f1d 0a77 826b 8aff
*
* Double-length key, double-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
* Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
*
* Triple-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
* Plain : 0123 4567 89ab cde7
* Cipher : de0b 7c06 ae5e 0ed5
*
* Triple-length key, double-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
* Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
*
* d3des V5.0a rwo 9208.07 18:44 Graven Imagery
**********************************************************************/

104
crypto/hash-gnutls.c Normal file
View File

@ -0,0 +1,104 @@
/*
* QEMU Crypto hash algorithms
*
* Copyright (c) 2021 Red Hat, Inc.
*
* 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/>.
*
*/
#include "qemu/osdep.h"
#include <gnutls/crypto.h>
#include "qapi/error.h"
#include "crypto/hash.h"
#include "hashpriv.h"
static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
[QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224,
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
[QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384,
[QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512,
[QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160,
};
gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
{
size_t i;
const gnutls_digest_algorithm_t *algs;
if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map) ||
qcrypto_hash_alg_map[alg] == GNUTLS_DIG_UNKNOWN) {
return false;
}
algs = gnutls_digest_list();
for (i = 0; algs[i] != GNUTLS_DIG_UNKNOWN; i++) {
if (algs[i] == qcrypto_hash_alg_map[alg]) {
return true;
}
}
return false;
}
static int
qcrypto_gnutls_hash_bytesv(QCryptoHashAlgorithm alg,
const struct iovec *iov,
size_t niov,
uint8_t **result,
size_t *resultlen,
Error **errp)
{
int i, ret;
gnutls_hash_hd_t hash;
if (!qcrypto_hash_supports(alg)) {
error_setg(errp,
"Unknown hash algorithm %d",
alg);
return -1;
}
ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]);
if (*resultlen == 0) {
*resultlen = ret;
*result = g_new0(uint8_t, *resultlen);
} else if (*resultlen != ret) {
error_setg(errp,
"Result buffer size %zu is smaller than hash %d",
*resultlen, ret);
return -1;
}
ret = gnutls_hash_init(&hash, qcrypto_hash_alg_map[alg]);
if (ret < 0) {
error_setg(errp,
"Unable to initialize hash algorithm: %s",
gnutls_strerror(ret));
return -1;
}
for (i = 0; i < niov; i++) {
gnutls_hash(hash, iov[i].iov_base, iov[i].iov_len);
}
gnutls_hash_deinit(hash, *result);
return 0;
}
QCryptoHashDriver qcrypto_hash_lib_driver = {
.hash_bytesv = qcrypto_gnutls_hash_bytesv,
};

139
crypto/hmac-gnutls.c Normal file
View File

@ -0,0 +1,139 @@
/*
* QEMU Crypto hmac algorithms
*
* Copyright (c) 2021 Red Hat, Inc.
*
* Derived from hmac-gcrypt.c:
*
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*
*/
#include "qemu/osdep.h"
#include <gnutls/crypto.h>
#include "qapi/error.h"
#include "crypto/hmac.h"
#include "hmacpriv.h"
static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_MAC_MD5,
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_MAC_SHA1,
[QCRYPTO_HASH_ALG_SHA224] = GNUTLS_MAC_SHA224,
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_MAC_SHA256,
[QCRYPTO_HASH_ALG_SHA384] = GNUTLS_MAC_SHA384,
[QCRYPTO_HASH_ALG_SHA512] = GNUTLS_MAC_SHA512,
[QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_MAC_RMD160,
};
typedef struct QCryptoHmacGnutls QCryptoHmacGnutls;
struct QCryptoHmacGnutls {
gnutls_hmac_hd_t handle;
};
bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
{
size_t i;
const gnutls_digest_algorithm_t *algs;
if (alg >= G_N_ELEMENTS(qcrypto_hmac_alg_map) ||
qcrypto_hmac_alg_map[alg] == GNUTLS_DIG_UNKNOWN) {
return false;
}
algs = gnutls_digest_list();
for (i = 0; algs[i] != GNUTLS_DIG_UNKNOWN; i++) {
if (algs[i] == qcrypto_hmac_alg_map[alg]) {
return true;
}
}
return false;
}
void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
const uint8_t *key, size_t nkey,
Error **errp)
{
QCryptoHmacGnutls *ctx;
int err;
if (!qcrypto_hmac_supports(alg)) {
error_setg(errp, "Unsupported hmac algorithm %s",
QCryptoHashAlgorithm_str(alg));
return NULL;
}
ctx = g_new0(QCryptoHmacGnutls, 1);
err = gnutls_hmac_init(&ctx->handle,
qcrypto_hmac_alg_map[alg],
(const void *)key, nkey);
if (err != 0) {
error_setg(errp, "Cannot initialize hmac: %s",
gnutls_strerror(err));
goto error;
}
return ctx;
error:
g_free(ctx);
return NULL;
}
static void
qcrypto_gnutls_hmac_ctx_free(QCryptoHmac *hmac)
{
QCryptoHmacGnutls *ctx;
ctx = hmac->opaque;
gnutls_hmac_deinit(ctx->handle, NULL);
g_free(ctx);
}
static int
qcrypto_gnutls_hmac_bytesv(QCryptoHmac *hmac,
const struct iovec *iov,
size_t niov,
uint8_t **result,
size_t *resultlen,
Error **errp)
{
QCryptoHmacGnutls *ctx;
uint32_t ret;
int i;
ctx = hmac->opaque;
for (i = 0; i < niov; i++) {
gnutls_hmac(ctx->handle, iov[i].iov_base, iov[i].iov_len);
}
ret = gnutls_hmac_get_len(qcrypto_hmac_alg_map[hmac->alg]);
if (ret <= 0) {
error_setg(errp, "Unable to get hmac length: %s",
gnutls_strerror(ret));
return -1;
}
if (*resultlen == 0) {
*resultlen = ret;
*result = g_new0(uint8_t, *resultlen);
} else if (*resultlen != ret) {
error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
*resultlen, ret);
return -1;
}
gnutls_hmac_output(ctx->handle, *result);
return 0;
}
QCryptoHmacDriver qcrypto_hmac_lib_driver = {
.hmac_bytesv = qcrypto_gnutls_hmac_bytesv,
.hmac_free = qcrypto_gnutls_hmac_ctx_free,
};

View File

@ -35,21 +35,6 @@
#include "crypto/random.h" #include "crypto/random.h"
/* #define DEBUG_GNUTLS */ /* #define DEBUG_GNUTLS */
/*
* We need to init gcrypt threading if
*
* - gcrypt < 1.6.0
*
*/
#if (defined(CONFIG_GCRYPT) && \
(GCRYPT_VERSION_NUMBER < 0x010600))
#define QCRYPTO_INIT_GCRYPT_THREADS
#else
#undef QCRYPTO_INIT_GCRYPT_THREADS
#endif
#ifdef DEBUG_GNUTLS #ifdef DEBUG_GNUTLS
static void qcrypto_gnutls_log(int level, const char *str) static void qcrypto_gnutls_log(int level, const char *str)
{ {
@ -57,55 +42,8 @@ static void qcrypto_gnutls_log(int level, const char *str)
} }
#endif #endif
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
static int qcrypto_gcrypt_mutex_init(void **priv)
{ \
QemuMutex *lock = NULL;
lock = g_new0(QemuMutex, 1);
qemu_mutex_init(lock);
*priv = lock;
return 0;
}
static int qcrypto_gcrypt_mutex_destroy(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_destroy(lock);
g_free(lock);
return 0;
}
static int qcrypto_gcrypt_mutex_lock(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_lock(lock);
return 0;
}
static int qcrypto_gcrypt_mutex_unlock(void **priv)
{
QemuMutex *lock = *priv;
qemu_mutex_unlock(lock);
return 0;
}
static struct gcry_thread_cbs qcrypto_gcrypt_thread_impl = {
(GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)),
NULL,
qcrypto_gcrypt_mutex_init,
qcrypto_gcrypt_mutex_destroy,
qcrypto_gcrypt_mutex_lock,
qcrypto_gcrypt_mutex_unlock,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
#endif /* QCRYPTO_INIT_GCRYPT */
int qcrypto_init(Error **errp) int qcrypto_init(Error **errp)
{ {
#ifdef QCRYPTO_INIT_GCRYPT_THREADS
gcry_control(GCRYCTL_SET_THREAD_CBS, &qcrypto_gcrypt_thread_impl);
#endif /* QCRYPTO_INIT_GCRYPT_THREADS */
#ifdef CONFIG_GNUTLS #ifdef CONFIG_GNUTLS
int ret; int ret;
ret = gnutls_global_init(); ret = gnutls_global_init();

View File

@ -5,7 +5,6 @@ crypto_ss.add(files(
'block-qcow.c', 'block-qcow.c',
'block.c', 'block.c',
'cipher.c', 'cipher.c',
'desrfb.c',
'hash.c', 'hash.c',
'hmac.c', 'hmac.c',
'ivgen-essiv.c', 'ivgen-essiv.c',
@ -24,14 +23,16 @@ crypto_ss.add(files(
if nettle.found() if nettle.found()
crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c')) crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c'))
elif gcrypt.found()
crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
else
crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c'))
endif
if xts == 'private' if xts == 'private'
crypto_ss.add(files('xts.c')) crypto_ss.add(files('xts.c'))
endif endif
elif gcrypt.found()
crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
elif gnutls_crypto.found()
crypto_ss.add(gnutls, files('hash-gnutls.c', 'hmac-gnutls.c', 'pbkdf-gnutls.c'))
else
crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c'))
endif
crypto_ss.add(when: 'CONFIG_SECRET_KEYRING', if_true: files('secret_keyring.c')) crypto_ss.add(when: 'CONFIG_SECRET_KEYRING', if_true: files('secret_keyring.c'))
crypto_ss.add(when: 'CONFIG_AF_ALG', if_true: files('afalg.c', 'cipher-afalg.c', 'hash-afalg.c')) crypto_ss.add(when: 'CONFIG_AF_ALG', if_true: files('afalg.c', 'cipher-afalg.c', 'hash-afalg.c'))
@ -39,6 +40,9 @@ crypto_ss.add(when: gnutls, if_true: files('tls-cipher-suites.c'))
util_ss.add(files('aes.c')) util_ss.add(files('aes.c'))
util_ss.add(files('init.c')) util_ss.add(files('init.c'))
if gnutls.found()
util_ss.add(gnutls)
endif
if gcrypt.found() if gcrypt.found()
util_ss.add(gcrypt, files('random-gcrypt.c')) util_ss.add(gcrypt, files('random-gcrypt.c'))

90
crypto/pbkdf-gnutls.c Normal file
View File

@ -0,0 +1,90 @@
/*
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
*
* Copyright (c) 2021 Red Hat, Inc.
*
* 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/>.
*
*/
#include "qemu/osdep.h"
#include <gnutls/crypto.h>
#include "qapi/error.h"
#include "crypto/pbkdf.h"
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
{
switch (hash) {
case QCRYPTO_HASH_ALG_MD5:
case QCRYPTO_HASH_ALG_SHA1:
case QCRYPTO_HASH_ALG_SHA224:
case QCRYPTO_HASH_ALG_SHA256:
case QCRYPTO_HASH_ALG_SHA384:
case QCRYPTO_HASH_ALG_SHA512:
case QCRYPTO_HASH_ALG_RIPEMD160:
return true;
default:
return false;
}
}
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp)
{
static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
[QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
[QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
[QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224,
[QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
[QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384,
[QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512,
[QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160,
};
int ret;
const gnutls_datum_t gkey = { (unsigned char *)key, nkey };
const gnutls_datum_t gsalt = { (unsigned char *)salt, nsalt };
if (iterations > ULONG_MAX) {
error_setg_errno(errp, ERANGE,
"PBKDF iterations %llu must be less than %lu",
(long long unsigned)iterations, ULONG_MAX);
return -1;
}
if (hash >= G_N_ELEMENTS(hash_map) ||
hash_map[hash] == GNUTLS_DIG_UNKNOWN) {
error_setg_errno(errp, ENOSYS,
"PBKDF does not support hash algorithm %s",
QCryptoHashAlgorithm_str(hash));
return -1;
}
ret = gnutls_pbkdf2(hash_map[hash],
&gkey,
&gsalt,
iterations,
out,
nout);
if (ret != 0) {
error_setg(errp, "Cannot derive password: %s",
gnutls_strerror(ret));
return -1;
}
return 0;
}

View File

@ -33,7 +33,7 @@ int print_insn_hexagon(bfd_vma memaddr, struct disassemble_info *info)
{ {
uint32_t words[PACKET_WORDS_MAX]; uint32_t words[PACKET_WORDS_MAX];
bool found_end = false; bool found_end = false;
GString *buf = g_string_sized_new(PACKET_BUFFER_LEN); GString *buf;
int i, len; int i, len;
for (i = 0; i < PACKET_WORDS_MAX && !found_end; i++) { for (i = 0; i < PACKET_WORDS_MAX && !found_end; i++) {
@ -57,6 +57,7 @@ int print_insn_hexagon(bfd_vma memaddr, struct disassemble_info *info)
return PACKET_WORDS_MAX * sizeof(uint32_t); return PACKET_WORDS_MAX * sizeof(uint32_t);
} }
buf = g_string_sized_new(PACKET_BUFFER_LEN);
len = disassemble_hexagon(words, i, memaddr, buf); len = disassemble_hexagon(words, i, memaddr, buf);
(*info->fprintf_func)(info->stream, "%s", buf->str); (*info->fprintf_func)(info->stream, "%s", buf->str);
g_string_free(buf, true); g_string_free(buf, true);

14
docs/_templates/footer.html vendored Normal file
View File

@ -0,0 +1,14 @@
{% extends "!footer.html" %}
{% block extrafooter %}
<!-- Empty para to force a blank line after "Built with Sphinx ..." -->
<p></p>
<p>This documentation is for QEMU version {{ version }}.</p>
{% trans path=pathto('about/license') %}
<p><a href="{{ path }}">QEMU and this manual are released under the
GNU General Public License, version 2.</a></p>
{% endtrans %}
{{ super() }}
{% endblock %}

27
docs/about/index.rst Normal file
View File

@ -0,0 +1,27 @@
About QEMU
==========
QEMU is a generic and open source machine emulator and virtualizer.
QEMU can be used in several different ways. The most common is for
"system emulation", where it provides a virtual model of an
entire machine (CPU, memory and emulated devices) to run a guest OS.
In this mode the CPU may be fully emulated, or it may work with
a hypervisor such as KVM, Xen, Hax or Hypervisor.Framework to
allow the guest to run directly on the host CPU.
The second supported way to use QEMU is "user mode emulation",
where QEMU can launch processes compiled for one CPU on another CPU.
In this mode the CPU is always emulated.
QEMU also provides a number of standalone commandline utilities,
such as the ``qemu-img`` disk image utility that allows you to create,
convert and modify disk images.
.. toctree::
:maxdepth: 2
build-platforms
deprecated
removed-features
license

View File

@ -9,8 +9,145 @@ trouble after a recent upgrade.
System emulator command line arguments System emulator command line arguments
-------------------------------------- --------------------------------------
``-net ...,name=``\ *name* (removed in 5.1) ``-hdachs`` (removed in 2.12)
''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''
The geometry defined by ``-hdachs c,h,s,t`` should now be specified via
``-device ide-hd,drive=dr,cyls=c,heads=h,secs=s,bios-chs-trans=t``
(together with ``-drive if=none,id=dr,...``).
``-net channel`` (removed in 2.12)
''''''''''''''''''''''''''''''''''
This option has been replaced by ``-net user,guestfwd=...``.
``-net dump`` (removed in 2.12)
'''''''''''''''''''''''''''''''
``-net dump[,vlan=n][,file=filename][,len=maxlen]`` has been replaced by
``-object filter-dump,id=id,netdev=dev[,file=filename][,maxlen=maxlen]``.
Note that the new syntax works with netdev IDs instead of the old "vlan" hubs.
``-no-kvm-pit`` (removed in 2.12)
'''''''''''''''''''''''''''''''''
This was just a dummy option that has been ignored, since the in-kernel PIT
cannot be disabled separately from the irqchip anymore. A similar effect
(which also disables the KVM IOAPIC) can be obtained with
``-M kernel_irqchip=split``.
``-tdf`` (removed in 2.12)
''''''''''''''''''''''''''
There is no replacement, the ``-tdf`` option has just been ignored since the
behaviour that could be changed by this option in qemu-kvm is now the default
when using the KVM PIT. It still can be requested explicitly using
``-global kvm-pit.lost_tick_policy=delay``.
``-drive secs=s``, ``-drive heads=h`` & ``-drive cyls=c`` (removed in 3.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
The drive geometry should now be specified via
``-device ...,drive=dr,cyls=c,heads=h,secs=s`` (together with
``-drive if=none,id=dr,...``).
``-drive serial=``, ``-drive trans=`` & ``-drive addr=`` (removed in 3.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Use ``-device ...,drive=dr,serial=r,bios-chs-trans=t,addr=a`` instead
(together with ``-drive if=none,id=dr,...``).
``-net ...,vlan=x`` (removed in 3.0)
''''''''''''''''''''''''''''''''''''
The term "vlan" was very confusing for most users in this context (it's about
specifying a hub ID, not about IEEE 802.1Q or something similar), so this
has been removed. To connect one NIC frontend with a network backend, either
use ``-nic ...`` (e.g. for on-board NICs) or use ``-netdev ...,id=n`` together
with ``-device ...,netdev=n`` (for full control over pluggable NICs). To
connect multiple NICs or network backends via a hub device (which is what
vlan did), use ``-nic hubport,hubid=x,...`` or
``-netdev hubport,id=n,hubid=x,...`` (with ``-device ...,netdev=n``) instead.
``-no-kvm-irqchip`` (removed in 3.0)
''''''''''''''''''''''''''''''''''''
Use ``-machine kernel_irqchip=off`` instead.
``-no-kvm-pit-reinjection`` (removed in 3.0)
''''''''''''''''''''''''''''''''''''''''''''
Use ``-global kvm-pit.lost_tick_policy=discard`` instead.
``-balloon`` (removed in 3.1)
'''''''''''''''''''''''''''''
The ``-balloon virtio`` option has been replaced by ``-device virtio-balloon``.
The ``-balloon none`` option was a no-op and has no replacement.
``-bootp`` (removed in 3.1)
'''''''''''''''''''''''''''
The ``-bootp /some/file`` argument is replaced by either
``-netdev user,id=x,bootp=/some/file`` (for pluggable NICs, accompanied with
``-device ...,netdev=x``), or ``-nic user,bootp=/some/file`` (for on-board NICs).
The new syntax allows different settings to be provided per NIC.
``-redir`` (removed in 3.1)
'''''''''''''''''''''''''''
The ``-redir [tcp|udp]:hostport:[guestaddr]:guestport`` option is replaced
by either ``-netdev
user,id=x,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport``
(for pluggable NICs, accompanied with ``-device ...,netdev=x``) or by the option
``-nic user,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport``
(for on-board NICs). The new syntax allows different settings to be provided
per NIC.
``-smb`` (removed in 3.1)
'''''''''''''''''''''''''
The ``-smb /some/dir`` argument is replaced by either
``-netdev user,id=x,smb=/some/dir`` (for pluggable NICs, accompanied with
``-device ...,netdev=x``), or ``-nic user,smb=/some/dir`` (for on-board NICs).
The new syntax allows different settings to be provided per NIC.
``-tftp`` (removed in 3.1)
''''''''''''''''''''''''''
The ``-tftp /some/dir`` argument is replaced by either
``-netdev user,id=x,tftp=/some/dir`` (for pluggable NICs, accompanied with
``-device ...,netdev=x``), or ``-nic user,tftp=/some/dir`` (for embedded NICs).
The new syntax allows different settings to be provided per NIC.
``-localtime`` (removed in 3.1)
'''''''''''''''''''''''''''''''
Replaced by ``-rtc base=localtime``.
``-nodefconfig`` (removed in 3.1)
'''''''''''''''''''''''''''''''''
Use ``-no-user-config`` instead.
``-rtc-td-hack`` (removed in 3.1)
'''''''''''''''''''''''''''''''''
Use ``-rtc driftfix=slew`` instead.
``-startdate`` (removed in 3.1)
'''''''''''''''''''''''''''''''
Replaced by ``-rtc base=date``.
``-vnc ...,tls=...``, ``-vnc ...,x509=...`` & ``-vnc ...,x509verify=...``
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
The "tls-creds" option should be used instead to point to a "tls-creds-x509"
object created using "-object".
``-net ...,name=...`` (removed in 5.1)
''''''''''''''''''''''''''''''''''''''
The ``name`` parameter of the ``-net`` option was a synonym The ``name`` parameter of the ``-net`` option was a synonym
for the ``id`` parameter, which should now be used instead. for the ``id`` parameter, which should now be used instead.
@ -124,7 +261,7 @@ devices. Drives the board doesn't pick up can no longer be used with
''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''
This option was undocumented and not used in the field. This option was undocumented and not used in the field.
Use `-device usb-ccid`` instead. Use ``-device usb-ccid`` instead.
RISC-V firmware not booted by default (removed in 5.1) RISC-V firmware not booted by default (removed in 5.1)
'''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''''''''''''''''''''''''''''''''''''''''''''''''''''
@ -219,6 +356,17 @@ Specify the properties for the object as top-level arguments instead.
Human Monitor Protocol (HMP) commands Human Monitor Protocol (HMP) commands
------------------------------------- -------------------------------------
``usb_add`` and ``usb_remove`` (removed in 2.12)
''''''''''''''''''''''''''''''''''''''''''''''''
Replaced by ``device_add`` and ``device_del`` (use ``device_add help`` for a
list of available devices).
``host_net_add`` and ``host_net_remove`` (removed in 2.12)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Replaced by ``netdev_add`` and ``netdev_del``.
The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0) The ``hub_id`` parameter of ``hostfwd_add`` / ``hostfwd_remove`` (removed in 5.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
@ -325,6 +473,22 @@ Removed without replacement.
System emulator machines System emulator machines
------------------------ ------------------------
``s390-virtio`` (removed in 2.6)
''''''''''''''''''''''''''''''''
Use the ``s390-ccw-virtio`` machine instead.
The m68k ``dummy`` machine (removed in 2.9)
'''''''''''''''''''''''''''''''''''''''''''
Use the ``none`` machine with the ``loader`` device instead.
``xlnx-ep108`` (removed in 3.0)
'''''''''''''''''''''''''''''''
The EP108 was an early access development board that is no longer used.
Use the ``xlnx-zcu102`` machine instead.
``spike_v1.9.1`` and ``spike_v1.10`` (removed in 5.1) ``spike_v1.9.1`` and ``spike_v1.10`` (removed in 5.1)
''''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''
@ -343,8 +507,8 @@ mips ``fulong2e`` machine alias (removed in 6.0)
This machine has been renamed ``fuloong2e``. This machine has been renamed ``fuloong2e``.
``pc-1.0``, ``pc-1.1``, ``pc-1.2`` and ``pc-1.3`` (removed in 6.0) ``pc-0.10`` up to ``pc-1.3`` (removed in 4.0 up to 6.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''
These machine types were very old and likely could not be used for live These machine types were very old and likely could not be used for live
migration from old QEMU versions anymore. Use a newer machine type instead. migration from old QEMU versions anymore. Use a newer machine type instead.
@ -365,6 +529,17 @@ running the old binaries, you can use older versions of QEMU.
System emulator devices System emulator devices
----------------------- -----------------------
``spapr-pci-vfio-host-bridge`` (removed in 2.12)
'''''''''''''''''''''''''''''''''''''''''''''''''
The ``spapr-pci-vfio-host-bridge`` device type has been replaced by the
``spapr-pci-host-bridge`` device type.
``ivshmem`` (removed in 4.0)
''''''''''''''''''''''''''''
Replaced by either the ``ivshmem-plain`` or ``ivshmem-doorbell``.
``ide-drive`` (removed in 6.0) ``ide-drive`` (removed in 6.0)
'''''''''''''''''''''''''''''' ''''''''''''''''''''''''''''''

View File

@ -1,370 +0,0 @@
QEMU Barrier Client
* About
Barrier is a KVM (Keyboard-Video-Mouse) software forked from Symless's
synergy 1.9 codebase.
See https://github.com/debauchee/barrier
* QEMU usage
Generally, mouse and keyboard are grabbed through the QEMU video
interface emulation.
But when we want to use a video graphic adapter via a PCI passthrough
there is no way to provide the keyboard and mouse inputs to the VM
except by plugging a second set of mouse and keyboard to the host
or by installing a KVM software in the guest OS.
The QEMU Barrier client avoids this by implementing directly the Barrier
protocol into QEMU.
This protocol is enabled by adding an input-barrier object to QEMU.
Syntax: input-barrier,id=<object-id>,name=<guest display name>
[,server=<barrier server address>][,port=<barrier server port>]
[,x-origin=<x-origin>][,y-origin=<y-origin>]
[,width=<width>][,height=<height>]
The object can be added on the QEMU command line, for instance with:
... -object input-barrier,id=barrier0,name=VM-1 ...
where VM-1 is the name the display configured int the Barrier server
on the host providing the mouse and the keyboard events.
by default <barrier server address> is "localhost", port is 24800,
<x-origin> and <y-origin> are set to 0, <width> and <height> to
1920 and 1080.
If Barrier server is stopped QEMU needs to be reconnected manually,
by removing and re-adding the input-barrier object, for instance
with the help of the HMP monitor:
(qemu) object_del barrier0
(qemu) object_add input-barrier,id=barrier0,name=VM-1
* Message format
Message format between the server and client is in two parts:
1- the payload length is a 32bit integer in network endianness,
2- the payload
The payload starts with a 4byte string (without NUL) which is the
command. The first command between the server and the client
is the only command not encoded on 4 bytes ("Barrier").
The remaining part of the payload is decoded according to the command.
* Protocol Description (from barrier/src/lib/barrier/protocol_types.h)
- barrierCmdHello "Barrier"
Direction: server -> client
Parameters: { int16_t minor, int16_t major }
Description:
Say hello to client
minor = protocol major version number supported by server
major = protocol minor version number supported by server
- barrierCmdHelloBack "Barrier"
Direction: client ->server
Parameters: { int16_t minor, int16_t major, char *name}
Description:
Respond to hello from server
minor = protocol major version number supported by client
major = protocol minor version number supported by client
name = client name
- barrierCmdDInfo "DINF"
Direction: client ->server
Parameters: { int16_t x_origin, int16_t y_origin, int16_t width, int16_t height, int16_t x, int16_t y}
Description:
The client screen must send this message in response to the
barrierCmdQInfo message. It must also send this message when the
screen's resolution changes. In this case, the client screen should
ignore any barrierCmdDMouseMove messages until it receives a
barrierCmdCInfoAck in order to prevent attempts to move the mouse off
the new screen area.
- barrierCmdCNoop "CNOP"
Direction: client -> server
Parameters: None
Description:
No operation
- barrierCmdCClose "CBYE"
Direction: server -> client
Parameters: None
Description:
Close connection
- barrierCmdCEnter "CINN"
Direction: server -> client
Parameters: { int16_t x, int16_t y, int32_t seq, int16_t modifier }
Description:
Enter screen.
x,y = entering screen absolute coordinates
seq = sequence number, which is used to order messages between
screens. the secondary screen must return this number
with some messages
modifier = modifier key mask. this will have bits set for each
toggle modifier key that is activated on entry to the
screen. the secondary screen should adjust its toggle
modifiers to reflect that state.
- barrierCmdCLeave "COUT"
Direction: server -> client
Parameters: None
Description:
Leaving screen. the secondary screen should send clipboard data in
response to this message for those clipboards that it has grabbed
(i.e. has sent a barrierCmdCClipboard for and has not received a
barrierCmdCClipboard for with a greater sequence number) and that
were grabbed or have changed since the last leave.
- barrierCmdCClipboard "CCLP"
Direction: server -> client
Parameters: { int8_t id, int32_t seq }
Description:
Grab clipboard. Sent by screen when some other app on that screen
grabs a clipboard.
id = the clipboard identifier
seq = sequence number. Client must use the sequence number passed in
the most recent barrierCmdCEnter. the server always sends 0.
- barrierCmdCScreenSaver "CSEC"
Direction: server -> client
Parameters: { int8_t started }
Description:
Screensaver change.
started = Screensaver on primary has started (1) or closed (0)
- barrierCmdCResetOptions "CROP"
Direction: server -> client
Parameters: None
Description:
Reset options. Client should reset all of its options to their
defaults.
- barrierCmdCInfoAck "CIAK"
Direction: server -> client
Parameters: None
Description:
Resolution change acknowledgment. Sent by server in response to a
client screen's barrierCmdDInfo. This is sent for every
barrierCmdDInfo, whether or not the server had sent a barrierCmdQInfo.
- barrierCmdCKeepAlive "CALV"
Direction: server -> client
Parameters: None
Description:
Keep connection alive. Sent by the server periodically to verify
that connections are still up and running. clients must reply in
kind on receipt. if the server gets an error sending the message or
does not receive a reply within a reasonable time then the server
disconnects the client. if the client doesn't receive these (or any
message) periodically then it should disconnect from the server. the
appropriate interval is defined by an option.
- barrierCmdDKeyDown "DKDN"
Direction: server -> client
Parameters: { int16_t keyid, int16_t modifier [,int16_t button] }
Description:
Key pressed.
keyid = X11 key id
modified = modified mask
button = X11 Xkb keycode (optional)
- barrierCmdDKeyRepeat "DKRP"
Direction: server -> client
Parameters: { int16_t keyid, int16_t modifier, int16_t repeat [,int16_t button] }
Description:
Key auto-repeat.
keyid = X11 key id
modified = modified mask
repeat = number of repeats
button = X11 Xkb keycode (optional)
- barrierCmdDKeyUp "DKUP"
Direction: server -> client
Parameters: { int16_t keyid, int16_t modifier [,int16_t button] }
Description:
Key released.
keyid = X11 key id
modified = modified mask
button = X11 Xkb keycode (optional)
- barrierCmdDMouseDown "DMDN"
Direction: server -> client
Parameters: { int8_t button }
Description:
Mouse button pressed.
button = button id
- barrierCmdDMouseUp "DMUP"
Direction: server -> client
Parameters: { int8_t button }
Description:
Mouse button release.
button = button id
- barrierCmdDMouseMove "DMMV"
Direction: server -> client
Parameters: { int16_t x, int16_t y }
Description:
Absolute mouse moved.
x,y = absolute screen coordinates
- barrierCmdDMouseRelMove "DMRM"
Direction: server -> client
Parameters: { int16_t x, int16_t y }
Description:
Relative mouse moved.
x,y = r relative screen coordinates
- barrierCmdDMouseWheel "DMWM"
Direction: server -> client
Parameters: { int16_t x , int16_t y } or { int16_t y }
Description:
Mouse scroll. The delta should be +120 for one tick forward (away
from the user) or right and -120 for one tick backward (toward the
user) or left.
x = x delta
y = y delta
- barrierCmdDClipboard "DCLP"
Direction: server -> client
Parameters: { int8_t id, int32_t seq, int8_t mark, char *data }
Description:
Clipboard data.
id = clipboard id
seq = sequence number. The sequence number is 0 when sent by the
server. Client screens should use the/ sequence number from
the most recent barrierCmdCEnter.
- barrierCmdDSetOptions "DSOP"
Direction: server -> client
Parameters: { int32 t nb, { int32_t id, int32_t val }[] }
Description:
Set options. Client should set the given option/value pairs.
nb = numbers of { id, val } entries
id = option id
val = option new value
- barrierCmdDFileTransfer "DFTR"
Direction: server -> client
Parameters: { int8_t mark, char *content }
Description:
Transfer file data.
mark = 0 means the content followed is the file size
1 means the content followed is the chunk data
2 means the file transfer is finished
- barrierCmdDDragInfo "DDRG" int16_t char *
Direction: server -> client
Parameters: { int16_t nb, char *content }
Description:
Drag information.
nb = number of dragging objects
content = object's directory
- barrierCmdQInfo "QINF"
Direction: server -> client
Parameters: None
Description:
Query screen info
Client should reply with a barrierCmdDInfo
- barrierCmdEIncompatible "EICV"
Direction: server -> client
Parameters: { int16_t nb, major *minor }
Description:
Incompatible version.
major = major version
minor = minor version
- barrierCmdEBusy "EBSY"
Direction: server -> client
Parameters: None
Description:
Name provided when connecting is already in use.
- barrierCmdEUnknown "EUNK"
Direction: server -> client
Parameters: None
Description:
Unknown client. Name provided when connecting is not in primary's
screen configuration map.
- barrierCmdEBad "EBAD"
Direction: server -> client
Parameters: None
Description:
Protocol violation. Server should disconnect after sending this
message.
* TO DO
- Enable SSL
- Manage SetOptions/ResetOptions commands

View File

@ -1,52 +0,0 @@
= Bootindex property =
Block and net devices have bootindex property. This property is used to
determine the order in which firmware will consider devices for booting
the guest OS. If the bootindex property is not set for a device, it gets
lowest boot priority. There is no particular order in which devices with
unset bootindex property will be considered for booting, but they will
still be bootable.
== Example ==
Let's assume we have a QEMU machine with two NICs (virtio, e1000) and two
disks (IDE, virtio):
qemu -drive file=disk1.img,if=none,id=disk1
-device ide-hd,drive=disk1,bootindex=4
-drive file=disk2.img,if=none,id=disk2
-device virtio-blk-pci,drive=disk2,bootindex=3
-netdev type=user,id=net0 -device virtio-net-pci,netdev=net0,bootindex=2
-netdev type=user,id=net1 -device e1000,netdev=net1,bootindex=1
Given the command above, firmware should try to boot from the e1000 NIC
first. If this fails, it should try the virtio NIC next; if this fails
too, it should try the virtio disk, and then the IDE disk.
== Limitations ==
1. Some firmware has limitations on which devices can be considered for
booting. For instance, the PC BIOS boot specification allows only one
disk to be bootable. If boot from disk fails for some reason, the BIOS
won't retry booting from other disk. It can still try to boot from
floppy or net, though.
2. Sometimes, firmware cannot map the device path QEMU wants firmware to
boot from to a boot method. It doesn't happen for devices the firmware
can natively boot from, but if firmware relies on an option ROM for
booting, and the same option ROM is used for booting from more then one
device, the firmware may not be able to ask the option ROM to boot from
a particular device reliably. For instance with the PC BIOS, if a SCSI HBA
has three bootable devices target1, target3, target5 connected to it,
the option ROM will have a boot method for each of them, but it is not
possible to map from boot method back to a specific target. This is a
shortcoming of the PC BIOS boot specification.
== Mixing bootindex and boot order parameters ==
Note that it does not make sense to use the bootindex property together
with the "-boot order=..." (or "-boot once=...") parameter. The guest
firmware implementations normally either support the one or the other,
but not both parameters at the same time. Mixing them will result in
undefined behavior, and thus the guest firmware will likely not boot
from the expected devices.

89
docs/bypass-iommu.txt Normal file
View File

@ -0,0 +1,89 @@
BYPASS IOMMU PROPERTY
=====================
Description
===========
Traditionally, there is a global switch to enable/disable vIOMMU. All
devices in the system can only support go through vIOMMU or not, which
is not flexible. We introduce this bypass iommu property to support
coexist of devices go through vIOMMU and devices not. This is useful to
passthrough devices with no-iommu mode and devices go through vIOMMU in
the same virtual machine.
PCI host bridges have a bypass_iommu property. This property is used to
determine whether the devices attached on the PCI host bridge will bypass
virtual iommu. The bypass_iommu property is valid only when there is a
virtual iommu in the system, it is implemented to allow some devices to
bypass vIOMMU. When bypass_iommu property is not set for a host bridge,
the attached devices will go through vIOMMU by default.
Usage
=====
The bypass iommu feature support PXB host bridge and default main host
bridge, we add a bypass_iommu property for PXB and default_bus_bypass_iommu
for machine. Note that default_bus_bypass_iommu is available only when
the 'q35' machine type on x86 architecture and the 'virt' machine type
on AArch64. Other machine types do not support bypass iommu for default
root bus.
1. The following is the bypass iommu options:
(1) PCI expander bridge
qemu -device pxb-pcie,bus_nr=0x10,addr=0x1,bypass_iommu=true
(2) Arm default host bridge
qemu -machine virt,iommu=smmuv3,default_bus_bypass_iommu=true
(3) X86 default root bus bypass iommu:
qemu -machine q35,default_bus_bypass_iommu=true
2. Here is the detailed qemu command line for 'virt' machine with PXB on
AArch64:
qemu-system-aarch64 \
-machine virt,kernel_irqchip=on,iommu=smmuv3,default_bus_bypass_iommu=true \
-device pxb-pcie,bus_nr=0x10,id=pci.10,bus=pcie.0,addr=0x3.0x1 \
-device pxb-pcie,bus_nr=0x20,id=pci.20,bus=pcie.0,addr=0x3.0x2,bypass_iommu=true \
And we got:
- a default host bridge which bypass SMMUv3
- a pxb host bridge which go through SMMUv3
- a pxb host bridge which bypass SMMUv3
3. Here is the detailed qemu command line for 'q35' machine with PXB on
x86 architecture:
qemu-system-x86_64 \
-machine q35,accel=kvm,default_bus_bypass_iommu=true \
-device pxb-pcie,bus_nr=0x10,id=pci.10,bus=pcie.0,addr=0x3 \
-device pxb-pcie,bus_nr=0x20,id=pci.20,bus=pcie.0,addr=0x4,bypass_iommu=true \
-device intel-iommu \
And we got:
- a default host bridge which bypass iommu
- a pxb host bridge which go through iommu
- a pxb host bridge which bypass iommu
Limitations
===========
There might be potential security risk when devices bypass iommu, because
devices might send malicious dma request to virtual machine if there is no
iommu isolation. So it would be necessary to only bypass iommu for trusted
device.
Implementation
==============
The bypass iommu feature includes:
- Address space
Add bypass iommu property check of PCI Host and do not get iommu address
space for devices bypass iommu.
- Arm SMMUv3 support
We traverse all PCI root bus and get bus number ranges, then build explicit
RID mapping for devices which do not bypass iommu.
- X86 IOMMU support
To support Intel iommu, we traverse all PCI host bridge and get information
of devices which do not bypass iommu, then fill the DMAR drhd struct with
explicit device scope info. To support AMD iommu, add check of bypass iommu
when traverse the PCI hsot bridge.
- Machine and PXB options
We add bypass iommu options in machine option for default root bus, and add
option for PXB also. Note that the default value of bypass iommu is false,
so that the devices will by default go through iommu if there exist one.

View File

@ -34,15 +34,14 @@ reader and smart card (i.e. not backed by a physical device) using this device.
2. Building 2. Building
The cryptographic functions and access to the physical card is done via NSS. The cryptographic functions and access to the physical card is done via the
libcacard library, whose development package must be installed prior to
Installing NSS: building QEMU:
In redhat/fedora: In redhat/fedora:
yum install nss-devel yum install libcacard-devel
In ubuntu/debian: In ubuntu:
apt-get install libnss3-dev apt-get install libcacard-dev
(not tested on ubuntu)
Configuring and building: Configuring and building:
./configure --enable-smartcard && make ./configure --enable-smartcard && make
@ -51,7 +50,7 @@ Configuring and building:
3. Using ccid-card-emulated with hardware 3. Using ccid-card-emulated with hardware
Assuming you have a working smartcard on the host with the current Assuming you have a working smartcard on the host with the current
user, using NSS, qemu acts as another NSS client using ccid-card-emulated: user, using libcacard, QEMU acts as another client using ccid-card-emulated:
qemu -usb -device usb-ccid -device ccid-card-emulated qemu -usb -device usb-ccid -device ccid-card-emulated

View File

@ -87,7 +87,7 @@ master_doc = 'index'
# General information about the project. # General information about the project.
project = u'QEMU' project = u'QEMU'
copyright = u'2020, The QEMU Project Developers' copyright = u'2021, The QEMU Project Developers'
author = u'The QEMU Project Developers' author = u'The QEMU Project Developers'
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for

View File

@ -53,14 +53,14 @@ following tasks:
- Add a Meson build option to meson_options.txt. - Add a Meson build option to meson_options.txt.
- Add support to the command line arg parser to handle any new - Add support to the command line arg parser to handle any new
`--enable-XXX`/`--disable-XXX` flags required by the feature. ``--enable-XXX``/``--disable-XXX`` flags required by the feature.
- Add information to the help output message to report on the new - Add information to the help output message to report on the new
feature flag. feature flag.
- Add code to perform the actual feature check. - Add code to perform the actual feature check.
- Add code to include the feature status in `config-host.h` - Add code to include the feature status in ``config-host.h``
- Add code to print out the feature status in the configure summary - Add code to print out the feature status in the configure summary
upon completion. upon completion.
@ -116,51 +116,51 @@ Helper functions
The configure script provides a variety of helper functions to assist The configure script provides a variety of helper functions to assist
developers in checking for system features: developers in checking for system features:
`do_cc $ARGS...` ``do_cc $ARGS...``
Attempt to run the system C compiler passing it $ARGS... Attempt to run the system C compiler passing it $ARGS...
`do_cxx $ARGS...` ``do_cxx $ARGS...``
Attempt to run the system C++ compiler passing it $ARGS... Attempt to run the system C++ compiler passing it $ARGS...
`compile_object $CFLAGS` ``compile_object $CFLAGS``
Attempt to compile a test program with the system C compiler using Attempt to compile a test program with the system C compiler using
$CFLAGS. The test program must have been previously written to a file $CFLAGS. The test program must have been previously written to a file
called $TMPC. The replacement in Meson is the compiler object `cc`, called $TMPC. The replacement in Meson is the compiler object ``cc``,
which has methods such as `cc.compiles()`, which has methods such as ``cc.compiles()``,
`cc.check_header()`, `cc.has_function()`. ``cc.check_header()``, ``cc.has_function()``.
`compile_prog $CFLAGS $LDFLAGS` ``compile_prog $CFLAGS $LDFLAGS``
Attempt to compile a test program with the system C compiler using Attempt to compile a test program with the system C compiler using
$CFLAGS and link it with the system linker using $LDFLAGS. The test $CFLAGS and link it with the system linker using $LDFLAGS. The test
program must have been previously written to a file called $TMPC. program must have been previously written to a file called $TMPC.
The replacement in Meson is `cc.find_library()` and `cc.links()`. The replacement in Meson is ``cc.find_library()`` and ``cc.links()``.
`has $COMMAND` ``has $COMMAND``
Determine if $COMMAND exists in the current environment, either as a Determine if $COMMAND exists in the current environment, either as a
shell builtin, or executable binary, returning 0 on success. The shell builtin, or executable binary, returning 0 on success. The
replacement in Meson is `find_program()`. replacement in Meson is ``find_program()``.
`check_define $NAME` ``check_define $NAME``
Determine if the macro $NAME is defined by the system C compiler Determine if the macro $NAME is defined by the system C compiler
`check_include $NAME` ``check_include $NAME``
Determine if the include $NAME file is available to the system C Determine if the include $NAME file is available to the system C
compiler. The replacement in Meson is `cc.has_header()`. compiler. The replacement in Meson is ``cc.has_header()``.
`write_c_skeleton` ``write_c_skeleton``
Write a minimal C program main() function to the temporary file Write a minimal C program main() function to the temporary file
indicated by $TMPC indicated by $TMPC
`feature_not_found $NAME $REMEDY` ``feature_not_found $NAME $REMEDY``
Print a message to stderr that the feature $NAME was not available Print a message to stderr that the feature $NAME was not available
on the system, suggesting the user try $REMEDY to address the on the system, suggesting the user try $REMEDY to address the
problem. problem.
`error_exit $MESSAGE $MORE...` ``error_exit $MESSAGE $MORE...``
Print $MESSAGE to stderr, followed by $MORE... and then exit from the Print $MESSAGE to stderr, followed by $MORE... and then exit from the
configure script with non-zero status configure script with non-zero status
`query_pkg_config $ARGS...` ``query_pkg_config $ARGS...``
Run pkg-config passing it $ARGS. If QEMU is doing a static build, Run pkg-config passing it $ARGS. If QEMU is doing a static build,
then --static will be automatically added to $ARGS then --static will be automatically added to $ARGS
@ -187,7 +187,7 @@ process for:
4) other data files, such as icons or desktop files 4) other data files, such as icons or desktop files
All executables are built by default, except for some `contrib/` All executables are built by default, except for some ``contrib/``
binaries that are known to fail to build on some platforms (for example binaries that are known to fail to build on some platforms (for example
32-bit or big-endian platforms). Tests are also built by default, 32-bit or big-endian platforms). Tests are also built by default,
though that might change in the future. though that might change in the future.
@ -195,14 +195,14 @@ though that might change in the future.
The source code is highly modularized, split across many files to The source code is highly modularized, split across many files to
facilitate building of all of these components with as little duplicated facilitate building of all of these components with as little duplicated
compilation as possible. Using the Meson "sourceset" functionality, compilation as possible. Using the Meson "sourceset" functionality,
`meson.build` files group the source files in rules that are ``meson.build`` files group the source files in rules that are
enabled according to the available system libraries and to various enabled according to the available system libraries and to various
configuration symbols. Sourcesets belong to one of four groups: configuration symbols. Sourcesets belong to one of four groups:
Subsystem sourcesets: Subsystem sourcesets:
Various subsystems that are common to both tools and emulators have Various subsystems that are common to both tools and emulators have
their own sourceset, for example `block_ss` for the block device subsystem, their own sourceset, for example ``block_ss`` for the block device subsystem,
`chardev_ss` for the character device subsystem, etc. These sourcesets ``chardev_ss`` for the character device subsystem, etc. These sourcesets
are then turned into static libraries as follows:: are then turned into static libraries as follows::
libchardev = static_library('chardev', chardev_ss.sources(), libchardev = static_library('chardev', chardev_ss.sources(),
@ -211,8 +211,8 @@ Subsystem sourcesets:
chardev = declare_dependency(link_whole: libchardev) chardev = declare_dependency(link_whole: libchardev)
As of Meson 0.55.1, the special `.fa` suffix should be used for everything As of Meson 0.55.1, the special ``.fa`` suffix should be used for everything
that is used with `link_whole`, to ensure that the link flags are placed that is used with ``link_whole``, to ensure that the link flags are placed
correctly in the command line. correctly in the command line.
Target-independent emulator sourcesets: Target-independent emulator sourcesets:
@ -221,38 +221,38 @@ Target-independent emulator sourcesets:
This includes error handling infrastructure, standard data structures, This includes error handling infrastructure, standard data structures,
platform portability wrapper functions, etc. platform portability wrapper functions, etc.
Target-independent code lives in the `common_ss`, `softmmu_ss` and Target-independent code lives in the ``common_ss``, ``softmmu_ss`` and
`user_ss` sourcesets. `common_ss` is linked into all emulators, ``user_ss`` sourcesets. ``common_ss`` is linked into all emulators,
`softmmu_ss` only in system emulators, `user_ss` only in user-mode ``softmmu_ss`` only in system emulators, ``user_ss`` only in user-mode
emulators. emulators.
Target-independent sourcesets must exercise particular care when using Target-independent sourcesets must exercise particular care when using
`if_false` rules. The `if_false` rule will be used correctly when linking ``if_false`` rules. The ``if_false`` rule will be used correctly when linking
emulator binaries; however, when *compiling* target-independent files emulator binaries; however, when *compiling* target-independent files
into .o files, Meson may need to pick *both* the `if_true` and into .o files, Meson may need to pick *both* the ``if_true`` and
`if_false` sides to cater for targets that want either side. To ``if_false`` sides to cater for targets that want either side. To
achieve that, you can add a special rule using the ``CONFIG_ALL`` achieve that, you can add a special rule using the ``CONFIG_ALL``
symbol:: symbol::
# Some targets have CONFIG_ACPI, some don't, so this is not enough # Some targets have CONFIG_ACPI, some don't, so this is not enough
softmmu_ss.add(when: 'CONFIG_ACPI`, if_true: files('acpi.c'), softmmu_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi.c'),
if_false: files('acpi-stub.c')) if_false: files('acpi-stub.c'))
# This is required as well: # This is required as well:
softmmu_ss.add(when: 'CONFIG_ALL`, if_true: files('acpi-stub.c')) softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('acpi-stub.c'))
Target-dependent emulator sourcesets: Target-dependent emulator sourcesets:
In the target-dependent set lives CPU emulation, some device emulation and In the target-dependent set lives CPU emulation, some device emulation and
much glue code. This sometimes also has to be compiled multiple times, much glue code. This sometimes also has to be compiled multiple times,
once for each target being built. Target-dependent files are included once for each target being built. Target-dependent files are included
in the `specific_ss` sourceset. in the ``specific_ss`` sourceset.
Each emulator also includes sources for files in the `hw/` and `target/` Each emulator also includes sources for files in the ``hw/`` and ``target/``
subdirectories. The subdirectory used for each emulator comes subdirectories. The subdirectory used for each emulator comes
from the target's definition of ``TARGET_BASE_ARCH`` or (if missing) from the target's definition of ``TARGET_BASE_ARCH`` or (if missing)
``TARGET_ARCH``, as found in `default-configs/targets/*.mak`. ``TARGET_ARCH``, as found in ``default-configs/targets/*.mak``.
Each subdirectory in `hw/` adds one sourceset to the `hw_arch` dictionary, Each subdirectory in ``hw/`` adds one sourceset to the ``hw_arch`` dictionary,
for example:: for example::
arm_ss = ss.source_set() arm_ss = ss.source_set()
@ -262,8 +262,8 @@ Target-dependent emulator sourcesets:
The sourceset is only used for system emulators. The sourceset is only used for system emulators.
Each subdirectory in `target/` instead should add one sourceset to each Each subdirectory in ``target/`` instead should add one sourceset to each
of the `target_arch` and `target_softmmu_arch`, which are used respectively of the ``target_arch`` and ``target_softmmu_arch``, which are used respectively
for all emulators and for system emulators only. For example:: for all emulators and for system emulators only. For example::
arm_ss = ss.source_set() arm_ss = ss.source_set()
@ -273,11 +273,11 @@ Target-dependent emulator sourcesets:
target_softmmu_arch += {'arm': arm_softmmu_ss} target_softmmu_arch += {'arm': arm_softmmu_ss}
Module sourcesets: Module sourcesets:
There are two dictionaries for modules: `modules` is used for There are two dictionaries for modules: ``modules`` is used for
target-independent modules and `target_modules` is used for target-independent modules and ``target_modules`` is used for
target-dependent modules. When modules are disabled the `module` target-dependent modules. When modules are disabled the ``module``
source sets are added to `softmmu_ss` and the `target_modules` source sets are added to ``softmmu_ss`` and the ``target_modules``
source sets are added to `specific_ss`. source sets are added to ``specific_ss``.
Both dictionaries are nested. One dictionary is created per Both dictionaries are nested. One dictionary is created per
subdirectory, and these per-subdirectory dictionaries are added to subdirectory, and these per-subdirectory dictionaries are added to
@ -290,15 +290,15 @@ Module sourcesets:
modules += { 'hw-display': hw_display_modules } modules += { 'hw-display': hw_display_modules }
Utility sourcesets: Utility sourcesets:
All binaries link with a static library `libqemuutil.a`. This library All binaries link with a static library ``libqemuutil.a``. This library
is built from several sourcesets; most of them however host generated is built from several sourcesets; most of them however host generated
code, and the only two of general interest are `util_ss` and `stub_ss`. code, and the only two of general interest are ``util_ss`` and ``stub_ss``.
The separation between these two is purely for documentation purposes. The separation between these two is purely for documentation purposes.
`util_ss` contains generic utility files. Even though this code is only ``util_ss`` contains generic utility files. Even though this code is only
linked in some binaries, sometimes it requires hooks only in some of linked in some binaries, sometimes it requires hooks only in some of
these and depend on other functions that are not fully implemented by these and depend on other functions that are not fully implemented by
all QEMU binaries. `stub_ss` links dummy stubs that will only be linked all QEMU binaries. ``stub_ss`` links dummy stubs that will only be linked
into the binary if the real implementation is not present. In a way, into the binary if the real implementation is not present. In a way,
the stubs can be thought of as a portable implementation of the weak the stubs can be thought of as a portable implementation of the weak
symbols concept. symbols concept.
@ -307,8 +307,8 @@ Utility sourcesets:
The following files concur in the definition of which files are linked The following files concur in the definition of which files are linked
into each emulator: into each emulator:
`default-configs/devices/*.mak` ``default-configs/devices/*.mak``
The files under `default-configs/devices/` control the boards and devices The files under ``default-configs/devices/`` control the boards and devices
that are built into each QEMU system emulation targets. They merely contain that are built into each QEMU system emulation targets. They merely contain
a list of config variable definitions such as:: a list of config variable definitions such as::
@ -316,18 +316,18 @@ into each emulator:
CONFIG_XLNX_ZYNQMP_ARM=y CONFIG_XLNX_ZYNQMP_ARM=y
CONFIG_XLNX_VERSAL=y CONFIG_XLNX_VERSAL=y
`*/Kconfig` ``*/Kconfig``
These files are processed together with `default-configs/devices/*.mak` and These files are processed together with ``default-configs/devices/*.mak`` and
describe the dependencies between various features, subsystems and describe the dependencies between various features, subsystems and
device models. They are described in :ref:`kconfig` device models. They are described in :ref:`kconfig`
`default-configs/targets/*.mak` ``default-configs/targets/*.mak``
These files mostly define symbols that appear in the `*-config-target.h` These files mostly define symbols that appear in the ``*-config-target.h``
file for each emulator [#cfgtarget]_. However, the ``TARGET_ARCH`` file for each emulator [#cfgtarget]_. However, the ``TARGET_ARCH``
and ``TARGET_BASE_ARCH`` will also be used to select the `hw/` and and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and
`target/` subdirectories that are compiled into each target. ``target/`` subdirectories that are compiled into each target.
.. [#cfgtarget] This header is included by `qemu/osdep.h` when .. [#cfgtarget] This header is included by ``qemu/osdep.h`` when
compiling files from the target-specific sourcesets. compiling files from the target-specific sourcesets.
These files rarely need changing unless you are adding a completely These files rarely need changing unless you are adding a completely
@ -339,19 +339,19 @@ Support scripts
--------------- ---------------
Meson has a special convention for invoking Python scripts: if their Meson has a special convention for invoking Python scripts: if their
first line is `#! /usr/bin/env python3` and the file is *not* executable, first line is ``#! /usr/bin/env python3`` and the file is *not* executable,
find_program() arranges to invoke the script under the same Python find_program() arranges to invoke the script under the same Python
interpreter that was used to invoke Meson. This is the most common interpreter that was used to invoke Meson. This is the most common
and preferred way to invoke support scripts from Meson build files, and preferred way to invoke support scripts from Meson build files,
because it automatically uses the value of configure's --python= option. because it automatically uses the value of configure's --python= option.
In case the script is not written in Python, use a `#! /usr/bin/env ...` In case the script is not written in Python, use a ``#! /usr/bin/env ...``
line and make the script executable. line and make the script executable.
Scripts written in Python, where it is desirable to make the script Scripts written in Python, where it is desirable to make the script
executable (for example for test scripts that developers may want to executable (for example for test scripts that developers may want to
invoke from the command line, such as tests/qapi-schema/test-qapi.py), invoke from the command line, such as tests/qapi-schema/test-qapi.py),
should be invoked through the `python` variable in meson.build. For should be invoked through the ``python`` variable in meson.build. For
example:: example::
test('QAPI schema regression tests', python, test('QAPI schema regression tests', python,
@ -375,10 +375,10 @@ rules and wraps them so that e.g. submodules are built before QEMU.
The resulting build system is largely non-recursive in nature, in The resulting build system is largely non-recursive in nature, in
contrast to common practices seen with automake. contrast to common practices seen with automake.
Tests are also ran by the Makefile with the traditional `make check` Tests are also ran by the Makefile with the traditional ``make check``
phony target, while benchmarks are run with `make bench`. Meson test phony target, while benchmarks are run with ``make bench``. Meson test
suites such as `unit` can be ran with `make check-unit` too. It is also suites such as ``unit`` can be ran with ``make check-unit`` too. It is also
possible to run tests defined in meson.build with `meson test`. possible to run tests defined in meson.build with ``meson test``.
Important files for the build system Important files for the build system
==================================== ====================================
@ -390,28 +390,28 @@ The following key files are statically defined in the source tree, with
the rules needed to build QEMU. Their behaviour is influenced by a the rules needed to build QEMU. Their behaviour is influenced by a
number of dynamically created files listed later. number of dynamically created files listed later.
`Makefile` ``Makefile``
The main entry point used when invoking make to build all the components The main entry point used when invoking make to build all the components
of QEMU. The default 'all' target will naturally result in the build of of QEMU. The default 'all' target will naturally result in the build of
every component. Makefile takes care of recursively building submodules every component. Makefile takes care of recursively building submodules
directly via a non-recursive set of rules. directly via a non-recursive set of rules.
`*/meson.build` ``*/meson.build``
The meson.build file in the root directory is the main entry point for the The meson.build file in the root directory is the main entry point for the
Meson build system, and it coordinates the configuration and build of all Meson build system, and it coordinates the configuration and build of all
executables. Build rules for various subdirectories are included in executables. Build rules for various subdirectories are included in
other meson.build files spread throughout the QEMU source tree. other meson.build files spread throughout the QEMU source tree.
`tests/Makefile.include` ``tests/Makefile.include``
Rules for external test harnesses. These include the TCG tests, Rules for external test harnesses. These include the TCG tests,
`qemu-iotests` and the Avocado-based acceptance tests. ``qemu-iotests`` and the Avocado-based acceptance tests.
`tests/docker/Makefile.include` ``tests/docker/Makefile.include``
Rules for Docker tests. Like tests/Makefile, this file is included Rules for Docker tests. Like tests/Makefile, this file is included
directly by the top level Makefile, anything defined in this file will directly by the top level Makefile, anything defined in this file will
influence the entire build system. influence the entire build system.
`tests/vm/Makefile.include` ``tests/vm/Makefile.include``
Rules for VM-based tests. Like tests/Makefile, this file is included Rules for VM-based tests. Like tests/Makefile, this file is included
directly by the top level Makefile, anything defined in this file will directly by the top level Makefile, anything defined in this file will
influence the entire build system. influence the entire build system.
@ -427,11 +427,11 @@ Makefile.
Built by configure: Built by configure:
`config-host.mak` ``config-host.mak``
When configure has determined the characteristics of the build host it When configure has determined the characteristics of the build host it
will write a long list of variables to config-host.mak file. This will write a long list of variables to config-host.mak file. This
provides the various install directories, compiler / linker flags and a provides the various install directories, compiler / linker flags and a
variety of `CONFIG_*` variables related to optionally enabled features. variety of ``CONFIG_*`` variables related to optionally enabled features.
This is imported by the top level Makefile and meson.build in order to This is imported by the top level Makefile and meson.build in order to
tailor the build output. tailor the build output.
@ -446,29 +446,29 @@ Built by configure:
Built by Meson: Built by Meson:
`${TARGET-NAME}-config-devices.mak` ``${TARGET-NAME}-config-devices.mak``
TARGET-NAME is again the name of a system or userspace emulator. The TARGET-NAME is again the name of a system or userspace emulator. The
config-devices.mak file is automatically generated by make using the config-devices.mak file is automatically generated by make using the
scripts/make_device_config.sh program, feeding it the scripts/make_device_config.sh program, feeding it the
default-configs/$TARGET-NAME file as input. default-configs/$TARGET-NAME file as input.
`config-host.h`, `$TARGET-NAME/config-target.h`, `$TARGET-NAME/config-devices.h` ``config-host.h``, ``$TARGET-NAME/config-target.h``, ``$TARGET-NAME/config-devices.h``
These files are used by source code to determine what features These files are used by source code to determine what features
are enabled. They are generated from the contents of the corresponding are enabled. They are generated from the contents of the corresponding
`*.h` files using the scripts/create_config program. This extracts ``*.h`` files using the scripts/create_config program. This extracts
relevant variables and formats them as C preprocessor macros. relevant variables and formats them as C preprocessor macros.
`build.ninja` ``build.ninja``
The build rules. The build rules.
Built by Makefile: Built by Makefile:
`Makefile.ninja` ``Makefile.ninja``
A Makefile include that bridges to ninja for the actual build. The A Makefile include that bridges to ninja for the actual build. The
Makefile is mostly a list of targets that Meson included in build.ninja. Makefile is mostly a list of targets that Meson included in build.ninja.
`Makefile.mtest` ``Makefile.mtest``
The Makefile definitions that let "make check" run tests defined in The Makefile definitions that let "make check" run tests defined in
meson.build. The rules are produced from Meson's JSON description of meson.build. The rules are produced from Meson's JSON description of
tests (obtained with "meson introspect --tests") through the script tests (obtained with "meson introspect --tests") through the script
@ -478,9 +478,9 @@ Built by Makefile:
Useful make targets Useful make targets
------------------- -------------------
`help` ``help``
Print a help message for the most common build targets. Print a help message for the most common build targets.
`print-VAR` ``print-VAR``
Print the value of the variable VAR. Useful for debugging the build Print the value of the variable VAR. Useful for debugging the build
system. system.

167
docs/devel/ci.rst Normal file
View File

@ -0,0 +1,167 @@
==
CI
==
QEMU has configurations enabled for a number of different CI services.
The most up to date information about them and their status can be
found at::
https://wiki.qemu.org/Testing/CI
Custom CI/CD variables
======================
QEMU CI pipelines can be tuned by setting some CI environment variables.
Set variable globally in the user's CI namespace
------------------------------------------------
Variables can be set globally in the user's CI namespace setting.
For further information about how to set these variables, please refer to::
https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project
Set variable manually when pushing a branch or tag to the user's repository
---------------------------------------------------------------------------
Variables can be set manually when pushing a branch or tag, using
git-push command line arguments.
Example setting the QEMU_CI_EXAMPLE_VAR variable:
.. code::
git push -o ci.variable="QEMU_CI_EXAMPLE_VAR=value" myrepo mybranch
For further information about how to set these variables, please refer to::
https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd
Here is a list of the most used variables:
QEMU_CI_AVOCADO_TESTING
~~~~~~~~~~~~~~~~~~~~~~~
By default, tests using the Avocado framework are not run automatically in
the pipelines (because multiple artifacts have to be downloaded, and if
these artifacts are not already cached, downloading them make the jobs
reach the timeout limit). Set this variable to have the tests using the
Avocado framework run automatically.
Jobs on Custom Runners
======================
Besides the jobs run under the various CI systems listed before, there
are a number additional jobs that will run before an actual merge.
These use the same GitLab CI's service/framework already used for all
other GitLab based CI jobs, but rely on additional systems, not the
ones provided by GitLab as "shared runners".
The architecture of GitLab's CI service allows different machines to
be set up with GitLab's "agent", called gitlab-runner, which will take
care of running jobs created by events such as a push to a branch.
Here, the combination of a machine, properly configured with GitLab's
gitlab-runner, is called a "custom runner".
The GitLab CI jobs definition for the custom runners are located under::
.gitlab-ci.d/custom-runners.yml
Custom runners entail custom machines. To see a list of the machines
currently deployed in the QEMU GitLab CI and their maintainers, please
refer to the QEMU `wiki <https://wiki.qemu.org/AdminContacts>`__.
Machine Setup Howto
-------------------
For all Linux based systems, the setup can be mostly automated by the
execution of two Ansible playbooks. Create an ``inventory`` file
under ``scripts/ci/setup``, such as this::
fully.qualified.domain
other.machine.hostname
You may need to set some variables in the inventory file itself. One
very common need is to tell Ansible to use a Python 3 interpreter on
those hosts. This would look like::
fully.qualified.domain ansible_python_interpreter=/usr/bin/python3
other.machine.hostname ansible_python_interpreter=/usr/bin/python3
Build environment
~~~~~~~~~~~~~~~~~
The ``scripts/ci/setup/build-environment.yml`` Ansible playbook will
set up machines with the environment needed to perform builds and run
QEMU tests. This playbook consists on the installation of various
required packages (and a general package update while at it). It
currently covers a number of different Linux distributions, but it can
be expanded to cover other systems.
The minimum required version of Ansible successfully tested in this
playbook is 2.8.0 (a version check is embedded within the playbook
itself). To run the playbook, execute::
cd scripts/ci/setup
ansible-playbook -i inventory build-environment.yml
Please note that most of the tasks in the playbook require superuser
privileges, such as those from the ``root`` account or those obtained
by ``sudo``. If necessary, please refer to ``ansible-playbook``
options such as ``--become``, ``--become-method``, ``--become-user``
and ``--ask-become-pass``.
gitlab-runner setup and registration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The gitlab-runner agent needs to be installed on each machine that
will run jobs. The association between a machine and a GitLab project
happens with a registration token. To find the registration token for
your repository/project, navigate on GitLab's web UI to:
* Settings (the gears-like icon at the bottom of the left hand side
vertical toolbar), then
* CI/CD, then
* Runners, and click on the "Expand" button, then
* Under "Set up a specific Runner manually", look for the value under
"And this registration token:"
Copy the ``scripts/ci/setup/vars.yml.template`` file to
``scripts/ci/setup/vars.yml``. Then, set the
``gitlab_runner_registration_token`` variable to the value obtained
earlier.
To run the playbook, execute::
cd scripts/ci/setup
ansible-playbook -i inventory gitlab-runner.yml
Following the registration, it's necessary to configure the runner tags,
and optionally other configurations on the GitLab UI. Navigate to:
* Settings (the gears like icon), then
* CI/CD, then
* Runners, and click on the "Expand" button, then
* "Runners activated for this project", then
* Click on the "Edit" icon (next to the "Lock" Icon)
Tags are very important as they are used to route specific jobs to
specific types of runners, so it's a good idea to double check that
the automatically created tags are consistent with the OS and
architecture. For instance, an Ubuntu 20.04 aarch64 system should
have tags set as::
ubuntu_20.04,aarch64
Because the job definition at ``.gitlab-ci.d/custom-runners.yml``
would contain::
ubuntu-20.04-aarch64-all:
tags:
- ubuntu_20.04
- aarch64
It's also recommended to:
* increase the "Maximum job timeout" to something like ``2h``
* give it a better Description

View File

@ -72,7 +72,7 @@ eBPF RSS implementation
eBPF RSS loading functionality located in ebpf/ebpf_rss.c and ebpf/ebpf_rss.h. eBPF RSS loading functionality located in ebpf/ebpf_rss.c and ebpf/ebpf_rss.h.
The `struct EBPFRSSContext` structure that holds 4 file descriptors: The ``struct EBPFRSSContext`` structure that holds 4 file descriptors:
- ctx - pointer of the libbpf context. - ctx - pointer of the libbpf context.
- program_fd - file descriptor of the eBPF RSS program. - program_fd - file descriptor of the eBPF RSS program.
@ -80,20 +80,20 @@ The `struct EBPFRSSContext` structure that holds 4 file descriptors:
- map_toeplitz_key - file descriptor of the 'Toeplitz key' map. One element of the 40byte key prepared for the hashing algorithm. - map_toeplitz_key - file descriptor of the 'Toeplitz key' map. One element of the 40byte key prepared for the hashing algorithm.
- map_indirections_table - 128 elements of queue indexes. - map_indirections_table - 128 elements of queue indexes.
`struct EBPFRSSConfig` fields: ``struct EBPFRSSConfig`` fields:
- redirect - "boolean" value, should the hash be calculated, on false - `default_queue` would be used as the final decision. - redirect - "boolean" value, should the hash be calculated, on false - ``default_queue`` would be used as the final decision.
- populate_hash - for now, not used. eBPF RSS doesn't support hash reporting. - populate_hash - for now, not used. eBPF RSS doesn't support hash reporting.
- hash_types - binary mask of different hash types. See `VIRTIO_NET_RSS_HASH_TYPE_*` defines. If for packet hash should not be calculated - `default_queue` would be used. - hash_types - binary mask of different hash types. See ``VIRTIO_NET_RSS_HASH_TYPE_*`` defines. If for packet hash should not be calculated - ``default_queue`` would be used.
- indirections_len - length of the indirections table, maximum 128. - indirections_len - length of the indirections table, maximum 128.
- default_queue - the queue index that used for packet that shouldn't be hashed. For some packets, the hash can't be calculated(g.e ARP). - default_queue - the queue index that used for packet that shouldn't be hashed. For some packets, the hash can't be calculated(g.e ARP).
Functions: Functions:
- `ebpf_rss_init()` - sets ctx to NULL, which indicates that EBPFRSSContext is not loaded. - ``ebpf_rss_init()`` - sets ctx to NULL, which indicates that EBPFRSSContext is not loaded.
- `ebpf_rss_load()` - creates 3 maps and loads eBPF program from the rss.bpf.skeleton.h. Returns 'true' on success. After that, program_fd can be used to set steering for TAP. - ``ebpf_rss_load()`` - creates 3 maps and loads eBPF program from the rss.bpf.skeleton.h. Returns 'true' on success. After that, program_fd can be used to set steering for TAP.
- `ebpf_rss_set_all()` - sets values for eBPF maps. `indirections_table` length is in EBPFRSSConfig. `toeplitz_key` is VIRTIO_NET_RSS_MAX_KEY_SIZE aka 40 bytes array. - ``ebpf_rss_set_all()`` - sets values for eBPF maps. ``indirections_table`` length is in EBPFRSSConfig. ``toeplitz_key`` is VIRTIO_NET_RSS_MAX_KEY_SIZE aka 40 bytes array.
- `ebpf_rss_unload()` - close all file descriptors and set ctx to NULL. - ``ebpf_rss_unload()`` - close all file descriptors and set ctx to NULL.
Simplified eBPF RSS workflow: Simplified eBPF RSS workflow:
@ -122,4 +122,4 @@ Simplified eBPF RSS workflow:
NetClientState SetSteeringEBPF() NetClientState SetSteeringEBPF()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For now, `set_steering_ebpf()` method supported by Linux TAP NetClientState. The method requires an eBPF program file descriptor as an argument. For now, ``set_steering_ebpf()`` method supported by Linux TAP NetClientState. The method requires an eBPF program file descriptor as an argument.

View File

@ -1,15 +1,10 @@
.. This is the top level page for the 'devel' manual.
Developer Information Developer Information
===================== =====================
This manual documents various parts of the internals of QEMU. This section of the manual documents various parts of the internals of QEMU.
You only need to read it if you are interested in reading or You only need to read it if you are interested in reading or
modifying QEMU's source code. modifying QEMU's source code.
Contents:
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
:includehidden: :includehidden:
@ -27,6 +22,7 @@ Contents:
migration migration
atomics atomics
stable-process stable-process
ci
qtest qtest
decodetree decodetree
secure-coding-practices secure-coding-practices
@ -46,3 +42,5 @@ Contents:
multi-process multi-process
ebpf_rss ebpf_rss
vfio-migration vfio-migration
qapi-code-gen
writing-qmp-commands

View File

@ -53,7 +53,7 @@ savevm/loadvm functionality.
Debugging Debugging
========= =========
The migration stream can be analyzed thanks to `scripts/analyze-migration.py`. The migration stream can be analyzed thanks to ``scripts/analyze-migration.py``.
Example usage: Example usage:
@ -75,8 +75,8 @@ Common infrastructure
===================== =====================
The files, sockets or fd's that carry the migration stream are abstracted by The files, sockets or fd's that carry the migration stream are abstracted by
the ``QEMUFile`` type (see `migration/qemu-file.h`). In most cases this the ``QEMUFile`` type (see ``migration/qemu-file.h``). In most cases this
is connected to a subtype of ``QIOChannel`` (see `io/`). is connected to a subtype of ``QIOChannel`` (see ``io/``).
Saving the state of one device Saving the state of one device
@ -166,14 +166,14 @@ An example (from hw/input/pckbd.c)
}; };
We are declaring the state with name "pckbd". We are declaring the state with name "pckbd".
The `version_id` is 3, and the fields are 4 uint8_t in a KBDState structure. The ``version_id`` is 3, and the fields are 4 uint8_t in a KBDState structure.
We registered this with: We registered this with:
.. code:: c .. code:: c
vmstate_register(NULL, 0, &vmstate_kbd, s); vmstate_register(NULL, 0, &vmstate_kbd, s);
For devices that are `qdev` based, we can register the device in the class For devices that are ``qdev`` based, we can register the device in the class
init function: init function:
.. code:: c .. code:: c
@ -210,9 +210,9 @@ another to load the state back.
SaveVMHandlers *ops, SaveVMHandlers *ops,
void *opaque); void *opaque);
Two functions in the ``ops`` structure are the `save_state` Two functions in the ``ops`` structure are the ``save_state``
and `load_state` functions. Notice that `load_state` receives a version_id and ``load_state`` functions. Notice that ``load_state`` receives a version_id
parameter to know what state format is receiving. `save_state` doesn't parameter to know what state format is receiving. ``save_state`` doesn't
have a version_id parameter because it always uses the latest version. have a version_id parameter because it always uses the latest version.
Note that because the VMState macros still save the data in a raw Note that because the VMState macros still save the data in a raw
@ -385,18 +385,18 @@ migration of a device, and using them breaks backward-migration
compatibility; in general most changes can be made by adding Subsections compatibility; in general most changes can be made by adding Subsections
(see above) or _TEST macros (see above) which won't break compatibility. (see above) or _TEST macros (see above) which won't break compatibility.
Each version is associated with a series of fields saved. The `save_state` always saves Each version is associated with a series of fields saved. The ``save_state`` always saves
the state as the newer version. But `load_state` sometimes is able to the state as the newer version. But ``load_state`` sometimes is able to
load state from an older version. load state from an older version.
You can see that there are several version fields: You can see that there are several version fields:
- `version_id`: the maximum version_id supported by VMState for that device. - ``version_id``: the maximum version_id supported by VMState for that device.
- `minimum_version_id`: the minimum version_id that VMState is able to understand - ``minimum_version_id``: the minimum version_id that VMState is able to understand
for that device. for that device.
- `minimum_version_id_old`: For devices that were not able to port to vmstate, we can - ``minimum_version_id_old``: For devices that were not able to port to vmstate, we can
assign a function that knows how to read this old state. This field is assign a function that knows how to read this old state. This field is
ignored if there is no `load_state_old` handler. ignored if there is no ``load_state_old`` handler.
VMState is able to read versions from minimum_version_id to VMState is able to read versions from minimum_version_id to
version_id. And the function ``load_state_old()`` (if present) is able to version_id. And the function ``load_state_old()`` (if present) is able to
@ -454,7 +454,7 @@ data and then transferred to the main structure.
If you use memory API functions that update memory layout outside If you use memory API functions that update memory layout outside
initialization (i.e., in response to a guest action), this is a strong initialization (i.e., in response to a guest action), this is a strong
indication that you need to call these functions in a `post_load` callback. indication that you need to call these functions in a ``post_load`` callback.
Examples of such memory API functions are: Examples of such memory API functions are:
- memory_region_add_subregion() - memory_region_add_subregion()
@ -823,12 +823,12 @@ Postcopy migration with shared memory needs explicit support from the other
processes that share memory and from QEMU. There are restrictions on the type of processes that share memory and from QEMU. There are restrictions on the type of
memory that userfault can support shared. memory that userfault can support shared.
The Linux kernel userfault support works on `/dev/shm` memory and on `hugetlbfs` The Linux kernel userfault support works on ``/dev/shm`` memory and on ``hugetlbfs``
(although the kernel doesn't provide an equivalent to `madvise(MADV_DONTNEED)` (although the kernel doesn't provide an equivalent to ``madvise(MADV_DONTNEED)``
for hugetlbfs which may be a problem in some configurations). for hugetlbfs which may be a problem in some configurations).
The vhost-user code in QEMU supports clients that have Postcopy support, The vhost-user code in QEMU supports clients that have Postcopy support,
and the `vhost-user-bridge` (in `tests/`) and the DPDK package have changes and the ``vhost-user-bridge`` (in ``tests/``) and the DPDK package have changes
to support postcopy. to support postcopy.
The client needs to open a userfaultfd and register the areas The client needs to open a userfaultfd and register the areas

File diff suppressed because it is too large Load Diff

View File

@ -66,11 +66,11 @@ Notes for the nodes:
Edges Edges
^^^^^^ ^^^^^^
An edge relation between two nodes (drivers or machines) `X` and `Y` can be: An edge relation between two nodes (drivers or machines) ``X`` and ``Y`` can be:
- ``X CONSUMES Y``: `Y` can be plugged into `X` - ``X CONSUMES Y``: ``Y`` can be plugged into ``X``
- ``X PRODUCES Y``: `X` provides the interface `Y` - ``X PRODUCES Y``: ``X`` provides the interface ``Y``
- ``X CONTAINS Y``: `Y` is part of `X` component - ``X CONTAINS Y``: ``Y`` is part of ``X`` component
Execution steps Execution steps
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^

View File

@ -34,11 +34,11 @@ version they were built against. This can be done simply by::
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
The core code will refuse to load a plugin that doesn't export a The core code will refuse to load a plugin that doesn't export a
`qemu_plugin_version` symbol or if plugin version is outside of QEMU's ``qemu_plugin_version`` symbol or if plugin version is outside of QEMU's
supported range of API versions. supported range of API versions.
Additionally the `qemu_info_t` structure which is passed to the Additionally the ``qemu_info_t`` structure which is passed to the
`qemu_plugin_install` method of a plugin will detail the minimum and ``qemu_plugin_install`` method of a plugin will detail the minimum and
current API versions supported by QEMU. The API version will be current API versions supported by QEMU. The API version will be
incremented if new APIs are added. The minimum API version will be incremented if new APIs are added. The minimum API version will be
incremented if existing APIs are changed or removed. incremented if existing APIs are changed or removed.
@ -71,7 +71,8 @@ API
Usage Usage
===== =====
The QEMU binary needs to be compiled for plugin support:: Any QEMU binary with TCG support has plugins enabled by default.
Earlier releases needed to be explicitly enabled with::
configure --enable-plugins configure --enable-plugins
@ -145,12 +146,12 @@ Example Plugins
There are a number of plugins included with QEMU and you are There are a number of plugins included with QEMU and you are
encouraged to contribute your own plugins plugins upstream. There is a encouraged to contribute your own plugins plugins upstream. There is a
`contrib/plugins` directory where they can go. ``contrib/plugins`` directory where they can go.
- tests/plugins - tests/plugins
These are some basic plugins that are used to test and exercise the These are some basic plugins that are used to test and exercise the
API during the `make check-tcg` target. API during the ``make check-tcg`` target.
- contrib/plugins/hotblocks.c - contrib/plugins/hotblocks.c
@ -162,7 +163,7 @@ with linux-user execution as system emulation tends to generate
re-translations as blocks from different programs get swapped in and re-translations as blocks from different programs get swapped in and
out of system memory. out of system memory.
If your program is single-threaded you can use the `inline` option for If your program is single-threaded you can use the ``inline`` option for
slightly faster (but not thread safe) counters. slightly faster (but not thread safe) counters.
Example:: Example::
@ -250,7 +251,7 @@ which will lead to a sorted list after the class breakdown::
... ...
To find the argument shorthand for the class you need to examine the To find the argument shorthand for the class you need to examine the
source code of the plugin at the moment, specifically the `*opt` source code of the plugin at the moment, specifically the ``*opt``
argument in the InsnClassExecCount tables. argument in the InsnClassExecCount tables.
- contrib/plugins/lockstep.c - contrib/plugins/lockstep.c
@ -319,3 +320,86 @@ the user to see what hardware is accessed how often. It has a number of options:
off:0000001c, 1, 2 off:0000001c, 1, 2
off:00000020, 1, 2 off:00000020, 1, 2
... ...
- contrib/plugins/execlog.c
The execlog tool traces executed instructions with memory access. It can be used
for debugging and security analysis purposes.
Please be aware that this will generate a lot of output.
The plugin takes no argument::
qemu-system-arm $(QEMU_ARGS) \
-plugin ./contrib/plugins/libexeclog.so -d plugin
which will output an execution trace following this structure::
# vCPU, vAddr, opcode, disassembly[, load/store, memory addr, device]...
0, 0xa12, 0xf8012400, "movs r4, #0"
0, 0xa14, 0xf87f42b4, "cmp r4, r6"
0, 0xa16, 0xd206, "bhs #0xa26"
0, 0xa18, 0xfff94803, "ldr r0, [pc, #0xc]", load, 0x00010a28, RAM
0, 0xa1a, 0xf989f000, "bl #0xd30"
0, 0xd30, 0xfff9b510, "push {r4, lr}", store, 0x20003ee0, RAM, store, 0x20003ee4, RAM
0, 0xd32, 0xf9893014, "adds r0, #0x14"
0, 0xd34, 0xf9c8f000, "bl #0x10c8"
0, 0x10c8, 0xfff96c43, "ldr r3, [r0, #0x44]", load, 0x200000e4, RAM
- contrib/plugins/cache
Cache modelling plugin that measures the performance of a given cache
configuration when a given working set is run::
qemu-x86_64 -plugin ./contrib/plugins/libcache.so \
-d plugin -D cache.log ./tests/tcg/x86_64-linux-user/float_convs
will report the following::
Data accesses: 996479, Misses: 507
Miss rate: 0.050879%
Instruction accesses: 2641737, Misses: 18617
Miss rate: 0.704726%
address, data misses, instruction
0x424f1e (_int_malloc), 109, movq %rax, 8(%rcx)
0x41f395 (_IO_default_xsputn), 49, movb %dl, (%rdi, %rax)
0x42584d (ptmalloc_init.part.0), 33, movaps %xmm0, (%rax)
0x454d48 (__tunables_init), 20, cmpb $0, (%r8)
...
address, fetch misses, instruction
0x4160a0 (__vfprintf_internal), 744, movl $1, %ebx
0x41f0a0 (_IO_setb), 744, endbr64
0x415882 (__vfprintf_internal), 744, movq %r12, %rdi
0x4268a0 (__malloc), 696, andq $0xfffffffffffffff0, %rax
...
The plugin has a number of arguments, all of them are optional:
* arg="limit=N"
Print top N icache and dcache thrashing instructions along with their
address, number of misses, and its disassembly. (default: 32)
* arg="icachesize=N"
* arg="iblksize=B"
* arg="iassoc=A"
Instruction cache configuration arguments. They specify the cache size, block
size, and associativity of the instruction cache, respectively.
(default: N = 16384, B = 64, A = 8)
* arg="dcachesize=N"
* arg="dblksize=B"
* arg="dassoc=A"
Data cache configuration arguments. They specify the cache size, block size,
and associativity of the data cache, respectively.
(default: N = 16384, B = 64, A = 8)
* arg="evict=POLICY"
Sets the eviction policy to POLICY. Available policies are: :code:`lru`,
:code:`fifo`, and :code:`rand`. The plugin will use the specified policy for
both instruction and data caches. (default: POLICY = :code:`lru`)

View File

@ -775,7 +775,7 @@ The base test class has also support for tests with more than one
QEMUMachine. The way to get machines is through the ``self.get_vm()`` QEMUMachine. The way to get machines is through the ``self.get_vm()``
method which will return a QEMUMachine instance. The ``self.get_vm()`` method which will return a QEMUMachine instance. The ``self.get_vm()``
method accepts arguments that will be passed to the QEMUMachine creation method accepts arguments that will be passed to the QEMUMachine creation
and also an optional `name` attribute so you can identify a specific and also an optional ``name`` attribute so you can identify a specific
machine and get it more than once through the tests methods. A simple machine and get it more than once through the tests methods. A simple
and hypothetical example follows: and hypothetical example follows:
@ -904,6 +904,17 @@ name. If one is not given explicitly, it will either be set to
``None``, or, if the test is tagged with one (and only one) ``None``, or, if the test is tagged with one (and only one)
``:avocado: tags=arch:VALUE`` tag, it will be set to ``VALUE``. ``:avocado: tags=arch:VALUE`` tag, it will be set to ``VALUE``.
cpu
~~~
The cpu model that will be set to all QEMUMachine instances created
by the test.
The ``cpu`` attribute will be set to the test parameter of the same
name. If one is not given explicitly, it will either be set to
``None ``, or, if the test is tagged with one (and only one)
``:avocado: tags=cpu:VALUE`` tag, it will be set to ``VALUE``.
machine machine
~~~~~~~ ~~~~~~~
@ -922,6 +933,39 @@ The preserved value of the ``qemu_bin`` parameter or the result of the
dynamic probe for a QEMU binary in the current working directory or dynamic probe for a QEMU binary in the current working directory or
source tree. source tree.
LinuxTest
~~~~~~~~~
Besides the attributes present on the ``avocado_qemu.Test`` base
class, the ``avocado_qemu.LinuxTest`` adds the following attributes:
distro
......
The name of the Linux distribution used as the guest image for the
test. The name should match the **Provider** column on the list
of images supported by the avocado.utils.vmimage library:
https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
distro_version
..............
The version of the Linux distribution as the guest image for the
test. The name should match the **Version** column on the list
of images supported by the avocado.utils.vmimage library:
https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
distro_checksum
...............
The sha256 hash of the guest image file used for the test.
If this value is not set in the code or by a test parameter (with the
same name), no validation on the integrity of the image will be
performed.
Parameter reference Parameter reference
------------------- -------------------
@ -950,6 +994,12 @@ architecture of a kernel or disk image to boot a VM with.
This parameter has a direct relation with the ``arch`` attribute. If This parameter has a direct relation with the ``arch`` attribute. If
not given, it will default to None. not given, it will default to None.
cpu
~~~
The cpu model that will be set to all QEMUMachine instances created
by the test.
machine machine
~~~~~~~ ~~~~~~~
@ -962,6 +1012,38 @@ qemu_bin
The exact QEMU binary to be used on QEMUMachine. The exact QEMU binary to be used on QEMUMachine.
LinuxTest
~~~~~~~~~
Besides the parameters present on the ``avocado_qemu.Test`` base
class, the ``avocado_qemu.LinuxTest`` adds the following parameters:
distro
......
The name of the Linux distribution used as the guest image for the
test. The name should match the **Provider** column on the list
of images supported by the avocado.utils.vmimage library:
https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
distro_version
..............
The version of the Linux distribution as the guest image for the
test. The name should match the **Version** column on the list
of images supported by the avocado.utils.vmimage library:
https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
distro_checksum
...............
The sha256 hash of the guest image file used for the test.
If this value is not set in the code or by this parameter no
validation on the integrity of the image will be performed.
Skipping tests Skipping tests
-------------- --------------
The Avocado framework provides Python decorators which allow for easily skip The Avocado framework provides Python decorators which allow for easily skip
@ -980,7 +1062,7 @@ Here is a list of the most used variables:
AVOCADO_ALLOW_LARGE_STORAGE AVOCADO_ALLOW_LARGE_STORAGE
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tests which are going to fetch or produce assets considered *large* are not Tests which are going to fetch or produce assets considered *large* are not
going to run unless that `AVOCADO_ALLOW_LARGE_STORAGE=1` is exported on going to run unless that ``AVOCADO_ALLOW_LARGE_STORAGE=1`` is exported on
the environment. the environment.
The definition of *large* is a bit arbitrary here, but it usually means an The definition of *large* is a bit arbitrary here, but it usually means an
@ -994,7 +1076,7 @@ skipped by default. The definition of *not safe* is also arbitrary but
usually it means a blob which either its source or build process aren't usually it means a blob which either its source or build process aren't
public available. public available.
You should export `AVOCADO_ALLOW_UNTRUSTED_CODE=1` on the environment in You should export ``AVOCADO_ALLOW_UNTRUSTED_CODE=1`` on the environment in
order to allow tests which make use of those kind of assets. order to allow tests which make use of those kind of assets.
AVOCADO_TIMEOUT_EXPECTED AVOCADO_TIMEOUT_EXPECTED
@ -1008,7 +1090,7 @@ property defined in the test class, for further details::
Even though the timeout can be set by the test developer, there are some tests Even though the timeout can be set by the test developer, there are some tests
that may not have a well-defined limit of time to finish under certain that may not have a well-defined limit of time to finish under certain
conditions. For example, tests that take longer to execute when QEMU is conditions. For example, tests that take longer to execute when QEMU is
compiled with debug flags. Therefore, the `AVOCADO_TIMEOUT_EXPECTED` variable compiled with debug flags. Therefore, the ``AVOCADO_TIMEOUT_EXPECTED`` variable
has been used to determine whether those tests should run or not. has been used to determine whether those tests should run or not.
GITLAB_CI GITLAB_CI

View File

@ -1,4 +1,5 @@
= How to write QMP commands using the QAPI framework = How to write QMP commands using the QAPI framework
==================================================
This document is a step-by-step guide on how to write new QMP commands using This document is a step-by-step guide on how to write new QMP commands using
the QAPI framework. It also shows how to implement new style HMP commands. the QAPI framework. It also shows how to implement new style HMP commands.
@ -10,7 +11,9 @@ For an in-depth introduction to the QAPI framework, please refer to
docs/devel/qapi-code-gen.txt. For documentation about the QMP protocol, docs/devel/qapi-code-gen.txt. For documentation about the QMP protocol,
start with docs/interop/qmp-intro.txt. start with docs/interop/qmp-intro.txt.
== Overview ==
Overview
--------
Generally speaking, the following steps should be taken in order to write a Generally speaking, the following steps should be taken in order to write a
new QMP command. new QMP command.
@ -31,18 +34,20 @@ new QMP command.
The following sections will demonstrate each of the steps above. We will start The following sections will demonstrate each of the steps above. We will start
very simple and get more complex as we progress. very simple and get more complex as we progress.
=== Testing ===
Testing
-------
For all the examples in the next sections, the test setup is the same and is For all the examples in the next sections, the test setup is the same and is
shown here. shown here.
First, QEMU should be started like this: First, QEMU should be started like this::
# qemu-system-TARGET [...] \ # qemu-system-TARGET [...] \
-chardev socket,id=qmp,port=4444,host=localhost,server=on \ -chardev socket,id=qmp,port=4444,host=localhost,server=on \
-mon chardev=qmp,mode=control,pretty=on -mon chardev=qmp,mode=control,pretty=on
Then, in a different terminal: Then, in a different terminal::
$ telnet localhost 4444 $ telnet localhost 4444
Trying 127.0.0.1... Trying 127.0.0.1...
@ -64,11 +69,11 @@ Escape character is '^]'.
} }
The above output is the QMP server saying you're connected. The server is The above output is the QMP server saying you're connected. The server is
actually in capabilities negotiation mode. To enter in command mode type: actually in capabilities negotiation mode. To enter in command mode type::
{ "execute": "qmp_capabilities" } { "execute": "qmp_capabilities" }
Then the server should respond: Then the server should respond::
{ {
"return": { "return": {
@ -79,7 +84,9 @@ Which is QMP's way of saying "the latest command executed OK and didn't return
any data". Now you're ready to enter the QMP example commands as explained in any data". Now you're ready to enter the QMP example commands as explained in
the following sections. the following sections.
== Writing a command that doesn't return data ==
Writing a command that doesn't return data
------------------------------------------
That's the most simple QMP command that can be written. Usually, this kind of That's the most simple QMP command that can be written. Usually, this kind of
command carries some meaningful action in QEMU but here it will just print command carries some meaningful action in QEMU but here it will just print
@ -90,7 +97,7 @@ return any data.
The first step is defining the command in the appropriate QAPI schema The first step is defining the command in the appropriate QAPI schema
module. We pick module qapi/misc.json, and add the following line at module. We pick module qapi/misc.json, and add the following line at
the bottom: the bottom::
{ 'command': 'hello-world' } { 'command': 'hello-world' }
@ -102,7 +109,7 @@ protocol data.
The next step is to write the "hello-world" implementation. As explained The next step is to write the "hello-world" implementation. As explained
earlier, it's preferable for commands to live in QEMU subsystems. But earlier, it's preferable for commands to live in QEMU subsystems. But
"hello-world" doesn't pertain to any, so we put its implementation in "hello-world" doesn't pertain to any, so we put its implementation in
monitor/qmp-cmds.c: monitor/qmp-cmds.c::
void qmp_hello_world(Error **errp) void qmp_hello_world(Error **errp)
{ {
@ -111,10 +118,10 @@ void qmp_hello_world(Error **errp)
There are a few things to be noticed: There are a few things to be noticed:
1. QMP command implementation functions must be prefixed with "qmp_" 1. QMP command implementation functions must be prefixed with "qmp\_"
2. qmp_hello_world() returns void, this is in accordance with the fact that the 2. qmp_hello_world() returns void, this is in accordance with the fact that the
command doesn't return any data command doesn't return any data
3. It takes an "Error **" argument. This is required. Later we will see how to 3. It takes an "Error \*\*" argument. This is required. Later we will see how to
return errors and take additional arguments. The Error argument should not return errors and take additional arguments. The Error argument should not
be touched if the command doesn't return errors be touched if the command doesn't return errors
4. We won't add the function's prototype. That's automatically done by the QAPI 4. We won't add the function's prototype. That's automatically done by the QAPI
@ -122,21 +129,23 @@ There are a few things to be noticed:
because it's the easiest way to demonstrate a QMP command because it's the easiest way to demonstrate a QMP command
You're done. Now build qemu, run it as suggested in the "Testing" section, You're done. Now build qemu, run it as suggested in the "Testing" section,
and then type the following QMP command: and then type the following QMP command::
{ "execute": "hello-world" } { "execute": "hello-world" }
Then check the terminal running qemu and look for the "Hello, world" string. If Then check the terminal running qemu and look for the "Hello, world" string. If
you don't see it then something went wrong. you don't see it then something went wrong.
=== Arguments ===
Arguments
~~~~~~~~~
Let's add an argument called "message" to our "hello-world" command. The new Let's add an argument called "message" to our "hello-world" command. The new
argument will contain the string to be printed to stdout. It's an optional argument will contain the string to be printed to stdout. It's an optional
argument, if it's not present we print our default "Hello, World" string. argument, if it's not present we print our default "Hello, World" string.
The first change we have to do is to modify the command specification in the The first change we have to do is to modify the command specification in the
schema file to the following: schema file to the following::
{ 'command': 'hello-world', 'data': { '*message': 'str' } } { 'command': 'hello-world', 'data': { '*message': 'str' } }
@ -147,7 +156,7 @@ for mandatory arguments). Finally, 'str' is the argument's type, which
stands for "string". The QAPI also supports integers, booleans, enumerations stands for "string". The QAPI also supports integers, booleans, enumerations
and user defined types. and user defined types.
Now, let's update our C implementation in monitor/qmp-cmds.c: Now, let's update our C implementation in monitor/qmp-cmds.c::
void qmp_hello_world(bool has_message, const char *message, Error **errp) void qmp_hello_world(bool has_message, const char *message, Error **errp)
{ {
@ -160,13 +169,13 @@ void qmp_hello_world(bool has_message, const char *message, Error **errp)
There are two important details to be noticed: There are two important details to be noticed:
1. All optional arguments are accompanied by a 'has_' boolean, which is set 1. All optional arguments are accompanied by a 'has\_' boolean, which is set
if the optional argument is present or false otherwise if the optional argument is present or false otherwise
2. The C implementation signature must follow the schema's argument ordering, 2. The C implementation signature must follow the schema's argument ordering,
which is defined by the "data" member which is defined by the "data" member
Time to test our new version of the "hello-world" command. Build qemu, run it as Time to test our new version of the "hello-world" command. Build qemu, run it as
described in the "Testing" section and then send two commands: described in the "Testing" section and then send two commands::
{ "execute": "hello-world" } { "execute": "hello-world" }
{ {
@ -183,13 +192,15 @@ described in the "Testing" section and then send two commands:
You should see "Hello, world" and "We love qemu" in the terminal running qemu, You should see "Hello, world" and "We love qemu" in the terminal running qemu,
if you don't see these strings, then something went wrong. if you don't see these strings, then something went wrong.
=== Errors ===
Errors
~~~~~~
QMP commands should use the error interface exported by the error.h header QMP commands should use the error interface exported by the error.h header
file. Basically, most errors are set by calling the error_setg() function. file. Basically, most errors are set by calling the error_setg() function.
Let's say we don't accept the string "message" to contain the word "love". If Let's say we don't accept the string "message" to contain the word "love". If
it does contain it, we want the "hello-world" command to return an error: it does contain it, we want the "hello-world" command to return an error::
void qmp_hello_world(bool has_message, const char *message, Error **errp) void qmp_hello_world(bool has_message, const char *message, Error **errp)
{ {
@ -209,11 +220,11 @@ to pointer, which is passed to all QMP functions. The next argument is a human
description of the error, this is a free-form printf-like string. description of the error, this is a free-form printf-like string.
Let's test the example above. Build qemu, run it as defined in the "Testing" Let's test the example above. Build qemu, run it as defined in the "Testing"
section, and then issue the following command: section, and then issue the following command::
{ "execute": "hello-world", "arguments": { "message": "all you need is love" } } { "execute": "hello-world", "arguments": { "message": "all you need is love" } }
The QMP server's response should be: The QMP server's response should be::
{ {
"error": { "error": {
@ -234,13 +245,15 @@ to this rule:
If the failure you want to report falls into one of the two cases above, If the failure you want to report falls into one of the two cases above,
use error_set() with a second argument of an ErrorClass value. use error_set() with a second argument of an ErrorClass value.
=== Command Documentation ===
Command Documentation
~~~~~~~~~~~~~~~~~~~~~
There's only one step missing to make "hello-world"'s implementation complete, There's only one step missing to make "hello-world"'s implementation complete,
and that's its documentation in the schema file. and that's its documentation in the schema file.
There are many examples of such documentation in the schema file already, but There are many examples of such documentation in the schema file already, but
here goes "hello-world"'s new entry for qapi/misc.json: here goes "hello-world"'s new entry for qapi/misc.json::
## ##
# @hello-world: # @hello-world:
@ -261,7 +274,9 @@ here goes "hello-world"'s new entry for qapi/misc.json:
Please, note that the "Returns" clause is optional if a command doesn't return Please, note that the "Returns" clause is optional if a command doesn't return
any data nor any errors. any data nor any errors.
=== Implementing the HMP command ===
Implementing the HMP command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now that the QMP command is in place, we can also make it available in the human Now that the QMP command is in place, we can also make it available in the human
monitor (HMP). monitor (HMP).
@ -270,7 +285,7 @@ With the introduction of the QAPI, HMP commands make QMP calls. Most of the
time HMP commands are simple wrappers. All HMP commands implementation exist in time HMP commands are simple wrappers. All HMP commands implementation exist in
the monitor/hmp-cmds.c file. the monitor/hmp-cmds.c file.
Here's the implementation of the "hello-world" HMP command: Here's the implementation of the "hello-world" HMP command::
void hmp_hello_world(Monitor *mon, const QDict *qdict) void hmp_hello_world(Monitor *mon, const QDict *qdict)
{ {
@ -299,7 +314,7 @@ There are three important points to be noticed:
QMP call QMP call
There's one last step to actually make the command available to monitor users, There's one last step to actually make the command available to monitor users,
we should add it to the hmp-commands.hx file: we should add it to the hmp-commands.hx file::
{ {
.name = "hello-world", .name = "hello-world",
@ -309,6 +324,8 @@ we should add it to the hmp-commands.hx file:
.cmd = hmp_hello_world, .cmd = hmp_hello_world,
}, },
::
STEXI STEXI
@item hello_world @var{message} @item hello_world @var{message}
@findex hello_world @findex hello_world
@ -322,7 +339,9 @@ HMP's "help" command.
Please, check the "-monitor" command-line option to know how to open a user Please, check the "-monitor" command-line option to know how to open a user
monitor. monitor.
== Writing a command that returns data ==
Writing a command that returns data
-----------------------------------
A QMP command is capable of returning any data the QAPI supports like integers, A QMP command is capable of returning any data the QAPI supports like integers,
strings, booleans, enumerations and user defined types. strings, booleans, enumerations and user defined types.
@ -330,7 +349,9 @@ strings, booleans, enumerations and user defined types.
In this section we will focus on user defined types. Please, check the QAPI In this section we will focus on user defined types. Please, check the QAPI
documentation for information about the other types. documentation for information about the other types.
=== User Defined Types ===
User Defined Types
~~~~~~~~~~~~~~~~~~
FIXME This example needs to be redone after commit 6d32717 FIXME This example needs to be redone after commit 6d32717
@ -344,7 +365,7 @@ returned as a string, the latter is an integer in nanoseconds (which is not
very useful in practice, as the timer has probably already fired when the very useful in practice, as the timer has probably already fired when the
information reaches the client). information reaches the client).
The best way to return that data is to create a new QAPI type, as shown below: The best way to return that data is to create a new QAPI type, as shown below::
## ##
# @QemuAlarmClock # @QemuAlarmClock
@ -364,7 +385,7 @@ The "type" keyword defines a new QAPI type. Its "data" member contains the
type's members. In this example our members are the "clock-name" and the type's members. In this example our members are the "clock-name" and the
"next-deadline" one, which is optional. "next-deadline" one, which is optional.
Now let's define the query-alarm-clock command: Now let's define the query-alarm-clock command::
## ##
# @query-alarm-clock # @query-alarm-clock
@ -383,7 +404,7 @@ Notice the "returns" keyword. As its name suggests, it's used to define the
data returned by a command. data returned by a command.
It's time to implement the qmp_query_alarm_clock() function, you can put it It's time to implement the qmp_query_alarm_clock() function, you can put it
in the qemu-timer.c file: in the qemu-timer.c file::
QemuAlarmClock *qmp_query_alarm_clock(Error **errp) QemuAlarmClock *qmp_query_alarm_clock(Error **errp)
{ {
@ -423,7 +444,7 @@ There are a number of things to be noticed:
6. You have to include "qapi/qapi-commands-misc.h" in qemu-timer.c 6. You have to include "qapi/qapi-commands-misc.h" in qemu-timer.c
Time to test the new command. Build qemu, run it as described in the "Testing" Time to test the new command. Build qemu, run it as described in the "Testing"
section and try this: section and try this::
{ "execute": "query-alarm-clock" } { "execute": "query-alarm-clock" }
{ {
@ -433,9 +454,11 @@ section and try this:
} }
} }
==== The HMP command ====
Here's the HMP counterpart of the query-alarm-clock command: The HMP command
~~~~~~~~~~~~~~~
Here's the HMP counterpart of the query-alarm-clock command::
void hmp_info_alarm_clock(Monitor *mon) void hmp_info_alarm_clock(Monitor *mon)
{ {
@ -471,7 +494,7 @@ it's good practice to always check for errors.
Another important detail is that HMP's "info" commands don't go into the Another important detail is that HMP's "info" commands don't go into the
hmp-commands.hx. Instead, they go into the info_cmds[] table, which is defined hmp-commands.hx. Instead, they go into the info_cmds[] table, which is defined
in the monitor/misc.c file. The entry for the "info alarmclock" follows: in the monitor/misc.c file. The entry for the "info alarmclock" follows::
{ {
.name = "alarmclock", .name = "alarmclock",
@ -483,13 +506,15 @@ in the monitor/misc.c file. The entry for the "info alarmclock" follows:
To test this, run qemu and type "info alarmclock" in the user monitor. To test this, run qemu and type "info alarmclock" in the user monitor.
=== Returning Lists ===
Returning Lists
~~~~~~~~~~~~~~~
For this example, we're going to return all available methods for the timer For this example, we're going to return all available methods for the timer
alarm, which is pretty much what the command-line option "-clock ?" does, alarm, which is pretty much what the command-line option "-clock ?" does,
except that we're also going to inform which method is in use. except that we're also going to inform which method is in use.
This first step is to define a new type: This first step is to define a new type::
## ##
# @TimerAlarmMethod # @TimerAlarmMethod
@ -506,7 +531,7 @@ This first step is to define a new type:
'data': { 'method-name': 'str', 'current': 'bool' } } 'data': { 'method-name': 'str', 'current': 'bool' } }
The command will be called "query-alarm-methods", here is its schema The command will be called "query-alarm-methods", here is its schema
specification: specification::
## ##
# @query-alarm-methods # @query-alarm-methods
@ -522,7 +547,7 @@ specification:
Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", this Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", this
should be read as "returns a list of TimerAlarmMethod instances". should be read as "returns a list of TimerAlarmMethod instances".
The C implementation follows: The C implementation follows::
TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp) TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
{ {
@ -557,7 +582,7 @@ first element of the alarm_timers array. Also notice that QAPI lists are handled
by hand and we return the head of the list. by hand and we return the head of the list.
Now Build qemu, run it as explained in the "Testing" section and try our new Now Build qemu, run it as explained in the "Testing" section and try our new
command: command::
{ "execute": "query-alarm-methods" } { "execute": "query-alarm-methods" }
{ {
@ -574,7 +599,7 @@ command:
} }
The HMP counterpart is a bit more complex than previous examples because it The HMP counterpart is a bit more complex than previous examples because it
has to traverse the list, it's shown below for reference: has to traverse the list, it's shown below for reference::
void hmp_info_alarm_methods(Monitor *mon) void hmp_info_alarm_methods(Monitor *mon)
{ {

Some files were not shown because too many files have changed in this diff Show More