Compare commits
156
Commits
v5.1.0
..
stable-4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cdf8c4efa | ||
|
|
4a0db6ba7d | ||
|
|
0664ffac4b | ||
|
|
27f56b9aa2 | ||
|
|
97701bc03e | ||
|
|
ecdb0d5651 | ||
|
|
9c2e242077 | ||
|
|
fb6a24fb1d | ||
|
|
60c21aa017 | ||
|
|
5eca12bbad | ||
|
|
1c8d9fb334 | ||
|
|
09397e9657 | ||
|
|
674d382225 | ||
|
|
5ff78dc9bc | ||
|
|
47e0fa7479 | ||
|
|
745859d5bf | ||
|
|
c6decabc4a | ||
|
|
580c08b326 | ||
|
|
9dd68ac26b | ||
|
|
4e258da94a | ||
|
|
e08de99abe | ||
|
|
5e063a5846 | ||
|
|
1509a13240 | ||
|
|
0b487ea664 | ||
|
|
3dd28c8ecc | ||
|
|
ee9f37f3e5 | ||
|
|
8952da32c3 | ||
|
|
e92b21ffc4 | ||
|
|
a967e75f3a | ||
|
|
aacf6bfb7e | ||
|
|
4b34c6d724 | ||
|
|
9adb6569bf | ||
|
|
b1b362aa8e | ||
|
|
dc6bdba433 | ||
|
|
bc509b2a5b | ||
|
|
cd8ecfb19c | ||
|
|
abf9ffa7b3 | ||
|
|
c44015c50c | ||
|
|
b5ba361d8f | ||
|
|
52771abbfa | ||
|
|
d306348fd6 | ||
|
|
f3ef98874e | ||
|
|
e8a286010c | ||
|
|
9a30621d3d | ||
|
|
0972fbf353 | ||
|
|
9b59fdf478 | ||
|
|
ec3bd881e2 | ||
|
|
65fad28d85 | ||
|
|
256ecc06eb | ||
|
|
606a6bf788 | ||
|
|
e8ae3a4e2b | ||
|
|
7e1bc51f3f | ||
|
|
8d151ab5c2 | ||
|
|
6772bba8a4 | ||
|
|
45b65bf8df | ||
|
|
aea7a50fb5 | ||
|
|
2f7597fbc2 | ||
|
|
f127d16397 | ||
|
|
862240852b | ||
|
|
1343d33371 | ||
|
|
c436692c6a | ||
|
|
69a6048e1e | ||
|
|
01392ae31a | ||
|
|
4e98c388d6 | ||
|
|
54bcaf08d6 | ||
|
|
e727aa1a7b | ||
|
|
690e3004ae | ||
|
|
a918ea2ec3 | ||
|
|
c1cad76dcd | ||
|
|
a6e44eee6c | ||
|
|
3729ff3032 | ||
|
|
2367c7235b | ||
|
|
0c6499ff2b | ||
|
|
17216bc044 | ||
|
|
410252fc5b | ||
|
|
603cda272d | ||
|
|
03afe9c035 | ||
|
|
18f6b13e08 | ||
|
|
6c75ddf4a9 | ||
|
|
d6d45d9ed1 | ||
|
|
2a7c80d82e | ||
|
|
e27f334fdc | ||
|
|
0c1d805360 | ||
|
|
252d614ea2 | ||
|
|
dad6d5e7e6 | ||
|
|
ad56aecb21 | ||
|
|
d5691a6373 | ||
|
|
34c78a4100 | ||
|
|
8d127b4be7 | ||
|
|
ea1518bb5e | ||
|
|
c5feb39219 | ||
|
|
25fcaed9a3 | ||
|
|
aabd9ddd2d | ||
|
|
33be7aa9b6 | ||
|
|
8f5728cb97 | ||
|
|
e3531619f1 | ||
|
|
4996bd7161 | ||
|
|
3c3e1653c5 | ||
|
|
7cc217b30d | ||
|
|
219362f965 | ||
|
|
8fc4aa4822 | ||
|
|
4a9486a02d | ||
|
|
c44c4f7229 | ||
|
|
a0dc4d2495 | ||
|
|
e0ccde3887 | ||
|
|
4a1c5955e7 | ||
|
|
2dc540e40d | ||
|
|
4540aa4a8d | ||
|
|
30aa0ea6c5 | ||
|
|
382b9f09bd | ||
|
|
373fd948ab | ||
|
|
ab7f6eaa5b | ||
|
|
f9854de0d8 | ||
|
|
e49ae74a24 | ||
|
|
0319118bcf | ||
|
|
2a7569e751 | ||
|
|
3e1d95301e | ||
|
|
735cd8ddab | ||
|
|
1190026fe4 | ||
|
|
8d61b1e2c4 | ||
|
|
cbc8277051 | ||
|
|
e7cad754fd | ||
|
|
d50aa8acbc | ||
|
|
3a8068f4eb | ||
|
|
5f08c382ca | ||
|
|
edd67a61f4 | ||
|
|
153c3320e7 | ||
|
|
bf3f12ac8c | ||
|
|
956e1b2d97 | ||
|
|
eb54a2f9ce | ||
|
|
fa446ae444 | ||
|
|
3fb2521040 | ||
|
|
742195db17 | ||
|
|
98c74fe49a | ||
|
|
7042922dd7 | ||
|
|
a474197f11 | ||
|
|
a843731d7f | ||
|
|
d5a5d43e27 | ||
|
|
0253531824 | ||
|
|
2f4affb721 | ||
|
|
77d9c84d9f | ||
|
|
4412cb3bca | ||
|
|
3a94a8b7fd | ||
|
|
0cfa46da8f | ||
|
|
ba6a94e64e | ||
|
|
a5f815514a | ||
|
|
2215837fe2 | ||
|
|
cbdfd3865b | ||
|
|
89eebb016d | ||
|
|
def30090ad | ||
|
|
52a02834e0 | ||
|
|
da0948d13c | ||
|
|
d636d64b35 | ||
|
|
bed590f2b8 | ||
|
|
a115daadf6 | ||
|
|
85df33073a |
No files matched your search
+10
-14
@@ -3,40 +3,36 @@ env:
|
||||
|
||||
freebsd_12_task:
|
||||
freebsd_instance:
|
||||
image_family: freebsd-12-1
|
||||
image: freebsd-12-0-release-amd64
|
||||
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
|
||||
install_script: pkg install -y
|
||||
bash bison curl cyrus-sasl git glib gmake gnutls gsed
|
||||
nettle perl5 pixman pkgconf png usbredir
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure || { cat config.log; exit 1; }
|
||||
- gmake -j8
|
||||
- gmake V=1 check
|
||||
- gmake -j8 V=1 check
|
||||
|
||||
macos_task:
|
||||
osx_instance:
|
||||
image: mojave-base
|
||||
install_script:
|
||||
- brew install pkg-config python gnu-sed glib pixman make sdl2 bash
|
||||
- brew install pkg-config python gnu-sed glib pixman make sdl2
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; }
|
||||
- ./configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake check
|
||||
- gmake check -j$(sysctl -n hw.ncpu)
|
||||
|
||||
macos_xcode_task:
|
||||
osx_instance:
|
||||
# this is an alias for the latest Xcode
|
||||
image: mojave-xcode
|
||||
install_script:
|
||||
- brew install pkg-config gnu-sed glib pixman make sdl2 bash
|
||||
- brew install pkg-config gnu-sed glib pixman make sdl2
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --cc=clang || { cat config.log; exit 1; }
|
||||
- ./configure --cc=clang || { cat config.log; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake check
|
||||
- gmake check -j$(sysctl -n hw.ncpu)
|
||||
@@ -1,34 +0,0 @@
|
||||
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
|
||||
|
||||
# Close issues and pull requests
|
||||
close: true
|
||||
|
||||
# Lock issues and pull requests
|
||||
lock: true
|
||||
|
||||
issues:
|
||||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's master
|
||||
repostories hosted on https://git.qemu.org/git/qemu.git.
|
||||
The project does not process issues filed on GitHub.
|
||||
|
||||
The project issues are tracked on Launchpad:
|
||||
https://bugs.launchpad.net/qemu
|
||||
|
||||
QEMU welcomes bug report contributions. You can file new ones on:
|
||||
https://bugs.launchpad.net/qemu/+filebug
|
||||
|
||||
pulls:
|
||||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's master
|
||||
repostories hosted on https://git.qemu.org/git/qemu.git.
|
||||
The project does not process merge requests filed on GitHub.
|
||||
|
||||
QEMU welcomes contributions of code (either fixing bugs or adding new
|
||||
functionality). However, we get a lot of patches, and so we have some
|
||||
guidelines about contributing on the project website:
|
||||
https://www.qemu.org/contribute/
|
||||
+10
-11
@@ -6,7 +6,6 @@
|
||||
/config-target.*
|
||||
/config.status
|
||||
/config-temp
|
||||
/tools/virtiofsd/50-qemu-virtiofsd.json
|
||||
/elf2dmp
|
||||
/trace-events-all
|
||||
/trace/generated-events.h
|
||||
@@ -34,18 +33,20 @@
|
||||
/qapi/qapi-builtin-types.[ch]
|
||||
/qapi/qapi-builtin-visit.[ch]
|
||||
/qapi/qapi-commands-*.[ch]
|
||||
**/qapi/qapi-commands.[ch]
|
||||
**/qapi/qapi-emit-events.[ch]
|
||||
/qapi/qapi-commands.[ch]
|
||||
/qapi/qapi-emit-events.[ch]
|
||||
/qapi/qapi-events-*.[ch]
|
||||
**/qapi/qapi-events.[ch]
|
||||
**/qapi/qapi-init-commands.[ch]
|
||||
**/qapi/qapi-introspect.[ch]
|
||||
/qapi/qapi-events.[ch]
|
||||
/qapi/qapi-introspect.[ch]
|
||||
/qapi/qapi-types-*.[ch]
|
||||
**/qapi/qapi-types.[ch]
|
||||
/qapi/qapi-types.[ch]
|
||||
/qapi/qapi-visit-*.[ch]
|
||||
!/qapi/qapi-visit-core.c
|
||||
**/qapi/qapi-visit.[ch]
|
||||
**/qapi/qapi-doc.texi
|
||||
/qapi/qapi-visit.[ch]
|
||||
/qapi/qapi-doc.texi
|
||||
/qemu-doc.html
|
||||
/qemu-doc.info
|
||||
/qemu-doc.txt
|
||||
/qemu-edid
|
||||
/qemu-img
|
||||
/qemu-nbd
|
||||
@@ -59,7 +60,6 @@
|
||||
/qemu-keymap
|
||||
/qemu-monitor.texi
|
||||
/qemu-monitor-info.texi
|
||||
/qemu-storage-daemon
|
||||
/qemu-version.h
|
||||
/qemu-version.h.tmp
|
||||
/module_block.h
|
||||
@@ -93,7 +93,6 @@
|
||||
*.tp
|
||||
*.vr
|
||||
*.d
|
||||
!/.gitlab-ci.d
|
||||
!/scripts/qemu-guest-agent/fsfreeze-hook.d
|
||||
*.o
|
||||
.sdk
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
.container_job_template: &container_job_definition
|
||||
image: docker:stable
|
||||
stage: containers
|
||||
services:
|
||||
- docker:dind
|
||||
before_script:
|
||||
- export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest"
|
||||
- export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest"
|
||||
- apk add python3
|
||||
- docker info
|
||||
- docker login registry.gitlab.com -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
|
||||
script:
|
||||
- echo "TAG:$TAG"
|
||||
- echo "COMMON_TAG:$COMMON_TAG"
|
||||
- docker pull "$TAG" || docker pull "$COMMON_TAG" || true
|
||||
- ./tests/docker/docker.py --engine docker build
|
||||
-t "qemu/$NAME" -f "tests/docker/dockerfiles/$NAME.docker"
|
||||
-r $CI_REGISTRY_IMAGE
|
||||
- docker tag "qemu/$NAME" "$TAG"
|
||||
- docker push "$TAG"
|
||||
after_script:
|
||||
- docker logout
|
||||
rules:
|
||||
- changes:
|
||||
- .gitlab-ci.d/containers.yml
|
||||
- tests/docker/*
|
||||
- tests/docker/dockerfiles/*
|
||||
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||
- if: '$CI_COMMIT_REF_NAME == "testing/next"'
|
||||
|
||||
amd64-centos7-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: centos7
|
||||
|
||||
amd64-centos8-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: centos8
|
||||
|
||||
amd64-debian10-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: debian10
|
||||
|
||||
amd64-debian11-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: debian11
|
||||
|
||||
amd64-debian9-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: debian9
|
||||
|
||||
amd64-debian9-mxe-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian9-container']
|
||||
variables:
|
||||
NAME: debian9-mxe
|
||||
|
||||
alpha-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-alpha-cross
|
||||
|
||||
amd64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-amd64-cross
|
||||
|
||||
amd64-debian-user-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-all-test-cross
|
||||
|
||||
amd64-debian-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-amd64
|
||||
|
||||
arm64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-arm64-cross
|
||||
|
||||
arm64-test-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian11-container']
|
||||
variables:
|
||||
NAME: debian-arm64-test-cross
|
||||
|
||||
armel-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-armel-cross
|
||||
|
||||
armhf-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-armhf-cross
|
||||
|
||||
hppa-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-hppa-cross
|
||||
|
||||
m68k-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-m68k-cross
|
||||
|
||||
mips64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips64-cross
|
||||
|
||||
mips64el-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips64el-cross
|
||||
|
||||
mips-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mips-cross
|
||||
|
||||
mipsel-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-mipsel-cross
|
||||
|
||||
powerpc-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-powerpc-cross
|
||||
|
||||
ppc64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-ppc64-cross
|
||||
|
||||
ppc64el-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-ppc64el-cross
|
||||
|
||||
riscv64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-riscv64-cross
|
||||
|
||||
s390x-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-s390x-cross
|
||||
|
||||
sh4-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-sh4-cross
|
||||
|
||||
sparc64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-sparc64-cross
|
||||
|
||||
tricore-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian9-container']
|
||||
variables:
|
||||
NAME: debian-tricore-cross
|
||||
|
||||
win32-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer3
|
||||
needs: ['amd64-debian9-mxe-container']
|
||||
variables:
|
||||
NAME: debian-win32-cross
|
||||
|
||||
win64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer3
|
||||
needs: ['amd64-debian9-mxe-container']
|
||||
variables:
|
||||
NAME: debian-win64-cross
|
||||
|
||||
xtensa-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: debian-xtensa-cross
|
||||
|
||||
cris-fedora-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora-cris-cross
|
||||
|
||||
amd64-fedora-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora
|
||||
|
||||
i386-fedora-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora-i386-cross
|
||||
|
||||
amd64-ubuntu1804-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: ubuntu1804
|
||||
|
||||
amd64-ubuntu2004-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: ubuntu2004
|
||||
|
||||
amd64-ubuntu-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: ubuntu
|
||||
@@ -1,50 +0,0 @@
|
||||
docker-edk2:
|
||||
stage: containers
|
||||
rules: # Only run this job when the Dockerfile is modified
|
||||
- changes:
|
||||
- .gitlab-ci.d/edk2.yml
|
||||
- .gitlab-ci.d/edk2/Dockerfile
|
||||
when: always
|
||||
image: docker:19.03.1
|
||||
services:
|
||||
- docker:19.03.1-dind
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:edk2-cross-build
|
||||
# We don't use TLS
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
before_script:
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
script:
|
||||
- docker pull $IMAGE_TAG || true
|
||||
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
--tag $IMAGE_TAG .gitlab-ci.d/edk2
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
- docker push $IMAGE_TAG
|
||||
|
||||
build-edk2:
|
||||
stage: build
|
||||
rules: # Only run this job when ...
|
||||
- changes: # ... roms/edk2/ is modified (submodule updated)
|
||||
- roms/edk2/*
|
||||
when: always
|
||||
- if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2'
|
||||
when: always
|
||||
- if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2'
|
||||
when: always
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/edk2*bz2
|
||||
- pc-bios/edk2-licenses.txt
|
||||
- edk2-stdout.log
|
||||
- edk2-stderr.log
|
||||
image: $CI_REGISTRY_IMAGE:edk2-cross-build
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
script: # Clone the required submodules and build EDK2
|
||||
- git submodule update --init roms/edk2
|
||||
- git -C roms/edk2 submodule update --init
|
||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
- make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# Docker image to cross-compile EDK2 firmware binaries
|
||||
#
|
||||
FROM ubuntu:16.04
|
||||
|
||||
MAINTAINER Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
|
||||
# Install packages required to build EDK2
|
||||
RUN apt update \
|
||||
&& \
|
||||
\
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
apt install --assume-yes --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
dos2unix \
|
||||
gcc-aarch64-linux-gnu \
|
||||
gcc-arm-linux-gnueabi \
|
||||
git \
|
||||
iasl \
|
||||
make \
|
||||
nasm \
|
||||
python \
|
||||
uuid-dev \
|
||||
&& \
|
||||
\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
@@ -1,64 +0,0 @@
|
||||
docker-opensbi:
|
||||
stage: containers
|
||||
rules: # Only run this job when the Dockerfile is modified
|
||||
- changes:
|
||||
- .gitlab-ci.d/opensbi.yml
|
||||
- .gitlab-ci.d/opensbi/Dockerfile
|
||||
when: always
|
||||
image: docker:19.03.1
|
||||
services:
|
||||
- docker:19.03.1-dind
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
||||
# We don't use TLS
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
before_script:
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
script:
|
||||
- docker pull $IMAGE_TAG || true
|
||||
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
--tag $IMAGE_TAG .gitlab-ci.d/opensbi
|
||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
- docker push $IMAGE_TAG
|
||||
|
||||
build-opensbi:
|
||||
stage: build
|
||||
rules: # Only run this job when ...
|
||||
- changes: # ... roms/opensbi/ is modified (submodule updated)
|
||||
- roms/opensbi/*
|
||||
when: always
|
||||
- if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi'
|
||||
when: always
|
||||
- if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI'
|
||||
when: always
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/opensbi-riscv32-sifive_u-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv32-virt-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv64-virt-fw_jump.bin
|
||||
- opensbi32-virt-stdout.log
|
||||
- opensbi32-virt-stderr.log
|
||||
- opensbi64-virt-stdout.log
|
||||
- opensbi64-virt-stderr.log
|
||||
- opensbi32-sifive_u-stdout.log
|
||||
- opensbi32-sifive_u-stderr.log
|
||||
- opensbi64-sifive_u-stdout.log
|
||||
- opensbi64-sifive_u-stderr.log
|
||||
image: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
script: # Clone the required submodules and build OpenSBI
|
||||
- git submodule update --init roms/opensbi
|
||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi32-virt 2>&1 1>opensbi32-virt-stdout.log | tee -a opensbi32-virt-stderr.log >&2
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi64-virt 2>&1 1>opensbi64-virt-stdout.log | tee -a opensbi64-virt-stderr.log >&2
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi32-sifive_u 2>&1 1>opensbi32-sifive_u-stdout.log | tee -a opensbi32-sifive_u-stderr.log >&2
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi64-sifive_u 2>&1 1>opensbi64-sifive_u-stdout.log | tee -a opensbi64-sifive_u-stderr.log >&2
|
||||
@@ -1,33 +0,0 @@
|
||||
#
|
||||
# Docker image to cross-compile OpenSBI firmware binaries
|
||||
#
|
||||
FROM ubuntu:18.04
|
||||
|
||||
MAINTAINER Bin Meng <bmeng.cn@gmail.com>
|
||||
|
||||
# Install packages required to build OpenSBI
|
||||
RUN apt update \
|
||||
&& \
|
||||
\
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
apt install --assume-yes --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
git \
|
||||
make \
|
||||
wget \
|
||||
&& \
|
||||
\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Manually install the kernel.org "Crosstool" based toolchains for gcc-8.3
|
||||
RUN wget -O - \
|
||||
https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/8.3.0/x86_64-gcc-8.3.0-nolibc-riscv32-linux.tar.xz \
|
||||
| tar -C /opt -xJ
|
||||
RUN wget -O - \
|
||||
https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/8.3.0/x86_64-gcc-8.3.0-nolibc-riscv64-linux.tar.xz \
|
||||
| tar -C /opt -xJ
|
||||
|
||||
# Export the toolchains to the system path
|
||||
ENV PATH="/opt/gcc-8.3.0-nolibc/riscv32-linux/bin:${PATH}"
|
||||
ENV PATH="/opt/gcc-8.3.0-nolibc/riscv64-linux/bin:${PATH}"
|
||||
+66
-256
@@ -1,273 +1,83 @@
|
||||
# Currently we have two build stages after our containers are built:
|
||||
# - build (for traditional build and test or first stage build)
|
||||
# - test (for test stages, using build artefacts from a build stage)
|
||||
stages:
|
||||
- containers
|
||||
- containers-layer2
|
||||
- containers-layer3
|
||||
- build
|
||||
- test
|
||||
before_script:
|
||||
- apt-get update -qq
|
||||
- apt-get install -y -qq flex bison libglib2.0-dev libpixman-1-dev genisoimage
|
||||
|
||||
# We assume GitLab has it's own caching set up for RPM/APT repositories so we
|
||||
# just take care of avocado assets here.
|
||||
cache:
|
||||
paths:
|
||||
- $HOME/avocado/data/cache
|
||||
build-system1:
|
||||
script:
|
||||
- apt-get install -y -qq libgtk-3-dev libvte-dev nettle-dev libcacard-dev
|
||||
libusb-dev libvde-dev libspice-protocol-dev libgl1-mesa-dev libvdeplug-dev
|
||||
- ./configure --enable-werror --target-list="aarch64-softmmu alpha-softmmu
|
||||
cris-softmmu hppa-softmmu lm32-softmmu moxie-softmmu microblazeel-softmmu
|
||||
mips64el-softmmu m68k-softmmu ppc-softmmu riscv64-softmmu sparc-softmmu"
|
||||
- make -j2
|
||||
- make -j2 check
|
||||
|
||||
include:
|
||||
- local: '/.gitlab-ci.d/edk2.yml'
|
||||
- local: '/.gitlab-ci.d/opensbi.yml'
|
||||
- local: '/.gitlab-ci.d/containers.yml'
|
||||
|
||||
.native_build_job_template: &native_build_job_definition
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
before_script:
|
||||
- JOBS=$(expr $(nproc) + 1)
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if test -n "$TARGETS";
|
||||
then
|
||||
../configure --enable-werror $CONFIGURE_ARGS --target-list="$TARGETS" ;
|
||||
else
|
||||
../configure --enable-werror $CONFIGURE_ARGS ;
|
||||
fi
|
||||
- make -j"$JOBS"
|
||||
- if test -n "$MAKE_CHECK_ARGS";
|
||||
then
|
||||
make -j"$JOBS" $MAKE_CHECK_ARGS ;
|
||||
fi
|
||||
|
||||
.native_test_job_template: &native_test_job_definition
|
||||
stage: test
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
script:
|
||||
- cd build
|
||||
- find . -type f -exec touch {} +
|
||||
- make $MAKE_CHECK_ARGS
|
||||
|
||||
.acceptance_template: &acceptance_definition
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}-cache"
|
||||
paths:
|
||||
- ${CI_PROJECT_DIR}/avocado-cache
|
||||
policy: pull-push
|
||||
before_script:
|
||||
- mkdir -p ~/.config/avocado
|
||||
- echo "[datadir.paths]" > ~/.config/avocado/avocado.conf
|
||||
- echo "cache_dirs = ['${CI_PROJECT_DIR}/avocado-cache']"
|
||||
>> ~/.config/avocado/avocado.conf
|
||||
- if [ -d ${CI_PROJECT_DIR}/avocado-cache ]; then
|
||||
du -chs ${CI_PROJECT_DIR}/avocado-cache ;
|
||||
fi
|
||||
after_script:
|
||||
- cd build
|
||||
- python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat
|
||||
- du -chs ${CI_PROJECT_DIR}/avocado-cache
|
||||
|
||||
build-system-ubuntu:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
moxie-softmmu microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-ubuntu:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-ubuntu
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-ubuntu:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-ubuntu
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-debian:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
|
||||
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-debian:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-debian:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-fedora:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu
|
||||
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-fedora:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-fedora:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-centos:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
TARGETS: ppc64-softmmu lm32-softmmu or1k-softmmu s390x-softmmu
|
||||
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-centos:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-centos
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-centos:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-centos
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
build-system2:
|
||||
script:
|
||||
- apt-get install -y -qq libsdl2-dev libgcrypt-dev libbrlapi-dev libaio-dev
|
||||
libfdt-dev liblzo2-dev librdmacm-dev libibverbs-dev libibumad-dev
|
||||
- ./configure --enable-werror --target-list="tricore-softmmu unicore32-softmmu
|
||||
microblaze-softmmu mips-softmmu riscv32-softmmu s390x-softmmu sh4-softmmu
|
||||
sparc64-softmmu x86_64-softmmu xtensa-softmmu nios2-softmmu or1k-softmmu"
|
||||
- make -j2
|
||||
- make -j2 check
|
||||
|
||||
build-disabled:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --disable-rdma --disable-slirp --disable-curl
|
||||
script:
|
||||
- ./configure --enable-werror --disable-rdma --disable-slirp --disable-curl
|
||||
--disable-capstone --disable-live-block-migration --disable-glusterfs
|
||||
--disable-replication --disable-coroutine-pool --disable-smartcard
|
||||
--disable-guest-agent --disable-curses --disable-libxml2 --disable-tpm
|
||||
--disable-qom-cast-debug --disable-spice --disable-vhost-vsock
|
||||
--disable-vhost-net --disable-vhost-crypto --disable-vhost-user
|
||||
TARGETS: i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user
|
||||
MAKE_CHECK_ARGS: check-qtest SPEED=slow
|
||||
--target-list="i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user"
|
||||
- make -j2
|
||||
- make -j2 check-qtest SPEED=slow
|
||||
|
||||
build-tcg-disabled:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-tcg --audio-drv-list=""
|
||||
- make -j"$JOBS"
|
||||
- make check-unit
|
||||
- make check-qapi-schema
|
||||
- cd tests/qemu-iotests/
|
||||
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
|
||||
052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163
|
||||
170 171 183 184 192 194 197 208 215 221 222 226 227 236 253 277
|
||||
- ./check -qcow2 028 051 056 057 058 065 067 068 082 085 091 095 096 102 122
|
||||
124 132 139 142 144 145 151 152 155 157 165 194 196 197 200 202
|
||||
208 209 215 216 218 222 227 234 246 247 248 250 254 255 257 258
|
||||
260 261 262 263 264 270 272 273 277 279
|
||||
script:
|
||||
- apt-get install -y -qq clang libgtk-3-dev libbluetooth-dev libusb-dev
|
||||
- ./configure --cc=clang --enable-werror --disable-tcg --audio-drv-list=""
|
||||
- make -j2
|
||||
- make check-unit
|
||||
- make check-qapi-schema
|
||||
- cd tests/qemu-iotests/
|
||||
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
|
||||
052 063 077 086 101 104 106 113 147 148 150 151 152 157 159 160
|
||||
163 170 171 183 184 192 194 197 205 208 215 221 222 226 227 236
|
||||
- ./check -qcow2 028 040 051 056 057 058 065 067 068 082 085 091 095 096 102
|
||||
122 124 127 129 132 139 142 144 145 147 151 152 155 157 165 194
|
||||
196 197 200 202 203 205 208 209 215 216 218 222 227 234 246 247
|
||||
248 250 254 255 256
|
||||
|
||||
build-user:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
script:
|
||||
- ./configure --enable-werror --disable-system --disable-guest-agent
|
||||
--disable-capstone --disable-slirp --disable-fdt
|
||||
- make -j2
|
||||
- make run-tcg-tests-i386-linux-user run-tcg-tests-x86_64-linux-user
|
||||
|
||||
build-clang:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++
|
||||
TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu
|
||||
ppc-softmmu s390x-softmmu arm-linux-user
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
build-oss-fuzz:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
script:
|
||||
- mkdir build-oss-fuzz
|
||||
- CC="clang" CXX="clang++" CFLAGS="-fsanitize=address"
|
||||
./scripts/oss-fuzz/build.sh
|
||||
- for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f
|
||||
| grep -v slirp); do
|
||||
grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ;
|
||||
echo Testing ${fuzzer} ... ;
|
||||
ASAN_OPTIONS="fast_unwind_on_malloc=0"
|
||||
"${fuzzer}" -runs=1000 -seed=1 || exit 1 ;
|
||||
done
|
||||
script:
|
||||
- apt-get install -y -qq clang libsdl2-dev libattr1-dev libcap-dev
|
||||
xfslibs-dev libiscsi-dev libnfs-dev libseccomp-dev gnutls-dev librbd-dev
|
||||
- ./configure --cc=clang --cxx=clang++ --enable-werror
|
||||
--target-list="alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu
|
||||
ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user"
|
||||
- make -j2
|
||||
- make -j2 check
|
||||
|
||||
build-tci:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
script:
|
||||
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-tcg-interpreter
|
||||
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)"
|
||||
- make -j"$JOBS"
|
||||
- make run-tcg-tests-x86_64-softmmu
|
||||
- make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
|
||||
- for tg in $TARGETS ; do
|
||||
export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ;
|
||||
./tests/qtest/boot-serial-test || exit 1 ;
|
||||
./tests/qtest/cdrom-test || exit 1 ;
|
||||
done
|
||||
- QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/qtest/pxe-test
|
||||
- QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x" ./tests/qtest/pxe-test -m slow
|
||||
script:
|
||||
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
|
||||
- ./configure --enable-tcg-interpreter
|
||||
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)"
|
||||
- make -j2
|
||||
- make tests/boot-serial-test tests/cdrom-test tests/pxe-test
|
||||
- for tg in $TARGETS ; do
|
||||
export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ;
|
||||
./tests/boot-serial-test || exit 1 ;
|
||||
./tests/cdrom-test || exit 1 ;
|
||||
done
|
||||
- QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/pxe-test
|
||||
- QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x" ./tests/pxe-test -m slow
|
||||
@@ -10,6 +10,9 @@
|
||||
[submodule "roms/openbios"]
|
||||
path = roms/openbios
|
||||
url = https://git.qemu.org/git/openbios.git
|
||||
[submodule "roms/openhackware"]
|
||||
path = roms/openhackware
|
||||
url = https://git.qemu.org/git/openhackware.git
|
||||
[submodule "roms/qemu-palcode"]
|
||||
path = roms/qemu-palcode
|
||||
url = https://git.qemu.org/git/qemu-palcode.git
|
||||
|
||||
@@ -39,23 +39,15 @@ Julia Suvorova <jusual@mail.ru> Julia Suvorova via Qemu-devel <qemu-devel@nongnu
|
||||
Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu-devel@nongnu.org>
|
||||
|
||||
# Next, replace old addresses by a more recent one.
|
||||
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@mips.com>
|
||||
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@imgtec.com>
|
||||
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <amarkovic@wavecomp.com>
|
||||
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <arikalo@wavecomp.com>
|
||||
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <aleksandar.rikalo@rt-rk.com>
|
||||
Alexander Graf <agraf@csgraf.de> <agraf@suse.de>
|
||||
Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@mips.com>
|
||||
Aleksandar Markovic <amarkovic@wavecomp.com> <aleksandar.markovic@imgtec.com>
|
||||
Aleksandar Rikalo <aleksandar.rikalo@rt-rk.com> <arikalo@wavecomp.com>
|
||||
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
|
||||
Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
|
||||
Frederic Konrad <konrad@adacore.com> <fred.konrad@greensocs.com>
|
||||
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
|
||||
Leif Lindholm <leif@nuviainc.com> <leif.lindholm@linaro.org>
|
||||
Radoslaw Biernacki <rad@semihalf.com> <radoslaw.biernacki@linaro.org>
|
||||
Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com>
|
||||
Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com>
|
||||
Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org>
|
||||
Philippe Mathieu-Daudé <philmd@redhat.com> <f4bug@amsat.org>
|
||||
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
|
||||
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
||||
|
||||
# Also list preferred name forms where people have changed their
|
||||
@@ -159,8 +151,7 @@ Xiaoqiang Zhao <zxq_yx_007@163.com>
|
||||
Xinhua Cao <caoxinhua@huawei.com>
|
||||
Xiong Zhang <xiong.y.zhang@intel.com>
|
||||
Yin Yin <yin.yin@cs2c.com.cn>
|
||||
Yu-Chen Lin <npes87184@gmail.com>
|
||||
Yu-Chen Lin <npes87184@gmail.com> <yuchenlin@synology.com>
|
||||
yuchenlin <npes87184@gmail.com>
|
||||
YunQiang Su <syq@debian.org>
|
||||
YunQiang Su <ysu@wavecomp.com>
|
||||
Yuri Pudgorodskiy <yur@virtuozzo.com>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# .readthedocs.yml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# We want all the document formats
|
||||
formats: all
|
||||
|
||||
# For consistency, we require that QEMU's Sphinx extensions
|
||||
# run with at least the same minimum version of Python that
|
||||
# we require for other Python in our codebase (our conf.py
|
||||
# enforces this, and some code needs it.)
|
||||
python:
|
||||
version: 3.5
|
||||
+6
-6
@@ -26,14 +26,14 @@ env:
|
||||
- IMAGE=debian-ppc64el-cross
|
||||
TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user
|
||||
build:
|
||||
pre_ci:
|
||||
- make docker-image-${IMAGE} V=1
|
||||
pre_ci_boot:
|
||||
image_name: registry.gitlab.com/qemu-project/qemu/qemu/${IMAGE}
|
||||
image_tag: latest
|
||||
pull: true
|
||||
image_name: qemu
|
||||
image_tag: ${IMAGE}
|
||||
pull: false
|
||||
options: "-e HOME=/root"
|
||||
ci:
|
||||
- unset CC
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-docs ${QEMU_CONFIGURE_OPTS} --target-list=${TARGET_LIST}
|
||||
- ./configure ${QEMU_CONFIGURE_OPTS} --target-list=${TARGET_LIST}
|
||||
- make -j$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
+102
-303
@@ -1,7 +1,6 @@
|
||||
# The current Travis default is a VM based 16.04 Xenial on GCE
|
||||
# Additional builds with specific requirements for a full VM need to
|
||||
# be added as additional matrix: entries later on
|
||||
os: linux
|
||||
dist: xenial
|
||||
language: c
|
||||
compiler:
|
||||
@@ -9,8 +8,9 @@ compiler:
|
||||
cache:
|
||||
# There is one cache per branch and compiler version.
|
||||
# characteristics of each job are used to identify the cache:
|
||||
# - OS name (currently only linux)
|
||||
# - OS name (currently, linux, osx, or windows)
|
||||
# - OS distribution (for Linux, xenial, trusty, or precise)
|
||||
# - macOS image name (e.g., xcode7.2)
|
||||
# - Names and values of visible environment variables set in .travis.yml or Settings panel
|
||||
timeout: 1200
|
||||
ccache: true
|
||||
@@ -26,6 +26,7 @@ addons:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-dev
|
||||
- libcap-ng-dev
|
||||
- libgcc-4.8-dev
|
||||
- libgnutls28-dev
|
||||
@@ -48,12 +49,16 @@ addons:
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
- libzstd-dev
|
||||
- sparse
|
||||
- uuid-dev
|
||||
- gcovr
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
- glib
|
||||
- pixman
|
||||
- gnu-sed
|
||||
update: true
|
||||
|
||||
|
||||
# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
|
||||
@@ -69,127 +74,94 @@ notifications:
|
||||
|
||||
env:
|
||||
global:
|
||||
- SRC_DIR=".."
|
||||
- BUILD_DIR="build"
|
||||
- SRC_DIR="."
|
||||
- BUILD_DIR="."
|
||||
- BASE_CONFIG="--disable-docs --disable-tools"
|
||||
- TEST_BUILD_CMD=""
|
||||
- TEST_CMD="make check V=1"
|
||||
# This is broadly a list of "mainline" softmmu targets which have support across the major distros
|
||||
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
|
||||
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
|
||||
- CCACHE_MAXSIZE=1G
|
||||
- G_MESSAGES_DEBUG=error
|
||||
|
||||
|
||||
git:
|
||||
# we want to do this ourselves
|
||||
submodules: false
|
||||
|
||||
# Common first phase for all steps
|
||||
before_install:
|
||||
- if command -v ccache ; then ccache --zero-stats ; fi
|
||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
|
||||
# Configure step - may be overridden
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then export PATH="/usr/local/opt/ccache/libexec:$PATH" ; fi
|
||||
- if command -v ccache ; then ccache --zero-stats ; fi
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
|
||||
|
||||
# Main build & test - rarely overridden - controlled by TEST_CMD
|
||||
script:
|
||||
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
|
||||
- |
|
||||
if [ "$BUILD_RC" -eq 0 ] && [ -n "$TEST_BUILD_CMD" ]; then
|
||||
${TEST_BUILD_CMD} || BUILD_RC=$?
|
||||
else
|
||||
$(exit $BUILD_RC);
|
||||
fi
|
||||
- |
|
||||
if [ "$BUILD_RC" -eq 0 ] ; then
|
||||
${TEST_CMD} ;
|
||||
else
|
||||
$(exit $BUILD_RC);
|
||||
fi
|
||||
- make -j3 && travis_retry ${TEST_CMD}
|
||||
after_script:
|
||||
- df -h
|
||||
- if command -v ccache ; then ccache --show-stats ; fi
|
||||
|
||||
|
||||
jobs:
|
||||
matrix:
|
||||
include:
|
||||
- name: "GCC static (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-system --static"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# we split the system builds as it takes a while to build them all
|
||||
- name: "GCC (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
- name: "GCC (other-softmmu)"
|
||||
env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
||||
- env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# Just build tools and run minimal unit and softfloat checks
|
||||
- name: "GCC check-softfloat (user)"
|
||||
env:
|
||||
- env:
|
||||
- BASE_CONFIG="--enable-tools"
|
||||
- CONFIG="--disable-user --disable-system"
|
||||
- TEST_CMD="make check-unit check-softfloat -j${JOBS}"
|
||||
- TEST_CMD="make check-unit check-softfloat -j3"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# --enable-debug implies --enable-debug-tcg, also runs quite a bit slower
|
||||
- name: "GCC debug (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-debug --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug"
|
||||
|
||||
|
||||
# TCG debug can be run just on its own and is mostly agnostic to user/softmmu distinctions
|
||||
- name: "GCC debug (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-debug-tcg --disable-system"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
- name: "GCC some libs disabled (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-libusb --disable-replication --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
|
||||
|
||||
# Module builds are mostly of interest to major distros
|
||||
- name: "GCC modules (main-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-modules --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# Alternate coroutines implementations are only really of interest to KVM users
|
||||
# However we can't test against KVM on Travis so we can only run unit tests
|
||||
- name: "check-unit coroutine=ucontext"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--with-coroutine=ucontext --disable-tcg"
|
||||
- TEST_CMD="make check-unit -j${JOBS} V=1"
|
||||
- TEST_CMD="make check-unit -j3 V=1"
|
||||
|
||||
|
||||
- name: "check-unit coroutine=sigaltstack"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--with-coroutine=sigaltstack --disable-tcg"
|
||||
- TEST_CMD="make check-unit -j${JOBS} V=1"
|
||||
- TEST_CMD="make check-unit -j3 V=1"
|
||||
|
||||
|
||||
# Check we can build docs and tools (out of tree)
|
||||
- name: "tools and docs (bionic)"
|
||||
dist: bionic
|
||||
env:
|
||||
- env:
|
||||
- BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
|
||||
- BASE_CONFIG="--enable-tools --enable-docs"
|
||||
- CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user"
|
||||
@@ -197,101 +169,118 @@ jobs:
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-sphinx
|
||||
- python-sphinx
|
||||
- texinfo
|
||||
- perl
|
||||
|
||||
|
||||
# Test with Clang for compile portability (Travis uses clang-5.0)
|
||||
- name: "Clang (user)"
|
||||
env:
|
||||
- CONFIG="--disable-system --host-cc=clang --cxx=clang++"
|
||||
- env:
|
||||
- CONFIG="--disable-system"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
|
||||
compiler: clang
|
||||
|
||||
|
||||
- name: "Clang (main-softmmu)"
|
||||
env:
|
||||
- CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS}
|
||||
--host-cc=clang --cxx=clang++"
|
||||
- env:
|
||||
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
|
||||
compiler: clang
|
||||
|
||||
|
||||
- env:
|
||||
- CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS} "
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-sanitize"
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${CONFIG} --extra-cflags="-fsanitize=undefined -Werror" || { cat config.log && exit 1; }
|
||||
- ./configure ${CONFIG} --extra-cflags="-fsanitize=undefined -Werror" || { cat config.log && exit 1; }
|
||||
|
||||
|
||||
- name: "Clang (other-softmmu)"
|
||||
env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}
|
||||
--host-cc=clang --cxx=clang++"
|
||||
- env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
|
||||
compiler: clang
|
||||
|
||||
|
||||
# gprof/gcov are GCC features
|
||||
- name: "GCC gprof/gcov"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-gprof --enable-gcov --disable-pie --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
after_success:
|
||||
- ${SRC_DIR}/scripts/travis/coverage-summary.sh
|
||||
|
||||
|
||||
# We manually include builds which we disable "make check" for
|
||||
- name: "GCC without-default-devices (softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--without-default-devices --disable-user"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
# Check the TCG interpreter (TCI)
|
||||
- name: "GCC TCI"
|
||||
env:
|
||||
- CONFIG="--enable-debug-tcg --enable-tcg-interpreter --disable-kvm --disable-containers
|
||||
--target-list=alpha-softmmu,arm-softmmu,hppa-softmmu,m68k-softmmu,microblaze-softmmu,moxie-softmmu,ppc-softmmu,s390x-softmmu,x86_64-softmmu"
|
||||
- TEST_CMD="make check-qtest check-tcg V=1"
|
||||
# We manually include builds which we disable "make check" for
|
||||
- env:
|
||||
- CONFIG="--enable-debug --enable-tcg-interpreter"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
# We don't need to exercise every backend with every front-end
|
||||
- name: "GCC trace log,simple,syslog (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-trace-backends=log,simple,syslog --disable-system"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
- name: "GCC trace ftrace (x86_64-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-trace-backends=ftrace --target-list=x86_64-softmmu"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
- name: "GCC trace ust (x86_64-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-trace-backends=ust --target-list=x86_64-softmmu"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
# MacOSX builds - cirrus.yml also tests some MacOS builds including latest Xcode
|
||||
|
||||
- env:
|
||||
- CONFIG="--target-list=i386-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,x86_64-softmmu"
|
||||
os: osx
|
||||
osx_image: xcode10.3
|
||||
compiler: clang
|
||||
|
||||
|
||||
# Python builds
|
||||
- name: "GCC Python 3.5 (x86_64-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--target-list=x86_64-softmmu"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
language: python
|
||||
python: 3.5
|
||||
python:
|
||||
- "3.4"
|
||||
|
||||
|
||||
- name: "GCC Python 3.6 (x86_64-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--target-list=x86_64-softmmu"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
language: python
|
||||
python: 3.6
|
||||
python:
|
||||
- "3.6"
|
||||
|
||||
|
||||
# Acceptance (Functional) tests
|
||||
- env:
|
||||
- CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,sparc-softmmu"
|
||||
- TEST_CMD="make check-acceptance"
|
||||
after_failure:
|
||||
- cat tests/results/latest/job.log
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-pil
|
||||
- python3-pip
|
||||
- python3.5-venv
|
||||
- tesseract-ocr
|
||||
- tesseract-ocr-eng
|
||||
|
||||
|
||||
# Using newer GCC with sanitizers
|
||||
- name: "GCC9 with sanitizers (softmmu)"
|
||||
addons:
|
||||
- addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
@@ -334,246 +323,56 @@ jobs:
|
||||
- CONFIG="--cc=gcc-9 --cxx=g++-9 --disable-pie --disable-linux-user"
|
||||
- TEST_CMD=""
|
||||
before_script:
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${CONFIG} --extra-cflags="-g3 -O0 -Wno-error=stringop-truncation -fsanitize=thread" --extra-ldflags="-fuse-ld=gold" || { cat config.log && exit 1; }
|
||||
- ./configure ${CONFIG} --extra-cflags="-g3 -O0 -Wno-error=stringop-truncation -fsanitize=thread -fuse-ld=gold" || { cat config.log && exit 1; }
|
||||
|
||||
|
||||
# Run check-tcg against linux-user
|
||||
- name: "GCC check-tcg (user)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--disable-system --enable-debug-tcg"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against linux-user (with plugins)
|
||||
# we skip sparc64-linux-user until it has been fixed somewhat
|
||||
# we skip cris-linux-user as it doesn't use the common run loop
|
||||
# we skip ppc64abi32-linux-user as it seems to have a broken libc
|
||||
- name: "GCC plugins check-tcg (user)"
|
||||
env:
|
||||
- CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user,ppc64abi32-linux-user"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- env:
|
||||
- CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against softmmu targets
|
||||
- name: "GCC check-tcg (some-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against softmmu targets (with plugins)
|
||||
- name: "GCC plugins check-tcg (some-softmmu)"
|
||||
env:
|
||||
- env:
|
||||
- CONFIG="--enable-plugins --enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
- name: "[aarch64] GCC check-tcg"
|
||||
arch: arm64
|
||||
dist: xenial
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libseccomp-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- TEST_CMD="make check check-tcg V=1"
|
||||
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- UNRELIABLE=true
|
||||
|
||||
- name: "[ppc64] GCC check-tcg"
|
||||
arch: ppc64le
|
||||
dist: xenial
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libseccomp-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- TEST_CMD="make check check-tcg V=1"
|
||||
- CONFIG="--disable-containers --target-list=ppc64-softmmu,ppc64le-linux-user"
|
||||
|
||||
- name: "[s390x] GCC check-tcg"
|
||||
arch: s390x
|
||||
dist: bionic
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libseccomp-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- TEST_CMD="make check check-tcg V=1"
|
||||
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user"
|
||||
- UNRELIABLE=true
|
||||
script:
|
||||
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
|
||||
- |
|
||||
if [ "$BUILD_RC" -eq 0 ] ; then
|
||||
mv pc-bios/s390-ccw/*.img pc-bios/ ;
|
||||
${TEST_CMD} ;
|
||||
else
|
||||
$(exit $BUILD_RC);
|
||||
fi
|
||||
|
||||
- name: "[s390x] GCC (other-softmmu)"
|
||||
arch: s390x
|
||||
dist: bionic
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libcap-ng-dev
|
||||
- libgnutls28-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- liblzo2-dev
|
||||
- libncurses-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libsdl2-dev
|
||||
- libsdl2-image-dev
|
||||
- libseccomp-dev
|
||||
- libsnappy-dev
|
||||
- libzstd-dev
|
||||
- nettle-dev
|
||||
- xfslibs-dev
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- CONFIG="--disable-containers --audio-drv-list=sdl --disable-user
|
||||
--target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
||||
|
||||
- name: "[s390x] GCC (user)"
|
||||
arch: s390x
|
||||
dist: bionic
|
||||
addons:
|
||||
apt_packages:
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
env:
|
||||
- CONFIG="--disable-containers --disable-system"
|
||||
|
||||
- name: "[s390x] Clang (disable-tcg)"
|
||||
arch: s390x
|
||||
dist: bionic
|
||||
compiler: clang
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libncurses5-dev
|
||||
- libnfs-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libseccomp-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
env:
|
||||
- TEST_CMD="make check-unit"
|
||||
- CONFIG="--disable-containers --disable-tcg --enable-kvm
|
||||
--disable-tools --host-cc=clang --cxx=clang++"
|
||||
- UNRELIABLE=true
|
||||
|
||||
# Release builds
|
||||
# The make-release script expect a QEMU version, so our tag must start with a 'v'.
|
||||
# This is the case when release candidate tags are created.
|
||||
- name: "Release tarball"
|
||||
if: tag IS present AND tag =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||
- if: tag IS present AND tag =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||
env:
|
||||
# We want to build from the release tarball
|
||||
- BUILD_DIR="release/build/dir" SRC_DIR="../../.."
|
||||
- BASE_CONFIG="--prefix=$PWD/dist"
|
||||
- CONFIG="--target-list=x86_64-softmmu,aarch64-softmmu,armeb-linux-user,ppc-linux-user"
|
||||
- TEST_CMD="make install -j${JOBS}"
|
||||
- TEST_CMD="make install -j3"
|
||||
- QEMU_VERSION="${TRAVIS_TAG:1}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
before_script:
|
||||
- command -v ccache && ccache --zero-stats
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
script:
|
||||
- make -C ${SRC_DIR} qemu-${QEMU_VERSION}.tar.bz2
|
||||
- ls -l ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2
|
||||
- tar -xf ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2 && cd qemu-${QEMU_VERSION}
|
||||
- mkdir -p release-build && cd release-build
|
||||
- ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
|
||||
- ./configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
|
||||
- make install
|
||||
allow_failures:
|
||||
- env: UNRELIABLE=true
|
||||
@@ -1,4 +0,0 @@
|
||||
source Kconfig.host
|
||||
source backends/Kconfig
|
||||
source accel/Kconfig
|
||||
source hw/Kconfig
|
||||
+5
-3
@@ -2,6 +2,9 @@
|
||||
# down to Kconfig. See also MINIKCONF_ARGS in the Makefile:
|
||||
# these two need to be kept in sync.
|
||||
|
||||
config KVM
|
||||
bool
|
||||
|
||||
config LINUX
|
||||
bool
|
||||
|
||||
@@ -22,11 +25,10 @@ config TPM
|
||||
|
||||
config VHOST_USER
|
||||
bool
|
||||
select VHOST
|
||||
|
||||
config VHOST_KERNEL
|
||||
config XEN
|
||||
bool
|
||||
select VHOST
|
||||
select FSDEV_9P if VIRTFS
|
||||
|
||||
config VIRTFS
|
||||
bool
|
||||
|
||||
+112
-515
File diff suppressed because it is too large.
Load diff
@@ -15,6 +15,9 @@ UNCHECKED_GOALS := %clean TAGS cscope ctags dist \
|
||||
help check-help print-% \
|
||||
docker docker-% vm-help vm-test vm-build-%
|
||||
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
||||
|
||||
# All following code might depend on configuration variables
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
# Put the all: rule here so that config-host.mak can contain dependencies.
|
||||
@@ -114,7 +117,6 @@ GENERATED_QAPI_FILES += qapi/qapi-builtin-visit.h qapi/qapi-builtin-visit.c
|
||||
GENERATED_QAPI_FILES += qapi/qapi-visit.h qapi/qapi-visit.c
|
||||
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-visit-%.h)
|
||||
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-visit-%.c)
|
||||
GENERATED_QAPI_FILES += qapi/qapi-init-commands.h qapi/qapi-init-commands.c
|
||||
GENERATED_QAPI_FILES += qapi/qapi-commands.h qapi/qapi-commands.c
|
||||
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-commands-%.h)
|
||||
GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-commands-%.c)
|
||||
@@ -125,28 +127,7 @@ GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-events-%.c)
|
||||
GENERATED_QAPI_FILES += qapi/qapi-introspect.c qapi/qapi-introspect.h
|
||||
GENERATED_QAPI_FILES += qapi/qapi-doc.texi
|
||||
|
||||
# The following list considers only the storage daemon main module. All other
|
||||
# modules are currently shared with the main schema, so we don't actually
|
||||
# generate additional files.
|
||||
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES = storage-daemon/qapi/qapi-commands.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-commands.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-emit-events.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-emit-events.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-events.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-events.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-init-commands.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-init-commands.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-introspect.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-introspect.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-types.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-types.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-visit.h
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-visit.c
|
||||
GENERATED_STORAGE_DAEMON_QAPI_FILES += storage-daemon/qapi/qapi-doc.texi
|
||||
|
||||
generated-files-y += $(GENERATED_QAPI_FILES)
|
||||
generated-files-y += $(GENERATED_STORAGE_DAEMON_QAPI_FILES)
|
||||
|
||||
generated-files-y += trace/generated-tcg-tracers.h
|
||||
|
||||
@@ -336,18 +317,17 @@ $(call set-vpath, $(SRC_PATH))
|
||||
LIBS+=-lz $(LIBS_TOOLS)
|
||||
|
||||
vhost-user-json-y =
|
||||
HELPERS-y = $(HELPERS)
|
||||
HELPERS-y =
|
||||
|
||||
HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) += qemu-bridge-helper$(EXESUF)
|
||||
HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = qemu-bridge-helper$(EXESUF)
|
||||
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_VIRGL)$(CONFIG_GBM)$(CONFIG_TOOLS),yyyy)
|
||||
ifdef CONFIG_LINUX
|
||||
ifdef CONFIG_VIRGL
|
||||
ifdef CONFIG_GBM
|
||||
HELPERS-y += vhost-user-gpu$(EXESUF)
|
||||
vhost-user-json-y += contrib/vhost-user-gpu/50-qemu-gpu.json
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SOFTMMU)$(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyyy)
|
||||
HELPERS-y += virtiofsd$(EXESUF)
|
||||
vhost-user-json-y += tools/virtiofsd/50-qemu-virtiofsd.json
|
||||
endif
|
||||
endif
|
||||
|
||||
# Sphinx does not allow building manuals into the same directory as
|
||||
@@ -362,23 +342,16 @@ MANUAL_BUILDDIR := docs
|
||||
endif
|
||||
|
||||
ifdef BUILD_DOCS
|
||||
DOCS+=$(MANUAL_BUILDDIR)/system/qemu.1
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-img.1
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-nbd.8
|
||||
DOCS+=$(MANUAL_BUILDDIR)/interop/qemu-ga.8
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/virtiofsd.1
|
||||
endif
|
||||
DOCS+=$(MANUAL_BUILDDIR)/system/qemu-block-drivers.7
|
||||
DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 $(MANUAL_BUILDDIR)/interop/qemu-ga.8
|
||||
DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
|
||||
DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7
|
||||
DOCS+=$(MANUAL_BUILDDIR)/system/qemu-cpu-models.7
|
||||
DOCS+=$(MANUAL_BUILDDIR)/index.html
|
||||
DOCS+=docs/qemu-block-drivers.7
|
||||
DOCS+=docs/qemu-cpu-models.7
|
||||
ifdef CONFIG_VIRTFS
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/virtfs-proxy-helper.1
|
||||
DOCS+=fsdev/virtfs-proxy-helper.1
|
||||
endif
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
DOCS+=$(MANUAL_BUILDDIR)/tools/qemu-trace-stap.1
|
||||
DOCS+=scripts/qemu-trace-stap.1
|
||||
endif
|
||||
else
|
||||
DOCS=
|
||||
@@ -404,8 +377,7 @@ endif
|
||||
# This has to be kept in sync with Kconfig.host.
|
||||
MINIKCONF_ARGS = \
|
||||
$(CONFIG_MINIKCONF_MODE) \
|
||||
$@ $*/config-devices.mak.d $< $(SRC_PATH)/Kconfig \
|
||||
CONFIG_TCG=$(CONFIG_TCG) \
|
||||
$@ $*/config-devices.mak.d $< $(MINIKCONF_INPUTS) \
|
||||
CONFIG_KVM=$(CONFIG_KVM) \
|
||||
CONFIG_SPICE=$(CONFIG_SPICE) \
|
||||
CONFIG_IVSHMEM=$(CONFIG_IVSHMEM) \
|
||||
@@ -414,16 +386,16 @@ MINIKCONF_ARGS = \
|
||||
CONFIG_OPENGL=$(CONFIG_OPENGL) \
|
||||
CONFIG_X11=$(CONFIG_X11) \
|
||||
CONFIG_VHOST_USER=$(CONFIG_VHOST_USER) \
|
||||
CONFIG_VHOST_KERNEL=$(CONFIG_VHOST_KERNEL) \
|
||||
CONFIG_VIRTFS=$(CONFIG_VIRTFS) \
|
||||
CONFIG_LINUX=$(CONFIG_LINUX) \
|
||||
CONFIG_PVRDMA=$(CONFIG_PVRDMA)
|
||||
|
||||
MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py
|
||||
MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig \
|
||||
$(wildcard $(SRC_PATH)/hw/*/Kconfig)
|
||||
MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \
|
||||
|
||||
$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(SRC_PATH)/Kconfig $(BUILD_DIR)/config-host.mak
|
||||
$(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) \
|
||||
> $@.tmp, "GEN", "$@.tmp")
|
||||
$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_INPUTS) $(BUILD_DIR)/config-host.mak
|
||||
$(call quiet-command, $(MINIKCONF) $(MINIKCONF_ARGS) > $@.tmp, "GEN", "$@.tmp")
|
||||
$(call quiet-command, if test -f $@; then \
|
||||
if cmp -s $@.old $@; then \
|
||||
mv $@.tmp $@; \
|
||||
@@ -458,7 +430,6 @@ dummy := $(call unnest-vars,, \
|
||||
elf2dmp-obj-y \
|
||||
ivshmem-client-obj-y \
|
||||
ivshmem-server-obj-y \
|
||||
virtiofsd-obj-y \
|
||||
rdmacm-mux-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
vhost-user-scsi-obj-y \
|
||||
@@ -468,13 +439,16 @@ dummy := $(call unnest-vars,, \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
storage-daemon-obj-y \
|
||||
storage-daemon-obj-m \
|
||||
crypto-obj-y \
|
||||
crypto-user-obj-y \
|
||||
qom-obj-y \
|
||||
io-obj-y \
|
||||
common-obj-y \
|
||||
common-obj-m \
|
||||
ui-obj-y \
|
||||
ui-obj-m \
|
||||
audio-obj-y \
|
||||
audio-obj-m \
|
||||
trace-obj-y)
|
||||
|
||||
include $(SRC_PATH)/tests/Makefile.include
|
||||
@@ -497,12 +471,11 @@ config-host.h-timestamp: config-host.mak
|
||||
qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
|
||||
|
||||
TARGET_DIRS_RULES := $(foreach t, all fuzz clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
|
||||
TARGET_DIRS_RULES := $(foreach t, all clean install, $(addsuffix /$(t), $(TARGET_DIRS)))
|
||||
|
||||
SOFTMMU_ALL_RULES=$(filter %-softmmu/all, $(TARGET_DIRS_RULES))
|
||||
$(SOFTMMU_ALL_RULES): $(authz-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(block-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(storage-daemon-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(chardev-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(crypto-obj-y)
|
||||
$(SOFTMMU_ALL_RULES): $(io-obj-y)
|
||||
@@ -511,29 +484,19 @@ ifdef DECOMPRESS_EDK2_BLOBS
|
||||
$(SOFTMMU_ALL_RULES): $(edk2-decompressed)
|
||||
endif
|
||||
|
||||
SOFTMMU_FUZZ_RULES=$(filter %-softmmu/fuzz, $(TARGET_DIRS_RULES))
|
||||
$(SOFTMMU_FUZZ_RULES): $(authz-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): $(block-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): $(chardev-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): $(crypto-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): $(io-obj-y)
|
||||
$(SOFTMMU_FUZZ_RULES): config-all-devices.mak
|
||||
$(SOFTMMU_FUZZ_RULES): $(edk2-decompressed)
|
||||
|
||||
.PHONY: $(TARGET_DIRS_RULES)
|
||||
# The $(TARGET_DIRS_RULES) are of the form SUBDIR/GOAL, so that
|
||||
# $(dir $@) yields the sub-directory, and $(notdir $@) yields the sub-goal
|
||||
$(TARGET_DIRS_RULES):
|
||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),)
|
||||
|
||||
# LIBFDT_lib="": avoid breaking existing trees with objects requiring -fPIC
|
||||
DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_lib=""
|
||||
DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_srcdir=$(SRC_PATH)/dtc/libfdt
|
||||
DTC_CFLAGS=$(CFLAGS) $(QEMU_CFLAGS)
|
||||
DTC_CPPFLAGS=-I$(SRC_PATH)/dtc/libfdt
|
||||
DTC_CPPFLAGS=-I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt
|
||||
|
||||
.PHONY: dtc/all
|
||||
dtc/all: .git-submodule-status dtc/libfdt
|
||||
$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt,)
|
||||
dtc/all: .git-submodule-status dtc/libfdt dtc/tests
|
||||
$(call quiet-command,$(MAKE) $(DTC_MAKE_ARGS) CPPFLAGS="$(DTC_CPPFLAGS)" CFLAGS="$(DTC_CFLAGS)" LDFLAGS="$(LDFLAGS)" ARFLAGS="$(ARFLAGS)" CC="$(CC)" AR="$(AR)" LD="$(LD)" $(SUBDIR_MAKEFLAGS) libfdt/libfdt.a,)
|
||||
|
||||
dtc/%: .git-submodule-status
|
||||
@mkdir -p $@
|
||||
@@ -560,12 +523,15 @@ slirp/all: .git-submodule-status
|
||||
BUILD_DIR="$(BUILD_DIR)/slirp" \
|
||||
PKG_CONFIG="$(PKG_CONFIG)" \
|
||||
CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" \
|
||||
CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(QEMU_LDFLAGS)")
|
||||
CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)")
|
||||
|
||||
# Compatibility gunk to keep make working across the rename of targets
|
||||
# for recursion, to be removed some time after 4.1.
|
||||
subdir-dtc: dtc/all
|
||||
subdir-capstone: capstone/all
|
||||
subdir-slirp: slirp/all
|
||||
|
||||
$(filter %/all, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
|
||||
$(qom-obj-y)
|
||||
|
||||
$(filter %/fuzz, $(TARGET_DIRS_RULES)): libqemuutil.a $(common-obj-y) \
|
||||
$(qom-obj-y) $(crypto-user-obj-$(CONFIG_USER_ONLY))
|
||||
|
||||
ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
|
||||
@@ -601,7 +567,6 @@ qemu-img.o: qemu-img-cmds.h
|
||||
qemu-img$(EXESUF): qemu-img.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-nbd$(EXESUF): qemu-nbd.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-io$(EXESUF): qemu-io.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
qemu-storage-daemon$(EXESUF): qemu-storage-daemon.o $(authz-obj-y) $(block-obj-y) $(crypto-obj-y) $(chardev-obj-y) $(io-obj-y) $(qom-obj-y) $(storage-daemon-obj-y) $(COMMON_LDADDS)
|
||||
|
||||
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
|
||||
|
||||
@@ -610,6 +575,7 @@ qemu-keymap$(EXESUF): qemu-keymap.o ui/input-keymap.o $(COMMON_LDADDS)
|
||||
qemu-edid$(EXESUF): qemu-edid.o hw/display/edid-generate.o $(COMMON_LDADDS)
|
||||
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
|
||||
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
|
||||
|
||||
scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(authz-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
ifdef CONFIG_MPATH
|
||||
@@ -644,7 +610,6 @@ $(SRC_PATH)/scripts/qapi-gen.py
|
||||
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h \
|
||||
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h \
|
||||
qga/qapi-generated/qga-qapi-commands.h qga/qapi-generated/qga-qapi-commands.c \
|
||||
qga/qapi-generated/qga-qapi-init-commands.h qga/qapi-generated/qga-qapi-init-commands.c \
|
||||
qga/qapi-generated/qga-qapi-doc.texi: \
|
||||
qga/qapi-generated/qapi-gen-timestamp ;
|
||||
qga/qapi-generated/qapi-gen-timestamp: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py)
|
||||
@@ -663,18 +628,7 @@ qapi-gen-timestamp: $(qapi-modules) $(qapi-py)
|
||||
"GEN","$(@:%-timestamp=%)")
|
||||
@>$@
|
||||
|
||||
qapi-modules-storage-daemon = \
|
||||
$(SRC_PATH)/storage-daemon/qapi/qapi-schema.json \
|
||||
$(QAPI_MODULES_STORAGE_DAEMON:%=$(SRC_PATH)/qapi/%.json)
|
||||
|
||||
$(GENERATED_STORAGE_DAEMON_QAPI_FILES): storage-daemon/qapi/qapi-gen-timestamp ;
|
||||
storage-daemon/qapi/qapi-gen-timestamp: $(qapi-modules-storage-daemon) $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
|
||||
-o "storage-daemon/qapi" $<, \
|
||||
"GEN","$(@:%-timestamp=%)")
|
||||
@>$@
|
||||
|
||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qapi-commands.h qga-qapi-init-commands.h)
|
||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qapi-commands.h)
|
||||
$(qga-obj-y): $(QGALIB_GEN)
|
||||
|
||||
qemu-ga$(EXESUF): $(qga-obj-y) $(COMMON_LDADDS)
|
||||
@@ -720,13 +674,7 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
|
||||
rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
|
||||
# relies on Linux-specific syscalls
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
virtiofsd$(EXESUF): $(virtiofsd-obj-y) libvhost-user.a $(COMMON_LDADDS)
|
||||
$(call LINK, $^)
|
||||
endif
|
||||
|
||||
vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a
|
||||
vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a
|
||||
$(call LINK, $^)
|
||||
|
||||
ifdef CONFIG_VHOST_USER_INPUT
|
||||
@@ -772,10 +720,8 @@ clean: recurse-clean
|
||||
rm -f trace/generated-tracers-dtrace.h*
|
||||
rm -f $(foreach f,$(generated-files-y),$(f) $(f)-timestamp)
|
||||
rm -f qapi-gen-timestamp
|
||||
rm -f storage-daemon/qapi/qapi-gen-timestamp
|
||||
rm -rf qga/qapi-generated
|
||||
rm -f config-all-devices.mak
|
||||
rm -f $(SUBDIR_DEVICES_MAK)
|
||||
|
||||
VERSION ?= $(shell cat VERSION)
|
||||
|
||||
@@ -790,12 +736,16 @@ rm -f $(MANUAL_BUILDDIR)/$1/objects.inv $(MANUAL_BUILDDIR)/$1/searchindex.js $(M
|
||||
endef
|
||||
|
||||
distclean: clean
|
||||
rm -f config-host.mak config-host.h* $(DOCS)
|
||||
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi qemu-monitor-info.texi
|
||||
rm -f tests/tcg/config-*.mak
|
||||
rm -f config-all-devices.mak config-all-disas.mak config.status
|
||||
rm -f $(SUBDIR_DEVICES_MAK)
|
||||
rm -f po/*.mo tests/qemu-iotests/common.env
|
||||
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
||||
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps
|
||||
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
|
||||
rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
|
||||
rm -f qemu-doc.vr qemu-doc.txt
|
||||
rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
|
||||
rm -f config.log
|
||||
rm -f linux-headers/asm
|
||||
@@ -805,17 +755,17 @@ distclean: clean
|
||||
rm -f docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
|
||||
rm -f docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
|
||||
rm -f docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html
|
||||
rm -f docs/qemu-block-drivers.7
|
||||
rm -f docs/qemu-cpu-models.7
|
||||
rm -rf .doctrees
|
||||
$(call clean-manual,devel)
|
||||
$(call clean-manual,interop)
|
||||
$(call clean-manual,specs)
|
||||
$(call clean-manual,system)
|
||||
$(call clean-manual,tools)
|
||||
$(call clean-manual,user)
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
rm -Rf .sdk
|
||||
if test -f dtc/version_gen.h; then $(MAKE) $(DTC_MAKE_ARGS) clean; fi
|
||||
|
||||
KEYMAPS=da en-gb et fr fr-ch is lt no pt-br sv \
|
||||
ar de en-us fi fr-be hr it lv nl pl ru th \
|
||||
@@ -826,7 +776,7 @@ ifdef INSTALL_BLOBS
|
||||
BLOBS=bios.bin bios-256k.bin bios-microvm.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
|
||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \
|
||||
vgabios-ramfb.bin vgabios-bochs-display.bin vgabios-ati.bin \
|
||||
openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
|
||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
|
||||
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
|
||||
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
|
||||
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
|
||||
@@ -842,7 +792,7 @@ u-boot.e500 u-boot-sam460-20100605.bin \
|
||||
qemu_vga.ndrv \
|
||||
edk2-licenses.txt \
|
||||
hppa-firmware.img \
|
||||
opensbi-riscv32-sifive_u-fw_jump.bin opensbi-riscv32-virt-fw_jump.bin \
|
||||
opensbi-riscv32-virt-fw_jump.bin \
|
||||
opensbi-riscv64-sifive_u-fw_jump.bin opensbi-riscv64-virt-fw_jump.bin
|
||||
|
||||
|
||||
@@ -867,45 +817,38 @@ endef
|
||||
install-sphinxdocs: sphinxdocs
|
||||
$(call install-manual,interop)
|
||||
$(call install-manual,specs)
|
||||
$(call install-manual,system)
|
||||
$(call install-manual,tools)
|
||||
$(call install-manual,user)
|
||||
|
||||
install-doc: $(DOCS) install-sphinxdocs
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/index.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/interop"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)/interop"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)/interop"
|
||||
$(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
ifdef CONFIG_POSIX
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/interop/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/system/qemu-cpu-models.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/qemu-block-drivers.7 "$(DESTDIR)$(mandir)/man7"
|
||||
$(INSTALL_DATA) docs/qemu-cpu-models.7 "$(DESTDIR)$(mandir)/man7"
|
||||
ifeq ($(CONFIG_TOOLS),y)
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
||||
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
|
||||
endif
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/qemu-trace-stap.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) scripts/qemu-trace-stap.1 "$(DESTDIR)$(mandir)/man1"
|
||||
endif
|
||||
ifneq (,$(findstring qemu-ga,$(TOOLS)))
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/interop/qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/interop"
|
||||
$(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)/interop"
|
||||
$(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)/interop"
|
||||
$(INSTALL_DATA) docs/interop/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-ga-ref.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) docs/interop/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7"
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_VIRTFS
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
|
||||
endif
|
||||
ifeq ($(CONFIG_LINUX)$(CONFIG_SECCOMP)$(CONFIG_LIBCAP_NG),yyy)
|
||||
$(INSTALL_DATA) $(MANUAL_BUILDDIR)/tools/virtiofsd.1 "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
|
||||
endif
|
||||
|
||||
install-datadir:
|
||||
@@ -1060,32 +1003,16 @@ docs/version.texi: $(SRC_PATH)/VERSION config-host.mak
|
||||
# and handles "don't rebuild things unless necessary" itself.
|
||||
# The '.doctrees' files are cached information to speed this up.
|
||||
.PHONY: sphinxdocs
|
||||
sphinxdocs: $(MANUAL_BUILDDIR)/devel/index.html \
|
||||
$(MANUAL_BUILDDIR)/interop/index.html \
|
||||
$(MANUAL_BUILDDIR)/specs/index.html \
|
||||
$(MANUAL_BUILDDIR)/system/index.html \
|
||||
$(MANUAL_BUILDDIR)/tools/index.html \
|
||||
$(MANUAL_BUILDDIR)/user/index.html
|
||||
sphinxdocs: $(MANUAL_BUILDDIR)/devel/index.html $(MANUAL_BUILDDIR)/interop/index.html $(MANUAL_BUILDDIR)/specs/index.html
|
||||
|
||||
# Canned command to build a single manual
|
||||
# Arguments: $1 = manual name, $2 = Sphinx builder ('html' or 'man')
|
||||
# Note the use of different doctree for each (manual, builder) tuple;
|
||||
# this works around Sphinx not handling parallel invocation on
|
||||
# a single doctree: https://github.com/sphinx-doc/sphinx/issues/2946
|
||||
build-manual = $(call quiet-command,CONFDIR="$(qemu_confdir)" $(SPHINX_BUILD) $(if $(V),,-q) $(SPHINX_WERROR) -b $2 -D version=$(VERSION) -D release="$(FULL_VERSION)" -d .doctrees/$1-$2 $(SRC_PATH)/docs/$1 $(MANUAL_BUILDDIR)/$1 ,"SPHINX","$(MANUAL_BUILDDIR)/$1")
|
||||
build-manual = $(call quiet-command,CONFDIR="$(qemu_confdir)" sphinx-build $(if $(V),,-q) -W -n -b $2 -D version=$(VERSION) -D release="$(FULL_VERSION)" -d .doctrees/$1-$2 $(SRC_PATH)/docs/$1 $(MANUAL_BUILDDIR)/$1 ,"SPHINX","$(MANUAL_BUILDDIR)/$1")
|
||||
# We assume all RST files in the manual's directory are used in it
|
||||
manual-deps = $(wildcard $(SRC_PATH)/docs/$1/*.rst $(SRC_PATH)/docs/$1/*/*.rst) \
|
||||
$(SRC_PATH)/docs/defs.rst.inc \
|
||||
$(SRC_PATH)/docs/$1/conf.py $(SRC_PATH)/docs/conf.py \
|
||||
$(SRC_PATH)/docs/sphinx/*.py
|
||||
# Macro to write out the rule and dependencies for building manpages
|
||||
# Usage: $(call define-manpage-rule,manualname,manpage1 manpage2...[,extradeps])
|
||||
# 'extradeps' is optional, and specifies extra files (eg .hx files) that
|
||||
# the manual page depends on.
|
||||
define define-manpage-rule
|
||||
$(call atomic,$(foreach manpage,$2,$(MANUAL_BUILDDIR)/$1/$(manpage)),$(call manual-deps,$1) $3)
|
||||
$(call build-manual,$1,man)
|
||||
endef
|
||||
manual-deps = $(wildcard $(SRC_PATH)/docs/$1/*.rst) $(SRC_PATH)/docs/$1/conf.py $(SRC_PATH)/docs/conf.py
|
||||
|
||||
$(MANUAL_BUILDDIR)/devel/index.html: $(call manual-deps,devel)
|
||||
$(call build-manual,devel,html)
|
||||
@@ -1096,28 +1023,20 @@ $(MANUAL_BUILDDIR)/interop/index.html: $(call manual-deps,interop)
|
||||
$(MANUAL_BUILDDIR)/specs/index.html: $(call manual-deps,specs)
|
||||
$(call build-manual,specs,html)
|
||||
|
||||
$(MANUAL_BUILDDIR)/system/index.html: $(call manual-deps,system) $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/qemu-options.hx
|
||||
$(call build-manual,system,html)
|
||||
$(MANUAL_BUILDDIR)/interop/qemu-ga.8: $(call manual-deps,interop)
|
||||
$(call build-manual,interop,man)
|
||||
|
||||
$(MANUAL_BUILDDIR)/tools/index.html: $(call manual-deps,tools) $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/docs/qemu-option-trace.rst.inc
|
||||
$(call build-manual,tools,html)
|
||||
qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
$(MANUAL_BUILDDIR)/user/index.html: $(call manual-deps,user)
|
||||
$(call build-manual,user,html)
|
||||
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
$(call define-manpage-rule,interop,qemu-ga.8)
|
||||
qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
$(call define-manpage-rule,system,qemu.1 qemu-block-drivers.7 qemu-cpu-models.7)
|
||||
|
||||
$(call define-manpage-rule,tools,\
|
||||
qemu-img.1 qemu-nbd.8 qemu-trace-stap.1\
|
||||
virtiofsd.1 virtfs-proxy-helper.1,\
|
||||
$(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/docs/qemu-option-trace.rst.inc)
|
||||
|
||||
$(MANUAL_BUILDDIR)/index.html: $(SRC_PATH)/docs/index.html.in qemu-version.h
|
||||
@mkdir -p "$(MANUAL_BUILDDIR)"
|
||||
$(call quiet-command, sed "s|@@VERSION@@|${VERSION}|g" $< >$@, \
|
||||
"GEN","$@")
|
||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||
|
||||
docs/interop/qemu-qmp-qapi.texi: qapi/qapi-doc.texi
|
||||
@cp -p $< $@
|
||||
@@ -1125,10 +1044,26 @@ docs/interop/qemu-qmp-qapi.texi: qapi/qapi-doc.texi
|
||||
docs/interop/qemu-ga-qapi.texi: qga/qapi-generated/qga-qapi-doc.texi
|
||||
@cp -p $< $@
|
||||
|
||||
html: docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html sphinxdocs
|
||||
info: docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info
|
||||
pdf: docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
|
||||
txt: docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
|
||||
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
|
||||
qemu.1: qemu-option-trace.texi
|
||||
qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi
|
||||
fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
|
||||
qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
|
||||
docs/qemu-block-drivers.7: docs/qemu-block-drivers.texi
|
||||
docs/qemu-cpu-models.7: docs/qemu-cpu-models.texi
|
||||
scripts/qemu-trace-stap.1: scripts/qemu-trace-stap.texi
|
||||
|
||||
html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html sphinxdocs
|
||||
info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info
|
||||
pdf: qemu-doc.pdf docs/interop/qemu-qmp-ref.pdf docs/interop/qemu-ga-ref.pdf
|
||||
txt: qemu-doc.txt docs/interop/qemu-qmp-ref.txt docs/interop/qemu-ga-ref.txt
|
||||
|
||||
qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \
|
||||
qemu-img.texi qemu-nbd.texi qemu-options.texi \
|
||||
qemu-tech.texi qemu-option-trace.texi \
|
||||
qemu-deprecated.texi qemu-monitor.texi qemu-img-cmds.texi \
|
||||
qemu-monitor-info.texi docs/qemu-block-drivers.texi \
|
||||
docs/qemu-cpu-models.texi docs/security.texi
|
||||
|
||||
docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \
|
||||
docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \
|
||||
@@ -1231,66 +1166,50 @@ endif
|
||||
include $(SRC_PATH)/tests/docker/Makefile.include
|
||||
include $(SRC_PATH)/tests/vm/Makefile.include
|
||||
|
||||
print-help-run = printf " %-30s - %s\\n" "$1" "$2"
|
||||
print-help = $(quiet-@)$(call print-help-run,$1,$2)
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo 'Generic targets:'
|
||||
$(call print-help,all,Build all)
|
||||
@echo ' all - Build all'
|
||||
ifdef CONFIG_MODULES
|
||||
$(call print-help,modules,Build all modules)
|
||||
@echo ' modules - Build all modules'
|
||||
endif
|
||||
$(call print-help,dir/file.o,Build specified target only)
|
||||
$(call print-help,install,Install QEMU, documentation and tools)
|
||||
$(call print-help,ctags/TAGS,Generate tags file for editors)
|
||||
$(call print-help,cscope,Generate cscope index)
|
||||
@echo ' dir/file.o - Build specified target only'
|
||||
@echo ' install - Install QEMU, documentation and tools'
|
||||
@echo ' ctags/TAGS - Generate tags file for editors'
|
||||
@echo ' cscope - Generate cscope index'
|
||||
@echo ''
|
||||
@$(if $(TARGET_DIRS), \
|
||||
echo 'Architecture specific targets:'; \
|
||||
$(foreach t, $(TARGET_DIRS), \
|
||||
$(call print-help-run,$(t)/all,Build for $(t)); \
|
||||
$(if $(CONFIG_FUZZ), \
|
||||
$(if $(findstring softmmu,$(t)), \
|
||||
$(call print-help-run,$(t)/fuzz,Build fuzzer for $(t)); \
|
||||
))) \
|
||||
echo '')
|
||||
@$(if $(HELPERS-y), \
|
||||
echo 'Helper targets:'; \
|
||||
$(foreach t, $(HELPERS-y), \
|
||||
$(call print-help-run,$(t),Build $(shell basename $(t)));) \
|
||||
echo '')
|
||||
@$(if $(TOOLS), \
|
||||
echo 'Tools targets:'; \
|
||||
$(foreach t, $(TOOLS), \
|
||||
$(call print-help-run,$(t),Build $(shell basename $(t)) tool);) \
|
||||
printf " %-30s - Build for %s\\n" $(t)/all $(t);) \
|
||||
echo '')
|
||||
@echo 'Cleaning targets:'
|
||||
$(call print-help,clean,Remove most generated files but keep the config)
|
||||
@echo ' clean - Remove most generated files but keep the config'
|
||||
ifdef CONFIG_GCOV
|
||||
$(call print-help,clean-coverage,Remove coverage files)
|
||||
@echo ' clean-coverage - Remove coverage files'
|
||||
endif
|
||||
$(call print-help,distclean,Remove all generated files)
|
||||
$(call print-help,dist,Build a distributable tarball)
|
||||
@echo ' distclean - Remove all generated files'
|
||||
@echo ' dist - Build a distributable tarball'
|
||||
@echo ''
|
||||
@echo 'Test targets:'
|
||||
$(call print-help,check,Run all tests (check-help for details))
|
||||
$(call print-help,docker,Help about targets running tests inside containers)
|
||||
$(call print-help,vm-help,Help about targets running tests inside VM)
|
||||
@echo ' check - Run all tests (check-help for details)'
|
||||
@echo ' docker - Help about targets running tests inside containers'
|
||||
@echo ' vm-help - Help about targets running tests inside VM'
|
||||
@echo ''
|
||||
@echo 'Documentation targets:'
|
||||
$(call print-help,html info pdf txt,Build documentation in specified format)
|
||||
@echo ' html info pdf txt'
|
||||
@echo ' - Build documentation in specified format'
|
||||
ifdef CONFIG_GCOV
|
||||
$(call print-help,coverage-report,Create code coverage report)
|
||||
@echo ' coverage-report - Create code coverage report'
|
||||
endif
|
||||
@echo ''
|
||||
ifdef CONFIG_WIN32
|
||||
@echo 'Windows targets:'
|
||||
$(call print-help,installer,Build NSIS-based installer for QEMU)
|
||||
@echo ' installer - Build NSIS-based installer for QEMU'
|
||||
ifdef QEMU_GA_MSI_ENABLED
|
||||
$(call print-help,msi,Build MSI-based installer for qemu-ga)
|
||||
@echo ' msi - Build MSI-based installer for qemu-ga'
|
||||
endif
|
||||
@echo ''
|
||||
endif
|
||||
$(call print-help,$(MAKE) [targets],(quiet build, default))
|
||||
$(call print-help,$(MAKE) V=1 [targets],(verbose build))
|
||||
@echo ' $(MAKE) [targets] (quiet build, default)'
|
||||
@echo ' $(MAKE) V=1 [targets] (verbose build)'
|
||||
+32
-32
@@ -1,39 +1,41 @@
|
||||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
stub-obj-y = stubs/
|
||||
util-obj-y = crypto/ util/ qobject/ qapi/
|
||||
qom-obj-y = qom/
|
||||
|
||||
#######################################################################
|
||||
# code used by both qemu system emulation and qemu-img
|
||||
|
||||
ifeq ($(call lor,$(CONFIG_SOFTMMU),$(CONFIG_TOOLS)),y)
|
||||
stub-obj-y = stubs/ util/ crypto/
|
||||
util-obj-y = util/ qobject/ qapi/
|
||||
|
||||
chardev-obj-y = chardev/
|
||||
|
||||
#######################################################################
|
||||
# authz-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
authz-obj-y = authz/
|
||||
|
||||
block-obj-y = block/ nbd/ scsi/
|
||||
#######################################################################
|
||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
block-obj-y = nbd/
|
||||
block-obj-y += block.o blockjob.o job.o
|
||||
block-obj-y += block/ scsi/
|
||||
block-obj-y += qemu-io-cmds.o
|
||||
block-obj-$(CONFIG_REPLICATION) += replication.o
|
||||
|
||||
block-obj-m = block/
|
||||
|
||||
#######################################################################
|
||||
# crypto-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
crypto-obj-y = crypto/
|
||||
|
||||
io-obj-y = io/
|
||||
|
||||
endif # CONFIG_SOFTMMU or CONFIG_TOOLS
|
||||
crypto-user-obj-y = crypto/
|
||||
|
||||
#######################################################################
|
||||
# storage-daemon-obj-y is code used by qemu-storage-daemon (these objects are
|
||||
# used for system emulation, too, but specified separately there)
|
||||
# qom-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
storage-daemon-obj-y = block/ monitor/ qapi/ qom/ storage-daemon/
|
||||
storage-daemon-obj-y += blockdev.o blockdev-nbd.o iothread.o job-qmp.o
|
||||
storage-daemon-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
storage-daemon-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
qom-obj-y = qom/
|
||||
|
||||
#######################################################################
|
||||
# io-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
io-obj-y = io/
|
||||
|
||||
######################################################################
|
||||
# Target independent part of system emulation. The long term path is to
|
||||
@@ -47,31 +49,32 @@ common-obj-y += dump/
|
||||
common-obj-y += job-qmp.o
|
||||
common-obj-y += monitor/
|
||||
common-obj-y += net/
|
||||
common-obj-y += qdev-monitor.o
|
||||
common-obj-y += qdev-monitor.o device-hotplug.o
|
||||
common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
|
||||
common-obj-$(CONFIG_LINUX) += fsdev/
|
||||
|
||||
common-obj-y += accel/
|
||||
common-obj-y += migration/
|
||||
|
||||
common-obj-y += audio/
|
||||
common-obj-m += audio/
|
||||
common-obj-y += hw/
|
||||
common-obj-m += hw/
|
||||
|
||||
common-obj-y += replay/
|
||||
|
||||
common-obj-y += ui/
|
||||
common-obj-m += ui/
|
||||
common-obj-y += bt-host.o bt-vhci.o
|
||||
bt-host.o-cflags := $(BLUEZ_CFLAGS)
|
||||
|
||||
common-obj-y += dma-helpers.o
|
||||
common-obj-y += vl.o
|
||||
vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS)
|
||||
common-obj-$(CONFIG_TPM) += tpm.o
|
||||
|
||||
common-obj-y += backends/
|
||||
common-obj-y += chardev/
|
||||
common-obj-m += chardev/
|
||||
|
||||
common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
|
||||
qemu-seccomp.o-cflags := $(SECCOMP_CFLAGS)
|
||||
@@ -79,9 +82,11 @@ qemu-seccomp.o-libs := $(SECCOMP_LIBS)
|
||||
|
||||
common-obj-$(CONFIG_FDT) += device_tree.o
|
||||
|
||||
common-obj-y += qapi/
|
||||
######################################################################
|
||||
# qapi
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
common-obj-y += qapi/
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
# Target-independent parts used in system and user emulation
|
||||
@@ -120,14 +125,11 @@ vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
||||
rdmacm-mux-obj-y = contrib/rdmacm-mux/
|
||||
vhost-user-input-obj-y = contrib/vhost-user-input/
|
||||
vhost-user-gpu-obj-y = contrib/vhost-user-gpu/
|
||||
virtiofsd-obj-y = tools/virtiofsd/
|
||||
|
||||
######################################################################
|
||||
trace-events-subdirs =
|
||||
trace-events-subdirs += accel/kvm
|
||||
trace-events-subdirs += accel/tcg
|
||||
trace-events-subdirs += backends
|
||||
trace-events-subdirs += backends/tpm
|
||||
trace-events-subdirs += crypto
|
||||
trace-events-subdirs += monitor
|
||||
ifeq ($(CONFIG_USER_ONLY),y)
|
||||
@@ -141,8 +143,8 @@ trace-events-subdirs += nbd
|
||||
trace-events-subdirs += scsi
|
||||
endif
|
||||
ifeq ($(CONFIG_SOFTMMU),y)
|
||||
trace-events-subdirs += audio
|
||||
trace-events-subdirs += chardev
|
||||
trace-events-subdirs += audio
|
||||
trace-events-subdirs += hw/9pfs
|
||||
trace-events-subdirs += hw/acpi
|
||||
trace-events-subdirs += hw/alpha
|
||||
@@ -153,7 +155,6 @@ trace-events-subdirs += hw/block/dataplane
|
||||
trace-events-subdirs += hw/char
|
||||
trace-events-subdirs += hw/dma
|
||||
trace-events-subdirs += hw/hppa
|
||||
trace-events-subdirs += hw/hyperv
|
||||
trace-events-subdirs += hw/i2c
|
||||
trace-events-subdirs += hw/i386
|
||||
trace-events-subdirs += hw/i386/xen
|
||||
@@ -178,7 +179,6 @@ trace-events-subdirs += hw/scsi
|
||||
trace-events-subdirs += hw/sd
|
||||
trace-events-subdirs += hw/sparc
|
||||
trace-events-subdirs += hw/sparc64
|
||||
trace-events-subdirs += hw/ssi
|
||||
trace-events-subdirs += hw/timer
|
||||
trace-events-subdirs += hw/tpm
|
||||
trace-events-subdirs += hw/usb
|
||||
@@ -192,7 +192,6 @@ trace-events-subdirs += migration
|
||||
trace-events-subdirs += net
|
||||
trace-events-subdirs += ui
|
||||
endif
|
||||
trace-events-subdirs += hw/core
|
||||
trace-events-subdirs += hw/display
|
||||
trace-events-subdirs += qapi
|
||||
trace-events-subdirs += qom
|
||||
@@ -205,6 +204,7 @@ trace-events-subdirs += target/riscv
|
||||
trace-events-subdirs += target/s390x
|
||||
trace-events-subdirs += target/sparc
|
||||
trace-events-subdirs += util
|
||||
trace-events-subdirs += hw/core
|
||||
|
||||
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
|
||||
|
||||
|
||||
+9
-36
@@ -12,7 +12,7 @@ endif
|
||||
|
||||
$(call set-vpath, $(SRC_PATH):$(BUILD_DIR))
|
||||
ifdef CONFIG_LINUX
|
||||
QEMU_CFLAGS += -isystem ../linux-headers
|
||||
QEMU_CFLAGS += -I../linux-headers
|
||||
endif
|
||||
QEMU_CFLAGS += -iquote .. -iquote $(SRC_PATH)/target/$(TARGET_BASE_ARCH) -DNEED_CPU_H
|
||||
|
||||
@@ -128,8 +128,7 @@ ifdef CONFIG_LINUX_USER
|
||||
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
|
||||
-I$(SRC_PATH)/linux-user/host/$(ARCH) \
|
||||
-I$(SRC_PATH)/linux-user \
|
||||
-Ilinux-user/$(TARGET_ABI_DIR)
|
||||
-I$(SRC_PATH)/linux-user
|
||||
|
||||
obj-y += linux-user/
|
||||
obj-y += gdbstub.o thunk.o
|
||||
@@ -152,12 +151,14 @@ endif #CONFIG_BSD_USER
|
||||
#########################################################
|
||||
# System emulator target
|
||||
ifdef CONFIG_SOFTMMU
|
||||
obj-y += softmmu/
|
||||
obj-y += gdbstub.o
|
||||
obj-y += arch_init.o cpus.o gdbstub.o balloon.o ioport.o
|
||||
obj-y += qtest.o
|
||||
obj-y += dump/
|
||||
obj-y += hw/
|
||||
obj-y += monitor/
|
||||
obj-y += qapi/
|
||||
obj-y += memory.o
|
||||
obj-y += memory_mapping.o
|
||||
obj-y += migration/ram.o
|
||||
LIBS := $(libs_softmmu) $(LIBS)
|
||||
|
||||
@@ -176,20 +177,6 @@ endif # CONFIG_SOFTMMU
|
||||
dummy := $(call unnest-vars,,obj-y)
|
||||
all-obj-y := $(obj-y)
|
||||
|
||||
#
|
||||
# common-obj-m has some crap here, probably as side effect from
|
||||
# unnest-vars recursing into target directories to fill obj-y and not
|
||||
# properly handling the -m case.
|
||||
#
|
||||
# Clear common-obj-m as workaround. Fixes suspious dependency errors
|
||||
# when building devices as modules. A bit hackish, but should be ok
|
||||
# as long as we do not have any target-specific modules.
|
||||
#
|
||||
# The meson-based build system currently in development doesn't need
|
||||
# unnest-vars and will obsolete this workaround.
|
||||
#
|
||||
common-obj-m :=
|
||||
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
dummy := $(call unnest-vars,.., \
|
||||
authz-obj-y \
|
||||
@@ -197,6 +184,7 @@ dummy := $(call unnest-vars,.., \
|
||||
block-obj-m \
|
||||
chardev-obj-y \
|
||||
crypto-obj-y \
|
||||
crypto-user-obj-y \
|
||||
qom-obj-y \
|
||||
io-obj-y \
|
||||
common-obj-y \
|
||||
@@ -205,6 +193,7 @@ all-obj-y += $(common-obj-y)
|
||||
all-obj-y += $(qom-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(authz-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y)
|
||||
all-obj-$(CONFIG_USER_ONLY) += $(crypto-user-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
|
||||
|
||||
@@ -215,7 +204,7 @@ endif
|
||||
COMMON_LDADDS = ../libqemuutil.a
|
||||
|
||||
# build either PROG or PROGW
|
||||
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS) $(softmmu-main-y)
|
||||
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
|
||||
$(call LINK, $(filter-out %.mak, $^))
|
||||
ifdef CONFIG_DARWIN
|
||||
$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@")
|
||||
@@ -240,22 +229,6 @@ ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
rm -f *.stp
|
||||
endif
|
||||
|
||||
ifdef CONFIG_FUZZ
|
||||
include $(SRC_PATH)/tests/qtest/fuzz/Makefile.include
|
||||
include $(SRC_PATH)/tests/qtest/Makefile.include
|
||||
|
||||
fuzz: fuzz-vars
|
||||
fuzz-vars: QEMU_CFLAGS := $(FUZZ_CFLAGS) $(QEMU_CFLAGS)
|
||||
fuzz-vars: QEMU_LDFLAGS := $(FUZZ_LDFLAGS) $(QEMU_LDFLAGS)
|
||||
fuzz-vars: $(QEMU_PROG_FUZZ)
|
||||
dummy := $(call unnest-vars,, fuzz-obj-y)
|
||||
|
||||
|
||||
$(QEMU_PROG_FUZZ): config-devices.mak $(all-obj-y) $(COMMON_LDADDS) $(fuzz-obj-y)
|
||||
$(call LINK, $(filter-out %.mak, $^))
|
||||
|
||||
endif
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
$(call install-prog,$(PROGS),$(DESTDIR)$(bindir))
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
config TCG
|
||||
bool
|
||||
|
||||
config KVM
|
||||
bool
|
||||
|
||||
config XEN
|
||||
bool
|
||||
select FSDEV_9P if VIRTFS
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
common-obj-$(CONFIG_SOFTMMU) += accel.o
|
||||
obj-$(CONFIG_SOFTMMU) += accel.o
|
||||
obj-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_POSIX)) += qtest.o
|
||||
obj-$(CONFIG_KVM) += kvm/
|
||||
obj-$(CONFIG_TCG) += tcg/
|
||||
obj-$(CONFIG_XEN) += xen/
|
||||
obj-y += stubs/
|
||||
+67
-5
@@ -28,7 +28,13 @@
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
static const TypeInfo accel_type = {
|
||||
.name = TYPE_ACCEL,
|
||||
@@ -38,7 +44,7 @@ static const TypeInfo accel_type = {
|
||||
};
|
||||
|
||||
/* Lookup AccelClass from opt_name. Returns NULL if not found */
|
||||
AccelClass *accel_find(const char *opt_name)
|
||||
static AccelClass *accel_find(const char *opt_name)
|
||||
{
|
||||
char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
|
||||
AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name));
|
||||
@@ -46,9 +52,11 @@ AccelClass *accel_find(const char *opt_name)
|
||||
return ac;
|
||||
}
|
||||
|
||||
int accel_init_machine(AccelState *accel, MachineState *ms)
|
||||
static int accel_init_machine(AccelClass *acc, MachineState *ms)
|
||||
{
|
||||
AccelClass *acc = ACCEL_GET_CLASS(accel);
|
||||
ObjectClass *oc = OBJECT_CLASS(acc);
|
||||
const char *cname = object_class_get_name(oc);
|
||||
AccelState *accel = ACCEL(object_new(cname));
|
||||
int ret;
|
||||
ms->accelerator = accel;
|
||||
*(acc->allowed) = true;
|
||||
@@ -63,9 +71,63 @@ int accel_init_machine(AccelState *accel, MachineState *ms)
|
||||
return ret;
|
||||
}
|
||||
|
||||
AccelState *current_accel(void)
|
||||
void configure_accelerator(MachineState *ms, const char *progname)
|
||||
{
|
||||
return current_machine->accelerator;
|
||||
const char *accel;
|
||||
char **accel_list, **tmp;
|
||||
int ret;
|
||||
bool accel_initialised = false;
|
||||
bool init_failed = false;
|
||||
AccelClass *acc = NULL;
|
||||
|
||||
accel = qemu_opt_get(qemu_get_machine_opts(), "accel");
|
||||
if (accel == NULL) {
|
||||
/* Select the default accelerator */
|
||||
int pnlen = strlen(progname);
|
||||
if (pnlen >= 3 && g_str_equal(&progname[pnlen - 3], "kvm")) {
|
||||
/* If the program name ends with "kvm", we prefer KVM */
|
||||
accel = "kvm:tcg";
|
||||
} else {
|
||||
#if defined(CONFIG_TCG)
|
||||
accel = "tcg";
|
||||
#elif defined(CONFIG_KVM)
|
||||
accel = "kvm";
|
||||
#else
|
||||
error_report("No accelerator selected and"
|
||||
" no default accelerator available");
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
accel_list = g_strsplit(accel, ":", 0);
|
||||
|
||||
for (tmp = accel_list; !accel_initialised && tmp && *tmp; tmp++) {
|
||||
acc = accel_find(*tmp);
|
||||
if (!acc) {
|
||||
continue;
|
||||
}
|
||||
ret = accel_init_machine(acc, ms);
|
||||
if (ret < 0) {
|
||||
init_failed = true;
|
||||
error_report("failed to initialize %s: %s",
|
||||
acc->name, strerror(-ret));
|
||||
} else {
|
||||
accel_initialised = true;
|
||||
}
|
||||
}
|
||||
g_strfreev(accel_list);
|
||||
|
||||
if (!accel_initialised) {
|
||||
if (!init_failed) {
|
||||
error_report("-machine accel=%s: No accelerator found", accel);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (init_failed) {
|
||||
error_report("Back to %s accelerator", acc->name);
|
||||
}
|
||||
}
|
||||
|
||||
void accel_setup_post(MachineState *ms)
|
||||
|
||||
+28
-267
@@ -40,10 +40,7 @@
|
||||
#include "trace.h"
|
||||
#include "hw/irq.h"
|
||||
#include "sysemu/sev.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi/qapi-types-common.h"
|
||||
#include "qapi/qapi-visit-common.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/balloon.h"
|
||||
|
||||
#include "hw/boards.h"
|
||||
|
||||
@@ -95,12 +92,8 @@ struct KVMState
|
||||
int max_nested_state_len;
|
||||
int many_ioeventfds;
|
||||
int intx_set_mask;
|
||||
int kvm_shadow_mem;
|
||||
bool kernel_irqchip_allowed;
|
||||
bool kernel_irqchip_required;
|
||||
OnOffAuto kernel_irqchip_split;
|
||||
bool sync_mmu;
|
||||
uint64_t manual_dirty_log_protect;
|
||||
bool manual_dirty_log_protect;
|
||||
/* The man page (and posix) say ioctl numbers are signed int, but
|
||||
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
|
||||
* unsigned, and treating them as signed here can break things */
|
||||
@@ -159,62 +152,12 @@ static const KVMCapabilityInfo kvm_required_capabilites[] = {
|
||||
static NotifierList kvm_irqchip_change_notifiers =
|
||||
NOTIFIER_LIST_INITIALIZER(kvm_irqchip_change_notifiers);
|
||||
|
||||
struct KVMResampleFd {
|
||||
int gsi;
|
||||
EventNotifier *resample_event;
|
||||
QLIST_ENTRY(KVMResampleFd) node;
|
||||
};
|
||||
typedef struct KVMResampleFd KVMResampleFd;
|
||||
|
||||
/*
|
||||
* Only used with split irqchip where we need to do the resample fd
|
||||
* kick for the kernel from userspace.
|
||||
*/
|
||||
static QLIST_HEAD(, KVMResampleFd) kvm_resample_fd_list =
|
||||
QLIST_HEAD_INITIALIZER(kvm_resample_fd_list);
|
||||
|
||||
#define kvm_slots_lock(kml) qemu_mutex_lock(&(kml)->slots_lock)
|
||||
#define kvm_slots_unlock(kml) qemu_mutex_unlock(&(kml)->slots_lock)
|
||||
|
||||
static inline void kvm_resample_fd_remove(int gsi)
|
||||
{
|
||||
KVMResampleFd *rfd;
|
||||
|
||||
QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) {
|
||||
if (rfd->gsi == gsi) {
|
||||
QLIST_REMOVE(rfd, node);
|
||||
g_free(rfd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void kvm_resample_fd_insert(int gsi, EventNotifier *event)
|
||||
{
|
||||
KVMResampleFd *rfd = g_new0(KVMResampleFd, 1);
|
||||
|
||||
rfd->gsi = gsi;
|
||||
rfd->resample_event = event;
|
||||
|
||||
QLIST_INSERT_HEAD(&kvm_resample_fd_list, rfd, node);
|
||||
}
|
||||
|
||||
void kvm_resample_fd_notify(int gsi)
|
||||
{
|
||||
KVMResampleFd *rfd;
|
||||
|
||||
QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) {
|
||||
if (rfd->gsi == gsi) {
|
||||
event_notifier_set(rfd->resample_event);
|
||||
trace_kvm_resample_fd_notify(gsi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_get_max_memslots(void)
|
||||
{
|
||||
KVMState *s = KVM_STATE(current_accel());
|
||||
KVMState *s = KVM_STATE(current_machine->accelerator);
|
||||
|
||||
return s->nr_slots;
|
||||
}
|
||||
@@ -358,23 +301,13 @@ static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, boo
|
||||
/* Set the slot size to 0 before setting the slot to the desired
|
||||
* value. This is needed based on KVM commit 75d61fbc. */
|
||||
mem.memory_size = 0;
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
}
|
||||
mem.memory_size = slot->memory_size;
|
||||
ret = kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
|
||||
slot->old_flags = mem.flags;
|
||||
err:
|
||||
trace_kvm_set_user_memory(mem.slot, mem.flags, mem.guest_phys_addr,
|
||||
mem.memory_size, mem.userspace_addr, ret);
|
||||
if (ret < 0) {
|
||||
error_report("%s: KVM_SET_USER_MEMORY_REGION failed, slot=%d,"
|
||||
" start=0x%" PRIx64 ", size=0x%" PRIx64 ": %s",
|
||||
__func__, mem.slot, slot->start_addr,
|
||||
(uint64_t)mem.memory_size, strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -933,39 +866,6 @@ int kvm_vm_check_extension(KVMState *s, unsigned int extension)
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct HWPoisonPage {
|
||||
ram_addr_t ram_addr;
|
||||
QLIST_ENTRY(HWPoisonPage) list;
|
||||
} HWPoisonPage;
|
||||
|
||||
static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list =
|
||||
QLIST_HEAD_INITIALIZER(hwpoison_page_list);
|
||||
|
||||
static void kvm_unpoison_all(void *param)
|
||||
{
|
||||
HWPoisonPage *page, *next_page;
|
||||
|
||||
QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) {
|
||||
QLIST_REMOVE(page, list);
|
||||
qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE);
|
||||
g_free(page);
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_hwpoison_page_add(ram_addr_t ram_addr)
|
||||
{
|
||||
HWPoisonPage *page;
|
||||
|
||||
QLIST_FOREACH(page, &hwpoison_page_list, list) {
|
||||
if (page->ram_addr == ram_addr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
page = g_new(HWPoisonPage, 1);
|
||||
page->ram_addr = ram_addr;
|
||||
QLIST_INSERT_HEAD(&hwpoison_page_list, page, list);
|
||||
}
|
||||
|
||||
static uint32_t adjust_ioeventfd_endianness(uint32_t val, uint32_t size)
|
||||
{
|
||||
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
|
||||
@@ -1711,13 +1611,9 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
|
||||
return kvm_update_routing_entry(s, &kroute);
|
||||
}
|
||||
|
||||
static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event,
|
||||
EventNotifier *resample, int virq,
|
||||
static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int rfd, int virq,
|
||||
bool assign)
|
||||
{
|
||||
int fd = event_notifier_get_fd(event);
|
||||
int rfd = resample ? event_notifier_get_fd(resample) : -1;
|
||||
|
||||
struct kvm_irqfd irqfd = {
|
||||
.fd = fd,
|
||||
.gsi = virq,
|
||||
@@ -1725,33 +1621,8 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event,
|
||||
};
|
||||
|
||||
if (rfd != -1) {
|
||||
assert(assign);
|
||||
if (kvm_irqchip_is_split()) {
|
||||
/*
|
||||
* When the slow irqchip (e.g. IOAPIC) is in the
|
||||
* userspace, KVM kernel resamplefd will not work because
|
||||
* the EOI of the interrupt will be delivered to userspace
|
||||
* instead, so the KVM kernel resamplefd kick will be
|
||||
* skipped. The userspace here mimics what the kernel
|
||||
* provides with resamplefd, remember the resamplefd and
|
||||
* kick it when we receive EOI of this IRQ.
|
||||
*
|
||||
* This is hackery because IOAPIC is mostly bypassed
|
||||
* (except EOI broadcasts) when irqfd is used. However
|
||||
* this can bring much performance back for split irqchip
|
||||
* with INTx IRQs (for VFIO, this gives 93% perf of the
|
||||
* full fast path, which is 46% perf boost comparing to
|
||||
* the INTx slow path).
|
||||
*/
|
||||
kvm_resample_fd_insert(virq, resample);
|
||||
} else {
|
||||
irqfd.flags |= KVM_IRQFD_FLAG_RESAMPLE;
|
||||
irqfd.resamplefd = rfd;
|
||||
}
|
||||
} else if (!assign) {
|
||||
if (kvm_irqchip_is_split()) {
|
||||
kvm_resample_fd_remove(virq);
|
||||
}
|
||||
irqfd.flags |= KVM_IRQFD_FLAG_RESAMPLE;
|
||||
irqfd.resamplefd = rfd;
|
||||
}
|
||||
|
||||
if (!kvm_irqfds_enabled()) {
|
||||
@@ -1847,9 +1718,7 @@ int kvm_irqchip_add_hv_sint_route(KVMState *s, uint32_t vcpu, uint32_t sint)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event,
|
||||
EventNotifier *resample, int virq,
|
||||
bool assign)
|
||||
static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
@@ -1863,13 +1732,15 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg)
|
||||
int kvm_irqchip_add_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
|
||||
EventNotifier *rn, int virq)
|
||||
{
|
||||
return kvm_irqchip_assign_irqfd(s, n, rn, virq, true);
|
||||
return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n),
|
||||
rn ? event_notifier_get_fd(rn) : -1, virq, true);
|
||||
}
|
||||
|
||||
int kvm_irqchip_remove_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
|
||||
int virq)
|
||||
{
|
||||
return kvm_irqchip_assign_irqfd(s, n, NULL, virq, false);
|
||||
return kvm_irqchip_assign_irqfd(s, event_notifier_get_fd(n), -1, virq,
|
||||
false);
|
||||
}
|
||||
|
||||
int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
|
||||
@@ -1901,11 +1772,10 @@ void kvm_irqchip_set_qemuirq_gsi(KVMState *s, qemu_irq irq, int gsi)
|
||||
g_hash_table_insert(s->gsimap, irq, GINT_TO_POINTER(gsi));
|
||||
}
|
||||
|
||||
static void kvm_irqchip_create(KVMState *s)
|
||||
static void kvm_irqchip_create(MachineState *machine, KVMState *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(s->kernel_irqchip_split != ON_OFF_AUTO_AUTO);
|
||||
if (kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
|
||||
;
|
||||
} else if (kvm_check_extension(s, KVM_CAP_S390_IRQCHIP)) {
|
||||
@@ -1920,9 +1790,9 @@ static void kvm_irqchip_create(KVMState *s)
|
||||
|
||||
/* First probe and see if there's a arch-specific hook to create the
|
||||
* in-kernel irqchip for us */
|
||||
ret = kvm_arch_irqchip_create(s);
|
||||
ret = kvm_arch_irqchip_create(machine, s);
|
||||
if (ret == 0) {
|
||||
if (s->kernel_irqchip_split == ON_OFF_AUTO_ON) {
|
||||
if (machine_kernel_irqchip_split(machine)) {
|
||||
perror("Split IRQ chip mode not supported.");
|
||||
exit(1);
|
||||
} else {
|
||||
@@ -1970,7 +1840,7 @@ static int kvm_max_vcpu_id(KVMState *s)
|
||||
|
||||
bool kvm_vcpu_id_is_valid(int vcpu_id)
|
||||
{
|
||||
KVMState *s = KVM_STATE(current_accel());
|
||||
KVMState *s = KVM_STATE(current_machine->accelerator);
|
||||
return vcpu_id >= 0 && vcpu_id < kvm_max_vcpu_id(s);
|
||||
}
|
||||
|
||||
@@ -1994,7 +1864,6 @@ static int kvm_init(MachineState *ms)
|
||||
int ret;
|
||||
int type = 0;
|
||||
const char *kvm_type;
|
||||
uint64_t dirty_log_manual_caps;
|
||||
|
||||
s = KVM_STATE(ms->accelerator);
|
||||
|
||||
@@ -2120,20 +1989,14 @@ static int kvm_init(MachineState *ms)
|
||||
s->coalesced_pio = s->coalesced_mmio &&
|
||||
kvm_check_extension(s, KVM_CAP_COALESCED_PIO);
|
||||
|
||||
dirty_log_manual_caps =
|
||||
s->manual_dirty_log_protect =
|
||||
kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
|
||||
dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |
|
||||
KVM_DIRTY_LOG_INITIALLY_SET);
|
||||
s->manual_dirty_log_protect = dirty_log_manual_caps;
|
||||
if (dirty_log_manual_caps) {
|
||||
ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0,
|
||||
dirty_log_manual_caps);
|
||||
if (s->manual_dirty_log_protect) {
|
||||
ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0, 1);
|
||||
if (ret) {
|
||||
warn_report("Trying to enable capability %"PRIu64" of "
|
||||
"KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. "
|
||||
"Falling back to the legacy mode. ",
|
||||
dirty_log_manual_caps);
|
||||
s->manual_dirty_log_protect = 0;
|
||||
warn_report("Trying to enable KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 "
|
||||
"but failed. Falling back to the legacy mode. ");
|
||||
s->manual_dirty_log_protect = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2200,14 +2063,8 @@ static int kvm_init(MachineState *ms)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (s->kernel_irqchip_split == ON_OFF_AUTO_AUTO) {
|
||||
s->kernel_irqchip_split = mc->default_kernel_irqchip_split ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
qemu_register_reset(kvm_unpoison_all, NULL);
|
||||
|
||||
if (s->kernel_irqchip_allowed) {
|
||||
kvm_irqchip_create(s);
|
||||
if (machine_kernel_irqchip_allowed(ms)) {
|
||||
kvm_irqchip_create(ms, s);
|
||||
}
|
||||
|
||||
if (kvm_eventfds_allowed) {
|
||||
@@ -2228,8 +2085,7 @@ static int kvm_init(MachineState *ms)
|
||||
|
||||
s->sync_mmu = !!kvm_vm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
|
||||
if (!s->sync_mmu) {
|
||||
ret = ram_block_discard_disable(true);
|
||||
assert(!ret);
|
||||
qemu_balloon_inhibit(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2310,9 +2166,9 @@ void kvm_flush_coalesced_mmio_buffer(void)
|
||||
ent = &ring->coalesced_mmio[ring->first];
|
||||
|
||||
if (ent->pio == 1) {
|
||||
address_space_write(&address_space_io, ent->phys_addr,
|
||||
MEMTXATTRS_UNSPECIFIED, ent->data,
|
||||
ent->len);
|
||||
address_space_rw(&address_space_io, ent->phys_addr,
|
||||
MEMTXATTRS_UNSPECIFIED, ent->data,
|
||||
ent->len, true);
|
||||
} else {
|
||||
cpu_physical_memory_write(ent->phys_addr, ent->data, ent->len);
|
||||
}
|
||||
@@ -3098,88 +2954,6 @@ static bool kvm_accel_has_memory(MachineState *ms, AddressSpace *as,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void kvm_get_kvm_shadow_mem(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
int64_t value = s->kvm_shadow_mem;
|
||||
|
||||
visit_type_int(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void kvm_set_kvm_shadow_mem(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
int64_t value;
|
||||
|
||||
if (!visit_type_int(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->kvm_shadow_mem = value;
|
||||
}
|
||||
|
||||
static void kvm_set_kernel_irqchip(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
OnOffSplit mode;
|
||||
|
||||
if (!visit_type_OnOffSplit(v, name, &mode, errp)) {
|
||||
return;
|
||||
}
|
||||
switch (mode) {
|
||||
case ON_OFF_SPLIT_ON:
|
||||
s->kernel_irqchip_allowed = true;
|
||||
s->kernel_irqchip_required = true;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
|
||||
break;
|
||||
case ON_OFF_SPLIT_OFF:
|
||||
s->kernel_irqchip_allowed = false;
|
||||
s->kernel_irqchip_required = false;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_OFF;
|
||||
break;
|
||||
case ON_OFF_SPLIT_SPLIT:
|
||||
s->kernel_irqchip_allowed = true;
|
||||
s->kernel_irqchip_required = true;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_ON;
|
||||
break;
|
||||
default:
|
||||
/* The value was checked in visit_type_OnOffSplit() above. If
|
||||
* we get here, then something is wrong in QEMU.
|
||||
*/
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool kvm_kernel_irqchip_allowed(void)
|
||||
{
|
||||
return kvm_state->kernel_irqchip_allowed;
|
||||
}
|
||||
|
||||
bool kvm_kernel_irqchip_required(void)
|
||||
{
|
||||
return kvm_state->kernel_irqchip_required;
|
||||
}
|
||||
|
||||
bool kvm_kernel_irqchip_split(void)
|
||||
{
|
||||
return kvm_state->kernel_irqchip_split == ON_OFF_AUTO_ON;
|
||||
}
|
||||
|
||||
static void kvm_accel_instance_init(Object *obj)
|
||||
{
|
||||
KVMState *s = KVM_STATE(obj);
|
||||
|
||||
s->kvm_shadow_mem = -1;
|
||||
s->kernel_irqchip_allowed = true;
|
||||
s->kernel_irqchip_split = ON_OFF_AUTO_AUTO;
|
||||
}
|
||||
|
||||
static void kvm_accel_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
@@ -3187,24 +2961,11 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data)
|
||||
ac->init_machine = kvm_init;
|
||||
ac->has_memory = kvm_accel_has_memory;
|
||||
ac->allowed = &kvm_allowed;
|
||||
|
||||
object_class_property_add(oc, "kernel-irqchip", "on|off|split",
|
||||
NULL, kvm_set_kernel_irqchip,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "kernel-irqchip",
|
||||
"Configure KVM in-kernel irqchip");
|
||||
|
||||
object_class_property_add(oc, "kvm-shadow-mem", "int",
|
||||
kvm_get_kvm_shadow_mem, kvm_set_kvm_shadow_mem,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "kvm-shadow-mem",
|
||||
"KVM shadow MMU size");
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_accel_type = {
|
||||
.name = TYPE_KVM_ACCEL,
|
||||
.parent = TYPE_ACCEL,
|
||||
.instance_init = kvm_accel_instance_init,
|
||||
.class_init = kvm_accel_class_init,
|
||||
.instance_size = sizeof(KVMState),
|
||||
};
|
||||
|
||||
@@ -16,5 +16,4 @@ kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_
|
||||
kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%x val=0x%x assign: %d size: %d match: %d"
|
||||
kvm_set_user_memory(uint32_t slot, uint32_t flags, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, int ret) "Slot#%d flags=0x%x gpa=0x%"PRIx64 " size=0x%"PRIx64 " ua=0x%"PRIx64 " ret=%d"
|
||||
kvm_clear_dirty_log(uint32_t slot, uint64_t start, uint32_t size) "slot#%"PRId32" start 0x%"PRIx64" size 0x%"PRIx32
|
||||
kvm_resample_fd_notify(int gsi) "gsi %d"
|
||||
|
||||
@@ -3,4 +3,3 @@ obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o
|
||||
obj-$(call lnot,$(CONFIG_WHPX)) += whpx-stub.o
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||
obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
|
||||
obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o
|
||||
@@ -22,10 +22,3 @@ void tb_flush(CPUState *cpu)
|
||||
void tlb_set_dirty(CPUState *cpu, target_ulong vaddr)
|
||||
{
|
||||
}
|
||||
|
||||
void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
/* Handled by hardware accelerator. */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
+43
-24
@@ -64,10 +64,13 @@
|
||||
the ATOMIC_NAME macro, and redefined below. */
|
||||
#if DATA_SIZE == 1
|
||||
# define END
|
||||
# define MEND _be /* either le or be would be fine */
|
||||
#elif defined(HOST_WORDS_BIGENDIAN)
|
||||
# define END _be
|
||||
# define MEND _be
|
||||
#else
|
||||
# define END _le
|
||||
# define MEND _le
|
||||
#endif
|
||||
|
||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
@@ -76,8 +79,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
#if DATA_SIZE == 16
|
||||
@@ -96,8 +99,8 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
|
||||
{
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_ld_pre(env, addr, info);
|
||||
val = atomic16_read(haddr);
|
||||
@@ -111,8 +114,8 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
|
||||
{
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, true,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_st_pre(env, addr, info);
|
||||
atomic16_set(haddr, val);
|
||||
@@ -127,8 +130,8 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
ret = atomic_xchg__nocheck(haddr, val);
|
||||
@@ -144,8 +147,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
DATA_TYPE ret; \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \
|
||||
false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
\
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
ret = atomic_##X(haddr, val); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
@@ -178,8 +183,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
XDATA_TYPE cmp, old, new, val = xval; \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \
|
||||
false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
\
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
smp_mb(); \
|
||||
cmp = atomic_read__nocheck(haddr); \
|
||||
@@ -206,6 +213,7 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
|
||||
#endif /* DATA SIZE >= 16 */
|
||||
|
||||
#undef END
|
||||
#undef MEND
|
||||
|
||||
#if DATA_SIZE > 1
|
||||
|
||||
@@ -213,8 +221,10 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
|
||||
within the ATOMIC_NAME macro. */
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
# define END _le
|
||||
# define MEND _le
|
||||
#else
|
||||
# define END _be
|
||||
# define MEND _be
|
||||
#endif
|
||||
|
||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
@@ -223,8 +233,9 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
DATA_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
|
||||
false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
#if DATA_SIZE == 16
|
||||
@@ -243,8 +254,9 @@ ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
|
||||
{
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
|
||||
false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_ld_pre(env, addr, info);
|
||||
val = atomic16_read(haddr);
|
||||
@@ -258,8 +270,9 @@ void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
|
||||
{
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
|
||||
true,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
val = BSWAP(val);
|
||||
atomic_trace_st_pre(env, addr, info);
|
||||
@@ -276,8 +289,9 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
||||
ATOMIC_MMU_DECLS;
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
|
||||
ABI_TYPE ret;
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
|
||||
ATOMIC_MMU_IDX);
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
|
||||
false,
|
||||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
ret = atomic_xchg__nocheck(haddr, BSWAP(val));
|
||||
@@ -293,8 +307,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
DATA_TYPE ret; \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \
|
||||
false, ATOMIC_MMU_IDX); \
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \
|
||||
false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
\
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
ret = atomic_##X(haddr, BSWAP(val)); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
@@ -325,8 +341,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||
ATOMIC_MMU_DECLS; \
|
||||
XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \
|
||||
XDATA_TYPE ldo, ldn, old, new, val = xval; \
|
||||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \
|
||||
false, ATOMIC_MMU_IDX); \
|
||||
uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \
|
||||
false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
\
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
smp_mb(); \
|
||||
ldn = atomic_read__nocheck(haddr); \
|
||||
@@ -360,6 +378,7 @@ GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
|
||||
#endif /* DATA_SIZE >= 16 */
|
||||
|
||||
#undef END
|
||||
#undef MEND
|
||||
#endif /* DATA_SIZE > 1 */
|
||||
|
||||
#undef BSWAP
|
||||
|
||||
+14
-32
@@ -23,7 +23,7 @@
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "qemu/timer.h"
|
||||
@@ -156,7 +156,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
#if defined(DEBUG_DISAS)
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)
|
||||
&& qemu_log_in_addr_range(itb->pc)) {
|
||||
FILE *logfile = qemu_log_lock();
|
||||
qemu_log_lock();
|
||||
int flags = 0;
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
|
||||
flags |= CPU_DUMP_FPU;
|
||||
@@ -165,7 +165,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
flags |= CPU_DUMP_CCOP;
|
||||
#endif
|
||||
log_cpu_state(cpu, flags);
|
||||
qemu_log_unlock(logfile);
|
||||
qemu_log_unlock();
|
||||
}
|
||||
#endif /* DEBUG_DISAS */
|
||||
|
||||
@@ -240,8 +240,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
uint32_t cf_mask = cflags & CF_HASH_MASK;
|
||||
|
||||
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
||||
start_exclusive();
|
||||
|
||||
tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask);
|
||||
if (tb == NULL) {
|
||||
mmap_lock();
|
||||
@@ -249,6 +247,8 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
mmap_unlock();
|
||||
}
|
||||
|
||||
start_exclusive();
|
||||
|
||||
/* Since we got here, we know that parallel_cpus must be true. */
|
||||
parallel_cpus = false;
|
||||
cc->cpu_exec_enter(cpu);
|
||||
@@ -271,15 +271,14 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
qemu_plugin_disable_mem_helpers(cpu);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* As we start the exclusive region before codegen we must still
|
||||
* be in the region if we longjump out of either the codegen or
|
||||
* the execution.
|
||||
*/
|
||||
g_assert(cpu_in_exclusive_context(cpu));
|
||||
parallel_cpus = true;
|
||||
end_exclusive();
|
||||
if (cpu_in_exclusive_context(cpu)) {
|
||||
/* We might longjump out of either the codegen or the
|
||||
* execution, so must make sure we only end the exclusive
|
||||
* region if we started it.
|
||||
*/
|
||||
parallel_cpus = true;
|
||||
end_exclusive();
|
||||
}
|
||||
}
|
||||
|
||||
struct tb_desc {
|
||||
@@ -504,17 +503,6 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
cc->do_interrupt(cpu);
|
||||
qemu_mutex_unlock_iothread();
|
||||
cpu->exception_index = -1;
|
||||
|
||||
if (unlikely(cpu->singlestep_enabled)) {
|
||||
/*
|
||||
* After processing the exception, ensure an EXCP_DEBUG is
|
||||
* raised when single-stepping so that GDB doesn't miss the
|
||||
* next instruction.
|
||||
*/
|
||||
*ret = EXCP_DEBUG;
|
||||
cpu_handle_debug_exception(cpu);
|
||||
return true;
|
||||
}
|
||||
} else if (!replay_has_interrupt()) {
|
||||
/* give a chance to iothread in replay mode */
|
||||
*ret = EXCP_INTERRUPT;
|
||||
@@ -588,13 +576,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
else {
|
||||
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
replay_interrupt();
|
||||
/*
|
||||
* After processing the interrupt, ensure an EXCP_DEBUG is
|
||||
* raised when single-stepping so that GDB doesn't miss the
|
||||
* next instruction.
|
||||
*/
|
||||
cpu->exception_index =
|
||||
(cpu->singlestep_enabled ? EXCP_DEBUG : -1);
|
||||
cpu->exception_index = -1;
|
||||
*last_tb = NULL;
|
||||
}
|
||||
/* The target hook may have updated the 'cpu->interrupt_request';
|
||||
|
||||
+252
-693
File diff suppressed because it is too large.
Load diff
+4
-141
@@ -30,23 +30,8 @@
|
||||
#include "cpu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/qapi-builtin-visit.h"
|
||||
|
||||
typedef struct TCGState {
|
||||
AccelState parent_obj;
|
||||
|
||||
bool mttcg_enabled;
|
||||
unsigned long tb_size;
|
||||
} TCGState;
|
||||
|
||||
#define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
|
||||
|
||||
#define TCG_STATE(obj) \
|
||||
OBJECT_CHECK(TCGState, (obj), TYPE_TCG_ACCEL)
|
||||
unsigned long tcg_tb_size;
|
||||
|
||||
/* mask must never be zero, except for A20 change call */
|
||||
static void tcg_handle_interrupt(CPUState *cpu, int mask)
|
||||
@@ -73,149 +58,27 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We default to false if we know other options have been enabled
|
||||
* which are currently incompatible with MTTCG. Otherwise when each
|
||||
* guest (target) has been updated to support:
|
||||
* - atomic instructions
|
||||
* - memory ordering primitives (barriers)
|
||||
* they can set the appropriate CONFIG flags in ${target}-softmmu.mak
|
||||
*
|
||||
* Once a guest architecture has been converted to the new primitives
|
||||
* there are two remaining limitations to check.
|
||||
*
|
||||
* - The guest can't be oversized (e.g. 64 bit guest on 32 bit host)
|
||||
* - The host must have a stronger memory order than the guest
|
||||
*
|
||||
* It may be possible in future to support strong guests on weak hosts
|
||||
* but that will require tagging all load/stores in a guest with their
|
||||
* implicit memory order requirements which would likely slow things
|
||||
* down a lot.
|
||||
*/
|
||||
|
||||
static bool check_tcg_memory_orders_compatible(void)
|
||||
{
|
||||
#if defined(TCG_GUEST_DEFAULT_MO) && defined(TCG_TARGET_DEFAULT_MO)
|
||||
return (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) == 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool default_mttcg_enabled(void)
|
||||
{
|
||||
if (use_icount || TCG_OVERSIZED_GUEST) {
|
||||
return false;
|
||||
} else {
|
||||
#ifdef TARGET_SUPPORTS_MTTCG
|
||||
return check_tcg_memory_orders_compatible();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_accel_instance_init(Object *obj)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
|
||||
s->mttcg_enabled = default_mttcg_enabled();
|
||||
}
|
||||
|
||||
static int tcg_init(MachineState *ms)
|
||||
{
|
||||
TCGState *s = TCG_STATE(current_accel());
|
||||
|
||||
tcg_exec_init(s->tb_size * 1024 * 1024);
|
||||
tcg_exec_init(tcg_tb_size * 1024 * 1024);
|
||||
cpu_interrupt_handler = tcg_handle_interrupt;
|
||||
mttcg_enabled = s->mttcg_enabled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *tcg_get_thread(Object *obj, Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
|
||||
return g_strdup(s->mttcg_enabled ? "multi" : "single");
|
||||
}
|
||||
|
||||
static void tcg_set_thread(Object *obj, const char *value, Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
|
||||
if (strcmp(value, "multi") == 0) {
|
||||
if (TCG_OVERSIZED_GUEST) {
|
||||
error_setg(errp, "No MTTCG when guest word size > hosts");
|
||||
} else if (use_icount) {
|
||||
error_setg(errp, "No MTTCG when icount is enabled");
|
||||
} else {
|
||||
#ifndef TARGET_SUPPORTS_MTTCG
|
||||
warn_report("Guest not yet converted to MTTCG - "
|
||||
"you may get unexpected results");
|
||||
#endif
|
||||
if (!check_tcg_memory_orders_compatible()) {
|
||||
warn_report("Guest expects a stronger memory ordering "
|
||||
"than the host provides");
|
||||
error_printf("This may cause strange/hard to debug errors\n");
|
||||
}
|
||||
s->mttcg_enabled = true;
|
||||
}
|
||||
} else if (strcmp(value, "single") == 0) {
|
||||
s->mttcg_enabled = false;
|
||||
} else {
|
||||
error_setg(errp, "Invalid 'thread' setting %s", value);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_get_tb_size(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
uint32_t value = s->tb_size;
|
||||
|
||||
visit_type_uint32(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void tcg_set_tb_size(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->tb_size = value;
|
||||
}
|
||||
|
||||
static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
ac->name = "tcg";
|
||||
ac->init_machine = tcg_init;
|
||||
ac->allowed = &tcg_allowed;
|
||||
|
||||
object_class_property_add_str(oc, "thread",
|
||||
tcg_get_thread,
|
||||
tcg_set_thread);
|
||||
|
||||
object_class_property_add(oc, "tb-size", "int",
|
||||
tcg_get_tb_size, tcg_set_tb_size,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "tb-size",
|
||||
"TCG translation block cache size");
|
||||
|
||||
}
|
||||
|
||||
#define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
|
||||
|
||||
static const TypeInfo tcg_accel_type = {
|
||||
.name = TYPE_TCG_ACCEL,
|
||||
.parent = TYPE_ACCEL,
|
||||
.instance_init = tcg_accel_instance_init,
|
||||
.class_init = tcg_accel_class_init,
|
||||
.instance_size = sizeof(TCGState),
|
||||
};
|
||||
|
||||
static void register_accel_types(void)
|
||||
|
||||
+182
-260
@@ -21,9 +21,51 @@
|
||||
#include "qemu/host-utils.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "tcg/tcg-gvec-desc.h"
|
||||
#include "tcg-gvec-desc.h"
|
||||
|
||||
|
||||
/* Virtually all hosts support 16-byte vectors. Those that don't can emulate
|
||||
* them via GCC's generic vector extension. This turns out to be simpler and
|
||||
* more reliable than getting the compiler to autovectorize.
|
||||
*
|
||||
* In tcg-op-gvec.c, we asserted that both the size and alignment of the data
|
||||
* are multiples of 16.
|
||||
*
|
||||
* When the compiler does not support all of the operations we require, the
|
||||
* loops are written so that we can always fall back on the base types.
|
||||
*/
|
||||
#ifdef CONFIG_VECTOR16
|
||||
typedef uint8_t vec8 __attribute__((vector_size(16)));
|
||||
typedef uint16_t vec16 __attribute__((vector_size(16)));
|
||||
typedef uint32_t vec32 __attribute__((vector_size(16)));
|
||||
typedef uint64_t vec64 __attribute__((vector_size(16)));
|
||||
|
||||
typedef int8_t svec8 __attribute__((vector_size(16)));
|
||||
typedef int16_t svec16 __attribute__((vector_size(16)));
|
||||
typedef int32_t svec32 __attribute__((vector_size(16)));
|
||||
typedef int64_t svec64 __attribute__((vector_size(16)));
|
||||
|
||||
#define DUP16(X) { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X }
|
||||
#define DUP8(X) { X, X, X, X, X, X, X, X }
|
||||
#define DUP4(X) { X, X, X, X }
|
||||
#define DUP2(X) { X, X }
|
||||
#else
|
||||
typedef uint8_t vec8;
|
||||
typedef uint16_t vec16;
|
||||
typedef uint32_t vec32;
|
||||
typedef uint64_t vec64;
|
||||
|
||||
typedef int8_t svec8;
|
||||
typedef int16_t svec16;
|
||||
typedef int32_t svec32;
|
||||
typedef int64_t svec64;
|
||||
|
||||
#define DUP16(X) X
|
||||
#define DUP8(X) X
|
||||
#define DUP4(X) X
|
||||
#define DUP2(X) X
|
||||
#endif /* CONFIG_VECTOR16 */
|
||||
|
||||
static inline void clear_high(void *d, intptr_t oprsz, uint32_t desc)
|
||||
{
|
||||
intptr_t maxsz = simd_maxsz(desc);
|
||||
@@ -41,8 +83,8 @@ void HELPER(gvec_add8)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) + *(uint8_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) + *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -52,8 +94,8 @@ void HELPER(gvec_add16)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) + *(uint16_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) + *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -63,8 +105,8 @@ void HELPER(gvec_add32)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) + *(uint32_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) + *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -74,8 +116,8 @@ void HELPER(gvec_add64)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) + *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) + *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -83,10 +125,11 @@ void HELPER(gvec_add64)(void *d, void *a, void *b, uint32_t desc)
|
||||
void HELPER(gvec_adds8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec8 vecb = (vec8)DUP16(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) + (uint8_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -94,10 +137,11 @@ void HELPER(gvec_adds8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_adds16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec16 vecb = (vec16)DUP8(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) + (uint16_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -105,10 +149,11 @@ void HELPER(gvec_adds16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_adds32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec32 vecb = (vec32)DUP4(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) + (uint32_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -116,10 +161,11 @@ void HELPER(gvec_adds32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_adds64)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) + b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) + vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -129,8 +175,8 @@ void HELPER(gvec_sub8)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) - *(uint8_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) - *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -140,8 +186,8 @@ void HELPER(gvec_sub16)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) - *(uint16_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) - *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -151,8 +197,8 @@ void HELPER(gvec_sub32)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) - *(uint32_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) - *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -162,8 +208,8 @@ void HELPER(gvec_sub64)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) - *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) - *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -171,10 +217,11 @@ void HELPER(gvec_sub64)(void *d, void *a, void *b, uint32_t desc)
|
||||
void HELPER(gvec_subs8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec8 vecb = (vec8)DUP16(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) - (uint8_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -182,10 +229,11 @@ void HELPER(gvec_subs8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_subs16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec16 vecb = (vec16)DUP8(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) - (uint16_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -193,10 +241,11 @@ void HELPER(gvec_subs16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_subs32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec32 vecb = (vec32)DUP4(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) - (uint32_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -204,10 +253,11 @@ void HELPER(gvec_subs32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_subs64)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) - b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) - vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -217,8 +267,8 @@ void HELPER(gvec_mul8)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) * *(uint8_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) * *(vec8 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -228,8 +278,8 @@ void HELPER(gvec_mul16)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) * *(uint16_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) * *(vec16 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -239,8 +289,8 @@ void HELPER(gvec_mul32)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) * *(uint32_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) * *(vec32 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -250,8 +300,8 @@ void HELPER(gvec_mul64)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) * *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) * *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -259,10 +309,11 @@ void HELPER(gvec_mul64)(void *d, void *a, void *b, uint32_t desc)
|
||||
void HELPER(gvec_muls8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec8 vecb = (vec8)DUP16(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) * (uint8_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -270,10 +321,11 @@ void HELPER(gvec_muls8)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_muls16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec16 vecb = (vec16)DUP8(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) * (uint16_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -281,10 +333,11 @@ void HELPER(gvec_muls16)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_muls32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec32 vecb = (vec32)DUP4(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) * (uint32_t)b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -292,10 +345,11 @@ void HELPER(gvec_muls32)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_muls64)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) * b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) * vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -305,8 +359,8 @@ void HELPER(gvec_neg8)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = -*(uint8_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = -*(vec8 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -316,8 +370,8 @@ void HELPER(gvec_neg16)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = -*(uint16_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = -*(vec16 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -327,8 +381,8 @@ void HELPER(gvec_neg32)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = -*(uint32_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = -*(vec32 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -338,8 +392,8 @@ void HELPER(gvec_neg64)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = -*(uint64_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = -*(vec64 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -445,8 +499,8 @@ void HELPER(gvec_not)(void *d, void *a, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = ~*(uint64_t *)(a + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = ~*(vec64 *)(a + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -456,8 +510,8 @@ void HELPER(gvec_and)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) & *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) & *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -467,8 +521,8 @@ void HELPER(gvec_or)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) | *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) | *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -478,8 +532,8 @@ void HELPER(gvec_xor)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) ^ *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) ^ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -489,8 +543,8 @@ void HELPER(gvec_andc)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) &~ *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) &~ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -500,8 +554,8 @@ void HELPER(gvec_orc)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) |~ *(uint64_t *)(b + i);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) |~ *(vec64 *)(b + i);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -511,8 +565,8 @@ void HELPER(gvec_nand)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) & *(uint64_t *)(b + i));
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = ~(*(vec64 *)(a + i) & *(vec64 *)(b + i));
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -522,8 +576,8 @@ void HELPER(gvec_nor)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) | *(uint64_t *)(b + i));
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = ~(*(vec64 *)(a + i) | *(vec64 *)(b + i));
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -533,8 +587,8 @@ void HELPER(gvec_eqv)(void *d, void *a, void *b, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) ^ *(uint64_t *)(b + i));
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = ~(*(vec64 *)(a + i) ^ *(vec64 *)(b + i));
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -542,10 +596,11 @@ void HELPER(gvec_eqv)(void *d, void *a, void *b, uint32_t desc)
|
||||
void HELPER(gvec_ands)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) & b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) & vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -553,10 +608,11 @@ void HELPER(gvec_ands)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_xors)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) ^ b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) ^ vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -564,10 +620,11 @@ void HELPER(gvec_xors)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
void HELPER(gvec_ors)(void *d, void *a, uint64_t b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
vec64 vecb = (vec64)DUP2(b);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) | b;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) | vecb;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -578,8 +635,8 @@ void HELPER(gvec_shl8i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) << shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -590,8 +647,8 @@ void HELPER(gvec_shl16i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) << shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -602,8 +659,8 @@ void HELPER(gvec_shl32i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) << shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -614,8 +671,8 @@ void HELPER(gvec_shl64i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) << shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) << shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -626,8 +683,8 @@ void HELPER(gvec_shr8i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = *(uint8_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(vec8 *)(d + i) = *(vec8 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -638,8 +695,8 @@ void HELPER(gvec_shr16i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = *(uint16_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(vec16 *)(d + i) = *(vec16 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -650,8 +707,8 @@ void HELPER(gvec_shr32i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = *(uint32_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(vec32 *)(d + i) = *(vec32 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -662,8 +719,8 @@ void HELPER(gvec_shr64i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = *(uint64_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(vec64 *)(d + i) = *(vec64 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -674,8 +731,8 @@ void HELPER(gvec_sar8i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(int8_t *)(d + i) = *(int8_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec8)) {
|
||||
*(svec8 *)(d + i) = *(svec8 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -686,8 +743,8 @@ void HELPER(gvec_sar16i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(int16_t *)(d + i) = *(int16_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec16)) {
|
||||
*(svec16 *)(d + i) = *(svec16 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -698,8 +755,8 @@ void HELPER(gvec_sar32i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(int32_t *)(d + i) = *(int32_t *)(a + i) >> shift;
|
||||
for (i = 0; i < oprsz; i += sizeof(vec32)) {
|
||||
*(svec32 *)(d + i) = *(svec32 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -710,56 +767,8 @@ void HELPER(gvec_sar64i)(void *d, void *a, uint32_t desc)
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(int64_t *)(d + i) = *(int64_t *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotl8i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
*(uint8_t *)(d + i) = rol8(*(uint8_t *)(a + i), shift);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotl16i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
*(uint16_t *)(d + i) = rol16(*(uint16_t *)(a + i), shift);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotl32i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
*(uint32_t *)(d + i) = rol32(*(uint32_t *)(a + i), shift);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotl64i)(void *d, void *a, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
int shift = simd_data(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
*(uint64_t *)(d + i) = rol64(*(uint64_t *)(a + i), shift);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
*(svec64 *)(d + i) = *(svec64 *)(a + i) >> shift;
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -908,101 +917,13 @@ void HELPER(gvec_sar64v)(void *d, void *a, void *b, uint32_t desc)
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotl8v)(void *d, void *a, void *b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
uint8_t sh = *(uint8_t *)(b + i) & 7;
|
||||
*(uint8_t *)(d + i) = rol8(*(uint8_t *)(a + i), sh);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotl16v)(void *d, void *a, void *b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
uint8_t sh = *(uint16_t *)(b + i) & 15;
|
||||
*(uint16_t *)(d + i) = rol16(*(uint16_t *)(a + i), sh);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotl32v)(void *d, void *a, void *b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
uint8_t sh = *(uint32_t *)(b + i) & 31;
|
||||
*(uint32_t *)(d + i) = rol32(*(uint32_t *)(a + i), sh);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotl64v)(void *d, void *a, void *b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
uint8_t sh = *(uint64_t *)(b + i) & 63;
|
||||
*(uint64_t *)(d + i) = rol64(*(uint64_t *)(a + i), sh);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotr8v)(void *d, void *a, void *b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
|
||||
uint8_t sh = *(uint8_t *)(b + i) & 7;
|
||||
*(uint8_t *)(d + i) = ror8(*(uint8_t *)(a + i), sh);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotr16v)(void *d, void *a, void *b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
|
||||
uint8_t sh = *(uint16_t *)(b + i) & 15;
|
||||
*(uint16_t *)(d + i) = ror16(*(uint16_t *)(a + i), sh);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotr32v)(void *d, void *a, void *b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
|
||||
uint8_t sh = *(uint32_t *)(b + i) & 31;
|
||||
*(uint32_t *)(d + i) = ror32(*(uint32_t *)(a + i), sh);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
|
||||
void HELPER(gvec_rotr64v)(void *d, void *a, void *b, uint32_t desc)
|
||||
{
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
uint8_t sh = *(uint64_t *)(b + i) & 63;
|
||||
*(uint64_t *)(d + i) = ror64(*(uint64_t *)(a + i), sh);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
/* If vectors are enabled, the compiler fills in -1 for true.
|
||||
Otherwise, we must take care of this by hand. */
|
||||
#ifdef CONFIG_VECTOR16
|
||||
# define DO_CMP0(X) X
|
||||
#else
|
||||
# define DO_CMP0(X) -(X)
|
||||
#endif
|
||||
|
||||
#define DO_CMP1(NAME, TYPE, OP) \
|
||||
void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \
|
||||
@@ -1010,24 +931,25 @@ void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \
|
||||
intptr_t oprsz = simd_oprsz(desc); \
|
||||
intptr_t i; \
|
||||
for (i = 0; i < oprsz; i += sizeof(TYPE)) { \
|
||||
*(TYPE *)(d + i) = -(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \
|
||||
*(TYPE *)(d + i) = DO_CMP0(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \
|
||||
} \
|
||||
clear_high(d, oprsz, desc); \
|
||||
}
|
||||
|
||||
#define DO_CMP2(SZ) \
|
||||
DO_CMP1(gvec_eq##SZ, uint##SZ##_t, ==) \
|
||||
DO_CMP1(gvec_ne##SZ, uint##SZ##_t, !=) \
|
||||
DO_CMP1(gvec_lt##SZ, int##SZ##_t, <) \
|
||||
DO_CMP1(gvec_le##SZ, int##SZ##_t, <=) \
|
||||
DO_CMP1(gvec_ltu##SZ, uint##SZ##_t, <) \
|
||||
DO_CMP1(gvec_leu##SZ, uint##SZ##_t, <=)
|
||||
DO_CMP1(gvec_eq##SZ, vec##SZ, ==) \
|
||||
DO_CMP1(gvec_ne##SZ, vec##SZ, !=) \
|
||||
DO_CMP1(gvec_lt##SZ, svec##SZ, <) \
|
||||
DO_CMP1(gvec_le##SZ, svec##SZ, <=) \
|
||||
DO_CMP1(gvec_ltu##SZ, vec##SZ, <) \
|
||||
DO_CMP1(gvec_leu##SZ, vec##SZ, <=)
|
||||
|
||||
DO_CMP2(8)
|
||||
DO_CMP2(16)
|
||||
DO_CMP2(32)
|
||||
DO_CMP2(64)
|
||||
|
||||
#undef DO_CMP0
|
||||
#undef DO_CMP1
|
||||
#undef DO_CMP2
|
||||
|
||||
@@ -1528,11 +1450,11 @@ void HELPER(gvec_bitsel)(void *d, void *a, void *b, void *c, uint32_t desc)
|
||||
intptr_t oprsz = simd_oprsz(desc);
|
||||
intptr_t i;
|
||||
|
||||
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
|
||||
uint64_t aa = *(uint64_t *)(a + i);
|
||||
uint64_t bb = *(uint64_t *)(b + i);
|
||||
uint64_t cc = *(uint64_t *)(c + i);
|
||||
*(uint64_t *)(d + i) = (bb & aa) | (cc & ~aa);
|
||||
for (i = 0; i < oprsz; i += sizeof(vec64)) {
|
||||
vec64 aa = *(vec64 *)(a + i);
|
||||
vec64 bb = *(vec64 *)(b + i);
|
||||
vec64 cc = *(vec64 *)(c + i);
|
||||
*(vec64 *)(d + i) = (bb & aa) | (cc & ~aa);
|
||||
}
|
||||
clear_high(d, oprsz, desc);
|
||||
}
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "exec/tb-lookup.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/log.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
/* 32-bit helpers */
|
||||
|
||||
|
||||
@@ -259,11 +259,6 @@ DEF_HELPER_FLAGS_3(gvec_sar16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_sar32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_sar64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(gvec_rotl8i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_rotl16i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_rotl32i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(gvec_rotl64i, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_shl8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_shl16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_shl32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
@@ -279,16 +274,6 @@ DEF_HELPER_FLAGS_4(gvec_sar16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_sar32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_sar64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_rotl8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_rotl16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_rotl32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_rotl64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_rotr8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_rotr16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_rotr32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_rotr64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(gvec_eq8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_eq16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_eq32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# TCG related tracing
|
||||
# TCG related tracing (mostly disabled by default)
|
||||
# cpu-exec.c
|
||||
exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
|
||||
exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
|
||||
exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x"
|
||||
disable exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
|
||||
disable exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
|
||||
disable exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x"
|
||||
|
||||
# translate-all.c
|
||||
translate_block(void *tb, uintptr_t pc, uint8_t *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p"
|
||||
+76
-112
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
#define NO_CPU_IO_DEFS
|
||||
@@ -26,7 +25,7 @@
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg.h"
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#include "qemu.h"
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
@@ -173,13 +172,8 @@ struct page_collection {
|
||||
#define TB_FOR_EACH_JMP(head_tb, tb, n) \
|
||||
TB_FOR_EACH_TAGGED((head_tb)->jmp_list_head, tb, n, jmp_list_next)
|
||||
|
||||
/*
|
||||
* In system mode we want L1_MAP to be based on ram offsets,
|
||||
* while in user mode we want it to be based on virtual addresses.
|
||||
*
|
||||
* TODO: For user mode, see the caveat re host vs guest virtual
|
||||
* address spaces near GUEST_ADDR_MAX.
|
||||
*/
|
||||
/* In system mode we want L1_MAP to be based on ram offsets,
|
||||
while in user mode we want it to be based on virtual addresses. */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#if HOST_LONG_BITS < TARGET_PHYS_ADDR_SPACE_BITS
|
||||
# define L1_MAP_ADDR_SPACE_BITS HOST_LONG_BITS
|
||||
@@ -187,7 +181,7 @@ struct page_collection {
|
||||
# define L1_MAP_ADDR_SPACE_BITS TARGET_PHYS_ADDR_SPACE_BITS
|
||||
#endif
|
||||
#else
|
||||
# define L1_MAP_ADDR_SPACE_BITS MIN(HOST_LONG_BITS, TARGET_ABI_BITS)
|
||||
# define L1_MAP_ADDR_SPACE_BITS TARGET_VIRT_ADDR_SPACE_BITS
|
||||
#endif
|
||||
|
||||
/* Size of the L2 (and L3, etc) page tables. */
|
||||
@@ -384,11 +378,6 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tb_destroy(TranslationBlock *tb)
|
||||
{
|
||||
qemu_spin_destroy(&tb->jmp_lock);
|
||||
}
|
||||
|
||||
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
@@ -418,7 +407,6 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
|
||||
/* one-shot translation, invalidate it immediately */
|
||||
tb_phys_invalidate(tb, -1);
|
||||
tcg_tb_remove(tb);
|
||||
tb_destroy(tb);
|
||||
}
|
||||
r = true;
|
||||
}
|
||||
@@ -547,15 +535,6 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
|
||||
#endif
|
||||
existing = atomic_cmpxchg(lp, NULL, pd);
|
||||
if (unlikely(existing)) {
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < V_L2_SIZE; i++) {
|
||||
qemu_spin_destroy(&pd[i].lock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
g_free(pd);
|
||||
pd = existing;
|
||||
}
|
||||
@@ -912,61 +891,43 @@ static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* Currently it is not recommended to allocate big chunks of data in
|
||||
user mode. It will change when a dedicated libc will be used. */
|
||||
/* ??? 64-bit hosts ought to have no problem mmaping data outside the
|
||||
region in which the guest needs to run. Revisit this. */
|
||||
#define USE_STATIC_CODE_GEN_BUFFER
|
||||
#endif
|
||||
|
||||
/* Minimum size of the code gen buffer. This number is randomly chosen,
|
||||
but not so small that we can't have a fair number of TB's live. */
|
||||
#define MIN_CODE_GEN_BUFFER_SIZE (1 * MiB)
|
||||
#define MIN_CODE_GEN_BUFFER_SIZE (1024u * 1024)
|
||||
|
||||
/* Maximum size of the code gen buffer we'd like to use. Unless otherwise
|
||||
indicated, this is constrained by the range of direct branches on the
|
||||
host cpu, as used by the TCG implementation of goto_tb. */
|
||||
#if defined(__x86_64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__sparc__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__powerpc64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__powerpc__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (32u * 1024 * 1024)
|
||||
#elif defined(__aarch64__)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__s390x__)
|
||||
/* We have a +- 4GB range on the branches; leave some slop. */
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (3ul * 1024 * 1024 * 1024)
|
||||
#elif defined(__mips__)
|
||||
/* We have a 256MB branch region, but leave room to make sure the
|
||||
main executable is also within that region. */
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (128 * MiB)
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE (128ul * 1024 * 1024)
|
||||
#else
|
||||
# define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||
#endif
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32 * MiB)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* For user mode on smaller 32 bit systems we may run into trouble
|
||||
* allocating big chunks of data in the right place. On these systems
|
||||
* we utilise a static code generation buffer directly in the binary.
|
||||
*/
|
||||
#define USE_STATIC_CODE_GEN_BUFFER
|
||||
#endif
|
||||
#else /* TCG_TARGET_REG_BITS == 64 */
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* As user-mode emulation typically means running multiple instances
|
||||
* of the translator don't go too nuts with our default code gen
|
||||
* buffer lest we make things too hard for the OS.
|
||||
*/
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (128 * MiB)
|
||||
#else
|
||||
/*
|
||||
* We expect most system emulation to run one or two guests per host.
|
||||
* Users running large scale system emulation may want to tweak their
|
||||
* runtime setup via the tb-size control on the command line.
|
||||
*/
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (1 * GiB)
|
||||
#endif
|
||||
#endif
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32u * 1024 * 1024)
|
||||
|
||||
#define DEFAULT_CODE_GEN_BUFFER_SIZE \
|
||||
(DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \
|
||||
@@ -976,12 +937,15 @@ static inline size_t size_code_gen_buffer(size_t tb_size)
|
||||
{
|
||||
/* Size the buffer. */
|
||||
if (tb_size == 0) {
|
||||
size_t phys_mem = qemu_get_host_physmem();
|
||||
if (phys_mem == 0) {
|
||||
tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
|
||||
} else {
|
||||
tb_size = MIN(DEFAULT_CODE_GEN_BUFFER_SIZE, phys_mem / 8);
|
||||
}
|
||||
#ifdef USE_STATIC_CODE_GEN_BUFFER
|
||||
tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
|
||||
#else
|
||||
/* ??? Needs adjustments. */
|
||||
/* ??? If we relax the requirement that CONFIG_USER_ONLY use the
|
||||
static buffer, we could size this on RESERVED_VA, on the text
|
||||
segment size of the executable, or continue to use the default. */
|
||||
tb_size = (unsigned long)(ram_size / 4);
|
||||
#endif
|
||||
}
|
||||
if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) {
|
||||
tb_size = MIN_CODE_GEN_BUFFER_SIZE;
|
||||
@@ -1068,20 +1032,47 @@ static inline void *alloc_code_gen_buffer(void)
|
||||
{
|
||||
int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
|
||||
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
uintptr_t start = 0;
|
||||
size_t size = tcg_ctx->code_gen_buffer_size;
|
||||
void *buf;
|
||||
|
||||
buf = mmap(NULL, size, prot, flags, -1, 0);
|
||||
/* Constrain the position of the buffer based on the host cpu.
|
||||
Note that these addresses are chosen in concert with the
|
||||
addresses assigned in the relevant linker script file. */
|
||||
# if defined(__PIE__) || defined(__PIC__)
|
||||
/* Don't bother setting a preferred location if we're building
|
||||
a position-independent executable. We're more likely to get
|
||||
an address near the main executable if we let the kernel
|
||||
choose the address. */
|
||||
# elif defined(__x86_64__) && defined(MAP_32BIT)
|
||||
/* Force the memory down into low memory with the executable.
|
||||
Leave the choice of exact location with the kernel. */
|
||||
flags |= MAP_32BIT;
|
||||
/* Cannot expect to map more than 800MB in low memory. */
|
||||
if (size > 800u * 1024 * 1024) {
|
||||
tcg_ctx->code_gen_buffer_size = size = 800u * 1024 * 1024;
|
||||
}
|
||||
# elif defined(__sparc__)
|
||||
start = 0x40000000ul;
|
||||
# elif defined(__s390x__)
|
||||
start = 0x90000000ul;
|
||||
# elif defined(__mips__)
|
||||
# if _MIPS_SIM == _ABI64
|
||||
start = 0x128000000ul;
|
||||
# else
|
||||
start = 0x08000000ul;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
buf = mmap((void *)start, size, prot, flags, -1, 0);
|
||||
if (buf == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __mips__
|
||||
if (cross_256mb(buf, size)) {
|
||||
/*
|
||||
* Try again, with the original still mapped, to avoid re-acquiring
|
||||
* the same 256mb crossing.
|
||||
*/
|
||||
/* Try again, with the original still mapped, to avoid re-acquiring
|
||||
that 256mb crossing. This time don't specify an address. */
|
||||
size_t size2;
|
||||
void *buf2 = mmap(NULL, size, prot, flags, -1, 0);
|
||||
switch ((int)(buf2 != MAP_FAILED)) {
|
||||
@@ -1813,44 +1804,15 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) &&
|
||||
qemu_log_in_addr_range(tb->pc)) {
|
||||
FILE *logfile = qemu_log_lock();
|
||||
int code_size, data_size = 0;
|
||||
g_autoptr(GString) note = g_string_new("[tb header & initial instruction]");
|
||||
size_t chunk_start = 0;
|
||||
int insn = 0;
|
||||
qemu_log_lock();
|
||||
qemu_log("OUT: [size=%d]\n", gen_code_size);
|
||||
if (tcg_ctx->data_gen_ptr) {
|
||||
code_size = tcg_ctx->data_gen_ptr - tb->tc.ptr;
|
||||
data_size = gen_code_size - code_size;
|
||||
} else {
|
||||
code_size = gen_code_size;
|
||||
}
|
||||
size_t code_size = tcg_ctx->data_gen_ptr - tb->tc.ptr;
|
||||
size_t data_size = gen_code_size - code_size;
|
||||
size_t i;
|
||||
|
||||
/* Dump header and the first instruction */
|
||||
chunk_start = tcg_ctx->gen_insn_end_off[insn];
|
||||
log_disas(tb->tc.ptr, chunk_start, note->str);
|
||||
log_disas(tb->tc.ptr, code_size);
|
||||
|
||||
/*
|
||||
* Dump each instruction chunk, wrapping up empty chunks into
|
||||
* the next instruction. The whole array is offset so the
|
||||
* first entry is the beginning of the 2nd instruction.
|
||||
*/
|
||||
while (insn <= tb->icount && chunk_start < code_size) {
|
||||
size_t chunk_end = tcg_ctx->gen_insn_end_off[insn];
|
||||
if (chunk_end > chunk_start) {
|
||||
g_string_printf(note, "[guest addr: " TARGET_FMT_lx "]",
|
||||
tcg_ctx->gen_insn_data[insn][0]);
|
||||
log_disas(tb->tc.ptr + chunk_start, chunk_end - chunk_start,
|
||||
note->str);
|
||||
chunk_start = chunk_end;
|
||||
}
|
||||
insn++;
|
||||
}
|
||||
|
||||
/* Finally dump any data we may have after the block */
|
||||
if (data_size) {
|
||||
int i;
|
||||
qemu_log(" data: [size=%d]\n", data_size);
|
||||
for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {
|
||||
if (sizeof(tcg_target_ulong) == 8) {
|
||||
qemu_log("0x%08" PRIxPTR ": .quad 0x%016" PRIx64 "\n",
|
||||
@@ -1862,10 +1824,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
*(uint32_t *)(tcg_ctx->data_gen_ptr + i));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_disas(tb->tc.ptr, gen_code_size);
|
||||
}
|
||||
qemu_log("\n");
|
||||
qemu_log_flush();
|
||||
qemu_log_unlock(logfile);
|
||||
qemu_log_unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1906,7 +1870,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
|
||||
orig_aligned -= ROUND_UP(sizeof(*tb), qemu_icache_linesize);
|
||||
atomic_set(&tcg_ctx->code_gen_ptr, (void *)orig_aligned);
|
||||
tb_destroy(tb);
|
||||
return existing_tb;
|
||||
}
|
||||
tcg_tb_insert(tb);
|
||||
@@ -2256,7 +2219,6 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
||||
tb_phys_invalidate(tb->orig_tb, -1);
|
||||
}
|
||||
tcg_tb_remove(tb);
|
||||
tb_destroy(tb);
|
||||
}
|
||||
|
||||
/* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
|
||||
@@ -2551,7 +2513,9 @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
|
||||
/* This function should never be called with addresses outside the
|
||||
guest address space. If this assert fires, it probably indicates
|
||||
a missing call to h2g_valid. */
|
||||
assert(end - 1 <= GUEST_ADDR_MAX);
|
||||
#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
|
||||
assert(end <= ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
|
||||
#endif
|
||||
assert(start < end);
|
||||
assert_memory_lock();
|
||||
|
||||
@@ -2587,9 +2551,9 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
|
||||
/* This function should never be called with addresses outside the
|
||||
guest address space. If this assert fires, it probably indicates
|
||||
a missing call to h2g_valid. */
|
||||
if (TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS) {
|
||||
assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
|
||||
}
|
||||
#if TARGET_ABI_BITS > L1_MAP_ADDR_SPACE_BITS
|
||||
assert(start < ((target_ulong)1 << L1_MAP_ADDR_SPACE_BITS));
|
||||
#endif
|
||||
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
|
||||
@@ -138,11 +138,11 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
||||
&& qemu_log_in_addr_range(db->pc_first)) {
|
||||
FILE *logfile = qemu_log_lock();
|
||||
qemu_log_lock();
|
||||
qemu_log("----------------\n");
|
||||
ops->disas_log(db, cpu);
|
||||
qemu_log("\n");
|
||||
qemu_log_unlock(logfile);
|
||||
qemu_log_unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+14
-447
@@ -20,14 +20,12 @@
|
||||
#include "cpu.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "tcg.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "translate-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "qemu/atomic128.h"
|
||||
#include "trace-root.h"
|
||||
#include "trace/mem.h"
|
||||
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
@@ -190,12 +188,13 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static int probe_access_internal(CPUArchState *env, target_ulong addr,
|
||||
int fault_size, MMUAccessType access_type,
|
||||
bool nonfault, uintptr_t ra)
|
||||
void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
int flags;
|
||||
|
||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||
|
||||
switch (access_type) {
|
||||
case MMU_DATA_STORE:
|
||||
flags = PAGE_WRITE;
|
||||
@@ -210,39 +209,13 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!guest_addr_valid(addr) || page_check_range(addr, 1, flags) < 0) {
|
||||
if (nonfault) {
|
||||
return TLB_INVALID_MASK;
|
||||
} else {
|
||||
CPUState *cpu = env_cpu(env);
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
cc->tlb_fill(cpu, addr, fault_size, access_type,
|
||||
MMU_USER_IDX, false, ra);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (!guest_addr_valid(addr) || page_check_range(addr, size, flags) < 0) {
|
||||
CPUState *cpu = env_cpu(env);
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
cc->tlb_fill(cpu, addr, size, access_type, MMU_USER_IDX, false,
|
||||
retaddr);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int probe_access_flags(CPUArchState *env, target_ulong addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool nonfault, void **phost, uintptr_t ra)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = probe_access_internal(env, addr, 0, access_type, nonfault, ra);
|
||||
*phost = flags ? NULL : g2h(addr);
|
||||
return flags;
|
||||
}
|
||||
|
||||
void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
int flags;
|
||||
|
||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||
flags = probe_access_internal(env, addr, size, access_type, false, ra);
|
||||
g_assert(flags == 0);
|
||||
|
||||
return size ? g2h(addr) : NULL;
|
||||
}
|
||||
@@ -517,7 +490,6 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <ucontext.h>
|
||||
#include <sys/siginfo.h>
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
@@ -526,12 +498,10 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
siginfo_t *info = pinfo;
|
||||
#if defined(__NetBSD__)
|
||||
ucontext_t *uc = puc;
|
||||
siginfo_t *si = pinfo;
|
||||
#else
|
||||
ucontext_t *uc = puc;
|
||||
#endif
|
||||
unsigned long pc;
|
||||
uint32_t fsr;
|
||||
int is_write;
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
@@ -542,48 +512,15 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
pc = uc->uc_mcontext.arm_pc;
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
fsr = si->si_trap;
|
||||
#else
|
||||
fsr = uc->uc_mcontext.error_code;
|
||||
#endif
|
||||
/*
|
||||
* In the FSR, bit 11 is WnR, assuming a v6 or
|
||||
* later processor. On v5 we will always report
|
||||
* this as a read, which will fail later.
|
||||
/* error_code is the FSR value, in which bit 11 is WnR (assuming a v6 or
|
||||
* later processor; on v5 we will always report this as a read).
|
||||
*/
|
||||
is_write = extract32(fsr, 11, 1);
|
||||
is_write = extract32(uc->uc_mcontext.error_code, 11, 1);
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
|
||||
#include <ucontext.h>
|
||||
#include <sys/siginfo.h>
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
{
|
||||
ucontext_t *uc = puc;
|
||||
siginfo_t *si = pinfo;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
uint32_t esr;
|
||||
|
||||
pc = uc->uc_mcontext.__gregs[_REG_PC];
|
||||
esr = si->si_trap;
|
||||
|
||||
/*
|
||||
* siginfo_t::si_trap is the ESR value, for data aborts ESR.EC
|
||||
* is 0b10010x: then bit 6 is the WnR bit
|
||||
*/
|
||||
is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
|
||||
return handle_cpu_signal(pc, si, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifndef ESR_MAGIC
|
||||
/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
|
||||
#define ESR_MAGIC 0x45535201
|
||||
@@ -646,7 +583,6 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
}
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
@@ -798,375 +734,6 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
|
||||
/* The softmmu versions of these helpers are in cputlb.c. */
|
||||
|
||||
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_UB, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldub_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
int ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_SB, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldsb_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = lduw_be_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
int ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_BESW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldsw_be_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldl_be_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint64_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldq_be_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = lduw_le_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
int ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_LESW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldsw_le_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldl_le_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint64_t ret;
|
||||
uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldq_le_p(g2h(ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldub_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldsb_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_lduw_be_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldsw_be_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldl_be_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldq_be_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_lduw_le_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldsw_le_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldl_le_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t retaddr)
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
set_helper_retaddr(retaddr);
|
||||
ret = cpu_ldq_le_data(env, ptr);
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_UB, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stb_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stw_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stw_be_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stl_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stl_be_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stq_be_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stq_be_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stw_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stw_le_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stl_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stl_le_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stq_le_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
|
||||
{
|
||||
uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stq_le_p(g2h(ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
void cpu_stb_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stb_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stw_be_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stl_be_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint64_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stq_be_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stw_le_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint32_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stl_le_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr ptr,
|
||||
uint64_t val, uintptr_t retaddr)
|
||||
{
|
||||
set_helper_retaddr(retaddr);
|
||||
cpu_stq_le_data(env, ptr, val);
|
||||
clear_helper_retaddr();
|
||||
}
|
||||
|
||||
uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldub_p(g2h(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = lduw_p(g2h(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldl_p(g2h(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr)
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldq_p(g2h(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Do not allow unaligned operations to proceed. Return the host address. */
|
||||
static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
int size, uintptr_t retaddr)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
obj-y += xen-all.o
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/audio/soundhw.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -76,8 +77,6 @@ int graphic_depth = 32;
|
||||
#define QEMU_ARCH QEMU_ARCH_PPC
|
||||
#elif defined(TARGET_RISCV)
|
||||
#define QEMU_ARCH QEMU_ARCH_RISCV
|
||||
#elif defined(TARGET_RX)
|
||||
#define QEMU_ARCH QEMU_ARCH_RX
|
||||
#elif defined(TARGET_S390X)
|
||||
#define QEMU_ARCH QEMU_ARCH_S390X
|
||||
#elif defined(TARGET_SH4)
|
||||
@@ -90,8 +89,6 @@ int graphic_depth = 32;
|
||||
#define QEMU_ARCH QEMU_ARCH_UNICORE32
|
||||
#elif defined(TARGET_XTENSA)
|
||||
#define QEMU_ARCH QEMU_ARCH_XTENSA
|
||||
#elif defined(TARGET_AVR)
|
||||
#define QEMU_ARCH QEMU_ARCH_AVR
|
||||
#endif
|
||||
|
||||
const uint32_t arch_type = QEMU_ARCH;
|
||||
@@ -28,8 +28,3 @@ common-obj-$(CONFIG_AUDIO_SDL) += sdl.mo
|
||||
sdl.mo-objs = sdlaudio.o
|
||||
sdl.mo-cflags := $(SDL_CFLAGS)
|
||||
sdl.mo-libs := $(SDL_LIBS)
|
||||
|
||||
# jack module
|
||||
common-obj-$(CONFIG_AUDIO_JACK) += jack.mo
|
||||
jack.mo-objs = jackaudio.o
|
||||
jack.mo-libs := $(JACK_LIBS)
|
||||
+2
-20
@@ -307,13 +307,6 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
|
||||
return SND_PCM_FORMAT_U32_LE;
|
||||
}
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_FLOAT_BE;
|
||||
} else {
|
||||
return SND_PCM_FORMAT_FLOAT_LE;
|
||||
}
|
||||
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||
#ifdef DEBUG_AUDIO
|
||||
@@ -377,16 +370,6 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
|
||||
*fmt = AUDIO_FORMAT_U32;
|
||||
break;
|
||||
|
||||
case SND_PCM_FORMAT_FLOAT_LE:
|
||||
*endianness = 0;
|
||||
*fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
case SND_PCM_FORMAT_FLOAT_BE:
|
||||
*endianness = 1;
|
||||
*fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
default:
|
||||
dolog ("Unrecognized audio format %d\n", alsafmt);
|
||||
return -1;
|
||||
@@ -819,7 +802,7 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len)
|
||||
switch (nread) {
|
||||
case 0:
|
||||
trace_alsa_read_zero(len);
|
||||
return pos;
|
||||
return pos;;
|
||||
|
||||
case -EPIPE:
|
||||
if (alsa_recover(alsa->handle)) {
|
||||
@@ -835,7 +818,7 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len)
|
||||
default:
|
||||
alsa_logerr(nread, "Failed to read %zu frames to %p\n",
|
||||
len, dst);
|
||||
return pos;
|
||||
return pos;;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,7 +906,6 @@ static struct audio_pcm_ops alsa_pcm_ops = {
|
||||
.init_out = alsa_init_out,
|
||||
.fini_out = alsa_fini_out,
|
||||
.write = alsa_write,
|
||||
.run_buffer_out = audio_generic_run_buffer_out,
|
||||
.enable_out = alsa_enable_out,
|
||||
|
||||
.init_in = alsa_init_in,
|
||||
|
||||
+67
-82
@@ -218,9 +218,6 @@ static void audio_print_settings (struct audsettings *as)
|
||||
case AUDIO_FORMAT_U32:
|
||||
AUD_log (NULL, "U32");
|
||||
break;
|
||||
case AUDIO_FORMAT_F32:
|
||||
AUD_log (NULL, "F32");
|
||||
break;
|
||||
default:
|
||||
AUD_log (NULL, "invalid(%d)", as->fmt);
|
||||
break;
|
||||
@@ -255,7 +252,6 @@ static int audio_validate_settings (struct audsettings *as)
|
||||
case AUDIO_FORMAT_U16:
|
||||
case AUDIO_FORMAT_S32:
|
||||
case AUDIO_FORMAT_U32:
|
||||
case AUDIO_FORMAT_F32:
|
||||
break;
|
||||
default:
|
||||
invalid = 1;
|
||||
@@ -268,28 +264,24 @@ static int audio_validate_settings (struct audsettings *as)
|
||||
|
||||
static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
|
||||
{
|
||||
int bits = 8;
|
||||
bool is_signed = false, is_float = false;
|
||||
int bits = 8, sign = 0;
|
||||
|
||||
switch (as->fmt) {
|
||||
case AUDIO_FORMAT_S8:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U8:
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_S16:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U16:
|
||||
bits = 16;
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
is_float = true;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_S32:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U32:
|
||||
bits = 32;
|
||||
@@ -300,38 +292,32 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
|
||||
}
|
||||
return info->freq == as->freq
|
||||
&& info->nchannels == as->nchannels
|
||||
&& info->is_signed == is_signed
|
||||
&& info->is_float == is_float
|
||||
&& info->sign == sign
|
||||
&& info->bits == bits
|
||||
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
|
||||
}
|
||||
|
||||
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
||||
{
|
||||
int bits = 8, mul;
|
||||
bool is_signed = false, is_float = false;
|
||||
int bits = 8, sign = 0, mul;
|
||||
|
||||
switch (as->fmt) {
|
||||
case AUDIO_FORMAT_S8:
|
||||
is_signed = true;
|
||||
/* fall through */
|
||||
sign = 1;
|
||||
case AUDIO_FORMAT_U8:
|
||||
mul = 1;
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_S16:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U16:
|
||||
bits = 16;
|
||||
mul = 2;
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
is_float = true;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_S32:
|
||||
is_signed = true;
|
||||
sign = 1;
|
||||
/* fall through */
|
||||
case AUDIO_FORMAT_U32:
|
||||
bits = 32;
|
||||
@@ -344,8 +330,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
||||
|
||||
info->freq = as->freq;
|
||||
info->bits = bits;
|
||||
info->is_signed = is_signed;
|
||||
info->is_float = is_float;
|
||||
info->sign = sign;
|
||||
info->nchannels = as->nchannels;
|
||||
info->bytes_per_frame = as->nchannels * mul;
|
||||
info->bytes_per_second = info->freq * info->bytes_per_frame;
|
||||
@@ -358,7 +343,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->is_signed || info->is_float) {
|
||||
if (info->sign) {
|
||||
memset(buf, 0x00, len * info->bytes_per_frame);
|
||||
}
|
||||
else {
|
||||
@@ -649,7 +634,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||
total += isamp;
|
||||
}
|
||||
|
||||
if (hw->pcm_ops && !hw->pcm_ops->volume_in) {
|
||||
if (!hw->pcm_ops->volume_in) {
|
||||
mixeng_volume (sw->buf, ret, &sw->vol);
|
||||
}
|
||||
|
||||
@@ -736,7 +721,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||
if (swlim) {
|
||||
sw->conv (sw->buf, buf, swlim);
|
||||
|
||||
if (sw->hw->pcm_ops && !sw->hw->pcm_ops->volume_out) {
|
||||
if (!sw->hw->pcm_ops->volume_out) {
|
||||
mixeng_volume (sw->buf, swlim, &sw->vol);
|
||||
}
|
||||
}
|
||||
@@ -784,9 +769,8 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||
#ifdef DEBUG_AUDIO
|
||||
static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
|
||||
{
|
||||
dolog("%s: bits %d, sign %d, float %d, freq %d, nchan %d\n",
|
||||
cap, info->bits, info->is_signed, info->is_float, info->freq,
|
||||
info->nchannels);
|
||||
dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
|
||||
cap, info->bits, info->sign, info->freq, info->nchannels);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -894,9 +878,9 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
int AUD_get_buffer_size_out(SWVoiceOut *sw)
|
||||
int AUD_get_buffer_size_out (SWVoiceOut *sw)
|
||||
{
|
||||
return sw->hw->samples * sw->hw->info.bytes_per_frame;
|
||||
return sw->hw->mix_buf->size * sw->hw->info.bytes_per_frame;
|
||||
}
|
||||
|
||||
void AUD_set_active_out (SWVoiceOut *sw, int on)
|
||||
@@ -1091,8 +1075,10 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
||||
while (live) {
|
||||
size_t size, decr, proc;
|
||||
void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
|
||||
if (!buf || size == 0) {
|
||||
break;
|
||||
if (!buf) {
|
||||
/* retrying will likely won't help, drop everything. */
|
||||
hw->mix_buf->pos = (hw->mix_buf->pos + live) % hw->mix_buf->size;
|
||||
return clipped + live;
|
||||
}
|
||||
|
||||
decr = MIN(size / hw->info.bytes_per_frame, live);
|
||||
@@ -1110,10 +1096,6 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
||||
}
|
||||
}
|
||||
|
||||
if (hw->pcm_ops->run_buffer_out) {
|
||||
hw->pcm_ops->run_buffer_out(hw);
|
||||
}
|
||||
|
||||
return clipped;
|
||||
}
|
||||
|
||||
@@ -1420,8 +1402,7 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||
}
|
||||
assert(start >= 0 && start < hw->size_emul);
|
||||
|
||||
*size = MIN(*size, hw->pending_emul);
|
||||
*size = MIN(*size, hw->size_emul - start);
|
||||
*size = MIN(hw->pending_emul, hw->size_emul - start);
|
||||
return hw->buf_emul + start;
|
||||
}
|
||||
|
||||
@@ -1431,28 +1412,6 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
|
||||
hw->pending_emul -= size;
|
||||
}
|
||||
|
||||
void audio_generic_run_buffer_out(HWVoiceOut *hw)
|
||||
{
|
||||
while (hw->pending_emul) {
|
||||
size_t write_len, written;
|
||||
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
|
||||
|
||||
if (start < 0) {
|
||||
start += hw->size_emul;
|
||||
}
|
||||
assert(start >= 0 && start < hw->size_emul);
|
||||
|
||||
write_len = MIN(hw->pending_emul, hw->size_emul - start);
|
||||
|
||||
written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
|
||||
hw->pending_emul -= written;
|
||||
|
||||
if (written < write_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
{
|
||||
if (unlikely(!hw->buf_emul)) {
|
||||
@@ -1468,7 +1427,8 @@ void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
return hw->buf_emul + hw->pos_emul;
|
||||
}
|
||||
|
||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||
size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
|
||||
size_t size)
|
||||
{
|
||||
assert(buf == hw->buf_emul + hw->pos_emul &&
|
||||
size + hw->pending_emul <= hw->size_emul);
|
||||
@@ -1479,6 +1439,35 @@ size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||
{
|
||||
audio_generic_put_buffer_out_nowrite(hw, buf, size);
|
||||
|
||||
while (hw->pending_emul) {
|
||||
size_t write_len, written;
|
||||
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
|
||||
if (start < 0) {
|
||||
start += hw->size_emul;
|
||||
}
|
||||
assert(start >= 0 && start < hw->size_emul);
|
||||
|
||||
write_len = MIN(hw->pending_emul, hw->size_emul - start);
|
||||
|
||||
written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
|
||||
hw->pending_emul -= written;
|
||||
|
||||
if (written < write_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fake we have written everything. non-written data remain in pending_emul,
|
||||
* so we do not have to clip them multiple times
|
||||
*/
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
||||
{
|
||||
size_t dst_size, copy_size;
|
||||
@@ -1486,19 +1475,21 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
||||
copy_size = MIN(size, dst_size);
|
||||
|
||||
memcpy(dst, buf, copy_size);
|
||||
return hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
|
||||
return hw->pcm_ops->put_buffer_out(hw, buf, copy_size);
|
||||
}
|
||||
|
||||
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
|
||||
{
|
||||
void *src = hw->pcm_ops->get_buffer_in(hw, &size);
|
||||
size_t dst_size, copy_size;
|
||||
void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size);
|
||||
copy_size = MIN(size, dst_size);
|
||||
|
||||
memcpy(buf, src, size);
|
||||
hw->pcm_ops->put_buffer_in(hw, src, size);
|
||||
|
||||
return size;
|
||||
memcpy(dst, buf, copy_size);
|
||||
hw->pcm_ops->put_buffer_in(hw, buf, copy_size);
|
||||
return copy_size;
|
||||
}
|
||||
|
||||
|
||||
static int audio_driver_init(AudioState *s, struct audio_driver *drv,
|
||||
bool msg, Audiodev *dev)
|
||||
{
|
||||
@@ -1747,7 +1738,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
|
||||
if (dev->timer_period <= 0) {
|
||||
s->period_ticks = 1;
|
||||
} else {
|
||||
s->period_ticks = dev->timer_period * (int64_t)SCALE_US;
|
||||
s->period_ticks = dev->timer_period * SCALE_US;
|
||||
}
|
||||
|
||||
e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
|
||||
@@ -1845,15 +1836,11 @@ CaptureVoiceOut *AUD_add_capture(
|
||||
|
||||
cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
|
||||
|
||||
if (hw->info.is_float) {
|
||||
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
||||
} else {
|
||||
hw->clip = mixeng_clip
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.is_signed]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index(hw->info.bits)];
|
||||
}
|
||||
hw->clip = mixeng_clip
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.sign]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index (hw->info.bits)];
|
||||
|
||||
QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
|
||||
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||
@@ -1969,7 +1956,6 @@ void audio_create_pdos(Audiodev *dev)
|
||||
CASE(ALSA, alsa, Alsa);
|
||||
CASE(COREAUDIO, coreaudio, Coreaudio);
|
||||
CASE(DSOUND, dsound, );
|
||||
CASE(JACK, jack, Jack);
|
||||
CASE(OSS, oss, Oss);
|
||||
CASE(PA, pa, Pa);
|
||||
CASE(SDL, sdl, );
|
||||
@@ -2093,7 +2079,6 @@ int audioformat_bytes_per_sample(AudioFormat fmt)
|
||||
|
||||
case AUDIO_FORMAT_U32:
|
||||
case AUDIO_FORMAT_S32:
|
||||
case AUDIO_FORMAT_F32:
|
||||
return 4;
|
||||
|
||||
case AUDIO_FORMAT__MAX:
|
||||
|
||||
+2
-2
@@ -60,7 +60,7 @@ typedef enum {
|
||||
|
||||
struct audio_capture_ops {
|
||||
void (*notify) (void *opaque, audcnotification_e cmd);
|
||||
void (*capture) (void *opaque, const void *buf, int size);
|
||||
void (*capture) (void *opaque, void *buf, int size);
|
||||
void (*destroy) (void *opaque);
|
||||
};
|
||||
|
||||
@@ -163,7 +163,7 @@ int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
|
||||
bool audio_is_cleaning_up(void);
|
||||
void audio_cleanup(void);
|
||||
|
||||
void audio_sample_to_uint64(const void *samples, int pos,
|
||||
void audio_sample_to_uint64(void *samples, int pos,
|
||||
uint64_t *left, uint64_t *right);
|
||||
void audio_sample_from_uint64(void *samples, int pos,
|
||||
uint64_t left, uint64_t right);
|
||||
|
||||
+3
-4
@@ -40,8 +40,7 @@ struct audio_callback {
|
||||
|
||||
struct audio_pcm_info {
|
||||
int bits;
|
||||
bool is_signed;
|
||||
bool is_float;
|
||||
int sign;
|
||||
int freq;
|
||||
int nchannels;
|
||||
int bytes_per_frame;
|
||||
@@ -153,7 +152,6 @@ struct audio_pcm_ops {
|
||||
int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
|
||||
void (*fini_out)(HWVoiceOut *hw);
|
||||
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
|
||||
void (*run_buffer_out)(HWVoiceOut *hw);
|
||||
/*
|
||||
* get a buffer that after later can be passed to put_buffer_out; optional
|
||||
* returns the buffer, and writes it's size to size (in bytes)
|
||||
@@ -180,9 +178,10 @@ struct audio_pcm_ops {
|
||||
|
||||
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
|
||||
void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
|
||||
void audio_generic_run_buffer_out(HWVoiceOut *hw);
|
||||
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
|
||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
|
||||
size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
|
||||
size_t size);
|
||||
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
|
||||
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
|
||||
|
||||
|
||||
+5
-10
@@ -421,12 +421,11 @@ typedef struct {
|
||||
GList *path;
|
||||
} LegacyPrintVisitor;
|
||||
|
||||
static bool lv_start_struct(Visitor *v, const char *name, void **obj,
|
||||
static void lv_start_struct(Visitor *v, const char *name, void **obj,
|
||||
size_t size, Error **errp)
|
||||
{
|
||||
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
|
||||
lv->path = g_list_append(lv->path, g_strdup(name));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lv_end_struct(Visitor *v, void **obj)
|
||||
@@ -454,30 +453,27 @@ static void lv_print_key(Visitor *v, const char *name)
|
||||
printf("%s=", name);
|
||||
}
|
||||
|
||||
static bool lv_type_int64(Visitor *v, const char *name, int64_t *obj,
|
||||
static void lv_type_int64(Visitor *v, const char *name, int64_t *obj,
|
||||
Error **errp)
|
||||
{
|
||||
lv_print_key(v, name);
|
||||
printf("%" PRIi64, *obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lv_type_uint64(Visitor *v, const char *name, uint64_t *obj,
|
||||
static void lv_type_uint64(Visitor *v, const char *name, uint64_t *obj,
|
||||
Error **errp)
|
||||
{
|
||||
lv_print_key(v, name);
|
||||
printf("%" PRIu64, *obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
|
||||
static void lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
|
||||
{
|
||||
lv_print_key(v, name);
|
||||
printf("%s", *obj ? "on" : "off");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
|
||||
static void lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
|
||||
{
|
||||
const char *str = *obj;
|
||||
lv_print_key(v, name);
|
||||
@@ -488,7 +484,6 @@ static bool lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
|
||||
}
|
||||
putchar(*str++);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lv_complete(Visitor *v, void *opaque)
|
||||
|
||||
+12
-30
@@ -153,23 +153,15 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
||||
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
||||
#endif
|
||||
|
||||
if (sw->info.is_float) {
|
||||
#ifdef DAC
|
||||
sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
|
||||
sw->conv = mixeng_conv
|
||||
#else
|
||||
sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
|
||||
sw->clip = mixeng_clip
|
||||
#endif
|
||||
} else {
|
||||
#ifdef DAC
|
||||
sw->conv = mixeng_conv
|
||||
#else
|
||||
sw->clip = mixeng_clip
|
||||
#endif
|
||||
[sw->info.nchannels == 2]
|
||||
[sw->info.is_signed]
|
||||
[sw->info.swap_endianness]
|
||||
[audio_bits_to_index(sw->info.bits)];
|
||||
}
|
||||
[sw->info.nchannels == 2]
|
||||
[sw->info.sign]
|
||||
[sw->info.swap_endianness]
|
||||
[audio_bits_to_index (sw->info.bits)];
|
||||
|
||||
sw->name = g_strdup (name);
|
||||
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
|
||||
@@ -284,23 +276,15 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (hw->info.is_float) {
|
||||
#ifdef DAC
|
||||
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
||||
hw->clip = mixeng_clip
|
||||
#else
|
||||
hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
|
||||
hw->conv = mixeng_conv
|
||||
#endif
|
||||
} else {
|
||||
#ifdef DAC
|
||||
hw->clip = mixeng_clip
|
||||
#else
|
||||
hw->conv = mixeng_conv
|
||||
#endif
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.is_signed]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index(hw->info.bits)];
|
||||
}
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.sign]
|
||||
[hw->info.swap_endianness]
|
||||
[audio_bits_to_index (hw->info.bits)];
|
||||
|
||||
glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
|
||||
|
||||
@@ -330,8 +314,6 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
||||
dev->u.coreaudio.TYPE);
|
||||
case AUDIODEV_DRIVER_DSOUND:
|
||||
return dev->u.dsound.TYPE;
|
||||
case AUDIODEV_DRIVER_JACK:
|
||||
return qapi_AudiodevJackPerDirectionOptions_base(dev->u.jack.TYPE);
|
||||
case AUDIODEV_DRIVER_OSS:
|
||||
return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE);
|
||||
case AUDIODEV_DRIVER_PA:
|
||||
|
||||
+25
-9
@@ -411,7 +411,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
|
||||
}
|
||||
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||
(hw, size))
|
||||
COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
|
||||
COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
|
||||
(HWVoiceOut *hw, void *buf, size_t size),
|
||||
(hw, buf, size))
|
||||
COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
|
||||
@@ -471,6 +471,20 @@ static OSStatus audioDeviceIOProc(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UInt32 coreaudio_get_flags(struct audio_pcm_info *info,
|
||||
struct audsettings *as)
|
||||
{
|
||||
UInt32 flags = info->sign ? kAudioFormatFlagIsSignedInteger : 0;
|
||||
if (as->endianness) { /* 0 = little, 1 = big */
|
||||
flags |= kAudioFormatFlagIsBigEndian;
|
||||
}
|
||||
|
||||
if (flags == 0) { /* must not be 0 */
|
||||
flags = kAudioFormatFlagsAreAllClear;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
void *drv_opaque)
|
||||
{
|
||||
@@ -482,7 +496,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
Audiodev *dev = drv_opaque;
|
||||
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
|
||||
int frames;
|
||||
struct audsettings fake_as;
|
||||
|
||||
/* create mutex */
|
||||
err = pthread_mutex_init(&core->mutex, NULL);
|
||||
@@ -491,9 +504,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
return -1;
|
||||
}
|
||||
|
||||
fake_as = *as;
|
||||
as = &fake_as;
|
||||
as->fmt = AUDIO_FORMAT_F32;
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
|
||||
status = coreaudio_get_voice(&core->outputDeviceID);
|
||||
@@ -562,6 +572,15 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
|
||||
/* set Samplerate */
|
||||
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
||||
core->outputStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
|
||||
core->outputStreamBasicDescription.mFormatFlags =
|
||||
coreaudio_get_flags(&hw->info, as);
|
||||
core->outputStreamBasicDescription.mBytesPerPacket =
|
||||
core->outputStreamBasicDescription.mBytesPerFrame =
|
||||
hw->info.nchannels * hw->info.bits / 8;
|
||||
core->outputStreamBasicDescription.mFramesPerPacket = 1;
|
||||
core->outputStreamBasicDescription.mChannelsPerFrame = hw->info.nchannels;
|
||||
core->outputStreamBasicDescription.mBitsPerChannel = hw->info.bits;
|
||||
|
||||
status = coreaudio_set_streamformat(core->outputDeviceID,
|
||||
&core->outputStreamBasicDescription);
|
||||
@@ -668,12 +687,9 @@ static void coreaudio_audio_fini (void *opaque)
|
||||
static struct audio_pcm_ops coreaudio_pcm_ops = {
|
||||
.init_out = coreaudio_init_out,
|
||||
.fini_out = coreaudio_fini_out,
|
||||
/* wrapper for audio_generic_write */
|
||||
.write = coreaudio_write,
|
||||
/* wrapper for audio_generic_get_buffer_out */
|
||||
.get_buffer_out = coreaudio_get_buffer_out,
|
||||
/* wrapper for audio_generic_put_buffer_out */
|
||||
.put_buffer_out = coreaudio_put_buffer_out,
|
||||
.put_buffer_out = coreaudio_put_buffer_out_nowrite,
|
||||
.enable_out = coreaudio_enable_out
|
||||
};
|
||||
|
||||
|
||||
@@ -244,7 +244,6 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
ds->first_time = true;
|
||||
obt_as.endianness = 0;
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
|
||||
|
||||
+6
-30
@@ -53,14 +53,12 @@ typedef struct {
|
||||
typedef struct {
|
||||
HWVoiceOut hw;
|
||||
LPDIRECTSOUNDBUFFER dsound_buffer;
|
||||
bool first_time;
|
||||
dsound *s;
|
||||
} DSoundVoiceOut;
|
||||
|
||||
typedef struct {
|
||||
HWVoiceIn hw;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
|
||||
bool first_time;
|
||||
dsound *s;
|
||||
} DSoundVoiceIn;
|
||||
|
||||
@@ -279,7 +277,7 @@ static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*statusp & DSBSTATUS_BUFFERLOST) {
|
||||
if (*statusp & DSERR_BUFFERLOST) {
|
||||
dsound_restore_out(dsb, s);
|
||||
return -1;
|
||||
}
|
||||
@@ -416,32 +414,21 @@ static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
||||
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
||||
HRESULT hr;
|
||||
DWORD ppos, wpos, act_size;
|
||||
DWORD ppos, act_size;
|
||||
size_t req_size;
|
||||
int err;
|
||||
void *ret;
|
||||
|
||||
hr = IDirectSoundBuffer_GetCurrentPosition(
|
||||
dsb, &ppos, ds->first_time ? &wpos : NULL);
|
||||
hr = IDirectSoundBuffer_GetCurrentPosition(dsb, &ppos, NULL);
|
||||
if (FAILED(hr)) {
|
||||
dsound_logerr(hr, "Could not get playback buffer position\n");
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ds->first_time) {
|
||||
hw->pos_emul = wpos;
|
||||
ds->first_time = false;
|
||||
}
|
||||
|
||||
req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
|
||||
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
||||
|
||||
if (req_size == 0) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
|
||||
&act_size, NULL, false, ds->s);
|
||||
if (err) {
|
||||
@@ -521,31 +508,20 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
||||
HRESULT hr;
|
||||
DWORD cpos, rpos, act_size;
|
||||
DWORD cpos, act_size;
|
||||
size_t req_size;
|
||||
int err;
|
||||
void *ret;
|
||||
|
||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
|
||||
dscb, &cpos, ds->first_time ? &rpos : NULL);
|
||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, &cpos, NULL);
|
||||
if (FAILED(hr)) {
|
||||
dsound_logerr(hr, "Could not get capture buffer position\n");
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ds->first_time) {
|
||||
hw->pos_emul = rpos;
|
||||
ds->first_time = false;
|
||||
}
|
||||
|
||||
req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
|
||||
req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul));
|
||||
|
||||
if (req_size == 0) {
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
||||
|
||||
err = dsound_lock_in(dscb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
|
||||
&act_size, NULL, false, ds->s);
|
||||
|
||||
@@ -1,670 +0,0 @@
|
||||
/*
|
||||
* QEMU JACK Audio Connection Kit Client
|
||||
*
|
||||
* Copyright (c) 2020 Geoffrey McRae (gnif)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
|
||||
#define AUDIO_CAP "jack"
|
||||
#include "audio_int.h"
|
||||
|
||||
#include <jack/jack.h>
|
||||
#include <jack/thread.h>
|
||||
|
||||
struct QJack;
|
||||
|
||||
typedef enum QJackState {
|
||||
QJACK_STATE_DISCONNECTED,
|
||||
QJACK_STATE_RUNNING,
|
||||
QJACK_STATE_SHUTDOWN
|
||||
}
|
||||
QJackState;
|
||||
|
||||
typedef struct QJackBuffer {
|
||||
int channels;
|
||||
int frames;
|
||||
uint32_t used;
|
||||
int rptr, wptr;
|
||||
float **data;
|
||||
}
|
||||
QJackBuffer;
|
||||
|
||||
typedef struct QJackClient {
|
||||
AudiodevJackPerDirectionOptions *opt;
|
||||
|
||||
bool out;
|
||||
bool enabled;
|
||||
bool connect_ports;
|
||||
int packets;
|
||||
|
||||
QJackState state;
|
||||
jack_client_t *client;
|
||||
jack_nframes_t freq;
|
||||
|
||||
struct QJack *j;
|
||||
int nchannels;
|
||||
int buffersize;
|
||||
jack_port_t **port;
|
||||
QJackBuffer fifo;
|
||||
}
|
||||
QJackClient;
|
||||
|
||||
typedef struct QJackOut {
|
||||
HWVoiceOut hw;
|
||||
QJackClient c;
|
||||
}
|
||||
QJackOut;
|
||||
|
||||
typedef struct QJackIn {
|
||||
HWVoiceIn hw;
|
||||
QJackClient c;
|
||||
}
|
||||
QJackIn;
|
||||
|
||||
static int qjack_client_init(QJackClient *c);
|
||||
static void qjack_client_connect_ports(QJackClient *c);
|
||||
static void qjack_client_fini(QJackClient *c);
|
||||
|
||||
static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames)
|
||||
{
|
||||
buffer->channels = channels;
|
||||
buffer->frames = frames;
|
||||
buffer->used = 0;
|
||||
buffer->rptr = 0;
|
||||
buffer->wptr = 0;
|
||||
buffer->data = g_malloc(channels * sizeof(float *));
|
||||
for (int i = 0; i < channels; ++i) {
|
||||
buffer->data[i] = g_malloc(frames * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
static void qjack_buffer_clear(QJackBuffer *buffer)
|
||||
{
|
||||
assert(buffer->data);
|
||||
atomic_store_release(&buffer->used, 0);
|
||||
buffer->rptr = 0;
|
||||
buffer->wptr = 0;
|
||||
}
|
||||
|
||||
static void qjack_buffer_free(QJackBuffer *buffer)
|
||||
{
|
||||
if (!buffer->data) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < buffer->channels; ++i) {
|
||||
g_free(buffer->data[i]);
|
||||
}
|
||||
|
||||
g_free(buffer->data);
|
||||
buffer->data = NULL;
|
||||
}
|
||||
|
||||
/* write PCM interleaved */
|
||||
static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size)
|
||||
{
|
||||
assert(buffer->data);
|
||||
const int samples = size / sizeof(float);
|
||||
int frames = samples / buffer->channels;
|
||||
const int avail = buffer->frames - atomic_load_acquire(&buffer->used);
|
||||
|
||||
if (frames > avail) {
|
||||
frames = avail;
|
||||
}
|
||||
|
||||
int copy = frames;
|
||||
int wptr = buffer->wptr;
|
||||
|
||||
while (copy) {
|
||||
|
||||
for (int c = 0; c < buffer->channels; ++c) {
|
||||
buffer->data[c][wptr] = *data++;
|
||||
}
|
||||
|
||||
if (++wptr == buffer->frames) {
|
||||
wptr = 0;
|
||||
}
|
||||
|
||||
--copy;
|
||||
}
|
||||
|
||||
buffer->wptr = wptr;
|
||||
|
||||
atomic_add(&buffer->used, frames);
|
||||
return frames * buffer->channels * sizeof(float);
|
||||
};
|
||||
|
||||
/* write PCM linear */
|
||||
static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames)
|
||||
{
|
||||
assert(buffer->data);
|
||||
const int avail = buffer->frames - atomic_load_acquire(&buffer->used);
|
||||
int wptr = buffer->wptr;
|
||||
|
||||
if (frames > avail) {
|
||||
frames = avail;
|
||||
}
|
||||
|
||||
int right = buffer->frames - wptr;
|
||||
if (right > frames) {
|
||||
right = frames;
|
||||
}
|
||||
|
||||
const int left = frames - right;
|
||||
for (int c = 0; c < buffer->channels; ++c) {
|
||||
memcpy(buffer->data[c] + wptr, dest[c] , right * sizeof(float));
|
||||
memcpy(buffer->data[c] , dest[c] + right, left * sizeof(float));
|
||||
}
|
||||
|
||||
wptr += frames;
|
||||
if (wptr >= buffer->frames) {
|
||||
wptr -= buffer->frames;
|
||||
}
|
||||
buffer->wptr = wptr;
|
||||
|
||||
atomic_add(&buffer->used, frames);
|
||||
return frames;
|
||||
}
|
||||
|
||||
/* read PCM interleaved */
|
||||
static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size)
|
||||
{
|
||||
assert(buffer->data);
|
||||
const int samples = size / sizeof(float);
|
||||
int frames = samples / buffer->channels;
|
||||
const int avail = atomic_load_acquire(&buffer->used);
|
||||
|
||||
if (frames > avail) {
|
||||
frames = avail;
|
||||
}
|
||||
|
||||
int copy = frames;
|
||||
int rptr = buffer->rptr;
|
||||
|
||||
while (copy) {
|
||||
|
||||
for (int c = 0; c < buffer->channels; ++c) {
|
||||
*dest++ = buffer->data[c][rptr];
|
||||
}
|
||||
|
||||
if (++rptr == buffer->frames) {
|
||||
rptr = 0;
|
||||
}
|
||||
|
||||
--copy;
|
||||
}
|
||||
|
||||
buffer->rptr = rptr;
|
||||
|
||||
atomic_sub(&buffer->used, frames);
|
||||
return frames * buffer->channels * sizeof(float);
|
||||
}
|
||||
|
||||
/* read PCM linear */
|
||||
static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames)
|
||||
{
|
||||
assert(buffer->data);
|
||||
int copy = frames;
|
||||
const int used = atomic_load_acquire(&buffer->used);
|
||||
int rptr = buffer->rptr;
|
||||
|
||||
if (copy > used) {
|
||||
copy = used;
|
||||
}
|
||||
|
||||
int right = buffer->frames - rptr;
|
||||
if (right > copy) {
|
||||
right = copy;
|
||||
}
|
||||
|
||||
const int left = copy - right;
|
||||
for (int c = 0; c < buffer->channels; ++c) {
|
||||
memcpy(dest[c] , buffer->data[c] + rptr, right * sizeof(float));
|
||||
memcpy(dest[c] + right, buffer->data[c] , left * sizeof(float));
|
||||
}
|
||||
|
||||
rptr += copy;
|
||||
if (rptr >= buffer->frames) {
|
||||
rptr -= buffer->frames;
|
||||
}
|
||||
buffer->rptr = rptr;
|
||||
|
||||
atomic_sub(&buffer->used, copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
static int qjack_process(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
QJackClient *c = (QJackClient *)arg;
|
||||
|
||||
if (c->state != QJACK_STATE_RUNNING) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get the buffers for the ports */
|
||||
float *buffers[c->nchannels];
|
||||
for (int i = 0; i < c->nchannels; ++i) {
|
||||
buffers[i] = jack_port_get_buffer(c->port[i], nframes);
|
||||
}
|
||||
|
||||
if (c->out) {
|
||||
if (likely(c->enabled)) {
|
||||
qjack_buffer_read_l(&c->fifo, buffers, nframes);
|
||||
} else {
|
||||
for(int i = 0; i < c->nchannels; ++i) {
|
||||
memset(buffers[i], 0, nframes * sizeof(float));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (likely(c->enabled)) {
|
||||
qjack_buffer_write_l(&c->fifo, buffers, nframes);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qjack_port_registration(jack_port_id_t port, int reg, void *arg)
|
||||
{
|
||||
if (reg) {
|
||||
QJackClient *c = (QJackClient *)arg;
|
||||
c->connect_ports = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int qjack_xrun(void *arg)
|
||||
{
|
||||
QJackClient *c = (QJackClient *)arg;
|
||||
if (c->state != QJACK_STATE_RUNNING) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
qjack_buffer_clear(&c->fifo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qjack_shutdown(void *arg)
|
||||
{
|
||||
QJackClient *c = (QJackClient *)arg;
|
||||
c->state = QJACK_STATE_SHUTDOWN;
|
||||
}
|
||||
|
||||
static void qjack_client_recover(QJackClient *c)
|
||||
{
|
||||
if (c->state == QJACK_STATE_SHUTDOWN) {
|
||||
qjack_client_fini(c);
|
||||
}
|
||||
|
||||
/* packets is used simply to throttle this */
|
||||
if (c->state == QJACK_STATE_DISCONNECTED &&
|
||||
c->packets % 100 == 0) {
|
||||
|
||||
/* if enabled then attempt to recover */
|
||||
if (c->enabled) {
|
||||
dolog("attempting to reconnect to server\n");
|
||||
qjack_client_init(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static size_t qjack_write(HWVoiceOut *hw, void *buf, size_t len)
|
||||
{
|
||||
QJackOut *jo = (QJackOut *)hw;
|
||||
++jo->c.packets;
|
||||
|
||||
if (jo->c.state != QJACK_STATE_RUNNING) {
|
||||
qjack_client_recover(&jo->c);
|
||||
return len;
|
||||
}
|
||||
|
||||
qjack_client_connect_ports(&jo->c);
|
||||
return qjack_buffer_write(&jo->c.fifo, buf, len);
|
||||
}
|
||||
|
||||
static size_t qjack_read(HWVoiceIn *hw, void *buf, size_t len)
|
||||
{
|
||||
QJackIn *ji = (QJackIn *)hw;
|
||||
++ji->c.packets;
|
||||
|
||||
if (ji->c.state != QJACK_STATE_RUNNING) {
|
||||
qjack_client_recover(&ji->c);
|
||||
return len;
|
||||
}
|
||||
|
||||
qjack_client_connect_ports(&ji->c);
|
||||
return qjack_buffer_read(&ji->c.fifo, buf, len);
|
||||
}
|
||||
|
||||
static void qjack_client_connect_ports(QJackClient *c)
|
||||
{
|
||||
if (!c->connect_ports || !c->opt->connect_ports) {
|
||||
return;
|
||||
}
|
||||
|
||||
c->connect_ports = false;
|
||||
const char **ports;
|
||||
ports = jack_get_ports(c->client, c->opt->connect_ports, NULL,
|
||||
c->out ? JackPortIsInput : JackPortIsOutput);
|
||||
|
||||
if (!ports) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < c->nchannels && ports[i]; ++i) {
|
||||
const char *p = jack_port_name(c->port[i]);
|
||||
if (jack_port_connected_to(c->port[i], ports[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c->out) {
|
||||
dolog("connect %s -> %s\n", p, ports[i]);
|
||||
jack_connect(c->client, p, ports[i]);
|
||||
} else {
|
||||
dolog("connect %s -> %s\n", ports[i], p);
|
||||
jack_connect(c->client, ports[i], p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int qjack_client_init(QJackClient *c)
|
||||
{
|
||||
jack_status_t status;
|
||||
char client_name[jack_client_name_size()];
|
||||
jack_options_t options = JackNullOption;
|
||||
|
||||
if (c->state == QJACK_STATE_RUNNING) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->connect_ports = true;
|
||||
|
||||
snprintf(client_name, sizeof(client_name), "%s-%s",
|
||||
c->out ? "out" : "in",
|
||||
c->opt->client_name ? c->opt->client_name : qemu_get_vm_name());
|
||||
|
||||
if (c->opt->exact_name) {
|
||||
options |= JackUseExactName;
|
||||
}
|
||||
|
||||
if (!c->opt->start_server) {
|
||||
options |= JackNoStartServer;
|
||||
}
|
||||
|
||||
if (c->opt->server_name) {
|
||||
options |= JackServerName;
|
||||
}
|
||||
|
||||
c->client = jack_client_open(client_name, options, &status,
|
||||
c->opt->server_name);
|
||||
|
||||
if (c->client == NULL) {
|
||||
dolog("jack_client_open failed: status = 0x%2.0x\n", status);
|
||||
if (status & JackServerFailed) {
|
||||
dolog("unable to connect to JACK server\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->freq = jack_get_sample_rate(c->client);
|
||||
|
||||
if (status & JackServerStarted) {
|
||||
dolog("JACK server started\n");
|
||||
}
|
||||
|
||||
if (status & JackNameNotUnique) {
|
||||
dolog("JACK unique name assigned %s\n",
|
||||
jack_get_client_name(c->client));
|
||||
}
|
||||
|
||||
jack_set_process_callback(c->client, qjack_process , c);
|
||||
jack_set_port_registration_callback(c->client, qjack_port_registration, c);
|
||||
jack_set_xrun_callback(c->client, qjack_xrun, c);
|
||||
jack_on_shutdown(c->client, qjack_shutdown, c);
|
||||
|
||||
/* allocate and register the ports */
|
||||
c->port = g_malloc(sizeof(jack_port_t *) * c->nchannels);
|
||||
for (int i = 0; i < c->nchannels; ++i) {
|
||||
|
||||
char port_name[16];
|
||||
snprintf(
|
||||
port_name,
|
||||
sizeof(port_name),
|
||||
c->out ? "output %d" : "input %d",
|
||||
i);
|
||||
|
||||
c->port[i] = jack_port_register(
|
||||
c->client,
|
||||
port_name,
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
c->out ? JackPortIsOutput : JackPortIsInput,
|
||||
0);
|
||||
}
|
||||
|
||||
/* activate the session */
|
||||
jack_activate(c->client);
|
||||
c->buffersize = jack_get_buffer_size(c->client);
|
||||
|
||||
/*
|
||||
* ensure the buffersize is no smaller then 512 samples, some (all?) qemu
|
||||
* virtual devices do not work correctly otherwise
|
||||
*/
|
||||
if (c->buffersize < 512) {
|
||||
c->buffersize = 512;
|
||||
}
|
||||
|
||||
/* create a 2 period buffer */
|
||||
qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2);
|
||||
|
||||
qjack_client_connect_ports(c);
|
||||
c->state = QJACK_STATE_RUNNING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
void *drv_opaque)
|
||||
{
|
||||
QJackOut *jo = (QJackOut *)hw;
|
||||
Audiodev *dev = (Audiodev *)drv_opaque;
|
||||
|
||||
qjack_client_fini(&jo->c);
|
||||
|
||||
jo->c.out = true;
|
||||
jo->c.enabled = false;
|
||||
jo->c.nchannels = as->nchannels;
|
||||
jo->c.opt = dev->u.jack.out;
|
||||
|
||||
int ret = qjack_client_init(&jo->c);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* report the buffer size to qemu */
|
||||
hw->samples = jo->c.buffersize;
|
||||
|
||||
/* report the audio format we support */
|
||||
struct audsettings os = {
|
||||
.freq = jo->c.freq,
|
||||
.nchannels = jo->c.nchannels,
|
||||
.fmt = AUDIO_FORMAT_F32,
|
||||
.endianness = 0
|
||||
};
|
||||
audio_pcm_init_info(&hw->info, &os);
|
||||
|
||||
dolog("JACK output configured for %dHz (%d samples)\n",
|
||||
jo->c.freq, jo->c.buffersize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as,
|
||||
void *drv_opaque)
|
||||
{
|
||||
QJackIn *ji = (QJackIn *)hw;
|
||||
Audiodev *dev = (Audiodev *)drv_opaque;
|
||||
|
||||
qjack_client_fini(&ji->c);
|
||||
|
||||
ji->c.out = false;
|
||||
ji->c.enabled = false;
|
||||
ji->c.nchannels = as->nchannels;
|
||||
ji->c.opt = dev->u.jack.in;
|
||||
|
||||
int ret = qjack_client_init(&ji->c);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* report the buffer size to qemu */
|
||||
hw->samples = ji->c.buffersize;
|
||||
|
||||
/* report the audio format we support */
|
||||
struct audsettings is = {
|
||||
.freq = ji->c.freq,
|
||||
.nchannels = ji->c.nchannels,
|
||||
.fmt = AUDIO_FORMAT_F32,
|
||||
.endianness = 0
|
||||
};
|
||||
audio_pcm_init_info(&hw->info, &is);
|
||||
|
||||
dolog("JACK input configured for %dHz (%d samples)\n",
|
||||
ji->c.freq, ji->c.buffersize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qjack_client_fini(QJackClient *c)
|
||||
{
|
||||
switch (c->state) {
|
||||
case QJACK_STATE_RUNNING:
|
||||
jack_deactivate(c->client);
|
||||
/* fallthrough */
|
||||
|
||||
case QJACK_STATE_SHUTDOWN:
|
||||
jack_client_close(c->client);
|
||||
/* fallthrough */
|
||||
|
||||
case QJACK_STATE_DISCONNECTED:
|
||||
break;
|
||||
}
|
||||
|
||||
qjack_buffer_free(&c->fifo);
|
||||
g_free(c->port);
|
||||
|
||||
c->state = QJACK_STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
static void qjack_fini_out(HWVoiceOut *hw)
|
||||
{
|
||||
QJackOut *jo = (QJackOut *)hw;
|
||||
qjack_client_fini(&jo->c);
|
||||
}
|
||||
|
||||
static void qjack_fini_in(HWVoiceIn *hw)
|
||||
{
|
||||
QJackIn *ji = (QJackIn *)hw;
|
||||
qjack_client_fini(&ji->c);
|
||||
}
|
||||
|
||||
static void qjack_enable_out(HWVoiceOut *hw, bool enable)
|
||||
{
|
||||
QJackOut *jo = (QJackOut *)hw;
|
||||
jo->c.enabled = enable;
|
||||
}
|
||||
|
||||
static void qjack_enable_in(HWVoiceIn *hw, bool enable)
|
||||
{
|
||||
QJackIn *ji = (QJackIn *)hw;
|
||||
ji->c.enabled = enable;
|
||||
}
|
||||
|
||||
static int qjack_thread_creator(jack_native_thread_t *thread,
|
||||
const pthread_attr_t *attr, void *(*function)(void *), void *arg)
|
||||
{
|
||||
int ret = pthread_create(thread, attr, function, arg);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set the name of the thread */
|
||||
pthread_setname_np(*thread, "jack-client");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *qjack_init(Audiodev *dev)
|
||||
{
|
||||
assert(dev->driver == AUDIODEV_DRIVER_JACK);
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void qjack_fini(void *opaque)
|
||||
{
|
||||
}
|
||||
|
||||
static struct audio_pcm_ops jack_pcm_ops = {
|
||||
.init_out = qjack_init_out,
|
||||
.fini_out = qjack_fini_out,
|
||||
.write = qjack_write,
|
||||
.run_buffer_out = audio_generic_run_buffer_out,
|
||||
.enable_out = qjack_enable_out,
|
||||
|
||||
.init_in = qjack_init_in,
|
||||
.fini_in = qjack_fini_in,
|
||||
.read = qjack_read,
|
||||
.enable_in = qjack_enable_in
|
||||
};
|
||||
|
||||
static struct audio_driver jack_driver = {
|
||||
.name = "jack",
|
||||
.descr = "JACK Audio Connection Kit Client",
|
||||
.init = qjack_init,
|
||||
.fini = qjack_fini,
|
||||
.pcm_ops = &jack_pcm_ops,
|
||||
.can_be_default = 1,
|
||||
.max_voices_out = INT_MAX,
|
||||
.max_voices_in = INT_MAX,
|
||||
.voice_size_out = sizeof(QJackOut),
|
||||
.voice_size_in = sizeof(QJackIn)
|
||||
};
|
||||
|
||||
static void qjack_error(const char *msg)
|
||||
{
|
||||
dolog("E: %s\n", msg);
|
||||
}
|
||||
|
||||
static void qjack_info(const char *msg)
|
||||
{
|
||||
dolog("I: %s\n", msg);
|
||||
}
|
||||
|
||||
static void register_audio_jack(void)
|
||||
{
|
||||
audio_driver_register(&jack_driver);
|
||||
jack_set_thread_creator(qjack_thread_creator);
|
||||
jack_set_error_function(qjack_error);
|
||||
jack_set_info_function(qjack_info);
|
||||
}
|
||||
type_init(register_audio_jack);
|
||||
+2
-73
@@ -267,82 +267,11 @@ f_sample *mixeng_clip[2][2][2][3] = {
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef FLOAT_MIXENG
|
||||
#define CONV_NATURAL_FLOAT(x) (x)
|
||||
#define CLIP_NATURAL_FLOAT(x) (x)
|
||||
#else
|
||||
/* macros to map [-1.f, 1.f] <-> [INT32_MIN, INT32_MAX + 1] */
|
||||
static const float float_scale = (int64_t)INT32_MAX + 1;
|
||||
#define CONV_NATURAL_FLOAT(x) ((x) * float_scale)
|
||||
|
||||
#ifdef RECIPROCAL
|
||||
static const float float_scale_reciprocal = 1.f / ((int64_t)INT32_MAX + 1);
|
||||
#define CLIP_NATURAL_FLOAT(x) ((x) * float_scale_reciprocal)
|
||||
#else
|
||||
#define CLIP_NATURAL_FLOAT(x) ((x) / float_scale)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void conv_natural_float_to_mono(struct st_sample *dst, const void *src,
|
||||
int samples)
|
||||
{
|
||||
float *in = (float *)src;
|
||||
|
||||
while (samples--) {
|
||||
dst->r = dst->l = CONV_NATURAL_FLOAT(*in++);
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src,
|
||||
int samples)
|
||||
{
|
||||
float *in = (float *)src;
|
||||
|
||||
while (samples--) {
|
||||
dst->l = CONV_NATURAL_FLOAT(*in++);
|
||||
dst->r = CONV_NATURAL_FLOAT(*in++);
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
t_sample *mixeng_conv_float[2] = {
|
||||
conv_natural_float_to_mono,
|
||||
conv_natural_float_to_stereo,
|
||||
};
|
||||
|
||||
static void clip_natural_float_from_mono(void *dst, const struct st_sample *src,
|
||||
int samples)
|
||||
{
|
||||
float *out = (float *)dst;
|
||||
|
||||
while (samples--) {
|
||||
*out++ = CLIP_NATURAL_FLOAT(src->l + src->r);
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
static void clip_natural_float_from_stereo(
|
||||
void *dst, const struct st_sample *src, int samples)
|
||||
{
|
||||
float *out = (float *)dst;
|
||||
|
||||
while (samples--) {
|
||||
*out++ = CLIP_NATURAL_FLOAT(src->l);
|
||||
*out++ = CLIP_NATURAL_FLOAT(src->r);
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
f_sample *mixeng_clip_float[2] = {
|
||||
clip_natural_float_from_mono,
|
||||
clip_natural_float_from_stereo,
|
||||
};
|
||||
|
||||
void audio_sample_to_uint64(const void *samples, int pos,
|
||||
void audio_sample_to_uint64(void *samples, int pos,
|
||||
uint64_t *left, uint64_t *right)
|
||||
{
|
||||
const struct st_sample *sample = samples;
|
||||
struct st_sample *sample = samples;
|
||||
sample += pos;
|
||||
#ifdef FLOAT_MIXENG
|
||||
error_report(
|
||||
|
||||
@@ -38,14 +38,9 @@ typedef struct st_sample st_sample;
|
||||
typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
|
||||
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
|
||||
|
||||
/* indices: [stereo][signed][swap endiannes][8, 16 or 32-bits] */
|
||||
extern t_sample *mixeng_conv[2][2][2][3];
|
||||
extern f_sample *mixeng_clip[2][2][2][3];
|
||||
|
||||
/* indices: [stereo] */
|
||||
extern t_sample *mixeng_conv_float[2];
|
||||
extern f_sample *mixeng_clip_float[2];
|
||||
|
||||
void *st_rate_start (int inrate, int outrate);
|
||||
void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||
size_t *isamp, size_t *osamp);
|
||||
|
||||
+12
-10
@@ -41,31 +41,32 @@ static inline mixeng_real glue (conv_, ET) (IN_T v)
|
||||
|
||||
#ifdef RECIPROCAL
|
||||
#ifdef SIGNED
|
||||
return nv * (2.f / ((mixeng_real)IN_MAX - IN_MIN));
|
||||
return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN));
|
||||
#else
|
||||
return (nv - HALF) * (2.f / (mixeng_real)IN_MAX);
|
||||
return (nv - HALF) * (1.f / (mixeng_real) IN_MAX);
|
||||
#endif
|
||||
#else /* !RECIPROCAL */
|
||||
#ifdef SIGNED
|
||||
return nv / (((mixeng_real)IN_MAX - IN_MIN) / 2.f);
|
||||
return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN);
|
||||
#else
|
||||
return (nv - HALF) / ((mixeng_real)IN_MAX / 2.f);
|
||||
return (nv - HALF) / (mixeng_real) IN_MAX;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline IN_T glue (clip_, ET) (mixeng_real v)
|
||||
{
|
||||
if (v >= 1.f) {
|
||||
if (v >= 0.5) {
|
||||
return IN_MAX;
|
||||
} else if (v < -1.f) {
|
||||
}
|
||||
else if (v < -0.5) {
|
||||
return IN_MIN;
|
||||
}
|
||||
|
||||
#ifdef SIGNED
|
||||
return ENDIAN_CONVERT((IN_T)(v * (((mixeng_real)IN_MAX - IN_MIN) / 2.f)));
|
||||
return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real) IN_MAX - IN_MIN)));
|
||||
#else
|
||||
return ENDIAN_CONVERT((IN_T)((v * ((mixeng_real)IN_MAX / 2.f)) + HALF));
|
||||
return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -83,9 +84,10 @@ static inline int64_t glue (conv_, ET) (IN_T v)
|
||||
|
||||
static inline IN_T glue (clip_, ET) (int64_t v)
|
||||
{
|
||||
if (v >= 0x7fffffffLL) {
|
||||
if (v >= 0x7f000000) {
|
||||
return IN_MAX;
|
||||
} else if (v < -2147483648LL) {
|
||||
}
|
||||
else if (v < -2147483648LL) {
|
||||
return IN_MIN;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ static struct audio_pcm_ops no_pcm_ops = {
|
||||
.init_out = no_init_out,
|
||||
.fini_out = no_fini_out,
|
||||
.write = no_write,
|
||||
.run_buffer_out = audio_generic_run_buffer_out,
|
||||
.enable_out = no_enable_out,
|
||||
|
||||
.init_in = no_init_in,
|
||||
|
||||
+10
-17
@@ -382,15 +382,6 @@ static size_t oss_get_available_bytes(OSSVoiceOut *oss)
|
||||
return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
|
||||
}
|
||||
|
||||
static void oss_run_buffer_out(HWVoiceOut *hw)
|
||||
{
|
||||
OSSVoiceOut *oss = (OSSVoiceOut *)hw;
|
||||
|
||||
if (!oss->mmapped) {
|
||||
audio_generic_run_buffer_out(hw);
|
||||
}
|
||||
}
|
||||
|
||||
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
{
|
||||
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
||||
@@ -579,18 +570,20 @@ static void oss_enable_out(HWVoiceOut *hw, bool enable)
|
||||
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
|
||||
|
||||
if (enable) {
|
||||
hw->poll_mode = opdo->try_poll;
|
||||
bool poll_mode = opdo->try_poll;
|
||||
|
||||
ldebug("enabling voice\n");
|
||||
if (hw->poll_mode) {
|
||||
if (poll_mode) {
|
||||
oss_poll_out(hw);
|
||||
poll_mode = 0;
|
||||
}
|
||||
hw->poll_mode = poll_mode;
|
||||
|
||||
if (!oss->mmapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples);
|
||||
audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->mix_buf->size);
|
||||
trig = PCM_ENABLE_OUTPUT;
|
||||
if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
|
||||
oss_logerr(errno,
|
||||
@@ -691,7 +684,6 @@ static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
|
||||
len, dst);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pos += nread;
|
||||
@@ -707,15 +699,17 @@ static void oss_enable_in(HWVoiceIn *hw, bool enable)
|
||||
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
|
||||
|
||||
if (enable) {
|
||||
hw->poll_mode = opdo->try_poll;
|
||||
bool poll_mode = opdo->try_poll;
|
||||
|
||||
if (hw->poll_mode) {
|
||||
if (poll_mode) {
|
||||
oss_poll_in(hw);
|
||||
poll_mode = 0;
|
||||
}
|
||||
hw->poll_mode = poll_mode;
|
||||
} else {
|
||||
if (hw->poll_mode) {
|
||||
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
|
||||
hw->poll_mode = 0;
|
||||
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -754,7 +748,6 @@ static struct audio_pcm_ops oss_pcm_ops = {
|
||||
.init_out = oss_init_out,
|
||||
.fini_out = oss_fini_out,
|
||||
.write = oss_write,
|
||||
.run_buffer_out = oss_run_buffer_out,
|
||||
.get_buffer_out = oss_get_buffer_out,
|
||||
.put_buffer_out = oss_put_buffer_out,
|
||||
.enable_out = oss_enable_out,
|
||||
|
||||
+24
-59
@@ -32,6 +32,7 @@ typedef struct {
|
||||
HWVoiceOut hw;
|
||||
pa_stream *stream;
|
||||
paaudio *g;
|
||||
size_t samples;
|
||||
} PAVoiceOut;
|
||||
|
||||
typedef struct {
|
||||
@@ -40,6 +41,7 @@ typedef struct {
|
||||
const void *read_data;
|
||||
size_t read_length;
|
||||
paaudio *g;
|
||||
size_t samples;
|
||||
} PAVoiceIn;
|
||||
|
||||
static void qpa_conn_fini(PAConnection *c);
|
||||
@@ -154,48 +156,34 @@ static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length)
|
||||
{
|
||||
PAVoiceIn *p = (PAVoiceIn *) hw;
|
||||
PAConnection *c = p->g->conn;
|
||||
size_t total = 0;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
|
||||
"pa_threaded_mainloop_lock failed\n");
|
||||
if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
|
||||
/* wait for stream to become ready */
|
||||
goto unlock;
|
||||
|
||||
if (!p->read_length) {
|
||||
r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
|
||||
CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
|
||||
"pa_stream_peek failed\n");
|
||||
}
|
||||
|
||||
while (total < length) {
|
||||
size_t l;
|
||||
int r;
|
||||
l = MIN(p->read_length, length);
|
||||
memcpy(data, p->read_data, l);
|
||||
|
||||
if (!p->read_length) {
|
||||
r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
|
||||
CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
|
||||
"pa_stream_peek failed\n");
|
||||
if (!p->read_length) {
|
||||
/* buffer is empty */
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->read_data += l;
|
||||
p->read_length -= l;
|
||||
|
||||
l = MIN(p->read_length, length - total);
|
||||
memcpy((char *)data + total, p->read_data, l);
|
||||
|
||||
p->read_data += l;
|
||||
p->read_length -= l;
|
||||
total += l;
|
||||
|
||||
if (!p->read_length) {
|
||||
r = pa_stream_drop(p->stream);
|
||||
CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
|
||||
"pa_stream_drop failed\n");
|
||||
}
|
||||
if (!p->read_length) {
|
||||
r = pa_stream_drop(p->stream);
|
||||
CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
|
||||
"pa_stream_drop failed\n");
|
||||
}
|
||||
|
||||
unlock:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return total;
|
||||
return l;
|
||||
|
||||
unlock_and_fail:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
@@ -277,9 +265,6 @@ static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
|
||||
case AUDIO_FORMAT_U32:
|
||||
format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
|
||||
break;
|
||||
case AUDIO_FORMAT_F32:
|
||||
format = endianness ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
|
||||
break;
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", afmt);
|
||||
format = PA_SAMPLE_U8;
|
||||
@@ -305,12 +290,6 @@ static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
|
||||
case PA_SAMPLE_S32LE:
|
||||
*endianness = 0;
|
||||
return AUDIO_FORMAT_S32;
|
||||
case PA_SAMPLE_FLOAT32BE:
|
||||
*endianness = 1;
|
||||
return AUDIO_FORMAT_F32;
|
||||
case PA_SAMPLE_FLOAT32LE:
|
||||
*endianness = 0;
|
||||
return AUDIO_FORMAT_F32;
|
||||
default:
|
||||
dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
|
||||
return AUDIO_FORMAT_U8;
|
||||
@@ -495,7 +474,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
}
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = audio_buffer_samples(
|
||||
hw->samples = pa->samples = audio_buffer_samples(
|
||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
||||
&obt_as, ppdo->buffer_length);
|
||||
|
||||
@@ -543,7 +522,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
}
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = audio_buffer_samples(
|
||||
hw->samples = pa->samples = audio_buffer_samples(
|
||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
||||
&obt_as, ppdo->buffer_length);
|
||||
|
||||
@@ -557,6 +536,7 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
|
||||
{
|
||||
int err;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
/*
|
||||
* wait until actually connects. workaround pa bug #247
|
||||
* https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
|
||||
@@ -570,6 +550,7 @@ static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
|
||||
dolog("Failed to disconnect! err=%d\n", err);
|
||||
}
|
||||
pa_stream_unref(stream);
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
|
||||
static void qpa_fini_out (HWVoiceOut *hw)
|
||||
@@ -577,12 +558,8 @@ static void qpa_fini_out (HWVoiceOut *hw)
|
||||
PAVoiceOut *pa = (PAVoiceOut *) hw;
|
||||
|
||||
if (pa->stream) {
|
||||
PAConnection *c = pa->g->conn;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
qpa_simple_disconnect(c, pa->stream);
|
||||
qpa_simple_disconnect(pa->g->conn, pa->stream);
|
||||
pa->stream = NULL;
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,20 +568,8 @@ static void qpa_fini_in (HWVoiceIn *hw)
|
||||
PAVoiceIn *pa = (PAVoiceIn *) hw;
|
||||
|
||||
if (pa->stream) {
|
||||
PAConnection *c = pa->g->conn;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
if (pa->read_length) {
|
||||
int r = pa_stream_drop(pa->stream);
|
||||
if (r) {
|
||||
qpa_logerr(pa_context_errno(c->context),
|
||||
"pa_stream_drop failed\n");
|
||||
}
|
||||
pa->read_length = 0;
|
||||
}
|
||||
qpa_simple_disconnect(c, pa->stream);
|
||||
qpa_simple_disconnect(pa->g->conn, pa->stream);
|
||||
pa->stream = NULL;
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-33
@@ -77,14 +77,6 @@ static int aud_to_sdlfmt (AudioFormat fmt)
|
||||
case AUDIO_FORMAT_U16:
|
||||
return AUDIO_U16LSB;
|
||||
|
||||
case AUDIO_FORMAT_S32:
|
||||
return AUDIO_S32LSB;
|
||||
|
||||
/* no unsigned 32-bit support in SDL */
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
return AUDIO_F32LSB;
|
||||
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||
#ifdef DEBUG_AUDIO
|
||||
@@ -127,26 +119,6 @@ static int sdl_to_audfmt(int sdlfmt, AudioFormat *fmt, int *endianness)
|
||||
*fmt = AUDIO_FORMAT_U16;
|
||||
break;
|
||||
|
||||
case AUDIO_S32LSB:
|
||||
*endianness = 0;
|
||||
*fmt = AUDIO_FORMAT_S32;
|
||||
break;
|
||||
|
||||
case AUDIO_S32MSB:
|
||||
*endianness = 1;
|
||||
*fmt = AUDIO_FORMAT_S32;
|
||||
break;
|
||||
|
||||
case AUDIO_F32LSB:
|
||||
*endianness = 0;
|
||||
*fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
case AUDIO_F32MSB:
|
||||
*endianness = 1;
|
||||
*fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
default:
|
||||
dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
|
||||
return -1;
|
||||
@@ -255,7 +227,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
|
||||
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||
(hw, size), *size = 0, sdl_unlock)
|
||||
SDL_WRAPPER_FUNC(put_buffer_out, size_t,
|
||||
SDL_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
|
||||
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
|
||||
/*nothing*/, sdl_unlock_and_post)
|
||||
SDL_WRAPPER_FUNC(write, size_t,
|
||||
@@ -348,12 +320,9 @@ static void sdl_audio_fini (void *opaque)
|
||||
static struct audio_pcm_ops sdl_pcm_ops = {
|
||||
.init_out = sdl_init_out,
|
||||
.fini_out = sdl_fini_out,
|
||||
/* wrapper for audio_generic_write */
|
||||
.write = sdl_write,
|
||||
/* wrapper for audio_generic_get_buffer_out */
|
||||
.get_buffer_out = sdl_get_buffer_out,
|
||||
/* wrapper for audio_generic_put_buffer_out */
|
||||
.put_buffer_out = sdl_put_buffer_out,
|
||||
.put_buffer_out = sdl_put_buffer_out_nowrite,
|
||||
.enable_out = sdl_enable_out,
|
||||
};
|
||||
|
||||
|
||||
@@ -197,7 +197,6 @@ static struct audio_pcm_ops wav_pcm_ops = {
|
||||
.init_out = wav_init_out,
|
||||
.fini_out = wav_fini_out,
|
||||
.write = wav_write_out,
|
||||
.run_buffer_out = audio_generic_run_buffer_out,
|
||||
.enable_out = wav_enable_out,
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ static void wav_destroy (void *opaque)
|
||||
g_free (wav->path);
|
||||
}
|
||||
|
||||
static void wav_capture(void *opaque, const void *buf, int size)
|
||||
static void wav_capture (void *opaque, void *buf, int size)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
|
||||
|
||||
+3
-2
@@ -124,12 +124,13 @@ qauthz_list_class_init(ObjectClass *oc, void *data)
|
||||
"QAuthZListPolicy",
|
||||
&QAuthZListPolicy_lookup,
|
||||
qauthz_list_prop_get_policy,
|
||||
qauthz_list_prop_set_policy);
|
||||
qauthz_list_prop_set_policy,
|
||||
NULL);
|
||||
|
||||
object_class_property_add(oc, "rules", "QAuthZListRule",
|
||||
qauthz_list_prop_get_rules,
|
||||
qauthz_list_prop_set_rules,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
|
||||
authz->is_allowed = qauthz_list_is_allowed;
|
||||
}
|
||||
|
||||
+5
-3
@@ -221,10 +221,12 @@ qauthz_list_file_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
object_class_property_add_str(oc, "filename",
|
||||
qauthz_list_file_prop_get_filename,
|
||||
qauthz_list_file_prop_set_filename);
|
||||
qauthz_list_file_prop_set_filename,
|
||||
NULL);
|
||||
object_class_property_add_bool(oc, "refresh",
|
||||
qauthz_list_file_prop_get_refresh,
|
||||
qauthz_list_file_prop_set_refresh);
|
||||
qauthz_list_file_prop_set_refresh,
|
||||
NULL);
|
||||
|
||||
authz->is_allowed = qauthz_list_file_is_allowed;
|
||||
}
|
||||
@@ -237,7 +239,7 @@ qauthz_list_file_init(Object *obj)
|
||||
|
||||
authz->file_watch = -1;
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
authz->refresh = true;
|
||||
authz->refresh = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -107,7 +107,8 @@ qauthz_pam_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
object_class_property_add_str(oc, "service",
|
||||
qauthz_pam_prop_get_service,
|
||||
qauthz_pam_prop_set_service);
|
||||
qauthz_pam_prop_set_service,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -74,7 +74,8 @@ qauthz_simple_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
object_class_property_add_str(oc, "identity",
|
||||
qauthz_simple_prop_get_identity,
|
||||
qauthz_simple_prop_set_identity);
|
||||
qauthz_simple_prop_set_identity,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
source tpm/Kconfig
|
||||
@@ -1,7 +1,7 @@
|
||||
common-obj-y += rng.o rng-egd.o rng-builtin.o
|
||||
common-obj-$(CONFIG_POSIX) += rng-random.o
|
||||
|
||||
common-obj-$(CONFIG_TPM) += tpm/
|
||||
common-obj-$(CONFIG_TPM) += tpm.o
|
||||
|
||||
common-obj-y += hostmem.o hostmem-ram.o
|
||||
common-obj-$(CONFIG_POSIX) += hostmem-file.o
|
||||
@@ -17,7 +17,3 @@ endif
|
||||
common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_VIRTIO)) += vhost-user.o
|
||||
|
||||
common-obj-$(CONFIG_LINUX) += hostmem-memfd.o
|
||||
|
||||
common-obj-$(CONFIG_GIO) += dbus-vmstate.o
|
||||
dbus-vmstate.o-cflags = $(GIO_CFLAGS)
|
||||
dbus-vmstate.o-libs = $(GIO_LIBS)
|
||||
@@ -282,7 +282,12 @@ static int cryptodev_builtin_sym_close_session(
|
||||
CryptoDevBackendBuiltin *builtin =
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
|
||||
assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]);
|
||||
if (session_id >= MAX_NUM_SESSIONS ||
|
||||
builtin->sessions[session_id] == NULL) {
|
||||
error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
|
||||
session_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
qcrypto_cipher_free(builtin->sessions[session_id]->cipher);
|
||||
g_free(builtin->sessions[session_id]);
|
||||
@@ -351,7 +356,8 @@ static void cryptodev_builtin_cleanup(
|
||||
|
||||
for (i = 0; i < MAX_NUM_SESSIONS; i++) {
|
||||
if (builtin->sessions[i] != NULL) {
|
||||
cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort);
|
||||
cryptodev_builtin_sym_close_session(
|
||||
backend, i, 0, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ cryptodev_vhost_claim_chardev(CryptoDevBackendVhostUser *s,
|
||||
return chr;
|
||||
}
|
||||
|
||||
static void cryptodev_vhost_user_event(void *opaque, QEMUChrEvent event)
|
||||
static void cryptodev_vhost_user_event(void *opaque, int event)
|
||||
{
|
||||
CryptoDevBackendVhostUser *s = opaque;
|
||||
CryptoDevBackend *b = CRYPTODEV_BACKEND(s);
|
||||
@@ -171,11 +171,6 @@ static void cryptodev_vhost_user_event(void *opaque, QEMUChrEvent event)
|
||||
b->ready = false;
|
||||
cryptodev_vhost_user_stop(queues, s);
|
||||
break;
|
||||
case CHR_EVENT_BREAK:
|
||||
case CHR_EVENT_MUX_IN:
|
||||
case CHR_EVENT_MUX_OUT:
|
||||
/* Ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +204,8 @@ static void cryptodev_vhost_user_init(
|
||||
backend->conf.peers.ccs[i] = cc;
|
||||
|
||||
if (i == 0) {
|
||||
if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
|
||||
if (!qemu_chr_fe_init(&s->chr, chr, &local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -339,7 +335,8 @@ static void cryptodev_vhost_user_instance_int(Object *obj)
|
||||
{
|
||||
object_property_add_str(obj, "chardev",
|
||||
cryptodev_vhost_user_get_chardev,
|
||||
cryptodev_vhost_user_set_chardev);
|
||||
cryptodev_vhost_user_set_chardev,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void cryptodev_vhost_user_finalize(Object *obj)
|
||||
|
||||
+21
-8
@@ -154,17 +154,21 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
||||
Error *local_err = NULL;
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
visit_type_uint32(v, name, &value, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
if (!value) {
|
||||
error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu32 "'",
|
||||
object_get_typename(obj), name, value);
|
||||
return;
|
||||
error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
|
||||
PRIu32 "'", object_get_typename(obj), name, value);
|
||||
goto out;
|
||||
}
|
||||
backend->conf.peers.queues = value;
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -172,10 +176,19 @@ cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
||||
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (bc->init) {
|
||||
bc->init(backend, errp);
|
||||
bc->init(backend, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
||||
@@ -209,9 +222,9 @@ static void cryptodev_backend_instance_init(Object *obj)
|
||||
object_property_add(obj, "queues", "uint32",
|
||||
cryptodev_backend_get_queues,
|
||||
cryptodev_backend_set_queues,
|
||||
NULL, NULL);
|
||||
NULL, NULL, NULL);
|
||||
/* Initialize devices' queues property to 1 */
|
||||
object_property_set_int(obj, "queues", 1, NULL);
|
||||
object_property_set_int(obj, 1, "queues", NULL);
|
||||
}
|
||||
|
||||
static void cryptodev_backend_finalize(Object *obj)
|
||||
|
||||
@@ -1,509 +0,0 @@
|
||||
/*
|
||||
* QEMU dbus-vmstate
|
||||
*
|
||||
* Copyright (C) 2019 Red Hat Inc
|
||||
*
|
||||
* Authors:
|
||||
* Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/dbus.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
typedef struct DBusVMState DBusVMState;
|
||||
typedef struct DBusVMStateClass DBusVMStateClass;
|
||||
|
||||
#define TYPE_DBUS_VMSTATE "dbus-vmstate"
|
||||
#define DBUS_VMSTATE(obj) \
|
||||
OBJECT_CHECK(DBusVMState, (obj), TYPE_DBUS_VMSTATE)
|
||||
#define DBUS_VMSTATE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(DBusVMStateClass, (obj), TYPE_DBUS_VMSTATE)
|
||||
#define DBUS_VMSTATE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(DBusVMStateClass, (klass), TYPE_DBUS_VMSTATE)
|
||||
|
||||
struct DBusVMStateClass {
|
||||
ObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct DBusVMState {
|
||||
Object parent;
|
||||
|
||||
GDBusConnection *bus;
|
||||
char *dbus_addr;
|
||||
char *id_list;
|
||||
|
||||
uint32_t data_size;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
static const GDBusPropertyInfo vmstate_property_info[] = {
|
||||
{ -1, (char *) "Id", (char *) "s",
|
||||
G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL },
|
||||
};
|
||||
|
||||
static const GDBusPropertyInfo * const vmstate_property_info_pointers[] = {
|
||||
&vmstate_property_info[0],
|
||||
NULL
|
||||
};
|
||||
|
||||
static const GDBusInterfaceInfo vmstate1_interface_info = {
|
||||
-1,
|
||||
(char *) "org.qemu.VMState1",
|
||||
(GDBusMethodInfo **) NULL,
|
||||
(GDBusSignalInfo **) NULL,
|
||||
(GDBusPropertyInfo **) &vmstate_property_info_pointers,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#define DBUS_VMSTATE_SIZE_LIMIT (1 * MiB)
|
||||
|
||||
static GHashTable *
|
||||
get_id_list_set(DBusVMState *self)
|
||||
{
|
||||
g_auto(GStrv) ids = NULL;
|
||||
g_autoptr(GHashTable) set = NULL;
|
||||
int i;
|
||||
|
||||
if (!self->id_list) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ids = g_strsplit(self->id_list, ",", -1);
|
||||
set = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
|
||||
for (i = 0; ids[i]; i++) {
|
||||
g_hash_table_add(set, ids[i]);
|
||||
ids[i] = NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer(&set);
|
||||
}
|
||||
|
||||
static GHashTable *
|
||||
dbus_get_proxies(DBusVMState *self, GError **err)
|
||||
{
|
||||
g_autoptr(GHashTable) proxies = NULL;
|
||||
g_autoptr(GHashTable) ids = NULL;
|
||||
g_auto(GStrv) names = NULL;
|
||||
Error *error = NULL;
|
||||
size_t i;
|
||||
|
||||
ids = get_id_list_set(self);
|
||||
proxies = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, g_object_unref);
|
||||
|
||||
names = qemu_dbus_get_queued_owners(self->bus, "org.qemu.VMState1", &error);
|
||||
if (!names) {
|
||||
g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
|
||||
error_get_pretty(error));
|
||||
error_free(error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; names[i]; i++) {
|
||||
g_autoptr(GDBusProxy) proxy = NULL;
|
||||
g_autoptr(GVariant) result = NULL;
|
||||
g_autofree char *id = NULL;
|
||||
size_t size;
|
||||
|
||||
proxy = g_dbus_proxy_new_sync(self->bus, G_DBUS_PROXY_FLAGS_NONE,
|
||||
(GDBusInterfaceInfo *) &vmstate1_interface_info,
|
||||
names[i],
|
||||
"/org/qemu/VMState1",
|
||||
"org.qemu.VMState1",
|
||||
NULL, err);
|
||||
if (!proxy) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = g_dbus_proxy_get_cached_property(proxy, "Id");
|
||||
if (!result) {
|
||||
g_set_error_literal(err, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"VMState Id property is missing.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id = g_variant_dup_string(result, &size);
|
||||
if (ids && !g_hash_table_remove(ids, id)) {
|
||||
g_clear_pointer(&id, g_free);
|
||||
g_clear_object(&proxy);
|
||||
continue;
|
||||
}
|
||||
if (size == 0 || size >= 256) {
|
||||
g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"VMState Id '%s' is invalid.", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!g_hash_table_insert(proxies, id, proxy)) {
|
||||
g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Duplicated VMState Id '%s'", id);
|
||||
return NULL;
|
||||
}
|
||||
id = NULL;
|
||||
proxy = NULL;
|
||||
|
||||
g_clear_pointer(&result, g_variant_unref);
|
||||
}
|
||||
|
||||
if (ids) {
|
||||
g_autofree char **left = NULL;
|
||||
|
||||
left = (char **)g_hash_table_get_keys_as_array(ids, NULL);
|
||||
if (*left) {
|
||||
g_autofree char *leftids = g_strjoinv(",", left);
|
||||
g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Required VMState Id are missing: %s", leftids);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return g_steal_pointer(&proxies);
|
||||
}
|
||||
|
||||
static int
|
||||
dbus_load_state_proxy(GDBusProxy *proxy, const uint8_t *data, size_t size)
|
||||
{
|
||||
g_autoptr(GError) err = NULL;
|
||||
g_autoptr(GVariant) result = NULL;
|
||||
g_autoptr(GVariant) value = NULL;
|
||||
|
||||
value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
|
||||
data, size, sizeof(char));
|
||||
result = g_dbus_proxy_call_sync(proxy, "Load",
|
||||
g_variant_new("(@ay)",
|
||||
g_steal_pointer(&value)),
|
||||
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
||||
-1, NULL, &err);
|
||||
if (!result) {
|
||||
error_report("%s: Failed to Load: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dbus_vmstate_post_load(void *opaque, int version_id)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(opaque);
|
||||
g_autoptr(GInputStream) m = NULL;
|
||||
g_autoptr(GDataInputStream) s = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
g_autoptr(GHashTable) proxies = NULL;
|
||||
uint32_t nelem;
|
||||
|
||||
trace_dbus_vmstate_post_load(version_id);
|
||||
|
||||
proxies = dbus_get_proxies(self, &err);
|
||||
if (!proxies) {
|
||||
error_report("%s: Failed to get proxies: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
m = g_memory_input_stream_new_from_data(self->data, self->data_size, NULL);
|
||||
s = g_data_input_stream_new(m);
|
||||
g_data_input_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
|
||||
|
||||
nelem = g_data_input_stream_read_uint32(s, NULL, &err);
|
||||
if (err) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (nelem > 0) {
|
||||
GDBusProxy *proxy = NULL;
|
||||
uint32_t len;
|
||||
gsize bytes_read, avail;
|
||||
char id[256];
|
||||
|
||||
len = g_data_input_stream_read_uint32(s, NULL, &err);
|
||||
if (err) {
|
||||
goto error;
|
||||
}
|
||||
if (len >= 256) {
|
||||
error_report("%s: Invalid DBus vmstate proxy name %u",
|
||||
__func__, len);
|
||||
return -1;
|
||||
}
|
||||
if (!g_input_stream_read_all(G_INPUT_STREAM(s), id, len,
|
||||
&bytes_read, NULL, &err)) {
|
||||
goto error;
|
||||
}
|
||||
g_return_val_if_fail(bytes_read == len, -1);
|
||||
id[len] = 0;
|
||||
|
||||
trace_dbus_vmstate_loading(id);
|
||||
|
||||
proxy = g_hash_table_lookup(proxies, id);
|
||||
if (!proxy) {
|
||||
error_report("%s: Failed to find proxy Id '%s'", __func__, id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = g_data_input_stream_read_uint32(s, NULL, &err);
|
||||
avail = g_buffered_input_stream_get_available(
|
||||
G_BUFFERED_INPUT_STREAM(s));
|
||||
|
||||
if (len > DBUS_VMSTATE_SIZE_LIMIT || len > avail) {
|
||||
error_report("%s: Invalid vmstate size: %u", __func__, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dbus_load_state_proxy(proxy,
|
||||
g_buffered_input_stream_peek_buffer(G_BUFFERED_INPUT_STREAM(s),
|
||||
NULL),
|
||||
len) < 0) {
|
||||
error_report("%s: Failed to restore Id '%s'", __func__, id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_seekable_seek(G_SEEKABLE(s), len, G_SEEK_CUR, NULL, &err)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
nelem -= 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
error_report("%s: Failed to read from stream: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_save_state_proxy(gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDataOutputStream *s = user_data;
|
||||
const char *id = key;
|
||||
GDBusProxy *proxy = value;
|
||||
g_autoptr(GVariant) result = NULL;
|
||||
g_autoptr(GVariant) child = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
const uint8_t *data;
|
||||
gsize size;
|
||||
|
||||
trace_dbus_vmstate_saving(id);
|
||||
|
||||
result = g_dbus_proxy_call_sync(proxy, "Save",
|
||||
NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
||||
-1, NULL, &err);
|
||||
if (!result) {
|
||||
error_report("%s: Failed to Save: %s", __func__, err->message);
|
||||
return;
|
||||
}
|
||||
|
||||
child = g_variant_get_child_value(result, 0);
|
||||
data = g_variant_get_fixed_array(child, &size, sizeof(char));
|
||||
if (!data) {
|
||||
error_report("%s: Failed to Save: not a byte array", __func__);
|
||||
return;
|
||||
}
|
||||
if (size > DBUS_VMSTATE_SIZE_LIMIT) {
|
||||
error_report("%s: Too large vmstate data to save: %zu",
|
||||
__func__, (size_t)size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_data_output_stream_put_uint32(s, strlen(id), NULL, &err) ||
|
||||
!g_data_output_stream_put_string(s, id, NULL, &err) ||
|
||||
!g_data_output_stream_put_uint32(s, size, NULL, &err) ||
|
||||
!g_output_stream_write_all(G_OUTPUT_STREAM(s),
|
||||
data, size, NULL, NULL, &err)) {
|
||||
error_report("%s: Failed to write to stream: %s",
|
||||
__func__, err->message);
|
||||
}
|
||||
}
|
||||
|
||||
static int dbus_vmstate_pre_save(void *opaque)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(opaque);
|
||||
g_autoptr(GOutputStream) m = NULL;
|
||||
g_autoptr(GDataOutputStream) s = NULL;
|
||||
g_autoptr(GHashTable) proxies = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
|
||||
trace_dbus_vmstate_pre_save();
|
||||
|
||||
proxies = dbus_get_proxies(self, &err);
|
||||
if (!proxies) {
|
||||
error_report("%s: Failed to get proxies: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
m = g_memory_output_stream_new_resizable();
|
||||
s = g_data_output_stream_new(m);
|
||||
g_data_output_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
|
||||
|
||||
if (!g_data_output_stream_put_uint32(s, g_hash_table_size(proxies),
|
||||
NULL, &err)) {
|
||||
error_report("%s: Failed to write to stream: %s",
|
||||
__func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_hash_table_foreach(proxies, dbus_save_state_proxy, s);
|
||||
|
||||
if (g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m))
|
||||
> UINT32_MAX) {
|
||||
error_report("%s: DBus vmstate buffer is too large", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_output_stream_close(G_OUTPUT_STREAM(m), NULL, &err)) {
|
||||
error_report("%s: Failed to close stream: %s", __func__, err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_free(self->data);
|
||||
self->data_size =
|
||||
g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m));
|
||||
self->data =
|
||||
g_memory_output_stream_steal_data(G_MEMORY_OUTPUT_STREAM(m));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription dbus_vmstate = {
|
||||
.name = TYPE_DBUS_VMSTATE,
|
||||
.version_id = 0,
|
||||
.pre_save = dbus_vmstate_pre_save,
|
||||
.post_load = dbus_vmstate_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(data_size, DBusVMState),
|
||||
VMSTATE_VBUFFER_ALLOC_UINT32(data, DBusVMState, 0, 0, data_size),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
dbus_vmstate_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(uc);
|
||||
g_autoptr(GError) err = NULL;
|
||||
|
||||
if (!object_resolve_path_type("", TYPE_DBUS_VMSTATE, NULL)) {
|
||||
error_setg(errp, "There is already an instance of %s",
|
||||
TYPE_DBUS_VMSTATE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->dbus_addr) {
|
||||
error_setg(errp, QERR_MISSING_PARAMETER, "addr");
|
||||
return;
|
||||
}
|
||||
|
||||
self->bus = g_dbus_connection_new_for_address_sync(self->dbus_addr,
|
||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
|
||||
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
|
||||
NULL, NULL, &err);
|
||||
if (err) {
|
||||
error_setg(errp, "failed to connect to DBus: '%s'", err->message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vmstate_register(VMSTATE_IF(self), VMSTATE_INSTANCE_ID_ANY,
|
||||
&dbus_vmstate, self) < 0) {
|
||||
error_setg(errp, "Failed to register vmstate");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_vmstate_finalize(Object *o)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
vmstate_unregister(VMSTATE_IF(self), &dbus_vmstate, self);
|
||||
|
||||
g_clear_object(&self->bus);
|
||||
g_free(self->dbus_addr);
|
||||
g_free(self->id_list);
|
||||
g_free(self->data);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_dbus_addr(Object *o, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
return g_strdup(self->dbus_addr);
|
||||
}
|
||||
|
||||
static void
|
||||
set_dbus_addr(Object *o, const char *str, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
g_free(self->dbus_addr);
|
||||
self->dbus_addr = g_strdup(str);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_id_list(Object *o, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
return g_strdup(self->id_list);
|
||||
}
|
||||
|
||||
static void
|
||||
set_id_list(Object *o, const char *str, Error **errp)
|
||||
{
|
||||
DBusVMState *self = DBUS_VMSTATE(o);
|
||||
|
||||
g_free(self->id_list);
|
||||
self->id_list = g_strdup(str);
|
||||
}
|
||||
|
||||
static char *
|
||||
dbus_vmstate_get_id(VMStateIf *vmif)
|
||||
{
|
||||
return g_strdup(TYPE_DBUS_VMSTATE);
|
||||
}
|
||||
|
||||
static void
|
||||
dbus_vmstate_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
VMStateIfClass *vc = VMSTATE_IF_CLASS(oc);
|
||||
|
||||
ucc->complete = dbus_vmstate_complete;
|
||||
vc->get_id = dbus_vmstate_get_id;
|
||||
|
||||
object_class_property_add_str(oc, "addr",
|
||||
get_dbus_addr, set_dbus_addr);
|
||||
object_class_property_add_str(oc, "id-list",
|
||||
get_id_list, set_id_list);
|
||||
}
|
||||
|
||||
static const TypeInfo dbus_vmstate_info = {
|
||||
.name = TYPE_DBUS_VMSTATE,
|
||||
.parent = TYPE_OBJECT,
|
||||
.instance_size = sizeof(DBusVMState),
|
||||
.instance_finalize = dbus_vmstate_finalize,
|
||||
.class_size = sizeof(DBusVMStateClass),
|
||||
.class_init = dbus_vmstate_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ TYPE_VMSTATE_IF },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
register_types(void)
|
||||
{
|
||||
type_register_static(&dbus_vmstate_info);
|
||||
}
|
||||
|
||||
type_init(register_types);
|
||||
+31
-10
@@ -18,6 +18,13 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
/* hostmem-file.c */
|
||||
/**
|
||||
* @TYPE_MEMORY_BACKEND_FILE:
|
||||
* name of backend that uses mmap on a file descriptor
|
||||
*/
|
||||
#define TYPE_MEMORY_BACKEND_FILE "memory-backend-file"
|
||||
|
||||
#define MEMORY_BACKEND_FILE(obj) \
|
||||
OBJECT_CHECK(HostMemoryBackendFile, (obj), TYPE_MEMORY_BACKEND_FILE)
|
||||
|
||||
@@ -51,6 +58,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
backend->force_prealloc = mem_prealloc;
|
||||
name = host_memory_backend_get_name(backend);
|
||||
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend),
|
||||
name,
|
||||
@@ -110,18 +118,23 @@ static void file_memory_backend_set_align(Object *o, Visitor *v,
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(o);
|
||||
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
|
||||
Error *local_err = NULL;
|
||||
uint64_t val;
|
||||
|
||||
if (host_memory_backend_mr_inited(backend)) {
|
||||
error_setg(errp, "cannot change property '%s' of %s", name,
|
||||
object_get_typename(o));
|
||||
return;
|
||||
error_setg(&local_err, "cannot change property '%s' of %s",
|
||||
name, object_get_typename(o));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!visit_type_size(v, name, &val, errp)) {
|
||||
return;
|
||||
visit_type_size(v, name, &val, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
fb->align = val;
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static bool file_memory_backend_get_pmem(Object *o, Error **errp)
|
||||
@@ -135,6 +148,7 @@ static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp)
|
||||
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
|
||||
|
||||
if (host_memory_backend_mr_inited(backend)) {
|
||||
|
||||
error_setg(errp, "cannot change property 'pmem' of %s.",
|
||||
object_get_typename(o));
|
||||
return;
|
||||
@@ -142,9 +156,13 @@ static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp)
|
||||
|
||||
#ifndef CONFIG_LIBPMEM
|
||||
if (value) {
|
||||
error_setg(errp, "Lack of libpmem support while setting the 'pmem=on'"
|
||||
Error *local_err = NULL;
|
||||
|
||||
error_setg(&local_err,
|
||||
"Lack of libpmem support while setting the 'pmem=on'"
|
||||
" of %s. We can't ensure data persistence.",
|
||||
object_get_typename(o));
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -174,15 +192,18 @@ file_backend_class_init(ObjectClass *oc, void *data)
|
||||
oc->unparent = file_backend_unparent;
|
||||
|
||||
object_class_property_add_bool(oc, "discard-data",
|
||||
file_memory_backend_get_discard_data, file_memory_backend_set_discard_data);
|
||||
file_memory_backend_get_discard_data, file_memory_backend_set_discard_data,
|
||||
&error_abort);
|
||||
object_class_property_add_str(oc, "mem-path",
|
||||
get_mem_path, set_mem_path);
|
||||
get_mem_path, set_mem_path,
|
||||
&error_abort);
|
||||
object_class_property_add(oc, "align", "int",
|
||||
file_memory_backend_get_align,
|
||||
file_memory_backend_set_align,
|
||||
NULL, NULL);
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_add_bool(oc, "pmem",
|
||||
file_memory_backend_get_pmem, file_memory_backend_set_pmem);
|
||||
file_memory_backend_get_pmem, file_memory_backend_set_pmem,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static void file_backend_instance_finalize(Object *o)
|
||||
|
||||
+23
-13
@@ -45,6 +45,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
backend->force_prealloc = mem_prealloc;
|
||||
fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD, backend->size,
|
||||
m->hugetlb, m->hugetlbsize, m->seal ?
|
||||
F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL : 0,
|
||||
@@ -77,22 +78,26 @@ memfd_backend_set_hugetlbsize(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
HostMemoryBackendMemfd *m = MEMORY_BACKEND_MEMFD(obj);
|
||||
Error *local_err = NULL;
|
||||
uint64_t value;
|
||||
|
||||
if (host_memory_backend_mr_inited(MEMORY_BACKEND(obj))) {
|
||||
error_setg(errp, "cannot change property value");
|
||||
return;
|
||||
error_setg(&local_err, "cannot change property value");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!visit_type_size(v, name, &value, errp)) {
|
||||
return;
|
||||
visit_type_size(v, name, &value, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
if (!value) {
|
||||
error_setg(errp, "Property '%s.%s' doesn't take value '%" PRIu64 "'",
|
||||
object_get_typename(obj), name, value);
|
||||
return;
|
||||
error_setg(&local_err, "Property '%s.%s' doesn't take value '%"
|
||||
PRIu64 "'", object_get_typename(obj), name, value);
|
||||
goto out;
|
||||
}
|
||||
m->hugetlbsize = value;
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -137,21 +142,26 @@ memfd_backend_class_init(ObjectClass *oc, void *data)
|
||||
if (qemu_memfd_check(MFD_HUGETLB)) {
|
||||
object_class_property_add_bool(oc, "hugetlb",
|
||||
memfd_backend_get_hugetlb,
|
||||
memfd_backend_set_hugetlb);
|
||||
memfd_backend_set_hugetlb,
|
||||
&error_abort);
|
||||
object_class_property_set_description(oc, "hugetlb",
|
||||
"Use huge pages");
|
||||
"Use huge pages",
|
||||
&error_abort);
|
||||
object_class_property_add(oc, "hugetlbsize", "int",
|
||||
memfd_backend_get_hugetlbsize,
|
||||
memfd_backend_set_hugetlbsize,
|
||||
NULL, NULL);
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_set_description(oc, "hugetlbsize",
|
||||
"Huge pages size (ex: 2M, 1G)");
|
||||
"Huge pages size (ex: 2M, 1G)",
|
||||
&error_abort);
|
||||
}
|
||||
object_class_property_add_bool(oc, "seal",
|
||||
memfd_backend_get_seal,
|
||||
memfd_backend_set_seal);
|
||||
memfd_backend_set_seal,
|
||||
&error_abort);
|
||||
object_class_property_set_description(oc, "seal",
|
||||
"Seal growing & shrinking");
|
||||
"Seal growing & shrinking",
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo memfd_backend_info = {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "qemu/module.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
|
||||
#define TYPE_MEMORY_BACKEND_RAM "memory-backend-ram"
|
||||
|
||||
static void
|
||||
ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
|
||||
{
|
||||
|
||||
+42
-58
@@ -33,7 +33,7 @@ char *
|
||||
host_memory_backend_get_name(HostMemoryBackend *backend)
|
||||
{
|
||||
if (!backend->use_canonical_path) {
|
||||
return g_strdup(object_get_canonical_path_component(OBJECT(backend)));
|
||||
return object_get_canonical_path_component(OBJECT(backend));
|
||||
}
|
||||
|
||||
return object_get_canonical_path(OBJECT(backend));
|
||||
@@ -54,24 +54,28 @@ host_memory_backend_set_size(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
Error *local_err = NULL;
|
||||
uint64_t value;
|
||||
|
||||
if (host_memory_backend_mr_inited(backend)) {
|
||||
error_setg(errp, "cannot change property %s of %s ", name,
|
||||
object_get_typename(obj));
|
||||
return;
|
||||
error_setg(&local_err, "cannot change property %s of %s ",
|
||||
name, object_get_typename(obj));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!visit_type_size(v, name, &value, errp)) {
|
||||
return;
|
||||
visit_type_size(v, name, &value, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
if (!value) {
|
||||
error_setg(errp,
|
||||
error_setg(&local_err,
|
||||
"property '%s' of %s doesn't take value '%" PRIu64 "'",
|
||||
name, object_get_typename(obj), value);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
backend->size = value;
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -211,7 +215,7 @@ static bool host_memory_backend_get_prealloc(Object *obj, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
|
||||
return backend->prealloc;
|
||||
return backend->prealloc || backend->force_prealloc;
|
||||
}
|
||||
|
||||
static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
@@ -219,6 +223,15 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
|
||||
if (backend->force_prealloc) {
|
||||
if (value) {
|
||||
error_setg(errp,
|
||||
"remove -mem-prealloc to use the prealloc property");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!host_memory_backend_mr_inited(backend)) {
|
||||
backend->prealloc = value;
|
||||
@@ -230,7 +243,7 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
void *ptr = memory_region_get_ram_ptr(&backend->mr);
|
||||
uint64_t sz = memory_region_size(&backend->mr);
|
||||
|
||||
os_mem_prealloc(fd, ptr, sz, backend->prealloc_threads, &local_err);
|
||||
os_mem_prealloc(fd, ptr, sz, ms->smp.cpus, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
@@ -239,39 +252,14 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
}
|
||||
}
|
||||
|
||||
static void host_memory_backend_get_prealloc_threads(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
visit_type_uint32(v, name, &backend->prealloc_threads, errp);
|
||||
}
|
||||
|
||||
static void host_memory_backend_set_prealloc_threads(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
if (value <= 0) {
|
||||
error_setg(errp, "property '%s' of %s doesn't take value '%d'", name,
|
||||
object_get_typename(obj), value);
|
||||
return;
|
||||
}
|
||||
backend->prealloc_threads = value;
|
||||
}
|
||||
|
||||
static void host_memory_backend_init(Object *obj)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
||||
/* TODO: convert access to globals to compat properties */
|
||||
backend->merge = machine_mem_merge(machine);
|
||||
backend->dump = machine_dump_guest_core(machine);
|
||||
backend->prealloc_threads = 1;
|
||||
backend->prealloc = mem_prealloc;
|
||||
}
|
||||
|
||||
static void host_memory_backend_post_init(Object *obj)
|
||||
@@ -325,6 +313,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(uc);
|
||||
HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(uc);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
Error *local_err = NULL;
|
||||
void *ptr;
|
||||
uint64_t sz;
|
||||
@@ -391,7 +380,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
|
||||
*/
|
||||
if (backend->prealloc) {
|
||||
os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz,
|
||||
backend->prealloc_threads, &local_err);
|
||||
ms->smp.cpus, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
@@ -456,50 +445,45 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
object_class_property_add_bool(oc, "merge",
|
||||
host_memory_backend_get_merge,
|
||||
host_memory_backend_set_merge);
|
||||
host_memory_backend_set_merge, &error_abort);
|
||||
object_class_property_set_description(oc, "merge",
|
||||
"Mark memory as mergeable");
|
||||
"Mark memory as mergeable", &error_abort);
|
||||
object_class_property_add_bool(oc, "dump",
|
||||
host_memory_backend_get_dump,
|
||||
host_memory_backend_set_dump);
|
||||
host_memory_backend_set_dump, &error_abort);
|
||||
object_class_property_set_description(oc, "dump",
|
||||
"Set to 'off' to exclude from core dump");
|
||||
"Set to 'off' to exclude from core dump", &error_abort);
|
||||
object_class_property_add_bool(oc, "prealloc",
|
||||
host_memory_backend_get_prealloc,
|
||||
host_memory_backend_set_prealloc);
|
||||
host_memory_backend_set_prealloc, &error_abort);
|
||||
object_class_property_set_description(oc, "prealloc",
|
||||
"Preallocate memory");
|
||||
object_class_property_add(oc, "prealloc-threads", "int",
|
||||
host_memory_backend_get_prealloc_threads,
|
||||
host_memory_backend_set_prealloc_threads,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "prealloc-threads",
|
||||
"Number of CPU threads to use for prealloc");
|
||||
"Preallocate memory", &error_abort);
|
||||
object_class_property_add(oc, "size", "int",
|
||||
host_memory_backend_get_size,
|
||||
host_memory_backend_set_size,
|
||||
NULL, NULL);
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_set_description(oc, "size",
|
||||
"Size of the memory region (ex: 500M)");
|
||||
"Size of the memory region (ex: 500M)", &error_abort);
|
||||
object_class_property_add(oc, "host-nodes", "int",
|
||||
host_memory_backend_get_host_nodes,
|
||||
host_memory_backend_set_host_nodes,
|
||||
NULL, NULL);
|
||||
NULL, NULL, &error_abort);
|
||||
object_class_property_set_description(oc, "host-nodes",
|
||||
"Binds memory to the list of NUMA host nodes");
|
||||
"Binds memory to the list of NUMA host nodes", &error_abort);
|
||||
object_class_property_add_enum(oc, "policy", "HostMemPolicy",
|
||||
&HostMemPolicy_lookup,
|
||||
host_memory_backend_get_policy,
|
||||
host_memory_backend_set_policy);
|
||||
host_memory_backend_set_policy, &error_abort);
|
||||
object_class_property_set_description(oc, "policy",
|
||||
"Set the NUMA policy");
|
||||
"Set the NUMA policy", &error_abort);
|
||||
object_class_property_add_bool(oc, "share",
|
||||
host_memory_backend_get_share, host_memory_backend_set_share);
|
||||
host_memory_backend_get_share, host_memory_backend_set_share,
|
||||
&error_abort);
|
||||
object_class_property_set_description(oc, "share",
|
||||
"Mark the memory as private to QEMU or shared");
|
||||
"Mark the memory as private to QEMU or shared", &error_abort);
|
||||
object_class_property_add_bool(oc, "x-use-canonical-path-for-ramblock-id",
|
||||
host_memory_backend_get_use_canonical_path,
|
||||
host_memory_backend_set_use_canonical_path);
|
||||
host_memory_backend_set_use_canonical_path, &error_abort);
|
||||
}
|
||||
|
||||
static const TypeInfo host_memory_backend_info = {
|
||||
|
||||
+2
-1
@@ -138,7 +138,8 @@ static char *rng_egd_get_chardev(Object *obj, Error **errp)
|
||||
static void rng_egd_init(Object *obj)
|
||||
{
|
||||
object_property_add_str(obj, "chardev",
|
||||
rng_egd_get_chardev, rng_egd_set_chardev);
|
||||
rng_egd_get_chardev, rng_egd_set_chardev,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void rng_egd_finalize(Object *obj)
|
||||
|
||||
@@ -110,7 +110,8 @@ static void rng_random_init(Object *obj)
|
||||
|
||||
object_property_add_str(obj, "filename",
|
||||
rng_random_get_filename,
|
||||
rng_random_set_filename);
|
||||
rng_random_set_filename,
|
||||
NULL);
|
||||
|
||||
s->filename = g_strdup("/dev/urandom");
|
||||
s->fd = -1;
|
||||
|
||||
+3
-2
@@ -48,7 +48,7 @@ static bool rng_backend_prop_get_opened(Object *obj, Error **errp)
|
||||
|
||||
static void rng_backend_complete(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
object_property_set_bool(OBJECT(uc), "opened", true, errp);
|
||||
object_property_set_bool(OBJECT(uc), true, "opened", errp);
|
||||
}
|
||||
|
||||
static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
|
||||
@@ -108,7 +108,8 @@ static void rng_backend_init(Object *obj)
|
||||
|
||||
object_property_add_bool(obj, "opened",
|
||||
rng_backend_prop_get_opened,
|
||||
rng_backend_prop_set_opened);
|
||||
rng_backend_prop_set_opened,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void rng_backend_finalize(Object *obj)
|
||||
|
||||
File renamed without changes.
@@ -1,14 +0,0 @@
|
||||
config TPM_BACKEND
|
||||
bool
|
||||
depends on TPM
|
||||
|
||||
config TPM_PASSTHROUGH
|
||||
bool
|
||||
default y
|
||||
# FIXME: should check for x86 host as well
|
||||
depends on TPM_BACKEND && LINUX
|
||||
|
||||
config TPM_EMULATOR
|
||||
bool
|
||||
default y
|
||||
depends on TPM_BACKEND
|
||||
@@ -1,4 +0,0 @@
|
||||
common-obj-y += tpm_backend.o
|
||||
common-obj-y += tpm_util.o
|
||||
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
|
||||
common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o
|
||||
@@ -1,33 +0,0 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# tpm_passthrough.c
|
||||
tpm_passthrough_handle_request(void *cmd) "processing command %p"
|
||||
tpm_passthrough_reset(void) "reset"
|
||||
|
||||
# tpm_util.c
|
||||
tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
|
||||
tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"
|
||||
tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu"
|
||||
tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu"
|
||||
tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu"
|
||||
tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s"
|
||||
|
||||
# tpm_emulator.c
|
||||
tpm_emulator_set_locality(uint8_t locty) "setting locality to %d"
|
||||
tpm_emulator_handle_request(void) "processing TPM command"
|
||||
tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64
|
||||
tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u"
|
||||
tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu"
|
||||
tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d"
|
||||
tpm_emulator_cancel_cmd_not_supt(void) "Backend does not support CANCEL_TPM_CMD"
|
||||
tpm_emulator_handle_device_opts_tpm12(void) "TPM Version 1.2"
|
||||
tpm_emulator_handle_device_opts_tpm2(void) "TPM Version 2"
|
||||
tpm_emulator_handle_device_opts_unspec(void) "TPM Version Unspecified"
|
||||
tpm_emulator_handle_device_opts_startup_error(void) "Startup error"
|
||||
tpm_emulator_get_state_blob(uint8_t type, uint32_t size, uint32_t flags) "got state blob type %d, %u bytes, flags 0x%08x"
|
||||
tpm_emulator_set_state_blob(uint8_t type, uint32_t size, uint32_t flags) "set state blob type %d, %u bytes, flags 0x%08x"
|
||||
tpm_emulator_set_state_blobs(void) "setting state blobs"
|
||||
tpm_emulator_set_state_blobs_error(const char *msg) "error while setting state blobs: %s"
|
||||
tpm_emulator_set_state_blobs_done(void) "Done setting state blobs"
|
||||
tpm_emulator_pre_save(void) ""
|
||||
tpm_emulator_inst_init(void) ""
|
||||
@@ -1,7 +0,0 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# dbus-vmstate.c
|
||||
dbus_vmstate_pre_save(void)
|
||||
dbus_vmstate_post_load(int version_id) "version_id: %d"
|
||||
dbus_vmstate_loading(const char *id) "id: %s"
|
||||
dbus_vmstate_saving(const char *id) "id: %s"
|
||||
@@ -177,7 +177,7 @@ static char *get_chardev(Object *obj, Error **errp)
|
||||
|
||||
static void vhost_user_backend_init(Object *obj)
|
||||
{
|
||||
object_property_add_str(obj, "chardev", get_chardev, set_chardev);
|
||||
object_property_add_str(obj, "chardev", get_chardev, set_chardev, NULL);
|
||||
}
|
||||
|
||||
static void vhost_user_backend_finalize(Object *obj)
|
||||
|
||||
@@ -36,6 +36,23 @@
|
||||
static QEMUBalloonEvent *balloon_event_fn;
|
||||
static QEMUBalloonStatus *balloon_stat_fn;
|
||||
static void *balloon_opaque;
|
||||
static int balloon_inhibit_count;
|
||||
|
||||
bool qemu_balloon_is_inhibited(void)
|
||||
{
|
||||
return atomic_read(&balloon_inhibit_count) > 0;
|
||||
}
|
||||
|
||||
void qemu_balloon_inhibit(bool state)
|
||||
{
|
||||
if (state) {
|
||||
atomic_inc(&balloon_inhibit_count);
|
||||
} else {
|
||||
atomic_dec(&balloon_inhibit_count);
|
||||
}
|
||||
|
||||
assert(atomic_read(&balloon_inhibit_count) >= 0);
|
||||
}
|
||||
|
||||
static bool have_balloon(Error **errp)
|
||||
{
|
||||
+4
-10
@@ -18,8 +18,7 @@ block-obj-y += block-backend.o snapshot.o qapi.o
|
||||
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += file-posix.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o
|
||||
block-obj-y += null.o mirror.o commit.o io.o create.o amend.o
|
||||
block-obj-y += null.o mirror.o commit.o io.o create.o
|
||||
block-obj-y += throttle-groups.o
|
||||
block-obj-$(CONFIG_LINUX) += nvme.o
|
||||
|
||||
@@ -31,6 +30,7 @@ block-obj-$(CONFIG_LIBNFS) += nfs.o
|
||||
block-obj-$(CONFIG_CURL) += curl.o
|
||||
block-obj-$(CONFIG_RBD) += rbd.o
|
||||
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
|
||||
block-obj-$(CONFIG_VXHS) += vxhs.o
|
||||
block-obj-$(CONFIG_LIBSSH) += ssh.o
|
||||
block-obj-y += accounting.o dirty-bitmap.o
|
||||
block-obj-y += write-threshold.o
|
||||
@@ -43,13 +43,8 @@ block-obj-y += crypto.o
|
||||
|
||||
block-obj-y += aio_task.o
|
||||
block-obj-y += backup-top.o
|
||||
block-obj-y += filter-compress.o
|
||||
common-obj-y += monitor/
|
||||
block-obj-y += monitor/
|
||||
|
||||
block-obj-y += stream.o
|
||||
|
||||
common-obj-y += qapi-sysemu.o
|
||||
common-obj-y += stream.o
|
||||
|
||||
nfs.o-libs := $(LIBNFS_LIBS)
|
||||
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||
@@ -60,6 +55,7 @@ rbd.o-cflags := $(RBD_CFLAGS)
|
||||
rbd.o-libs := $(RBD_LIBS)
|
||||
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
|
||||
gluster.o-libs := $(GLUSTERFS_LIBS)
|
||||
vxhs.o-libs := $(VXHS_LIBS)
|
||||
ssh.o-cflags := $(LIBSSH_CFLAGS)
|
||||
ssh.o-libs := $(LIBSSH_LIBS)
|
||||
block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
|
||||
@@ -69,7 +65,5 @@ block-obj-$(if $(CONFIG_LZFSE),m,n) += dmg-lzfse.o
|
||||
dmg-lzfse.o-libs := $(LZFSE_LIBS)
|
||||
qcow.o-libs := -lz
|
||||
linux-aio.o-libs := -laio
|
||||
io_uring.o-cflags := $(LINUX_IO_URING_CFLAGS)
|
||||
io_uring.o-libs := $(LINUX_IO_URING_LIBS)
|
||||
parallels.o-cflags := $(LIBXML2_CFLAGS)
|
||||
parallels.o-libs := $(LIBXML2_LIBS)
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Block layer code related to image options amend
|
||||
*
|
||||
* Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
|
||||
* Copyright (c) 2020 Red Hat. Inc
|
||||
*
|
||||
* Heavily based on create.c
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qemu/job.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qapi/qapi-commands-block-core.h"
|
||||
#include "qapi/qapi-visit-block-core.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
typedef struct BlockdevAmendJob {
|
||||
Job common;
|
||||
BlockdevAmendOptions *opts;
|
||||
BlockDriverState *bs;
|
||||
bool force;
|
||||
} BlockdevAmendJob;
|
||||
|
||||
static int coroutine_fn blockdev_amend_run(Job *job, Error **errp)
|
||||
{
|
||||
BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);
|
||||
int ret;
|
||||
|
||||
job_progress_set_remaining(&s->common, 1);
|
||||
ret = s->bs->drv->bdrv_co_amend(s->bs, s->opts, s->force, errp);
|
||||
job_progress_update(&s->common, 1);
|
||||
qapi_free_BlockdevAmendOptions(s->opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const JobDriver blockdev_amend_job_driver = {
|
||||
.instance_size = sizeof(BlockdevAmendJob),
|
||||
.job_type = JOB_TYPE_AMEND,
|
||||
.run = blockdev_amend_run,
|
||||
};
|
||||
|
||||
void qmp_x_blockdev_amend(const char *job_id,
|
||||
const char *node_name,
|
||||
BlockdevAmendOptions *options,
|
||||
bool has_force,
|
||||
bool force,
|
||||
Error **errp)
|
||||
{
|
||||
BlockdevAmendJob *s;
|
||||
const char *fmt = BlockdevDriver_str(options->driver);
|
||||
BlockDriver *drv = bdrv_find_format(fmt);
|
||||
BlockDriverState *bs;
|
||||
|
||||
bs = bdrv_lookup_bs(NULL, node_name, errp);
|
||||
if (!bs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!drv) {
|
||||
error_setg(errp, "Block driver '%s' not found or not supported", fmt);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the driver is in the schema, we know that it exists. But it may not
|
||||
* be whitelisted.
|
||||
*/
|
||||
if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
|
||||
error_setg(errp, "Driver is not whitelisted");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bs->drv != drv) {
|
||||
error_setg(errp,
|
||||
"x-blockdev-amend doesn't support changing the block driver");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Error out if the driver doesn't support .bdrv_co_amend */
|
||||
if (!drv->bdrv_co_amend) {
|
||||
error_setg(errp, "Driver does not support x-blockdev-amend");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the block job */
|
||||
s = job_create(job_id, &blockdev_amend_job_driver, NULL,
|
||||
bdrv_get_aio_context(bs), JOB_DEFAULT | JOB_MANUAL_DISMISS,
|
||||
NULL, NULL, errp);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->bs = bs,
|
||||
s->opts = QAPI_CLONE(BlockdevAmendOptions, options),
|
||||
s->force = has_force ? force : false;
|
||||
job_start(&s->common);
|
||||
}
|
||||
+26
-37
@@ -38,7 +38,6 @@ typedef struct BDRVBackupTopState {
|
||||
BlockCopyState *bcs;
|
||||
BdrvChild *target;
|
||||
bool active;
|
||||
int64_t cluster_size;
|
||||
} BDRVBackupTopState;
|
||||
|
||||
static coroutine_fn int backup_top_co_preadv(
|
||||
@@ -49,17 +48,11 @@ static coroutine_fn int backup_top_co_preadv(
|
||||
}
|
||||
|
||||
static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, BdrvRequestFlags flags)
|
||||
uint64_t bytes)
|
||||
{
|
||||
BDRVBackupTopState *s = bs->opaque;
|
||||
uint64_t off, end;
|
||||
|
||||
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
off = QEMU_ALIGN_DOWN(offset, s->cluster_size);
|
||||
end = QEMU_ALIGN_UP(offset + bytes, s->cluster_size);
|
||||
uint64_t end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size);
|
||||
uint64_t off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size);
|
||||
|
||||
return block_copy(s->bcs, off, end - off, NULL);
|
||||
}
|
||||
@@ -67,7 +60,7 @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
|
||||
static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
|
||||
int64_t offset, int bytes)
|
||||
{
|
||||
int ret = backup_top_cbw(bs, offset, bytes, 0);
|
||||
int ret = backup_top_cbw(bs, offset, bytes);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -78,7 +71,7 @@ static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
|
||||
static int coroutine_fn backup_top_co_pwrite_zeroes(BlockDriverState *bs,
|
||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||
{
|
||||
int ret = backup_top_cbw(bs, offset, bytes, flags);
|
||||
int ret = backup_top_cbw(bs, offset, bytes);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -91,9 +84,11 @@ static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs,
|
||||
uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
int ret = backup_top_cbw(bs, offset, bytes, flags);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
if (!(flags & BDRV_REQ_WRITE_UNCHANGED)) {
|
||||
int ret = backup_top_cbw(bs, offset, bytes);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
|
||||
@@ -122,7 +117,7 @@ static void backup_top_refresh_filename(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
const BdrvChildRole *role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
@@ -142,26 +137,24 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(role & BDRV_CHILD_FILTERED)) {
|
||||
if (role == &child_file) {
|
||||
/*
|
||||
* Target child
|
||||
*
|
||||
* Share write to target (child_file), to not interfere
|
||||
* with guest writes to its disk which may be in target backing chain.
|
||||
* Can't resize during a backup block job because we check the size
|
||||
* only upfront.
|
||||
*/
|
||||
*nshared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
|
||||
*nshared = BLK_PERM_ALL;
|
||||
*nperm = BLK_PERM_WRITE;
|
||||
} else {
|
||||
/* Source child */
|
||||
bdrv_default_perms(bs, c, role, reopen_queue,
|
||||
perm, shared, nperm, nshared);
|
||||
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
|
||||
nperm, nshared);
|
||||
|
||||
if (perm & BLK_PERM_WRITE) {
|
||||
*nperm = *nperm | BLK_PERM_CONSISTENT_READ;
|
||||
}
|
||||
*nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
|
||||
*nshared &= ~BLK_PERM_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,28 +187,20 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
BDRVBackupTopState *state;
|
||||
BlockDriverState *top;
|
||||
BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
|
||||
filter_node_name,
|
||||
BDRV_O_RDWR, errp);
|
||||
bool appended = false;
|
||||
|
||||
assert(source->total_sectors == target->total_sectors);
|
||||
|
||||
top = bdrv_new_open_driver(&bdrv_backup_top_filter, filter_node_name,
|
||||
BDRV_O_RDWR, errp);
|
||||
if (!top) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = top->opaque;
|
||||
top->total_sectors = source->total_sectors;
|
||||
top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
(BDRV_REQ_FUA & source->supported_write_flags);
|
||||
top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
|
||||
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
|
||||
source->supported_zero_flags);
|
||||
state = top->opaque;
|
||||
|
||||
bdrv_ref(target);
|
||||
state->target = bdrv_attach_child(top, target, "target", &child_of_bds,
|
||||
BDRV_CHILD_DATA, errp);
|
||||
state->target = bdrv_attach_child(top, target, "target", &child_file, errp);
|
||||
if (!state->target) {
|
||||
bdrv_unref(target);
|
||||
bdrv_unref(top);
|
||||
@@ -244,7 +229,6 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
state->cluster_size = cluster_size;
|
||||
state->bcs = block_copy_state_new(top->backing, state->target,
|
||||
cluster_size, write_flags, &local_err);
|
||||
if (local_err) {
|
||||
@@ -274,6 +258,9 @@ fail:
|
||||
void bdrv_backup_top_drop(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBackupTopState *s = bs->opaque;
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
bdrv_drained_begin(bs);
|
||||
|
||||
@@ -287,4 +274,6 @@ void bdrv_backup_top_drop(BlockDriverState *bs)
|
||||
bdrv_drained_end(bs);
|
||||
|
||||
bdrv_unref(bs);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
+16
-28
@@ -102,7 +102,7 @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
|
||||
|
||||
if (ret < 0 && job->bitmap_mode == BITMAP_SYNC_MODE_ALWAYS) {
|
||||
/* If we failed and synced, merge in the bits we didn't copy: */
|
||||
bdrv_dirty_bitmap_merge_internal(bm, block_copy_dirty_bitmap(job->bcs),
|
||||
bdrv_dirty_bitmap_merge_internal(bm, job->bcs->copy_bitmap,
|
||||
NULL, true);
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,7 @@ static void backup_abort(Job *job)
|
||||
static void backup_clean(Job *job)
|
||||
{
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
||||
|
||||
bdrv_backup_top_drop(s->backup_top);
|
||||
}
|
||||
|
||||
@@ -141,8 +142,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_set_dirty_bitmap(block_copy_dirty_bitmap(backup_job->bcs), 0,
|
||||
backup_job->len);
|
||||
bdrv_set_dirty_bitmap(backup_job->bcs->copy_bitmap, 0, backup_job->len);
|
||||
}
|
||||
|
||||
static BlockErrorAction backup_error_action(BackupBlockJob *job,
|
||||
@@ -187,7 +187,7 @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
|
||||
BdrvDirtyBitmapIter *bdbi;
|
||||
int ret = 0;
|
||||
|
||||
bdbi = bdrv_dirty_iter_new(block_copy_dirty_bitmap(job->bcs));
|
||||
bdbi = bdrv_dirty_iter_new(job->bcs->copy_bitmap);
|
||||
while ((offset = bdrv_dirty_iter_next(bdbi)) != -1) {
|
||||
do {
|
||||
if (yield_and_check(job)) {
|
||||
@@ -207,14 +207,14 @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void backup_init_bcs_bitmap(BackupBlockJob *job)
|
||||
static void backup_init_copy_bitmap(BackupBlockJob *job)
|
||||
{
|
||||
bool ret;
|
||||
uint64_t estimate;
|
||||
BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
|
||||
|
||||
if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
|
||||
ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap,
|
||||
ret = bdrv_dirty_bitmap_merge_internal(job->bcs->copy_bitmap,
|
||||
job->sync_bitmap,
|
||||
NULL, true);
|
||||
assert(ret);
|
||||
} else {
|
||||
@@ -223,12 +223,12 @@ static void backup_init_bcs_bitmap(BackupBlockJob *job)
|
||||
* We can't hog the coroutine to initialize this thoroughly.
|
||||
* Set a flag and resume work when we are able to yield safely.
|
||||
*/
|
||||
block_copy_set_skip_unallocated(job->bcs, true);
|
||||
job->bcs->skip_unallocated = true;
|
||||
}
|
||||
bdrv_set_dirty_bitmap(bcs_bitmap, 0, job->len);
|
||||
bdrv_set_dirty_bitmap(job->bcs->copy_bitmap, 0, job->len);
|
||||
}
|
||||
|
||||
estimate = bdrv_get_dirty_count(bcs_bitmap);
|
||||
estimate = bdrv_get_dirty_count(job->bcs->copy_bitmap);
|
||||
job_progress_set_remaining(&job->common.job, estimate);
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
|
||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
||||
int ret = 0;
|
||||
|
||||
backup_init_bcs_bitmap(s);
|
||||
backup_init_copy_bitmap(s);
|
||||
|
||||
if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
|
||||
int64_t offset = 0;
|
||||
@@ -256,12 +256,12 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
|
||||
|
||||
offset += count;
|
||||
}
|
||||
block_copy_set_skip_unallocated(s->bcs, false);
|
||||
s->bcs->skip_unallocated = false;
|
||||
}
|
||||
|
||||
if (s->sync_mode == MIRROR_SYNC_MODE_NONE) {
|
||||
/*
|
||||
* All bits are set in bcs bitmap to allow any cluster to be copied.
|
||||
* All bits are set in copy_bitmap to allow any cluster to be copied.
|
||||
* This does not actually require them to be copied.
|
||||
*/
|
||||
while (!job_is_cancelled(job)) {
|
||||
@@ -340,7 +340,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque,
|
||||
JobTxn *txn, Error **errp)
|
||||
{
|
||||
int64_t len, target_len;
|
||||
int64_t len;
|
||||
BackupBlockJob *job = NULL;
|
||||
int64_t cluster_size;
|
||||
BdrvRequestFlags write_flags;
|
||||
@@ -400,20 +400,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
||||
|
||||
len = bdrv_getlength(bs);
|
||||
if (len < 0) {
|
||||
error_setg_errno(errp, -len, "Unable to get length for '%s'",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
goto error;
|
||||
}
|
||||
|
||||
target_len = bdrv_getlength(target);
|
||||
if (target_len < 0) {
|
||||
error_setg_errno(errp, -target_len, "Unable to get length for '%s'",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (target_len != len) {
|
||||
error_setg(errp, "Source and target image have different sizes");
|
||||
error_setg_errno(errp, -len, "unable to get length for '%s'",
|
||||
bdrv_get_device_name(bs));
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
+11
-8
@@ -359,6 +359,7 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
|
||||
QObject *crumpled_subqdict = NULL;
|
||||
Visitor *v = NULL;
|
||||
BlockPermissionList *perm_list = NULL, *element;
|
||||
Error *local_err = NULL;
|
||||
|
||||
*dest = 0;
|
||||
|
||||
@@ -374,7 +375,9 @@ static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
|
||||
}
|
||||
|
||||
v = qobject_input_visitor_new(crumpled_subqdict);
|
||||
if (!visit_type_BlockPermissionList(v, NULL, &perm_list, errp)) {
|
||||
visit_type_BlockPermissionList(v, NULL, &perm_list, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -469,7 +472,9 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
uint64_t align;
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -492,9 +497,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
/* Open the image file */
|
||||
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
|
||||
bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, &local_err);
|
||||
bs, &child_file, false, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
@@ -990,15 +993,15 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
|
||||
}
|
||||
|
||||
static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
const BdrvChildRole *role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
|
||||
bdrv_default_perms(bs, c, role, reopen_queue,
|
||||
perm, shared, nperm, nshared);
|
||||
bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
|
||||
nperm, nshared);
|
||||
|
||||
*nperm |= s->take_child_perms;
|
||||
*nshared &= ~s->unshare_child_perms;
|
||||
|
||||
+12
-8
@@ -149,14 +149,15 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
bool log_append;
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Open the file */
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, false,
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
@@ -165,8 +166,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
/* Open the log file */
|
||||
s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_of_bds,
|
||||
BDRV_CHILD_METADATA, false, &local_err);
|
||||
s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
@@ -281,7 +282,7 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
const BdrvChildRole *role,
|
||||
BlockReopenQueue *ro_q,
|
||||
uint64_t perm, uint64_t shrd,
|
||||
uint64_t *nperm, uint64_t *nshrd)
|
||||
@@ -292,8 +293,11 @@ static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_default_perms(bs, c, role, ro_q, perm, shrd,
|
||||
nperm, nshrd);
|
||||
if (!strcmp(c->name, "log")) {
|
||||
bdrv_format_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
|
||||
} else {
|
||||
bdrv_filter_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd);
|
||||
}
|
||||
}
|
||||
|
||||
static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
|
||||
+3
-5
@@ -27,9 +27,8 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
|
||||
/* Open the image file */
|
||||
bs->file = bdrv_open_child(NULL, options, "image", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, &local_err);
|
||||
bs->file = bdrv_open_child(NULL, options, "image",
|
||||
bs, &child_file, false, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
@@ -136,10 +135,9 @@ static int blkreplay_snapshot_goto(BlockDriverState *bs,
|
||||
static BlockDriver bdrv_blkreplay = {
|
||||
.format_name = "blkreplay",
|
||||
.instance_size = 0,
|
||||
.is_filter = true,
|
||||
|
||||
.bdrv_open = blkreplay_open,
|
||||
.bdrv_child_perm = bdrv_default_perms,
|
||||
.bdrv_child_perm = bdrv_filter_default_perms,
|
||||
.bdrv_getlength = blkreplay_getlength,
|
||||
|
||||
.bdrv_co_preadv = blkreplay_co_preadv,
|
||||
|
||||
+17
-17
@@ -116,16 +116,16 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int ret;
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Open the raw file */
|
||||
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw",
|
||||
bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, &local_err);
|
||||
bs, &child_file, false, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
@@ -134,8 +134,8 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
/* Open the test file */
|
||||
s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options,
|
||||
"test", bs, &child_of_bds, BDRV_CHILD_DATA,
|
||||
false, &local_err);
|
||||
"test", bs, &child_format, false,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
error_propagate(errp, local_err);
|
||||
@@ -268,18 +268,18 @@ static int blkverify_co_flush(BlockDriverState *bs)
|
||||
return bdrv_co_flush(s->test_file->bs);
|
||||
}
|
||||
|
||||
static bool blkverify_recurse_can_replace(BlockDriverState *bs,
|
||||
BlockDriverState *to_replace)
|
||||
static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
|
||||
/*
|
||||
* blkverify quits the whole qemu process if there is a mismatch
|
||||
* between bs->file->bs and s->test_file->bs. Therefore, we know
|
||||
* know that both must match bs and we can recurse down to either.
|
||||
*/
|
||||
return bdrv_recurse_can_replace(bs->file->bs, to_replace) ||
|
||||
bdrv_recurse_can_replace(s->test_file->bs, to_replace);
|
||||
bool perm = bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
|
||||
|
||||
if (perm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate);
|
||||
}
|
||||
|
||||
static void blkverify_refresh_filename(BlockDriverState *bs)
|
||||
@@ -317,7 +317,7 @@ static BlockDriver bdrv_blkverify = {
|
||||
.bdrv_parse_filename = blkverify_parse_filename,
|
||||
.bdrv_file_open = blkverify_open,
|
||||
.bdrv_close = blkverify_close,
|
||||
.bdrv_child_perm = bdrv_default_perms,
|
||||
.bdrv_child_perm = bdrv_filter_default_perms,
|
||||
.bdrv_getlength = blkverify_getlength,
|
||||
.bdrv_refresh_filename = blkverify_refresh_filename,
|
||||
.bdrv_dirname = blkverify_dirname,
|
||||
@@ -327,7 +327,7 @@ static BlockDriver bdrv_blkverify = {
|
||||
.bdrv_co_flush = blkverify_co_flush,
|
||||
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_can_replace = blkverify_recurse_can_replace,
|
||||
.bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
|
||||
};
|
||||
|
||||
static void bdrv_blkverify_init(void)
|
||||
|
||||
+89
-186
@@ -120,8 +120,7 @@ static QTAILQ_HEAD(, BlockBackend) block_backends =
|
||||
static QTAILQ_HEAD(, BlockBackend) monitor_block_backends =
|
||||
QTAILQ_HEAD_INITIALIZER(monitor_block_backends);
|
||||
|
||||
static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format,
|
||||
int *child_flags, QDict *child_options,
|
||||
static void blk_root_inherit_options(int *child_flags, QDict *child_options,
|
||||
int parent_flags, QDict *parent_options)
|
||||
{
|
||||
/* We're not supposed to call this function for root nodes */
|
||||
@@ -298,7 +297,7 @@ static void blk_root_detach(BdrvChild *child)
|
||||
}
|
||||
}
|
||||
|
||||
static const BdrvChildClass child_root = {
|
||||
static const BdrvChildRole child_root = {
|
||||
.inherit_options = blk_root_inherit_options,
|
||||
|
||||
.change_media = blk_root_change_media,
|
||||
@@ -356,29 +355,6 @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
|
||||
return blk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new BlockBackend connected to an existing BlockDriverState.
|
||||
*
|
||||
* @perm is a bitmasks of BLK_PERM_* constants which describes the
|
||||
* permissions to request for @bs that is attached to this
|
||||
* BlockBackend. @shared_perm is a bitmask which describes which
|
||||
* permissions may be granted to other users of the attached node.
|
||||
* Both sets of permissions can be changed later using blk_set_perm().
|
||||
*
|
||||
* Return the new BlockBackend on success, null on failure.
|
||||
*/
|
||||
BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm,
|
||||
uint64_t shared_perm, Error **errp)
|
||||
{
|
||||
BlockBackend *blk = blk_new(bdrv_get_aio_context(bs), perm, shared_perm);
|
||||
|
||||
if (blk_insert_bs(blk, bs, errp) < 0) {
|
||||
blk_unref(blk);
|
||||
return NULL;
|
||||
}
|
||||
return blk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new BlockBackend, opens a new BlockDriverState, and connects both.
|
||||
* The new BlockBackend is in the main AioContext.
|
||||
@@ -424,9 +400,8 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
blk->ctx, perm, BLK_PERM_ALL, blk, errp);
|
||||
blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
|
||||
perm, BLK_PERM_ALL, blk, errp);
|
||||
if (!blk->root) {
|
||||
blk_unref(blk);
|
||||
return NULL;
|
||||
@@ -718,7 +693,7 @@ static BlockBackend *bdrv_first_blk(BlockDriverState *bs)
|
||||
{
|
||||
BdrvChild *child;
|
||||
QLIST_FOREACH(child, &bs->parents, next_parent) {
|
||||
if (child->klass == &child_root) {
|
||||
if (child->role == &child_root) {
|
||||
return child->opaque;
|
||||
}
|
||||
}
|
||||
@@ -742,7 +717,7 @@ bool bdrv_is_root_node(BlockDriverState *bs)
|
||||
BdrvChild *c;
|
||||
|
||||
QLIST_FOREACH(c, &bs->parents, next_parent) {
|
||||
if (c->klass != &child_root) {
|
||||
if (c->role != &child_root) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -808,7 +783,6 @@ void blk_remove_bs(BlockBackend *blk)
|
||||
{
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
BlockDriverState *bs;
|
||||
BdrvChild *root;
|
||||
|
||||
notifier_list_notify(&blk->remove_bs_notifiers, blk);
|
||||
if (tgm->throttle_state) {
|
||||
@@ -826,9 +800,8 @@ void blk_remove_bs(BlockBackend *blk)
|
||||
* to avoid that and a potential QEMU crash.
|
||||
*/
|
||||
blk_drain(blk);
|
||||
root = blk->root;
|
||||
bdrv_root_unref_child(blk->root);
|
||||
blk->root = NULL;
|
||||
bdrv_root_unref_child(root);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -838,10 +811,8 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
|
||||
bdrv_ref(bs);
|
||||
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
blk->ctx, blk->perm, blk->shared_perm,
|
||||
blk, errp);
|
||||
blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
|
||||
blk->perm, blk->shared_perm, blk, errp);
|
||||
if (blk->root == NULL) {
|
||||
return -EPERM;
|
||||
}
|
||||
@@ -1169,22 +1140,16 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
|
||||
{
|
||||
assert(blk->in_flight > 0);
|
||||
|
||||
if (blk->quiesce_counter && !blk->disable_request_queuing) {
|
||||
blk_dec_in_flight(blk);
|
||||
qemu_co_queue_wait(&blk->queued_requests, NULL);
|
||||
blk_inc_in_flight(blk);
|
||||
}
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static int coroutine_fn
|
||||
blk_do_preadv(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
QEMUIOVector *qiov, BdrvRequestFlags flags)
|
||||
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
BlockDriverState *bs;
|
||||
@@ -1213,24 +1178,10 @@ blk_do_preadv(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_do_preadv(blk, offset, bytes, qiov, flags);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static int coroutine_fn
|
||||
blk_do_pwritev_part(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
BlockDriverState *bs;
|
||||
@@ -1263,20 +1214,6 @@ blk_do_pwritev_part(BlockBackend *blk, int64_t offset, unsigned int bytes,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes,
|
||||
QEMUIOVector *qiov, size_t qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
|
||||
unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
@@ -1297,7 +1234,7 @@ static void blk_read_entry(void *opaque)
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, qiov->size,
|
||||
rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, qiov->size,
|
||||
qiov, rwco->flags);
|
||||
aio_wait_kick();
|
||||
}
|
||||
@@ -1307,8 +1244,8 @@ static void blk_write_entry(void *opaque)
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, qiov->size,
|
||||
qiov, 0, rwco->flags);
|
||||
rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, qiov->size,
|
||||
qiov, rwco->flags);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
@@ -1325,7 +1262,6 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
.ret = NOT_DONE,
|
||||
};
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
if (qemu_in_coroutine()) {
|
||||
/* Fast-path if already in coroutine context */
|
||||
co_entry(&rwco);
|
||||
@@ -1334,7 +1270,6 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
|
||||
bdrv_coroutine_enter(blk_bs(blk), co);
|
||||
BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE);
|
||||
}
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return rwco.ret;
|
||||
}
|
||||
@@ -1394,16 +1329,8 @@ typedef struct BlkAioEmAIOCB {
|
||||
bool has_returned;
|
||||
} BlkAioEmAIOCB;
|
||||
|
||||
static AioContext *blk_aio_em_aiocb_get_aio_context(BlockAIOCB *acb_)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = container_of(acb_, BlkAioEmAIOCB, common);
|
||||
|
||||
return blk_get_aio_context(acb->rwco.blk);
|
||||
}
|
||||
|
||||
static const AIOCBInfo blk_aio_em_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlkAioEmAIOCB),
|
||||
.get_aio_context = blk_aio_em_aiocb_get_aio_context,
|
||||
};
|
||||
|
||||
static void blk_aio_complete(BlkAioEmAIOCB *acb)
|
||||
@@ -1460,8 +1387,14 @@ static void blk_aio_read_entry(void *opaque)
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
if (rwco->blk->quiesce_counter) {
|
||||
blk_dec_in_flight(rwco->blk);
|
||||
blk_wait_while_drained(rwco->blk);
|
||||
blk_inc_in_flight(rwco->blk);
|
||||
}
|
||||
|
||||
assert(qiov->size == acb->bytes);
|
||||
rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, acb->bytes,
|
||||
rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, acb->bytes,
|
||||
qiov, rwco->flags);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
@@ -1472,9 +1405,15 @@ static void blk_aio_write_entry(void *opaque)
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
if (rwco->blk->quiesce_counter) {
|
||||
blk_dec_in_flight(rwco->blk);
|
||||
blk_wait_while_drained(rwco->blk);
|
||||
blk_inc_in_flight(rwco->blk);
|
||||
}
|
||||
|
||||
assert(!qiov || qiov->size == acb->bytes);
|
||||
rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, acb->bytes,
|
||||
qiov, 0, rwco->flags);
|
||||
rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, acb->bytes,
|
||||
qiov, rwco->flags);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
@@ -1549,6 +1488,38 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
|
||||
blk_aio_write_entry, flags, cb, opaque);
|
||||
}
|
||||
|
||||
static void blk_aio_flush_entry(void *opaque)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_co_flush(rwco->blk);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_flush(BlockBackend *blk,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque);
|
||||
}
|
||||
|
||||
static void blk_aio_pdiscard_entry(void *opaque)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, acb->bytes);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
|
||||
int64_t offset, int bytes,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0,
|
||||
cb, opaque);
|
||||
}
|
||||
|
||||
void blk_aio_cancel(BlockAIOCB *acb)
|
||||
{
|
||||
bdrv_aio_cancel(acb);
|
||||
@@ -1559,9 +1530,7 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
|
||||
bdrv_aio_cancel_async(acb);
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static int coroutine_fn
|
||||
blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
int blk_co_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
{
|
||||
blk_wait_while_drained(blk);
|
||||
|
||||
@@ -1577,7 +1546,8 @@ static void blk_ioctl_entry(void *opaque)
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, qiov->iov[0].iov_base);
|
||||
rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset,
|
||||
qiov->iov[0].iov_base);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
@@ -1591,7 +1561,7 @@ static void blk_aio_ioctl_entry(void *opaque)
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf);
|
||||
rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset, rwco->iobuf);
|
||||
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
@@ -1602,9 +1572,7 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
||||
return blk_aio_prwv(blk, req, 0, buf, blk_aio_ioctl_entry, 0, cb, opaque);
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static int coroutine_fn
|
||||
blk_do_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -1618,50 +1586,7 @@ blk_do_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
return bdrv_co_pdiscard(blk->root, offset, bytes);
|
||||
}
|
||||
|
||||
static void blk_aio_pdiscard_entry(void *opaque)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, acb->bytes);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
|
||||
int64_t offset, int bytes,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0,
|
||||
cb, opaque);
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_do_pdiscard(blk, offset, bytes);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void blk_pdiscard_entry(void *opaque)
|
||||
{
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, qiov->size);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
{
|
||||
return blk_prw(blk, offset, NULL, bytes, blk_pdiscard_entry, 0);
|
||||
}
|
||||
|
||||
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
|
||||
static int coroutine_fn blk_do_flush(BlockBackend *blk)
|
||||
int blk_co_flush(BlockBackend *blk)
|
||||
{
|
||||
blk_wait_while_drained(blk);
|
||||
|
||||
@@ -1672,36 +1597,10 @@ static int coroutine_fn blk_do_flush(BlockBackend *blk)
|
||||
return bdrv_co_flush(blk_bs(blk));
|
||||
}
|
||||
|
||||
static void blk_aio_flush_entry(void *opaque)
|
||||
{
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
BlkRwCo *rwco = &acb->rwco;
|
||||
|
||||
rwco->ret = blk_do_flush(rwco->blk);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_flush(BlockBackend *blk,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque);
|
||||
}
|
||||
|
||||
int coroutine_fn blk_co_flush(BlockBackend *blk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
blk_inc_in_flight(blk);
|
||||
ret = blk_do_flush(blk);
|
||||
blk_dec_in_flight(blk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void blk_flush_entry(void *opaque)
|
||||
{
|
||||
BlkRwCo *rwco = opaque;
|
||||
rwco->ret = blk_do_flush(rwco->blk);
|
||||
rwco->ret = blk_co_flush(rwco->blk);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
@@ -2174,14 +2073,28 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
|
||||
}
|
||||
|
||||
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
|
||||
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
|
||||
PreallocMode prealloc, Error **errp)
|
||||
{
|
||||
if (!blk_is_available(blk)) {
|
||||
error_setg(errp, "No medium inserted");
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
|
||||
return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
|
||||
}
|
||||
|
||||
static void blk_pdiscard_entry(void *opaque)
|
||||
{
|
||||
BlkRwCo *rwco = opaque;
|
||||
QEMUIOVector *qiov = rwco->iobuf;
|
||||
|
||||
rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, qiov->size);
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
|
||||
{
|
||||
return blk_prw(blk, offset, NULL, bytes, blk_pdiscard_entry, 0);
|
||||
}
|
||||
|
||||
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
|
||||
@@ -2416,13 +2329,3 @@ const BdrvChild *blk_root(BlockBackend *blk)
|
||||
{
|
||||
return blk->root;
|
||||
}
|
||||
|
||||
int blk_make_empty(BlockBackend *blk, Error **errp)
|
||||
{
|
||||
if (!blk_is_available(blk)) {
|
||||
error_setg(errp, "No medium inserted");
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
return bdrv_make_empty(blk->root, errp);
|
||||
}
|
||||
+111
-435
@@ -19,181 +19,44 @@
|
||||
#include "block/block-copy.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/coroutine.h"
|
||||
#include "block/aio_task.h"
|
||||
|
||||
#define BLOCK_COPY_MAX_COPY_RANGE (16 * MiB)
|
||||
#define BLOCK_COPY_MAX_BUFFER (1 * MiB)
|
||||
#define BLOCK_COPY_MAX_MEM (128 * MiB)
|
||||
#define BLOCK_COPY_MAX_WORKERS 64
|
||||
|
||||
static coroutine_fn int block_copy_task_entry(AioTask *task);
|
||||
|
||||
typedef struct BlockCopyCallState {
|
||||
bool failed;
|
||||
bool error_is_read;
|
||||
} BlockCopyCallState;
|
||||
|
||||
typedef struct BlockCopyTask {
|
||||
AioTask task;
|
||||
|
||||
BlockCopyState *s;
|
||||
BlockCopyCallState *call_state;
|
||||
int64_t offset;
|
||||
int64_t bytes;
|
||||
bool zeroes;
|
||||
QLIST_ENTRY(BlockCopyTask) list;
|
||||
CoQueue wait_queue; /* coroutines blocked on this task */
|
||||
} BlockCopyTask;
|
||||
|
||||
static int64_t task_end(BlockCopyTask *task)
|
||||
static void coroutine_fn block_copy_wait_inflight_reqs(BlockCopyState *s,
|
||||
int64_t start,
|
||||
int64_t end)
|
||||
{
|
||||
return task->offset + task->bytes;
|
||||
}
|
||||
BlockCopyInFlightReq *req;
|
||||
bool waited;
|
||||
|
||||
typedef struct BlockCopyState {
|
||||
/*
|
||||
* BdrvChild objects are not owned or managed by block-copy. They are
|
||||
* provided by block-copy user and user is responsible for appropriate
|
||||
* permissions on these children.
|
||||
*/
|
||||
BdrvChild *source;
|
||||
BdrvChild *target;
|
||||
BdrvDirtyBitmap *copy_bitmap;
|
||||
int64_t in_flight_bytes;
|
||||
int64_t cluster_size;
|
||||
bool use_copy_range;
|
||||
int64_t copy_size;
|
||||
uint64_t len;
|
||||
QLIST_HEAD(, BlockCopyTask) tasks;
|
||||
|
||||
BdrvRequestFlags write_flags;
|
||||
|
||||
/*
|
||||
* skip_unallocated:
|
||||
*
|
||||
* Used by sync=top jobs, which first scan the source node for unallocated
|
||||
* areas and clear them in the copy_bitmap. During this process, the bitmap
|
||||
* is thus not fully initialized: It may still have bits set for areas that
|
||||
* are unallocated and should actually not be copied.
|
||||
*
|
||||
* This is indicated by skip_unallocated.
|
||||
*
|
||||
* In this case, block_copy() will query the source’s allocation status,
|
||||
* skip unallocated regions, clear them in the copy_bitmap, and invoke
|
||||
* block_copy_reset_unallocated() every time it does.
|
||||
*/
|
||||
bool skip_unallocated;
|
||||
|
||||
ProgressMeter *progress;
|
||||
/* progress_bytes_callback: called when some copying progress is done. */
|
||||
ProgressBytesCallbackFunc progress_bytes_callback;
|
||||
void *progress_opaque;
|
||||
|
||||
SharedResource *mem;
|
||||
} BlockCopyState;
|
||||
|
||||
static BlockCopyTask *find_conflicting_task(BlockCopyState *s,
|
||||
int64_t offset, int64_t bytes)
|
||||
{
|
||||
BlockCopyTask *t;
|
||||
|
||||
QLIST_FOREACH(t, &s->tasks, list) {
|
||||
if (offset + bytes > t->offset && offset < t->offset + t->bytes) {
|
||||
return t;
|
||||
do {
|
||||
waited = false;
|
||||
QLIST_FOREACH(req, &s->inflight_reqs, list) {
|
||||
if (end > req->start_byte && start < req->end_byte) {
|
||||
qemu_co_queue_wait(&req->wait_queue, NULL);
|
||||
waited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} while (waited);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no intersecting tasks return false. Otherwise, wait for the
|
||||
* first found intersecting tasks to finish and return true.
|
||||
*/
|
||||
static bool coroutine_fn block_copy_wait_one(BlockCopyState *s, int64_t offset,
|
||||
int64_t bytes)
|
||||
static void block_copy_inflight_req_begin(BlockCopyState *s,
|
||||
BlockCopyInFlightReq *req,
|
||||
int64_t start, int64_t end)
|
||||
{
|
||||
BlockCopyTask *task = find_conflicting_task(s, offset, bytes);
|
||||
|
||||
if (!task) {
|
||||
return false;
|
||||
}
|
||||
|
||||
qemu_co_queue_wait(&task->wait_queue, NULL);
|
||||
|
||||
return true;
|
||||
req->start_byte = start;
|
||||
req->end_byte = end;
|
||||
qemu_co_queue_init(&req->wait_queue);
|
||||
QLIST_INSERT_HEAD(&s->inflight_reqs, req, list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for the first dirty area in offset/bytes range and create task at
|
||||
* the beginning of it.
|
||||
*/
|
||||
static BlockCopyTask *block_copy_task_create(BlockCopyState *s,
|
||||
BlockCopyCallState *call_state,
|
||||
int64_t offset, int64_t bytes)
|
||||
static void coroutine_fn block_copy_inflight_req_end(BlockCopyInFlightReq *req)
|
||||
{
|
||||
BlockCopyTask *task;
|
||||
|
||||
if (!bdrv_dirty_bitmap_next_dirty_area(s->copy_bitmap,
|
||||
offset, offset + bytes,
|
||||
s->copy_size, &offset, &bytes))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* region is dirty, so no existent tasks possible in it */
|
||||
assert(!find_conflicting_task(s, offset, bytes));
|
||||
|
||||
bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
|
||||
s->in_flight_bytes += bytes;
|
||||
|
||||
task = g_new(BlockCopyTask, 1);
|
||||
*task = (BlockCopyTask) {
|
||||
.task.func = block_copy_task_entry,
|
||||
.s = s,
|
||||
.call_state = call_state,
|
||||
.offset = offset,
|
||||
.bytes = bytes,
|
||||
};
|
||||
qemu_co_queue_init(&task->wait_queue);
|
||||
QLIST_INSERT_HEAD(&s->tasks, task, list);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/*
|
||||
* block_copy_task_shrink
|
||||
*
|
||||
* Drop the tail of the task to be handled later. Set dirty bits back and
|
||||
* wake up all tasks waiting for us (may be some of them are not intersecting
|
||||
* with shrunk task)
|
||||
*/
|
||||
static void coroutine_fn block_copy_task_shrink(BlockCopyTask *task,
|
||||
int64_t new_bytes)
|
||||
{
|
||||
if (new_bytes == task->bytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(new_bytes > 0 && new_bytes < task->bytes);
|
||||
|
||||
task->s->in_flight_bytes -= task->bytes - new_bytes;
|
||||
bdrv_set_dirty_bitmap(task->s->copy_bitmap,
|
||||
task->offset + new_bytes, task->bytes - new_bytes);
|
||||
|
||||
task->bytes = new_bytes;
|
||||
qemu_co_queue_restart_all(&task->wait_queue);
|
||||
}
|
||||
|
||||
static void coroutine_fn block_copy_task_end(BlockCopyTask *task, int ret)
|
||||
{
|
||||
task->s->in_flight_bytes -= task->bytes;
|
||||
if (ret < 0) {
|
||||
bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset, task->bytes);
|
||||
}
|
||||
QLIST_REMOVE(task, list);
|
||||
qemu_co_queue_restart_all(&task->wait_queue);
|
||||
QLIST_REMOVE(req, list);
|
||||
qemu_co_queue_restart_all(&req->wait_queue);
|
||||
}
|
||||
|
||||
void block_copy_state_free(BlockCopyState *s)
|
||||
@@ -207,19 +70,16 @@ void block_copy_state_free(BlockCopyState *s)
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target)
|
||||
{
|
||||
return MIN_NON_ZERO(INT_MAX,
|
||||
MIN_NON_ZERO(source->bs->bl.max_transfer,
|
||||
target->bs->bl.max_transfer));
|
||||
}
|
||||
|
||||
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
|
||||
int64_t cluster_size,
|
||||
BdrvRequestFlags write_flags, Error **errp)
|
||||
{
|
||||
BlockCopyState *s;
|
||||
BdrvDirtyBitmap *copy_bitmap;
|
||||
uint32_t max_transfer =
|
||||
MIN_NON_ZERO(INT_MAX,
|
||||
MIN_NON_ZERO(source->bs->bl.max_transfer,
|
||||
target->bs->bl.max_transfer));
|
||||
|
||||
copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL,
|
||||
errp);
|
||||
@@ -239,7 +99,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
|
||||
.mem = shres_create(BLOCK_COPY_MAX_MEM),
|
||||
};
|
||||
|
||||
if (block_copy_max_transfer(source, target) < cluster_size) {
|
||||
if (max_transfer < cluster_size) {
|
||||
/*
|
||||
* copy_range does not respect max_transfer. We don't want to bother
|
||||
* with requests smaller than block-copy cluster size, so fallback to
|
||||
@@ -254,14 +114,15 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
|
||||
s->copy_size = cluster_size;
|
||||
} else {
|
||||
/*
|
||||
* We enable copy-range, but keep small copy_size, until first
|
||||
* successful copy_range (look at block_copy_do_copy).
|
||||
* copy_range does not respect max_transfer (it's a TODO), so we factor
|
||||
* that in here.
|
||||
*/
|
||||
s->use_copy_range = true;
|
||||
s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
|
||||
s->copy_size = MIN(MAX(cluster_size, BLOCK_COPY_MAX_COPY_RANGE),
|
||||
QEMU_ALIGN_DOWN(max_transfer, cluster_size));
|
||||
}
|
||||
|
||||
QLIST_INIT(&s->tasks);
|
||||
QLIST_INIT(&s->inflight_reqs);
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -280,99 +141,37 @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm)
|
||||
s->progress = pm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes ownership of @task
|
||||
*
|
||||
* If pool is NULL directly run the task, otherwise schedule it into the pool.
|
||||
*
|
||||
* Returns: task.func return code if pool is NULL
|
||||
* otherwise -ECANCELED if pool status is bad
|
||||
* otherwise 0 (successfully scheduled)
|
||||
*/
|
||||
static coroutine_fn int block_copy_task_run(AioTaskPool *pool,
|
||||
BlockCopyTask *task)
|
||||
{
|
||||
if (!pool) {
|
||||
int ret = task->task.func(&task->task);
|
||||
|
||||
g_free(task);
|
||||
return ret;
|
||||
}
|
||||
|
||||
aio_task_pool_wait_slot(pool);
|
||||
if (aio_task_pool_status(pool) < 0) {
|
||||
co_put_to_shres(task->s->mem, task->bytes);
|
||||
block_copy_task_end(task, -ECANCELED);
|
||||
g_free(task);
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
aio_task_pool_start_task(pool, &task->task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* block_copy_do_copy
|
||||
*
|
||||
* Do copy of cluster-aligned chunk. Requested region is allowed to exceed
|
||||
* s->len only to cover last cluster when s->len is not aligned to clusters.
|
||||
* Do copy of cluser-aligned chunk. @end is allowed to exceed s->len only to
|
||||
* cover last cluster when s->len is not aligned to clusters.
|
||||
*
|
||||
* No sync here: nor bitmap neighter intersecting requests handling, only copy.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
|
||||
int64_t offset, int64_t bytes,
|
||||
bool zeroes, bool *error_is_read)
|
||||
int64_t start, int64_t end,
|
||||
bool *error_is_read)
|
||||
{
|
||||
int ret;
|
||||
int64_t nbytes = MIN(offset + bytes, s->len) - offset;
|
||||
int nbytes = MIN(end, s->len) - start;
|
||||
void *bounce_buffer = NULL;
|
||||
|
||||
assert(offset >= 0 && bytes > 0 && INT64_MAX - offset >= bytes);
|
||||
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
|
||||
assert(offset < s->len);
|
||||
assert(offset + bytes <= s->len ||
|
||||
offset + bytes == QEMU_ALIGN_UP(s->len, s->cluster_size));
|
||||
assert(nbytes < INT_MAX);
|
||||
|
||||
if (zeroes) {
|
||||
ret = bdrv_co_pwrite_zeroes(s->target, offset, nbytes, s->write_flags &
|
||||
~BDRV_REQ_WRITE_COMPRESSED);
|
||||
if (ret < 0) {
|
||||
trace_block_copy_write_zeroes_fail(s, offset, ret);
|
||||
*error_is_read = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
assert(QEMU_IS_ALIGNED(start, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(end, s->cluster_size));
|
||||
assert(end < s->len || end == QEMU_ALIGN_UP(s->len, s->cluster_size));
|
||||
|
||||
if (s->use_copy_range) {
|
||||
ret = bdrv_co_copy_range(s->source, offset, s->target, offset, nbytes,
|
||||
ret = bdrv_co_copy_range(s->source, start, s->target, start, nbytes,
|
||||
0, s->write_flags);
|
||||
if (ret < 0) {
|
||||
trace_block_copy_copy_range_fail(s, offset, ret);
|
||||
trace_block_copy_copy_range_fail(s, start, ret);
|
||||
s->use_copy_range = false;
|
||||
s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER);
|
||||
/* Fallback to read+write with allocated buffer */
|
||||
} else {
|
||||
if (s->use_copy_range) {
|
||||
/*
|
||||
* Successful copy-range. Now increase copy_size. copy_range
|
||||
* does not respect max_transfer (it's a TODO), so we factor
|
||||
* that in here.
|
||||
*
|
||||
* Note: we double-check s->use_copy_range for the case when
|
||||
* parallel block-copy request unsets it during previous
|
||||
* bdrv_co_copy_range call.
|
||||
*/
|
||||
s->copy_size =
|
||||
MIN(MAX(s->cluster_size, BLOCK_COPY_MAX_COPY_RANGE),
|
||||
QEMU_ALIGN_DOWN(block_copy_max_transfer(s->source,
|
||||
s->target),
|
||||
s->cluster_size));
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -380,26 +179,27 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
|
||||
/*
|
||||
* In case of failed copy_range request above, we may proceed with buffered
|
||||
* request larger than BLOCK_COPY_MAX_BUFFER. Still, further requests will
|
||||
* be properly limited, so don't care too much. Moreover the most likely
|
||||
* case (copy_range is unsupported for the configuration, so the very first
|
||||
* copy_range request fails) is handled by setting large copy_size only
|
||||
* after first successful copy_range.
|
||||
* be properly limited, so don't care too much.
|
||||
*/
|
||||
|
||||
bounce_buffer = qemu_blockalign(s->source->bs, nbytes);
|
||||
|
||||
ret = bdrv_co_pread(s->source, offset, nbytes, bounce_buffer, 0);
|
||||
ret = bdrv_co_pread(s->source, start, nbytes, bounce_buffer, 0);
|
||||
if (ret < 0) {
|
||||
trace_block_copy_read_fail(s, offset, ret);
|
||||
*error_is_read = true;
|
||||
trace_block_copy_read_fail(s, start, ret);
|
||||
if (error_is_read) {
|
||||
*error_is_read = true;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = bdrv_co_pwrite(s->target, offset, nbytes, bounce_buffer,
|
||||
ret = bdrv_co_pwrite(s->target, start, nbytes, bounce_buffer,
|
||||
s->write_flags);
|
||||
if (ret < 0) {
|
||||
trace_block_copy_write_fail(s, offset, ret);
|
||||
*error_is_read = false;
|
||||
trace_block_copy_write_fail(s, start, ret);
|
||||
if (error_is_read) {
|
||||
*error_is_read = false;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -409,59 +209,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static coroutine_fn int block_copy_task_entry(AioTask *task)
|
||||
{
|
||||
BlockCopyTask *t = container_of(task, BlockCopyTask, task);
|
||||
bool error_is_read = false;
|
||||
int ret;
|
||||
|
||||
ret = block_copy_do_copy(t->s, t->offset, t->bytes, t->zeroes,
|
||||
&error_is_read);
|
||||
if (ret < 0 && !t->call_state->failed) {
|
||||
t->call_state->failed = true;
|
||||
t->call_state->error_is_read = error_is_read;
|
||||
} else {
|
||||
progress_work_done(t->s->progress, t->bytes);
|
||||
t->s->progress_bytes_callback(t->bytes, t->s->progress_opaque);
|
||||
}
|
||||
co_put_to_shres(t->s->mem, t->bytes);
|
||||
block_copy_task_end(t, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int block_copy_block_status(BlockCopyState *s, int64_t offset,
|
||||
int64_t bytes, int64_t *pnum)
|
||||
{
|
||||
int64_t num;
|
||||
BlockDriverState *base;
|
||||
int ret;
|
||||
|
||||
if (s->skip_unallocated && s->source->bs->backing) {
|
||||
base = s->source->bs->backing->bs;
|
||||
} else {
|
||||
base = NULL;
|
||||
}
|
||||
|
||||
ret = bdrv_block_status_above(s->source->bs, base, offset, bytes, &num,
|
||||
NULL, NULL);
|
||||
if (ret < 0 || num < s->cluster_size) {
|
||||
/*
|
||||
* On error or if failed to obtain large enough chunk just fallback to
|
||||
* copy one cluster.
|
||||
*/
|
||||
num = s->cluster_size;
|
||||
ret = BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_DATA;
|
||||
} else if (offset + num == s->len) {
|
||||
num = QEMU_ALIGN_UP(num, s->cluster_size);
|
||||
} else {
|
||||
num = QEMU_ALIGN_DOWN(num, s->cluster_size);
|
||||
}
|
||||
|
||||
*pnum = num;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the cluster starting at offset is allocated or not.
|
||||
* return via pnum the number of contiguous clusters sharing this allocation.
|
||||
@@ -534,22 +281,14 @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* block_copy_dirty_clusters
|
||||
*
|
||||
* Copy dirty clusters in @offset/@bytes range.
|
||||
* Returns 1 if dirty clusters found and successfully copied, 0 if no dirty
|
||||
* clusters found and -errno on failure.
|
||||
*/
|
||||
static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s,
|
||||
int64_t offset, int64_t bytes,
|
||||
bool *error_is_read)
|
||||
int coroutine_fn block_copy(BlockCopyState *s,
|
||||
int64_t start, uint64_t bytes,
|
||||
bool *error_is_read)
|
||||
{
|
||||
int ret = 0;
|
||||
bool found_dirty = false;
|
||||
int64_t end = offset + bytes;
|
||||
AioTaskPool *aio = NULL;
|
||||
BlockCopyCallState call_state = {false, false};
|
||||
int64_t end = bytes + start; /* bytes */
|
||||
int64_t status_bytes;
|
||||
BlockCopyInFlightReq req;
|
||||
|
||||
/*
|
||||
* block_copy() user is responsible for keeping source and target in same
|
||||
@@ -558,126 +297,63 @@ static int coroutine_fn block_copy_dirty_clusters(BlockCopyState *s,
|
||||
assert(bdrv_get_aio_context(s->source->bs) ==
|
||||
bdrv_get_aio_context(s->target->bs));
|
||||
|
||||
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(start, s->cluster_size));
|
||||
assert(QEMU_IS_ALIGNED(end, s->cluster_size));
|
||||
|
||||
while (bytes && aio_task_pool_status(aio) == 0) {
|
||||
BlockCopyTask *task;
|
||||
int64_t status_bytes;
|
||||
block_copy_wait_inflight_reqs(s, start, bytes);
|
||||
block_copy_inflight_req_begin(s, &req, start, end);
|
||||
|
||||
task = block_copy_task_create(s, &call_state, offset, bytes);
|
||||
if (!task) {
|
||||
/* No more dirty bits in the bitmap */
|
||||
trace_block_copy_skip_range(s, offset, bytes);
|
||||
while (start < end) {
|
||||
int64_t next_zero, chunk_end;
|
||||
|
||||
if (!bdrv_dirty_bitmap_get(s->copy_bitmap, start)) {
|
||||
trace_block_copy_skip(s, start);
|
||||
start += s->cluster_size;
|
||||
continue; /* already copied */
|
||||
}
|
||||
|
||||
chunk_end = MIN(end, start + s->copy_size);
|
||||
|
||||
next_zero = bdrv_dirty_bitmap_next_zero(s->copy_bitmap, start,
|
||||
chunk_end - start);
|
||||
if (next_zero >= 0) {
|
||||
assert(next_zero > start); /* start is dirty */
|
||||
assert(next_zero < chunk_end); /* no need to do MIN() */
|
||||
chunk_end = next_zero;
|
||||
}
|
||||
|
||||
if (s->skip_unallocated) {
|
||||
ret = block_copy_reset_unallocated(s, start, &status_bytes);
|
||||
if (ret == 0) {
|
||||
trace_block_copy_skip_range(s, start, status_bytes);
|
||||
start += status_bytes;
|
||||
continue;
|
||||
}
|
||||
/* Clamp to known allocated region */
|
||||
chunk_end = MIN(chunk_end, start + status_bytes);
|
||||
}
|
||||
|
||||
trace_block_copy_process(s, start);
|
||||
|
||||
bdrv_reset_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
|
||||
s->in_flight_bytes += chunk_end - start;
|
||||
|
||||
co_get_from_shres(s->mem, chunk_end - start);
|
||||
ret = block_copy_do_copy(s, start, chunk_end, error_is_read);
|
||||
co_put_to_shres(s->mem, chunk_end - start);
|
||||
s->in_flight_bytes -= chunk_end - start;
|
||||
if (ret < 0) {
|
||||
bdrv_set_dirty_bitmap(s->copy_bitmap, start, chunk_end - start);
|
||||
break;
|
||||
}
|
||||
if (task->offset > offset) {
|
||||
trace_block_copy_skip_range(s, offset, task->offset - offset);
|
||||
}
|
||||
|
||||
found_dirty = true;
|
||||
|
||||
ret = block_copy_block_status(s, task->offset, task->bytes,
|
||||
&status_bytes);
|
||||
assert(ret >= 0); /* never fail */
|
||||
if (status_bytes < task->bytes) {
|
||||
block_copy_task_shrink(task, status_bytes);
|
||||
}
|
||||
if (s->skip_unallocated && !(ret & BDRV_BLOCK_ALLOCATED)) {
|
||||
block_copy_task_end(task, 0);
|
||||
progress_set_remaining(s->progress,
|
||||
bdrv_get_dirty_count(s->copy_bitmap) +
|
||||
s->in_flight_bytes);
|
||||
trace_block_copy_skip_range(s, task->offset, task->bytes);
|
||||
offset = task_end(task);
|
||||
bytes = end - offset;
|
||||
g_free(task);
|
||||
continue;
|
||||
}
|
||||
task->zeroes = ret & BDRV_BLOCK_ZERO;
|
||||
|
||||
trace_block_copy_process(s, task->offset);
|
||||
|
||||
co_get_from_shres(s->mem, task->bytes);
|
||||
|
||||
offset = task_end(task);
|
||||
bytes = end - offset;
|
||||
|
||||
if (!aio && bytes) {
|
||||
aio = aio_task_pool_new(BLOCK_COPY_MAX_WORKERS);
|
||||
}
|
||||
|
||||
ret = block_copy_task_run(aio, task);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
progress_work_done(s->progress, chunk_end - start);
|
||||
s->progress_bytes_callback(chunk_end - start, s->progress_opaque);
|
||||
start = chunk_end;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
if (aio) {
|
||||
aio_task_pool_wait_all(aio);
|
||||
|
||||
/*
|
||||
* We are not really interested in -ECANCELED returned from
|
||||
* block_copy_task_run. If it fails, it means some task already failed
|
||||
* for real reason, let's return first failure.
|
||||
* Still, assert that we don't rewrite failure by success.
|
||||
*
|
||||
* Note: ret may be positive here because of block-status result.
|
||||
*/
|
||||
assert(ret >= 0 || aio_task_pool_status(aio) < 0);
|
||||
ret = aio_task_pool_status(aio);
|
||||
|
||||
aio_task_pool_free(aio);
|
||||
}
|
||||
if (error_is_read && ret < 0) {
|
||||
*error_is_read = call_state.error_is_read;
|
||||
}
|
||||
|
||||
return ret < 0 ? ret : found_dirty;
|
||||
}
|
||||
|
||||
/*
|
||||
* block_copy
|
||||
*
|
||||
* Copy requested region, accordingly to dirty bitmap.
|
||||
* Collaborate with parallel block_copy requests: if they succeed it will help
|
||||
* us. If they fail, we will retry not-copied regions. So, if we return error,
|
||||
* it means that some I/O operation failed in context of _this_ block_copy call,
|
||||
* not some parallel operation.
|
||||
*/
|
||||
int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
|
||||
bool *error_is_read)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = block_copy_dirty_clusters(s, offset, bytes, error_is_read);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = block_copy_wait_one(s, offset, bytes);
|
||||
}
|
||||
|
||||
/*
|
||||
* We retry in two cases:
|
||||
* 1. Some progress done
|
||||
* Something was copied, which means that there were yield points
|
||||
* and some new dirty bits may have appeared (due to failed parallel
|
||||
* block-copy requests).
|
||||
* 2. We have waited for some intersecting block-copy request
|
||||
* It may have failed and produced new dirty bits.
|
||||
*/
|
||||
} while (ret > 0);
|
||||
block_copy_inflight_req_end(&req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s)
|
||||
{
|
||||
return s->copy_bitmap;
|
||||
}
|
||||
|
||||
void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip)
|
||||
{
|
||||
s->skip_unallocated = skip;
|
||||
}
|
||||
+3
-4
@@ -110,8 +110,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -297,11 +297,10 @@ static BlockDriver bdrv_bochs = {
|
||||
.instance_size = sizeof(BDRVBochsState),
|
||||
.bdrv_probe = bochs_probe,
|
||||
.bdrv_open = bochs_open,
|
||||
.bdrv_child_perm = bdrv_default_perms,
|
||||
.bdrv_child_perm = bdrv_format_default_perms,
|
||||
.bdrv_refresh_limits = bochs_refresh_limits,
|
||||
.bdrv_co_preadv = bochs_co_preadv,
|
||||
.bdrv_close = bochs_close,
|
||||
.is_format = true,
|
||||
};
|
||||
|
||||
static void bdrv_bochs_init(void)
|
||||
|
||||
+3
-4
@@ -71,8 +71,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_IMAGE, false, errp);
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
|
||||
false, errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -293,11 +293,10 @@ static BlockDriver bdrv_cloop = {
|
||||
.instance_size = sizeof(BDRVCloopState),
|
||||
.bdrv_probe = cloop_probe,
|
||||
.bdrv_open = cloop_open,
|
||||
.bdrv_child_perm = bdrv_default_perms,
|
||||
.bdrv_child_perm = bdrv_format_default_perms,
|
||||
.bdrv_refresh_limits = cloop_refresh_limits,
|
||||
.bdrv_co_preadv = cloop_co_preadv,
|
||||
.bdrv_close = cloop_close,
|
||||
.is_format = true,
|
||||
};
|
||||
|
||||
static void bdrv_cloop_init(void)
|
||||
|
||||
+35
-26
@@ -43,6 +43,27 @@ typedef struct CommitBlockJob {
|
||||
char *backing_file_str;
|
||||
} CommitBlockJob;
|
||||
|
||||
static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
|
||||
int64_t offset, uint64_t bytes,
|
||||
void *buf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
assert(bytes < SIZE_MAX);
|
||||
|
||||
ret = blk_co_pread(bs, offset, bytes, buf, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = blk_co_pwrite(base, offset, bytes, buf, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int commit_prepare(Job *job)
|
||||
{
|
||||
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
|
||||
@@ -119,6 +140,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
|
||||
int ret = 0;
|
||||
int64_t n = 0; /* bytes */
|
||||
void *buf = NULL;
|
||||
int bytes_written = 0;
|
||||
int64_t len, base_len;
|
||||
|
||||
ret = len = blk_getlength(s->top);
|
||||
@@ -133,7 +155,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
|
||||
}
|
||||
|
||||
if (base_len < len) {
|
||||
ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
|
||||
ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
@@ -143,7 +165,6 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
|
||||
|
||||
for (offset = 0; offset < len; offset += n) {
|
||||
bool copy;
|
||||
bool error_in_source = true;
|
||||
|
||||
/* Note that even when no rate limit is applied we need to yield
|
||||
* with no pending I/O here so that bdrv_drain_all() returns.
|
||||
@@ -158,20 +179,12 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
|
||||
copy = (ret == 1);
|
||||
trace_commit_one_iteration(s, offset, n, ret);
|
||||
if (copy) {
|
||||
assert(n < SIZE_MAX);
|
||||
|
||||
ret = blk_co_pread(s->top, offset, n, buf, 0);
|
||||
if (ret >= 0) {
|
||||
ret = blk_co_pwrite(s->base, offset, n, buf, 0);
|
||||
if (ret < 0) {
|
||||
error_in_source = false;
|
||||
}
|
||||
}
|
||||
ret = commit_populate(s->top, s->base, offset, n, buf);
|
||||
bytes_written += n;
|
||||
}
|
||||
if (ret < 0) {
|
||||
BlockErrorAction action =
|
||||
block_job_error_action(&s->common, s->on_error,
|
||||
error_in_source, -ret);
|
||||
block_job_error_action(&s->common, false, s->on_error, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT) {
|
||||
goto out;
|
||||
} else {
|
||||
@@ -223,7 +236,7 @@ static void bdrv_commit_top_refresh_filename(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
const BdrvChildRole *role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
@@ -240,8 +253,6 @@ static BlockDriver bdrv_commit_top = {
|
||||
.bdrv_co_block_status = bdrv_co_block_status_from_backing,
|
||||
.bdrv_refresh_filename = bdrv_commit_top_refresh_filename,
|
||||
.bdrv_child_perm = bdrv_commit_top_child_perm,
|
||||
|
||||
.is_filter = true,
|
||||
};
|
||||
|
||||
void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
@@ -416,9 +427,7 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
ctx = bdrv_get_aio_context(bs);
|
||||
/* WRITE_UNCHANGED is required for bdrv_make_empty() */
|
||||
src = blk_new(ctx, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED,
|
||||
BLK_PERM_ALL);
|
||||
src = blk_new(ctx, BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
|
||||
backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
|
||||
|
||||
ret = blk_insert_bs(src, bs, &local_err);
|
||||
@@ -462,7 +471,7 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
* grow the backing file image if possible. If not possible,
|
||||
* we must return an error */
|
||||
if (length > backing_length) {
|
||||
ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
|
||||
ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
error_report_err(local_err);
|
||||
@@ -496,14 +505,14 @@ int bdrv_commit(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
ret = blk_make_empty(src, NULL);
|
||||
/* Ignore -ENOTSUP */
|
||||
if (ret < 0 && ret != -ENOTSUP) {
|
||||
goto ro_cleanup;
|
||||
if (drv->bdrv_make_empty) {
|
||||
ret = drv->bdrv_make_empty(bs);
|
||||
if (ret < 0) {
|
||||
goto ro_cleanup;
|
||||
}
|
||||
blk_flush(src);
|
||||
}
|
||||
|
||||
blk_flush(src);
|
||||
|
||||
/*
|
||||
* Make sure all data we wrote to the backing device is actually
|
||||
* stable on disk.
|
||||
|
||||
+12
-4
@@ -28,9 +28,8 @@
|
||||
static int cor_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
||||
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
|
||||
false, errp);
|
||||
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
|
||||
errp);
|
||||
if (!bs->file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -52,7 +51,7 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
#define PERM_UNCHANGED (BLK_PERM_ALL & ~PERM_PASSTHROUGH)
|
||||
|
||||
static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
|
||||
BdrvChildRole role,
|
||||
const BdrvChildRole *role,
|
||||
BlockReopenQueue *reopen_queue,
|
||||
uint64_t perm, uint64_t shared,
|
||||
uint64_t *nperm, uint64_t *nshared)
|
||||
@@ -119,6 +118,13 @@ static void cor_lock_medium(BlockDriverState *bs, bool locked)
|
||||
}
|
||||
|
||||
|
||||
static bool cor_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
BlockDriverState *candidate)
|
||||
{
|
||||
return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
|
||||
}
|
||||
|
||||
|
||||
static BlockDriver bdrv_copy_on_read = {
|
||||
.format_name = "copy-on-read",
|
||||
|
||||
@@ -137,6 +143,8 @@ static BlockDriver bdrv_copy_on_read = {
|
||||
|
||||
.bdrv_co_block_status = bdrv_co_block_status_from_file,
|
||||
|
||||
.bdrv_recurse_is_first_non_filter = cor_recurse_is_first_non_filter,
|
||||
|
||||
.has_variable_length = true,
|
||||
.is_filter = true,
|
||||
};
|
||||
|
||||
Loaded 100 of 3419 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user