Fix conflicts
This commit is contained in:
commit
f3b17f95ac
55
.cirrus.yml
55
.cirrus.yml
@ -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
2
.gitignore
vendored
@ -15,3 +15,5 @@ GTAGS
|
|||||||
*~
|
*~
|
||||||
*.ast_raw
|
*.ast_raw
|
||||||
*.depend_raw
|
*.depend_raw
|
||||||
|
*.swp
|
||||||
|
*.patch
|
||||||
|
@ -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
|
||||||
|
@ -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
87
.gitlab-ci.d/cirrus.yml
Normal 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
|
54
.gitlab-ci.d/cirrus/README.rst
Normal file
54
.gitlab-ci.d/cirrus/README.rst
Normal 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/
|
35
.gitlab-ci.d/cirrus/build.yml
Normal file
35
.gitlab-ci.d/cirrus/build.yml
Normal 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
|
13
.gitlab-ci.d/cirrus/freebsd-12.vars
Normal file
13
.gitlab-ci.d/cirrus/freebsd-12.vars
Normal 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'
|
13
.gitlab-ci.d/cirrus/freebsd-13.vars
Normal file
13
.gitlab-ci.d/cirrus/freebsd-13.vars
Normal 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'
|
15
.gitlab-ci.d/cirrus/macos-11.vars
Normal file
15
.gitlab-ci.d/cirrus/macos-11.vars
Normal 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'
|
@ -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.
|
||||||
#
|
#
|
||||||
|
@ -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
|
||||||
|
238
.gitlab-ci.d/custom-runners.yml
Normal file
238
.gitlab-ci.d/custom-runners.yml
Normal 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
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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'
|
||||||
|
@ -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
|
||||||
|
@ -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'
|
||||||
|
5
.mailmap
5
.mailmap
@ -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>
|
||||||
|
12
.travis.yml
12
.travis.yml
@ -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
|
||||||
|
56
MAINTAINERS
56
MAINTAINERS
@ -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
|
||||||
-------------
|
-------------
|
||||||
|
8
Makefile
8
Makefile
@ -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)))) \
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 { \
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
3
block.c
3
block.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
132
block/blkdebug.c
132
block/blkdebug.c
@ -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);
|
|
||||||
g_free(r.tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
|
/* Called with lock held. */
|
||||||
bool injected)
|
static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule,
|
||||||
|
int *action_count, int *new_state)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
22
block/nvme.c
22
block/nvme.c
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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 */
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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
|
|
||||||
|
@ -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
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
CONFIG_TRICORE_TESTBOARD=y
|
||||||
CONFIG_TRIBOARD=y
|
CONFIG_TRIBOARD=y
|
||||||
|
223
configure
vendored
223
configure
vendored
@ -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
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -16,3 +16,6 @@ cota@braap.org
|
|||||||
uni-paderborn.de
|
uni-paderborn.de
|
||||||
edu
|
edu
|
||||||
edu.cn
|
edu.cn
|
||||||
|
|
||||||
|
# Boston University
|
||||||
|
bu.edu
|
||||||
|
@ -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
|
||||||
|
13
contrib/gitdm/group-map-interns
Normal file
13
contrib/gitdm/group-map-interns
Normal 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
|
5
contrib/gitdm/group-map-netflix
Normal file
5
contrib/gitdm/group-map-netflix
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#
|
||||||
|
# Netflix contributors using their personal emails
|
||||||
|
#
|
||||||
|
|
||||||
|
imp@bsdimp.com
|
7
contrib/gitdm/group-map-robots
Normal file
7
contrib/gitdm/group-map-robots
Normal 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
|
@ -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
640
contrib/plugins/cache.c
Normal 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
153
contrib/plugins/execlog.c
Normal 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
34
cpu.c
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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
335
crypto/cipher-gnutls.c.inc
Normal 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;
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
416
crypto/desrfb.c
416
crypto/desrfb.c
@ -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
104
crypto/hash-gnutls.c
Normal 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
139
crypto/hmac-gnutls.c
Normal 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,
|
||||||
|
};
|
@ -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();
|
||||||
|
@ -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'))
|
||||||
|
if xts == 'private'
|
||||||
|
crypto_ss.add(files('xts.c'))
|
||||||
|
endif
|
||||||
elif gcrypt.found()
|
elif gcrypt.found()
|
||||||
crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
|
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
|
else
|
||||||
crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c'))
|
crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c'))
|
||||||
endif
|
endif
|
||||||
if xts == 'private'
|
|
||||||
crypto_ss.add(files('xts.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
90
crypto/pbkdf-gnutls.c
Normal 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;
|
||||||
|
}
|
@ -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
14
docs/_templates/footer.html
vendored
Normal 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
27
docs/about/index.rst
Normal 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
|
@ -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)
|
||||||
''''''''''''''''''''''''''''''
|
''''''''''''''''''''''''''''''
|
||||||
|
|
370
docs/barrier.txt
370
docs/barrier.txt
@ -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
|
|
||||||
|
|
@ -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
89
docs/bypass-iommu.txt
Normal 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.
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
167
docs/devel/ci.rst
Normal 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
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
@ -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
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
@ -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`)
|
||||||
|
@ -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
|
||||||
|
@ -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,24 +34,26 @@ 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...
|
||||||
Connected to localhost.
|
Connected to localhost.
|
||||||
Escape character is '^]'.
|
Escape character is '^]'.
|
||||||
{
|
{
|
||||||
"QMP": {
|
"QMP": {
|
||||||
"version": {
|
"version": {
|
||||||
"qemu": {
|
"qemu": {
|
||||||
@ -61,25 +66,27 @@ Escape character is '^]'.
|
|||||||
"capabilities": [
|
"capabilities": [
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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": {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Which is QMP's way of saying "the latest command executed OK and didn't return
|
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,9 +97,9 @@ 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' }
|
||||||
|
|
||||||
The "command" keyword defines a new QMP command. It's an JSON object. All
|
The "command" keyword defines a new QMP command. It's an JSON object. All
|
||||||
schema entries are JSON objects. The line above will instruct the QAPI to
|
schema entries are JSON objects. The line above will instruct the QAPI to
|
||||||
@ -102,19 +109,19 @@ 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)
|
||||||
{
|
{
|
||||||
printf("Hello, world!\n");
|
printf("Hello, world!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
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,23 +129,25 @@ 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' } }
|
||||||
|
|
||||||
Notice the new 'data' member in the schema. It's an JSON object whose each
|
Notice the new 'data' member in the schema. It's an JSON object whose each
|
||||||
element is an argument to the command in question. Also notice the asterisk,
|
element is an argument to the command in question. Also notice the asterisk,
|
||||||
@ -147,52 +156,54 @@ 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)
|
||||||
{
|
{
|
||||||
if (has_message) {
|
if (has_message) {
|
||||||
printf("%s\n", message);
|
printf("%s\n", message);
|
||||||
} else {
|
} else {
|
||||||
printf("Hello, world\n");
|
printf("Hello, world\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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" }
|
||||||
{
|
{
|
||||||
"return": {
|
"return": {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ "execute": "hello-world", "arguments": { "message": "We love qemu" } }
|
{ "execute": "hello-world", "arguments": { "message": "We love qemu" } }
|
||||||
{
|
{
|
||||||
"return": {
|
"return": {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (has_message) {
|
if (has_message) {
|
||||||
if (strstr(message, "love")) {
|
if (strstr(message, "love")) {
|
||||||
error_setg(errp, "the word 'love' is not allowed");
|
error_setg(errp, "the word 'love' is not allowed");
|
||||||
@ -202,25 +213,25 @@ void qmp_hello_world(bool has_message, const char *message, Error **errp)
|
|||||||
} else {
|
} else {
|
||||||
printf("Hello, world\n");
|
printf("Hello, world\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
The first argument to the error_setg() function is the Error pointer
|
The first argument to the error_setg() function is the Error pointer
|
||||||
to pointer, which is passed to all QMP functions. The next argument is a human
|
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": {
|
||||||
"class": "GenericError",
|
"class": "GenericError",
|
||||||
"desc": "the word 'love' is not allowed"
|
"desc": "the word 'love' is not allowed"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Note that error_setg() produces a "GenericError" class. In general,
|
Note that error_setg() produces a "GenericError" class. In general,
|
||||||
all QMP errors should have that error class. There are two exceptions
|
all QMP errors should have that error class. There are two exceptions
|
||||||
@ -234,34 +245,38 @@ 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:
|
||||||
#
|
#
|
||||||
# Print a client provided string to the standard output stream.
|
# Print a client provided string to the standard output stream.
|
||||||
#
|
#
|
||||||
# @message: string to be printed
|
# @message: string to be printed
|
||||||
#
|
#
|
||||||
# Returns: Nothing on success.
|
# Returns: Nothing on success.
|
||||||
#
|
#
|
||||||
# Notes: if @message is not provided, the "Hello, world" string will
|
# Notes: if @message is not provided, the "Hello, world" string will
|
||||||
# be printed instead
|
# be printed instead
|
||||||
#
|
#
|
||||||
# Since: <next qemu stable release, eg. 1.0>
|
# Since: <next qemu stable release, eg. 1.0>
|
||||||
##
|
##
|
||||||
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
|
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
|
||||||
|
|
||||||
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,10 +285,10 @@ 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)
|
||||||
{
|
{
|
||||||
const char *message = qdict_get_try_str(qdict, "message");
|
const char *message = qdict_get_try_str(qdict, "message");
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
@ -283,7 +298,7 @@ void hmp_hello_world(Monitor *mon, const QDict *qdict)
|
|||||||
error_free(err);
|
error_free(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Also, you have to add the function's prototype to the hmp.h file.
|
Also, you have to add the function's prototype to the hmp.h file.
|
||||||
|
|
||||||
@ -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,11 +324,13 @@ we should add it to the hmp-commands.hx file:
|
|||||||
.cmd = hmp_hello_world,
|
.cmd = hmp_hello_world,
|
||||||
},
|
},
|
||||||
|
|
||||||
STEXI
|
::
|
||||||
@item hello_world @var{message}
|
|
||||||
@findex hello_world
|
STEXI
|
||||||
Print message to the standard output
|
@item hello_world @var{message}
|
||||||
ETEXI
|
@findex hello_world
|
||||||
|
Print message to the standard output
|
||||||
|
ETEXI
|
||||||
|
|
||||||
To test this you have to open a user monitor and issue the "hello-world"
|
To test this you have to open a user monitor and issue the "hello-world"
|
||||||
command. It might be instructive to check the command's documentation with
|
command. It might be instructive to check the command's documentation with
|
||||||
@ -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,49 +365,49 @@ 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
|
||||||
#
|
#
|
||||||
# QEMU alarm clock information.
|
# QEMU alarm clock information.
|
||||||
#
|
#
|
||||||
# @clock-name: The alarm clock method's name.
|
# @clock-name: The alarm clock method's name.
|
||||||
#
|
#
|
||||||
# @next-deadline: The time (in nanoseconds) the next alarm will fire.
|
# @next-deadline: The time (in nanoseconds) the next alarm will fire.
|
||||||
#
|
#
|
||||||
# Since: 1.0
|
# Since: 1.0
|
||||||
##
|
##
|
||||||
{ 'type': 'QemuAlarmClock',
|
{ 'type': 'QemuAlarmClock',
|
||||||
'data': { 'clock-name': 'str', '*next-deadline': 'int' } }
|
'data': { 'clock-name': 'str', '*next-deadline': 'int' } }
|
||||||
|
|
||||||
The "type" keyword defines a new QAPI type. Its "data" member contains the
|
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
|
||||||
#
|
#
|
||||||
# Return information about QEMU's alarm clock.
|
# Return information about QEMU's alarm clock.
|
||||||
#
|
#
|
||||||
# Returns a @QemuAlarmClock instance describing the alarm clock method
|
# Returns a @QemuAlarmClock instance describing the alarm clock method
|
||||||
# being currently used by QEMU (this is usually set by the '-clock'
|
# being currently used by QEMU (this is usually set by the '-clock'
|
||||||
# command-line option).
|
# command-line option).
|
||||||
#
|
#
|
||||||
# Since: 1.0
|
# Since: 1.0
|
||||||
##
|
##
|
||||||
{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' }
|
{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' }
|
||||||
|
|
||||||
Notice the "returns" keyword. As its name suggests, it's used to define the
|
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)
|
||||||
{
|
{
|
||||||
QemuAlarmClock *clock;
|
QemuAlarmClock *clock;
|
||||||
int64_t deadline;
|
int64_t deadline;
|
||||||
|
|
||||||
@ -400,7 +421,7 @@ QemuAlarmClock *qmp_query_alarm_clock(Error **errp)
|
|||||||
clock->clock_name = g_strdup(alarm_timer->name);
|
clock->clock_name = g_strdup(alarm_timer->name);
|
||||||
|
|
||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
There are a number of things to be noticed:
|
There are a number of things to be noticed:
|
||||||
|
|
||||||
@ -423,22 +444,24 @@ 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" }
|
||||||
{
|
{
|
||||||
"return": {
|
"return": {
|
||||||
"next-deadline": 2368219,
|
"next-deadline": 2368219,
|
||||||
"clock-name": "dynticks"
|
"clock-name": "dynticks"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
==== The HMP command ====
|
|
||||||
|
|
||||||
Here's the HMP counterpart of the query-alarm-clock command:
|
The HMP command
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
void hmp_info_alarm_clock(Monitor *mon)
|
Here's the HMP counterpart of the query-alarm-clock command::
|
||||||
{
|
|
||||||
|
void hmp_info_alarm_clock(Monitor *mon)
|
||||||
|
{
|
||||||
QemuAlarmClock *clock;
|
QemuAlarmClock *clock;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
@ -456,7 +479,7 @@ void hmp_info_alarm_clock(Monitor *mon)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qapi_free_QemuAlarmClock(clock);
|
qapi_free_QemuAlarmClock(clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
It's important to notice that hmp_info_alarm_clock() calls
|
It's important to notice that hmp_info_alarm_clock() calls
|
||||||
qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_clock().
|
qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_clock().
|
||||||
@ -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,49 +506,51 @@ 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
|
||||||
#
|
#
|
||||||
# Timer alarm method information.
|
# Timer alarm method information.
|
||||||
#
|
#
|
||||||
# @method-name: The method's name.
|
# @method-name: The method's name.
|
||||||
#
|
#
|
||||||
# @current: true if this alarm method is currently in use, false otherwise
|
# @current: true if this alarm method is currently in use, false otherwise
|
||||||
#
|
#
|
||||||
# Since: 1.0
|
# Since: 1.0
|
||||||
##
|
##
|
||||||
{ 'type': 'TimerAlarmMethod',
|
{ 'type': 'TimerAlarmMethod',
|
||||||
'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
|
||||||
#
|
#
|
||||||
# Returns information about available alarm methods.
|
# Returns information about available alarm methods.
|
||||||
#
|
#
|
||||||
# Returns: a list of @TimerAlarmMethod for each method
|
# Returns: a list of @TimerAlarmMethod for each method
|
||||||
#
|
#
|
||||||
# Since: 1.0
|
# Since: 1.0
|
||||||
##
|
##
|
||||||
{ 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] }
|
{ 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] }
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
TimerAlarmMethodList *method_list = NULL;
|
TimerAlarmMethodList *method_list = NULL;
|
||||||
const struct qemu_alarm_timer *p;
|
const struct qemu_alarm_timer *p;
|
||||||
bool current = true;
|
bool current = true;
|
||||||
@ -539,7 +564,7 @@ TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return method_list;
|
return method_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
The most important difference from the previous examples is the
|
The most important difference from the previous examples is the
|
||||||
TimerAlarmMethodList type, which is automatically generated by the QAPI from
|
TimerAlarmMethodList type, which is automatically generated by the QAPI from
|
||||||
@ -557,10 +582,10 @@ 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" }
|
||||||
{
|
{
|
||||||
"return": [
|
"return": [
|
||||||
{
|
{
|
||||||
"current": false,
|
"current": false,
|
||||||
@ -571,13 +596,13 @@ command:
|
|||||||
"method-name": "dynticks"
|
"method-name": "dynticks"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
TimerAlarmMethodList *method_list, *method;
|
TimerAlarmMethodList *method_list, *method;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
@ -594,4 +619,4 @@ void hmp_info_alarm_methods(Monitor *mon)
|
|||||||
}
|
}
|
||||||
|
|
||||||
qapi_free_TimerAlarmMethodList(method_list);
|
qapi_free_TimerAlarmMethodList(method_list);
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user