Compare commits

..

5 Commits

Author SHA1 Message Date
Fabiano Rosas
34370ee6ff target/ppc: support single stepping with KVM HV
The hardware singlestep mechanism in POWER works via a Trace Interrupt
(0xd00) that happens after any instruction executes, whenever MSR_SE =
1 (PowerISA Section 6.5.15 - Trace Interrupt).

However, with kvm_hv, the Trace Interrupt happens inside the guest and
KVM has no visibility of it. Therefore, when the gdbstub uses the
KVM_SET_GUEST_DEBUG ioctl to enable singlestep, KVM simply ignores it.

This patch takes advantage of the Trace Interrupt to perform the step
inside the guest, but uses a breakpoint at the Trace Interrupt handler
to return control to KVM. The exit is treated by KVM as a regular
breakpoint and it returns to the host (and QEMU eventually).

Before signalling GDB, QEMU sets the Next Instruction Pointer to the
instruction following the one being stepped and restores the MSR,
SRR0, SRR1 values from before the step, effectively skipping the
interrupt handler execution and hiding the trace interrupt breakpoint
from GDB.

This approach works with both of GDB's 'scheduler-locking' options
(off, step).

Note:

- kvm_arch_set_singlestep happens after GDB asks for a single step,
  while the vcpus are stopped.

- kvm_handle_singlestep executes after the step, during the handling
  of the Emulation Assist Interrupt (breakpoint).

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
2019-02-28 16:12:49 -03:00
Fabiano Rosas
9953b32e77 target/ppc: Refactor kvm_handle_debug
There are four scenarios being handled in this function:

- single stepping
- hardware breakpoints
- software breakpoints
- fallback (no debug supported)

A future patch will add code to handle specific single step and
software breakpoints cases so let's split each scenario into its own
function now to avoid hurting readability.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
2019-02-28 16:12:39 -03:00
Fabiano Rosas
0da2fd84e1 target/ppc: Move handling of hardware breakpoints to a separate function
This is in preparation for a refactoring of the kvm_handle_debug
function in the next patch.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
2019-02-28 16:12:37 -03:00
Fabiano Rosas
b82417e8bf kvm-all: Introduce kvm_set_singlestep
For single stepping (via KVM) of a guest vcpu to work, KVM needs not
only to support the SET_GUEST_DEBUG ioctl but to also recognize the
KVM_GUESTDBG_SINGLESTEP bit in the control field of the
kvm_guest_debug struct.

This patch adds support for querying the single step capability so
that QEMU can decide what to do for the platforms that do not have
such support.

This will allow architecture-specific implementations of a fallback
mechanism for single stepping in cases where KVM does not support it.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
2019-02-28 16:10:58 -03:00
Fabiano Rosas
0b72719af8 target/ppc: Move exception vector offset computation into a function
Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
2019-02-28 16:10:29 -03:00
3897 changed files with 77730 additions and 202119 deletions

View File

@@ -1,13 +1,12 @@
env:
CIRRUS_CLONE_DEPTH: 1
freebsd_12_task: freebsd_12_task:
freebsd_instance: freebsd_instance:
image: freebsd-12-0-release-amd64 image: freebsd-12-0-release-amd64
cpu: 8 cpu: 8
memory: 8G memory: 8G
env:
CIRRUS_CLONE_DEPTH: 1
install_script: pkg install -y install_script: pkg install -y
bash bison curl cyrus-sasl git glib gmake gnutls gsed bison curl cyrus-sasl git glib gmake gnutls
nettle perl5 pixman pkgconf png usbredir nettle perl5 pixman pkgconf png usbredir
script: script:
- mkdir build - mkdir build
@@ -15,13 +14,3 @@ freebsd_12_task:
- ../configure || { cat config.log; exit 1; } - ../configure || { cat config.log; exit 1; }
- gmake -j8 - gmake -j8
- gmake -j8 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
script:
- ./configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; }
- gmake -j$(sysctl -n hw.ncpu)
- gmake check -j$(sysctl -n hw.ncpu)

View File

@@ -26,15 +26,6 @@ file_type_emacs = makefile
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
[*.sh]
indent_style = space
indent_size = 4
[*.{s,S}]
indent_style = tab
indent_size = 8
file_type_emacs = asm
[*.{vert,frag}] [*.{vert,frag}]
file_type_emacs = glsl file_type_emacs = glsl

4
.gitignore vendored
View File

@@ -1,4 +1,3 @@
/.doctrees
/config-devices.* /config-devices.*
/config-all-devices.* /config-all-devices.*
/config-all-disas.* /config-all-disas.*
@@ -6,7 +5,6 @@
/config-target.* /config-target.*
/config.status /config.status
/config-temp /config-temp
/elf2dmp
/trace-events-all /trace-events-all
/trace/generated-events.h /trace/generated-events.h
/trace/generated-events.c /trace/generated-events.c
@@ -97,7 +95,6 @@
*.gcno *.gcno
*.gcov *.gcov
/pc-bios/bios-pq/status /pc-bios/bios-pq/status
/pc-bios/edk2-*.fd
/pc-bios/vgabios-pq/status /pc-bios/vgabios-pq/status
/pc-bios/optionrom/linuxboot.asm /pc-bios/optionrom/linuxboot.asm
/pc-bios/optionrom/linuxboot.bin /pc-bios/optionrom/linuxboot.bin
@@ -121,7 +118,6 @@
/pc-bios/optionrom/kvmvapic.img /pc-bios/optionrom/kvmvapic.img
/pc-bios/s390-ccw/s390-ccw.elf /pc-bios/s390-ccw/s390-ccw.elf
/pc-bios/s390-ccw/s390-ccw.img /pc-bios/s390-ccw/s390-ccw.img
/docs/built
/docs/interop/qemu-ga-qapi.texi /docs/interop/qemu-ga-qapi.texi
/docs/interop/qemu-ga-ref.html /docs/interop/qemu-ga-ref.html
/docs/interop/qemu-ga-ref.info* /docs/interop/qemu-ga-ref.info*

View File

@@ -71,18 +71,3 @@ build-clang:
ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user" ppc-softmmu s390x-softmmu x86_64-softmmu arm-linux-user"
- make -j2 - make -j2
- make -j2 check - make -j2 check
build-tci:
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

15
.gitmodules vendored
View File

@@ -39,22 +39,13 @@
url = https://git.qemu.org/git/capstone.git url = https://git.qemu.org/git/capstone.git
[submodule "roms/seabios-hppa"] [submodule "roms/seabios-hppa"]
path = roms/seabios-hppa path = roms/seabios-hppa
url = https://git.qemu.org/git/seabios-hppa.git url = https://github.com/hdeller/seabios-hppa.git
[submodule "roms/u-boot-sam460ex"] [submodule "roms/u-boot-sam460ex"]
path = roms/u-boot-sam460ex path = roms/u-boot-sam460ex
url = https://git.qemu.org/git/u-boot-sam460ex.git url = https://git.qemu.org/git/u-boot-sam460ex.git
[submodule "tests/fp/berkeley-testfloat-3"] [submodule "tests/fp/berkeley-testfloat-3"]
path = tests/fp/berkeley-testfloat-3 path = tests/fp/berkeley-testfloat-3
url = https://git.qemu.org/git/berkeley-testfloat-3.git url = https://github.com/cota/berkeley-testfloat-3
[submodule "tests/fp/berkeley-softfloat-3"] [submodule "tests/fp/berkeley-softfloat-3"]
path = tests/fp/berkeley-softfloat-3 path = tests/fp/berkeley-softfloat-3
url = https://git.qemu.org/git/berkeley-softfloat-3.git url = https://github.com/cota/berkeley-softfloat-3
[submodule "roms/edk2"]
path = roms/edk2
url = https://git.qemu.org/git/edk2.git
[submodule "slirp"]
path = slirp
url = https://git.qemu.org/git/libslirp.git
[submodule "roms/opensbi"]
path = roms/opensbi
url = https://git.qemu.org/git/opensbi.git

View File

@@ -1,302 +0,0 @@
---
# Note: this file is still unused. It serves as a documentation for the
# Patchew configuration in case patchew.org disappears or has to be
# reinstalled.
#
# Patchew configuration is available to project administrators at
# https://patchew.org/api/v1/projects/1/config/ and can be configured
# to YAML using the following Python script:
#
# import json
# import sys
# import ruamel.yaml
#
# json_str = sys.stdin.read()
# yaml = ruamel.yaml.YAML()
# yaml.explicit_start = True
# data = json.loads(json_str, object_pairs_hook=ruamel.yaml.comments.CommentedMap)
# ruamel.yaml.scalarstring.walk_tree(data)
# yaml.dump(data, sys.stdout)
email:
notifications:
timeouts:
event: TestingReport
enabled: true
to_user: false
reply_subject: true
set_reply_to: true
in_reply_to: true
reply_to_all: false
subject_template: none
to: fam@euphon.net
cc: ''
body_template: |
{% if not is_timeout %} {{ cancel }} {% endif %}
Test '{{ test }}' timeout, log:
{{ log }}
ENOSPC:
event: TestingReport
enabled: true
to_user: false
reply_subject: false
set_reply_to: false
in_reply_to: true
reply_to_all: false
subject_template: Out of space error
to: fam@euphon.net
cc: ''
body_template: |
{% if passed %}
{{ cancel }}
{% endif %}
{% if 'No space left on device' in log %}
Tester {{ tester }} out of space when running {{ test }}
{{ log }}
{% else %}
{{ cancel }}
{% endif %}
FailureShort:
event: TestingReport
enabled: true
to_user: false
reply_subject: true
set_reply_to: true
in_reply_to: true
reply_to_all: true
subject_template: Testing failed
to: ''
cc: ''
body_template: |
{% if passed or not obj.message_id or is_timeout %}
{{ cancel }}
{% endif %}
{% if 'No space left on device' in log %}
{{ cancel }}
{% endif %}
Patchew URL: https://patchew.org/QEMU/{{ obj.message_id }}/
{% ansi2text log as logtext %}
{% if test == "checkpatch" %}
Hi,
This series seems to have some coding style problems. See output below for
more information:
{{ logtext }}
{% elif test == "docker-mingw@fedora" or test == "docker-quick@centos7" or test == "asan" %}
Hi,
This series failed the {{ test }} build test. Please find the testing commands and
their output below. If you have Docker installed, you can probably reproduce it
locally.
{% lines_between logtext start="^=== TEST SCRIPT BEGIN ===$" stop="^=== TEST SCRIPT END ===$" %}
{% lines_between logtext start="^=== OUTPUT BEGIN ===$" stop="=== OUTPUT END ===$" as output %}
{% grep_C output regex="\b(FAIL|XPASS|ERROR|WARN|error:|warning:)" n=3 %}
{% elif test == "s390x" or test == "FreeBSD" or test == "ppcle" or test == "ppcbe" %}
Hi,
This series failed build test on {{test}} host. Please find the details below.
{% lines_between logtext start="^=== TEST SCRIPT BEGIN ===$" stop="^=== TEST SCRIPT END ===$" %}
{% lines_between logtext start="^=== OUTPUT BEGIN ===$" stop="=== OUTPUT END ===$" as output %}
{% grep_C output regex="\b(FAIL|XPASS|ERROR|WARN|error:|warning:)" n=3 %}
{% else %}
{{ cancel }}
{% endif %}
The full log is available at
{{ log_url }}.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com
testing:
tests:
asan:
enabled: true
requirements: docker
timeout: 3600
script: |
#!/bin/bash
time make docker-test-debug@fedora TARGET_LIST=x86_64-softmmu J=14 NETWORK=1
docker-quick@centos7:
enabled: false
requirements: docker,x86_64
timeout: 3600
script: |
#!/bin/bash
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1
checkpatch:
enabled: true
requirements: ''
timeout: 600
script: |
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
docker-mingw@fedora:
enabled: true
requirements: docker,x86_64
timeout: 3600
script: |
#! /bin/bash
test "$(uname -m)" = "x86_64"
ppcle:
enabled: false
requirements: ppcle
timeout: 3600
script: |
#!/bin/bash
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
set -e
CC=$HOME/bin/cc
INSTALL=$PWD/install
BUILD=$PWD/build
mkdir -p $BUILD $INSTALL
SRC=$PWD
cd $BUILD
$SRC/configure --cc=$CC --prefix=$INSTALL
make -j4
# XXX: we need reliable clean up
# make check -j4 V=1
make install
echo
echo "=== ENV ==="
env
echo
echo "=== PACKAGES ==="
rpm -qa
ppcbe:
enabled: false
requirements: ppcbe
timeout: 3600
script: |
#!/bin/bash
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
set -e
CC=$HOME/bin/cc
INSTALL=$PWD/install
BUILD=$PWD/build
mkdir -p $BUILD $INSTALL
SRC=$PWD
cd $BUILD
$SRC/configure --cc=$CC --prefix=$INSTALL
make -j4
# XXX: we need reliable clean up
# make check -j4 V=1
make install
echo
echo "=== ENV ==="
env
echo
echo "=== PACKAGES ==="
rpm -qa
FreeBSD:
enabled: true
requirements: qemu-x86,x86_64,git
timeout: 3600
script: |
#!/bin/bash
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
if qemu-system-x86_64 --help >/dev/null 2>&1; then
QEMU=qemu-system-x86_64
elif /usr/libexec/qemu-kvm --help >/dev/null 2>&1; then
QEMU=/usr/libexec/qemu-kvm
else
exit 1
fi
make vm-build-freebsd J=21 QEMU=$QEMU
exit 0
docker-clang@ubuntu:
enabled: true
requirements: docker,x86_64
timeout: 3600
script: |
#!/bin/bash
time make docker-test-clang@ubuntu SHOW_ENV=1 J=14 NETWORK=1
s390x:
enabled: true
requirements: s390x
timeout: 3600
script: |
#!/bin/bash
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
set -e
CC=$HOME/bin/cc
INSTALL=$PWD/install
BUILD=$PWD/build
mkdir -p $BUILD $INSTALL
SRC=$PWD
cd $BUILD
$SRC/configure --cc=$CC --prefix=$INSTALL
make -j4
# XXX: we need reliable clean up
# make check -j4 V=1
make install
echo
echo "=== ENV ==="
env
echo
echo "=== PACKAGES ==="
rpm -qa
requirements:
x86_64:
script: |
#! /bin/bash
test "$(uname -m)" = "x86_64"
qemu-x86:
script: |
#!/bin/bash
if qemu-system-x86_64 --help >/dev/null 2>&1; then
:
elif /usr/libexec/qemu-kvm --help >/dev/null 2>&1; then
:
else
exit 1
fi
ppcle:
script: |
#!/bin/bash
test "$(uname -m)" = "ppc64le"
ppcbe:
script: |
#!/bin/bash
test "$(uname -m)" = "ppc64"
git:
script: |
#! /bin/bash
git config user.name > /dev/null 2>&1
docker:
script: |
#!/bin/bash
docker ps || sudo -n docker ps
s390x:
script: |
#!/bin/bash
test "$(uname -m)" = "s390x"
git:
push_to: git@github.com:patchew-project/qemu
public_repo: https://github.com/patchew-project/qemu
url_template: https://github.com/patchew-project/qemu/tree/%t

View File

@@ -7,10 +7,11 @@ env:
matrix: matrix:
- IMAGE=debian-amd64 - IMAGE=debian-amd64
TARGET_LIST=x86_64-softmmu,x86_64-linux-user TARGET_LIST=x86_64-softmmu,x86_64-linux-user
- IMAGE=debian-win32-cross # currently disabled as the mxe.cc repos are down
TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu # - IMAGE=debian-win32-cross
- IMAGE=debian-win64-cross # TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu
TARGET_LIST=aarch64-softmmu,sparc64-softmmu,x86_64-softmmu # - IMAGE=debian-win64-cross
# TARGET_LIST=aarch64-softmmu,sparc64-softmmu,x86_64-softmmu
- IMAGE=debian-armel-cross - IMAGE=debian-armel-cross
TARGET_LIST=arm-softmmu,arm-linux-user,armeb-linux-user TARGET_LIST=arm-softmmu,arm-linux-user,armeb-linux-user
- IMAGE=debian-armhf-cross - IMAGE=debian-armhf-cross

View File

@@ -31,7 +31,7 @@ addons:
- libseccomp-dev - libseccomp-dev
- libspice-protocol-dev - libspice-protocol-dev
- libspice-server-dev - libspice-server-dev
- libssh-dev - libssh2-1-dev
- liburcu-dev - liburcu-dev
- libusb-1.0-0-dev - libusb-1.0-0-dev
- libvte-2.91-dev - libvte-2.91-dev
@@ -42,8 +42,6 @@ addons:
packages: packages:
- glib - glib
- pixman - pixman
- gnu-sed
update: true
# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu # The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
@@ -63,8 +61,7 @@ env:
- BUILD_DIR="." - BUILD_DIR="."
- BASE_CONFIG="--disable-docs --disable-tools" - BASE_CONFIG="--disable-docs --disable-tools"
- TEST_CMD="make check -j3 V=1" - TEST_CMD="make check -j3 V=1"
# This is broadly a list of "mainline" softmmu targets which have support across the major distros
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
git: git:
# we want to do this ourselves # we want to do this ourselves
@@ -75,30 +72,19 @@ before_script:
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR} - mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; } - ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
script: script:
- make -j3 && travis_retry ${TEST_CMD} - make -j3 && ${TEST_CMD}
matrix: matrix:
include: include:
- env: - env:
- CONFIG="--disable-system --static" - CONFIG="--disable-system"
# we split the system builds as it takes a while to build them all
- env:
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
- env: - env:
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}" - CONFIG="--disable-user"
# Just build tools and run minimal unit and softfloat checks
- env:
- BASE_CONFIG="--enable-tools"
- CONFIG="--disable-user --disable-system"
- TEST_CMD="make check-unit check-softfloat -j3"
- env: - env:
- CONFIG="--enable-debug --enable-debug-tcg --disable-user" - CONFIG="--enable-debug --enable-debug-tcg --disable-user"
@@ -109,12 +95,11 @@ matrix:
- env: - env:
- CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-libusb --disable-replication --target-list=${MAIN_SOFTMMU_TARGETS}" - CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-libusb --disable-user --disable-replication"
# Module builds are mostly of interest to major distros
- env: - env:
- CONFIG="--enable-modules --target-list=${MAIN_SOFTMMU_TARGETS}" - CONFIG="--enable-modules --disable-linux-user"
# Alternate coroutines implementations are only really of interest to KVM users # Alternate coroutines implementations are only really of interest to KVM users
@@ -129,9 +114,8 @@ matrix:
- TEST_CMD="make check-unit -j3 V=1" - TEST_CMD="make check-unit -j3 V=1"
# Check we can build docs and tools (out of tree) # Check we can build docs and tools
- env: - env:
- BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
- BASE_CONFIG="--enable-tools --enable-docs" - BASE_CONFIG="--enable-tools --enable-docs"
- CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user" - CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user"
addons: addons:
@@ -141,6 +125,11 @@ matrix:
- texinfo - texinfo
- perl - perl
# Test out-of-tree builds
- env:
- CONFIG="--enable-debug --enable-debug-tcg"
- BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
# Test with Clang for compile portability (Travis uses clang-5.0) # Test with Clang for compile portability (Travis uses clang-5.0)
- env: - env:
@@ -149,35 +138,17 @@ matrix:
- env: - env:
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}" - CONFIG="--disable-user"
compiler: clang
- env:
- CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS} "
compiler: clang
before_script:
- ./configure ${CONFIG} --extra-cflags="-fsanitize=undefined -Werror" || { cat config.log && exit 1; }
- env:
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
compiler: clang compiler: clang
# gprof/gcov are GCC features # gprof/gcov are GCC features
- env: - env:
- CONFIG="--enable-gprof --enable-gcov --disable-pie --target-list=${MAIN_SOFTMMU_TARGETS}" - CONFIG="--enable-gprof --enable-gcov --disable-pie --target-list=aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
after_success: after_success:
- ${SRC_DIR}/scripts/travis/coverage-summary.sh - ${SRC_DIR}/scripts/travis/coverage-summary.sh
# We manually include builds which we disable "make check" for
- env:
- CONFIG="--without-default-devices --disable-user"
- TEST_CMD=""
# We manually include builds which we disable "make check" for # We manually include builds which we disable "make check" for
- env: - env:
- CONFIG="--enable-debug --enable-tcg-interpreter" - CONFIG="--enable-debug --enable-tcg-interpreter"
@@ -202,19 +173,12 @@ matrix:
# MacOSX builds # MacOSX builds
- env: - env:
- CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS}" - CONFIG="--target-list=aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
os: osx os: osx
osx_image: xcode9.4 osx_image: xcode9.4
compiler: clang compiler: clang
- env:
- CONFIG="--target-list=i386-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,x86_64-softmmu"
os: osx
osx_image: xcode10.2
compiler: clang
# Python builds # Python builds
- env: - env:
- CONFIG="--target-list=x86_64-softmmu" - CONFIG="--target-list=x86_64-softmmu"
@@ -232,10 +196,8 @@ matrix:
# Acceptance (Functional) tests # Acceptance (Functional) tests
- env: - env:
- CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu" - CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu"
- TEST_CMD="make check-acceptance" - TEST_CMD="make AVOCADO_SHOW=app check-acceptance"
after_failure:
- cat tests/results/latest/job.log
addons: addons:
apt: apt:
packages: packages:
@@ -250,8 +212,8 @@ matrix:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
packages: packages:
# Extra toolchains # Extra toolchains
- gcc-9 - gcc-7
- g++-9 - g++-7
# Build dependencies # Build dependencies
- libaio-dev - libaio-dev
- libattr1-dev - libattr1-dev
@@ -271,7 +233,7 @@ matrix:
- libseccomp-dev - libseccomp-dev
- libspice-protocol-dev - libspice-protocol-dev
- libspice-server-dev - libspice-server-dev
- libssh-dev - libssh2-1-dev
- liburcu-dev - liburcu-dev
- libusb-1.0-0-dev - libusb-1.0-0-dev
- libvte-2.91-dev - libvte-2.91-dev
@@ -280,19 +242,13 @@ matrix:
language: generic language: generic
compiler: none compiler: none
env: env:
- COMPILER_NAME=gcc CXX=g++-9 CC=gcc-9 - COMPILER_NAME=gcc CXX=g++-7 CC=gcc-7
- CONFIG="--cc=gcc-9 --cxx=g++-9 --disable-pie --disable-linux-user" - CONFIG="--cc=gcc-7 --cxx=g++-7 --disable-pie --disable-linux-user"
- TEST_CMD="" - TEST_CMD=""
before_script: before_script:
- ./configure ${CONFIG} --extra-cflags="-g3 -O0 -Wno-error=stringop-truncation -fsanitize=thread -fuse-ld=gold" || { cat config.log && exit 1; } - ./configure ${CONFIG} --extra-cflags="-g3 -O0 -fsanitize=thread -fuse-ld=gold" || { cat config.log && exit 1; }
# Run check-tcg against linux-user
- env: - env:
- CONFIG="--disable-system" - CONFIG="--disable-system"
- TEST_CMD="make -j3 check-tcg V=1" - TEST_CMD="make -j3 check-tcg V=1"
# Run check-tcg against softmmu targets
- env:
- CONFIG="--target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
- TEST_CMD="make -j3 check-tcg V=1"

View File

@@ -29,45 +29,6 @@ Spaces of course are superior to tabs because:
Do not leave whitespace dangling off the ends of lines. Do not leave whitespace dangling off the ends of lines.
1.1 Multiline Indent
There are several places where indent is necessary:
- if/else
- while/for
- function definition & call
When breaking up a long line to fit within line width, we need a proper indent
for the following lines.
In case of if/else, while/for, align the secondary lines just after the
opening parenthesis of the first.
For example:
if (a == 1 &&
b == 2) {
while (a == 1 &&
b == 2) {
In case of function, there are several variants:
* 4 spaces indent from the beginning
* align the secondary lines just after the opening parenthesis of the
first
For example:
do_something(x, y,
z);
do_something(x, y,
z);
do_something(x, do_another(y,
z));
2. Line width 2. Line width
Lines should be 80 characters; try not to make them longer. Lines should be 80 characters; try not to make them longer.
@@ -147,10 +108,10 @@ block to a separate function altogether.
When comparing a variable for (in)equality with a constant, list the When comparing a variable for (in)equality with a constant, list the
constant on the right, as in: constant on the right, as in:
if (a == 1) { if (a == 1) {
/* Reads like: "If a equals 1" */ /* Reads like: "If a equals 1" */
do_something(); do_something();
} }
Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read. Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read.
Besides, good compilers already warn users when '==' is mis-typed as '=', Besides, good compilers already warn users when '==' is mis-typed as '=',

View File

@@ -1,36 +0,0 @@
# These are "proxy" symbols used to pass config-host.mak values
# down to Kconfig. See also MINIKCONF_ARGS in the Makefile:
# these two need to be kept in sync.
config KVM
bool
config LINUX
bool
config OPENGL
bool
config X11
bool
config SPICE
bool
config IVSHMEM
bool
config TPM
bool
config VHOST_USER
bool
config XEN
bool
config VIRTFS
bool
config PVRDMA
bool

21
LICENSE
View File

@@ -1,18 +1,13 @@
The QEMU distribution includes both the QEMU emulator and The following points clarify the QEMU license:
various firmware files. These are separate programs that are
distributed together for our users' convenience, and they have
separate licenses.
The following points clarify the license of the QEMU emulator: 1) QEMU as a whole is released under the GNU General Public License,
version 2.
1) The QEMU emulator as a whole is released under the GNU General 2) Parts of QEMU have specific licenses which are compatible with the
Public License, version 2. GNU General Public License, version 2. Hence each source file contains
its own licensing information. Source files with no licensing information
2) Parts of the QEMU emulator have specific licenses which are compatible are released under the GNU General Public License, version 2 or (at your
with the GNU General Public License, version 2. Hence each source file option) any later version.
contains its own licensing information. Source files with no licensing
information are released under the GNU General Public License, version
2 or (at your option) any later version.
As of July 2013, contributions under version 2 of the GNU General Public As of July 2013, contributions under version 2 of the GNU General Public
License (and no later version) are only accepted for the following files License (and no later version) are only accepted for the following files

View File

@@ -65,7 +65,7 @@ F: *
F: */ F: */
Responsible Disclosure, Reporting Security Issues Responsible Disclosure, Reporting Security Issues
------------------------------------------------- ------------------------------
W: https://wiki.qemu.org/SecurityProcess W: https://wiki.qemu.org/SecurityProcess
M: Michael S. Tsirkin <mst@redhat.com> M: Michael S. Tsirkin <mst@redhat.com>
L: secalert@redhat.com L: secalert@redhat.com
@@ -83,7 +83,7 @@ T: git https://github.com/vivier/qemu.git trivial-patches
Architecture support Architecture support
-------------------- --------------------
S390 general architecture support S390
M: Cornelia Huck <cohuck@redhat.com> M: Cornelia Huck <cohuck@redhat.com>
S: Supported S: Supported
F: default-configs/s390x-softmmu.mak F: default-configs/s390x-softmmu.mak
@@ -102,14 +102,14 @@ F: pc-bios/s390-ccw/
F: pc-bios/s390-ccw.img F: pc-bios/s390-ccw.img
F: target/s390x/ F: target/s390x/
F: docs/vfio-ap.txt F: docs/vfio-ap.txt
F: tests/migration/s390x/
K: ^Subject:.*(?i)s390x? K: ^Subject:.*(?i)s390x?
T: git https://github.com/cohuck/qemu.git s390-next T: git https://github.com/cohuck/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
Guest CPU cores (TCG) Guest CPU cores (TCG):
--------------------- ----------------------
Overall TCG CPUs Overall
L: qemu-devel@nongnu.org
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
R: Paolo Bonzini <pbonzini@redhat.com> R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained S: Maintained
@@ -117,14 +117,11 @@ F: cpus.c
F: exec.c F: exec.c
F: accel/tcg/ F: accel/tcg/
F: accel/stubs/tcg-stub.c F: accel/stubs/tcg-stub.c
F: scripts/decodetree.py
F: docs/devel/decodetree.rst
F: include/exec/cpu*.h F: include/exec/cpu*.h
F: include/exec/exec-all.h F: include/exec/exec-all.h
F: include/exec/helper*.h F: include/exec/helper*.h
F: include/exec/tb-hash.h F: include/exec/tb-hash.h
F: include/sysemu/cpus.h F: include/sysemu/cpus.h
F: include/sysemu/tcg.h
FPU emulation FPU emulation
M: Aurelien Jarno <aurelien@aurel32.net> M: Aurelien Jarno <aurelien@aurel32.net>
@@ -135,14 +132,14 @@ F: fpu/
F: include/fpu/ F: include/fpu/
F: tests/fp/ F: tests/fp/
Alpha TCG CPUs Alpha
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
S: Maintained S: Maintained
F: target/alpha/ F: target/alpha/
F: tests/tcg/alpha/ F: tests/tcg/alpha/
F: disas/alpha.c F: disas/alpha.c
ARM TCG CPUs ARM
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Maintained S: Maintained
@@ -163,7 +160,7 @@ S: Maintained
F: hw/arm/smmu* F: hw/arm/smmu*
F: include/hw/arm/smmu* F: include/hw/arm/smmu*
CRIS TCG CPUs CRIS
M: Edgar E. Iglesias <edgar.iglesias@gmail.com> M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained S: Maintained
F: target/cris/ F: target/cris/
@@ -172,14 +169,14 @@ F: include/hw/cris/
F: tests/tcg/cris/ F: tests/tcg/cris/
F: disas/cris.c F: disas/cris.c
HPPA (PA-RISC) TCG CPUs HPPA (PA-RISC)
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
S: Maintained S: Maintained
F: target/hppa/ F: target/hppa/
F: hw/hppa/ F: hw/hppa/
F: disas/hppa.c F: disas/hppa.c
LM32 TCG CPUs LM32
M: Michael Walle <michael@walle.cc> M: Michael Walle <michael@walle.cc>
S: Maintained S: Maintained
F: target/lm32/ F: target/lm32/
@@ -192,27 +189,29 @@ F: include/hw/char/lm32_juart.h
F: include/hw/lm32/ F: include/hw/lm32/
F: tests/tcg/lm32/ F: tests/tcg/lm32/
M68K TCG CPUs M68K
M: Laurent Vivier <laurent@vivier.eu> M: Laurent Vivier <laurent@vivier.eu>
S: Maintained S: Maintained
F: target/m68k/ F: target/m68k/
F: disas/m68k.c F: disas/m68k.c
MicroBlaze TCG CPUs MicroBlaze
M: Edgar E. Iglesias <edgar.iglesias@gmail.com> M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained S: Maintained
F: target/microblaze/ F: target/microblaze/
F: hw/microblaze/ F: hw/microblaze/
F: disas/microblaze.c F: disas/microblaze.c
MIPS TCG CPUs MIPS
M: Aurelien Jarno <aurelien@aurel32.net> M: Aurelien Jarno <aurelien@aurel32.net>
M: Aleksandar Markovic <amarkovic@wavecomp.com> M: Aleksandar Markovic <amarkovic@wavecomp.com>
R: Aleksandar Rikalo <arikalo@wavecomp.com> R: Aleksandar Rikalo <arikalo@wavecomp.com>
S: Maintained S: Maintained
F: target/mips/ F: target/mips/
F: default-configs/*mips* F: default-configs/*mips*
F: disas/*mips* F: disas/mips.c
F: disas/nanomips.cpp
F: disas/nanomips.h
F: hw/intc/mips_gic.c F: hw/intc/mips_gic.c
F: hw/mips/ F: hw/mips/
F: hw/misc/mips_* F: hw/misc/mips_*
@@ -224,7 +223,7 @@ F: include/hw/timer/mips_gictimer.h
F: tests/tcg/mips/ F: tests/tcg/mips/
K: ^Subject:.*(?i)mips K: ^Subject:.*(?i)mips
Moxie TCG CPUs Moxie
M: Anthony Green <green@moxielogic.com> M: Anthony Green <green@moxielogic.com>
S: Maintained S: Maintained
F: target/moxie/ F: target/moxie/
@@ -232,7 +231,7 @@ F: disas/moxie.c
F: hw/moxie/ F: hw/moxie/
F: default-configs/moxie-softmmu.mak F: default-configs/moxie-softmmu.mak
NiosII TCG CPUs NiosII
M: Chris Wulff <crwulff@gmail.com> M: Chris Wulff <crwulff@gmail.com>
M: Marek Vasut <marex@denx.de> M: Marek Vasut <marex@denx.de>
S: Maintained S: Maintained
@@ -242,14 +241,14 @@ F: hw/intc/nios2_iic.c
F: disas/nios2.c F: disas/nios2.c
F: default-configs/nios2-softmmu.mak F: default-configs/nios2-softmmu.mak
OpenRISC TCG CPUs OpenRISC
M: Stafford Horne <shorne@gmail.com> M: Stafford Horne <shorne@gmail.com>
S: Odd Fixes S: Odd Fixes
F: target/openrisc/ F: target/openrisc/
F: hw/openrisc/ F: hw/openrisc/
F: tests/tcg/openrisc/ F: tests/tcg/openrisc/
PowerPC TCG CPUs PowerPC
M: David Gibson <david@gibson.dropbear.id.au> M: David Gibson <david@gibson.dropbear.id.au>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Maintained
@@ -258,7 +257,7 @@ F: hw/ppc/
F: include/hw/ppc/ F: include/hw/ppc/
F: disas/ppc.c F: disas/ppc.c
RISC-V TCG CPUs RISC-V
M: Palmer Dabbelt <palmer@sifive.com> M: Palmer Dabbelt <palmer@sifive.com>
M: Alistair Francis <Alistair.Francis@wdc.com> M: Alistair Francis <Alistair.Francis@wdc.com>
M: Sagar Karandikar <sagark@eecs.berkeley.edu> M: Sagar Karandikar <sagark@eecs.berkeley.edu>
@@ -271,7 +270,7 @@ F: include/hw/riscv/
F: linux-user/host/riscv32/ F: linux-user/host/riscv32/
F: linux-user/host/riscv64/ F: linux-user/host/riscv64/
S390 TCG CPUs S390
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
M: David Hildenbrand <david@redhat.com> M: David Hildenbrand <david@redhat.com>
S: Maintained S: Maintained
@@ -281,7 +280,7 @@ F: disas/s390.c
F: tests/tcg/s390x/ F: tests/tcg/s390x/
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
SH4 TCG CPUs SH4
M: Aurelien Jarno <aurelien@aurel32.net> M: Aurelien Jarno <aurelien@aurel32.net>
S: Odd Fixes S: Odd Fixes
F: target/sh4/ F: target/sh4/
@@ -289,7 +288,7 @@ F: hw/sh4/
F: disas/sh4.c F: disas/sh4.c
F: include/hw/sh4/ F: include/hw/sh4/
SPARC TCG CPUs SPARC
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
M: Artyom Tarasenko <atar4qemu@gmail.com> M: Artyom Tarasenko <atar4qemu@gmail.com>
S: Maintained S: Maintained
@@ -299,14 +298,14 @@ F: hw/sparc64/
F: include/hw/sparc/sparc64.h F: include/hw/sparc/sparc64.h
F: disas/sparc.c F: disas/sparc.c
UniCore32 TCG CPUs UniCore32
M: Guan Xuetao <gxt@mprc.pku.edu.cn> M: Guan Xuetao <gxt@mprc.pku.edu.cn>
S: Maintained S: Maintained
F: target/unicore32/ F: target/unicore32/
F: hw/unicore32/ F: hw/unicore32/
F: include/hw/unicore32/ F: include/hw/unicore32/
X86 TCG CPUs X86
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
M: Eduardo Habkost <ehabkost@redhat.com> M: Eduardo Habkost <ehabkost@redhat.com>
@@ -319,7 +318,7 @@ F: disas/i386.c
F: docs/qemu-cpu-models.texi F: docs/qemu-cpu-models.texi
T: git https://github.com/ehabkost/qemu.git x86-next T: git https://github.com/ehabkost/qemu.git x86-next
Xtensa TCG CPUs Xtensa
M: Max Filippov <jcmvbkbc@gmail.com> M: Max Filippov <jcmvbkbc@gmail.com>
W: http://wiki.osll.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa W: http://wiki.osll.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
S: Maintained S: Maintained
@@ -330,7 +329,7 @@ F: disas/xtensa.c
F: include/hw/xtensa/xtensa-isa.h F: include/hw/xtensa/xtensa-isa.h
F: default-configs/xtensa*.mak F: default-configs/xtensa*.mak
TriCore TCG CPUs TriCore
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
S: Maintained S: Maintained
F: target/tricore/ F: target/tricore/
@@ -339,12 +338,12 @@ F: include/hw/tricore/
Multiarch Linux User Tests Multiarch Linux User Tests
M: Alex Bennée <alex.bennee@linaro.org> M: Alex Bennée <alex.bennee@linaro.org>
S: Maintained
F: tests/tcg/multiarch/ F: tests/tcg/multiarch/
Guest CPU Cores (KVM) Guest CPU Cores (KVM):
--------------------- ----------------------
Overall KVM CPUs
Overall
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
L: kvm@vger.kernel.org L: kvm@vger.kernel.org
S: Supported S: Supported
@@ -355,24 +354,24 @@ F: include/hw/kvm/
F: include/sysemu/kvm*.h F: include/sysemu/kvm*.h
F: scripts/kvm/kvm_flightrecorder F: scripts/kvm/kvm_flightrecorder
ARM KVM CPUs ARM
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Maintained S: Maintained
F: target/arm/kvm.c F: target/arm/kvm.c
MIPS KVM CPUs MIPS
M: James Hogan <jhogan@kernel.org> M: James Hogan <jhogan@kernel.org>
R: Aleksandar Rikalo <arikalo@wavecomp.com> R: Aleksandar Rikalo <arikalo@wavecomp.com>
S: Maintained S: Maintained
F: target/mips/kvm.c F: target/mips/kvm.c
PPC KVM CPUs PPC
M: David Gibson <david@gibson.dropbear.id.au> M: David Gibson <david@gibson.dropbear.id.au>
S: Maintained S: Maintained
F: target/ppc/kvm.c F: target/ppc/kvm.c
S390 KVM CPUs S390
M: Halil Pasic <pasic@linux.ibm.com> M: Halil Pasic <pasic@linux.ibm.com>
M: Cornelia Huck <cohuck@redhat.com> M: Cornelia Huck <cohuck@redhat.com>
M: Christian Borntraeger <borntraeger@de.ibm.com> M: Christian Borntraeger <borntraeger@de.ibm.com>
@@ -383,8 +382,6 @@ F: target/s390x/kvm-stub.c
F: target/s390x/ioinst.[ch] F: target/s390x/ioinst.[ch]
F: target/s390x/machine.c F: target/s390x/machine.c
F: target/s390x/sigp.c F: target/s390x/sigp.c
F: target/s390x/cpu_features*.[ch]
F: target/s390x/cpu_models.[ch]
F: hw/intc/s390_flic.c F: hw/intc/s390_flic.c
F: hw/intc/s390_flic_kvm.c F: hw/intc/s390_flic_kvm.c
F: include/hw/s390x/s390_flic.h F: include/hw/s390x/s390_flic.h
@@ -393,7 +390,7 @@ T: git https://github.com/cohuck/qemu.git s390-next
T: git https://github.com/borntraeger/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
X86 KVM CPUs X86
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
M: Marcelo Tosatti <mtosatti@redhat.com> M: Marcelo Tosatti <mtosatti@redhat.com>
L: kvm@vger.kernel.org L: kvm@vger.kernel.org
@@ -401,16 +398,17 @@ S: Supported
F: target/i386/kvm.c F: target/i386/kvm.c
F: scripts/kvm/vmxcap F: scripts/kvm/vmxcap
Guest CPU Cores (Xen) Guest CPU Cores (Xen):
--------------------- ----------------------
X86 Xen CPUs
X86
M: Stefano Stabellini <sstabellini@kernel.org> M: Stefano Stabellini <sstabellini@kernel.org>
M: Anthony Perard <anthony.perard@citrix.com> M: Anthony Perard <anthony.perard@citrix.com>
M: Paul Durrant <paul.durrant@citrix.com> M: Paul Durrant <paul.durrant@citrix.com>
L: xen-devel@lists.xenproject.org L: xen-devel@lists.xenproject.org
S: Supported S: Supported
F: */xen* F: */xen*
F: hw/9pfs/xen-9p* F: hw/9pfs/xen-9p-backend.c
F: hw/char/xen_console.c F: hw/char/xen_console.c
F: hw/display/xenfb.c F: hw/display/xenfb.c
F: hw/net/xen_nic.c F: hw/net/xen_nic.c
@@ -423,35 +421,34 @@ F: include/hw/block/dataplane/xen*
F: include/hw/xen/ F: include/hw/xen/
F: include/sysemu/xen-mapcache.h F: include/sysemu/xen-mapcache.h
Hosts Hosts:
----- ------
LINUX LINUX
M: Michael S. Tsirkin <mst@redhat.com> L: qemu-devel@nongnu.org
M: Cornelia Huck <cohuck@redhat.com>
M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained S: Maintained
F: linux-*
F: linux-headers/ F: linux-headers/
F: scripts/update-linux-headers.sh
POSIX POSIX
M: Paolo Bonzini <pbonzini@redhat.com> L: qemu-devel@nongnu.org
S: Maintained S: Maintained
F: os-posix.c F: *posix*
F: include/sysemu/os-posix.h
F: util/*posix*.c
F: include/qemu/*posix*.h
NETBSD NETBSD
L: qemu-devel@nongnu.org
M: Kamil Rytarowski <kamil@netbsd.org> M: Kamil Rytarowski <kamil@netbsd.org>
S: Maintained S: Maintained
K: ^Subject:.*(?i)NetBSD K: ^Subject:.*(?i)NetBSD
OPENBSD OPENBSD
L: qemu-devel@nongnu.org
M: Brad Smith <brad@comstyle.com> M: Brad Smith <brad@comstyle.com>
S: Maintained S: Maintained
K: ^Subject:.*(?i)OpenBSD K: ^Subject:.*(?i)OpenBSD
W32, W64 W32, W64
L: qemu-devel@nongnu.org
M: Stefan Weil <sw@weilnetz.de> M: Stefan Weil <sw@weilnetz.de>
S: Maintained S: Maintained
F: *win32* F: *win32*
@@ -461,12 +458,10 @@ X: qga/*win32*
F: qemu.nsi F: qemu.nsi
Alpha Machines Alpha Machines
--------------
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
S: Maintained S: Maintained
F: hw/alpha/ F: hw/alpha/
F: hw/isa/smc37c669-superio.c F: hw/isa/smc37c669-superio.c
F: tests/tcg/alpha/system/
ARM Machines ARM Machines
------------ ------------
@@ -561,6 +556,7 @@ F: include/hw/*/digic*
Gumstix Gumstix
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <f4bug@amsat.org>
L: qemu-devel@nongnu.org
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/arm/gumstix.c F: hw/arm/gumstix.c
@@ -637,8 +633,6 @@ F: hw/misc/iotkit-sysinfo.c
F: include/hw/misc/iotkit-sysinfo.h F: include/hw/misc/iotkit-sysinfo.h
F: hw/misc/armsse-cpuid.c F: hw/misc/armsse-cpuid.c
F: include/hw/misc/armsse-cpuid.h F: include/hw/misc/armsse-cpuid.h
F: hw/misc/armsse-mhu.c
F: include/hw/misc/armsse-mhu.h
Musca Musca
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
@@ -659,14 +653,10 @@ M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/arm/nseries.c F: hw/arm/nseries.c
F: hw/display/blizzard.c
F: hw/input/lm832x.c F: hw/input/lm832x.c
F: hw/input/tsc2005.c F: hw/input/tsc2005.c
F: hw/misc/cbus.c F: hw/misc/cbus.c
F: hw/timer/twl92230.c F: hw/timer/twl92230.c
F: include/hw/display/blizzard.h
F: include/hw/input/tsc2xxx.h
F: include/hw/misc/cbus.h
Palm Palm
M: Andrzej Zaborowski <balrogg@gmail.com> M: Andrzej Zaborowski <balrogg@gmail.com>
@@ -675,7 +665,6 @@ L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/arm/palm.c F: hw/arm/palm.c
F: hw/input/tsc210x.c F: hw/input/tsc210x.c
F: include/hw/input/tsc2xxx.h
Raspberry Pi Raspberry Pi
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
@@ -715,7 +704,6 @@ F: hw/misc/mst_fpga.c
F: hw/misc/max111x.c F: hw/misc/max111x.c
F: include/hw/arm/pxa.h F: include/hw/arm/pxa.h
F: include/hw/arm/sharpsl.h F: include/hw/arm/sharpsl.h
F: include/hw/display/tc6393xb.h
SABRELITE / i.MX6 SABRELITE / i.MX6
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
@@ -730,14 +718,6 @@ F: include/hw/arm/fsl-imx6.h
F: include/hw/misc/imx6_*.h F: include/hw/misc/imx6_*.h
F: include/hw/ssi/imx_spi.h F: include/hw/ssi/imx_spi.h
SBSA-REF
M: Radoslaw Biernacki <radoslaw.biernacki@linaro.org>
M: Peter Maydell <peter.maydell@linaro.org>
R: Leif Lindholm <leif.lindholm@linaro.org>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/sbsa-ref.c
Sharp SL-5500 (Collie) PDA Sharp SL-5500 (Collie) PDA
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
@@ -750,7 +730,6 @@ M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Maintained S: Maintained
F: hw/*/stellaris* F: hw/*/stellaris*
F: include/hw/input/gamepad.h
Versatile Express Versatile Express
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
@@ -872,15 +851,6 @@ S: Maintained
F: hw/cris/axis_dev88.c F: hw/cris/axis_dev88.c
F: hw/*/etraxfs_*.c F: hw/*/etraxfs_*.c
HP-PARISC Machines
------------------
Dino
M: Richard Henderson <rth@twiddle.net>
R: Helge Deller <deller@gmx.de>
S: Odd Fixes
F: hw/hppa/
F: pc-bios/hppa-firmware.img
LM32 Machines LM32 Machines
------------- -------------
EVR32 and uclinux BSP EVR32 and uclinux BSP
@@ -938,8 +908,6 @@ M: Aurelien Jarno <aurelien@aurel32.net>
R: Aleksandar Rikalo <arikalo@wavecomp.com> R: Aleksandar Rikalo <arikalo@wavecomp.com>
S: Maintained S: Maintained
F: hw/mips/mips_malta.c F: hw/mips/mips_malta.c
F: hw/mips/gt64xxx_pci.c
F: tests/acceptance/linux_ssh_mips_malta.py
Mipssim Mipssim
M: Aleksandar Markovic <amarkovic@wavecomp.com> M: Aleksandar Markovic <amarkovic@wavecomp.com>
@@ -999,7 +967,6 @@ L: qemu-ppc@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/ppc/e500* F: hw/ppc/e500*
F: hw/gpio/mpc8xxx.c F: hw/gpio/mpc8xxx.c
F: hw/i2c/mpc_i2c.c
F: hw/net/fsl_etsec/ F: hw/net/fsl_etsec/
F: hw/pci-host/ppce500.c F: hw/pci-host/ppce500.c
F: include/hw/ppc/ppc_e500.h F: include/hw/ppc/ppc_e500.h
@@ -1048,6 +1015,7 @@ F: pc-bios/qemu_vga.ndrv
PReP PReP
M: Hervé Poussineau <hpoussin@reactos.org> M: Hervé Poussineau <hpoussin@reactos.org>
L: qemu-devel@nongnu.org
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Maintained
F: hw/ppc/prep.c F: hw/ppc/prep.c
@@ -1073,6 +1041,7 @@ F: include/hw/*/xics*
F: pc-bios/spapr-rtas/* F: pc-bios/spapr-rtas/*
F: pc-bios/spapr-rtas.bin F: pc-bios/spapr-rtas.bin
F: pc-bios/slof.bin F: pc-bios/slof.bin
F: pc-bios/skiboot.lid
F: docs/specs/ppc-spapr-hcalls.txt F: docs/specs/ppc-spapr-hcalls.txt
F: docs/specs/ppc-spapr-hotplug.txt F: docs/specs/ppc-spapr-hotplug.txt
F: tests/spapr* F: tests/spapr*
@@ -1080,18 +1049,6 @@ F: tests/libqos/*spapr*
F: tests/rtas* F: tests/rtas*
F: tests/libqos/rtas* F: tests/libqos/rtas*
PowerNV (Non-Virtualized)
M: Cédric Le Goater <clg@kaod.org>
M: David Gibson <david@gibson.dropbear.id.au>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/pnv*
F: hw/intc/pnv*
F: hw/intc/xics_pnv.c
F: include/hw/ppc/pnv*
F: pc-bios/skiboot.lid
F: tests/pnv*
virtex_ml507 virtex_ml507
M: Edgar E. Iglesias <edgar.iglesias@gmail.com> M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@@ -1132,27 +1089,20 @@ M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
S: Maintained S: Maintained
F: hw/sparc/sun4m.c F: hw/sparc/sun4m.c
F: hw/sparc/sun4m_iommu.c F: hw/sparc/sun4m_iommu.c
F: hw/display/cg3.c
F: hw/display/tcx.c
F: hw/dma/sparc32_dma.c F: hw/dma/sparc32_dma.c
F: hw/misc/eccmemctl.c F: hw/misc/eccmemctl.c
F: hw/*/slavio_*.c F: hw/misc/slavio_misc.c
F: include/hw/nvram/sun_nvram.h
F: include/hw/sparc/sparc32_dma.h F: include/hw/sparc/sparc32_dma.h
F: include/hw/sparc/sun4m_iommu.h
F: pc-bios/openbios-sparc32 F: pc-bios/openbios-sparc32
F: include/hw/sparc/sun4m_iommu.h
Sun4u Sun4u
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
S: Maintained S: Maintained
F: hw/sparc64/sun4u.c F: hw/sparc64/sun4u.c
F: hw/sparc64/sun4u_iommu.c F: pc-bios/openbios-sparc64
F: include/hw/sparc/sun4u_iommu.h
F: hw/pci-host/sabre.c F: hw/pci-host/sabre.c
F: include/hw/pci-host/sabre.h F: include/hw/pci-host/sabre.h
F: hw/pci-bridge/simba.c
F: include/hw/pci-bridge/simba.h
F: pc-bios/openbios-sparc64
Sun4v Sun4v
M: Artyom Tarasenko <atar4qemu@gmail.com> M: Artyom Tarasenko <atar4qemu@gmail.com>
@@ -1163,11 +1113,10 @@ F: include/hw/timer/sun4v-rtc.h
Leon3 Leon3
M: Fabien Chouteau <chouteau@adacore.com> M: Fabien Chouteau <chouteau@adacore.com>
M: KONRAD Frederic <frederic.konrad@adacore.com>
S: Maintained S: Maintained
F: hw/sparc/leon3.c F: hw/sparc/leon3.c
F: hw/*/grlib* F: hw/*/grlib*
F: include/hw/*/grlib* F: include/hw/sparc/grlib.h
S390 Machines S390 Machines
------------- -------------
@@ -1194,7 +1143,6 @@ S: Supported
F: hw/s390x/ipl.* F: hw/s390x/ipl.*
F: pc-bios/s390-ccw/ F: pc-bios/s390-ccw/
F: pc-bios/s390-ccw.img F: pc-bios/s390-ccw.img
F: docs/devel/s390-dasd-ipl.txt
T: git https://github.com/borntraeger/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
@@ -1205,7 +1153,7 @@ F: hw/s390x/s390-pci*
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
UniCore32 Machines UniCore32 Machines
------------------ -------------
PKUnity-3 SoC initramfs-with-busybox PKUnity-3 SoC initramfs-with-busybox
M: Guan Xuetao <gxt@mprc.pku.edu.cn> M: Guan Xuetao <gxt@mprc.pku.edu.cn>
S: Maintained S: Maintained
@@ -1233,10 +1181,6 @@ F: hw/acpi/ich9.c
F: include/hw/acpi/ich9.h F: include/hw/acpi/ich9.h
F: include/hw/acpi/piix4.h F: include/hw/acpi/piix4.h
F: hw/misc/sga.c F: hw/misc/sga.c
F: hw/isa/apm.c
F: include/hw/isa/apm.h
F: tests/test-x86-cpuid.c
F: tests/test-x86-cpuid-compat.c
PC Chipset PC Chipset
M: Michael S. Tsirkin <mst@redhat.com> M: Michael S. Tsirkin <mst@redhat.com>
@@ -1274,18 +1218,11 @@ Machine core
M: Eduardo Habkost <ehabkost@redhat.com> M: Eduardo Habkost <ehabkost@redhat.com>
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
S: Supported S: Supported
F: hw/core/machine-qmp-cmds.c
F: hw/core/machine.c F: hw/core/machine.c
F: hw/core/null-machine.c F: hw/core/null-machine.c
F: hw/core/numa.c
F: hw/cpu/cluster.c F: hw/cpu/cluster.c
F: qapi/machine.json
F: qapi/machine-target.json
F: qom/cpu.c
F: include/hw/boards.h F: include/hw/boards.h
F: include/hw/cpu/cluster.h F: include/hw/cpu/cluster.h
F: include/qom/cpu.h
F: include/sysemu/numa.h
T: git https://github.com/ehabkost/qemu.git machine-next T: git https://github.com/ehabkost/qemu.git machine-next
Xtensa Machines Xtensa Machines
@@ -1404,13 +1341,6 @@ F: include/hw/net/
F: tests/virtio-net-test.c F: tests/virtio-net-test.c
T: git https://github.com/jasowang/qemu.git net T: git https://github.com/jasowang/qemu.git net
Parallel NOR Flash devices
M: Philippe Mathieu-Daudé <philmd@redhat.com>
T: git https://gitlab.com/philmd/qemu.git pflash-next
S: Maintained
F: hw/block/pflash_cfi*.c
F: include/hw/block/flash.h
SCSI SCSI
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
R: Fam Zheng <fam@euphon.net> R: Fam Zheng <fam@euphon.net>
@@ -1468,11 +1398,11 @@ F: include/hw/vfio/
vfio-ccw vfio-ccw
M: Cornelia Huck <cohuck@redhat.com> M: Cornelia Huck <cohuck@redhat.com>
M: Eric Farman <farman@linux.ibm.com> M: Eric Farman <farman@linux.ibm.com>
M: Farhan Ali <alifm@linux.ibm.com>
S: Supported S: Supported
F: hw/vfio/ccw.c F: hw/vfio/ccw.c
F: hw/s390x/s390-ccw.c F: hw/s390x/s390-ccw.c
F: include/hw/s390x/s390-ccw.h F: include/hw/s390x/s390-ccw.h
F: include/hw/s390x/vfio-ccw.h
T: git https://github.com/cohuck/qemu.git s390-next T: git https://github.com/cohuck/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
@@ -1494,11 +1424,8 @@ vhost
M: Michael S. Tsirkin <mst@redhat.com> M: Michael S. Tsirkin <mst@redhat.com>
S: Supported S: Supported
F: hw/*/*vhost* F: hw/*/*vhost*
F: docs/interop/vhost-user.json F: docs/interop/vhost-user.txt
F: docs/interop/vhost-user.rst
F: contrib/vhost-user-*/ F: contrib/vhost-user-*/
F: backends/vhost-user.c
F: include/sysemu/vhost-user-backend.h
virtio virtio
M: Michael S. Tsirkin <mst@redhat.com> M: Michael S. Tsirkin <mst@redhat.com>
@@ -1514,7 +1441,6 @@ virtio-9p
M: Greg Kurz <groug@kaod.org> M: Greg Kurz <groug@kaod.org>
S: Supported S: Supported
F: hw/9pfs/ F: hw/9pfs/
X: hw/9pfs/xen-9p*
F: fsdev/ F: fsdev/
F: tests/virtio-9p-test.c F: tests/virtio-9p-test.c
T: git https://github.com/gkurz/qemu.git 9p-next T: git https://github.com/gkurz/qemu.git 9p-next
@@ -1541,10 +1467,8 @@ L: qemu-s390x@nongnu.org
virtio-input virtio-input
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained S: Maintained
F: hw/input/vhost-user-input.c
F: hw/input/virtio-input*.c F: hw/input/virtio-input*.c
F: include/hw/virtio/virtio-input.h F: include/hw/virtio/virtio-input.h
F: contrib/vhost-user-input/*
virtio-serial virtio-serial
M: Amit Shah <amit@kernel.org> M: Amit Shah <amit@kernel.org>
@@ -1685,17 +1609,9 @@ virtio-gpu
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained S: Maintained
F: hw/display/virtio-gpu* F: hw/display/virtio-gpu*
F: hw/display/virtio-vga.* F: hw/display/virtio-vga.c
F: include/hw/virtio/virtio-gpu.h F: include/hw/virtio/virtio-gpu.h
vhost-user-gpu
M: Marc-André Lureau <marcandre.lureau@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: docs/interop/vhost-user-gpu.rst
F: contrib/vhost-user-gpu
F: hw/display/vhost-user-*
Cirrus VGA Cirrus VGA
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Odd Fixes S: Odd Fixes
@@ -1716,7 +1632,6 @@ R: Gerd Hoffmann <kraxel@redhat.com>
S: Supported S: Supported
F: docs/specs/fw_cfg.txt F: docs/specs/fw_cfg.txt
F: hw/nvram/fw_cfg.c F: hw/nvram/fw_cfg.c
F: stubs/fw_cfg.c
F: include/hw/nvram/fw_cfg.h F: include/hw/nvram/fw_cfg.h
F: include/standard-headers/linux/qemu_fw_cfg.h F: include/standard-headers/linux/qemu_fw_cfg.h
F: tests/libqos/fw_cfg.c F: tests/libqos/fw_cfg.c
@@ -1730,7 +1645,6 @@ L: qemu-ppc@nongnu.org
S: Supported S: Supported
F: hw/*/*xive* F: hw/*/*xive*
F: include/hw/*/*xive* F: include/hw/*/*xive*
F: docs/*/*xive*
Subsystems Subsystems
---------- ----------
@@ -1849,9 +1763,14 @@ M: Markus Armbruster <armbru@redhat.com>
S: Supported S: Supported
F: scripts/coverity-model.c F: scripts/coverity-model.c
CPU
L: qemu-devel@nongnu.org
S: Supported
F: qom/cpu.c
F: include/qom/cpu.h
Device Tree Device Tree
M: Alistair Francis <alistair.francis@wdc.com> M: Alexander Graf <agraf@suse.de>
R: David Gibson <david@gibson.dropbear.id.au>
S: Maintained S: Maintained
F: device_tree.c F: device_tree.c
F: include/sysemu/device_tree.h F: include/sysemu/device_tree.h
@@ -1859,13 +1778,11 @@ F: include/sysemu/device_tree.h
Dump Dump
S: Supported S: Supported
M: Marc-André Lureau <marcandre.lureau@redhat.com> M: Marc-André Lureau <marcandre.lureau@redhat.com>
F: dump/ F: dump.c
F: hw/misc/vmcoreinfo.c F: hw/misc/vmcoreinfo.c
F: include/hw/misc/vmcoreinfo.h F: include/hw/misc/vmcoreinfo.h
F: include/qemu/win_dump_defs
F: include/sysemu/dump-arch.h F: include/sysemu/dump-arch.h
F: include/sysemu/dump.h F: include/sysemu/dump.h
F: qapi/dump.json
F: scripts/dump-guest-memory.py F: scripts/dump-guest-memory.py
F: stubs/dump.c F: stubs/dump.c
@@ -1878,9 +1795,8 @@ F: util/error.c
F: util/qemu-error.c F: util/qemu-error.c
GDB stub GDB stub
M: Alex Bennée <alex.bennee@linaro.org> L: qemu-devel@nongnu.org
R: Philippe Mathieu-Daudé <philmd@redhat.com> S: Odd Fixes
S: Maintained
F: gdbstub* F: gdbstub*
F: gdb-xml/ F: gdb-xml/
@@ -1931,23 +1847,17 @@ F: qapi/run-state.json
Human Monitor (HMP) Human Monitor (HMP)
M: Dr. David Alan Gilbert <dgilbert@redhat.com> M: Dr. David Alan Gilbert <dgilbert@redhat.com>
S: Maintained S: Maintained
F: monitor/monitor-internal.h F: monitor.c
F: monitor/misc.c F: hmp.[ch]
F: monitor/monitor.c
F: monitor/hmp*
F: hmp.h
F: hmp-commands*.hx F: hmp-commands*.hx
F: include/monitor/hmp-target.h F: include/monitor/hmp-target.h
F: tests/test-hmp.c F: tests/test-hmp.c
F: include/qemu/qemu-print.h
F: util/qemu-print.c
Network device backends Network device backends
M: Jason Wang <jasowang@redhat.com> M: Jason Wang <jasowang@redhat.com>
S: Maintained S: Maintained
F: net/ F: net/
F: include/net/ F: include/net/
F: qemu-bridge-helper.c
T: git https://github.com/jasowang/qemu.git net T: git https://github.com/jasowang/qemu.git net
F: qapi/net.json F: qapi/net.json
@@ -1959,6 +1869,13 @@ W: http://info.iet.unipi.it/~luigi/netmap/
S: Maintained S: Maintained
F: net/netmap.c F: net/netmap.c
NUMA
M: Eduardo Habkost <ehabkost@redhat.com>
S: Maintained
F: numa.c
F: include/sysemu/numa.h
T: git https://github.com/ehabkost/qemu.git machine-next
Host Memory Backends Host Memory Backends
M: Eduardo Habkost <ehabkost@redhat.com> M: Eduardo Habkost <ehabkost@redhat.com>
M: Igor Mammedov <imammedo@redhat.com> M: Igor Mammedov <imammedo@redhat.com>
@@ -2015,14 +1932,10 @@ F: include/qapi/qmp/
X: include/qapi/qmp/dispatch.h X: include/qapi/qmp/dispatch.h
F: scripts/coccinelle/qobject.cocci F: scripts/coccinelle/qobject.cocci
F: tests/check-qdict.c F: tests/check-qdict.c
F: tests/check-qnum.c
F: tests/check-qjson.c F: tests/check-qjson.c
F: tests/check-qlist.c F: tests/check-qlist.c
F: tests/check-qlit.c
F: tests/check-qnull.c
F: tests/check-qnum.c
F: tests/check-qobject.c
F: tests/check-qstring.c F: tests/check-qstring.c
F: tests/data/qobject/qdict.txt
T: git https://repo.or.cz/qemu/armbru.git qapi-next T: git https://repo.or.cz/qemu/armbru.git qapi-next
QEMU Guest Agent QEMU Guest Agent
@@ -2036,32 +1949,21 @@ F: docs/interop/qemu-ga-ref.texi
T: git https://github.com/mdroth/qemu.git qga T: git https://github.com/mdroth/qemu.git qga
QOM QOM
M: Paolo Bonzini <pbonzini@redhat.com> M: Andreas Färber <afaerber@suse.de>
R: Daniel P. Berrange <berrange@redhat.com>
R: Eduardo Habkost <ehabkost@redhat.com>
S: Supported S: Supported
F: docs/qdev-device-use.txt T: git https://github.com/afaerber/qemu-cpu.git qom-next
F: hw/core/qdev*
F: include/hw/qdev*
F: include/monitor/qdev.h
F: include/qom/ F: include/qom/
X: include/qom/cpu.h X: include/qom/cpu.h
F: qapi/qom.json
F: qapi/qdev.json
F: qdev-monitor.c
F: qom/ F: qom/
X: qom/cpu.c X: qom/cpu.c
F: tests/check-qom-interface.c F: tests/check-qom-interface.c
F: tests/check-qom-proplist.c F: tests/check-qom-proplist.c
F: tests/test-qdev-global-props.c
QMP QMP
M: Markus Armbruster <armbru@redhat.com> M: Markus Armbruster <armbru@redhat.com>
S: Supported S: Supported
F: monitor/monitor-internal.h F: qmp.c
F: monitor/qmp* F: monitor.c
F: monitor/misc.c
F: monitor/monitor.c
F: docs/devel/*qmp-* F: docs/devel/*qmp-*
F: docs/interop/*qmp-* F: docs/interop/*qmp-*
F: scripts/qmp/ F: scripts/qmp/
@@ -2075,7 +1977,6 @@ M: Laurent Vivier <lvivier@redhat.com>
R: Paolo Bonzini <pbonzini@redhat.com> R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained S: Maintained
F: qtest.c F: qtest.c
F: accel/qtest.c
F: tests/libqtest.* F: tests/libqtest.*
F: tests/libqos/ F: tests/libqos/
F: tests/*-test.c F: tests/*-test.c
@@ -2156,14 +2057,11 @@ F: crypto/
F: include/crypto/ F: include/crypto/
F: tests/test-crypto-* F: tests/test-crypto-*
F: tests/benchmark-crypto-* F: tests/benchmark-crypto-*
F: tests/crypto-tls-*
F: tests/pkix_asn1_tab.c
F: qemu.sasl F: qemu.sasl
Coroutines Coroutines
M: Stefan Hajnoczi <stefanha@redhat.com> M: Stefan Hajnoczi <stefanha@redhat.com>
M: Kevin Wolf <kwolf@redhat.com> M: Kevin Wolf <kwolf@redhat.com>
S: Maintained
F: util/*coroutine* F: util/*coroutine*
F: include/qemu/coroutine* F: include/qemu/coroutine*
F: tests/test-coroutine.c F: tests/test-coroutine.c
@@ -2231,7 +2129,7 @@ F: include/migration/failover.h
F: docs/COLO-FT.txt F: docs/COLO-FT.txt
COLO Proxy COLO Proxy
M: Zhang Chen <chen.zhang@intel.com> M: Zhang Chen <zhangckid@gmail.com>
M: Li Zhijian <lizhijian@cn.fujitsu.com> M: Li Zhijian <lizhijian@cn.fujitsu.com>
S: Supported S: Supported
F: docs/colo-proxy.txt F: docs/colo-proxy.txt
@@ -2262,33 +2160,9 @@ M: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
S: Maintained S: Maintained
F: contrib/elf2dmp/ F: contrib/elf2dmp/
I2C and SMBus
M: Corey Minyard <cminyard@mvista.com>
S: Maintained
F: hw/i2c/core.c
F: hw/i2c/smbus_slave.c
F: hw/i2c/smbus_master.c
F: hw/i2c/smbus_eeprom.c
F: include/hw/i2c/i2c.h
F: include/hw/i2c/smbus_master.h
F: include/hw/i2c/smbus_slave.h
F: include/hw/i2c/smbus_eeprom.h
EDK2 Firmware
M: Laszlo Ersek <lersek@redhat.com>
M: Philippe Mathieu-Daudé <philmd@redhat.com>
S: Supported
F: pc-bios/descriptors/??-edk2-*.json
F: pc-bios/edk2-*
F: roms/Makefile.edk2
F: roms/edk2
F: roms/edk2-*
F: tests/data/uefi-boot-images/
F: tests/uefi-test-tools/
Usermode Emulation Usermode Emulation
------------------ ------------------
Overall usermode emulation Overall
M: Riku Voipio <riku.voipio@iki.fi> M: Riku Voipio <riku.voipio@iki.fi>
S: Maintained S: Maintained
F: thunk.c F: thunk.c
@@ -2309,12 +2183,12 @@ F: scripts/qemu-binfmt-conf.sh
Tiny Code Generator (TCG) Tiny Code Generator (TCG)
------------------------- -------------------------
Common TCG code Common code
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
S: Maintained S: Maintained
F: tcg/ F: tcg/
AArch64 TCG target AArch64 target
M: Claudio Fontana <claudio.fontana@huawei.com> M: Claudio Fontana <claudio.fontana@huawei.com>
M: Claudio Fontana <claudio.fontana@gmail.com> M: Claudio Fontana <claudio.fontana@gmail.com>
S: Maintained S: Maintained
@@ -2323,32 +2197,34 @@ F: tcg/aarch64/
F: disas/arm-a64.cc F: disas/arm-a64.cc
F: disas/libvixl/ F: disas/libvixl/
ARM TCG target ARM target
M: Andrzej Zaborowski <balrogg@gmail.com> M: Andrzej Zaborowski <balrogg@gmail.com>
S: Maintained S: Maintained
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
F: tcg/arm/ F: tcg/arm/
F: disas/arm.c F: disas/arm.c
i386 TCG target i386 target
M: Richard Henderson <rth@twiddle.net> L: qemu-devel@nongnu.org
S: Maintained S: Maintained
F: tcg/i386/ F: tcg/i386/
F: disas/i386.c F: disas/i386.c
MIPS TCG target MIPS target
M: Aurelien Jarno <aurelien@aurel32.net> M: Aurelien Jarno <aurelien@aurel32.net>
R: Aleksandar Rikalo <arikalo@wavecomp.com> R: Aleksandar Rikalo <arikalo@wavecomp.com>
S: Maintained S: Maintained
F: tcg/mips/ F: tcg/mips/
F: disas/mips.c
PPC TCG target PPC
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
S: Odd Fixes S: Odd Fixes
F: tcg/ppc/ F: tcg/ppc/
F: disas/ppc.c F: disas/ppc.c
RISC-V TCG target RISC-V
M: Michael Clark <mjc@sifive.com>
M: Palmer Dabbelt <palmer@sifive.com> M: Palmer Dabbelt <palmer@sifive.com>
M: Alistair Francis <Alistair.Francis@wdc.com> M: Alistair Francis <Alistair.Francis@wdc.com>
L: qemu-riscv@nongnu.org L: qemu-riscv@nongnu.org
@@ -2356,19 +2232,19 @@ S: Maintained
F: tcg/riscv/ F: tcg/riscv/
F: disas/riscv.c F: disas/riscv.c
S390 TCG target S390 target
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
S: Maintained S: Maintained
F: tcg/s390/ F: tcg/s390/
F: disas/s390.c F: disas/s390.c
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
SPARC TCG target SPARC target
S: Odd Fixes S: Odd Fixes
F: tcg/sparc/ F: tcg/sparc/
F: disas/sparc.c F: disas/sparc.c
TCI TCG target TCI target
M: Stefan Weil <sw@weilnetz.de> M: Stefan Weil <sw@weilnetz.de>
S: Maintained S: Maintained
F: tcg/tci/ F: tcg/tci/
@@ -2384,7 +2260,7 @@ S: Supported
F: block/vmdk.c F: block/vmdk.c
RBD RBD
M: Jason Dillaman <dillaman@redhat.com> M: Josh Durgin <jdurgin@redhat.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Supported S: Supported
F: block/rbd.c F: block/rbd.c
@@ -2443,13 +2319,12 @@ F: block/ssh.c
CURL CURL
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Odd Fixes S: Supported
F: block/curl.c F: block/curl.c
GLUSTER GLUSTER
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
L: integration@gluster.org S: Supported
S: Odd Fixes
F: block/gluster.c F: block/gluster.c
Null Block Driver Null Block Driver
@@ -2588,18 +2463,13 @@ F: docs/pvrdma.txt
F: contrib/rdmacm-mux/* F: contrib/rdmacm-mux/*
F: qapi/rdma.json F: qapi/rdma.json
Semihosting
M: Alex Bennée <alex.bennee@linaro.org>
S: Maintained
F: hw/semihosting/
F: include/hw/semihosting/
Build and test automation Build and test automation
------------------------- -------------------------
Build and test automation Build and test automation
M: Alex Bennée <alex.bennee@linaro.org> M: Alex Bennée <alex.bennee@linaro.org>
M: Fam Zheng <fam@euphon.net> M: Fam Zheng <fam@euphon.net>
R: Philippe Mathieu-Daudé <philmd@redhat.com> R: Philippe Mathieu-Daudé <philmd@redhat.com>
L: qemu-devel@nongnu.org
S: Maintained S: Maintained
F: .travis.yml F: .travis.yml
F: scripts/travis/ F: scripts/travis/
@@ -2614,6 +2484,7 @@ W: http://patchew.org/QEMU/
FreeBSD Hosted Continuous Integration FreeBSD Hosted Continuous Integration
M: Ed Maste <emaste@freebsd.org> M: Ed Maste <emaste@freebsd.org>
M: Li-Wen Hsu <lwhsu@freebsd.org> M: Li-Wen Hsu <lwhsu@freebsd.org>
L: qemu-devel@nongnu.org
S: Maintained S: Maintained
F: .cirrus.yml F: .cirrus.yml
W: https://cirrus-ci.com/github/qemu/qemu W: https://cirrus-ci.com/github/qemu/qemu
@@ -2626,9 +2497,9 @@ F: .gitlab-ci.yml
Guest Test Compilation Support Guest Test Compilation Support
M: Alex Bennée <alex.bennee@linaro.org> M: Alex Bennée <alex.bennee@linaro.org>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <f4bug@amsat.org>
S: Maintained
F: tests/tcg/Makefile F: tests/tcg/Makefile
F: tests/tcg/Makefile.include F: tests/tcg/Makefile.include
L: qemu-devel@nongnu.org
Documentation Documentation
------------- -------------
@@ -2653,9 +2524,3 @@ GIT submodules
M: Daniel P. Berrange <berrange@redhat.com> M: Daniel P. Berrange <berrange@redhat.com>
S: Odd Fixes S: Odd Fixes
F: scripts/git-submodule.sh F: scripts/git-submodule.sh
Sphinx documentation configuration and build machinery
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: docs/conf.py
F: docs/*/conf.py

375
Makefile
View File

@@ -1,9 +1,5 @@
# Makefile for QEMU. # Makefile for QEMU.
ifneq ($(words $(subst :, ,$(CURDIR))), 1)
$(error main directory cannot contain spaces nor colons)
endif
# Always point to the root of the build tree (needs GNU make). # Always point to the root of the build tree (needs GNU make).
BUILD_DIR=$(CURDIR) BUILD_DIR=$(CURDIR)
@@ -13,7 +9,7 @@ SRC_PATH=.
UNCHECKED_GOALS := %clean TAGS cscope ctags dist \ UNCHECKED_GOALS := %clean TAGS cscope ctags dist \
html info pdf txt \ html info pdf txt \
help check-help print-% \ help check-help print-% \
docker docker-% vm-help vm-test vm-build-% docker docker-% vm-test vm-build-%
print-%: print-%:
@echo '$*=$($*)' @echo '$*=$($*)'
@@ -73,7 +69,14 @@ CONFIG_ALL=y
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
@echo $@ is out-of-date, running configure @echo $@ is out-of-date, running configure
@./config.status @# TODO: The next lines include code which supports a smooth
@# transition from old configurations without config.status.
@# This code can be removed after QEMU 1.7.
@if test -x config.status; then \
./config.status; \
else \
sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh; \
fi
else else
config-host.mak: config-host.mak:
ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail)) ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
@@ -84,25 +87,7 @@ endif
include $(SRC_PATH)/rules.mak include $(SRC_PATH)/rules.mak
# notempy and lor are defined in rules.mak GENERATED_FILES = qemu-version.h config-host.h qemu-options.def
CONFIG_TOOLS := $(call notempty,$(TOOLS))
CONFIG_BLOCK := $(call lor,$(CONFIG_SOFTMMU),$(CONFIG_TOOLS))
# Create QEMU_PKGVERSION and FULL_VERSION strings
# If PKGVERSION is set, use that; otherwise get version and -dirty status from git
QEMU_PKGVERSION := $(if $(PKGVERSION),$(PKGVERSION),$(shell \
cd $(SRC_PATH); \
if test -e .git; then \
git describe --match 'v*' 2>/dev/null | tr -d '\n'; \
if ! git diff-index --quiet HEAD &>/dev/null; then \
echo "-dirty"; \
fi; \
fi))
# Either "version (pkgversion)", or just "version" if pkgversion not set
FULL_VERSION := $(if $(QEMU_PKGVERSION),$(VERSION) ($(QEMU_PKGVERSION)),$(VERSION))
generated-files-y = qemu-version.h config-host.h qemu-options.def
GENERATED_QAPI_FILES = qapi/qapi-builtin-types.h qapi/qapi-builtin-types.c GENERATED_QAPI_FILES = qapi/qapi-builtin-types.h qapi/qapi-builtin-types.c
GENERATED_QAPI_FILES += qapi/qapi-types.h qapi/qapi-types.c GENERATED_QAPI_FILES += qapi/qapi-types.h qapi/qapi-types.c
@@ -122,18 +107,20 @@ 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-introspect.c qapi/qapi-introspect.h
GENERATED_QAPI_FILES += qapi/qapi-doc.texi GENERATED_QAPI_FILES += qapi/qapi-doc.texi
generated-files-y += $(GENERATED_QAPI_FILES) GENERATED_FILES += $(GENERATED_QAPI_FILES)
generated-files-y += trace/generated-tcg-tracers.h GENERATED_FILES += trace/generated-tcg-tracers.h
generated-files-y += trace/generated-helpers-wrappers.h GENERATED_FILES += trace/generated-helpers-wrappers.h
generated-files-y += trace/generated-helpers.h GENERATED_FILES += trace/generated-helpers.h
generated-files-y += trace/generated-helpers.c GENERATED_FILES += trace/generated-helpers.c
generated-files-$(CONFIG_TRACE_UST) += trace-ust-all.h ifdef CONFIG_TRACE_UST
generated-files-$(CONFIG_TRACE_UST) += trace-ust-all.c GENERATED_FILES += trace-ust-all.h
GENERATED_FILES += trace-ust-all.c
endif
generated-files-y += module_block.h GENERATED_FILES += module_block.h
TRACE_HEADERS = trace-root.h $(trace-events-subdirs:%=%/trace.h) TRACE_HEADERS = trace-root.h $(trace-events-subdirs:%=%/trace.h)
TRACE_SOURCES = trace-root.c $(trace-events-subdirs:%=%/trace.c) TRACE_SOURCES = trace-root.c $(trace-events-subdirs:%=%/trace.c)
@@ -146,10 +133,10 @@ ifdef CONFIG_TRACE_UST
TRACE_HEADERS += trace-ust-root.h $(trace-events-subdirs:%=%/trace-ust.h) TRACE_HEADERS += trace-ust-root.h $(trace-events-subdirs:%=%/trace-ust.h)
endif endif
generated-files-y += $(TRACE_HEADERS) GENERATED_FILES += $(TRACE_HEADERS)
generated-files-y += $(TRACE_SOURCES) GENERATED_FILES += $(TRACE_SOURCES)
generated-files-y += $(BUILD_DIR)/trace-events-all GENERATED_FILES += $(BUILD_DIR)/trace-events-all
generated-files-y += .git-submodule-status GENERATED_FILES += .git-submodule-status
trace-group-name = $(shell dirname $1 | sed -e 's/[^a-zA-Z0-9]/_/g') trace-group-name = $(shell dirname $1 | sed -e 's/[^a-zA-Z0-9]/_/g')
@@ -280,7 +267,7 @@ KEYCODEMAP_FILES = \
ui/input-keymap-osx-to-qcode.c \ ui/input-keymap-osx-to-qcode.c \
$(NULL) $(NULL)
generated-files-$(CONFIG_SOFTMMU) += $(KEYCODEMAP_FILES) GENERATED_FILES += $(KEYCODEMAP_FILES)
ui/input-keymap-%.c: $(KEYCODEMAP_GEN) $(KEYCODEMAP_CSV) $(SRC_PATH)/ui/Makefile.objs ui/input-keymap-%.c: $(KEYCODEMAP_GEN) $(KEYCODEMAP_CSV) $(SRC_PATH)/ui/Makefile.objs
$(call quiet-command,\ $(call quiet-command,\
@@ -295,10 +282,6 @@ ui/input-keymap-%.c: $(KEYCODEMAP_GEN) $(KEYCODEMAP_CSV) $(SRC_PATH)/ui/Makefile
$(KEYCODEMAP_GEN): .git-submodule-status $(KEYCODEMAP_GEN): .git-submodule-status
$(KEYCODEMAP_CSV): .git-submodule-status $(KEYCODEMAP_CSV): .git-submodule-status
edk2-decompressed = $(basename $(wildcard pc-bios/edk2-*.fd.bz2))
pc-bios/edk2-%.fd: pc-bios/edk2-%.fd.bz2
$(call quiet-command,bzip2 -d -c $< > $@,"BUNZIP2",$<)
# Don't try to regenerate Makefile or configure # Don't try to regenerate Makefile or configure
# We don't generate any of them # We don't generate any of them
Makefile: ; Makefile: ;
@@ -311,20 +294,8 @@ $(call set-vpath, $(SRC_PATH))
LIBS+=-lz $(LIBS_TOOLS) LIBS+=-lz $(LIBS_TOOLS)
vhost-user-json-y =
HELPERS-y =
HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = qemu-bridge-helper$(EXESUF) HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = qemu-bridge-helper$(EXESUF)
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
endif
endif
ifdef BUILD_DOCS ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8 DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 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-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
@@ -342,14 +313,14 @@ DOCS=
endif endif
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet) BUILD_DIR=$(BUILD_DIR) SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory --quiet) BUILD_DIR=$(BUILD_DIR)
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(filter %-softmmu, $(TARGET_DIRS))) SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %.d, $(SUBDIR_DEVICES_MAK)) SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS))
ifeq ($(SUBDIR_DEVICES_MAK),) ifeq ($(SUBDIR_DEVICES_MAK),)
config-all-devices.mak: config-host.mak config-all-devices.mak:
$(call quiet-command,echo '# no devices' > $@,"GEN","$@") $(call quiet-command,echo '# no devices' > $@,"GEN","$@")
else else
config-all-devices.mak: $(SUBDIR_DEVICES_MAK) config-host.mak config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
$(call quiet-command, sed -n \ $(call quiet-command, sed -n \
's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \ 's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \
$(SUBDIR_DEVICES_MAK) | sort -u > $@, \ $(SUBDIR_DEVICES_MAK) | sort -u > $@, \
@@ -358,27 +329,9 @@ endif
-include $(SUBDIR_DEVICES_MAK_DEP) -include $(SUBDIR_DEVICES_MAK_DEP)
# This has to be kept in sync with Kconfig.host. %/config-devices.mak: default-configs/%.mak $(SRC_PATH)/scripts/make_device_config.sh
MINIKCONF_ARGS = \ $(call quiet-command, \
$(CONFIG_MINIKCONF_MODE) \ $(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $< $*-config-devices.mak.d $@ > $@.tmp,"GEN","$@.tmp")
$@ $*/config-devices.mak.d $< $(MINIKCONF_INPUTS) \
CONFIG_KVM=$(CONFIG_KVM) \
CONFIG_SPICE=$(CONFIG_SPICE) \
CONFIG_IVSHMEM=$(CONFIG_IVSHMEM) \
CONFIG_TPM=$(CONFIG_TPM) \
CONFIG_XEN=$(CONFIG_XEN) \
CONFIG_OPENGL=$(CONFIG_OPENGL) \
CONFIG_X11=$(CONFIG_X11) \
CONFIG_VHOST_USER=$(CONFIG_VHOST_USER) \
CONFIG_VIRTFS=$(CONFIG_VIRTFS) \
CONFIG_LINUX=$(CONFIG_LINUX) \
CONFIG_PVRDMA=$(CONFIG_PVRDMA)
MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig
MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \
$(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 \ $(call quiet-command, if test -f $@; then \
if cmp -s $@.old $@; then \ if cmp -s $@.old $@; then \
mv $@.tmp $@; \ mv $@.tmp $@; \
@@ -417,13 +370,11 @@ dummy := $(call unnest-vars,, \
libvhost-user-obj-y \ libvhost-user-obj-y \
vhost-user-scsi-obj-y \ vhost-user-scsi-obj-y \
vhost-user-blk-obj-y \ vhost-user-blk-obj-y \
vhost-user-input-obj-y \
vhost-user-gpu-obj-y \
qga-vss-dll-obj-y \ qga-vss-dll-obj-y \
block-obj-y \ block-obj-y \
block-obj-m \ block-obj-m \
crypto-obj-y \ crypto-obj-y \
crypto-user-obj-y \ crypto-aes-obj-y \
qom-obj-y \ qom-obj-y \
io-obj-y \ io-obj-y \
common-obj-y \ common-obj-y \
@@ -432,16 +383,32 @@ dummy := $(call unnest-vars,, \
ui-obj-m \ ui-obj-m \
audio-obj-y \ audio-obj-y \
audio-obj-m \ audio-obj-m \
trace-obj-y) trace-obj-y \
slirp-obj-y)
include $(SRC_PATH)/tests/Makefile.include include $(SRC_PATH)/tests/Makefile.include
all: $(DOCS) $(if $(BUILD_DOCS),sphinxdocs) $(TOOLS) $(HELPERS-y) recurse-all modules $(vhost-user-json-y) all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
qemu-version.h: FORCE qemu-version.h: FORCE
$(call quiet-command, \ $(call quiet-command, \
(printf '#define QEMU_PKGVERSION "$(QEMU_PKGVERSION)"\n'; \ (cd $(SRC_PATH); \
printf '#define QEMU_FULL_VERSION "$(FULL_VERSION)"\n'; \ if test -n "$(PKGVERSION)"; then \
pkgvers="$(PKGVERSION)"; \
else \
if test -d .git; then \
pkgvers=$$(git describe --match 'v*' 2>/dev/null | tr -d '\n');\
if ! git diff-index --quiet HEAD &>/dev/null; then \
pkgvers="$${pkgvers}-dirty"; \
fi; \
fi; \
fi; \
printf "#define QEMU_PKGVERSION \"$${pkgvers}\"\n"; \
if test -n "$${pkgvers}"; then \
printf '#define QEMU_FULL_VERSION QEMU_VERSION " (" QEMU_PKGVERSION ")"\n'; \
else \
printf '#define QEMU_FULL_VERSION QEMU_VERSION\n'; \
fi; \
) > $@.tmp) ) > $@.tmp)
$(call quiet-command, if ! cmp -s $@ $@.tmp; then \ $(call quiet-command, if ! cmp -s $@ $@.tmp; then \
mv $@.tmp $@; \ mv $@.tmp $@; \
@@ -454,29 +421,23 @@ config-host.h-timestamp: config-host.mak
qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool qemu-options.def: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@") $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
TARGET_DIRS_RULES := $(foreach t, all clean install, $(addsuffix /$(t), $(TARGET_DIRS))) SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
SOFTMMU_ALL_RULES=$(filter %-softmmu/all, $(TARGET_DIRS_RULES)) $(SOFTMMU_SUBDIR_RULES): $(authz-obj-y)
$(SOFTMMU_ALL_RULES): $(authz-obj-y) $(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
$(SOFTMMU_ALL_RULES): $(block-obj-y) $(SOFTMMU_SUBDIR_RULES): $(crypto-obj-y)
$(SOFTMMU_ALL_RULES): $(chardev-obj-y) $(SOFTMMU_SUBDIR_RULES): $(io-obj-y)
$(SOFTMMU_ALL_RULES): $(crypto-obj-y) $(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
$(SOFTMMU_ALL_RULES): $(io-obj-y)
$(SOFTMMU_ALL_RULES): config-all-devices.mak
$(SOFTMMU_ALL_RULES): $(edk2-decompressed)
.PHONY: $(TARGET_DIRS_RULES) subdir-%:
# The $(TARGET_DIRS_RULES) are of the form SUBDIR/GOAL, so that $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
# $(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 $@),)
DTC_MAKE_ARGS=-I$(SRC_PATH)/dtc VPATH=$(SRC_PATH)/dtc -C dtc V="$(V)" LIBFDT_srcdir=$(SRC_PATH)/dtc/libfdt 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_CFLAGS=$(CFLAGS) $(QEMU_CFLAGS)
DTC_CPPFLAGS=-I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt DTC_CPPFLAGS=-I$(BUILD_DIR)/dtc -I$(SRC_PATH)/dtc -I$(SRC_PATH)/dtc/libfdt
.PHONY: dtc/all subdir-dtc: .git-submodule-status dtc/libfdt dtc/tests
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,) $(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 dtc/%: .git-submodule-status
@@ -494,35 +455,20 @@ CAP_CFLAGS += -DCAPSTONE_HAS_ARM64
CAP_CFLAGS += -DCAPSTONE_HAS_POWERPC CAP_CFLAGS += -DCAPSTONE_HAS_POWERPC
CAP_CFLAGS += -DCAPSTONE_HAS_X86 CAP_CFLAGS += -DCAPSTONE_HAS_X86
.PHONY: capstone/all subdir-capstone: .git-submodule-status
capstone/all: .git-submodule-status
$(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE)) $(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE))
.PHONY: slirp/all $(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) $(slirp-obj-y) \
slirp/all: .git-submodule-status $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
$(call quiet-command,$(MAKE) -C $(SRC_PATH)/slirp BUILD_DIR="$(BUILD_DIR)/slirp" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)")
# Compatibility gunk to keep make working across the rename of targets ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
# 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) $(crypto-user-obj-$(CONFIG_USER_ONLY))
ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
ROM_DIRS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROM_DIRS)))
# Only keep -O and -g cflags # Only keep -O and -g cflags
.PHONY: $(ROM_DIRS_RULES) romsubdir-%:
$(ROM_DIRS_RULES): $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pc-bios/$* V="$(V)" TARGET_DIR="$*/" CFLAGS="$(filter -O% -g%,$(CFLAGS))",)
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" CFLAGS="$(filter -O% -g%,$(CFLAGS))" $(notdir $@),)
.PHONY: recurse-all recurse-clean recurse-install ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
recurse-all: $(addsuffix /all, $(TARGET_DIRS) $(ROM_DIRS))
recurse-clean: $(addsuffix /clean, $(TARGET_DIRS) $(ROM_DIRS)) recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
recurse-install: $(addsuffix /install, $(TARGET_DIRS))
$(addsuffix /install, $(TARGET_DIRS)): all
$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h $(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h
$(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o") $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o")
@@ -533,7 +479,7 @@ Makefile: $(version-obj-y)
# Build libraries # Build libraries
libqemuutil.a: $(util-obj-y) $(trace-obj-y) $(stub-obj-y) libqemuutil.a: $(util-obj-y) $(trace-obj-y) $(stub-obj-y)
libvhost-user.a: $(libvhost-user-obj-y) $(util-obj-y) $(stub-obj-y) libvhost-user.a: $(libvhost-user-obj-y)
###################################################################### ######################################################################
@@ -626,6 +572,7 @@ ifneq ($(EXESUF),)
qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI) qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
endif endif
elf2dmp$(EXESUF): LIBS += $(CURL_LIBS)
elf2dmp$(EXESUF): $(elf2dmp-obj-y) elf2dmp$(EXESUF): $(elf2dmp-obj-y)
$(call LINK, $^) $(call LINK, $^)
@@ -644,19 +591,6 @@ rdmacm-mux$(EXESUF): LIBS += "-libumad"
rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS) rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
$(call LINK, $^) $(call LINK, $^)
vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a
$(call LINK, $^)
ifdef CONFIG_VHOST_USER_INPUT
ifdef CONFIG_LINUX
vhost-user-input$(EXESUF): $(vhost-user-input-obj-y) libvhost-user.a libqemuutil.a
$(call LINK, $^)
# build by default, do not install
all: vhost-user-input$(EXESUF)
endif
endif
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
$(call quiet-command,$(PYTHON) $< $@ \ $(call quiet-command,$(PYTHON) $< $@ \
$(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \ $(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \
@@ -670,27 +604,26 @@ clean-coverage:
"CLEAN", "coverage files") "CLEAN", "coverage files")
endif endif
clean: recurse-clean clean:
# avoid old build problems by removing potentially incorrect old files # avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f qemu-options.def rm -f qemu-options.def
rm -f *.msi rm -f *.msi
find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f \ find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-aarch64.a \ rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-arm.a \
! -path ./roms/edk2/BaseTools/Source/Python/UPT/Dll/sqlite3.dll \
-exec rm {} +
rm -f $(edk2-decompressed)
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga$(EXESUF) TAGS cscope.* *.pod *~ */*~
rm -f fsdev/*.pod scsi/*.pod rm -f fsdev/*.pod scsi/*.pod
rm -f qemu-img-cmds.h rm -f qemu-img-cmds.h
rm -f ui/shader/*-vert.h ui/shader/*-frag.h rm -f ui/shader/*-vert.h ui/shader/*-frag.h
@# May not be present in generated-files-y @# May not be present in GENERATED_FILES
rm -f trace/generated-tracers-dtrace.dtrace* rm -f trace/generated-tracers-dtrace.dtrace*
rm -f trace/generated-tracers-dtrace.h* rm -f trace/generated-tracers-dtrace.h*
rm -f $(foreach f,$(generated-files-y),$(f) $(f)-timestamp) rm -f $(foreach f,$(GENERATED_FILES),$(f) $(f)-timestamp)
rm -f qapi-gen-timestamp rm -f qapi-gen-timestamp
rm -rf qga/qapi-generated rm -rf qga/qapi-generated
for d in $(ALL_SUBDIRS); do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
done
rm -f config-all-devices.mak rm -f config-all-devices.mak
VERSION ?= $(shell cat VERSION) VERSION ?= $(shell cat VERSION)
@@ -700,22 +633,6 @@ dist: qemu-$(VERSION).tar.bz2
qemu-%.tar.bz2: qemu-%.tar.bz2:
$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)" $(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
# Sphinx does not allow building manuals into the same directory as
# the source files, so if we're doing an in-tree QEMU build we must
# build the manuals into a subdirectory (and then install them from
# there for 'make install'). For an out-of-tree build we can just
# use the docs/ subdirectory in the build tree as normal.
ifeq ($(realpath $(SRC_PATH)),$(realpath .))
MANUAL_BUILDDIR := docs/built
else
MANUAL_BUILDDIR := docs
endif
define clean-manual =
rm -rf $(MANUAL_BUILDDIR)/$1/_static
rm -f $(MANUAL_BUILDDIR)/$1/objects.inv $(MANUAL_BUILDDIR)/$1/searchindex.js $(MANUAL_BUILDDIR)/$1/*.html
endef
distclean: clean distclean: clean
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 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 config-all-devices.mak config-all-disas.mak config.status rm -f config-all-devices.mak config-all-disas.mak config.status
@@ -736,10 +653,6 @@ distclean: clean
rm -f docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html 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-block-drivers.7
rm -f docs/qemu-cpu-models.7 rm -f docs/qemu-cpu-models.7
rm -rf .doctrees
$(call clean-manual,devel)
$(call clean-manual,interop)
$(call clean-manual,specs)
for d in $(TARGET_DIRS); do \ for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \ rm -rf $$d || exit 1 ; \
done done
@@ -754,14 +667,13 @@ bepo cz
ifdef INSTALL_BLOBS ifdef INSTALL_BLOBS
BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \ vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \
vgabios-ramfb.bin vgabios-bochs-display.bin vgabios-ati.bin \ vgabios-ramfb.bin vgabios-bochs-display.bin \
ppc_rom.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-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \ efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \ efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \
efi-e1000e.rom efi-vmxnet3.rom \ efi-e1000e.rom efi-vmxnet3.rom \
qemu-nsis.bmp \
bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin \ multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin \
s390-ccw.img s390-netboot.img \ s390-ccw.img s390-netboot.img \
@@ -769,34 +681,12 @@ spapr-rtas.bin slof.bin skiboot.lid \
palcode-clipper \ palcode-clipper \
u-boot.e500 u-boot-sam460-20100605.bin \ u-boot.e500 u-boot-sam460-20100605.bin \
qemu_vga.ndrv \ qemu_vga.ndrv \
edk2-licenses.txt \ hppa-firmware.img
hppa-firmware.img \
opensbi-riscv32-virt-fw_jump.bin \
opensbi-riscv64-sifive_u-fw_jump.bin opensbi-riscv64-virt-fw_jump.bin
DESCS=50-edk2-i386-secure.json 50-edk2-x86_64-secure.json \
60-edk2-aarch64.json 60-edk2-arm.json 60-edk2-i386.json 60-edk2-x86_64.json
else else
BLOBS= BLOBS=
DESCS=
endif endif
# Note that we manually filter-out the non-Sphinx documentation which install-doc: $(DOCS)
# is currently built into the docs/interop directory in the build tree.
define install-manual =
for d in $$(cd $(MANUAL_BUILDDIR) && find $1 -type d); do $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)/$$d"; done
for f in $$(cd $(MANUAL_BUILDDIR) && find $1 -type f -a '!' '(' -name 'qemu-*-qapi.*' -o -name 'qemu-*-ref.*' ')' ); do $(INSTALL_DATA) "$(MANUAL_BUILDDIR)/$$f" "$(DESTDIR)$(qemu_docdir)/$$f"; done
endef
# Note that we deliberately do not install the "devel" manual: it is
# for QEMU developers, and not interesting to our users.
.PHONY: install-sphinxdocs
install-sphinxdocs: sphinxdocs
$(call install-manual,interop)
$(call install-manual,specs)
install-doc: $(DOCS) install-sphinxdocs
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) qemu-doc.txt "$(DESTDIR)$(qemu_docdir)" $(INSTALL_DATA) qemu-doc.txt "$(DESTDIR)$(qemu_docdir)"
@@ -841,9 +731,7 @@ endif
ICON_SIZES=16x16 24x24 32x32 48x48 64x64 128x128 256x256 512x512 ICON_SIZES=16x16 24x24 32x32 48x48 64x64 128x128 256x256 512x512
install: all $(if $(BUILD_DOCS),install-doc) install-datadir install-localstatedir \ install: all $(if $(BUILD_DOCS),install-doc) install-datadir install-localstatedir
$(if $(INSTALL_BLOBS),$(edk2-decompressed)) \
recurse-install
ifneq ($(TOOLS),) ifneq ($(TOOLS),)
$(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir)) $(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir))
endif endif
@@ -858,12 +746,6 @@ endif
ifneq ($(HELPERS-y),) ifneq ($(HELPERS-y),)
$(call install-prog,$(HELPERS-y),$(DESTDIR)$(libexecdir)) $(call install-prog,$(HELPERS-y),$(DESTDIR)$(libexecdir))
endif endif
ifneq ($(vhost-user-json-y),)
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/vhost-user/"
for x in $(vhost-user-json-y); do \
$(INSTALL_DATA) $$x "$(DESTDIR)$(qemu_datadir)/vhost-user/"; \
done
endif
ifdef CONFIG_TRACE_SYSTEMTAP ifdef CONFIG_TRACE_SYSTEMTAP
$(INSTALL_PROG) "scripts/qemu-trace-stap" $(DESTDIR)$(bindir) $(INSTALL_PROG) "scripts/qemu-trace-stap" $(DESTDIR)$(bindir)
endif endif
@@ -871,36 +753,21 @@ ifneq ($(BLOBS),)
set -e; for x in $(BLOBS); do \ set -e; for x in $(BLOBS); do \
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
done done
endif
ifdef INSTALL_BLOBS
set -e; for x in $(edk2-decompressed); do \
$(INSTALL_DATA) $$x "$(DESTDIR)$(qemu_datadir)"; \
done
endif
ifneq ($(DESCS),)
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/firmware"
set -e; tmpf=$$(mktemp); trap 'rm -f -- "$$tmpf"' EXIT; \
for x in $(DESCS); do \
sed -e 's,@DATADIR@,$(qemu_datadir),' \
"$(SRC_PATH)/pc-bios/descriptors/$$x" > "$$tmpf"; \
$(INSTALL_DATA) "$$tmpf" \
"$(DESTDIR)$(qemu_datadir)/firmware/$$x"; \
done
endif endif
for s in $(ICON_SIZES); do \ for s in $(ICON_SIZES); do \
mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/$${s}/apps"; \ mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/$${s}/apps"; \
$(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_$${s}.png \ $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_$${s}.png \
"$(DESTDIR)$(qemu_icondir)/hicolor/$${s}/apps/qemu.png"; \ "$(DESTDIR)/$(qemu_icondir)/hicolor/$${s}/apps/qemu.png"; \
done; \ done; \
mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/32x32/apps"; \ mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/32x32/apps"; \
$(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_32x32.bmp \ $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_32x32.bmp \
"$(DESTDIR)$(qemu_icondir)/hicolor/32x32/apps/qemu.bmp"; \ "$(DESTDIR)/$(qemu_icondir)/hicolor/32x32/apps/qemu.bmp"; \
mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/scalable/apps"; \ mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/scalable/apps"; \
$(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu.svg \ $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu.svg \
"$(DESTDIR)$(qemu_icondir)/hicolor/scalable/apps/qemu.svg" "$(DESTDIR)/$(qemu_icondir)/hicolor/scalable/apps/qemu.svg"
mkdir -p "$(DESTDIR)$(qemu_desktopdir)" mkdir -p "$(DESTDIR)/$(qemu_desktopdir)"
$(INSTALL_DATA) $(SRC_PATH)/ui/qemu.desktop \ $(INSTALL_DATA) $(SRC_PATH)/ui/qemu.desktop \
"$(DESTDIR)$(qemu_desktopdir)/qemu.desktop" "$(DESTDIR)/$(qemu_desktopdir)/qemu.desktop"
ifdef CONFIG_GTK ifdef CONFIG_GTK
$(MAKE) -C po $@ $(MAKE) -C po $@
endif endif
@@ -909,6 +776,9 @@ endif
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
done done
$(INSTALL_DATA) $(BUILD_DIR)/trace-events-all "$(DESTDIR)$(qemu_datadir)/trace-events-all" $(INSTALL_DATA) $(BUILD_DIR)/trace-events-all "$(DESTDIR)$(qemu_datadir)/trace-events-all"
for d in $(TARGET_DIRS); do \
$(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \
done
.PHONY: ctags .PHONY: ctags
ctags: ctags:
@@ -947,14 +817,11 @@ ui/shader.o: $(SRC_PATH)/ui/shader.c \
MAKEINFO=makeinfo MAKEINFO=makeinfo
MAKEINFOINCLUDES= -I docs -I $(<D) -I $(@D) MAKEINFOINCLUDES= -I docs -I $(<D) -I $(@D)
MAKEINFOFLAGS=--no-split --number-sections $(MAKEINFOINCLUDES) MAKEINFOFLAGS=--no-split --number-sections $(MAKEINFOINCLUDES)
TEXI2PODFLAGS=$(MAKEINFOINCLUDES) -DVERSION="$(VERSION)" -DCONFDIR="$(qemu_confdir)" TEXI2PODFLAGS=$(MAKEINFOINCLUDES) "-DVERSION=$(VERSION)"
TEXI2PDFFLAGS=$(if $(V),,--quiet) -I $(SRC_PATH) $(MAKEINFOINCLUDES) TEXI2PDFFLAGS=$(if $(V),,--quiet) -I $(SRC_PATH) $(MAKEINFOINCLUDES)
docs/version.texi: $(SRC_PATH)/VERSION config-host.mak docs/version.texi: $(SRC_PATH)/VERSION
$(call quiet-command,(\ $(call quiet-command,echo "@set VERSION $(VERSION)" > $@,"GEN","$@")
echo "@set VERSION $(VERSION)" && \
echo "@set CONFDIR $(qemu_confdir)" \
)> $@,"GEN","$@")
%.html: %.texi docs/version.texi %.html: %.texi docs/version.texi
$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --no-headers \ $(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --no-headers \
@@ -970,26 +837,6 @@ docs/version.texi: $(SRC_PATH)/VERSION config-host.mak
%.pdf: %.texi docs/version.texi %.pdf: %.texi docs/version.texi
$(call quiet-command,texi2pdf $(TEXI2PDFFLAGS) $< -o $@,"GEN","$@") $(call quiet-command,texi2pdf $(TEXI2PDFFLAGS) $< -o $@,"GEN","$@")
# Sphinx builds all its documentation at once in one invocation
# 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
# Canned command to build a single manual
build-manual = $(call quiet-command,sphinx-build $(if $(V),,-q) -W -n -b html -D version=$(VERSION) -D release="$(FULL_VERSION)" -d .doctrees/$1 $(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/conf.py $(SRC_PATH)/docs/conf.py
$(MANUAL_BUILDDIR)/devel/index.html: $(call manual-deps,devel)
$(call build-manual,devel)
$(MANUAL_BUILDDIR)/interop/index.html: $(call manual-deps,interop)
$(call build-manual,interop)
$(MANUAL_BUILDDIR)/specs/index.html: $(call manual-deps,specs)
$(call build-manual,specs)
qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@") $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
@@ -1018,17 +865,16 @@ docs/qemu-block-drivers.7: docs/qemu-block-drivers.texi
docs/qemu-cpu-models.7: docs/qemu-cpu-models.texi docs/qemu-cpu-models.7: docs/qemu-cpu-models.texi
scripts/qemu-trace-stap.1: scripts/qemu-trace-stap.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 html: qemu-doc.html docs/interop/qemu-qmp-ref.html docs/interop/qemu-ga-ref.html
info: qemu-doc.info docs/interop/qemu-qmp-ref.info docs/interop/qemu-ga-ref.info 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 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 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-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \
qemu-img.texi qemu-nbd.texi qemu-options.texi \ qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
qemu-tech.texi qemu-option-trace.texi \
qemu-deprecated.texi qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \ qemu-deprecated.texi qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \
qemu-monitor-info.texi docs/qemu-block-drivers.texi \ qemu-monitor-info.texi docs/qemu-block-drivers.texi \
docs/qemu-cpu-models.texi docs/security.texi docs/qemu-cpu-models.texi
docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \ docs/interop/qemu-ga-ref.dvi docs/interop/qemu-ga-ref.html \
docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \ docs/interop/qemu-ga-ref.info docs/interop/qemu-ga-ref.pdf \
@@ -1047,10 +893,7 @@ $(filter %.1 %.7 %.8,$(DOCS)): scripts/texi2pod.pl
%/coverage-report.html: %/coverage-report.html:
@mkdir -p $* @mkdir -p $*
$(call quiet-command,\ $(call quiet-command,\
gcovr -r $(SRC_PATH) \ gcovr -p --html --html-details -o $@, \
$(foreach t, $(TARGET_DIRS), --object-directory $(BUILD_DIR)/$(t)) \
--object-directory $(BUILD_DIR) \
-p --html --html-details -o $@, \
"GEN", "coverage-report.html") "GEN", "coverage-report.html")
.PHONY: coverage-report .PHONY: coverage-report
@@ -1078,7 +921,7 @@ installer: $(INSTALLER)
INSTDIR=/tmp/qemu-nsis INSTDIR=/tmp/qemu-nsis
$(INSTALLER): install-doc $(SRC_PATH)/qemu.nsi $(INSTALLER): $(SRC_PATH)/qemu.nsi
$(MAKE) install prefix=${INSTDIR} $(MAKE) install prefix=${INSTDIR}
ifdef SIGNCODE ifdef SIGNCODE
(cd ${INSTDIR}; \ (cd ${INSTDIR}; \
@@ -1116,7 +959,7 @@ endif # CONFIG_WIN
# rebuilt before other object files # rebuilt before other object files
ifneq ($(wildcard config-host.mak),) ifneq ($(wildcard config-host.mak),)
ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail)) ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
Makefile: $(generated-files-y) Makefile: $(GENERATED_FILES)
endif endif
endif endif
@@ -1146,7 +989,7 @@ endif
@$(if $(TARGET_DIRS), \ @$(if $(TARGET_DIRS), \
echo 'Architecture specific targets:'; \ echo 'Architecture specific targets:'; \
$(foreach t, $(TARGET_DIRS), \ $(foreach t, $(TARGET_DIRS), \
printf " %-30s - Build for %s\\n" $(t)/all $(t);) \ printf " %-30s - Build for %s\\n" $(patsubst %,subdir-%,$(t)) $(t);) \
echo '') echo '')
@echo 'Cleaning targets:' @echo 'Cleaning targets:'
@echo ' clean - Remove most generated files but keep the config' @echo ' clean - Remove most generated files but keep the config'
@@ -1159,7 +1002,7 @@ endif
@echo 'Test targets:' @echo 'Test targets:'
@echo ' check - Run all tests (check-help for details)' @echo ' check - Run all tests (check-help for details)'
@echo ' docker - Help about targets running tests inside Docker containers' @echo ' docker - Help about targets running tests inside Docker containers'
@echo ' vm-help - Help about targets running tests inside VM' @echo ' vm-test - Help about targets running tests inside VM'
@echo '' @echo ''
@echo 'Documentation targets:' @echo 'Documentation targets:'
@echo ' html info pdf txt' @echo ' html info pdf txt'

View File

@@ -4,6 +4,7 @@ stub-obj-y = stubs/ util/ crypto/
util-obj-y = util/ qobject/ qapi/ util-obj-y = util/ qobject/ qapi/
chardev-obj-y = chardev/ chardev-obj-y = chardev/
slirp-obj-$(CONFIG_SLIRP) = slirp/
####################################################################### #######################################################################
# authz-obj-y is code used by both qemu system emulation and qemu-img # authz-obj-y is code used by both qemu system emulation and qemu-img
@@ -13,7 +14,7 @@ authz-obj-y = authz/
####################################################################### #######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img # block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y = nbd/ block-obj-y += nbd/
block-obj-y += block.o blockjob.o job.o block-obj-y += block.o blockjob.o job.o
block-obj-y += block/ scsi/ block-obj-y += block/ scsi/
block-obj-y += qemu-io-cmds.o block-obj-y += qemu-io-cmds.o
@@ -25,7 +26,7 @@ block-obj-m = block/
# crypto-obj-y is code used by both qemu system emulation and qemu-img # crypto-obj-y is code used by both qemu system emulation and qemu-img
crypto-obj-y = crypto/ crypto-obj-y = crypto/
crypto-user-obj-y = crypto/ crypto-aes-obj-y = crypto/
####################################################################### #######################################################################
# qom-obj-y is code used by both qemu system emulation and qemu-img # qom-obj-y is code used by both qemu system emulation and qemu-img
@@ -45,9 +46,7 @@ io-obj-y = io/
ifeq ($(CONFIG_SOFTMMU),y) ifeq ($(CONFIG_SOFTMMU),y)
common-obj-y = blockdev.o blockdev-nbd.o block/ common-obj-y = blockdev.o blockdev-nbd.o block/
common-obj-y += bootdevice.o iothread.o common-obj-y += bootdevice.o iothread.o
common-obj-y += dump/
common-obj-y += job-qmp.o common-obj-y += job-qmp.o
common-obj-y += monitor/
common-obj-y += net/ common-obj-y += net/
common-obj-y += qdev-monitor.o device-hotplug.o common-obj-y += qdev-monitor.o device-hotplug.o
common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_WIN32) += os-win32.o
@@ -85,6 +84,7 @@ common-obj-$(CONFIG_FDT) += device_tree.o
###################################################################### ######################################################################
# qapi # qapi
common-obj-y += qmp.o hmp.o
common-obj-y += qapi/ common-obj-y += qapi/
endif endif
@@ -102,6 +102,7 @@ version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o
###################################################################### ######################################################################
# tracing # tracing
util-obj-y += trace/ util-obj-y += trace/
target-obj-y += trace/
###################################################################### ######################################################################
# guest agent # guest agent
@@ -123,28 +124,16 @@ vhost-user-scsi.o-libs := $(LIBISCSI_LIBS)
vhost-user-scsi-obj-y = contrib/vhost-user-scsi/ vhost-user-scsi-obj-y = contrib/vhost-user-scsi/
vhost-user-blk-obj-y = contrib/vhost-user-blk/ vhost-user-blk-obj-y = contrib/vhost-user-blk/
rdmacm-mux-obj-y = contrib/rdmacm-mux/ 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/
###################################################################### ######################################################################
trace-events-subdirs = trace-events-subdirs =
trace-events-subdirs += accel/kvm trace-events-subdirs += accel/kvm
trace-events-subdirs += accel/tcg trace-events-subdirs += accel/tcg
trace-events-subdirs += crypto trace-events-subdirs += audio
trace-events-subdirs += monitor
ifeq ($(CONFIG_USER_ONLY),y)
trace-events-subdirs += linux-user
endif
ifeq ($(CONFIG_BLOCK),y)
trace-events-subdirs += authz trace-events-subdirs += authz
trace-events-subdirs += block trace-events-subdirs += block
trace-events-subdirs += io
trace-events-subdirs += nbd
trace-events-subdirs += scsi
endif
ifeq ($(CONFIG_SOFTMMU),y)
trace-events-subdirs += chardev trace-events-subdirs += chardev
trace-events-subdirs += audio trace-events-subdirs += crypto
trace-events-subdirs += hw/9pfs trace-events-subdirs += hw/9pfs
trace-events-subdirs += hw/acpi trace-events-subdirs += hw/acpi
trace-events-subdirs += hw/alpha trace-events-subdirs += hw/alpha
@@ -153,6 +142,7 @@ trace-events-subdirs += hw/audio
trace-events-subdirs += hw/block trace-events-subdirs += hw/block
trace-events-subdirs += hw/block/dataplane trace-events-subdirs += hw/block/dataplane
trace-events-subdirs += hw/char trace-events-subdirs += hw/char
trace-events-subdirs += hw/display
trace-events-subdirs += hw/dma trace-events-subdirs += hw/dma
trace-events-subdirs += hw/hppa trace-events-subdirs += hw/hppa
trace-events-subdirs += hw/i2c trace-events-subdirs += hw/i2c
@@ -163,7 +153,6 @@ trace-events-subdirs += hw/input
trace-events-subdirs += hw/intc trace-events-subdirs += hw/intc
trace-events-subdirs += hw/isa trace-events-subdirs += hw/isa
trace-events-subdirs += hw/mem trace-events-subdirs += hw/mem
trace-events-subdirs += hw/mips
trace-events-subdirs += hw/misc trace-events-subdirs += hw/misc
trace-events-subdirs += hw/misc/macio trace-events-subdirs += hw/misc/macio
trace-events-subdirs += hw/net trace-events-subdirs += hw/net
@@ -186,22 +175,21 @@ trace-events-subdirs += hw/virtio
trace-events-subdirs += hw/watchdog trace-events-subdirs += hw/watchdog
trace-events-subdirs += hw/xen trace-events-subdirs += hw/xen
trace-events-subdirs += hw/gpio trace-events-subdirs += hw/gpio
trace-events-subdirs += hw/riscv trace-events-subdirs += io
trace-events-subdirs += linux-user
trace-events-subdirs += migration trace-events-subdirs += migration
trace-events-subdirs += nbd
trace-events-subdirs += net trace-events-subdirs += net
trace-events-subdirs += ui
endif
trace-events-subdirs += hw/display
trace-events-subdirs += qapi trace-events-subdirs += qapi
trace-events-subdirs += qom trace-events-subdirs += qom
trace-events-subdirs += scsi
trace-events-subdirs += target/arm trace-events-subdirs += target/arm
trace-events-subdirs += target/hppa
trace-events-subdirs += target/i386 trace-events-subdirs += target/i386
trace-events-subdirs += target/mips trace-events-subdirs += target/mips
trace-events-subdirs += target/ppc trace-events-subdirs += target/ppc
trace-events-subdirs += target/riscv
trace-events-subdirs += target/s390x trace-events-subdirs += target/s390x
trace-events-subdirs += target/sparc trace-events-subdirs += target/sparc
trace-events-subdirs += ui
trace-events-subdirs += util trace-events-subdirs += util
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events) trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)

View File

@@ -4,11 +4,8 @@ BUILD_DIR?=$(CURDIR)/..
include ../config-host.mak include ../config-host.mak
include config-target.mak include config-target.mak
include $(SRC_PATH)/rules.mak
ifdef CONFIG_SOFTMMU
include config-devices.mak include config-devices.mak
endif include $(SRC_PATH)/rules.mak
$(call set-vpath, $(SRC_PATH):$(BUILD_DIR)) $(call set-vpath, $(SRC_PATH):$(BUILD_DIR))
ifdef CONFIG_LINUX ifdef CONFIG_LINUX
@@ -40,14 +37,13 @@ PROGS=$(QEMU_PROG) $(QEMU_PROGW)
STPFILES= STPFILES=
# Makefile Tests # Makefile Tests
ifdef CONFIG_USER_ONLY
include $(SRC_PATH)/tests/tcg/Makefile.include include $(SRC_PATH)/tests/tcg/Makefile.include
endif
config-target.h: config-target.h-timestamp config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak config-target.h-timestamp: config-target.mak
config-devices.h: config-devices.h-timestamp
config-devices.h-timestamp: config-devices.mak
ifdef CONFIG_TRACE_SYSTEMTAP ifdef CONFIG_TRACE_SYSTEMTAP
stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp $(QEMU_PROG)-simpletrace.stp $(QEMU_PROG)-log.stp stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp $(QEMU_PROG)-simpletrace.stp $(QEMU_PROG)-log.stp
@@ -106,8 +102,6 @@ all: $(PROGS) stap
# Dummy command so that make thinks it has done something # Dummy command so that make thinks it has done something
@true @true
obj-y += trace/
######################################################### #########################################################
# cpu emulator library # cpu emulator library
obj-y += exec.o obj-y += exec.o
@@ -120,7 +114,6 @@ obj-$(CONFIG_TCG) += fpu/softfloat.o
obj-y += target/$(TARGET_BASE_ARCH)/ obj-y += target/$(TARGET_BASE_ARCH)/
obj-y += disas.o obj-y += disas.o
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
LIBS := $(libs_cpu) $(LIBS)
######################################################### #########################################################
# Linux user emulator target # Linux user emulator target
@@ -152,14 +145,14 @@ endif #CONFIG_BSD_USER
######################################################### #########################################################
# System emulator target # System emulator target
ifdef CONFIG_SOFTMMU ifdef CONFIG_SOFTMMU
obj-y += arch_init.o cpus.o gdbstub.o balloon.o ioport.o obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
obj-y += qtest.o obj-y += qtest.o
obj-y += dump/
obj-y += hw/ obj-y += hw/
obj-y += monitor/
obj-y += qapi/ obj-y += qapi/
obj-y += memory.o obj-y += memory.o
obj-y += memory_mapping.o obj-y += memory_mapping.o
obj-y += dump.o
obj-$(TARGET_X86_64) += win_dump.o
obj-y += migration/ram.o obj-y += migration/ram.o
LIBS := $(libs_softmmu) $(LIBS) LIBS := $(libs_softmmu) $(LIBS)
@@ -170,37 +163,45 @@ else
obj-y += hw/$(TARGET_BASE_ARCH)/ obj-y += hw/$(TARGET_BASE_ARCH)/
endif endif
generated-files-y += hmp-commands.h hmp-commands-info.h GENERATED_FILES += hmp-commands.h hmp-commands-info.h
generated-files-y += config-devices.h
endif # CONFIG_SOFTMMU endif # CONFIG_SOFTMMU
dummy := $(call unnest-vars,,obj-y) dummy := $(call unnest-vars,,obj-y)
all-obj-y := $(obj-y) all-obj-y := $(obj-y)
target-obj-y :=
block-obj-y :=
common-obj-y :=
chardev-obj-y :=
slirp-obj-y :=
include $(SRC_PATH)/Makefile.objs include $(SRC_PATH)/Makefile.objs
dummy := $(call unnest-vars,,target-obj-y)
target-obj-y-save := $(target-obj-y)
dummy := $(call unnest-vars,.., \ dummy := $(call unnest-vars,.., \
authz-obj-y \ authz-obj-y \
block-obj-y \ block-obj-y \
block-obj-m \ block-obj-m \
chardev-obj-y \ chardev-obj-y \
crypto-obj-y \ crypto-obj-y \
crypto-user-obj-y \ crypto-aes-obj-y \
qom-obj-y \ qom-obj-y \
io-obj-y \ io-obj-y \
common-obj-y \ common-obj-y \
common-obj-m) common-obj-m \
slirp-obj-y)
target-obj-y := $(target-obj-y-save)
all-obj-y += $(common-obj-y) all-obj-y += $(common-obj-y)
all-obj-y += $(target-obj-y)
all-obj-y += $(qom-obj-y) all-obj-y += $(qom-obj-y)
all-obj-$(CONFIG_SOFTMMU) += $(authz-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(authz-obj-y)
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y)
all-obj-$(CONFIG_USER_ONLY) += $(crypto-user-obj-y) all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y)
all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
all-obj-$(CONFIG_SOFTMMU) += $(slirp-obj-y)
ifdef CONFIG_SOFTMMU
$(QEMU_PROG_BUILD): config-devices.mak $(QEMU_PROG_BUILD): config-devices.mak
endif
COMMON_LDADDS = ../libqemuutil.a COMMON_LDADDS = ../libqemuutil.a
@@ -225,7 +226,6 @@ clean: clean-target
rm -f *.a *~ $(PROGS) rm -f *.a *~ $(PROGS)
rm -f $(shell find . -name '*.[od]') rm -f $(shell find . -name '*.[od]')
rm -f hmp-commands.h gdbstub-xml.c rm -f hmp-commands.h gdbstub-xml.c
rm -f trace/generated-helpers.c trace/generated-helpers.c-timestamp
ifdef CONFIG_TRACE_SYSTEMTAP ifdef CONFIG_TRACE_SYSTEMTAP
rm -f *.stp rm -f *.stp
endif endif
@@ -241,21 +241,5 @@ ifdef CONFIG_TRACE_SYSTEMTAP
$(INSTALL_DATA) $(QEMU_PROG)-log.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-log.stp" $(INSTALL_DATA) $(QEMU_PROG)-log.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-log.stp"
endif endif
generated-files-y += config-target.h GENERATED_FILES += config-target.h
Makefile: $(generated-files-y) Makefile: $(GENERATED_FILES)
# Reports/Analysis
#
# The target specific coverage report only cares about target specific
# blobs and not the shared code.
#
%/coverage-report.html:
@mkdir -p $*
$(call quiet-command,\
gcovr -r $(SRC_PATH) --object-directory $(CURDIR) \
-p --html --html-details -o $@, \
"GEN", "coverage-report.html")
.PHONY: coverage-report
coverage-report: $(CURDIR)/reports/coverage/coverage-report.html

View File

@@ -1 +1 @@
4.1.1 3.1.50

View File

@@ -1,5 +1,4 @@
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_KVM) += kvm/
obj-$(CONFIG_TCG) += tcg/ obj-$(CONFIG_TCG) += tcg/
obj-y += stubs/ obj-y += stubs/

View File

@@ -65,8 +65,6 @@ static int accel_init_machine(AccelClass *acc, MachineState *ms)
ms->accelerator = NULL; ms->accelerator = NULL;
*(acc->allowed) = false; *(acc->allowed) = false;
object_unref(OBJECT(accel)); object_unref(OBJECT(accel));
} else {
object_set_accelerator_compat_props(acc->compat_props);
} }
return ret; return ret;
} }
@@ -93,9 +91,7 @@ void configure_accelerator(MachineState *ms, const char *progname)
#elif defined(CONFIG_KVM) #elif defined(CONFIG_KVM)
accel = "kvm"; accel = "kvm";
#else #else
error_report("No accelerator selected and" #error "No default accelerator available"
" no default accelerator available");
exit(1);
#endif #endif
} }
} }
@@ -107,6 +103,11 @@ void configure_accelerator(MachineState *ms, const char *progname)
if (!acc) { if (!acc) {
continue; continue;
} }
if (acc->available && !acc->available()) {
printf("%s not supported for this target\n",
acc->name);
continue;
}
ret = accel_init_machine(acc, ms); ret = accel_init_machine(acc, ms);
if (ret < 0) { if (ret < 0) {
init_failed = true; init_failed = true;

View File

@@ -18,6 +18,7 @@
#include <linux/kvm.h> #include <linux/kvm.h>
#include "qemu-common.h"
#include "qemu/atomic.h" #include "qemu/atomic.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "qemu/config-file.h" #include "qemu/config-file.h"
@@ -87,11 +88,9 @@ struct KVMState
#ifdef KVM_CAP_SET_GUEST_DEBUG #ifdef KVM_CAP_SET_GUEST_DEBUG
QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints; QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints;
#endif #endif
int max_nested_state_len;
int many_ioeventfds; int many_ioeventfds;
int intx_set_mask; int intx_set_mask;
bool sync_mmu; bool sync_mmu;
bool manual_dirty_log_protect;
/* The man page (and posix) say ioctl numbers are signed int, but /* The man page (and posix) say ioctl numbers are signed int, but
* they're not. Linux, glibc and *BSD all treat ioctl numbers as * they're not. Linux, glibc and *BSD all treat ioctl numbers as
* unsigned, and treating them as signed here can break things */ * unsigned, and treating them as signed here can break things */
@@ -111,13 +110,6 @@ struct KVMState
/* memory encryption */ /* memory encryption */
void *memcrypt_handle; void *memcrypt_handle;
int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len); int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
/* For "info mtree -f" to tell if an MR is registered in KVM */
int nr_as;
struct KVMAs {
KVMMemoryListener *ml;
AddressSpace *as;
} *as;
}; };
KVMState *kvm_state; KVMState *kvm_state;
@@ -146,9 +138,6 @@ static const KVMCapabilityInfo kvm_required_capabilites[] = {
KVM_CAP_LAST_INFO KVM_CAP_LAST_INFO
}; };
#define kvm_slots_lock(kml) qemu_mutex_lock(&(kml)->slots_lock)
#define kvm_slots_unlock(kml) qemu_mutex_unlock(&(kml)->slots_lock)
int kvm_get_max_memslots(void) int kvm_get_max_memslots(void)
{ {
KVMState *s = KVM_STATE(current_machine->accelerator); KVMState *s = KVM_STATE(current_machine->accelerator);
@@ -176,7 +165,6 @@ int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
return 1; return 1;
} }
/* Called with KVMMemoryListener.slots_lock held */
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml) static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
{ {
KVMState *s = kvm_state; KVMState *s = kvm_state;
@@ -194,17 +182,10 @@ static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
bool kvm_has_free_slot(MachineState *ms) bool kvm_has_free_slot(MachineState *ms)
{ {
KVMState *s = KVM_STATE(ms->accelerator); KVMState *s = KVM_STATE(ms->accelerator);
bool result;
KVMMemoryListener *kml = &s->memory_listener;
kvm_slots_lock(kml); return kvm_get_free_slot(&s->memory_listener);
result = !!kvm_get_free_slot(kml);
kvm_slots_unlock(kml);
return result;
} }
/* Called with KVMMemoryListener.slots_lock held */
static KVMSlot *kvm_alloc_slot(KVMMemoryListener *kml) static KVMSlot *kvm_alloc_slot(KVMMemoryListener *kml)
{ {
KVMSlot *slot = kvm_get_free_slot(kml); KVMSlot *slot = kvm_get_free_slot(kml);
@@ -263,21 +244,18 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
hwaddr *phys_addr) hwaddr *phys_addr)
{ {
KVMMemoryListener *kml = &s->memory_listener; KVMMemoryListener *kml = &s->memory_listener;
int i, ret = 0; int i;
kvm_slots_lock(kml);
for (i = 0; i < s->nr_slots; i++) { for (i = 0; i < s->nr_slots; i++) {
KVMSlot *mem = &kml->slots[i]; KVMSlot *mem = &kml->slots[i];
if (ram >= mem->ram && ram < mem->ram + mem->memory_size) { if (ram >= mem->ram && ram < mem->ram + mem->memory_size) {
*phys_addr = mem->start_addr + (ram - mem->ram); *phys_addr = mem->start_addr + (ram - mem->ram);
ret = 1; return 1;
break;
} }
} }
kvm_slots_unlock(kml);
return ret; return 0;
} }
static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, bool new) static int kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot, bool new)
@@ -314,11 +292,6 @@ int kvm_destroy_vcpu(CPUState *cpu)
DPRINTF("kvm_destroy_vcpu\n"); DPRINTF("kvm_destroy_vcpu\n");
ret = kvm_arch_destroy_vcpu(cpu);
if (ret < 0) {
goto err;
}
mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
if (mmap_size < 0) { if (mmap_size < 0) {
ret = mmap_size; ret = mmap_size;
@@ -418,7 +391,6 @@ static int kvm_mem_flags(MemoryRegion *mr)
return flags; return flags;
} }
/* Called with KVMMemoryListener.slots_lock held */
static int kvm_slot_update_flags(KVMMemoryListener *kml, KVMSlot *mem, static int kvm_slot_update_flags(KVMMemoryListener *kml, KVMSlot *mem,
MemoryRegion *mr) MemoryRegion *mr)
{ {
@@ -437,26 +409,19 @@ static int kvm_section_update_flags(KVMMemoryListener *kml,
{ {
hwaddr start_addr, size; hwaddr start_addr, size;
KVMSlot *mem; KVMSlot *mem;
int ret = 0;
size = kvm_align_section(section, &start_addr); size = kvm_align_section(section, &start_addr);
if (!size) { if (!size) {
return 0; return 0;
} }
kvm_slots_lock(kml);
mem = kvm_lookup_matching_slot(kml, start_addr, size); mem = kvm_lookup_matching_slot(kml, start_addr, size);
if (!mem) { if (!mem) {
/* We don't have a slot if we want to trap every access. */ /* We don't have a slot if we want to trap every access. */
goto out; return 0;
} }
ret = kvm_slot_update_flags(kml, mem, section->mr); return kvm_slot_update_flags(kml, mem, section->mr);
out:
kvm_slots_unlock(kml);
return ret;
} }
static void kvm_log_start(MemoryListener *listener, static void kvm_log_start(MemoryListener *listener,
@@ -508,15 +473,13 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
#define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1)) #define ALIGN(x, y) (((x)+(y)-1) & ~((y)-1))
/** /**
* kvm_physical_sync_dirty_bitmap - Sync dirty bitmap from kernel space * kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
* This function updates qemu's dirty bitmap using
* memory_region_set_dirty(). This means all bits are set
* to dirty.
* *
* This function will first try to fetch dirty bitmap from the kernel, * @start_add: start of logged region.
* and then updates qemu's dirty bitmap. * @end_addr: end of logged region.
*
* NOTE: caller must be with kml->slots_lock held.
*
* @kml: the KVM memory listener object
* @section: the memory section to sync the dirty bitmap with
*/ */
static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
MemoryRegionSection *section) MemoryRegionSection *section)
@@ -525,14 +488,13 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
struct kvm_dirty_log d = {}; struct kvm_dirty_log d = {};
KVMSlot *mem; KVMSlot *mem;
hwaddr start_addr, size; hwaddr start_addr, size;
int ret = 0;
size = kvm_align_section(section, &start_addr); size = kvm_align_section(section, &start_addr);
if (size) { if (size) {
mem = kvm_lookup_matching_slot(kml, start_addr, size); mem = kvm_lookup_matching_slot(kml, start_addr, size);
if (!mem) { if (!mem) {
/* We don't have a slot if we want to trap every access. */ /* We don't have a slot if we want to trap every access. */
goto out; return 0;
} }
/* XXX bad kernel interface alert /* XXX bad kernel interface alert
@@ -549,176 +511,20 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
*/ */
size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
/*HOST_LONG_BITS*/ 64) / 8; /*HOST_LONG_BITS*/ 64) / 8;
if (!mem->dirty_bmap) { d.dirty_bitmap = g_malloc0(size);
/* Allocate on the first log_sync, once and for all */
mem->dirty_bmap = g_malloc0(size);
}
d.dirty_bitmap = mem->dirty_bmap;
d.slot = mem->slot | (kml->as_id << 16); d.slot = mem->slot | (kml->as_id << 16);
if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) { if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
DPRINTF("ioctl failed %d\n", errno); DPRINTF("ioctl failed %d\n", errno);
ret = -1; g_free(d.dirty_bitmap);
goto out; return -1;
} }
kvm_get_dirty_pages_log_range(section, d.dirty_bitmap); kvm_get_dirty_pages_log_range(section, d.dirty_bitmap);
} g_free(d.dirty_bitmap);
out:
return ret;
}
/* Alignment requirement for KVM_CLEAR_DIRTY_LOG - 64 pages */
#define KVM_CLEAR_LOG_SHIFT 6
#define KVM_CLEAR_LOG_ALIGN (qemu_real_host_page_size << KVM_CLEAR_LOG_SHIFT)
#define KVM_CLEAR_LOG_MASK (-KVM_CLEAR_LOG_ALIGN)
/**
* kvm_physical_log_clear - Clear the kernel's dirty bitmap for range
*
* NOTE: this will be a no-op if we haven't enabled manual dirty log
* protection in the host kernel because in that case this operation
* will be done within log_sync().
*
* @kml: the kvm memory listener
* @section: the memory range to clear dirty bitmap
*/
static int kvm_physical_log_clear(KVMMemoryListener *kml,
MemoryRegionSection *section)
{
KVMState *s = kvm_state;
struct kvm_clear_dirty_log d;
uint64_t start, end, bmap_start, start_delta, bmap_npages, size;
unsigned long *bmap_clear = NULL, psize = qemu_real_host_page_size;
KVMSlot *mem = NULL;
int ret, i;
if (!s->manual_dirty_log_protect) {
/* No need to do explicit clear */
return 0;
} }
start = section->offset_within_address_space; return 0;
size = int128_get64(section->size);
if (!size) {
/* Nothing more we can do... */
return 0;
}
kvm_slots_lock(kml);
/* Find any possible slot that covers the section */
for (i = 0; i < s->nr_slots; i++) {
mem = &kml->slots[i];
if (mem->start_addr <= start &&
start + size <= mem->start_addr + mem->memory_size) {
break;
}
}
/*
* We should always find one memslot until this point, otherwise
* there could be something wrong from the upper layer
*/
assert(mem && i != s->nr_slots);
/*
* We need to extend either the start or the size or both to
* satisfy the KVM interface requirement. Firstly, do the start
* page alignment on 64 host pages
*/
bmap_start = (start - mem->start_addr) & KVM_CLEAR_LOG_MASK;
start_delta = start - mem->start_addr - bmap_start;
bmap_start /= psize;
/*
* The kernel interface has restriction on the size too, that either:
*
* (1) the size is 64 host pages aligned (just like the start), or
* (2) the size fills up until the end of the KVM memslot.
*/
bmap_npages = DIV_ROUND_UP(size + start_delta, KVM_CLEAR_LOG_ALIGN)
<< KVM_CLEAR_LOG_SHIFT;
end = mem->memory_size / psize;
if (bmap_npages > end - bmap_start) {
bmap_npages = end - bmap_start;
}
start_delta /= psize;
/*
* Prepare the bitmap to clear dirty bits. Here we must guarantee
* that we won't clear any unknown dirty bits otherwise we might
* accidentally clear some set bits which are not yet synced from
* the kernel into QEMU's bitmap, then we'll lose track of the
* guest modifications upon those pages (which can directly lead
* to guest data loss or panic after migration).
*
* Layout of the KVMSlot.dirty_bmap:
*
* |<-------- bmap_npages -----------..>|
* [1]
* start_delta size
* |----------------|-------------|------------------|------------|
* ^ ^ ^ ^
* | | | |
* start bmap_start (start) end
* of memslot of memslot
*
* [1] bmap_npages can be aligned to either 64 pages or the end of slot
*/
assert(bmap_start % BITS_PER_LONG == 0);
/* We should never do log_clear before log_sync */
assert(mem->dirty_bmap);
if (start_delta) {
/* Slow path - we need to manipulate a temp bitmap */
bmap_clear = bitmap_new(bmap_npages);
bitmap_copy_with_src_offset(bmap_clear, mem->dirty_bmap,
bmap_start, start_delta + size / psize);
/*
* We need to fill the holes at start because that was not
* specified by the caller and we extended the bitmap only for
* 64 pages alignment
*/
bitmap_clear(bmap_clear, 0, start_delta);
d.dirty_bitmap = bmap_clear;
} else {
/* Fast path - start address aligns well with BITS_PER_LONG */
d.dirty_bitmap = mem->dirty_bmap + BIT_WORD(bmap_start);
}
d.first_page = bmap_start;
/* It should never overflow. If it happens, say something */
assert(bmap_npages <= UINT32_MAX);
d.num_pages = bmap_npages;
d.slot = mem->slot | (kml->as_id << 16);
if (kvm_vm_ioctl(s, KVM_CLEAR_DIRTY_LOG, &d) == -1) {
ret = -errno;
error_report("%s: KVM_CLEAR_DIRTY_LOG failed, slot=%d, "
"start=0x%"PRIx64", size=0x%"PRIx32", errno=%d",
__func__, d.slot, (uint64_t)d.first_page,
(uint32_t)d.num_pages, ret);
} else {
ret = 0;
trace_kvm_clear_dirty_log(d.slot, d.first_page, d.num_pages);
}
/*
* After we have updated the remote dirty bitmap, we update the
* cached bitmap as well for the memslot, then if another user
* clears the same region we know we shouldn't clear it again on
* the remote otherwise it's data loss as well.
*/
bitmap_clear(mem->dirty_bmap, bmap_start + start_delta,
size / psize);
/* This handles the NULL case well */
g_free(bmap_clear);
kvm_slots_unlock(kml);
return ret;
} }
static void kvm_coalesce_mmio_region(MemoryListener *listener, static void kvm_coalesce_mmio_region(MemoryListener *listener,
@@ -980,20 +786,16 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
ram = memory_region_get_ram_ptr(mr) + section->offset_within_region + ram = memory_region_get_ram_ptr(mr) + section->offset_within_region +
(start_addr - section->offset_within_address_space); (start_addr - section->offset_within_address_space);
kvm_slots_lock(kml);
if (!add) { if (!add) {
mem = kvm_lookup_matching_slot(kml, start_addr, size); mem = kvm_lookup_matching_slot(kml, start_addr, size);
if (!mem) { if (!mem) {
goto out; return;
} }
if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
kvm_physical_sync_dirty_bitmap(kml, section); kvm_physical_sync_dirty_bitmap(kml, section);
} }
/* unregister the slot */ /* unregister the slot */
g_free(mem->dirty_bmap);
mem->dirty_bmap = NULL;
mem->memory_size = 0; mem->memory_size = 0;
mem->flags = 0; mem->flags = 0;
err = kvm_set_user_memory_region(kml, mem, false); err = kvm_set_user_memory_region(kml, mem, false);
@@ -1002,7 +804,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
__func__, strerror(-err)); __func__, strerror(-err));
abort(); abort();
} }
goto out; return;
} }
/* register the new slot */ /* register the new slot */
@@ -1018,9 +820,6 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
strerror(-err)); strerror(-err));
abort(); abort();
} }
out:
kvm_slots_unlock(kml);
} }
static void kvm_region_add(MemoryListener *listener, static void kvm_region_add(MemoryListener *listener,
@@ -1047,30 +846,12 @@ static void kvm_log_sync(MemoryListener *listener,
KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener); KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener);
int r; int r;
kvm_slots_lock(kml);
r = kvm_physical_sync_dirty_bitmap(kml, section); r = kvm_physical_sync_dirty_bitmap(kml, section);
kvm_slots_unlock(kml);
if (r < 0) { if (r < 0) {
abort(); abort();
} }
} }
static void kvm_log_clear(MemoryListener *listener,
MemoryRegionSection *section)
{
KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener);
int r;
r = kvm_physical_log_clear(kml, section);
if (r < 0) {
error_report_once("%s: kvm log clear failed: mr=%s "
"offset=%"HWADDR_PRIx" size=%"PRIx64, __func__,
section->mr->name, section->offset_within_region,
int128_get64(section->size));
abort();
}
}
static void kvm_mem_ioeventfd_add(MemoryListener *listener, static void kvm_mem_ioeventfd_add(MemoryListener *listener,
MemoryRegionSection *section, MemoryRegionSection *section,
bool match_data, uint64_t data, bool match_data, uint64_t data,
@@ -1083,8 +864,8 @@ static void kvm_mem_ioeventfd_add(MemoryListener *listener,
data, true, int128_get64(section->size), data, true, int128_get64(section->size),
match_data); match_data);
if (r < 0) { if (r < 0) {
fprintf(stderr, "%s: error adding ioeventfd: %s (%d)\n", fprintf(stderr, "%s: error adding ioeventfd: %s\n",
__func__, strerror(-r), -r); __func__, strerror(-r));
abort(); abort();
} }
} }
@@ -1101,8 +882,6 @@ static void kvm_mem_ioeventfd_del(MemoryListener *listener,
data, false, int128_get64(section->size), data, false, int128_get64(section->size),
match_data); match_data);
if (r < 0) { if (r < 0) {
fprintf(stderr, "%s: error deleting ioeventfd: %s (%d)\n",
__func__, strerror(-r), -r);
abort(); abort();
} }
} }
@@ -1119,8 +898,8 @@ static void kvm_io_ioeventfd_add(MemoryListener *listener,
data, true, int128_get64(section->size), data, true, int128_get64(section->size),
match_data); match_data);
if (r < 0) { if (r < 0) {
fprintf(stderr, "%s: error adding ioeventfd: %s (%d)\n", fprintf(stderr, "%s: error adding ioeventfd: %s\n",
__func__, strerror(-r), -r); __func__, strerror(-r));
abort(); abort();
} }
} }
@@ -1138,8 +917,6 @@ static void kvm_io_ioeventfd_del(MemoryListener *listener,
data, false, int128_get64(section->size), data, false, int128_get64(section->size),
match_data); match_data);
if (r < 0) { if (r < 0) {
fprintf(stderr, "%s: error deleting ioeventfd: %s (%d)\n",
__func__, strerror(-r), -r);
abort(); abort();
} }
} }
@@ -1149,7 +926,6 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
{ {
int i; int i;
qemu_mutex_init(&kml->slots_lock);
kml->slots = g_malloc0(s->nr_slots * sizeof(KVMSlot)); kml->slots = g_malloc0(s->nr_slots * sizeof(KVMSlot));
kml->as_id = as_id; kml->as_id = as_id;
@@ -1162,18 +938,9 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
kml->listener.log_start = kvm_log_start; kml->listener.log_start = kvm_log_start;
kml->listener.log_stop = kvm_log_stop; kml->listener.log_stop = kvm_log_stop;
kml->listener.log_sync = kvm_log_sync; kml->listener.log_sync = kvm_log_sync;
kml->listener.log_clear = kvm_log_clear;
kml->listener.priority = 10; kml->listener.priority = 10;
memory_listener_register(&kml->listener, as); memory_listener_register(&kml->listener, as);
for (i = 0; i < s->nr_as; ++i) {
if (!s->as[i].as) {
s->as[i].as = as;
s->as[i].ml = kml;
break;
}
}
} }
static MemoryListener kvm_io_listener = { static MemoryListener kvm_io_listener = {
@@ -1766,8 +1533,8 @@ static int kvm_init(MachineState *ms)
const char *name; const char *name;
int num; int num;
} num_cpus[] = { } num_cpus[] = {
{ "SMP", ms->smp.cpus }, { "SMP", smp_cpus },
{ "hotpluggable", ms->smp.max_cpus }, { "hotpluggable", max_cpus },
{ NULL, } { NULL, }
}, *nc = num_cpus; }, *nc = num_cpus;
int soft_vcpus_limit, hard_vcpus_limit; int soft_vcpus_limit, hard_vcpus_limit;
@@ -1824,15 +1591,9 @@ static int kvm_init(MachineState *ms)
s->nr_slots = 32; s->nr_slots = 32;
} }
s->nr_as = kvm_check_extension(s, KVM_CAP_MULTI_ADDRESS_SPACE);
if (s->nr_as <= 1) {
s->nr_as = 1;
}
s->as = g_new0(struct KVMAs, s->nr_as);
kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type"); kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type");
if (mc->kvm_type) { if (mc->kvm_type) {
type = mc->kvm_type(ms, kvm_type); type = mc->kvm_type(kvm_type);
} else if (kvm_type) { } else if (kvm_type) {
ret = -EINVAL; ret = -EINVAL;
fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type); fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type);
@@ -1901,17 +1662,6 @@ static int kvm_init(MachineState *ms)
s->coalesced_pio = s->coalesced_mmio && s->coalesced_pio = s->coalesced_mmio &&
kvm_check_extension(s, KVM_CAP_COALESCED_PIO); kvm_check_extension(s, KVM_CAP_COALESCED_PIO);
s->manual_dirty_log_protect =
kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
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 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 "
"but failed. Falling back to the legacy mode. ");
s->manual_dirty_log_protect = false;
}
}
#ifdef KVM_CAP_VCPU_EVENTS #ifdef KVM_CAP_VCPU_EVENTS
s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS); s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS);
#endif #endif
@@ -1923,8 +1673,6 @@ static int kvm_init(MachineState *ms)
s->debugregs = kvm_check_extension(s, KVM_CAP_DEBUGREGS); s->debugregs = kvm_check_extension(s, KVM_CAP_DEBUGREGS);
#endif #endif
s->max_nested_state_len = kvm_check_extension(s, KVM_CAP_NESTED_STATE);
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
kvm_direct_msi_allowed = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0); kvm_direct_msi_allowed = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0);
#endif #endif
@@ -2050,7 +1798,7 @@ static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run)
if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) { if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
fprintf(stderr, "emulation failure\n"); fprintf(stderr, "emulation failure\n");
if (!kvm_arch_stop_on_emulation_error(cpu)) { if (!kvm_arch_stop_on_emulation_error(cpu)) {
cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); cpu_dump_state(cpu, stderr, fprintf, CPU_DUMP_CODE);
return EXCP_INTERRUPT; return EXCP_INTERRUPT;
} }
} }
@@ -2341,7 +2089,7 @@ int kvm_cpu_exec(CPUState *cpu)
qemu_mutex_lock_iothread(); qemu_mutex_lock_iothread();
if (ret < 0) { if (ret < 0) {
cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); cpu_dump_state(cpu, stderr, fprintf, CPU_DUMP_CODE);
vm_stop(RUN_STATE_INTERNAL_ERROR); vm_stop(RUN_STATE_INTERNAL_ERROR);
} }
@@ -2492,11 +2240,6 @@ int kvm_has_debugregs(void)
return kvm_state->debugregs; return kvm_state->debugregs;
} }
int kvm_max_nested_state_length(void)
{
return kvm_state->max_nested_state_len;
}
int kvm_has_many_ioeventfds(void) int kvm_has_many_ioeventfds(void)
{ {
if (!kvm_enabled()) { if (!kvm_enabled()) {
@@ -2524,6 +2267,13 @@ bool kvm_arm_supports_user_irq(void)
return kvm_check_extension(kvm_state, KVM_CAP_ARM_USER_IRQ); return kvm_check_extension(kvm_state, KVM_CAP_ARM_USER_IRQ);
} }
/* Whether the KVM_SET_GUEST_DEBUG ioctl supports single stepping */
int kvm_has_guestdbg_singlestep(void)
{
/* return kvm_check_extension(kvm_state, KVM_CAP_GUEST_DEBUG_SSTEP); */
return 0;
}
#ifdef KVM_CAP_SET_GUEST_DEBUG #ifdef KVM_CAP_SET_GUEST_DEBUG
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu,
target_ulong pc) target_ulong pc)
@@ -2573,6 +2323,15 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
return data.err; return data.err;
} }
void kvm_set_singlestep(CPUState *cs, int enabled)
{
if (kvm_has_guestdbg_singlestep()) {
kvm_update_guest_debug(cs, 0);
} else {
kvm_arch_set_singlestep(cs, enabled);
}
}
int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type) target_ulong len, int type)
{ {
@@ -2849,28 +2608,11 @@ int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target)
return r; return r;
} }
static bool kvm_accel_has_memory(MachineState *ms, AddressSpace *as,
hwaddr start_addr, hwaddr size)
{
KVMState *kvm = KVM_STATE(ms->accelerator);
int i;
for (i = 0; i < kvm->nr_as; ++i) {
if (kvm->as[i].as == as && kvm->as[i].ml) {
return NULL != kvm_lookup_matching_slot(kvm->as[i].ml,
start_addr, size);
}
}
return false;
}
static void kvm_accel_class_init(ObjectClass *oc, void *data) static void kvm_accel_class_init(ObjectClass *oc, void *data)
{ {
AccelClass *ac = ACCEL_CLASS(oc); AccelClass *ac = ACCEL_CLASS(oc);
ac->name = "KVM"; ac->name = "KVM";
ac->init_machine = kvm_init; ac->init_machine = kvm_init;
ac->has_memory = kvm_accel_has_memory;
ac->allowed = &kvm_allowed; ac->allowed = &kvm_allowed;
} }

View File

@@ -1,4 +1,4 @@
# See docs/devel/tracing.txt for syntax documentation. # Trace events for debugging and performance instrumentation
# kvm-all.c # kvm-all.c
kvm_ioctl(int type, void *arg) "type 0x%x, arg %p" kvm_ioctl(int type, void *arg) "type 0x%x, arg %p"
@@ -15,5 +15,4 @@ kvm_irqchip_release_virq(int virq) "virq %d"
kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%" PRIx64 " val=0x%x assign: %d size: %d match: %d" kvm_set_ioeventfd_mmio(int fd, uint64_t addr, uint32_t val, bool assign, uint32_t size, bool datamatch) "fd: %d @0x%" PRIx64 " val=0x%x assign: %d size: %d match: %d"
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_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_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

View File

@@ -1,54 +0,0 @@
/*
* QTest accelerator code
*
* Copyright IBM, Corp. 2011
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.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 "qapi/error.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "sysemu/accel.h"
#include "sysemu/qtest.h"
#include "sysemu/cpus.h"
static int qtest_init_accel(MachineState *ms)
{
QemuOpts *opts = qemu_opts_create(qemu_find_opts("icount"), NULL, 0,
&error_abort);
qemu_opt_set(opts, "shift", "0", &error_abort);
configure_icount(opts, &error_abort);
qemu_opts_del(opts);
return 0;
}
static void qtest_accel_class_init(ObjectClass *oc, void *data)
{
AccelClass *ac = ACCEL_CLASS(oc);
ac->name = "QTest";
ac->init_machine = qtest_init_accel;
ac->allowed = &qtest_allowed;
}
#define TYPE_QTEST_ACCEL ACCEL_CLASS_NAME("qtest")
static const TypeInfo qtest_accel_type = {
.name = TYPE_QTEST_ACCEL,
.parent = TYPE_ACCEL,
.class_init = qtest_accel_class_init,
};
static void qtest_type_init(void)
{
type_register_static(&qtest_accel_type);
}
type_init(qtest_type_init);

View File

@@ -14,6 +14,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
#include "sysemu/hax.h" #include "sysemu/hax.h"

View File

@@ -12,6 +12,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
#include "sysemu/hvf.h" #include "sysemu/hvf.h"

View File

@@ -11,6 +11,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
@@ -78,6 +79,10 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
return -ENOSYS; return -ENOSYS;
} }
void kvm_set_singlestep(CPUState *cs, int enabled)
{
}
int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr, int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
target_ulong len, int type) target_ulong len, int type)
{ {

View File

@@ -9,6 +9,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
#include "sysemu/whpx.h" #include "sysemu/whpx.h"

View File

@@ -62,21 +62,21 @@
#define ATOMIC_TRACE_RMW do { \ #define ATOMIC_TRACE_RMW do { \
uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \ uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
\ \
trace_guest_mem_before_exec(env_cpu(env), addr, info); \ trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \
trace_guest_mem_before_exec(env_cpu(env), addr, \ trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, \
info | TRACE_MEM_ST); \ info | TRACE_MEM_ST); \
} while (0) } while (0)
#define ATOMIC_TRACE_LD do { \ #define ATOMIC_TRACE_LD do { \
uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \ uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
\ \
trace_guest_mem_before_exec(env_cpu(env), addr, info); \ trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \
} while (0) } while (0)
# define ATOMIC_TRACE_ST do { \ # define ATOMIC_TRACE_ST do { \
uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true); \ uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true); \
\ \
trace_guest_mem_before_exec(env_cpu(env), addr, info); \ trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \
} while (0) } while (0)
/* Define host-endian atomic operations. Note that END is used within /* Define host-endian atomic operations. Note that END is used within

View File

@@ -20,7 +20,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "cpu.h" #include "cpu.h"
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "sysemu/tcg.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
bool tcg_allowed; bool tcg_allowed;

View File

@@ -16,9 +16,7 @@
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
#include "trace.h" #include "trace.h"
#include "disas/disas.h" #include "disas/disas.h"
@@ -56,7 +54,7 @@ typedef struct SyncClocks {
#define MAX_DELAY_PRINT_RATE 2000000000LL #define MAX_DELAY_PRINT_RATE 2000000000LL
#define MAX_NB_PRINTS 100 #define MAX_NB_PRINTS 100
static void align_clocks(SyncClocks *sc, CPUState *cpu) static void align_clocks(SyncClocks *sc, const CPUState *cpu)
{ {
int64_t cpu_icount; int64_t cpu_icount;
@@ -64,7 +62,7 @@ static void align_clocks(SyncClocks *sc, CPUState *cpu)
return; return;
} }
cpu_icount = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low; cpu_icount = cpu->icount_extra + cpu->icount_decr.u16.low;
sc->diff_clk += cpu_icount_to_ns(sc->last_cpu_icount - cpu_icount); sc->diff_clk += cpu_icount_to_ns(sc->last_cpu_icount - cpu_icount);
sc->last_cpu_icount = cpu_icount; sc->last_cpu_icount = cpu_icount;
@@ -107,15 +105,15 @@ static void print_delay(const SyncClocks *sc)
} }
} }
static void init_delay_params(SyncClocks *sc, CPUState *cpu) static void init_delay_params(SyncClocks *sc,
const CPUState *cpu)
{ {
if (!icount_align_option) { if (!icount_align_option) {
return; return;
} }
sc->realtime_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); sc->realtime_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT);
sc->diff_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sc->realtime_clock; sc->diff_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sc->realtime_clock;
sc->last_cpu_icount sc->last_cpu_icount = cpu->icount_extra + cpu->icount_decr.u16.low;
= cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low;
if (sc->diff_clk < max_delay) { if (sc->diff_clk < max_delay) {
max_delay = sc->diff_clk; max_delay = sc->diff_clk;
} }
@@ -469,7 +467,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
if (cpu->exception_index < 0) { if (cpu->exception_index < 0) {
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (replay_has_exception() if (replay_has_exception()
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) { && cpu->icount_decr.u16.low + cpu->icount_extra == 0) {
/* try to cause an exception pending in the log */ /* try to cause an exception pending in the log */
cpu_exec_nocache(cpu, 1, tb_find(cpu, NULL, 0, curr_cflags()), true); cpu_exec_nocache(cpu, 1, tb_find(cpu, NULL, 0, curr_cflags()), true);
} }
@@ -527,7 +525,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
* Ensure zeroing happens before reading cpu->exit_request or * Ensure zeroing happens before reading cpu->exit_request or
* cpu->interrupt_request (see also smp_wmb in cpu_exit()) * cpu->interrupt_request (see also smp_wmb in cpu_exit())
*/ */
atomic_mb_set(&cpu_neg(cpu)->icount_decr.u16.high, 0); atomic_mb_set(&cpu->icount_decr.u16.high, 0);
if (unlikely(atomic_read(&cpu->interrupt_request))) { if (unlikely(atomic_read(&cpu->interrupt_request))) {
int interrupt_request; int interrupt_request;
@@ -598,9 +596,8 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
} }
/* Finally, check if we need to exit to the main loop. */ /* Finally, check if we need to exit to the main loop. */
if (unlikely(atomic_read(&cpu->exit_request)) if (unlikely(atomic_read(&cpu->exit_request)
|| (use_icount || (use_icount && cpu->icount_decr.u16.low + cpu->icount_extra == 0))) {
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0)) {
atomic_set(&cpu->exit_request, 0); atomic_set(&cpu->exit_request, 0);
if (cpu->exception_index == -1) { if (cpu->exception_index == -1) {
cpu->exception_index = EXCP_INTERRUPT; cpu->exception_index = EXCP_INTERRUPT;
@@ -627,7 +624,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
} }
*last_tb = NULL; *last_tb = NULL;
insns_left = atomic_read(&cpu_neg(cpu)->icount_decr.u32); insns_left = atomic_read(&cpu->icount_decr.u32);
if (insns_left < 0) { if (insns_left < 0) {
/* Something asked us to stop executing chained TBs; just /* Something asked us to stop executing chained TBs; just
* continue round the main loop. Whatever requested the exit * continue round the main loop. Whatever requested the exit
@@ -646,7 +643,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
cpu_update_icount(cpu); cpu_update_icount(cpu);
/* Refill decrementer and continue execution. */ /* Refill decrementer and continue execution. */
insns_left = MIN(0xffff, cpu->icount_budget); insns_left = MIN(0xffff, cpu->icount_budget);
cpu_neg(cpu)->icount_decr.u16.low = insns_left; cpu->icount_decr.u16.low = insns_left;
cpu->icount_extra = cpu->icount_budget - insns_left; cpu->icount_extra = cpu->icount_budget - insns_left;
if (!cpu->icount_extra) { if (!cpu->icount_extra) {
/* Execute any remaining instructions, then let the main loop /* Execute any remaining instructions, then let the main loop

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,454 @@
/*
* Software MMU support
*
* Generate helpers used by TCG for qemu_ld/st ops and code load
* functions.
*
* Included from target op helpers and exec.c.
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#if DATA_SIZE == 8
#define SUFFIX q
#define LSUFFIX q
#define SDATA_TYPE int64_t
#define DATA_TYPE uint64_t
#elif DATA_SIZE == 4
#define SUFFIX l
#define LSUFFIX l
#define SDATA_TYPE int32_t
#define DATA_TYPE uint32_t
#elif DATA_SIZE == 2
#define SUFFIX w
#define LSUFFIX uw
#define SDATA_TYPE int16_t
#define DATA_TYPE uint16_t
#elif DATA_SIZE == 1
#define SUFFIX b
#define LSUFFIX ub
#define SDATA_TYPE int8_t
#define DATA_TYPE uint8_t
#else
#error unsupported data size
#endif
/* For the benefit of TCG generated code, we want to avoid the complication
of ABI-specific return type promotion and always return a value extended
to the register size of the host. This is tcg_target_long, except in the
case of a 32-bit host and 64-bit data, and for that we always have
uint64_t. Don't bother with this widened value for SOFTMMU_CODE_ACCESS. */
#if defined(SOFTMMU_CODE_ACCESS) || DATA_SIZE == 8
# define WORD_TYPE DATA_TYPE
# define USUFFIX SUFFIX
#else
# define WORD_TYPE tcg_target_ulong
# define USUFFIX glue(u, SUFFIX)
# define SSUFFIX glue(s, SUFFIX)
#endif
#ifdef SOFTMMU_CODE_ACCESS
#define READ_ACCESS_TYPE MMU_INST_FETCH
#define ADDR_READ addr_code
#else
#define READ_ACCESS_TYPE MMU_DATA_LOAD
#define ADDR_READ addr_read
#endif
#if DATA_SIZE == 8
# define BSWAP(X) bswap64(X)
#elif DATA_SIZE == 4
# define BSWAP(X) bswap32(X)
#elif DATA_SIZE == 2
# define BSWAP(X) bswap16(X)
#else
# define BSWAP(X) (X)
#endif
#if DATA_SIZE == 1
# define helper_le_ld_name glue(glue(helper_ret_ld, USUFFIX), MMUSUFFIX)
# define helper_be_ld_name helper_le_ld_name
# define helper_le_lds_name glue(glue(helper_ret_ld, SSUFFIX), MMUSUFFIX)
# define helper_be_lds_name helper_le_lds_name
# define helper_le_st_name glue(glue(helper_ret_st, SUFFIX), MMUSUFFIX)
# define helper_be_st_name helper_le_st_name
#else
# define helper_le_ld_name glue(glue(helper_le_ld, USUFFIX), MMUSUFFIX)
# define helper_be_ld_name glue(glue(helper_be_ld, USUFFIX), MMUSUFFIX)
# define helper_le_lds_name glue(glue(helper_le_ld, SSUFFIX), MMUSUFFIX)
# define helper_be_lds_name glue(glue(helper_be_ld, SSUFFIX), MMUSUFFIX)
# define helper_le_st_name glue(glue(helper_le_st, SUFFIX), MMUSUFFIX)
# define helper_be_st_name glue(glue(helper_be_st, SUFFIX), MMUSUFFIX)
#endif
#ifndef SOFTMMU_CODE_ACCESS
static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env,
size_t mmu_idx, size_t index,
target_ulong addr,
uintptr_t retaddr,
bool recheck,
MMUAccessType access_type)
{
CPUIOTLBEntry *iotlbentry = &env->iotlb[mmu_idx][index];
return io_readx(env, iotlbentry, mmu_idx, addr, retaddr, recheck,
access_type, DATA_SIZE);
}
#endif
WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
uintptr_t mmu_idx = get_mmuidx(oi);
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
target_ulong tlb_addr = entry->ADDR_READ;
unsigned a_bits = get_alignment_bits(get_memop(oi));
uintptr_t haddr;
DATA_TYPE res;
if (addr & ((1 << a_bits) - 1)) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
mmu_idx, retaddr);
}
/* If the TLB entry is for a different page, reload and try again. */
if (!tlb_hit(tlb_addr, addr)) {
if (!VICTIM_TLB_HIT(ADDR_READ, addr)) {
tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, READ_ACCESS_TYPE,
mmu_idx, retaddr);
index = tlb_index(env, mmu_idx, addr);
entry = tlb_entry(env, mmu_idx, addr);
}
tlb_addr = entry->ADDR_READ;
}
/* Handle an IO access. */
if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) {
if ((addr & (DATA_SIZE - 1)) != 0) {
goto do_unaligned_access;
}
/* ??? Note that the io helpers always read data in the target
byte ordering. We should push the LE/BE request down into io. */
res = glue(io_read, SUFFIX)(env, mmu_idx, index, addr, retaddr,
tlb_addr & TLB_RECHECK,
READ_ACCESS_TYPE);
res = TGT_LE(res);
return res;
}
/* Handle slow unaligned access (it spans two pages or IO). */
if (DATA_SIZE > 1
&& unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1
>= TARGET_PAGE_SIZE)) {
target_ulong addr1, addr2;
DATA_TYPE res1, res2;
unsigned shift;
do_unaligned_access:
addr1 = addr & ~(DATA_SIZE - 1);
addr2 = addr1 + DATA_SIZE;
res1 = helper_le_ld_name(env, addr1, oi, retaddr);
res2 = helper_le_ld_name(env, addr2, oi, retaddr);
shift = (addr & (DATA_SIZE - 1)) * 8;
/* Little-endian combine. */
res = (res1 >> shift) | (res2 << ((DATA_SIZE * 8) - shift));
return res;
}
haddr = addr + entry->addend;
#if DATA_SIZE == 1
res = glue(glue(ld, LSUFFIX), _p)((uint8_t *)haddr);
#else
res = glue(glue(ld, LSUFFIX), _le_p)((uint8_t *)haddr);
#endif
return res;
}
#if DATA_SIZE > 1
WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
uintptr_t mmu_idx = get_mmuidx(oi);
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
target_ulong tlb_addr = entry->ADDR_READ;
unsigned a_bits = get_alignment_bits(get_memop(oi));
uintptr_t haddr;
DATA_TYPE res;
if (addr & ((1 << a_bits) - 1)) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, READ_ACCESS_TYPE,
mmu_idx, retaddr);
}
/* If the TLB entry is for a different page, reload and try again. */
if (!tlb_hit(tlb_addr, addr)) {
if (!VICTIM_TLB_HIT(ADDR_READ, addr)) {
tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, READ_ACCESS_TYPE,
mmu_idx, retaddr);
index = tlb_index(env, mmu_idx, addr);
entry = tlb_entry(env, mmu_idx, addr);
}
tlb_addr = entry->ADDR_READ;
}
/* Handle an IO access. */
if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) {
if ((addr & (DATA_SIZE - 1)) != 0) {
goto do_unaligned_access;
}
/* ??? Note that the io helpers always read data in the target
byte ordering. We should push the LE/BE request down into io. */
res = glue(io_read, SUFFIX)(env, mmu_idx, index, addr, retaddr,
tlb_addr & TLB_RECHECK,
READ_ACCESS_TYPE);
res = TGT_BE(res);
return res;
}
/* Handle slow unaligned access (it spans two pages or IO). */
if (DATA_SIZE > 1
&& unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1
>= TARGET_PAGE_SIZE)) {
target_ulong addr1, addr2;
DATA_TYPE res1, res2;
unsigned shift;
do_unaligned_access:
addr1 = addr & ~(DATA_SIZE - 1);
addr2 = addr1 + DATA_SIZE;
res1 = helper_be_ld_name(env, addr1, oi, retaddr);
res2 = helper_be_ld_name(env, addr2, oi, retaddr);
shift = (addr & (DATA_SIZE - 1)) * 8;
/* Big-endian combine. */
res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
return res;
}
haddr = addr + entry->addend;
res = glue(glue(ld, LSUFFIX), _be_p)((uint8_t *)haddr);
return res;
}
#endif /* DATA_SIZE > 1 */
#ifndef SOFTMMU_CODE_ACCESS
/* Provide signed versions of the load routines as well. We can of course
avoid this for 64-bit data, or for 32-bit data on 32-bit host. */
#if DATA_SIZE * 8 < TCG_TARGET_REG_BITS
WORD_TYPE helper_le_lds_name(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
return (SDATA_TYPE)helper_le_ld_name(env, addr, oi, retaddr);
}
# if DATA_SIZE > 1
WORD_TYPE helper_be_lds_name(CPUArchState *env, target_ulong addr,
TCGMemOpIdx oi, uintptr_t retaddr)
{
return (SDATA_TYPE)helper_be_ld_name(env, addr, oi, retaddr);
}
# endif
#endif
static inline void glue(io_write, SUFFIX)(CPUArchState *env,
size_t mmu_idx, size_t index,
DATA_TYPE val,
target_ulong addr,
uintptr_t retaddr,
bool recheck)
{
CPUIOTLBEntry *iotlbentry = &env->iotlb[mmu_idx][index];
return io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr,
recheck, DATA_SIZE);
}
void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
uintptr_t mmu_idx = get_mmuidx(oi);
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
target_ulong tlb_addr = tlb_addr_write(entry);
unsigned a_bits = get_alignment_bits(get_memop(oi));
uintptr_t haddr;
if (addr & ((1 << a_bits) - 1)) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
mmu_idx, retaddr);
}
/* If the TLB entry is for a different page, reload and try again. */
if (!tlb_hit(tlb_addr, addr)) {
if (!VICTIM_TLB_HIT(addr_write, addr)) {
tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, MMU_DATA_STORE,
mmu_idx, retaddr);
index = tlb_index(env, mmu_idx, addr);
entry = tlb_entry(env, mmu_idx, addr);
}
tlb_addr = tlb_addr_write(entry) & ~TLB_INVALID_MASK;
}
/* Handle an IO access. */
if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) {
if ((addr & (DATA_SIZE - 1)) != 0) {
goto do_unaligned_access;
}
/* ??? Note that the io helpers always read data in the target
byte ordering. We should push the LE/BE request down into io. */
val = TGT_LE(val);
glue(io_write, SUFFIX)(env, mmu_idx, index, val, addr,
retaddr, tlb_addr & TLB_RECHECK);
return;
}
/* Handle slow unaligned access (it spans two pages or IO). */
if (DATA_SIZE > 1
&& unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1
>= TARGET_PAGE_SIZE)) {
int i;
target_ulong page2;
CPUTLBEntry *entry2;
do_unaligned_access:
/* Ensure the second page is in the TLB. Note that the first page
is already guaranteed to be filled, and that the second page
cannot evict the first. */
page2 = (addr + DATA_SIZE) & TARGET_PAGE_MASK;
entry2 = tlb_entry(env, mmu_idx, page2);
if (!tlb_hit_page(tlb_addr_write(entry2), page2)
&& !VICTIM_TLB_HIT(addr_write, page2)) {
tlb_fill(ENV_GET_CPU(env), page2, DATA_SIZE, MMU_DATA_STORE,
mmu_idx, retaddr);
}
/* XXX: not efficient, but simple. */
/* This loop must go in the forward direction to avoid issues
with self-modifying code in Windows 64-bit. */
for (i = 0; i < DATA_SIZE; ++i) {
/* Little-endian extract. */
uint8_t val8 = val >> (i * 8);
glue(helper_ret_stb, MMUSUFFIX)(env, addr + i, val8,
oi, retaddr);
}
return;
}
haddr = addr + entry->addend;
#if DATA_SIZE == 1
glue(glue(st, SUFFIX), _p)((uint8_t *)haddr, val);
#else
glue(glue(st, SUFFIX), _le_p)((uint8_t *)haddr, val);
#endif
}
#if DATA_SIZE > 1
void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
TCGMemOpIdx oi, uintptr_t retaddr)
{
uintptr_t mmu_idx = get_mmuidx(oi);
uintptr_t index = tlb_index(env, mmu_idx, addr);
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
target_ulong tlb_addr = tlb_addr_write(entry);
unsigned a_bits = get_alignment_bits(get_memop(oi));
uintptr_t haddr;
if (addr & ((1 << a_bits) - 1)) {
cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE,
mmu_idx, retaddr);
}
/* If the TLB entry is for a different page, reload and try again. */
if (!tlb_hit(tlb_addr, addr)) {
if (!VICTIM_TLB_HIT(addr_write, addr)) {
tlb_fill(ENV_GET_CPU(env), addr, DATA_SIZE, MMU_DATA_STORE,
mmu_idx, retaddr);
index = tlb_index(env, mmu_idx, addr);
entry = tlb_entry(env, mmu_idx, addr);
}
tlb_addr = tlb_addr_write(entry) & ~TLB_INVALID_MASK;
}
/* Handle an IO access. */
if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) {
if ((addr & (DATA_SIZE - 1)) != 0) {
goto do_unaligned_access;
}
/* ??? Note that the io helpers always read data in the target
byte ordering. We should push the LE/BE request down into io. */
val = TGT_BE(val);
glue(io_write, SUFFIX)(env, mmu_idx, index, val, addr, retaddr,
tlb_addr & TLB_RECHECK);
return;
}
/* Handle slow unaligned access (it spans two pages or IO). */
if (DATA_SIZE > 1
&& unlikely((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1
>= TARGET_PAGE_SIZE)) {
int i;
target_ulong page2;
CPUTLBEntry *entry2;
do_unaligned_access:
/* Ensure the second page is in the TLB. Note that the first page
is already guaranteed to be filled, and that the second page
cannot evict the first. */
page2 = (addr + DATA_SIZE) & TARGET_PAGE_MASK;
entry2 = tlb_entry(env, mmu_idx, page2);
if (!tlb_hit_page(tlb_addr_write(entry2), page2)
&& !VICTIM_TLB_HIT(addr_write, page2)) {
tlb_fill(ENV_GET_CPU(env), page2, DATA_SIZE, MMU_DATA_STORE,
mmu_idx, retaddr);
}
/* XXX: not efficient, but simple */
/* This loop must go in the forward direction to avoid issues
with self-modifying code. */
for (i = 0; i < DATA_SIZE; ++i) {
/* Big-endian extract. */
uint8_t val8 = val >> (((DATA_SIZE - 1) * 8) - (i * 8));
glue(helper_ret_stb, MMUSUFFIX)(env, addr + i, val8,
oi, retaddr);
}
return;
}
haddr = addr + entry->addend;
glue(glue(st, SUFFIX), _be_p)((uint8_t *)haddr, val);
}
#endif /* DATA_SIZE > 1 */
#endif /* !defined(SOFTMMU_CODE_ACCESS) */
#undef READ_ACCESS_TYPE
#undef DATA_TYPE
#undef SUFFIX
#undef LSUFFIX
#undef DATA_SIZE
#undef ADDR_READ
#undef WORD_TYPE
#undef SDATA_TYPE
#undef USUFFIX
#undef SSUFFIX
#undef BSWAP
#undef helper_le_ld_name
#undef helper_be_ld_name
#undef helper_le_lds_name
#undef helper_be_lds_name
#undef helper_le_st_name
#undef helper_be_st_name

View File

@@ -26,14 +26,15 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "sysemu/accel.h" #include "sysemu/accel.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "qom/object.h" #include "qom/object.h"
#include "cpu.h" #include "qemu-common.h"
#include "qom/cpu.h"
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
unsigned long tcg_tb_size; unsigned long tcg_tb_size;
#ifndef CONFIG_USER_ONLY
/* mask must never be zero, except for A20 change call */ /* mask must never be zero, except for A20 change call */
static void tcg_handle_interrupt(CPUState *cpu, int mask) static void tcg_handle_interrupt(CPUState *cpu, int mask)
{ {
@@ -50,7 +51,7 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask)
if (!qemu_cpu_is_self(cpu)) { if (!qemu_cpu_is_self(cpu)) {
qemu_cpu_kick(cpu); qemu_cpu_kick(cpu);
} else { } else {
atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); atomic_set(&cpu->icount_decr.u16.high, -1);
if (use_icount && if (use_icount &&
!cpu->can_do_io !cpu->can_do_io
&& (mask & ~old_mask) != 0) { && (mask & ~old_mask) != 0) {
@@ -58,6 +59,7 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask)
} }
} }
} }
#endif
static int tcg_init(MachineState *ms) static int tcg_init(MachineState *ms)
{ {

View File

@@ -398,54 +398,6 @@ void HELPER(gvec_neg64)(void *d, void *a, uint32_t desc)
clear_high(d, oprsz, desc); clear_high(d, oprsz, desc);
} }
void HELPER(gvec_abs8)(void *d, void *a, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(int8_t)) {
int8_t aa = *(int8_t *)(a + i);
*(int8_t *)(d + i) = aa < 0 ? -aa : aa;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_abs16)(void *d, void *a, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(int16_t)) {
int16_t aa = *(int16_t *)(a + i);
*(int16_t *)(d + i) = aa < 0 ? -aa : aa;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_abs32)(void *d, void *a, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(int32_t)) {
int32_t aa = *(int32_t *)(a + i);
*(int32_t *)(d + i) = aa < 0 ? -aa : aa;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_abs64)(void *d, void *a, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
for (i = 0; i < oprsz; i += sizeof(int64_t)) {
int64_t aa = *(int64_t *)(a + i);
*(int64_t *)(d + i) = aa < 0 ? -aa : aa;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_mov)(void *d, void *a, uint32_t desc) void HELPER(gvec_mov)(void *d, void *a, uint32_t desc)
{ {
intptr_t oprsz = simd_oprsz(desc); intptr_t oprsz = simd_oprsz(desc);
@@ -773,150 +725,6 @@ void HELPER(gvec_sar64i)(void *d, void *a, uint32_t desc)
clear_high(d, oprsz, desc); clear_high(d, oprsz, desc);
} }
void HELPER(gvec_shl8v)(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) = *(uint8_t *)(a + i) << sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_shl16v)(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) = *(uint16_t *)(a + i) << sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_shl32v)(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) = *(uint32_t *)(a + i) << sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_shl64v)(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) = *(uint64_t *)(a + i) << sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_shr8v)(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) = *(uint8_t *)(a + i) >> sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_shr16v)(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) = *(uint16_t *)(a + i) >> sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_shr32v)(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) = *(uint32_t *)(a + i) >> sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_shr64v)(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) = *(uint64_t *)(a + i) >> sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_sar8v)(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(int8_t)) {
uint8_t sh = *(uint8_t *)(b + i) & 7;
*(int8_t *)(d + i) = *(int8_t *)(a + i) >> sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_sar16v)(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(int16_t)) {
uint8_t sh = *(uint16_t *)(b + i) & 15;
*(int16_t *)(d + i) = *(int16_t *)(a + i) >> sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_sar32v)(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(int32_t)) {
uint8_t sh = *(uint32_t *)(b + i) & 31;
*(int32_t *)(d + i) = *(int32_t *)(a + i) >> sh;
}
clear_high(d, oprsz, desc);
}
void HELPER(gvec_sar64v)(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(int64_t)) {
uint8_t sh = *(uint64_t *)(b + i) & 63;
*(int64_t *)(d + i) = *(int64_t *)(a + i) >> sh;
}
clear_high(d, oprsz, desc);
}
/* If vectors are enabled, the compiler fills in -1 for true. /* If vectors are enabled, the compiler fills in -1 for true.
Otherwise, we must take care of this by hand. */ Otherwise, we must take care of this by hand. */
#ifdef CONFIG_VECTOR16 #ifdef CONFIG_VECTOR16
@@ -1444,17 +1252,3 @@ void HELPER(gvec_umax64)(void *d, void *a, void *b, uint32_t desc)
} }
clear_high(d, oprsz, desc); clear_high(d, oprsz, desc);
} }
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(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);
}

View File

@@ -146,7 +146,7 @@ uint64_t HELPER(ctpop_i64)(uint64_t arg)
void *HELPER(lookup_tb_ptr)(CPUArchState *env) void *HELPER(lookup_tb_ptr)(CPUArchState *env)
{ {
CPUState *cpu = env_cpu(env); CPUState *cpu = ENV_GET_CPU(env);
TranslationBlock *tb; TranslationBlock *tb;
target_ulong cs_base, pc; target_ulong cs_base, pc;
uint32_t flags; uint32_t flags;
@@ -165,5 +165,5 @@ void *HELPER(lookup_tb_ptr)(CPUArchState *env)
void HELPER(exit_atomic)(CPUArchState *env) void HELPER(exit_atomic)(CPUArchState *env)
{ {
cpu_loop_exit_atomic(env_cpu(env), GETPC()); cpu_loop_exit_atomic(ENV_GET_CPU(env), GETPC());
} }

View File

@@ -225,11 +225,6 @@ DEF_HELPER_FLAGS_3(gvec_neg16, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_neg32, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_neg32, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_neg64, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_neg64, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_abs8, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_abs16, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_abs32, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_abs64, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(gvec_not, TCG_CALL_NO_RWG, void, ptr, ptr, i32) DEF_HELPER_FLAGS_3(gvec_not, TCG_CALL_NO_RWG, void, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_and, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_and, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_or, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_or, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@@ -259,21 +254,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_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_sar64i, 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)
DEF_HELPER_FLAGS_4(gvec_shl64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shr8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shr16v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shr32v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_shr64v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_sar8v, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
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_eq8, 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_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) DEF_HELPER_FLAGS_4(gvec_eq32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@@ -303,5 +283,3 @@ DEF_HELPER_FLAGS_4(gvec_leu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_leu16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)

View File

@@ -1,4 +1,4 @@
# See docs/devel/tracing.txt for syntax documentation. # Trace events for debugging and performance instrumentation
# TCG related tracing (mostly disabled by default) # TCG related tracing (mostly disabled by default)
# cpu-exec.c # cpu-exec.c

View File

@@ -16,10 +16,9 @@
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu-common.h"
#define NO_CPU_IO_DEFS #define NO_CPU_IO_DEFS
#include "cpu.h" #include "cpu.h"
#include "trace.h" #include "trace.h"
@@ -51,12 +50,10 @@
#include "translate-all.h" #include "translate-all.h"
#include "qemu/bitmap.h" #include "qemu/bitmap.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/qemu-print.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "exec/log.h" #include "exec/log.h"
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "sysemu/tcg.h"
/* #define DEBUG_TB_INVALIDATE */ /* #define DEBUG_TB_INVALIDATE */
/* #define DEBUG_TB_FLUSH */ /* #define DEBUG_TB_FLUSH */
@@ -366,7 +363,7 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
assert(use_icount); assert(use_icount);
/* Reset the cycle counter to the start of the block /* Reset the cycle counter to the start of the block
and shift if to the number of actually executed instructions */ and shift if to the number of actually executed instructions */
cpu_neg(cpu)->icount_decr.u16.low += num_insns - i; cpu->icount_decr.u16.low += num_insns - i;
} }
restore_state_to_opc(env, tb, data); restore_state_to_opc(env, tb, data);
@@ -1676,7 +1673,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tb_page_addr_t phys_pc, phys_page2; tb_page_addr_t phys_pc, phys_page2;
target_ulong virt_page2; target_ulong virt_page2;
tcg_insn_unit *gen_code_buf; tcg_insn_unit *gen_code_buf;
int gen_code_size, search_size, max_insns; int gen_code_size, search_size;
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
TCGProfile *prof = &tcg_ctx->prof; TCGProfile *prof = &tcg_ctx->prof;
int64_t ti; int64_t ti;
@@ -1694,17 +1691,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
cflags &= ~CF_CLUSTER_MASK; cflags &= ~CF_CLUSTER_MASK;
cflags |= cpu->cluster_index << CF_CLUSTER_SHIFT; cflags |= cpu->cluster_index << CF_CLUSTER_SHIFT;
max_insns = cflags & CF_COUNT_MASK;
if (max_insns == 0) {
max_insns = CF_COUNT_MASK;
}
if (max_insns > TCG_MAX_INSNS) {
max_insns = TCG_MAX_INSNS;
}
if (cpu->singlestep_enabled || singlestep) {
max_insns = 1;
}
buffer_overflow: buffer_overflow:
tb = tb_alloc(pc); tb = tb_alloc(pc);
if (unlikely(!tb)) { if (unlikely(!tb)) {
@@ -1724,7 +1710,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tb->cflags = cflags; tb->cflags = cflags;
tb->trace_vcpu_dstate = *cpu->trace_dstate; tb->trace_vcpu_dstate = *cpu->trace_dstate;
tcg_ctx->tb_cflags = cflags; tcg_ctx->tb_cflags = cflags;
tb_overflow:
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
/* includes aborted translations because of exceptions */ /* includes aborted translations because of exceptions */
@@ -1734,8 +1719,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tcg_func_start(tcg_ctx); tcg_func_start(tcg_ctx);
tcg_ctx->cpu = env_cpu(env); tcg_ctx->cpu = ENV_GET_CPU(env);
gen_intermediate_code(cpu, tb, max_insns); gen_intermediate_code(cpu, tb);
tcg_ctx->cpu = NULL; tcg_ctx->cpu = NULL;
trace_translate_block(tb, tb->pc, tb->tc.ptr); trace_translate_block(tb, tb->pc, tb->tc.ptr);
@@ -1758,39 +1743,14 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
ti = profile_getclock(); ti = profile_getclock();
#endif #endif
/* ??? Overflow could be handled better here. In particular, we
don't need to re-do gen_intermediate_code, nor should we re-do
the tcg optimization currently hidden inside tcg_gen_code. All
that should be required is to flush the TBs, allocate a new TB,
re-initialize it per above, and re-do the actual code generation. */
gen_code_size = tcg_gen_code(tcg_ctx, tb); gen_code_size = tcg_gen_code(tcg_ctx, tb);
if (unlikely(gen_code_size < 0)) { if (unlikely(gen_code_size < 0)) {
switch (gen_code_size) { goto buffer_overflow;
case -1:
/*
* Overflow of code_gen_buffer, or the current slice of it.
*
* TODO: We don't need to re-do gen_intermediate_code, nor
* should we re-do the tcg optimization currently hidden
* inside tcg_gen_code. All that should be required is to
* flush the TBs, allocate a new TB, re-initialize it per
* above, and re-do the actual code generation.
*/
goto buffer_overflow;
case -2:
/*
* The code generated for the TranslationBlock is too large.
* The maximum size allowed by the unwind info is 64k.
* There may be stricter constraints from relocations
* in the tcg backend.
*
* Try again with half as many insns as we attempted this time.
* If a single insn overflows, there's a bug somewhere...
*/
max_insns = tb->icount;
assert(max_insns > 1);
max_insns /= 2;
goto tb_overflow;
default:
g_assert_not_reached();
}
} }
search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size); search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);
if (unlikely(search_size < 0)) { if (unlikely(search_size < 0)) {
@@ -2202,7 +2162,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
if ((env->hflags & MIPS_HFLAG_BMASK) != 0 if ((env->hflags & MIPS_HFLAG_BMASK) != 0
&& env->active_tc.PC != tb->pc) { && env->active_tc.PC != tb->pc) {
env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
cpu_neg(cpu)->icount_decr.u16.low++; cpu->icount_decr.u16.low++;
env->hflags &= ~MIPS_HFLAG_BMASK; env->hflags &= ~MIPS_HFLAG_BMASK;
n = 2; n = 2;
} }
@@ -2210,7 +2170,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0 if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
&& env->pc != tb->pc) { && env->pc != tb->pc) {
env->pc -= 2; env->pc -= 2;
cpu_neg(cpu)->icount_decr.u16.low++; cpu->icount_decr.u16.low++;
env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
n = 2; n = 2;
} }
@@ -2254,7 +2214,8 @@ void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr)
tb_jmp_cache_clear_page(cpu, addr); tb_jmp_cache_clear_page(cpu, addr);
} }
static void print_qht_statistics(struct qht_stats hst) static void print_qht_statistics(FILE *f, fprintf_function cpu_fprintf,
struct qht_stats hst)
{ {
uint32_t hgram_opts; uint32_t hgram_opts;
size_t hgram_bins; size_t hgram_bins;
@@ -2263,7 +2224,7 @@ static void print_qht_statistics(struct qht_stats hst)
if (!hst.head_buckets) { if (!hst.head_buckets) {
return; return;
} }
qemu_printf("TB hash buckets %zu/%zu (%0.2f%% head buckets used)\n", cpu_fprintf(f, "TB hash buckets %zu/%zu (%0.2f%% head buckets used)\n",
hst.used_head_buckets, hst.head_buckets, hst.used_head_buckets, hst.head_buckets,
(double)hst.used_head_buckets / hst.head_buckets * 100); (double)hst.used_head_buckets / hst.head_buckets * 100);
@@ -2273,7 +2234,7 @@ static void print_qht_statistics(struct qht_stats hst)
hgram_opts |= QDIST_PR_NODECIMAL; hgram_opts |= QDIST_PR_NODECIMAL;
} }
hgram = qdist_pr(&hst.occupancy, 10, hgram_opts); hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
qemu_printf("TB hash occupancy %0.2f%% avg chain occ. Histogram: %s\n", cpu_fprintf(f, "TB hash occupancy %0.2f%% avg chain occ. Histogram: %s\n",
qdist_avg(&hst.occupancy) * 100, hgram); qdist_avg(&hst.occupancy) * 100, hgram);
g_free(hgram); g_free(hgram);
@@ -2286,7 +2247,7 @@ static void print_qht_statistics(struct qht_stats hst)
hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE; hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
} }
hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts); hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
qemu_printf("TB hash avg chain %0.3f buckets. Histogram: %s\n", cpu_fprintf(f, "TB hash avg chain %0.3f buckets. Histogram: %s\n",
qdist_avg(&hst.chain), hgram); qdist_avg(&hst.chain), hgram);
g_free(hgram); g_free(hgram);
} }
@@ -2324,7 +2285,7 @@ static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
return false; return false;
} }
void dump_exec_info(void) void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
{ {
struct tb_tree_stats tst = {}; struct tb_tree_stats tst = {};
struct qht_stats hst; struct qht_stats hst;
@@ -2333,49 +2294,48 @@ void dump_exec_info(void)
tcg_tb_foreach(tb_tree_stats_iter, &tst); tcg_tb_foreach(tb_tree_stats_iter, &tst);
nb_tbs = tst.nb_tbs; nb_tbs = tst.nb_tbs;
/* XXX: avoid using doubles ? */ /* XXX: avoid using doubles ? */
qemu_printf("Translation buffer state:\n"); cpu_fprintf(f, "Translation buffer state:\n");
/* /*
* Report total code size including the padding and TB structs; * Report total code size including the padding and TB structs;
* otherwise users might think "-tb-size" is not honoured. * otherwise users might think "-tb-size" is not honoured.
* For avg host size we use the precise numbers from tb_tree_stats though. * For avg host size we use the precise numbers from tb_tree_stats though.
*/ */
qemu_printf("gen code size %zu/%zu\n", cpu_fprintf(f, "gen code size %zu/%zu\n",
tcg_code_size(), tcg_code_capacity()); tcg_code_size(), tcg_code_capacity());
qemu_printf("TB count %zu\n", nb_tbs); cpu_fprintf(f, "TB count %zu\n", nb_tbs);
qemu_printf("TB avg target size %zu max=%zu bytes\n", cpu_fprintf(f, "TB avg target size %zu max=%zu bytes\n",
nb_tbs ? tst.target_size / nb_tbs : 0, nb_tbs ? tst.target_size / nb_tbs : 0,
tst.max_target_size); tst.max_target_size);
qemu_printf("TB avg host size %zu bytes (expansion ratio: %0.1f)\n", cpu_fprintf(f, "TB avg host size %zu bytes (expansion ratio: %0.1f)\n",
nb_tbs ? tst.host_size / nb_tbs : 0, nb_tbs ? tst.host_size / nb_tbs : 0,
tst.target_size ? (double)tst.host_size / tst.target_size : 0); tst.target_size ? (double)tst.host_size / tst.target_size : 0);
qemu_printf("cross page TB count %zu (%zu%%)\n", tst.cross_page, cpu_fprintf(f, "cross page TB count %zu (%zu%%)\n", tst.cross_page,
nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0); nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
qemu_printf("direct jump count %zu (%zu%%) (2 jumps=%zu %zu%%)\n", cpu_fprintf(f, "direct jump count %zu (%zu%%) (2 jumps=%zu %zu%%)\n",
tst.direct_jmp_count, tst.direct_jmp_count,
nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0, nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
tst.direct_jmp2_count, tst.direct_jmp2_count,
nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0); nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
qht_statistics_init(&tb_ctx.htable, &hst); qht_statistics_init(&tb_ctx.htable, &hst);
print_qht_statistics(hst); print_qht_statistics(f, cpu_fprintf, hst);
qht_statistics_destroy(&hst); qht_statistics_destroy(&hst);
qemu_printf("\nStatistics:\n"); cpu_fprintf(f, "\nStatistics:\n");
qemu_printf("TB flush count %u\n", cpu_fprintf(f, "TB flush count %u\n",
atomic_read(&tb_ctx.tb_flush_count)); atomic_read(&tb_ctx.tb_flush_count));
qemu_printf("TB invalidate count %zu\n", cpu_fprintf(f, "TB invalidate count %zu\n", tcg_tb_phys_invalidate_count());
tcg_tb_phys_invalidate_count());
tlb_flush_counts(&flush_full, &flush_part, &flush_elide); tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
qemu_printf("TLB full flushes %zu\n", flush_full); cpu_fprintf(f, "TLB full flushes %zu\n", flush_full);
qemu_printf("TLB partial flushes %zu\n", flush_part); cpu_fprintf(f, "TLB partial flushes %zu\n", flush_part);
qemu_printf("TLB elided flushes %zu\n", flush_elide); cpu_fprintf(f, "TLB elided flushes %zu\n", flush_elide);
tcg_dump_info(); tcg_dump_info(f, cpu_fprintf);
} }
void dump_opcount_info(void) void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf)
{ {
tcg_dump_op_count(); tcg_dump_op_count(f, cpu_fprintf);
} }
#else /* CONFIG_USER_ONLY */ #else /* CONFIG_USER_ONLY */
@@ -2384,7 +2344,7 @@ void cpu_interrupt(CPUState *cpu, int mask)
{ {
g_assert(qemu_mutex_iothread_locked()); g_assert(qemu_mutex_iothread_locked());
cpu->interrupt_request |= mask; cpu->interrupt_request |= mask;
atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); atomic_set(&cpu->icount_decr.u16.high, -1);
} }
/* /*

View File

@@ -8,6 +8,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "cpu.h" #include "cpu.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
@@ -31,7 +32,7 @@ void translator_loop_temp_check(DisasContextBase *db)
} }
void translator_loop(const TranslatorOps *ops, DisasContextBase *db, void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
CPUState *cpu, TranslationBlock *tb, int max_insns) CPUState *cpu, TranslationBlock *tb)
{ {
int bp_insn = 0; int bp_insn = 0;
@@ -41,9 +42,20 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
db->pc_next = db->pc_first; db->pc_next = db->pc_first;
db->is_jmp = DISAS_NEXT; db->is_jmp = DISAS_NEXT;
db->num_insns = 0; db->num_insns = 0;
db->max_insns = max_insns;
db->singlestep_enabled = cpu->singlestep_enabled; db->singlestep_enabled = cpu->singlestep_enabled;
/* Instruction counting */
db->max_insns = tb_cflags(db->tb) & CF_COUNT_MASK;
if (db->max_insns == 0) {
db->max_insns = CF_COUNT_MASK;
}
if (db->max_insns > TCG_MAX_INSNS) {
db->max_insns = TCG_MAX_INSNS;
}
if (db->singlestep_enabled || singlestep) {
db->max_insns = 1;
}
ops->init_disas_context(db, cpu); ops->init_disas_context(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */

View File

@@ -1,4 +1,5 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "qom/cpu.h" #include "qom/cpu.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"

View File

@@ -63,57 +63,28 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
{ {
CPUState *cpu = current_cpu; CPUState *cpu = current_cpu;
CPUClass *cc; CPUClass *cc;
int ret;
unsigned long address = (unsigned long)info->si_addr; unsigned long address = (unsigned long)info->si_addr;
MMUAccessType access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
switch (helper_retaddr) { /* We must handle PC addresses from two different sources:
default: * a call return address and a signal frame address.
/* *
* Fault during host memory operation within a helper function. * Within cpu_restore_state_from_tb we assume the former and adjust
* The helper's host return address, saved here, gives us a * the address by -GETPC_ADJ so that the address is within the call
* pointer into the generated code that will unwind to the * insn so that addr does not accidentally match the beginning of the
* correct guest pc. * next guest insn.
*/ *
* However, when the PC comes from the signal frame, it points to
* the actual faulting host insn and not a call insn. Subtracting
* GETPC_ADJ in that case may accidentally match the previous guest insn.
*
* So for the later case, adjust forward to compensate for what
* will be done later by cpu_restore_state_from_tb.
*/
if (helper_retaddr) {
pc = helper_retaddr; pc = helper_retaddr;
break; } else {
case 0:
/*
* Fault during host memory operation within generated code.
* (Or, a unrelated bug within qemu, but we can't tell from here).
*
* We take the host pc from the signal frame. However, we cannot
* use that value directly. Within cpu_restore_state_from_tb, we
* assume PC comes from GETPC(), as used by the helper functions,
* so we adjust the address by -GETPC_ADJ to form an address that
* is within the call insn, so that the address does not accidentially
* match the beginning of the next guest insn. However, when the
* pc comes from the signal frame it points to the actual faulting
* host memory insn and not the return from a call insn.
*
* Therefore, adjust to compensate for what will be done later
* by cpu_restore_state_from_tb.
*/
pc += GETPC_ADJ; pc += GETPC_ADJ;
break;
case 1:
/*
* Fault during host read for translation, or loosely, "execution".
*
* The guest pc is already pointing to the start of the TB for which
* code is being generated. If the guest translator manages the
* page crossings correctly, this is exactly the correct address
* (and if the translator doesn't handle page boundaries correctly
* there's little we can do about that here). Therefore, do not
* trigger the unwinder.
*
* Like tb_gen_code, release the memory lock before cpu_loop_exit.
*/
pc = 0;
access_type = MMU_INST_FETCH;
mmap_unlock();
break;
} }
/* For synchronous signals we expect to be coming from the vCPU /* For synchronous signals we expect to be coming from the vCPU
@@ -163,7 +134,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
* currently executing TB was modified and must be exited * currently executing TB was modified and must be exited
* immediately. Clear helper_retaddr for next execution. * immediately. Clear helper_retaddr for next execution.
*/ */
clear_helper_retaddr(); helper_retaddr = 0;
cpu_exit_tb_from_sighandler(cpu, old_set); cpu_exit_tb_from_sighandler(cpu, old_set);
/* NORETURN */ /* NORETURN */
@@ -176,16 +147,35 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
are still valid segv ones */ are still valid segv ones */
address = h2g_nocheck(address); address = h2g_nocheck(address);
/*
* There is no way the target can handle this other than raising
* an exception. Undo signal and retaddr state prior to longjmp.
*/
sigprocmask(SIG_SETMASK, old_set, NULL);
clear_helper_retaddr();
cc = CPU_GET_CLASS(cpu); cc = CPU_GET_CLASS(cpu);
cc->tlb_fill(cpu, address, 0, access_type, MMU_USER_IDX, false, pc); /* see if it is an MMU fault */
g_assert_not_reached(); g_assert(cc->handle_mmu_fault);
ret = cc->handle_mmu_fault(cpu, address, 0, is_write, MMU_USER_IDX);
if (ret == 0) {
/* The MMU fault was handled without causing real CPU fault.
* Retain helper_retaddr for a possible second fault.
*/
return 1;
}
/* All other paths lead to cpu_exit; clear helper_retaddr
* for next execution.
*/
helper_retaddr = 0;
if (ret < 0) {
return 0; /* not an MMU fault */
}
/* Now we have a real cpu fault. */
cpu_restore_state(cpu, pc, true);
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit(cpu);
/* never comes here */
return 1;
} }
#if defined(__i386__) #if defined(__i386__)
@@ -708,17 +698,16 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
{ {
/* Enforce qemu required alignment. */ /* Enforce qemu required alignment. */
if (unlikely(addr & (size - 1))) { if (unlikely(addr & (size - 1))) {
cpu_loop_exit_atomic(env_cpu(env), retaddr); cpu_loop_exit_atomic(ENV_GET_CPU(env), retaddr);
} }
void *ret = g2h(addr); helper_retaddr = retaddr;
set_helper_retaddr(retaddr); return g2h(addr);
return ret;
} }
/* Macro to call the above, with local variables from the use context. */ /* Macro to call the above, with local variables from the use context. */
#define ATOMIC_MMU_DECLS do {} while (0) #define ATOMIC_MMU_DECLS do {} while (0)
#define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, DATA_SIZE, GETPC()) #define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, DATA_SIZE, GETPC())
#define ATOMIC_MMU_CLEANUP do { clear_helper_retaddr(); } while (0) #define ATOMIC_MMU_CLEANUP do { helper_retaddr = 0; } while (0)
#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) #define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END))
#define EXTRA_ARGS #define EXTRA_ARGS

View File

@@ -22,6 +22,7 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "sysemu/arch_init.h" #include "sysemu/arch_init.h"

View File

@@ -1,4 +1,4 @@
common-obj-y = audio.o audio_legacy.o noaudio.o wavaudio.o mixeng.o common-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
common-obj-$(CONFIG_SPICE) += spiceaudio.o common-obj-$(CONFIG_SPICE) += spiceaudio.o
common-obj-$(CONFIG_AUDIO_COREAUDIO) += coreaudio.o common-obj-$(CONFIG_AUDIO_COREAUDIO) += coreaudio.o
common-obj-$(CONFIG_AUDIO_DSOUND) += dsoundaudio.o common-obj-$(CONFIG_AUDIO_DSOUND) += dsoundaudio.o

View File

@@ -21,11 +21,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include "qemu-common.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/module.h"
#include "audio.h" #include "audio.h"
#include "trace.h" #include "trace.h"
@@ -34,9 +33,28 @@
#define AUDIO_CAP "alsa" #define AUDIO_CAP "alsa"
#include "audio_int.h" #include "audio_int.h"
typedef struct ALSAConf {
int size_in_usec_in;
int size_in_usec_out;
const char *pcm_name_in;
const char *pcm_name_out;
unsigned int buffer_size_in;
unsigned int period_size_in;
unsigned int buffer_size_out;
unsigned int period_size_out;
unsigned int threshold;
int buffer_size_in_overridden;
int period_size_in_overridden;
int buffer_size_out_overridden;
int period_size_out_overridden;
} ALSAConf;
struct pollhlp { struct pollhlp {
snd_pcm_t *handle; snd_pcm_t *handle;
struct pollfd *pfds; struct pollfd *pfds;
ALSAConf *conf;
int count; int count;
int mask; int mask;
}; };
@@ -48,7 +66,6 @@ typedef struct ALSAVoiceOut {
void *pcm_buf; void *pcm_buf;
snd_pcm_t *handle; snd_pcm_t *handle;
struct pollhlp pollhlp; struct pollhlp pollhlp;
Audiodev *dev;
} ALSAVoiceOut; } ALSAVoiceOut;
typedef struct ALSAVoiceIn { typedef struct ALSAVoiceIn {
@@ -56,18 +73,21 @@ typedef struct ALSAVoiceIn {
snd_pcm_t *handle; snd_pcm_t *handle;
void *pcm_buf; void *pcm_buf;
struct pollhlp pollhlp; struct pollhlp pollhlp;
Audiodev *dev;
} ALSAVoiceIn; } ALSAVoiceIn;
struct alsa_params_req { struct alsa_params_req {
int freq; int freq;
snd_pcm_format_t fmt; snd_pcm_format_t fmt;
int nchannels; int nchannels;
int size_in_usec;
int override_mask;
unsigned int buffer_size;
unsigned int period_size;
}; };
struct alsa_params_obt { struct alsa_params_obt {
int freq; int freq;
AudioFormat fmt; audfmt_e fmt;
int endianness; int endianness;
int nchannels; int nchannels;
snd_pcm_uframes_t samples; snd_pcm_uframes_t samples;
@@ -274,16 +294,16 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
return audio_pcm_sw_write (sw, buf, len); return audio_pcm_sw_write (sw, buf, len);
} }
static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness) static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
{ {
switch (fmt) { switch (fmt) {
case AUDIO_FORMAT_S8: case AUD_FMT_S8:
return SND_PCM_FORMAT_S8; return SND_PCM_FORMAT_S8;
case AUDIO_FORMAT_U8: case AUD_FMT_U8:
return SND_PCM_FORMAT_U8; return SND_PCM_FORMAT_U8;
case AUDIO_FORMAT_S16: case AUD_FMT_S16:
if (endianness) { if (endianness) {
return SND_PCM_FORMAT_S16_BE; return SND_PCM_FORMAT_S16_BE;
} }
@@ -291,7 +311,7 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
return SND_PCM_FORMAT_S16_LE; return SND_PCM_FORMAT_S16_LE;
} }
case AUDIO_FORMAT_U16: case AUD_FMT_U16:
if (endianness) { if (endianness) {
return SND_PCM_FORMAT_U16_BE; return SND_PCM_FORMAT_U16_BE;
} }
@@ -299,7 +319,7 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
return SND_PCM_FORMAT_U16_LE; return SND_PCM_FORMAT_U16_LE;
} }
case AUDIO_FORMAT_S32: case AUD_FMT_S32:
if (endianness) { if (endianness) {
return SND_PCM_FORMAT_S32_BE; return SND_PCM_FORMAT_S32_BE;
} }
@@ -307,7 +327,7 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
return SND_PCM_FORMAT_S32_LE; return SND_PCM_FORMAT_S32_LE;
} }
case AUDIO_FORMAT_U32: case AUD_FMT_U32:
if (endianness) { if (endianness) {
return SND_PCM_FORMAT_U32_BE; return SND_PCM_FORMAT_U32_BE;
} }
@@ -324,58 +344,58 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
} }
} }
static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt, static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
int *endianness) int *endianness)
{ {
switch (alsafmt) { switch (alsafmt) {
case SND_PCM_FORMAT_S8: case SND_PCM_FORMAT_S8:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_S8; *fmt = AUD_FMT_S8;
break; break;
case SND_PCM_FORMAT_U8: case SND_PCM_FORMAT_U8:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_U8; *fmt = AUD_FMT_U8;
break; break;
case SND_PCM_FORMAT_S16_LE: case SND_PCM_FORMAT_S16_LE:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_S16; *fmt = AUD_FMT_S16;
break; break;
case SND_PCM_FORMAT_U16_LE: case SND_PCM_FORMAT_U16_LE:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_U16; *fmt = AUD_FMT_U16;
break; break;
case SND_PCM_FORMAT_S16_BE: case SND_PCM_FORMAT_S16_BE:
*endianness = 1; *endianness = 1;
*fmt = AUDIO_FORMAT_S16; *fmt = AUD_FMT_S16;
break; break;
case SND_PCM_FORMAT_U16_BE: case SND_PCM_FORMAT_U16_BE:
*endianness = 1; *endianness = 1;
*fmt = AUDIO_FORMAT_U16; *fmt = AUD_FMT_U16;
break; break;
case SND_PCM_FORMAT_S32_LE: case SND_PCM_FORMAT_S32_LE:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_S32; *fmt = AUD_FMT_S32;
break; break;
case SND_PCM_FORMAT_U32_LE: case SND_PCM_FORMAT_U32_LE:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_U32; *fmt = AUD_FMT_U32;
break; break;
case SND_PCM_FORMAT_S32_BE: case SND_PCM_FORMAT_S32_BE:
*endianness = 1; *endianness = 1;
*fmt = AUDIO_FORMAT_S32; *fmt = AUD_FMT_S32;
break; break;
case SND_PCM_FORMAT_U32_BE: case SND_PCM_FORMAT_U32_BE:
*endianness = 1; *endianness = 1;
*fmt = AUDIO_FORMAT_U32; *fmt = AUD_FMT_U32;
break; break;
default: default:
@@ -388,18 +408,17 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
static void alsa_dump_info (struct alsa_params_req *req, static void alsa_dump_info (struct alsa_params_req *req,
struct alsa_params_obt *obt, struct alsa_params_obt *obt,
snd_pcm_format_t obtfmt, snd_pcm_format_t obtfmt)
AudiodevAlsaPerDirectionOptions *apdo)
{ {
dolog("parameter | requested value | obtained value\n"); dolog ("parameter | requested value | obtained value\n");
dolog("format | %10d | %10d\n", req->fmt, obtfmt); dolog ("format | %10d | %10d\n", req->fmt, obtfmt);
dolog("channels | %10d | %10d\n", dolog ("channels | %10d | %10d\n",
req->nchannels, obt->nchannels); req->nchannels, obt->nchannels);
dolog("frequency | %10d | %10d\n", req->freq, obt->freq); dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
dolog("============================================\n"); dolog ("============================================\n");
dolog("requested: buffer len %" PRId32 " period len %" PRId32 "\n", dolog ("requested: buffer size %d period size %d\n",
apdo->buffer_length, apdo->period_length); req->buffer_size, req->period_size);
dolog("obtained: samples %ld\n", obt->samples); dolog ("obtained: samples %ld\n", obt->samples);
} }
static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
@@ -432,23 +451,23 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
} }
} }
static int alsa_open(bool in, struct alsa_params_req *req, static int alsa_open (int in, struct alsa_params_req *req,
struct alsa_params_obt *obt, snd_pcm_t **handlep, struct alsa_params_obt *obt, snd_pcm_t **handlep,
Audiodev *dev) ALSAConf *conf)
{ {
AudiodevAlsaOptions *aopts = &dev->u.alsa;
AudiodevAlsaPerDirectionOptions *apdo = in ? aopts->in : aopts->out;
snd_pcm_t *handle; snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_t *hw_params;
int err; int err;
int size_in_usec;
unsigned int freq, nchannels; unsigned int freq, nchannels;
const char *pcm_name = apdo->has_dev ? apdo->dev : "default"; const char *pcm_name = in ? conf->pcm_name_in : conf->pcm_name_out;
snd_pcm_uframes_t obt_buffer_size; snd_pcm_uframes_t obt_buffer_size;
const char *typ = in ? "ADC" : "DAC"; const char *typ = in ? "ADC" : "DAC";
snd_pcm_format_t obtfmt; snd_pcm_format_t obtfmt;
freq = req->freq; freq = req->freq;
nchannels = req->nchannels; nchannels = req->nchannels;
size_in_usec = req->size_in_usec;
snd_pcm_hw_params_alloca (&hw_params); snd_pcm_hw_params_alloca (&hw_params);
@@ -508,42 +527,79 @@ static int alsa_open(bool in, struct alsa_params_req *req,
goto err; goto err;
} }
if (apdo->buffer_length) { if (req->buffer_size) {
int dir = 0; unsigned long obt;
unsigned int btime = apdo->buffer_length;
err = snd_pcm_hw_params_set_buffer_time_near( if (size_in_usec) {
handle, hw_params, &btime, &dir); int dir = 0;
unsigned int btime = req->buffer_size;
err = snd_pcm_hw_params_set_buffer_time_near (
handle,
hw_params,
&btime,
&dir
);
obt = btime;
}
else {
snd_pcm_uframes_t bsize = req->buffer_size;
err = snd_pcm_hw_params_set_buffer_size_near (
handle,
hw_params,
&bsize
);
obt = bsize;
}
if (err < 0) { if (err < 0) {
alsa_logerr2(err, typ, "Failed to set buffer time to %" PRId32 "\n", alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
apdo->buffer_length); size_in_usec ? "time" : "size", req->buffer_size);
goto err; goto err;
} }
if (apdo->has_buffer_length && btime != apdo->buffer_length) { if ((req->override_mask & 2) && (obt - req->buffer_size))
dolog("Requested buffer time %" PRId32 dolog ("Requested buffer %s %u was rejected, using %lu\n",
" was rejected, using %u\n", apdo->buffer_length, btime); size_in_usec ? "time" : "size", req->buffer_size, obt);
}
} }
if (apdo->period_length) { if (req->period_size) {
int dir = 0; unsigned long obt;
unsigned int ptime = apdo->period_length;
err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &ptime, if (size_in_usec) {
&dir); int dir = 0;
unsigned int ptime = req->period_size;
err = snd_pcm_hw_params_set_period_time_near (
handle,
hw_params,
&ptime,
&dir
);
obt = ptime;
}
else {
int dir = 0;
snd_pcm_uframes_t psize = req->period_size;
err = snd_pcm_hw_params_set_period_size_near (
handle,
hw_params,
&psize,
&dir
);
obt = psize;
}
if (err < 0) { if (err < 0) {
alsa_logerr2(err, typ, "Failed to set period time to %" PRId32 "\n", alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
apdo->period_length); size_in_usec ? "time" : "size", req->period_size);
goto err; goto err;
} }
if (apdo->has_period_length && ptime != apdo->period_length) { if (((req->override_mask & 1) && (obt - req->period_size)))
dolog("Requested period time %" PRId32 " was rejected, using %d\n", dolog ("Requested period %s %u was rejected, using %lu\n",
apdo->period_length, ptime); size_in_usec ? "time" : "size", req->period_size, obt);
}
} }
err = snd_pcm_hw_params (handle, hw_params); err = snd_pcm_hw_params (handle, hw_params);
@@ -575,12 +631,30 @@ static int alsa_open(bool in, struct alsa_params_req *req,
goto err; goto err;
} }
if (!in && aopts->has_threshold && aopts->threshold) { if (!in && conf->threshold) {
struct audsettings as = { .freq = freq }; snd_pcm_uframes_t threshold;
alsa_set_threshold( int bytes_per_sec;
handle,
audio_buffer_frames(qapi_AudiodevAlsaPerDirectionOptions_base(apdo), bytes_per_sec = freq << (nchannels == 2);
&as, aopts->threshold));
switch (obt->fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
bytes_per_sec <<= 1;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
bytes_per_sec <<= 2;
break;
}
threshold = (conf->threshold * bytes_per_sec) / 1000;
alsa_set_threshold (handle, threshold);
} }
obt->nchannels = nchannels; obt->nchannels = nchannels;
@@ -593,11 +667,11 @@ static int alsa_open(bool in, struct alsa_params_req *req,
obt->nchannels != req->nchannels || obt->nchannels != req->nchannels ||
obt->freq != req->freq) { obt->freq != req->freq) {
dolog ("Audio parameters for %s\n", typ); dolog ("Audio parameters for %s\n", typ);
alsa_dump_info(req, obt, obtfmt, apdo); alsa_dump_info (req, obt, obtfmt);
} }
#ifdef DEBUG #ifdef DEBUG
alsa_dump_info(req, obt, obtfmt, pdo); alsa_dump_info (req, obt, obtfmt);
#endif #endif
return 0; return 0;
@@ -723,13 +797,19 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
struct alsa_params_obt obt; struct alsa_params_obt obt;
snd_pcm_t *handle; snd_pcm_t *handle;
struct audsettings obt_as; struct audsettings obt_as;
Audiodev *dev = drv_opaque; ALSAConf *conf = drv_opaque;
req.fmt = aud_to_alsafmt (as->fmt, as->endianness); req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
req.freq = as->freq; req.freq = as->freq;
req.nchannels = as->nchannels; req.nchannels = as->nchannels;
req.period_size = conf->period_size_out;
req.buffer_size = conf->buffer_size_out;
req.size_in_usec = conf->size_in_usec_out;
req.override_mask =
(conf->period_size_out_overridden ? 1 : 0) |
(conf->buffer_size_out_overridden ? 2 : 0);
if (alsa_open(0, &req, &obt, &handle, dev)) { if (alsa_open (0, &req, &obt, &handle, conf)) {
return -1; return -1;
} }
@@ -750,7 +830,7 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
} }
alsa->handle = handle; alsa->handle = handle;
alsa->dev = dev; alsa->pollhlp.conf = conf;
return 0; return 0;
} }
@@ -790,12 +870,16 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...) static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
{ {
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.out;
switch (cmd) { switch (cmd) {
case VOICE_ENABLE: case VOICE_ENABLE:
{ {
bool poll_mode = apdo->try_poll; va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
ldebug ("enabling voice\n"); ldebug ("enabling voice\n");
if (poll_mode && alsa_poll_out (hw)) { if (poll_mode && alsa_poll_out (hw)) {
@@ -824,13 +908,19 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
struct alsa_params_obt obt; struct alsa_params_obt obt;
snd_pcm_t *handle; snd_pcm_t *handle;
struct audsettings obt_as; struct audsettings obt_as;
Audiodev *dev = drv_opaque; ALSAConf *conf = drv_opaque;
req.fmt = aud_to_alsafmt (as->fmt, as->endianness); req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
req.freq = as->freq; req.freq = as->freq;
req.nchannels = as->nchannels; req.nchannels = as->nchannels;
req.period_size = conf->period_size_in;
req.buffer_size = conf->buffer_size_in;
req.size_in_usec = conf->size_in_usec_in;
req.override_mask =
(conf->period_size_in_overridden ? 1 : 0) |
(conf->buffer_size_in_overridden ? 2 : 0);
if (alsa_open(1, &req, &obt, &handle, dev)) { if (alsa_open (1, &req, &obt, &handle, conf)) {
return -1; return -1;
} }
@@ -851,7 +941,7 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
} }
alsa->handle = handle; alsa->handle = handle;
alsa->dev = dev; alsa->pollhlp.conf = conf;
return 0; return 0;
} }
@@ -993,12 +1083,16 @@ static int alsa_read (SWVoiceIn *sw, void *buf, int size)
static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...) static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
{ {
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.in;
switch (cmd) { switch (cmd) {
case VOICE_ENABLE: case VOICE_ENABLE:
{ {
bool poll_mode = apdo->try_poll; va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
ldebug ("enabling voice\n"); ldebug ("enabling voice\n");
if (poll_mode && alsa_poll_in (hw)) { if (poll_mode && alsa_poll_in (hw)) {
@@ -1021,54 +1115,88 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
return -1; return -1;
} }
static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo) static ALSAConf glob_conf = {
.buffer_size_out = 4096,
.period_size_out = 1024,
.pcm_name_out = "default",
.pcm_name_in = "default",
};
static void *alsa_audio_init (void)
{ {
if (!apdo->has_try_poll) { ALSAConf *conf = g_malloc(sizeof(ALSAConf));
apdo->try_poll = true; *conf = glob_conf;
apdo->has_try_poll = true; return conf;
}
}
static void *alsa_audio_init(Audiodev *dev)
{
AudiodevAlsaOptions *aopts;
assert(dev->driver == AUDIODEV_DRIVER_ALSA);
aopts = &dev->u.alsa;
alsa_init_per_direction(aopts->in);
alsa_init_per_direction(aopts->out);
/*
* need to define them, as otherwise alsa produces no sound
* doesn't set has_* so alsa_open can identify it wasn't set by the user
*/
if (!dev->u.alsa.out->has_period_length) {
/* 1024 frames assuming 44100Hz */
dev->u.alsa.out->period_length = 1024 * 1000000 / 44100;
}
if (!dev->u.alsa.out->has_buffer_length) {
/* 4096 frames assuming 44100Hz */
dev->u.alsa.out->buffer_length = 4096ll * 1000000 / 44100;
}
/*
* OptsVisitor sets unspecified optional fields to zero, but do not depend
* on it...
*/
if (!dev->u.alsa.in->has_period_length) {
dev->u.alsa.in->period_length = 0;
}
if (!dev->u.alsa.in->has_buffer_length) {
dev->u.alsa.in->buffer_length = 0;
}
return dev;
} }
static void alsa_audio_fini (void *opaque) static void alsa_audio_fini (void *opaque)
{ {
g_free(opaque);
} }
static struct audio_option alsa_options[] = {
{
.name = "DAC_SIZE_IN_USEC",
.tag = AUD_OPT_BOOL,
.valp = &glob_conf.size_in_usec_out,
.descr = "DAC period/buffer size in microseconds (otherwise in frames)"
},
{
.name = "DAC_PERIOD_SIZE",
.tag = AUD_OPT_INT,
.valp = &glob_conf.period_size_out,
.descr = "DAC period size (0 to go with system default)",
.overriddenp = &glob_conf.period_size_out_overridden
},
{
.name = "DAC_BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &glob_conf.buffer_size_out,
.descr = "DAC buffer size (0 to go with system default)",
.overriddenp = &glob_conf.buffer_size_out_overridden
},
{
.name = "ADC_SIZE_IN_USEC",
.tag = AUD_OPT_BOOL,
.valp = &glob_conf.size_in_usec_in,
.descr =
"ADC period/buffer size in microseconds (otherwise in frames)"
},
{
.name = "ADC_PERIOD_SIZE",
.tag = AUD_OPT_INT,
.valp = &glob_conf.period_size_in,
.descr = "ADC period size (0 to go with system default)",
.overriddenp = &glob_conf.period_size_in_overridden
},
{
.name = "ADC_BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &glob_conf.buffer_size_in,
.descr = "ADC buffer size (0 to go with system default)",
.overriddenp = &glob_conf.buffer_size_in_overridden
},
{
.name = "THRESHOLD",
.tag = AUD_OPT_INT,
.valp = &glob_conf.threshold,
.descr = "(undocumented)"
},
{
.name = "DAC_DEV",
.tag = AUD_OPT_STR,
.valp = &glob_conf.pcm_name_out,
.descr = "DAC device name (for instance dmix)"
},
{
.name = "ADC_DEV",
.tag = AUD_OPT_STR,
.valp = &glob_conf.pcm_name_in,
.descr = "ADC device name"
},
{ /* End of list */ }
};
static struct audio_pcm_ops alsa_pcm_ops = { static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out, .init_out = alsa_init_out,
.fini_out = alsa_fini_out, .fini_out = alsa_fini_out,
@@ -1086,6 +1214,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
static struct audio_driver alsa_audio_driver = { static struct audio_driver alsa_audio_driver = {
.name = "alsa", .name = "alsa",
.descr = "ALSA http://www.alsa-project.org", .descr = "ALSA http://www.alsa-project.org",
.options = alsa_options,
.init = alsa_audio_init, .init = alsa_audio_init,
.fini = alsa_audio_fini, .fini = alsa_audio_fini,
.pcm_ops = &alsa_pcm_ops, .pcm_ops = &alsa_pcm_ops,

File diff suppressed because it is too large Load Diff

View File

@@ -26,31 +26,30 @@
#define QEMU_AUDIO_H #define QEMU_AUDIO_H
#include "qemu/queue.h" #include "qemu/queue.h"
#include "qapi/qapi-types-audio.h"
typedef void (*audio_callback_fn) (void *opaque, int avail); typedef void (*audio_callback_fn) (void *opaque, int avail);
typedef enum {
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16,
AUD_FMT_U32,
AUD_FMT_S32
} audfmt_e;
#ifdef HOST_WORDS_BIGENDIAN #ifdef HOST_WORDS_BIGENDIAN
#define AUDIO_HOST_ENDIANNESS 1 #define AUDIO_HOST_ENDIANNESS 1
#else #else
#define AUDIO_HOST_ENDIANNESS 0 #define AUDIO_HOST_ENDIANNESS 0
#endif #endif
typedef struct audsettings { struct audsettings {
int freq; int freq;
int nchannels; int nchannels;
AudioFormat fmt; audfmt_e fmt;
int endianness; int endianness;
} audsettings; };
audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo);
int audioformat_bytes_per_sample(AudioFormat fmt);
int audio_buffer_frames(AudiodevPerDirectionOptions *pdo,
audsettings *as, int def_usecs);
int audio_buffer_samples(AudiodevPerDirectionOptions *pdo,
audsettings *as, int def_usecs);
int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo,
audsettings *as, int def_usecs);
typedef enum { typedef enum {
AUD_CNOTIFY_ENABLE, AUD_CNOTIFY_ENABLE,
@@ -90,6 +89,7 @@ typedef struct QEMUAudioTimeStamp {
void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0); void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
void AUD_help (void);
void AUD_register_card (const char *name, QEMUSoundCard *card); void AUD_register_card (const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card); void AUD_remove_card (QEMUSoundCard *card);
CaptureVoiceOut *AUD_add_capture ( CaptureVoiceOut *AUD_add_capture (
@@ -171,8 +171,4 @@ void audio_sample_to_uint64(void *samples, int pos,
void audio_sample_from_uint64(void *samples, int pos, void audio_sample_from_uint64(void *samples, int pos,
uint64_t left, uint64_t right); uint64_t left, uint64_t right);
void audio_parse_option(const char *opt);
void audio_init_audiodevs(void);
void audio_legacy_help(void);
#endif /* QEMU_AUDIO_H */ #endif /* QEMU_AUDIO_H */

View File

@@ -33,6 +33,22 @@
struct audio_pcm_ops; struct audio_pcm_ops;
typedef enum {
AUD_OPT_INT,
AUD_OPT_FMT,
AUD_OPT_STR,
AUD_OPT_BOOL
} audio_option_tag_e;
struct audio_option {
const char *name;
audio_option_tag_e tag;
void *valp;
const char *descr;
int *overriddenp;
int overridden;
};
struct audio_callback { struct audio_callback {
void *opaque; void *opaque;
audio_callback_fn fn; audio_callback_fn fn;
@@ -129,7 +145,8 @@ typedef struct audio_driver audio_driver;
struct audio_driver { struct audio_driver {
const char *name; const char *name;
const char *descr; const char *descr;
void *(*init) (Audiodev *); struct audio_option *options;
void *(*init) (void);
void (*fini) (void *); void (*fini) (void *);
struct audio_pcm_ops *pcm_ops; struct audio_pcm_ops *pcm_ops;
int can_be_default; int can_be_default;
@@ -176,7 +193,6 @@ struct SWVoiceCap {
typedef struct AudioState { typedef struct AudioState {
struct audio_driver *drv; struct audio_driver *drv;
Audiodev *dev;
void *drv_opaque; void *drv_opaque;
QEMUTimer *ts; QEMUTimer *ts;
@@ -187,13 +203,10 @@ typedef struct AudioState {
int nb_hw_voices_out; int nb_hw_voices_out;
int nb_hw_voices_in; int nb_hw_voices_in;
int vm_running; int vm_running;
int64_t period_ticks;
} AudioState; } AudioState;
extern const struct mixeng_volume nominal_volume; extern const struct mixeng_volume nominal_volume;
extern const char *audio_prio_list[];
void audio_driver_register(audio_driver *drv); void audio_driver_register(audio_driver *drv);
audio_driver *audio_driver_lookup(const char *name); audio_driver *audio_driver_lookup(const char *name);
@@ -235,18 +248,4 @@ static inline int audio_ring_dist (int dst, int src, int len)
#define AUDIO_STRINGIFY_(n) #n #define AUDIO_STRINGIFY_(n) #n
#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n) #define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
typedef struct AudiodevListEntry {
Audiodev *dev;
QSIMPLEQ_ENTRY(AudiodevListEntry) next;
} AudiodevListEntry;
typedef QSIMPLEQ_HEAD(, AudiodevListEntry) AudiodevListHead;
AudiodevListHead audio_handle_legacy_opts(void);
void audio_free_audiodev_list(AudiodevListHead *head);
void audio_create_pdos(Audiodev *dev);
AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev);
AudiodevPerDirectionOptions *audio_get_pdo_out(Audiodev *dev);
#endif /* QEMU_AUDIO_INT_H */ #endif /* QEMU_AUDIO_INT_H */

View File

@@ -1,549 +0,0 @@
/*
* QEMU Audio subsystem: legacy configuration handling
*
* Copyright (c) 2015-2019 Zoltán Kővágó <DirtY.iCE.hu@gmail.com>
*
* 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 "audio.h"
#include "audio_int.h"
#include "qemu/cutils.h"
#include "qemu/timer.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-audio.h"
#include "qapi/visitor-impl.h"
#define AUDIO_CAP "audio-legacy"
#include "audio_int.h"
static uint32_t toui32(const char *str)
{
unsigned long long ret;
if (parse_uint_full(str, &ret, 10) || ret > UINT32_MAX) {
dolog("Invalid integer value `%s'\n", str);
exit(1);
}
return ret;
}
/* helper functions to convert env variables */
static void get_bool(const char *env, bool *dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
*dst = toui32(val) != 0;
*has_dst = true;
}
}
static void get_int(const char *env, uint32_t *dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
*dst = toui32(val);
*has_dst = true;
}
}
static void get_str(const char *env, char **dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
if (*has_dst) {
g_free(*dst);
}
*dst = g_strdup(val);
*has_dst = true;
}
}
static void get_fmt(const char *env, AudioFormat *dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
size_t i;
for (i = 0; AudioFormat_lookup.size; ++i) {
if (strcasecmp(val, AudioFormat_lookup.array[i]) == 0) {
*dst = i;
*has_dst = true;
return;
}
}
dolog("Invalid audio format `%s'\n", val);
exit(1);
}
}
static void get_millis_to_usecs(const char *env, uint32_t *dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
*dst = toui32(val) * 1000;
*has_dst = true;
}
}
static uint32_t frames_to_usecs(uint32_t frames,
AudiodevPerDirectionOptions *pdo)
{
uint32_t freq = pdo->has_frequency ? pdo->frequency : 44100;
return (frames * 1000000 + freq / 2) / freq;
}
static void get_frames_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
AudiodevPerDirectionOptions *pdo)
{
const char *val = getenv(env);
if (val) {
*dst = frames_to_usecs(toui32(val), pdo);
*has_dst = true;
}
}
static uint32_t samples_to_usecs(uint32_t samples,
AudiodevPerDirectionOptions *pdo)
{
uint32_t channels = pdo->has_channels ? pdo->channels : 2;
return frames_to_usecs(samples / channels, pdo);
}
static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
AudiodevPerDirectionOptions *pdo)
{
const char *val = getenv(env);
if (val) {
*dst = samples_to_usecs(toui32(val), pdo);
*has_dst = true;
}
}
static uint32_t bytes_to_usecs(uint32_t bytes, AudiodevPerDirectionOptions *pdo)
{
AudioFormat fmt = pdo->has_format ? pdo->format : AUDIO_FORMAT_S16;
uint32_t bytes_per_sample = audioformat_bytes_per_sample(fmt);
return samples_to_usecs(bytes / bytes_per_sample, pdo);
}
static void get_bytes_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
AudiodevPerDirectionOptions *pdo)
{
const char *val = getenv(env);
if (val) {
*dst = bytes_to_usecs(toui32(val), pdo);
*has_dst = true;
}
}
/* backend specific functions */
/* ALSA */
static void handle_alsa_per_direction(
AudiodevAlsaPerDirectionOptions *apdo, const char *prefix)
{
char buf[64];
size_t len = strlen(prefix);
bool size_in_usecs = false;
bool dummy;
memcpy(buf, prefix, len);
strcpy(buf + len, "TRY_POLL");
get_bool(buf, &apdo->try_poll, &apdo->has_try_poll);
strcpy(buf + len, "DEV");
get_str(buf, &apdo->dev, &apdo->has_dev);
strcpy(buf + len, "SIZE_IN_USEC");
get_bool(buf, &size_in_usecs, &dummy);
strcpy(buf + len, "PERIOD_SIZE");
get_int(buf, &apdo->period_length, &apdo->has_period_length);
if (apdo->has_period_length && !size_in_usecs) {
apdo->period_length = frames_to_usecs(
apdo->period_length,
qapi_AudiodevAlsaPerDirectionOptions_base(apdo));
}
strcpy(buf + len, "BUFFER_SIZE");
get_int(buf, &apdo->buffer_length, &apdo->has_buffer_length);
if (apdo->has_buffer_length && !size_in_usecs) {
apdo->buffer_length = frames_to_usecs(
apdo->buffer_length,
qapi_AudiodevAlsaPerDirectionOptions_base(apdo));
}
}
static void handle_alsa(Audiodev *dev)
{
AudiodevAlsaOptions *aopt = &dev->u.alsa;
handle_alsa_per_direction(aopt->in, "QEMU_ALSA_ADC_");
handle_alsa_per_direction(aopt->out, "QEMU_ALSA_DAC_");
get_millis_to_usecs("QEMU_ALSA_THRESHOLD",
&aopt->threshold, &aopt->has_threshold);
}
/* coreaudio */
static void handle_coreaudio(Audiodev *dev)
{
get_frames_to_usecs(
"QEMU_COREAUDIO_BUFFER_SIZE",
&dev->u.coreaudio.out->buffer_length,
&dev->u.coreaudio.out->has_buffer_length,
qapi_AudiodevCoreaudioPerDirectionOptions_base(dev->u.coreaudio.out));
get_int("QEMU_COREAUDIO_BUFFER_COUNT",
&dev->u.coreaudio.out->buffer_count,
&dev->u.coreaudio.out->has_buffer_count);
}
/* dsound */
static void handle_dsound(Audiodev *dev)
{
get_millis_to_usecs("QEMU_DSOUND_LATENCY_MILLIS",
&dev->u.dsound.latency, &dev->u.dsound.has_latency);
get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_OUT",
&dev->u.dsound.out->buffer_length,
&dev->u.dsound.out->has_buffer_length,
dev->u.dsound.out);
get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_IN",
&dev->u.dsound.in->buffer_length,
&dev->u.dsound.in->has_buffer_length,
dev->u.dsound.in);
}
/* OSS */
static void handle_oss_per_direction(
AudiodevOssPerDirectionOptions *opdo, const char *try_poll_env,
const char *dev_env)
{
get_bool(try_poll_env, &opdo->try_poll, &opdo->has_try_poll);
get_str(dev_env, &opdo->dev, &opdo->has_dev);
get_bytes_to_usecs("QEMU_OSS_FRAGSIZE",
&opdo->buffer_length, &opdo->has_buffer_length,
qapi_AudiodevOssPerDirectionOptions_base(opdo));
get_int("QEMU_OSS_NFRAGS", &opdo->buffer_count,
&opdo->has_buffer_count);
}
static void handle_oss(Audiodev *dev)
{
AudiodevOssOptions *oopt = &dev->u.oss;
handle_oss_per_direction(oopt->in, "QEMU_AUDIO_ADC_TRY_POLL",
"QEMU_OSS_ADC_DEV");
handle_oss_per_direction(oopt->out, "QEMU_AUDIO_DAC_TRY_POLL",
"QEMU_OSS_DAC_DEV");
get_bool("QEMU_OSS_MMAP", &oopt->try_mmap, &oopt->has_try_mmap);
get_bool("QEMU_OSS_EXCLUSIVE", &oopt->exclusive, &oopt->has_exclusive);
get_int("QEMU_OSS_POLICY", &oopt->dsp_policy, &oopt->has_dsp_policy);
}
/* pulseaudio */
static void handle_pa_per_direction(
AudiodevPaPerDirectionOptions *ppdo, const char *env)
{
get_str(env, &ppdo->name, &ppdo->has_name);
}
static void handle_pa(Audiodev *dev)
{
handle_pa_per_direction(dev->u.pa.in, "QEMU_PA_SOURCE");
handle_pa_per_direction(dev->u.pa.out, "QEMU_PA_SINK");
get_samples_to_usecs(
"QEMU_PA_SAMPLES", &dev->u.pa.in->buffer_length,
&dev->u.pa.in->has_buffer_length,
qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.in));
get_samples_to_usecs(
"QEMU_PA_SAMPLES", &dev->u.pa.out->buffer_length,
&dev->u.pa.out->has_buffer_length,
qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.out));
get_str("QEMU_PA_SERVER", &dev->u.pa.server, &dev->u.pa.has_server);
}
/* SDL */
static void handle_sdl(Audiodev *dev)
{
/* SDL is output only */
get_samples_to_usecs("QEMU_SDL_SAMPLES", &dev->u.sdl.out->buffer_length,
&dev->u.sdl.out->has_buffer_length, dev->u.sdl.out);
}
/* wav */
static void handle_wav(Audiodev *dev)
{
get_int("QEMU_WAV_FREQUENCY",
&dev->u.wav.out->frequency, &dev->u.wav.out->has_frequency);
get_fmt("QEMU_WAV_FORMAT", &dev->u.wav.out->format,
&dev->u.wav.out->has_format);
get_int("QEMU_WAV_DAC_FIXED_CHANNELS",
&dev->u.wav.out->channels, &dev->u.wav.out->has_channels);
get_str("QEMU_WAV_PATH", &dev->u.wav.path, &dev->u.wav.has_path);
}
/* general */
static void handle_per_direction(
AudiodevPerDirectionOptions *pdo, const char *prefix)
{
char buf[64];
size_t len = strlen(prefix);
memcpy(buf, prefix, len);
strcpy(buf + len, "FIXED_SETTINGS");
get_bool(buf, &pdo->fixed_settings, &pdo->has_fixed_settings);
strcpy(buf + len, "FIXED_FREQ");
get_int(buf, &pdo->frequency, &pdo->has_frequency);
strcpy(buf + len, "FIXED_FMT");
get_fmt(buf, &pdo->format, &pdo->has_format);
strcpy(buf + len, "FIXED_CHANNELS");
get_int(buf, &pdo->channels, &pdo->has_channels);
strcpy(buf + len, "VOICES");
get_int(buf, &pdo->voices, &pdo->has_voices);
}
static AudiodevListEntry *legacy_opt(const char *drvname)
{
AudiodevListEntry *e = g_malloc0(sizeof(AudiodevListEntry));
e->dev = g_malloc0(sizeof(Audiodev));
e->dev->id = g_strdup(drvname);
e->dev->driver = qapi_enum_parse(
&AudiodevDriver_lookup, drvname, -1, &error_abort);
audio_create_pdos(e->dev);
handle_per_direction(audio_get_pdo_in(e->dev), "QEMU_AUDIO_ADC_");
handle_per_direction(audio_get_pdo_out(e->dev), "QEMU_AUDIO_DAC_");
/* Original description: Timer period in HZ (0 - use lowest possible) */
get_int("QEMU_AUDIO_TIMER_PERIOD",
&e->dev->timer_period, &e->dev->has_timer_period);
if (e->dev->has_timer_period && e->dev->timer_period) {
e->dev->timer_period = NANOSECONDS_PER_SECOND / 1000 /
e->dev->timer_period;
}
switch (e->dev->driver) {
case AUDIODEV_DRIVER_ALSA:
handle_alsa(e->dev);
break;
case AUDIODEV_DRIVER_COREAUDIO:
handle_coreaudio(e->dev);
break;
case AUDIODEV_DRIVER_DSOUND:
handle_dsound(e->dev);
break;
case AUDIODEV_DRIVER_OSS:
handle_oss(e->dev);
break;
case AUDIODEV_DRIVER_PA:
handle_pa(e->dev);
break;
case AUDIODEV_DRIVER_SDL:
handle_sdl(e->dev);
break;
case AUDIODEV_DRIVER_WAV:
handle_wav(e->dev);
break;
default:
break;
}
return e;
}
AudiodevListHead audio_handle_legacy_opts(void)
{
const char *drvname = getenv("QEMU_AUDIO_DRV");
AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head);
if (drvname) {
AudiodevListEntry *e;
audio_driver *driver = audio_driver_lookup(drvname);
if (!driver) {
dolog("Unknown audio driver `%s'\n", drvname);
exit(1);
}
e = legacy_opt(drvname);
QSIMPLEQ_INSERT_TAIL(&head, e, next);
} else {
for (int i = 0; audio_prio_list[i]; i++) {
audio_driver *driver = audio_driver_lookup(audio_prio_list[i]);
if (driver && driver->can_be_default) {
AudiodevListEntry *e = legacy_opt(driver->name);
QSIMPLEQ_INSERT_TAIL(&head, e, next);
}
}
if (QSIMPLEQ_EMPTY(&head)) {
dolog("Internal error: no default audio driver available\n");
exit(1);
}
}
return head;
}
/* visitor to print -audiodev option */
typedef struct {
Visitor visitor;
bool comma;
GList *path;
} LegacyPrintVisitor;
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));
}
static void lv_end_struct(Visitor *v, void **obj)
{
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
lv->path = g_list_delete_link(lv->path, g_list_last(lv->path));
}
static void lv_print_key(Visitor *v, const char *name)
{
GList *e;
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
if (lv->comma) {
putchar(',');
} else {
lv->comma = true;
}
for (e = lv->path; e; e = e->next) {
if (e->data) {
printf("%s.", (const char *) e->data);
}
}
printf("%s=", name);
}
static void lv_type_int64(Visitor *v, const char *name, int64_t *obj,
Error **errp)
{
lv_print_key(v, name);
printf("%" PRIi64, *obj);
}
static void lv_type_uint64(Visitor *v, const char *name, uint64_t *obj,
Error **errp)
{
lv_print_key(v, name);
printf("%" PRIu64, *obj);
}
static void lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
{
lv_print_key(v, name);
printf("%s", *obj ? "on" : "off");
}
static void lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
{
const char *str = *obj;
lv_print_key(v, name);
while (*str) {
if (*str == ',') {
putchar(',');
}
putchar(*str++);
}
}
static void lv_complete(Visitor *v, void *opaque)
{
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
assert(lv->path == NULL);
}
static void lv_free(Visitor *v)
{
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
g_list_free_full(lv->path, g_free);
g_free(lv);
}
static Visitor *legacy_visitor_new(void)
{
LegacyPrintVisitor *lv = g_malloc0(sizeof(LegacyPrintVisitor));
lv->visitor.start_struct = lv_start_struct;
lv->visitor.end_struct = lv_end_struct;
/* lists not supported */
lv->visitor.type_int64 = lv_type_int64;
lv->visitor.type_uint64 = lv_type_uint64;
lv->visitor.type_bool = lv_type_bool;
lv->visitor.type_str = lv_type_str;
lv->visitor.type = VISITOR_OUTPUT;
lv->visitor.complete = lv_complete;
lv->visitor.free = lv_free;
return &lv->visitor;
}
void audio_legacy_help(void)
{
AudiodevListHead head;
AudiodevListEntry *e;
printf("Environment variable based configuration deprecated.\n");
printf("Please use the new -audiodev option.\n");
head = audio_handle_legacy_opts();
printf("\nEquivalent -audiodev to your current environment variables:\n");
if (!getenv("QEMU_AUDIO_DRV")) {
printf("(Since you didn't specify QEMU_AUDIO_DRV, I'll list all "
"possibilities)\n");
}
QSIMPLEQ_FOREACH(e, &head, next) {
Visitor *v;
Audiodev *dev = e->dev;
printf("-audiodev ");
v = legacy_visitor_new();
visit_type_Audiodev(v, NULL, &dev, &error_abort);
visit_free(v);
printf("\n");
}
audio_free_audiodev_list(&head);
}

View File

@@ -1,4 +1,5 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "audio.h" #include "audio.h"
#define AUDIO_CAP "audio-pt" #define AUDIO_CAP "audio-pt"

View File

@@ -299,42 +299,11 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
return NULL; return NULL;
} }
AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
{
switch (dev->driver) {
case AUDIODEV_DRIVER_NONE:
return dev->u.none.TYPE;
case AUDIODEV_DRIVER_ALSA:
return qapi_AudiodevAlsaPerDirectionOptions_base(dev->u.alsa.TYPE);
case AUDIODEV_DRIVER_COREAUDIO:
return qapi_AudiodevCoreaudioPerDirectionOptions_base(
dev->u.coreaudio.TYPE);
case AUDIODEV_DRIVER_DSOUND:
return dev->u.dsound.TYPE;
case AUDIODEV_DRIVER_OSS:
return qapi_AudiodevOssPerDirectionOptions_base(dev->u.oss.TYPE);
case AUDIODEV_DRIVER_PA:
return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
case AUDIODEV_DRIVER_SDL:
return dev->u.sdl.TYPE;
case AUDIODEV_DRIVER_SPICE:
return dev->u.spice.TYPE;
case AUDIODEV_DRIVER_WAV:
return dev->u.wav.TYPE;
case AUDIODEV_DRIVER__MAX:
break;
}
abort();
}
static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as) static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
{ {
HW *hw; HW *hw;
AudioState *s = &glob_audio_state;
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
if (pdo->fixed_settings) { if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
hw = glue (audio_pcm_hw_add_new_, TYPE) (as); hw = glue (audio_pcm_hw_add_new_, TYPE) (as);
if (hw) { if (hw) {
return hw; return hw;
@@ -362,11 +331,9 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
SW *sw; SW *sw;
HW *hw; HW *hw;
struct audsettings hw_as; struct audsettings hw_as;
AudioState *s = &glob_audio_state;
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
if (pdo->fixed_settings) { if (glue (conf.fixed_, TYPE).enabled) {
hw_as = audiodev_to_audsettings(pdo); hw_as = glue (conf.fixed_, TYPE).settings;
} }
else { else {
hw_as = *as; hw_as = *as;
@@ -431,7 +398,6 @@ SW *glue (AUD_open_, TYPE) (
) )
{ {
AudioState *s = &glob_audio_state; AudioState *s = &glob_audio_state;
AudiodevPerDirectionOptions *pdo = glue(audio_get_pdo_, TYPE)(s->dev);
if (audio_bug(__func__, !card || !name || !callback_fn || !as)) { if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
dolog ("card=%p name=%p callback_fn=%p as=%p\n", dolog ("card=%p name=%p callback_fn=%p as=%p\n",
@@ -456,7 +422,7 @@ SW *glue (AUD_open_, TYPE) (
return sw; return sw;
} }
if (!pdo->fixed_settings && sw) { if (!glue (conf.fixed_, TYPE).enabled && sw) {
glue (AUD_close_, TYPE) (card, sw); glue (AUD_close_, TYPE) (card, sw);
sw = NULL; sw = NULL;
} }

View File

@@ -24,20 +24,20 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
wfx->cbSize = 0; wfx->cbSize = 0;
switch (as->fmt) { switch (as->fmt) {
case AUDIO_FORMAT_S8: case AUD_FMT_S8:
case AUDIO_FORMAT_U8: case AUD_FMT_U8:
wfx->wBitsPerSample = 8; wfx->wBitsPerSample = 8;
break; break;
case AUDIO_FORMAT_S16: case AUD_FMT_S16:
case AUDIO_FORMAT_U16: case AUD_FMT_U16:
wfx->wBitsPerSample = 16; wfx->wBitsPerSample = 16;
wfx->nAvgBytesPerSec <<= 1; wfx->nAvgBytesPerSec <<= 1;
wfx->nBlockAlign <<= 1; wfx->nBlockAlign <<= 1;
break; break;
case AUDIO_FORMAT_S32: case AUD_FMT_S32:
case AUDIO_FORMAT_U32: case AUD_FMT_U32:
wfx->wBitsPerSample = 32; wfx->wBitsPerSample = 32;
wfx->nAvgBytesPerSec <<= 2; wfx->nAvgBytesPerSec <<= 2;
wfx->nBlockAlign <<= 2; wfx->nBlockAlign <<= 2;
@@ -85,15 +85,15 @@ int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
switch (wfx->wBitsPerSample) { switch (wfx->wBitsPerSample) {
case 8: case 8:
as->fmt = AUDIO_FORMAT_U8; as->fmt = AUD_FMT_U8;
break; break;
case 16: case 16:
as->fmt = AUDIO_FORMAT_S16; as->fmt = AUD_FMT_S16;
break; break;
case 32: case 32:
as->fmt = AUDIO_FORMAT_S32; as->fmt = AUD_FMT_S32;
break; break;
default: default:

View File

@@ -26,7 +26,7 @@
#include <CoreAudio/CoreAudio.h> #include <CoreAudio/CoreAudio.h>
#include <pthread.h> /* pthread_X */ #include <pthread.h> /* pthread_X */
#include "qemu/module.h" #include "qemu-common.h"
#include "audio.h" #include "audio.h"
#define AUDIO_CAP "coreaudio" #define AUDIO_CAP "coreaudio"
@@ -36,6 +36,11 @@
#define MAC_OS_X_VERSION_10_6 1060 #define MAC_OS_X_VERSION_10_6 1060
#endif #endif
typedef struct {
int buffer_frames;
int nbuffers;
} CoreaudioConf;
typedef struct coreaudioVoiceOut { typedef struct coreaudioVoiceOut {
HWVoiceOut hw; HWVoiceOut hw;
pthread_mutex_t mutex; pthread_mutex_t mutex;
@@ -502,9 +507,7 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
int err; int err;
const char *typ = "playback"; const char *typ = "playback";
AudioValueRange frameRange; AudioValueRange frameRange;
Audiodev *dev = drv_opaque; CoreaudioConf *conf = drv_opaque;
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
int frames;
/* create mutex */ /* create mutex */
err = pthread_mutex_init(&core->mutex, NULL); err = pthread_mutex_init(&core->mutex, NULL);
@@ -535,17 +538,16 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
return -1; return -1;
} }
frames = audio_buffer_frames( if (frameRange.mMinimum > conf->buffer_frames) {
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
if (frameRange.mMinimum > frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum; core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum); dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
} else if (frameRange.mMaximum < frames) { }
else if (frameRange.mMaximum < conf->buffer_frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum; core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum); dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
} }
else { else {
core->audioDevicePropertyBufferFrameSize = frames; core->audioDevicePropertyBufferFrameSize = conf->buffer_frames;
} }
/* set Buffer Frame Size */ /* set Buffer Frame Size */
@@ -566,8 +568,7 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
"Could not get device buffer frame size\n"); "Could not get device buffer frame size\n");
return -1; return -1;
} }
hw->samples = (cpdo->has_buffer_count ? cpdo->buffer_count : 4) * hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */ /* get StreamFormat */
status = coreaudio_get_streamformat(core->outputDeviceID, status = coreaudio_get_streamformat(core->outputDeviceID,
@@ -679,15 +680,40 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0; return 0;
} }
static void *coreaudio_audio_init(Audiodev *dev) static CoreaudioConf glob_conf = {
.buffer_frames = 512,
.nbuffers = 4,
};
static void *coreaudio_audio_init (void)
{ {
return dev; CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf));
*conf = glob_conf;
return conf;
} }
static void coreaudio_audio_fini (void *opaque) static void coreaudio_audio_fini (void *opaque)
{ {
g_free(opaque);
} }
static struct audio_option coreaudio_options[] = {
{
.name = "BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &glob_conf.buffer_frames,
.descr = "Size of the buffer in frames"
},
{
.name = "BUFFER_COUNT",
.tag = AUD_OPT_INT,
.valp = &glob_conf.nbuffers,
.descr = "Number of buffers"
},
{ /* End of list */ }
};
static struct audio_pcm_ops coreaudio_pcm_ops = { static struct audio_pcm_ops coreaudio_pcm_ops = {
.init_out = coreaudio_init_out, .init_out = coreaudio_init_out,
.fini_out = coreaudio_fini_out, .fini_out = coreaudio_fini_out,
@@ -699,6 +725,7 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
static struct audio_driver coreaudio_audio_driver = { static struct audio_driver coreaudio_audio_driver = {
.name = "coreaudio", .name = "coreaudio",
.descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html", .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
.options = coreaudio_options,
.init = coreaudio_audio_init, .init = coreaudio_audio_init,
.fini = coreaudio_audio_fini, .fini = coreaudio_audio_fini,
.pcm_ops = &coreaudio_pcm_ops, .pcm_ops = &coreaudio_pcm_ops,

View File

@@ -167,18 +167,17 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
dsound *s = drv_opaque; dsound *s = drv_opaque;
WAVEFORMATEX wfx; WAVEFORMATEX wfx;
struct audsettings obt_as; struct audsettings obt_as;
DSoundConf *conf = &s->conf;
#ifdef DSBTYPE_IN #ifdef DSBTYPE_IN
const char *typ = "ADC"; const char *typ = "ADC";
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
DSCBUFFERDESC bd; DSCBUFFERDESC bd;
DSCBCAPS bc; DSCBCAPS bc;
AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.in;
#else #else
const char *typ = "DAC"; const char *typ = "DAC";
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
DSBUFFERDESC bd; DSBUFFERDESC bd;
DSBCAPS bc; DSBCAPS bc;
AudiodevPerDirectionOptions *pdo = s->dev->u.dsound.out;
#endif #endif
if (!s->FIELD2) { if (!s->FIELD2) {
@@ -194,8 +193,8 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
memset (&bd, 0, sizeof (bd)); memset (&bd, 0, sizeof (bd));
bd.dwSize = sizeof (bd); bd.dwSize = sizeof (bd);
bd.lpwfxFormat = &wfx; bd.lpwfxFormat = &wfx;
bd.dwBufferBytes = audio_buffer_bytes(pdo, as, 92880);
#ifdef DSBTYPE_IN #ifdef DSBTYPE_IN
bd.dwBufferBytes = conf->bufsize_in;
hr = IDirectSoundCapture_CreateCaptureBuffer ( hr = IDirectSoundCapture_CreateCaptureBuffer (
s->dsound_capture, s->dsound_capture,
&bd, &bd,
@@ -204,6 +203,7 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
); );
#else #else
bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
bd.dwBufferBytes = conf->bufsize_out;
hr = IDirectSound_CreateSoundBuffer ( hr = IDirectSound_CreateSoundBuffer (
s->dsound, s->dsound,
&bd, &bd,

View File

@@ -27,12 +27,11 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "audio.h" #include "audio.h"
#define AUDIO_CAP "dsound" #define AUDIO_CAP "dsound"
#include "audio_int.h" #include "audio_int.h"
#include "qemu/host-utils.h"
#include "qemu/module.h"
#include <windows.h> #include <windows.h>
#include <mmsystem.h> #include <mmsystem.h>
@@ -43,11 +42,17 @@
/* #define DEBUG_DSOUND */ /* #define DEBUG_DSOUND */
typedef struct {
int bufsize_in;
int bufsize_out;
int latency_millis;
} DSoundConf;
typedef struct { typedef struct {
LPDIRECTSOUND dsound; LPDIRECTSOUND dsound;
LPDIRECTSOUNDCAPTURE dsound_capture; LPDIRECTSOUNDCAPTURE dsound_capture;
struct audsettings settings; struct audsettings settings;
Audiodev *dev; DSoundConf conf;
} dsound; } dsound;
typedef struct { typedef struct {
@@ -243,9 +248,9 @@ static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
dsound_log_hresult (hr); dsound_log_hresult (hr);
} }
static uint64_t usecs_to_bytes(struct audio_pcm_info *info, uint32_t usecs) static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis)
{ {
return muldiv64(usecs, info->bytes_per_second, 1000000); return (millis * info->bytes_per_second) / 1000;
} }
#ifdef DEBUG_DSOUND #ifdef DEBUG_DSOUND
@@ -473,7 +478,7 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
LPVOID p1, p2; LPVOID p1, p2;
int bufsize; int bufsize;
dsound *s = ds->s; dsound *s = ds->s;
AudiodevDsoundOptions *dso = &s->dev->u.dsound; DSoundConf *conf = &s->conf;
if (!dsb) { if (!dsb) {
dolog ("Attempt to run empty with playback buffer\n"); dolog ("Attempt to run empty with playback buffer\n");
@@ -496,14 +501,14 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
len = live << hwshift; len = live << hwshift;
if (ds->first_time) { if (ds->first_time) {
if (dso->latency) { if (conf->latency_millis) {
DWORD cur_blat; DWORD cur_blat;
cur_blat = audio_ring_dist (wpos, ppos, bufsize); cur_blat = audio_ring_dist (wpos, ppos, bufsize);
ds->first_time = 0; ds->first_time = 0;
old_pos = wpos; old_pos = wpos;
old_pos += old_pos +=
usecs_to_bytes(&hw->info, dso->latency) - cur_blat; millis_to_bytes (&hw->info, conf->latency_millis) - cur_blat;
old_pos %= bufsize; old_pos %= bufsize;
old_pos &= ~hw->info.align; old_pos &= ~hw->info.align;
} }
@@ -742,6 +747,12 @@ static int dsound_run_in (HWVoiceIn *hw)
return decr; return decr;
} }
static DSoundConf glob_conf = {
.bufsize_in = 16384,
.bufsize_out = 16384,
.latency_millis = 10
};
static void dsound_audio_fini (void *opaque) static void dsound_audio_fini (void *opaque)
{ {
HRESULT hr; HRESULT hr;
@@ -772,22 +783,13 @@ static void dsound_audio_fini (void *opaque)
g_free(s); g_free(s);
} }
static void *dsound_audio_init(Audiodev *dev) static void *dsound_audio_init (void)
{ {
int err; int err;
HRESULT hr; HRESULT hr;
dsound *s = g_malloc0(sizeof(dsound)); dsound *s = g_malloc0(sizeof(dsound));
AudiodevDsoundOptions *dso;
assert(dev->driver == AUDIODEV_DRIVER_DSOUND);
s->dev = dev;
dso = &dev->u.dsound;
if (!dso->has_latency) {
dso->has_latency = true;
dso->latency = 10000; /* 10 ms */
}
s->conf = glob_conf;
hr = CoInitialize (NULL); hr = CoInitialize (NULL);
if (FAILED (hr)) { if (FAILED (hr)) {
dsound_logerr (hr, "Could not initialize COM\n"); dsound_logerr (hr, "Could not initialize COM\n");
@@ -852,6 +854,28 @@ static void *dsound_audio_init(Audiodev *dev)
return s; return s;
} }
static struct audio_option dsound_options[] = {
{
.name = "LATENCY_MILLIS",
.tag = AUD_OPT_INT,
.valp = &glob_conf.latency_millis,
.descr = "(undocumented)"
},
{
.name = "BUFSIZE_OUT",
.tag = AUD_OPT_INT,
.valp = &glob_conf.bufsize_out,
.descr = "(undocumented)"
},
{
.name = "BUFSIZE_IN",
.tag = AUD_OPT_INT,
.valp = &glob_conf.bufsize_in,
.descr = "(undocumented)"
},
{ /* End of list */ }
};
static struct audio_pcm_ops dsound_pcm_ops = { static struct audio_pcm_ops dsound_pcm_ops = {
.init_out = dsound_init_out, .init_out = dsound_init_out,
.fini_out = dsound_fini_out, .fini_out = dsound_fini_out,
@@ -869,6 +893,7 @@ static struct audio_pcm_ops dsound_pcm_ops = {
static struct audio_driver dsound_audio_driver = { static struct audio_driver dsound_audio_driver = {
.name = "dsound", .name = "dsound",
.descr = "DirectSound http://wikipedia.org/wiki/DirectSound", .descr = "DirectSound http://wikipedia.org/wiki/DirectSound",
.options = dsound_options,
.init = dsound_audio_init, .init = dsound_audio_init,
.fini = dsound_audio_fini, .fini = dsound_audio_fini,
.pcm_ops = &dsound_pcm_ops, .pcm_ops = &dsound_pcm_ops,

View File

@@ -23,6 +23,7 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/bswap.h" #include "qemu/bswap.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "audio.h" #include "audio.h"

View File

@@ -21,10 +21,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "qemu/module.h"
#include "audio.h" #include "audio.h"
#include "qemu/timer.h" #include "qemu/timer.h"
@@ -137,7 +136,7 @@ static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
return 0; return 0;
} }
static void *no_audio_init(Audiodev *dev) static void *no_audio_init (void)
{ {
return &no_audio_init; return &no_audio_init;
} }
@@ -164,6 +163,7 @@ static struct audio_pcm_ops no_pcm_ops = {
static struct audio_driver no_audio_driver = { static struct audio_driver no_audio_driver = {
.name = "none", .name = "none",
.descr = "Timer based audio emulation", .descr = "Timer based audio emulation",
.options = NULL,
.init = no_audio_init, .init = no_audio_init,
.fini = no_audio_fini, .fini = no_audio_fini,
.pcm_ops = &no_pcm_ops, .pcm_ops = &no_pcm_ops,

View File

@@ -21,12 +21,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/soundcard.h> #include <sys/soundcard.h>
#include "qemu-common.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "audio.h" #include "audio.h"
#include "trace.h" #include "trace.h"
@@ -38,6 +37,16 @@
#define USE_DSP_POLICY #define USE_DSP_POLICY
#endif #endif
typedef struct OSSConf {
int try_mmap;
int nfrags;
int fragsize;
const char *devpath_out;
const char *devpath_in;
int exclusive;
int policy;
} OSSConf;
typedef struct OSSVoiceOut { typedef struct OSSVoiceOut {
HWVoiceOut hw; HWVoiceOut hw;
void *pcm_buf; void *pcm_buf;
@@ -47,7 +56,7 @@ typedef struct OSSVoiceOut {
int fragsize; int fragsize;
int mmapped; int mmapped;
int pending; int pending;
Audiodev *dev; OSSConf *conf;
} OSSVoiceOut; } OSSVoiceOut;
typedef struct OSSVoiceIn { typedef struct OSSVoiceIn {
@@ -56,12 +65,12 @@ typedef struct OSSVoiceIn {
int fd; int fd;
int nfrags; int nfrags;
int fragsize; int fragsize;
Audiodev *dev; OSSConf *conf;
} OSSVoiceIn; } OSSVoiceIn;
struct oss_params { struct oss_params {
int freq; int freq;
int fmt; audfmt_e fmt;
int nchannels; int nchannels;
int nfrags; int nfrags;
int fragsize; int fragsize;
@@ -139,16 +148,16 @@ static int oss_write (SWVoiceOut *sw, void *buf, int len)
return audio_pcm_sw_write (sw, buf, len); return audio_pcm_sw_write (sw, buf, len);
} }
static int aud_to_ossfmt (AudioFormat fmt, int endianness) static int aud_to_ossfmt (audfmt_e fmt, int endianness)
{ {
switch (fmt) { switch (fmt) {
case AUDIO_FORMAT_S8: case AUD_FMT_S8:
return AFMT_S8; return AFMT_S8;
case AUDIO_FORMAT_U8: case AUD_FMT_U8:
return AFMT_U8; return AFMT_U8;
case AUDIO_FORMAT_S16: case AUD_FMT_S16:
if (endianness) { if (endianness) {
return AFMT_S16_BE; return AFMT_S16_BE;
} }
@@ -156,7 +165,7 @@ static int aud_to_ossfmt (AudioFormat fmt, int endianness)
return AFMT_S16_LE; return AFMT_S16_LE;
} }
case AUDIO_FORMAT_U16: case AUD_FMT_U16:
if (endianness) { if (endianness) {
return AFMT_U16_BE; return AFMT_U16_BE;
} }
@@ -173,37 +182,37 @@ static int aud_to_ossfmt (AudioFormat fmt, int endianness)
} }
} }
static int oss_to_audfmt (int ossfmt, AudioFormat *fmt, int *endianness) static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
{ {
switch (ossfmt) { switch (ossfmt) {
case AFMT_S8: case AFMT_S8:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_S8; *fmt = AUD_FMT_S8;
break; break;
case AFMT_U8: case AFMT_U8:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_U8; *fmt = AUD_FMT_U8;
break; break;
case AFMT_S16_LE: case AFMT_S16_LE:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_S16; *fmt = AUD_FMT_S16;
break; break;
case AFMT_U16_LE: case AFMT_U16_LE:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_U16; *fmt = AUD_FMT_U16;
break; break;
case AFMT_S16_BE: case AFMT_S16_BE:
*endianness = 1; *endianness = 1;
*fmt = AUDIO_FORMAT_S16; *fmt = AUD_FMT_S16;
break; break;
case AFMT_U16_BE: case AFMT_U16_BE:
*endianness = 1; *endianness = 1;
*fmt = AUDIO_FORMAT_U16; *fmt = AUD_FMT_U16;
break; break;
default: default:
@@ -253,25 +262,19 @@ static int oss_get_version (int fd, int *version, const char *typ)
} }
#endif #endif
static int oss_open(int in, struct oss_params *req, audsettings *as, static int oss_open (int in, struct oss_params *req,
struct oss_params *obt, int *pfd, Audiodev *dev) struct oss_params *obt, int *pfd, OSSConf* conf)
{ {
AudiodevOssOptions *oopts = &dev->u.oss;
AudiodevOssPerDirectionOptions *opdo = in ? oopts->in : oopts->out;
int fd; int fd;
int oflags = (oopts->has_exclusive && oopts->exclusive) ? O_EXCL : 0; int oflags = conf->exclusive ? O_EXCL : 0;
audio_buf_info abinfo; audio_buf_info abinfo;
int fmt, freq, nchannels; int fmt, freq, nchannels;
int setfragment = 1; int setfragment = 1;
const char *dspname = opdo->has_dev ? opdo->dev : "/dev/dsp"; const char *dspname = in ? conf->devpath_in : conf->devpath_out;
const char *typ = in ? "ADC" : "DAC"; const char *typ = in ? "ADC" : "DAC";
#ifdef USE_DSP_POLICY
int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5;
#endif
/* Kludge needed to have working mmap on Linux */ /* Kludge needed to have working mmap on Linux */
oflags |= (oopts->has_try_mmap && oopts->try_mmap) ? oflags |= conf->try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
O_RDWR : (in ? O_RDONLY : O_WRONLY);
fd = open (dspname, oflags | O_NONBLOCK); fd = open (dspname, oflags | O_NONBLOCK);
if (-1 == fd) { if (-1 == fd) {
@@ -282,9 +285,6 @@ static int oss_open(int in, struct oss_params *req, audsettings *as,
freq = req->freq; freq = req->freq;
nchannels = req->nchannels; nchannels = req->nchannels;
fmt = req->fmt; fmt = req->fmt;
req->nfrags = opdo->has_buffer_count ? opdo->buffer_count : 4;
req->fragsize = audio_buffer_bytes(
qapi_AudiodevOssPerDirectionOptions_base(opdo), as, 23220);
if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt); oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
@@ -308,18 +308,18 @@ static int oss_open(int in, struct oss_params *req, audsettings *as,
} }
#ifdef USE_DSP_POLICY #ifdef USE_DSP_POLICY
if (policy >= 0) { if (conf->policy >= 0) {
int version; int version;
if (!oss_get_version (fd, &version, typ)) { if (!oss_get_version (fd, &version, typ)) {
trace_oss_version(version); trace_oss_version(version);
if (version >= 0x040000) { if (version >= 0x040000) {
int policy2 = policy; int policy = conf->policy;
if (ioctl(fd, SNDCTL_DSP_POLICY, &policy2)) { if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
oss_logerr2 (errno, typ, oss_logerr2 (errno, typ,
"Failed to set timing policy to %d\n", "Failed to set timing policy to %d\n",
policy); conf->policy);
goto err; goto err;
} }
setfragment = 0; setfragment = 0;
@@ -500,18 +500,19 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
int endianness; int endianness;
int err; int err;
int fd; int fd;
AudioFormat effective_fmt; audfmt_e effective_fmt;
struct audsettings obt_as; struct audsettings obt_as;
Audiodev *dev = drv_opaque; OSSConf *conf = drv_opaque;
AudiodevOssOptions *oopts = &dev->u.oss;
oss->fd = -1; oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt, as->endianness); req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
req.freq = as->freq; req.freq = as->freq;
req.nchannels = as->nchannels; req.nchannels = as->nchannels;
req.fragsize = conf->fragsize;
req.nfrags = conf->nfrags;
if (oss_open(0, &req, as, &obt, &fd, dev)) { if (oss_open (0, &req, &obt, &fd, conf)) {
return -1; return -1;
} }
@@ -538,7 +539,7 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
oss->mmapped = 0; oss->mmapped = 0;
if (oopts->has_try_mmap && oopts->try_mmap) { if (conf->try_mmap) {
oss->pcm_buf = mmap ( oss->pcm_buf = mmap (
NULL, NULL,
hw->samples << hw->info.shift, hw->samples << hw->info.shift,
@@ -596,7 +597,7 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
} }
oss->fd = fd; oss->fd = fd;
oss->dev = dev; oss->conf = conf;
return 0; return 0;
} }
@@ -604,12 +605,16 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
{ {
int trig; int trig;
OSSVoiceOut *oss = (OSSVoiceOut *) hw; OSSVoiceOut *oss = (OSSVoiceOut *) hw;
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
switch (cmd) { switch (cmd) {
case VOICE_ENABLE: case VOICE_ENABLE:
{ {
bool poll_mode = opdo->try_poll; va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
ldebug ("enabling voice\n"); ldebug ("enabling voice\n");
if (poll_mode) { if (poll_mode) {
@@ -662,16 +667,18 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
int endianness; int endianness;
int err; int err;
int fd; int fd;
AudioFormat effective_fmt; audfmt_e effective_fmt;
struct audsettings obt_as; struct audsettings obt_as;
Audiodev *dev = drv_opaque; OSSConf *conf = drv_opaque;
oss->fd = -1; oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt, as->endianness); req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
req.freq = as->freq; req.freq = as->freq;
req.nchannels = as->nchannels; req.nchannels = as->nchannels;
if (oss_open(1, &req, as, &obt, &fd, dev)) { req.fragsize = conf->fragsize;
req.nfrags = conf->nfrags;
if (oss_open (1, &req, &obt, &fd, conf)) {
return -1; return -1;
} }
@@ -705,7 +712,7 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
} }
oss->fd = fd; oss->fd = fd;
oss->dev = dev; oss->conf = conf;
return 0; return 0;
} }
@@ -796,12 +803,16 @@ static int oss_read (SWVoiceIn *sw, void *buf, int size)
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
{ {
OSSVoiceIn *oss = (OSSVoiceIn *) hw; OSSVoiceIn *oss = (OSSVoiceIn *) hw;
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
switch (cmd) { switch (cmd) {
case VOICE_ENABLE: case VOICE_ENABLE:
{ {
bool poll_mode = opdo->try_poll; va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
if (poll_mode) { if (poll_mode) {
oss_poll_in (hw); oss_poll_in (hw);
@@ -821,36 +832,82 @@ static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
return 0; return 0;
} }
static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo) static OSSConf glob_conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp",
.exclusive = 0,
.policy = 5
};
static void *oss_audio_init (void)
{ {
if (!opdo->has_try_poll) { OSSConf *conf = g_malloc(sizeof(OSSConf));
opdo->try_poll = true; *conf = glob_conf;
opdo->has_try_poll = true;
}
}
static void *oss_audio_init(Audiodev *dev) if (access(conf->devpath_in, R_OK | W_OK) < 0 ||
{ access(conf->devpath_out, R_OK | W_OK) < 0) {
AudiodevOssOptions *oopts; g_free(conf);
assert(dev->driver == AUDIODEV_DRIVER_OSS);
oopts = &dev->u.oss;
oss_init_per_direction(oopts->in);
oss_init_per_direction(oopts->out);
if (access(oopts->in->has_dev ? oopts->in->dev : "/dev/dsp",
R_OK | W_OK) < 0 ||
access(oopts->out->has_dev ? oopts->out->dev : "/dev/dsp",
R_OK | W_OK) < 0) {
return NULL; return NULL;
} }
return dev; return conf;
} }
static void oss_audio_fini (void *opaque) static void oss_audio_fini (void *opaque)
{ {
g_free(opaque);
} }
static struct audio_option oss_options[] = {
{
.name = "FRAGSIZE",
.tag = AUD_OPT_INT,
.valp = &glob_conf.fragsize,
.descr = "Fragment size in bytes"
},
{
.name = "NFRAGS",
.tag = AUD_OPT_INT,
.valp = &glob_conf.nfrags,
.descr = "Number of fragments"
},
{
.name = "MMAP",
.tag = AUD_OPT_BOOL,
.valp = &glob_conf.try_mmap,
.descr = "Try using memory mapped access"
},
{
.name = "DAC_DEV",
.tag = AUD_OPT_STR,
.valp = &glob_conf.devpath_out,
.descr = "Path to DAC device"
},
{
.name = "ADC_DEV",
.tag = AUD_OPT_STR,
.valp = &glob_conf.devpath_in,
.descr = "Path to ADC device"
},
{
.name = "EXCLUSIVE",
.tag = AUD_OPT_BOOL,
.valp = &glob_conf.exclusive,
.descr = "Open device in exclusive mode (vmix won't work)"
},
#ifdef USE_DSP_POLICY
{
.name = "POLICY",
.tag = AUD_OPT_INT,
.valp = &glob_conf.policy,
.descr = "Set the timing policy of the device, -1 to use fragment mode",
},
#endif
{ /* End of list */ }
};
static struct audio_pcm_ops oss_pcm_ops = { static struct audio_pcm_ops oss_pcm_ops = {
.init_out = oss_init_out, .init_out = oss_init_out,
.fini_out = oss_fini_out, .fini_out = oss_fini_out,
@@ -868,6 +925,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
static struct audio_driver oss_audio_driver = { static struct audio_driver oss_audio_driver = {
.name = "oss", .name = "oss",
.descr = "OSS http://www.opensound.com", .descr = "OSS http://www.opensound.com",
.options = oss_options,
.init = oss_audio_init, .init = oss_audio_init,
.fini = oss_audio_fini, .fini = oss_audio_fini,
.pcm_ops = &oss_pcm_ops, .pcm_ops = &oss_pcm_ops,

View File

@@ -1,9 +1,7 @@
/* public domain */ /* public domain */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/module.h" #include "qemu-common.h"
#include "audio.h" #include "audio.h"
#include "qapi/opts-visitor.h"
#include <pulse/pulseaudio.h> #include <pulse/pulseaudio.h>
@@ -12,7 +10,14 @@
#include "audio_pt_int.h" #include "audio_pt_int.h"
typedef struct { typedef struct {
Audiodev *dev; int samples;
char *server;
char *sink;
char *source;
} PAConf;
typedef struct {
PAConf conf;
pa_threaded_mainloop *mainloop; pa_threaded_mainloop *mainloop;
pa_context *context; pa_context *context;
} paaudio; } paaudio;
@@ -27,7 +32,6 @@ typedef struct {
void *pcm_buf; void *pcm_buf;
struct audio_pt pt; struct audio_pt pt;
paaudio *g; paaudio *g;
int samples;
} PAVoiceOut; } PAVoiceOut;
typedef struct { typedef struct {
@@ -42,7 +46,6 @@ typedef struct {
const void *read_data; const void *read_data;
size_t read_index, read_length; size_t read_index, read_length;
paaudio *g; paaudio *g;
int samples;
} PAVoiceIn; } PAVoiceIn;
static void qpa_audio_fini(void *opaque); static void qpa_audio_fini(void *opaque);
@@ -224,7 +227,7 @@ static void *qpa_thread_out (void *arg)
} }
} }
decr = to_mix = audio_MIN(pa->live, pa->samples >> 5); decr = to_mix = audio_MIN(pa->live, pa->g->conf.samples >> 5);
rpos = pa->rpos; rpos = pa->rpos;
if (audio_pt_unlock(&pa->pt, __func__)) { if (audio_pt_unlock(&pa->pt, __func__)) {
@@ -316,7 +319,7 @@ static void *qpa_thread_in (void *arg)
} }
} }
incr = to_grab = audio_MIN(pa->dead, pa->samples >> 5); incr = to_grab = audio_MIN(pa->dead, pa->g->conf.samples >> 5);
wpos = pa->wpos; wpos = pa->wpos;
if (audio_pt_unlock(&pa->pt, __func__)) { if (audio_pt_unlock(&pa->pt, __func__)) {
@@ -382,21 +385,21 @@ static int qpa_read (SWVoiceIn *sw, void *buf, int len)
return audio_pcm_sw_read (sw, buf, len); return audio_pcm_sw_read (sw, buf, len);
} }
static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness) static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
{ {
int format; int format;
switch (afmt) { switch (afmt) {
case AUDIO_FORMAT_S8: case AUD_FMT_S8:
case AUDIO_FORMAT_U8: case AUD_FMT_U8:
format = PA_SAMPLE_U8; format = PA_SAMPLE_U8;
break; break;
case AUDIO_FORMAT_S16: case AUD_FMT_S16:
case AUDIO_FORMAT_U16: case AUD_FMT_U16:
format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
break; break;
case AUDIO_FORMAT_S32: case AUD_FMT_S32:
case AUDIO_FORMAT_U32: case AUD_FMT_U32:
format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
break; break;
default: default:
@@ -407,26 +410,26 @@ static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
return format; return format;
} }
static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness) static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
{ {
switch (fmt) { switch (fmt) {
case PA_SAMPLE_U8: case PA_SAMPLE_U8:
return AUDIO_FORMAT_U8; return AUD_FMT_U8;
case PA_SAMPLE_S16BE: case PA_SAMPLE_S16BE:
*endianness = 1; *endianness = 1;
return AUDIO_FORMAT_S16; return AUD_FMT_S16;
case PA_SAMPLE_S16LE: case PA_SAMPLE_S16LE:
*endianness = 0; *endianness = 0;
return AUDIO_FORMAT_S16; return AUD_FMT_S16;
case PA_SAMPLE_S32BE: case PA_SAMPLE_S32BE:
*endianness = 1; *endianness = 1;
return AUDIO_FORMAT_S32; return AUD_FMT_S32;
case PA_SAMPLE_S32LE: case PA_SAMPLE_S32LE:
*endianness = 0; *endianness = 0;
return AUDIO_FORMAT_S32; return AUD_FMT_S32;
default: default:
dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
return AUDIO_FORMAT_U8; return AUD_FMT_U8;
} }
} }
@@ -543,15 +546,17 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
struct audsettings obt_as = *as; struct audsettings obt_as = *as;
PAVoiceOut *pa = (PAVoiceOut *) hw; PAVoiceOut *pa = (PAVoiceOut *) hw;
paaudio *g = pa->g = drv_opaque; paaudio *g = pa->g = drv_opaque;
AudiodevPaOptions *popts = &g->dev->u.pa;
AudiodevPaPerDirectionOptions *ppdo = popts->out;
ss.format = audfmt_to_pa (as->fmt, as->endianness); ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels; ss.channels = as->nchannels;
ss.rate = as->freq; ss.rate = as->freq;
ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss); /*
ba.minreq = -1; * qemu audio tick runs at 100 Hz (by default), so processing
* data chunks worth 10 ms of sound should be a good fit.
*/
ba.tlength = pa_usec_to_bytes (10 * 1000, &ss);
ba.minreq = pa_usec_to_bytes (5 * 1000, &ss);
ba.maxlength = -1; ba.maxlength = -1;
ba.prebuf = -1; ba.prebuf = -1;
@@ -561,7 +566,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
g, g,
"qemu", "qemu",
PA_STREAM_PLAYBACK, PA_STREAM_PLAYBACK,
ppdo->has_name ? ppdo->name : NULL, g->conf.sink,
&ss, &ss,
NULL, /* channel map */ NULL, /* channel map */
&ba, /* buffering attributes */ &ba, /* buffering attributes */
@@ -573,9 +578,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
} }
audio_pcm_init_info (&hw->info, &obt_as); audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = pa->samples = audio_buffer_samples( hw->samples = g->conf.samples;
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
&obt_as, ppdo->buffer_length);
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
pa->rpos = hw->rpos; pa->rpos = hw->rpos;
if (!pa->pcm_buf) { if (!pa->pcm_buf) {
@@ -606,32 +609,24 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{ {
int error; int error;
pa_sample_spec ss; pa_sample_spec ss;
pa_buffer_attr ba;
struct audsettings obt_as = *as; struct audsettings obt_as = *as;
PAVoiceIn *pa = (PAVoiceIn *) hw; PAVoiceIn *pa = (PAVoiceIn *) hw;
paaudio *g = pa->g = drv_opaque; paaudio *g = pa->g = drv_opaque;
AudiodevPaOptions *popts = &g->dev->u.pa;
AudiodevPaPerDirectionOptions *ppdo = popts->in;
ss.format = audfmt_to_pa (as->fmt, as->endianness); ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels; ss.channels = as->nchannels;
ss.rate = as->freq; ss.rate = as->freq;
ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss);
ba.maxlength = pa_usec_to_bytes(ppdo->latency * 2, &ss);
ba.minreq = -1;
ba.prebuf = -1;
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
pa->stream = qpa_simple_new ( pa->stream = qpa_simple_new (
g, g,
"qemu", "qemu",
PA_STREAM_RECORD, PA_STREAM_RECORD,
ppdo->has_name ? ppdo->name : NULL, g->conf.source,
&ss, &ss,
NULL, /* channel map */ NULL, /* channel map */
&ba, /* buffering attributes */ NULL, /* buffering attributes */
&error &error
); );
if (!pa->stream) { if (!pa->stream) {
@@ -640,9 +635,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
} }
audio_pcm_init_info (&hw->info, &obt_as); audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = pa->samples = audio_buffer_samples( hw->samples = g->conf.samples;
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
&obt_as, ppdo->buffer_length);
pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
pa->wpos = hw->wpos; pa->wpos = hw->wpos;
if (!pa->pcm_buf) { if (!pa->pcm_buf) {
@@ -814,27 +807,14 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
return 0; return 0;
} }
static int qpa_validate_per_direction_opts(Audiodev *dev, /* common */
AudiodevPaPerDirectionOptions *pdo) static PAConf glob_conf = {
{ .samples = 4096,
if (!pdo->has_buffer_length) { };
pdo->has_buffer_length = true;
pdo->buffer_length = 46440;
}
if (!pdo->has_latency) {
pdo->has_latency = true;
pdo->latency = 15000;
}
return 1;
}
static void *qpa_audio_init(Audiodev *dev) static void *qpa_audio_init (void)
{ {
paaudio *g; if (glob_conf.server == NULL) {
AudiodevPaOptions *popts = &dev->u.pa;
const char *server;
if (!popts->has_server) {
char pidfile[64]; char pidfile[64];
char *runtime; char *runtime;
struct stat st; struct stat st;
@@ -849,19 +829,8 @@ static void *qpa_audio_init(Audiodev *dev)
} }
} }
assert(dev->driver == AUDIODEV_DRIVER_PA); paaudio *g = g_malloc(sizeof(paaudio));
g->conf = glob_conf;
g = g_malloc(sizeof(paaudio));
server = popts->has_server ? popts->server : NULL;
if (!qpa_validate_per_direction_opts(dev, popts->in)) {
goto fail;
}
if (!qpa_validate_per_direction_opts(dev, popts->out)) {
goto fail;
}
g->dev = dev;
g->mainloop = NULL; g->mainloop = NULL;
g->context = NULL; g->context = NULL;
@@ -871,14 +840,14 @@ static void *qpa_audio_init(Audiodev *dev)
} }
g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop),
server); g->conf.server);
if (!g->context) { if (!g->context) {
goto fail; goto fail;
} }
pa_context_set_state_callback (g->context, context_state_cb, g); pa_context_set_state_callback (g->context, context_state_cb, g);
if (pa_context_connect(g->context, server, 0, NULL) < 0) { if (pa_context_connect (g->context, g->conf.server, 0, NULL) < 0) {
qpa_logerr (pa_context_errno (g->context), qpa_logerr (pa_context_errno (g->context),
"pa_context_connect() failed\n"); "pa_context_connect() failed\n");
goto fail; goto fail;
@@ -941,6 +910,34 @@ static void qpa_audio_fini (void *opaque)
g_free(g); g_free(g);
} }
struct audio_option qpa_options[] = {
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &glob_conf.samples,
.descr = "buffer size in samples"
},
{
.name = "SERVER",
.tag = AUD_OPT_STR,
.valp = &glob_conf.server,
.descr = "server address"
},
{
.name = "SINK",
.tag = AUD_OPT_STR,
.valp = &glob_conf.sink,
.descr = "sink device name"
},
{
.name = "SOURCE",
.tag = AUD_OPT_STR,
.valp = &glob_conf.source,
.descr = "source device name"
},
{ /* End of list */ }
};
static struct audio_pcm_ops qpa_pcm_ops = { static struct audio_pcm_ops qpa_pcm_ops = {
.init_out = qpa_init_out, .init_out = qpa_init_out,
.fini_out = qpa_fini_out, .fini_out = qpa_fini_out,
@@ -958,6 +955,7 @@ static struct audio_pcm_ops qpa_pcm_ops = {
static struct audio_driver pa_audio_driver = { static struct audio_driver pa_audio_driver = {
.name = "pa", .name = "pa",
.descr = "http://www.pulseaudio.org/", .descr = "http://www.pulseaudio.org/",
.options = qpa_options,
.init = qpa_audio_init, .init = qpa_audio_init,
.fini = qpa_audio_fini, .fini = qpa_audio_fini,
.pcm_ops = &qpa_pcm_ops, .pcm_ops = &qpa_pcm_ops,

View File

@@ -21,11 +21,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include <SDL.h> #include <SDL.h>
#include <SDL_thread.h> #include <SDL_thread.h>
#include "qemu/module.h" #include "qemu-common.h"
#include "audio.h" #include "audio.h"
#ifndef _WIN32 #ifndef _WIN32
@@ -39,17 +38,31 @@
#define AUDIO_CAP "sdl" #define AUDIO_CAP "sdl"
#include "audio_int.h" #include "audio_int.h"
#define USE_SEMAPHORE (SDL_MAJOR_VERSION < 2)
typedef struct SDLVoiceOut { typedef struct SDLVoiceOut {
HWVoiceOut hw; HWVoiceOut hw;
int live; int live;
#if USE_SEMAPHORE
int rpos;
#endif
int decr; int decr;
} SDLVoiceOut; } SDLVoiceOut;
static struct {
int nb_samples;
} conf = {
.nb_samples = 1024
};
static struct SDLAudioState { static struct SDLAudioState {
int exit; int exit;
#if USE_SEMAPHORE
SDL_mutex *mutex;
SDL_sem *sem;
#endif
int initialized; int initialized;
bool driver_created; bool driver_created;
Audiodev *dev;
} glob_sdl; } glob_sdl;
typedef struct SDLAudioState SDLAudioState; typedef struct SDLAudioState SDLAudioState;
@@ -64,19 +77,79 @@ static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ()); AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ());
} }
static int aud_to_sdlfmt (AudioFormat fmt) static int sdl_lock (SDLAudioState *s, const char *forfn)
{
#if USE_SEMAPHORE
if (SDL_LockMutex (s->mutex)) {
sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
return -1;
}
#else
SDL_LockAudio();
#endif
return 0;
}
static int sdl_unlock (SDLAudioState *s, const char *forfn)
{
#if USE_SEMAPHORE
if (SDL_UnlockMutex (s->mutex)) {
sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
return -1;
}
#else
SDL_UnlockAudio();
#endif
return 0;
}
static int sdl_post (SDLAudioState *s, const char *forfn)
{
#if USE_SEMAPHORE
if (SDL_SemPost (s->sem)) {
sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
return -1;
}
#endif
return 0;
}
#if USE_SEMAPHORE
static int sdl_wait (SDLAudioState *s, const char *forfn)
{
if (SDL_SemWait (s->sem)) {
sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
return -1;
}
return 0;
}
#endif
static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
{
if (sdl_unlock (s, forfn)) {
return -1;
}
return sdl_post (s, forfn);
}
static int aud_to_sdlfmt (audfmt_e fmt)
{ {
switch (fmt) { switch (fmt) {
case AUDIO_FORMAT_S8: case AUD_FMT_S8:
return AUDIO_S8; return AUDIO_S8;
case AUDIO_FORMAT_U8: case AUD_FMT_U8:
return AUDIO_U8; return AUDIO_U8;
case AUDIO_FORMAT_S16: case AUD_FMT_S16:
return AUDIO_S16LSB; return AUDIO_S16LSB;
case AUDIO_FORMAT_U16: case AUD_FMT_U16:
return AUDIO_U16LSB; return AUDIO_U16LSB;
default: default:
@@ -88,37 +161,37 @@ static int aud_to_sdlfmt (AudioFormat fmt)
} }
} }
static int sdl_to_audfmt(int sdlfmt, AudioFormat *fmt, int *endianness) static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness)
{ {
switch (sdlfmt) { switch (sdlfmt) {
case AUDIO_S8: case AUDIO_S8:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_S8; *fmt = AUD_FMT_S8;
break; break;
case AUDIO_U8: case AUDIO_U8:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_U8; *fmt = AUD_FMT_U8;
break; break;
case AUDIO_S16LSB: case AUDIO_S16LSB:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_S16; *fmt = AUD_FMT_S16;
break; break;
case AUDIO_U16LSB: case AUDIO_U16LSB:
*endianness = 0; *endianness = 0;
*fmt = AUDIO_FORMAT_U16; *fmt = AUD_FMT_U16;
break; break;
case AUDIO_S16MSB: case AUDIO_S16MSB:
*endianness = 1; *endianness = 1;
*fmt = AUDIO_FORMAT_S16; *fmt = AUD_FMT_S16;
break; break;
case AUDIO_U16MSB: case AUDIO_U16MSB:
*endianness = 1; *endianness = 1;
*fmt = AUDIO_FORMAT_U16; *fmt = AUD_FMT_U16;
break; break;
default: default:
@@ -170,9 +243,9 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
static void sdl_close (SDLAudioState *s) static void sdl_close (SDLAudioState *s)
{ {
if (s->initialized) { if (s->initialized) {
SDL_LockAudio(); sdl_lock (s, "sdl_close");
s->exit = 1; s->exit = 1;
SDL_UnlockAudio(); sdl_unlock_and_post (s, "sdl_close");
SDL_PauseAudio (1); SDL_PauseAudio (1);
SDL_CloseAudio (); SDL_CloseAudio ();
s->initialized = 0; s->initialized = 0;
@@ -185,36 +258,76 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
SDLAudioState *s = &glob_sdl; SDLAudioState *s = &glob_sdl;
HWVoiceOut *hw = &sdl->hw; HWVoiceOut *hw = &sdl->hw;
int samples = len >> hw->info.shift; int samples = len >> hw->info.shift;
int to_mix, decr;
if (s->exit || !sdl->live) { if (s->exit) {
return; return;
} }
/* dolog ("in callback samples=%d live=%d\n", samples, sdl->live); */ while (samples) {
int to_mix, decr;
to_mix = audio_MIN(samples, sdl->live); /* dolog ("in callback samples=%d\n", samples); */
decr = to_mix; #if USE_SEMAPHORE
while (to_mix) { sdl_wait (s, "sdl_callback");
int chunk = audio_MIN(to_mix, hw->samples - hw->rpos); if (s->exit) {
struct st_sample *src = hw->mix_buf + hw->rpos; return;
}
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ if (sdl_lock (s, "sdl_callback")) {
hw->clip(buf, src, chunk); return;
hw->rpos = (hw->rpos + chunk) % hw->samples; }
to_mix -= chunk;
buf += chunk << hw->info.shift; if (audio_bug(__func__, sdl->live < 0 || sdl->live > hw->samples)) {
dolog ("sdl->live=%d hw->samples=%d\n",
sdl->live, hw->samples);
return;
}
if (!sdl->live) {
goto again;
}
#else
if (s->exit || !sdl->live) {
break;
}
#endif
/* dolog ("in callback live=%d\n", live); */
to_mix = audio_MIN (samples, sdl->live);
decr = to_mix;
while (to_mix) {
int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
struct st_sample *src = hw->mix_buf + hw->rpos;
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
#if USE_SEMAPHORE
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
#else
hw->rpos = (hw->rpos + chunk) % hw->samples;
#endif
to_mix -= chunk;
buf += chunk << hw->info.shift;
}
samples -= decr;
sdl->live -= decr;
sdl->decr += decr;
#if USE_SEMAPHORE
again:
if (sdl_unlock (s, "sdl_callback")) {
return;
}
#endif
} }
samples -= decr;
sdl->live -= decr;
sdl->decr += decr;
/* dolog ("done len=%d\n", len); */ /* dolog ("done len=%d\n", len); */
#if (SDL_MAJOR_VERSION >= 2)
/* SDL2 does not clear the remaining buffer for us, so do it on our own */ /* SDL2 does not clear the remaining buffer for us, so do it on our own */
if (samples) { if (samples) {
memset(buf, 0, samples << hw->info.shift); memset(buf, 0, samples << hw->info.shift);
} }
#endif
} }
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len) static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
@@ -226,8 +339,11 @@ static int sdl_run_out (HWVoiceOut *hw, int live)
{ {
int decr; int decr;
SDLVoiceOut *sdl = (SDLVoiceOut *) hw; SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLAudioState *s = &glob_sdl;
SDL_LockAudio(); if (sdl_lock (s, "sdl_run_out")) {
return 0;
}
if (sdl->decr > live) { if (sdl->decr > live) {
ldebug ("sdl->decr %d live %d sdl->live %d\n", ldebug ("sdl->decr %d live %d sdl->live %d\n",
@@ -239,10 +355,19 @@ static int sdl_run_out (HWVoiceOut *hw, int live)
decr = audio_MIN (sdl->decr, live); decr = audio_MIN (sdl->decr, live);
sdl->decr -= decr; sdl->decr -= decr;
#if USE_SEMAPHORE
sdl->live = live - decr;
hw->rpos = sdl->rpos;
#else
sdl->live = live; sdl->live = live;
#endif
SDL_UnlockAudio(); if (sdl->live > 0) {
sdl_unlock_and_post (s, "sdl_run_out");
}
else {
sdl_unlock (s, "sdl_run_out");
}
return decr; return decr;
} }
@@ -261,13 +386,13 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
SDL_AudioSpec req, obt; SDL_AudioSpec req, obt;
int endianness; int endianness;
int err; int err;
AudioFormat effective_fmt; audfmt_e effective_fmt;
struct audsettings obt_as; struct audsettings obt_as;
req.freq = as->freq; req.freq = as->freq;
req.format = aud_to_sdlfmt (as->fmt); req.format = aud_to_sdlfmt (as->fmt);
req.channels = as->nchannels; req.channels = as->nchannels;
req.samples = audio_buffer_samples(s->dev->u.sdl.out, as, 11610); req.samples = conf.nb_samples;
req.callback = sdl_callback; req.callback = sdl_callback;
req.userdata = sdl; req.userdata = sdl;
@@ -311,7 +436,7 @@ static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0; return 0;
} }
static void *sdl_audio_init(Audiodev *dev) static void *sdl_audio_init (void)
{ {
SDLAudioState *s = &glob_sdl; SDLAudioState *s = &glob_sdl;
if (s->driver_created) { if (s->driver_created) {
@@ -324,8 +449,24 @@ static void *sdl_audio_init(Audiodev *dev)
return NULL; return NULL;
} }
#if USE_SEMAPHORE
s->mutex = SDL_CreateMutex ();
if (!s->mutex) {
sdl_logerr ("Failed to create SDL mutex\n");
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
s->sem = SDL_CreateSemaphore (0);
if (!s->sem) {
sdl_logerr ("Failed to create SDL semaphore\n");
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
#endif
s->driver_created = true; s->driver_created = true;
s->dev = dev;
return s; return s;
} }
@@ -333,11 +474,24 @@ static void sdl_audio_fini (void *opaque)
{ {
SDLAudioState *s = opaque; SDLAudioState *s = opaque;
sdl_close (s); sdl_close (s);
#if USE_SEMAPHORE
SDL_DestroySemaphore (s->sem);
SDL_DestroyMutex (s->mutex);
#endif
SDL_QuitSubSystem (SDL_INIT_AUDIO); SDL_QuitSubSystem (SDL_INIT_AUDIO);
s->driver_created = false; s->driver_created = false;
s->dev = NULL;
} }
static struct audio_option sdl_options[] = {
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.nb_samples,
.descr = "Size of SDL buffer in samples"
},
{ /* End of list */ }
};
static struct audio_pcm_ops sdl_pcm_ops = { static struct audio_pcm_ops sdl_pcm_ops = {
.init_out = sdl_init_out, .init_out = sdl_init_out,
.fini_out = sdl_fini_out, .fini_out = sdl_fini_out,
@@ -349,6 +503,7 @@ static struct audio_pcm_ops sdl_pcm_ops = {
static struct audio_driver sdl_audio_driver = { static struct audio_driver sdl_audio_driver = {
.name = "sdl", .name = "sdl",
.descr = "SDL http://www.libsdl.org", .descr = "SDL http://www.libsdl.org",
.options = sdl_options,
.init = sdl_audio_init, .init = sdl_audio_init,
.fini = sdl_audio_fini, .fini = sdl_audio_fini,
.pcm_ops = &sdl_pcm_ops, .pcm_ops = &sdl_pcm_ops,

View File

@@ -20,7 +20,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "qemu/module.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "ui/qemu-spice.h" #include "ui/qemu-spice.h"
@@ -78,7 +77,7 @@ static const SpiceRecordInterface record_sif = {
.base.minor_version = SPICE_INTERFACE_RECORD_MINOR, .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
}; };
static void *spice_audio_init(Audiodev *dev) static void *spice_audio_init (void)
{ {
if (!using_spice) { if (!using_spice) {
return NULL; return NULL;
@@ -131,7 +130,7 @@ static int line_out_init(HWVoiceOut *hw, struct audsettings *as,
settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ; settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ;
#endif #endif
settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN; settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN;
settings.fmt = AUDIO_FORMAT_S16; settings.fmt = AUD_FMT_S16;
settings.endianness = AUDIO_HOST_ENDIANNESS; settings.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &settings); audio_pcm_init_info (&hw->info, &settings);
@@ -259,7 +258,7 @@ static int line_in_init(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
settings.freq = SPICE_INTERFACE_RECORD_FREQ; settings.freq = SPICE_INTERFACE_RECORD_FREQ;
#endif #endif
settings.nchannels = SPICE_INTERFACE_RECORD_CHAN; settings.nchannels = SPICE_INTERFACE_RECORD_CHAN;
settings.fmt = AUDIO_FORMAT_S16; settings.fmt = AUD_FMT_S16;
settings.endianness = AUDIO_HOST_ENDIANNESS; settings.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &settings); audio_pcm_init_info (&hw->info, &settings);
@@ -374,6 +373,10 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
return 0; return 0;
} }
static struct audio_option audio_options[] = {
{ /* end of list */ },
};
static struct audio_pcm_ops audio_callbacks = { static struct audio_pcm_ops audio_callbacks = {
.init_out = line_out_init, .init_out = line_out_init,
.fini_out = line_out_fini, .fini_out = line_out_fini,
@@ -391,6 +394,7 @@ static struct audio_pcm_ops audio_callbacks = {
static struct audio_driver spice_audio_driver = { static struct audio_driver spice_audio_driver = {
.name = "spice", .name = "spice",
.descr = "spice audio driver", .descr = "spice audio driver",
.options = audio_options,
.init = spice_audio_init, .init = spice_audio_init,
.fini = spice_audio_fini, .fini = spice_audio_fini,
.pcm_ops = &audio_callbacks, .pcm_ops = &audio_callbacks,

View File

@@ -1,6 +1,6 @@
# See docs/devel/tracing.txt for syntax documentation. # See docs/devel/tracing.txt for syntax documentation.
# alsaaudio.c # audio/alsaaudio.c
alsa_revents(int revents) "revents = %d" alsa_revents(int revents) "revents = %d"
alsa_pollout(int i, int fd) "i = %d fd = %d" alsa_pollout(int i, int fd) "i = %d fd = %d"
alsa_set_handler(int events, int index, int fd, int err) "events=0x%x index=%d fd=%d err=%d" alsa_set_handler(int events, int index, int fd, int err) "events=0x%x index=%d fd=%d err=%d"
@@ -12,11 +12,11 @@ alsa_resume_out(void) "Resuming suspended output stream"
alsa_resume_in(void) "Resuming suspended input stream" alsa_resume_in(void) "Resuming suspended input stream"
alsa_no_frames(int state) "No frames available and ALSA state is %d" alsa_no_frames(int state) "No frames available and ALSA state is %d"
# ossaudio.c # audio/ossaudio.c
oss_version(int version) "OSS version = 0x%x" oss_version(int version) "OSS version = 0x%x"
oss_invalid_available_size(int size, int bufsize) "Invalid available size, size=%d bufsize=%d" oss_invalid_available_size(int size, int bufsize) "Invalid available size, size=%d bufsize=%d"
# audio.c # audio/audio.c
audio_timer_start(int interval) "interval %d ms" audio_timer_start(int interval) "interval %d ms"
audio_timer_stop(void) "" audio_timer_stop(void) ""
audio_timer_delayed(int interval) "interval %d ms" audio_timer_delayed(int interval) "interval %d ms"

View File

@@ -21,12 +21,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "qemu/module.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qapi/opts-visitor.h"
#include "audio.h" #include "audio.h"
#define AUDIO_CAP "wav" #define AUDIO_CAP "wav"
@@ -40,6 +37,11 @@ typedef struct WAVVoiceOut {
int total_samples; int total_samples;
} WAVVoiceOut; } WAVVoiceOut;
typedef struct {
struct audsettings settings;
const char *wav_path;
} WAVConf;
static int wav_run_out (HWVoiceOut *hw, int live) static int wav_run_out (HWVoiceOut *hw, int live)
{ {
WAVVoiceOut *wav = (WAVVoiceOut *) hw; WAVVoiceOut *wav = (WAVVoiceOut *) hw;
@@ -110,30 +112,25 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
}; };
Audiodev *dev = drv_opaque; WAVConf *conf = drv_opaque;
AudiodevWavOptions *wopts = &dev->u.wav; struct audsettings wav_as = conf->settings;
struct audsettings wav_as = audiodev_to_audsettings(dev->u.wav.out);
const char *wav_path = wopts->has_path ? wopts->path : "qemu.wav";
stereo = wav_as.nchannels == 2; stereo = wav_as.nchannels == 2;
switch (wav_as.fmt) { switch (wav_as.fmt) {
case AUDIO_FORMAT_S8: case AUD_FMT_S8:
case AUDIO_FORMAT_U8: case AUD_FMT_U8:
bits16 = 0; bits16 = 0;
break; break;
case AUDIO_FORMAT_S16: case AUD_FMT_S16:
case AUDIO_FORMAT_U16: case AUD_FMT_U16:
bits16 = 1; bits16 = 1;
break; break;
case AUDIO_FORMAT_S32: case AUD_FMT_S32:
case AUDIO_FORMAT_U32: case AUD_FMT_U32:
dolog ("WAVE files can not handle 32bit formats\n"); dolog ("WAVE files can not handle 32bit formats\n");
return -1; return -1;
default:
abort();
} }
hdr[34] = bits16 ? 0x10 : 0x08; hdr[34] = bits16 ? 0x10 : 0x08;
@@ -154,10 +151,10 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
le_store (hdr + 32, 1 << (bits16 + stereo), 2); le_store (hdr + 32, 1 << (bits16 + stereo), 2);
wav->f = fopen(wav_path, "wb"); wav->f = fopen (conf->wav_path, "wb");
if (!wav->f) { if (!wav->f) {
dolog ("Failed to open wave file `%s'\nReason: %s\n", dolog ("Failed to open wave file `%s'\nReason: %s\n",
wav_path, strerror(errno)); conf->wav_path, strerror (errno));
g_free (wav->pcm_buf); g_free (wav->pcm_buf);
wav->pcm_buf = NULL; wav->pcm_buf = NULL;
return -1; return -1;
@@ -225,17 +222,54 @@ static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0; return 0;
} }
static void *wav_audio_init(Audiodev *dev) static WAVConf glob_conf = {
.settings.freq = 44100,
.settings.nchannels = 2,
.settings.fmt = AUD_FMT_S16,
.wav_path = "qemu.wav"
};
static void *wav_audio_init (void)
{ {
assert(dev->driver == AUDIODEV_DRIVER_WAV); WAVConf *conf = g_malloc(sizeof(WAVConf));
return dev; *conf = glob_conf;
return conf;
} }
static void wav_audio_fini (void *opaque) static void wav_audio_fini (void *opaque)
{ {
ldebug ("wav_fini"); ldebug ("wav_fini");
g_free(opaque);
} }
static struct audio_option wav_options[] = {
{
.name = "FREQUENCY",
.tag = AUD_OPT_INT,
.valp = &glob_conf.settings.freq,
.descr = "Frequency"
},
{
.name = "FORMAT",
.tag = AUD_OPT_FMT,
.valp = &glob_conf.settings.fmt,
.descr = "Format"
},
{
.name = "DAC_FIXED_CHANNELS",
.tag = AUD_OPT_INT,
.valp = &glob_conf.settings.nchannels,
.descr = "Number of channels (1 - mono, 2 - stereo)"
},
{
.name = "PATH",
.tag = AUD_OPT_STR,
.valp = &glob_conf.wav_path,
.descr = "Path to wave file"
},
{ /* End of list */ }
};
static struct audio_pcm_ops wav_pcm_ops = { static struct audio_pcm_ops wav_pcm_ops = {
.init_out = wav_init_out, .init_out = wav_init_out,
.fini_out = wav_fini_out, .fini_out = wav_fini_out,
@@ -247,6 +281,7 @@ static struct audio_pcm_ops wav_pcm_ops = {
static struct audio_driver wav_audio_driver = { static struct audio_driver wav_audio_driver = {
.name = "wav", .name = "wav",
.descr = "WAV renderer http://wikipedia.org/wiki/WAV", .descr = "WAV renderer http://wikipedia.org/wiki/WAV",
.options = wav_options,
.init = wav_audio_init, .init = wav_audio_init,
.fini = wav_audio_fini, .fini = wav_audio_fini,
.pcm_ops = &wav_pcm_ops, .pcm_ops = &wav_pcm_ops,

View File

@@ -136,7 +136,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
as.freq = freq; as.freq = freq;
as.nchannels = 1 << stereo; as.nchannels = 1 << stereo;
as.fmt = bits16 ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8; as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
as.endianness = 0; as.endianness = 0;
ops.notify = wav_notify; ops.notify = wav_notify;

View File

@@ -20,8 +20,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "authz/base.h" #include "authz/base.h"
#include "qemu/module.h" #include "authz/trace.h"
#include "trace.h"
bool qauthz_is_allowed(QAuthZ *authz, bool qauthz_is_allowed(QAuthZ *authz,
const char *identity, const char *identity,

View File

@@ -20,10 +20,9 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "authz/list.h" #include "authz/list.h"
#include "trace.h" #include "authz/trace.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#include "qapi/qapi-visit-authz.h" #include "qapi/qapi-visit-authz.h"
#include "qemu/module.h"
static bool qauthz_list_is_allowed(QAuthZ *authz, static bool qauthz_list_is_allowed(QAuthZ *authz,
const char *identity, const char *identity,

View File

@@ -20,10 +20,9 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "authz/listfile.h" #include "authz/listfile.h"
#include "trace.h" #include "authz/trace.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/sockets.h" #include "qemu/sockets.h"
#include "qemu/filemonitor.h" #include "qemu/filemonitor.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
@@ -94,7 +93,7 @@ qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp)
static void static void
qauthz_list_file_event(int64_t wd G_GNUC_UNUSED, qauthz_list_file_event(int wd G_GNUC_UNUSED,
QFileMonitorEvent ev G_GNUC_UNUSED, QFileMonitorEvent ev G_GNUC_UNUSED,
const char *name G_GNUC_UNUSED, const char *name G_GNUC_UNUSED,
void *opaque) void *opaque)

View File

@@ -20,8 +20,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "authz/pamacct.h" #include "authz/pamacct.h"
#include "trace.h" #include "authz/trace.h"
#include "qemu/module.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#include <security/pam_appl.h> #include <security/pam_appl.h>

View File

@@ -20,8 +20,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "authz/simple.h" #include "authz/simple.h"
#include "trace.h" #include "authz/trace.h"
#include "qemu/module.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
static bool qauthz_simple_is_allowed(QAuthZ *authz, static bool qauthz_simple_is_allowed(QAuthZ *authz,

View File

@@ -1,18 +1,18 @@
# See docs/devel/tracing.txt for syntax documentation. # See docs/devel/tracing.txt for syntax documentation.
# base.c # authz/base.c
qauthz_is_allowed(void *authz, const char *identity, bool allowed) "AuthZ %p check identity=%s allowed=%d" qauthz_is_allowed(void *authz, const char *identity, bool allowed) "AuthZ %p check identity=%s allowed=%d"
# simple.c # auth/simple.c
qauthz_simple_is_allowed(void *authz, const char *wantidentity, const char *gotidentity) "AuthZ simple %p check want identity=%s got identity=%s" qauthz_simple_is_allowed(void *authz, const char *wantidentity, const char *gotidentity) "AuthZ simple %p check want identity=%s got identity=%s"
# list.c # auth/list.c
qauthz_list_check_rule(void *authz, const char *identity, const char *rule, int format, int policy) "AuthZ list %p check rule=%s identity=%s format=%d policy=%d" qauthz_list_check_rule(void *authz, const char *identity, const char *rule, int format, int policy) "AuthZ list %p check rule=%s identity=%s format=%d policy=%d"
qauthz_list_default_policy(void *authz, const char *identity, int policy) "AuthZ list %p default identity=%s policy=%d" qauthz_list_default_policy(void *authz, const char *identity, int policy) "AuthZ list %p default identity=%s policy=%d"
# listfile.c # auth/listfile.c
qauthz_list_file_load(void *authz, const char *filename) "AuthZ file %p load filename=%s" qauthz_list_file_load(void *authz, const char *filename) "AuthZ file %p load filename=%s"
qauthz_list_file_refresh(void *authz, const char *filename, int success) "AuthZ file %p load filename=%s success=%d" qauthz_list_file_refresh(void *authz, const char *filename, int success) "AuthZ file %p load filename=%s success=%d"
# pamacct.c # auth/pam.c
qauthz_pam_check(void *authz, const char *identity, const char *service) "AuthZ PAM %p identity=%s service=%s" qauthz_pam_check(void *authz, const char *identity, const char *service) "AuthZ PAM %p identity=%s service=%s"

View File

@@ -9,11 +9,10 @@ common-obj-$(CONFIG_POSIX) += hostmem-file.o
common-obj-y += cryptodev.o common-obj-y += cryptodev.o
common-obj-y += cryptodev-builtin.o common-obj-y += cryptodev-builtin.o
ifeq ($(CONFIG_VIRTIO_CRYPTO),y) ifeq ($(CONFIG_VIRTIO),y)
common-obj-y += cryptodev-vhost.o common-obj-y += cryptodev-vhost.o
common-obj-$(CONFIG_VHOST_CRYPTO) += cryptodev-vhost-user.o common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) += \
cryptodev-vhost-user.o
endif endif
common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_VIRTIO)) += vhost-user.o
common-obj-$(CONFIG_LINUX) += hostmem-memfd.o common-obj-$(CONFIG_LINUX) += hostmem-memfd.o

View File

@@ -47,7 +47,7 @@
typedef struct CryptoDevBackendVhostUser { typedef struct CryptoDevBackendVhostUser {
CryptoDevBackend parent_obj; CryptoDevBackend parent_obj;
VhostUserState vhost_user; VhostUserState *vhost_user;
CharBackend chr; CharBackend chr;
char *chr_name; char *chr_name;
bool opened; bool opened;
@@ -104,7 +104,7 @@ cryptodev_vhost_user_start(int queues,
continue; continue;
} }
options.opaque = &s->vhost_user; options.opaque = s->vhost_user;
options.backend_type = VHOST_BACKEND_TYPE_USER; options.backend_type = VHOST_BACKEND_TYPE_USER;
options.cc = b->conf.peers.ccs[i]; options.cc = b->conf.peers.ccs[i];
s->vhost_crypto[i] = cryptodev_vhost_init(&options); s->vhost_crypto[i] = cryptodev_vhost_init(&options);
@@ -182,6 +182,7 @@ static void cryptodev_vhost_user_init(
size_t i; size_t i;
Error *local_err = NULL; Error *local_err = NULL;
Chardev *chr; Chardev *chr;
VhostUserState *user;
CryptoDevBackendClient *cc; CryptoDevBackendClient *cc;
CryptoDevBackendVhostUser *s = CryptoDevBackendVhostUser *s =
CRYPTODEV_BACKEND_VHOST_USER(backend); CRYPTODEV_BACKEND_VHOST_USER(backend);
@@ -212,10 +213,15 @@ static void cryptodev_vhost_user_init(
} }
} }
if (!vhost_user_init(&s->vhost_user, &s->chr, errp)) { user = vhost_user_init();
if (!user) {
error_setg(errp, "Failed to init vhost_user");
return; return;
} }
user->chr = &s->chr;
s->vhost_user = user;
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
cryptodev_vhost_user_event, NULL, s, NULL, true); cryptodev_vhost_user_event, NULL, s, NULL, true);
@@ -301,7 +307,11 @@ static void cryptodev_vhost_user_cleanup(
} }
} }
vhost_user_cleanup(&s->vhost_user); if (s->vhost_user) {
vhost_user_cleanup(s->vhost_user);
g_free(s->vhost_user);
s->vhost_user = NULL;
}
} }
static void cryptodev_vhost_user_set_chardev(Object *obj, static void cryptodev_vhost_user_set_chardev(Object *obj,

View File

@@ -9,11 +9,10 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later. * This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu-common.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/module.h"
#include "sysemu/hostmem.h" #include "sysemu/hostmem.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
@@ -42,12 +41,10 @@ struct HostMemoryBackendFile {
static void static void
file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
{ {
#ifndef CONFIG_POSIX
error_setg(errp, "backend '%s' not supported on this host",
object_get_typename(OBJECT(backend)));
#else
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(backend); HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(backend);
#ifdef CONFIG_POSIX
gchar *name; gchar *name;
#endif
if (!backend->size) { if (!backend->size) {
error_setg(errp, "can't create backend with size 0"); error_setg(errp, "can't create backend with size 0");
@@ -57,29 +54,9 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
error_setg(errp, "mem-path property not set"); error_setg(errp, "mem-path property not set");
return; return;
} }
#ifndef CONFIG_POSIX
/* error_setg(errp, "-mem-path not supported on this host");
* Verify pmem file size since starting a guest with an incorrect size #else
* leads to confusing failures inside the guest.
*/
if (fb->is_pmem) {
Error *local_err = NULL;
uint64_t size;
size = qemu_get_pmem_size(fb->mem_path, &local_err);
if (!size) {
error_propagate(errp, local_err);
return;
}
if (backend->size > size) {
error_setg(errp, "size property %" PRIu64 " is larger than "
"pmem file \"%s\" size %" PRIu64, backend->size,
fb->mem_path, size);
return;
}
}
backend->force_prealloc = mem_prealloc; backend->force_prealloc = mem_prealloc;
name = host_memory_backend_get_name(backend); name = host_memory_backend_get_name(backend);
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), memory_region_init_ram_from_file(&backend->mr, OBJECT(backend),

View File

@@ -9,13 +9,12 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later. * This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "sysemu/hostmem.h" #include "sysemu/hostmem.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#include "qemu/memfd.h" #include "qemu/memfd.h"
#include "qemu/module.h"
#include "qapi/error.h" #include "qapi/error.h"
#define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd" #define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd"
@@ -155,13 +154,15 @@ memfd_backend_class_init(ObjectClass *oc, void *data)
"Huge pages size (ex: 2M, 1G)", "Huge pages size (ex: 2M, 1G)",
&error_abort); &error_abort);
} }
object_class_property_add_bool(oc, "seal", if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
memfd_backend_get_seal, object_class_property_add_bool(oc, "seal",
memfd_backend_set_seal, memfd_backend_get_seal,
&error_abort); memfd_backend_set_seal,
object_class_property_set_description(oc, "seal", &error_abort);
"Seal growing & shrinking", object_class_property_set_description(oc, "seal",
&error_abort); "Seal growing & shrinking",
&error_abort);
}
} }
static const TypeInfo memfd_backend_info = { static const TypeInfo memfd_backend_info = {
@@ -174,7 +175,7 @@ static const TypeInfo memfd_backend_info = {
static void register_types(void) static void register_types(void)
{ {
if (qemu_memfd_check(MFD_ALLOW_SEALING)) { if (qemu_memfd_check(0)) {
type_register_static(&memfd_backend_info); type_register_static(&memfd_backend_info);
} }
} }

View File

@@ -9,11 +9,9 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later. * This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "sysemu/hostmem.h" #include "sysemu/hostmem.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/module.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#define TYPE_MEMORY_BACKEND_RAM "memory-backend-ram" #define TYPE_MEMORY_BACKEND_RAM "memory-backend-ram"

View File

@@ -88,7 +88,7 @@ host_memory_backend_get_host_nodes(Object *obj, Visitor *v, const char *name,
value = find_first_bit(backend->host_nodes, MAX_NODES); value = find_first_bit(backend->host_nodes, MAX_NODES);
if (value == MAX_NODES) { if (value == MAX_NODES) {
goto ret; return;
} }
*node = g_malloc0(sizeof(**node)); *node = g_malloc0(sizeof(**node));
@@ -106,7 +106,6 @@ host_memory_backend_get_host_nodes(Object *obj, Visitor *v, const char *name,
node = &(*node)->next; node = &(*node)->next;
} while (true); } while (true);
ret:
visit_type_uint16List(v, name, &host_nodes, errp); visit_type_uint16List(v, name, &host_nodes, errp);
} }
@@ -222,7 +221,6 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
{ {
Error *local_err = NULL; Error *local_err = NULL;
HostMemoryBackend *backend = MEMORY_BACKEND(obj); HostMemoryBackend *backend = MEMORY_BACKEND(obj);
MachineState *ms = MACHINE(qdev_get_machine());
if (backend->force_prealloc) { if (backend->force_prealloc) {
if (value) { if (value) {
@@ -242,7 +240,7 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
void *ptr = memory_region_get_ram_ptr(&backend->mr); void *ptr = memory_region_get_ram_ptr(&backend->mr);
uint64_t sz = memory_region_size(&backend->mr); uint64_t sz = memory_region_size(&backend->mr);
os_mem_prealloc(fd, ptr, sz, ms->smp.cpus, &local_err); os_mem_prealloc(fd, ptr, sz, smp_cpus, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return; return;
@@ -312,7 +310,6 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
{ {
HostMemoryBackend *backend = MEMORY_BACKEND(uc); HostMemoryBackend *backend = MEMORY_BACKEND(uc);
HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(uc); HostMemoryBackendClass *bc = MEMORY_BACKEND_GET_CLASS(uc);
MachineState *ms = MACHINE(qdev_get_machine());
Error *local_err = NULL; Error *local_err = NULL;
void *ptr; void *ptr;
uint64_t sz; uint64_t sz;
@@ -377,7 +374,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
*/ */
if (backend->prealloc) { if (backend->prealloc) {
os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz, os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz,
ms->smp.cpus, &local_err); smp_cpus, &local_err);
if (local_err) { if (local_err) {
goto out; goto out;
} }

View File

@@ -15,7 +15,6 @@
#include "chardev/char-fe.h" #include "chardev/char-fe.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qemu/module.h"
#define TYPE_RNG_EGD "rng-egd" #define TYPE_RNG_EGD "rng-egd"
#define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD) #define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)

View File

@@ -16,7 +16,6 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/module.h"
struct RngRandom struct RngRandom
{ {
@@ -113,7 +112,7 @@ static void rng_random_init(Object *obj)
rng_random_set_filename, rng_random_set_filename,
NULL); NULL);
s->filename = g_strdup("/dev/urandom"); s->filename = g_strdup("/dev/random");
s->fd = -1; s->fd = -1;
} }

View File

@@ -14,7 +14,6 @@
#include "sysemu/rng.h" #include "sysemu/rng.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qemu/module.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
void rng_backend_request_entropy(RngBackend *s, size_t size, void rng_backend_request_entropy(RngBackend *s, size_t size,

View File

@@ -18,7 +18,6 @@
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
#include "qemu/thread.h" #include "qemu/thread.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/module.h"
#include "block/thread-pool.h" #include "block/thread-pool.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"

View File

@@ -1,209 +0,0 @@
/*
* QEMU vhost-user backend
*
* Copyright (C) 2018 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 "hw/qdev.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
#include "qom/object_interfaces.h"
#include "sysemu/vhost-user-backend.h"
#include "sysemu/kvm.h"
#include "io/channel-command.h"
#include "hw/virtio/virtio-bus.h"
static bool
ioeventfd_enabled(void)
{
return kvm_enabled() && kvm_eventfds_enabled();
}
int
vhost_user_backend_dev_init(VhostUserBackend *b, VirtIODevice *vdev,
unsigned nvqs, Error **errp)
{
int ret;
assert(!b->vdev && vdev);
if (!ioeventfd_enabled()) {
error_setg(errp, "vhost initialization failed: requires kvm");
return -1;
}
if (!vhost_user_init(&b->vhost_user, &b->chr, errp)) {
return -1;
}
b->vdev = vdev;
b->dev.nvqs = nvqs;
b->dev.vqs = g_new(struct vhost_virtqueue, nvqs);
ret = vhost_dev_init(&b->dev, &b->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "vhost initialization failed");
return -1;
}
return 0;
}
void
vhost_user_backend_start(VhostUserBackend *b)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int ret, i ;
if (b->started) {
return;
}
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
return;
}
ret = vhost_dev_enable_notifiers(&b->dev, b->vdev);
if (ret < 0) {
return;
}
ret = k->set_guest_notifiers(qbus->parent, b->dev.nvqs, true);
if (ret < 0) {
error_report("Error binding guest notifier");
goto err_host_notifiers;
}
b->dev.acked_features = b->vdev->guest_features;
ret = vhost_dev_start(&b->dev, b->vdev);
if (ret < 0) {
error_report("Error start vhost dev");
goto err_guest_notifiers;
}
/* guest_notifier_mask/pending not used yet, so just unmask
* everything here. virtio-pci will do the right thing by
* enabling/disabling irqfd.
*/
for (i = 0; i < b->dev.nvqs; i++) {
vhost_virtqueue_mask(&b->dev, b->vdev,
b->dev.vq_index + i, false);
}
b->started = true;
return;
err_guest_notifiers:
k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false);
err_host_notifiers:
vhost_dev_disable_notifiers(&b->dev, b->vdev);
}
void
vhost_user_backend_stop(VhostUserBackend *b)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int ret = 0;
if (!b->started) {
return;
}
vhost_dev_stop(&b->dev, b->vdev);
if (k->set_guest_notifiers) {
ret = k->set_guest_notifiers(qbus->parent,
b->dev.nvqs, false);
if (ret < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
}
}
assert(ret >= 0);
vhost_dev_disable_notifiers(&b->dev, b->vdev);
b->started = false;
}
static void set_chardev(Object *obj, const char *value, Error **errp)
{
VhostUserBackend *b = VHOST_USER_BACKEND(obj);
Chardev *chr;
if (b->completed) {
error_setg(errp, QERR_PERMISSION_DENIED);
return;
}
g_free(b->chr_name);
b->chr_name = g_strdup(value);
chr = qemu_chr_find(b->chr_name);
if (chr == NULL) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"Chardev '%s' not found", b->chr_name);
return;
}
if (!qemu_chr_fe_init(&b->chr, chr, errp)) {
return;
}
b->completed = true;
/* could call vhost_dev_init() so early message can be exchanged */
}
static char *get_chardev(Object *obj, Error **errp)
{
VhostUserBackend *b = VHOST_USER_BACKEND(obj);
Chardev *chr = qemu_chr_fe_get_driver(&b->chr);
if (chr && chr->label) {
return g_strdup(chr->label);
}
return NULL;
}
static void vhost_user_backend_init(Object *obj)
{
object_property_add_str(obj, "chardev", get_chardev, set_chardev, NULL);
}
static void vhost_user_backend_finalize(Object *obj)
{
VhostUserBackend *b = VHOST_USER_BACKEND(obj);
g_free(b->dev.vqs);
g_free(b->chr_name);
vhost_user_cleanup(&b->vhost_user);
qemu_chr_fe_deinit(&b->chr, true);
}
static const TypeInfo vhost_user_backend_info = {
.name = TYPE_VHOST_USER_BACKEND,
.parent = TYPE_OBJECT,
.instance_size = sizeof(VhostUserBackend),
.instance_init = vhost_user_backend_init,
.instance_finalize = vhost_user_backend_finalize,
.class_size = sizeof(VhostUserBackendClass),
};
static void register_types(void)
{
type_register_static(&vhost_user_backend_info);
}
type_init(register_types);

View File

@@ -25,6 +25,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/atomic.h" #include "qemu/atomic.h"
#include "exec/cpu-common.h" #include "exec/cpu-common.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"

1020
block.c

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ block-obj-$(CONFIG_BOCHS) += bochs.o
block-obj-$(CONFIG_VVFAT) += vvfat.o block-obj-$(CONFIG_VVFAT) += vvfat.o
block-obj-$(CONFIG_DMG) += dmg.o block-obj-$(CONFIG_DMG) += dmg.o
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o qcow2-threads.o block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
block-obj-$(CONFIG_QED) += qed.o qed-l2-cache.o qed-table.o qed-cluster.o block-obj-$(CONFIG_QED) += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-$(CONFIG_QED) += qed-check.o block-obj-$(CONFIG_QED) += qed-check.o
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
@@ -22,7 +22,7 @@ block-obj-y += null.o mirror.o commit.o io.o create.o
block-obj-y += throttle-groups.o block-obj-y += throttle-groups.o
block-obj-$(CONFIG_LINUX) += nvme.o block-obj-$(CONFIG_LINUX) += nvme.o
block-obj-y += nbd.o block-obj-y += nbd.o nbd-client.o
block-obj-$(CONFIG_SHEEPDOG) += sheepdog.o block-obj-$(CONFIG_SHEEPDOG) += sheepdog.o
block-obj-$(CONFIG_LIBISCSI) += iscsi.o block-obj-$(CONFIG_LIBISCSI) += iscsi.o
block-obj-$(if $(CONFIG_LIBISCSI),y,n) += iscsi-opts.o block-obj-$(if $(CONFIG_LIBISCSI),y,n) += iscsi-opts.o
@@ -31,7 +31,7 @@ block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o block-obj-$(CONFIG_RBD) += rbd.o
block-obj-$(CONFIG_GLUSTERFS) += gluster.o block-obj-$(CONFIG_GLUSTERFS) += gluster.o
block-obj-$(CONFIG_VXHS) += vxhs.o block-obj-$(CONFIG_VXHS) += vxhs.o
block-obj-$(CONFIG_LIBSSH) += ssh.o block-obj-$(CONFIG_LIBSSH2) += ssh.o
block-obj-y += accounting.o dirty-bitmap.o block-obj-y += accounting.o dirty-bitmap.o
block-obj-y += write-threshold.o block-obj-y += write-threshold.o
block-obj-y += backup.o block-obj-y += backup.o
@@ -52,8 +52,8 @@ rbd.o-libs := $(RBD_LIBS)
gluster.o-cflags := $(GLUSTERFS_CFLAGS) gluster.o-cflags := $(GLUSTERFS_CFLAGS)
gluster.o-libs := $(GLUSTERFS_LIBS) gluster.o-libs := $(GLUSTERFS_LIBS)
vxhs.o-libs := $(VXHS_LIBS) vxhs.o-libs := $(VXHS_LIBS)
ssh.o-cflags := $(LIBSSH_CFLAGS) ssh.o-cflags := $(LIBSSH2_CFLAGS)
ssh.o-libs := $(LIBSSH_LIBS) ssh.o-libs := $(LIBSSH2_LIBS)
block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y) block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y)
dmg-bz2.o-libs := $(BZIP2_LIBS) dmg-bz2.o-libs := $(BZIP2_LIBS)

View File

@@ -107,19 +107,20 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
void **bounce_buffer) void **bounce_buffer)
{ {
int ret; int ret;
QEMUIOVector qiov;
BlockBackend *blk = job->common.blk; BlockBackend *blk = job->common.blk;
int nbytes; int nbytes;
int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0; int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0;
int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0; int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
assert(QEMU_IS_ALIGNED(start, job->cluster_size)); hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1);
hbitmap_reset(job->copy_bitmap, start, job->cluster_size);
nbytes = MIN(job->cluster_size, job->len - start); nbytes = MIN(job->cluster_size, job->len - start);
if (!*bounce_buffer) { if (!*bounce_buffer) {
*bounce_buffer = blk_blockalign(blk, job->cluster_size); *bounce_buffer = blk_blockalign(blk, job->cluster_size);
} }
qemu_iovec_init_buf(&qiov, *bounce_buffer, nbytes);
ret = blk_co_pread(blk, start, nbytes, *bounce_buffer, read_flags); ret = blk_co_preadv(blk, start, qiov.size, &qiov, read_flags);
if (ret < 0) { if (ret < 0) {
trace_backup_do_cow_read_fail(job, start, ret); trace_backup_do_cow_read_fail(job, start, ret);
if (error_is_read) { if (error_is_read) {
@@ -128,13 +129,13 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
goto fail; goto fail;
} }
if (buffer_is_zero(*bounce_buffer, nbytes)) { if (qemu_iovec_is_zero(&qiov)) {
ret = blk_co_pwrite_zeroes(job->target, start, ret = blk_co_pwrite_zeroes(job->target, start,
nbytes, write_flags | BDRV_REQ_MAY_UNMAP); qiov.size, write_flags | BDRV_REQ_MAY_UNMAP);
} else { } else {
ret = blk_co_pwrite(job->target, start, ret = blk_co_pwritev(job->target, start,
nbytes, *bounce_buffer, write_flags | qiov.size, &qiov, write_flags |
(job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0)); (job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0));
} }
if (ret < 0) { if (ret < 0) {
trace_backup_do_cow_write_fail(job, start, ret); trace_backup_do_cow_write_fail(job, start, ret);
@@ -146,7 +147,7 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
return nbytes; return nbytes;
fail: fail:
hbitmap_set(job->copy_bitmap, start, job->cluster_size); hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1);
return ret; return ret;
} }
@@ -166,15 +167,16 @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0; int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size)); assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size));
assert(QEMU_IS_ALIGNED(start, job->cluster_size)); nbytes = MIN(job->copy_range_size, end - start);
nbytes = MIN(job->copy_range_size, MIN(end, job->len) - start);
nr_clusters = DIV_ROUND_UP(nbytes, job->cluster_size); nr_clusters = DIV_ROUND_UP(nbytes, job->cluster_size);
hbitmap_reset(job->copy_bitmap, start, job->cluster_size * nr_clusters); hbitmap_reset(job->copy_bitmap, start / job->cluster_size,
nr_clusters);
ret = blk_co_copy_range(blk, start, job->target, start, nbytes, ret = blk_co_copy_range(blk, start, job->target, start, nbytes,
read_flags, write_flags); read_flags, write_flags);
if (ret < 0) { if (ret < 0) {
trace_backup_do_cow_copy_range_fail(job, start, ret); trace_backup_do_cow_copy_range_fail(job, start, ret);
hbitmap_set(job->copy_bitmap, start, job->cluster_size * nr_clusters); hbitmap_set(job->copy_bitmap, start / job->cluster_size,
nr_clusters);
return ret; return ret;
} }
@@ -202,31 +204,22 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
cow_request_begin(&cow_request, job, start, end); cow_request_begin(&cow_request, job, start, end);
while (start < end) { while (start < end) {
int64_t dirty_end; if (!hbitmap_get(job->copy_bitmap, start / job->cluster_size)) {
if (!hbitmap_get(job->copy_bitmap, start)) {
trace_backup_do_cow_skip(job, start); trace_backup_do_cow_skip(job, start);
start += job->cluster_size; start += job->cluster_size;
continue; /* already copied */ continue; /* already copied */
} }
dirty_end = hbitmap_next_zero(job->copy_bitmap, start, (end - start));
if (dirty_end < 0) {
dirty_end = end;
}
trace_backup_do_cow_process(job, start); trace_backup_do_cow_process(job, start);
if (job->use_copy_range) { if (job->use_copy_range) {
ret = backup_cow_with_offload(job, start, dirty_end, ret = backup_cow_with_offload(job, start, end, is_write_notifier);
is_write_notifier);
if (ret < 0) { if (ret < 0) {
job->use_copy_range = false; job->use_copy_range = false;
} }
} }
if (!job->use_copy_range) { if (!job->use_copy_range) {
ret = backup_cow_with_bounce_buffer(job, start, dirty_end, ret = backup_cow_with_bounce_buffer(job, start, end, is_write_notifier,
is_write_notifier,
error_is_read, &bounce_buffer); error_is_read, &bounce_buffer);
} }
if (ret < 0) { if (ret < 0) {
@@ -307,16 +300,19 @@ static void backup_clean(Job *job)
assert(s->target); assert(s->target);
blk_unref(s->target); blk_unref(s->target);
s->target = NULL; s->target = NULL;
}
if (s->copy_bitmap) { static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
hbitmap_free(s->copy_bitmap); {
s->copy_bitmap = NULL; BackupBlockJob *s = container_of(job, BackupBlockJob, common);
}
blk_set_aio_context(s->target, aio_context);
} }
void backup_do_checkpoint(BlockJob *job, Error **errp) void backup_do_checkpoint(BlockJob *job, Error **errp)
{ {
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common); BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
int64_t len;
assert(block_job_driver(job) == &backup_job_driver); assert(block_job_driver(job) == &backup_job_driver);
@@ -326,7 +322,8 @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
return; return;
} }
hbitmap_set(backup_job->copy_bitmap, 0, backup_job->len); len = DIV_ROUND_UP(backup_job->len, backup_job->cluster_size);
hbitmap_set(backup_job->copy_bitmap, 0, len);
} }
static void backup_drain(BlockJob *job) static void backup_drain(BlockJob *job)
@@ -377,44 +374,20 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job)
return false; return false;
} }
static bool bdrv_is_unallocated_range(BlockDriverState *bs, static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
int64_t offset, int64_t bytes)
{
int64_t end = offset + bytes;
while (offset < end && !bdrv_is_allocated(bs, offset, bytes, &bytes)) {
if (bytes == 0) {
return true;
}
offset += bytes;
bytes = end - offset;
}
return offset >= end;
}
static int coroutine_fn backup_loop(BackupBlockJob *job)
{ {
int ret; int ret;
bool error_is_read; bool error_is_read;
int64_t offset; int64_t cluster;
HBitmapIter hbi; HBitmapIter hbi;
BlockDriverState *bs = blk_bs(job->common.blk);
hbitmap_iter_init(&hbi, job->copy_bitmap, 0); hbitmap_iter_init(&hbi, job->copy_bitmap, 0);
while ((offset = hbitmap_iter_next(&hbi)) != -1) { while ((cluster = hbitmap_iter_next(&hbi)) != -1) {
if (job->sync_mode == MIRROR_SYNC_MODE_TOP &&
bdrv_is_unallocated_range(bs, offset, job->cluster_size))
{
hbitmap_reset(job->copy_bitmap, offset, job->cluster_size);
continue;
}
do { do {
if (yield_and_check(job)) { if (yield_and_check(job)) {
return 0; return 0;
} }
ret = backup_do_cow(job, offset, ret = backup_do_cow(job, cluster * job->cluster_size,
job->cluster_size, &error_is_read, false); job->cluster_size, &error_is_read, false);
if (ret < 0 && backup_error_action(job, error_is_read, -ret) == if (ret < 0 && backup_error_action(job, error_is_read, -ret) ==
BLOCK_ERROR_ACTION_REPORT) BLOCK_ERROR_ACTION_REPORT)
@@ -430,43 +403,66 @@ static int coroutine_fn backup_loop(BackupBlockJob *job)
/* init copy_bitmap from sync_bitmap */ /* init copy_bitmap from sync_bitmap */
static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
{ {
uint64_t offset = 0; BdrvDirtyBitmapIter *dbi;
uint64_t bytes = job->len; int64_t offset;
int64_t end = DIV_ROUND_UP(bdrv_dirty_bitmap_size(job->sync_bitmap),
job->cluster_size);
while (bdrv_dirty_bitmap_next_dirty_area(job->sync_bitmap, dbi = bdrv_dirty_iter_new(job->sync_bitmap);
&offset, &bytes)) while ((offset = bdrv_dirty_iter_next(dbi)) != -1) {
{ int64_t cluster = offset / job->cluster_size;
hbitmap_set(job->copy_bitmap, offset, bytes); int64_t next_cluster;
offset += bytes; offset += bdrv_dirty_bitmap_granularity(job->sync_bitmap);
if (offset >= job->len) { if (offset >= bdrv_dirty_bitmap_size(job->sync_bitmap)) {
hbitmap_set(job->copy_bitmap, cluster, end - cluster);
break; break;
} }
bytes = job->len - offset;
offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset,
UINT64_MAX);
if (offset == -1) {
hbitmap_set(job->copy_bitmap, cluster, end - cluster);
break;
}
next_cluster = DIV_ROUND_UP(offset, job->cluster_size);
hbitmap_set(job->copy_bitmap, cluster, next_cluster - cluster);
if (next_cluster >= end) {
break;
}
bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size);
} }
/* TODO job_progress_set_remaining() would make more sense */ /* TODO job_progress_set_remaining() would make more sense */
job_progress_update(&job->common.job, job_progress_update(&job->common.job,
job->len - hbitmap_count(job->copy_bitmap)); job->len - hbitmap_count(job->copy_bitmap) * job->cluster_size);
bdrv_dirty_iter_free(dbi);
} }
static int coroutine_fn backup_run(Job *job, Error **errp) static int coroutine_fn backup_run(Job *job, Error **errp)
{ {
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
BlockDriverState *bs = blk_bs(s->common.blk); BlockDriverState *bs = blk_bs(s->common.blk);
int64_t offset, nb_clusters;
int ret = 0; int ret = 0;
QLIST_INIT(&s->inflight_reqs); QLIST_INIT(&s->inflight_reqs);
qemu_co_rwlock_init(&s->flush_rwlock); qemu_co_rwlock_init(&s->flush_rwlock);
nb_clusters = DIV_ROUND_UP(s->len, s->cluster_size);
job_progress_set_remaining(job, s->len); job_progress_set_remaining(job, s->len);
s->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
backup_incremental_init_copy_bitmap(s); backup_incremental_init_copy_bitmap(s);
} else { } else {
hbitmap_set(s->copy_bitmap, 0, s->len); hbitmap_set(s->copy_bitmap, 0, nb_clusters);
} }
s->before_write.notify = backup_before_write_notify; s->before_write.notify = backup_before_write_notify;
bdrv_add_before_write_notifier(bs, &s->before_write); bdrv_add_before_write_notifier(bs, &s->before_write);
@@ -478,8 +474,68 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
* notify callback service CoW requests. */ * notify callback service CoW requests. */
job_yield(job); job_yield(job);
} }
} else if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
ret = backup_run_incremental(s);
} else { } else {
ret = backup_loop(s); /* Both FULL and TOP SYNC_MODE's require copying.. */
for (offset = 0; offset < s->len;
offset += s->cluster_size) {
bool error_is_read;
int alloced = 0;
if (yield_and_check(s)) {
break;
}
if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
int i;
int64_t n;
/* Check to see if these blocks are already in the
* backing file. */
for (i = 0; i < s->cluster_size;) {
/* bdrv_is_allocated() only returns true/false based
* on the first set of sectors it comes across that
* are are all in the same state.
* For that reason we must verify each sector in the
* backup cluster length. We end up copying more than
* needed but at some point that is always the case. */
alloced =
bdrv_is_allocated(bs, offset + i,
s->cluster_size - i, &n);
i += n;
if (alloced || n == 0) {
break;
}
}
/* If the above loop never found any sectors that are in
* the topmost image, skip this backup. */
if (alloced == 0) {
continue;
}
}
/* FULL sync mode we copy the whole drive. */
if (alloced < 0) {
ret = alloced;
} else {
ret = backup_do_cow(s, offset, s->cluster_size,
&error_is_read, false);
}
if (ret < 0) {
/* Depending on error action, fail now or retry cluster */
BlockErrorAction action =
backup_error_action(s, error_is_read, -ret);
if (action == BLOCK_ERROR_ACTION_REPORT) {
break;
} else {
offset -= s->cluster_size;
continue;
}
}
}
} }
notifier_with_return_remove(&s->before_write); notifier_with_return_remove(&s->before_write);
@@ -487,6 +543,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
/* wait until pending backup_do_cow() calls have completed */ /* wait until pending backup_do_cow() calls have completed */
qemu_co_rwlock_wrlock(&s->flush_rwlock); qemu_co_rwlock_wrlock(&s->flush_rwlock);
qemu_co_rwlock_unlock(&s->flush_rwlock); qemu_co_rwlock_unlock(&s->flush_rwlock);
hbitmap_free(s->copy_bitmap);
return ret; return ret;
} }
@@ -503,45 +560,10 @@ static const BlockJobDriver backup_job_driver = {
.abort = backup_abort, .abort = backup_abort,
.clean = backup_clean, .clean = backup_clean,
}, },
.attached_aio_context = backup_attached_aio_context,
.drain = backup_drain, .drain = backup_drain,
}; };
static int64_t backup_calculate_cluster_size(BlockDriverState *target,
Error **errp)
{
int ret;
BlockDriverInfo bdi;
/*
* If there is no backing file on the target, we cannot rely on COW if our
* backup cluster size is smaller than the target cluster size. Even for
* targets with a backing file, try to avoid COW if possible.
*/
ret = bdrv_get_info(target, &bdi);
if (ret == -ENOTSUP && !target->backing) {
/* Cluster size is not defined */
warn_report("The target block device doesn't provide "
"information about the block size and it doesn't have a "
"backing file. The default block size of %u bytes is "
"used. If the actual block size of the target exceeds "
"this default, the backup may be unusable",
BACKUP_CLUSTER_SIZE_DEFAULT);
return BACKUP_CLUSTER_SIZE_DEFAULT;
} else if (ret < 0 && !target->backing) {
error_setg_errno(errp, -ret,
"Couldn't determine the cluster size of the target image, "
"which has no backing file");
error_append_hint(errp,
"Aborting, since this may create an unusable destination image\n");
return ret;
} else if (ret < 0 && target->backing) {
/* Not fatal; just trudge on ahead. */
return BACKUP_CLUSTER_SIZE_DEFAULT;
}
return MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
}
BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, int64_t speed, BlockDriverState *target, int64_t speed,
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
@@ -553,10 +575,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
JobTxn *txn, Error **errp) JobTxn *txn, Error **errp)
{ {
int64_t len; int64_t len;
BlockDriverInfo bdi;
BackupBlockJob *job = NULL; BackupBlockJob *job = NULL;
int ret; int ret;
int64_t cluster_size;
HBitmap *copy_bitmap = NULL;
assert(bs); assert(bs);
assert(target); assert(target);
@@ -618,13 +639,6 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
goto error; goto error;
} }
cluster_size = backup_calculate_cluster_size(target, errp);
if (cluster_size < 0) {
goto error;
}
copy_bitmap = hbitmap_alloc(len, ctz32(cluster_size));
/* job->len is fixed, so we can't allow resize */ /* job->len is fixed, so we can't allow resize */
job = block_job_create(job_id, &backup_job_driver, txn, bs, job = block_job_create(job_id, &backup_job_driver, txn, bs,
BLK_PERM_CONSISTENT_READ, BLK_PERM_CONSISTENT_READ,
@@ -636,8 +650,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
} }
/* The target must match the source in size, so no resize here either */ /* The target must match the source in size, so no resize here either */
job->target = blk_new(job->common.job.aio_context, job->target = blk_new(BLK_PERM_WRITE,
BLK_PERM_WRITE,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE |
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD);
ret = blk_insert_bs(job->target, target, errp); ret = blk_insert_bs(job->target, target, errp);
@@ -654,22 +667,39 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
/* Detect image-fleecing (and similar) schemes */ /* Detect image-fleecing (and similar) schemes */
job->serialize_target_writes = bdrv_chain_contains(target, bs); job->serialize_target_writes = bdrv_chain_contains(target, bs);
job->cluster_size = cluster_size;
job->copy_bitmap = copy_bitmap; /* If there is no backing file on the target, we cannot rely on COW if our
copy_bitmap = NULL; * backup cluster size is smaller than the target cluster size. Even for
* targets with a backing file, try to avoid COW if possible. */
ret = bdrv_get_info(target, &bdi);
if (ret == -ENOTSUP && !target->backing) {
/* Cluster size is not defined */
warn_report("The target block device doesn't provide "
"information about the block size and it doesn't have a "
"backing file. The default block size of %u bytes is "
"used. If the actual block size of the target exceeds "
"this default, the backup may be unusable",
BACKUP_CLUSTER_SIZE_DEFAULT);
job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
} else if (ret < 0 && !target->backing) {
error_setg_errno(errp, -ret,
"Couldn't determine the cluster size of the target image, "
"which has no backing file");
error_append_hint(errp,
"Aborting, since this may create an unusable destination image\n");
goto error;
} else if (ret < 0 && target->backing) {
/* Not fatal; just trudge on ahead. */
job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
} else {
job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
}
job->use_copy_range = true;
job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk), job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk),
blk_get_max_transfer(job->target)); blk_get_max_transfer(job->target));
job->copy_range_size = QEMU_ALIGN_DOWN(job->copy_range_size, job->copy_range_size = MAX(job->cluster_size,
job->cluster_size); QEMU_ALIGN_UP(job->copy_range_size,
/* job->cluster_size));
* Set use_copy_range, consider the following:
* 1. Compression is not supported for copy_range.
* 2. copy_range does not respect max_transfer (it's a TODO), so we factor
* that in here. If max_transfer is smaller than the job->cluster_size,
* we do not use copy_range (in that case it's zero after aligning down
* above).
*/
job->use_copy_range = !compress && job->copy_range_size > 0;
/* Required permissions are already taken with target's blk_new() */ /* Required permissions are already taken with target's blk_new() */
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
@@ -679,10 +709,6 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return &job->common; return &job->common;
error: error:
if (copy_bitmap) {
assert(!job || !job->copy_bitmap);
hbitmap_free(copy_bitmap);
}
if (sync_bitmap) { if (sync_bitmap) {
bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL); bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL);
} }

View File

@@ -75,7 +75,6 @@ typedef struct BlkdebugRule {
int state; int state;
union { union {
struct { struct {
uint64_t iotype_mask;
int error; int error;
int immediately; int immediately;
int once; int once;
@@ -92,9 +91,6 @@ typedef struct BlkdebugRule {
QSIMPLEQ_ENTRY(BlkdebugRule) active_next; QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
} BlkdebugRule; } BlkdebugRule;
QEMU_BUILD_BUG_MSG(BLKDEBUG_IO_TYPE__MAX > 64,
"BlkdebugIOType mask does not fit into an uint64_t");
static QemuOptsList inject_error_opts = { static QemuOptsList inject_error_opts = {
.name = "inject-error", .name = "inject-error",
.head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head), .head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
@@ -107,10 +103,6 @@ static QemuOptsList inject_error_opts = {
.name = "state", .name = "state",
.type = QEMU_OPT_NUMBER, .type = QEMU_OPT_NUMBER,
}, },
{
.name = "iotype",
.type = QEMU_OPT_STRING,
},
{ {
.name = "errno", .name = "errno",
.type = QEMU_OPT_NUMBER, .type = QEMU_OPT_NUMBER,
@@ -170,8 +162,6 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
int event; int event;
struct BlkdebugRule *rule; struct BlkdebugRule *rule;
int64_t sector; int64_t sector;
BlkdebugIOType iotype;
Error *local_error = NULL;
/* Find the right event for the rule */ /* Find the right event for the rule */
event_name = qemu_opt_get(opts, "event"); event_name = qemu_opt_get(opts, "event");
@@ -202,26 +192,6 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
sector = qemu_opt_get_number(opts, "sector", -1); sector = qemu_opt_get_number(opts, "sector", -1);
rule->options.inject.offset = rule->options.inject.offset =
sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE; sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
iotype = qapi_enum_parse(&BlkdebugIOType_lookup,
qemu_opt_get(opts, "iotype"),
BLKDEBUG_IO_TYPE__MAX, &local_error);
if (local_error) {
error_propagate(errp, local_error);
return -1;
}
if (iotype != BLKDEBUG_IO_TYPE__MAX) {
rule->options.inject.iotype_mask = (1ull << iotype);
} else {
/* Apply the default */
rule->options.inject.iotype_mask =
(1ull << BLKDEBUG_IO_TYPE_READ)
| (1ull << BLKDEBUG_IO_TYPE_WRITE)
| (1ull << BLKDEBUG_IO_TYPE_WRITE_ZEROES)
| (1ull << BLKDEBUG_IO_TYPE_DISCARD)
| (1ull << BLKDEBUG_IO_TYPE_FLUSH);
}
break; break;
case ACTION_SET_STATE: case ACTION_SET_STATE:
@@ -431,7 +401,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags); (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
bs->file->bs->supported_zero_flags); bs->file->bs->supported_zero_flags);
ret = -EINVAL; ret = -EINVAL;
@@ -491,8 +461,6 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
goto out; goto out;
} }
bdrv_debug_event(bs, BLKDBG_NONE);
ret = 0; ret = 0;
out: out:
if (ret < 0) { if (ret < 0) {
@@ -502,8 +470,7 @@ out:
return ret; return ret;
} }
static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes, static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
BlkdebugIOType iotype)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = NULL; BlkdebugRule *rule = NULL;
@@ -513,10 +480,9 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
uint64_t inject_offset = rule->options.inject.offset; uint64_t inject_offset = rule->options.inject.offset;
if ((inject_offset == -1 || if (inject_offset == -1 ||
(bytes && inject_offset >= offset && (bytes && inject_offset >= offset &&
inject_offset < offset + bytes)) && inject_offset < offset + bytes))
(rule->options.inject.iotype_mask & (1ull << iotype)))
{ {
break; break;
} }
@@ -555,7 +521,7 @@ blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
assert(bytes <= bs->bl.max_transfer); assert(bytes <= bs->bl.max_transfer);
} }
err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_READ); err = rule_check(bs, offset, bytes);
if (err) { if (err) {
return err; return err;
} }
@@ -576,7 +542,7 @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
assert(bytes <= bs->bl.max_transfer); assert(bytes <= bs->bl.max_transfer);
} }
err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE); err = rule_check(bs, offset, bytes);
if (err) { if (err) {
return err; return err;
} }
@@ -586,7 +552,7 @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
static int blkdebug_co_flush(BlockDriverState *bs) static int blkdebug_co_flush(BlockDriverState *bs)
{ {
int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH); int err = rule_check(bs, 0, 0);
if (err) { if (err) {
return err; return err;
@@ -620,7 +586,7 @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
assert(bytes <= bs->bl.max_pwrite_zeroes); assert(bytes <= bs->bl.max_pwrite_zeroes);
} }
err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE_ZEROES); err = rule_check(bs, offset, bytes);
if (err) { if (err) {
return err; return err;
} }
@@ -654,7 +620,7 @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
assert(bytes <= bs->bl.max_pdiscard); assert(bytes <= bs->bl.max_pdiscard);
} }
err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_DISCARD); err = rule_check(bs, offset, bytes);
if (err) { if (err) {
return err; return err;
} }
@@ -670,15 +636,7 @@ static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs,
int64_t *map, int64_t *map,
BlockDriverState **file) BlockDriverState **file)
{ {
int err;
assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment)); assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_BLOCK_STATUS);
if (err) {
return err;
}
return bdrv_co_block_status_from_file(bs, want_zero, offset, bytes, return bdrv_co_block_status_from_file(bs, want_zero, offset, bytes,
pnum, map, file); pnum, map, file);
} }

View File

@@ -16,7 +16,6 @@
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/option.h" #include "qemu/option.h"
/* Disk format stuff - taken from Linux drivers/md/dm-log-writes.c */ /* Disk format stuff - taken from Linux drivers/md/dm-log-writes.c */

View File

@@ -10,7 +10,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/module.h" #include "qemu-common.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "qapi/error.h" #include "qapi/error.h"

View File

@@ -14,7 +14,6 @@
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/option.h" #include "qemu/option.h"
typedef struct { typedef struct {

View File

@@ -42,7 +42,6 @@ struct BlockBackend {
char *name; char *name;
int refcnt; int refcnt;
BdrvChild *root; BdrvChild *root;
AioContext *ctx;
DriveInfo *legacy_dinfo; /* null unless created by drive_new() */ DriveInfo *legacy_dinfo; /* null unless created by drive_new() */
QTAILQ_ENTRY(BlockBackend) link; /* for block_backends */ QTAILQ_ENTRY(BlockBackend) link; /* for block_backends */
QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */ QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */
@@ -72,7 +71,6 @@ struct BlockBackend {
uint64_t shared_perm; uint64_t shared_perm;
bool disable_perm; bool disable_perm;
bool allow_aio_context_change;
bool allow_write_beyond_eof; bool allow_write_beyond_eof;
NotifierList remove_bs_notifiers, insert_bs_notifiers; NotifierList remove_bs_notifiers, insert_bs_notifiers;
@@ -121,16 +119,11 @@ static void blk_root_inherit_options(int *child_flags, QDict *child_options,
} }
static void blk_root_drained_begin(BdrvChild *child); static void blk_root_drained_begin(BdrvChild *child);
static bool blk_root_drained_poll(BdrvChild *child); static bool blk_root_drained_poll(BdrvChild *child);
static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter); static void blk_root_drained_end(BdrvChild *child);
static void blk_root_change_media(BdrvChild *child, bool load); static void blk_root_change_media(BdrvChild *child, bool load);
static void blk_root_resize(BdrvChild *child); static void blk_root_resize(BdrvChild *child);
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
GSList **ignore, Error **errp);
static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
GSList **ignore);
static char *blk_root_get_parent_desc(BdrvChild *child) static char *blk_root_get_parent_desc(BdrvChild *child)
{ {
BlockBackend *blk = child->opaque; BlockBackend *blk = child->opaque;
@@ -307,9 +300,6 @@ static const BdrvChildRole child_root = {
.attach = blk_root_attach, .attach = blk_root_attach,
.detach = blk_root_detach, .detach = blk_root_detach,
.can_set_aio_ctx = blk_root_can_set_aio_ctx,
.set_aio_ctx = blk_root_set_aio_ctx,
}; };
/* /*
@@ -323,13 +313,12 @@ static const BdrvChildRole child_root = {
* *
* Return the new BlockBackend on success, null on failure. * Return the new BlockBackend on success, null on failure.
*/ */
BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm) BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
{ {
BlockBackend *blk; BlockBackend *blk;
blk = g_new0(BlockBackend, 1); blk = g_new0(BlockBackend, 1);
blk->refcnt = 1; blk->refcnt = 1;
blk->ctx = ctx;
blk->perm = perm; blk->perm = perm;
blk->shared_perm = shared_perm; blk->shared_perm = shared_perm;
blk_set_enable_write_cache(blk, true); blk_set_enable_write_cache(blk, true);
@@ -349,7 +338,6 @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
/* /*
* Creates a new BlockBackend, opens a new BlockDriverState, and connects both. * Creates a new BlockBackend, opens a new BlockDriverState, and connects both.
* The new BlockBackend is in the main AioContext.
* *
* Just as with bdrv_open(), after having called this function the reference to * Just as with bdrv_open(), after having called this function the reference to
* @options belongs to the block layer (even on failure). * @options belongs to the block layer (even on failure).
@@ -385,16 +373,17 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
perm |= BLK_PERM_RESIZE; perm |= BLK_PERM_RESIZE;
} }
blk = blk_new(qemu_get_aio_context(), perm, BLK_PERM_ALL); blk = blk_new(perm, BLK_PERM_ALL);
bs = bdrv_open(filename, reference, options, flags, errp); bs = bdrv_open(filename, reference, options, flags, errp);
if (!bs) { if (!bs) {
blk_unref(blk); blk_unref(blk);
return NULL; return NULL;
} }
blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx, blk->root = bdrv_root_attach_child(bs, "root", &child_root,
perm, BLK_PERM_ALL, blk, errp); perm, BLK_PERM_ALL, blk, errp);
if (!blk->root) { if (!blk->root) {
bdrv_unref(bs);
blk_unref(blk); blk_unref(blk);
return NULL; return NULL;
} }
@@ -802,12 +791,12 @@ void blk_remove_bs(BlockBackend *blk)
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
{ {
ThrottleGroupMember *tgm = &blk->public.throttle_group_member; ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
bdrv_ref(bs); blk->root = bdrv_root_attach_child(bs, "root", &child_root,
blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
blk->perm, blk->shared_perm, blk, errp); blk->perm, blk->shared_perm, blk, errp);
if (blk->root == NULL) { if (blk->root == NULL) {
return -EPERM; return -EPERM;
} }
bdrv_ref(bs);
notifier_list_notify(&blk->insert_bs_notifiers, blk); notifier_list_notify(&blk->insert_bs_notifiers, blk);
if (tgm->throttle_state) { if (tgm->throttle_state) {
@@ -1073,7 +1062,11 @@ void blk_iostatus_disable(BlockBackend *blk)
void blk_iostatus_reset(BlockBackend *blk) void blk_iostatus_reset(BlockBackend *blk)
{ {
if (blk_iostatus_is_enabled(blk)) { if (blk_iostatus_is_enabled(blk)) {
BlockDriverState *bs = blk_bs(blk);
blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK; blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
if (bs && bs->job) {
block_job_iostatus_reset(bs->job);
}
} }
} }
@@ -1091,11 +1084,6 @@ void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow)
blk->allow_write_beyond_eof = allow; blk->allow_write_beyond_eof = allow;
} }
void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow)
{
blk->allow_aio_context_change = allow;
}
static int blk_check_byte_request(BlockBackend *blk, int64_t offset, static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
size_t size) size_t size)
{ {
@@ -1249,7 +1237,7 @@ int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
blk_root_drained_begin(blk->root); blk_root_drained_begin(blk->root);
ret = blk_pread(blk, offset, buf, count); ret = blk_pread(blk, offset, buf, count);
blk_root_drained_end(blk->root, NULL); blk_root_drained_end(blk->root);
return ret; return ret;
} }
@@ -1776,13 +1764,6 @@ int blk_get_flags(BlockBackend *blk)
} }
} }
/* Returns the minimum request alignment, in bytes; guaranteed nonzero */
uint32_t blk_get_request_alignment(BlockBackend *blk)
{
BlockDriverState *bs = blk_bs(blk);
return bs ? bs->bl.request_alignment : BDRV_SECTOR_SIZE;
}
/* Returns the maximum transfer length, in bytes; guaranteed nonzero */ /* Returns the maximum transfer length, in bytes; guaranteed nonzero */
uint32_t blk_get_max_transfer(BlockBackend *blk) uint32_t blk_get_max_transfer(BlockBackend *blk)
{ {
@@ -1855,14 +1836,7 @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason)
AioContext *blk_get_aio_context(BlockBackend *blk) AioContext *blk_get_aio_context(BlockBackend *blk)
{ {
BlockDriverState *bs = blk_bs(blk); return bdrv_get_aio_context(blk_bs(blk));
if (bs) {
AioContext *ctx = bdrv_get_aio_context(blk_bs(blk));
assert(ctx == blk->ctx);
}
return blk->ctx;
} }
static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb) static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
@@ -1871,64 +1845,20 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
return blk_get_aio_context(blk_acb->blk); return blk_get_aio_context(blk_acb->blk);
} }
static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context, void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
bool update_root_node, Error **errp)
{ {
BlockDriverState *bs = blk_bs(blk); BlockDriverState *bs = blk_bs(blk);
ThrottleGroupMember *tgm = &blk->public.throttle_group_member; ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
int ret;
if (bs) { if (bs) {
if (update_root_node) {
ret = bdrv_child_try_set_aio_context(bs, new_context, blk->root,
errp);
if (ret < 0) {
return ret;
}
}
if (tgm->throttle_state) { if (tgm->throttle_state) {
bdrv_drained_begin(bs); bdrv_drained_begin(bs);
throttle_group_detach_aio_context(tgm); throttle_group_detach_aio_context(tgm);
throttle_group_attach_aio_context(tgm, new_context); throttle_group_attach_aio_context(tgm, new_context);
bdrv_drained_end(bs); bdrv_drained_end(bs);
} }
bdrv_set_aio_context(bs, new_context);
} }
blk->ctx = new_context;
return 0;
}
int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
Error **errp)
{
return blk_do_set_aio_context(blk, new_context, true, errp);
}
static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
GSList **ignore, Error **errp)
{
BlockBackend *blk = child->opaque;
if (blk->allow_aio_context_change) {
return true;
}
/* Only manually created BlockBackends that are not attached to anything
* can change their AioContext without updating their user. */
if (!blk->name || blk->dev) {
/* TODO Add BB name/QOM path */
error_setg(errp, "Cannot change iothread of active block backend");
return false;
}
return true;
}
static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
GSList **ignore)
{
BlockBackend *blk = child->opaque;
blk_do_set_aio_context(blk, ctx, false, &error_abort);
} }
void blk_add_aio_context_notifier(BlockBackend *blk, void blk_add_aio_context_notifier(BlockBackend *blk,
@@ -2236,7 +2166,7 @@ static bool blk_root_drained_poll(BdrvChild *child)
return !!blk->in_flight; return !!blk->in_flight;
} }
static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter) static void blk_root_drained_end(BdrvChild *child)
{ {
BlockBackend *blk = child->opaque; BlockBackend *blk = child->opaque;
assert(blk->quiesce_counter); assert(blk->quiesce_counter);

View File

@@ -24,6 +24,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu-common.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/bswap.h" #include "qemu/bswap.h"

View File

@@ -24,6 +24,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu-common.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/bswap.h" #include "qemu/bswap.h"

View File

@@ -39,7 +39,6 @@ typedef struct CommitBlockJob {
BlockDriverState *base_bs; BlockDriverState *base_bs;
BlockdevOnError on_error; BlockdevOnError on_error;
bool base_read_only; bool base_read_only;
bool chain_frozen;
char *backing_file_str; char *backing_file_str;
} CommitBlockJob; } CommitBlockJob;
@@ -48,15 +47,16 @@ static int coroutine_fn commit_populate(BlockBackend *bs, BlockBackend *base,
void *buf) void *buf)
{ {
int ret = 0; int ret = 0;
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
assert(bytes < SIZE_MAX); assert(bytes < SIZE_MAX);
ret = blk_co_pread(bs, offset, bytes, buf, 0); ret = blk_co_preadv(bs, offset, qiov.size, &qiov, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
ret = blk_co_pwrite(base, offset, bytes, buf, 0); ret = blk_co_pwritev(base, offset, qiov.size, &qiov, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@@ -68,9 +68,6 @@ static int commit_prepare(Job *job)
{ {
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
s->chain_frozen = false;
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before /* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
* the normal backing chain can be restored. */ * the normal backing chain can be restored. */
blk_unref(s->base); blk_unref(s->base);
@@ -87,10 +84,6 @@ static void commit_abort(Job *job)
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
BlockDriverState *top_bs = blk_bs(s->top); BlockDriverState *top_bs = blk_bs(s->top);
if (s->chain_frozen) {
bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
}
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */ /* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
bdrv_ref(top_bs); bdrv_ref(top_bs);
bdrv_ref(s->commit_top_bs); bdrv_ref(s->commit_top_bs);
@@ -110,6 +103,8 @@ static void commit_abort(Job *job)
* XXX Can (or should) we somehow keep 'consistent read' blocked even * XXX Can (or should) we somehow keep 'consistent read' blocked even
* after the failed/cancelled commit job is gone? If we already wrote * after the failed/cancelled commit job is gone? If we already wrote
* something to base, the intermediate images aren't valid any more. */ * something to base, the intermediate images aren't valid any more. */
bdrv_child_try_set_perm(s->commit_top_bs->backing, 0, BLK_PERM_ALL,
&error_abort);
bdrv_replace_node(s->commit_top_bs, backing_bs(s->commit_top_bs), bdrv_replace_node(s->commit_top_bs, backing_bs(s->commit_top_bs),
&error_abort); &error_abort);
@@ -174,7 +169,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
break; break;
} }
/* Copy if allocated above the base */ /* Copy if allocated above the base */
ret = bdrv_is_allocated_above(blk_bs(s->top), blk_bs(s->base), false, ret = bdrv_is_allocated_above(blk_bs(s->top), blk_bs(s->base),
offset, COMMIT_BUFFER_SIZE, &n); offset, COMMIT_BUFFER_SIZE, &n);
copy = (ret == 1); copy = (ret == 1);
trace_commit_one_iteration(s, offset, n, ret); trace_commit_one_iteration(s, offset, n, ret);
@@ -298,20 +293,26 @@ void commit_start(const char *job_id, BlockDriverState *bs,
if (!filter_node_name) { if (!filter_node_name) {
commit_top_bs->implicit = true; commit_top_bs->implicit = true;
} }
/* So that we can always drop this node */
commit_top_bs->never_freeze = true;
commit_top_bs->total_sectors = top->total_sectors; commit_top_bs->total_sectors = top->total_sectors;
bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(top));
bdrv_append(commit_top_bs, top, &local_err); bdrv_set_backing_hd(commit_top_bs, top, &local_err);
if (local_err) { if (local_err) {
bdrv_unref(commit_top_bs);
commit_top_bs = NULL;
error_propagate(errp, local_err);
goto fail;
}
bdrv_replace_node(top, commit_top_bs, &local_err);
if (local_err) {
bdrv_unref(commit_top_bs);
commit_top_bs = NULL; commit_top_bs = NULL;
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto fail; goto fail;
} }
s->commit_top_bs = commit_top_bs; s->commit_top_bs = commit_top_bs;
bdrv_unref(commit_top_bs);
/* Block all nodes between top and base, because they will /* Block all nodes between top and base, because they will
* disappear from the chain after this operation. */ * disappear from the chain after this operation. */
@@ -329,18 +330,12 @@ void commit_start(const char *job_id, BlockDriverState *bs,
} }
} }
if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
goto fail;
}
s->chain_frozen = true;
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp); ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
s->base = blk_new(s->common.job.aio_context, s->base = blk_new(BLK_PERM_CONSISTENT_READ
BLK_PERM_CONSISTENT_READ
| BLK_PERM_WRITE | BLK_PERM_WRITE
| BLK_PERM_RESIZE, | BLK_PERM_RESIZE,
BLK_PERM_CONSISTENT_READ BLK_PERM_CONSISTENT_READ
@@ -353,7 +348,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
s->base_bs = base; s->base_bs = base;
/* Required permissions are already taken with block_job_add_bdrv() */ /* Required permissions are already taken with block_job_add_bdrv() */
s->top = blk_new(s->common.job.aio_context, 0, BLK_PERM_ALL); s->top = blk_new(0, BLK_PERM_ALL);
ret = blk_insert_bs(s->top, top, errp); ret = blk_insert_bs(s->top, top, errp);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
@@ -367,18 +362,12 @@ void commit_start(const char *job_id, BlockDriverState *bs,
return; return;
fail: fail:
if (s->chain_frozen) {
bdrv_unfreeze_backing_chain(commit_top_bs, base);
}
if (s->base) { if (s->base) {
blk_unref(s->base); blk_unref(s->base);
} }
if (s->top) { if (s->top) {
blk_unref(s->top); blk_unref(s->top);
} }
if (s->base_read_only) {
bdrv_reopen_set_read_only(base, true, NULL);
}
job_early_fail(&s->common.job); job_early_fail(&s->common.job);
/* commit_top_bs has to be replaced after deleting the block job, /* commit_top_bs has to be replaced after deleting the block job,
* otherwise this would fail because of lack of permissions. */ * otherwise this would fail because of lack of permissions. */
@@ -397,7 +386,6 @@ int bdrv_commit(BlockDriverState *bs)
BlockDriverState *backing_file_bs = NULL; BlockDriverState *backing_file_bs = NULL;
BlockDriverState *commit_top_bs = NULL; BlockDriverState *commit_top_bs = NULL;
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
AioContext *ctx;
int64_t offset, length, backing_length; int64_t offset, length, backing_length;
int ro; int ro;
int64_t n; int64_t n;
@@ -425,9 +413,8 @@ int bdrv_commit(BlockDriverState *bs)
} }
} }
ctx = bdrv_get_aio_context(bs); src = blk_new(BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL);
src = blk_new(ctx, BLK_PERM_CONSISTENT_READ, BLK_PERM_ALL); backing = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(src, bs, &local_err); ret = blk_insert_bs(src, bs, &local_err);
if (ret < 0) { if (ret < 0) {
@@ -444,6 +431,7 @@ int bdrv_commit(BlockDriverState *bs)
error_report_err(local_err); error_report_err(local_err);
goto ro_cleanup; goto ro_cleanup;
} }
bdrv_set_aio_context(commit_top_bs, bdrv_get_aio_context(backing_file_bs));
bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort); bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
bdrv_set_backing_hd(bs, commit_top_bs, &error_abort); bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);

View File

@@ -22,7 +22,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "qemu/module.h"
static int cor_open(BlockDriverState *bs, QDict *options, int flags, static int cor_open(BlockDriverState *bs, QDict *options, int flags,
@@ -35,11 +34,12 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
} }
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags); (BDRV_REQ_FUA &
bs->file->bs->supported_write_flags);
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP) &
bs->file->bs->supported_zero_flags); bs->file->bs->supported_zero_flags);
return 0; return 0;
} }
@@ -56,14 +56,16 @@ static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
uint64_t perm, uint64_t shared, uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared) uint64_t *nperm, uint64_t *nshared)
{ {
*nperm = perm & PERM_PASSTHROUGH; if (c == NULL) {
*nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED; *nperm = (perm & PERM_PASSTHROUGH) | BLK_PERM_WRITE_UNCHANGED;
*nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED;
/* We must not request write permissions for an inactive node, the child return;
* cannot provide it. */
if (!(bs->open_flags & BDRV_O_INACTIVE)) {
*nperm |= BLK_PERM_WRITE_UNCHANGED;
} }
*nperm = (perm & PERM_PASSTHROUGH) |
(c->perm & PERM_UNCHANGED);
*nshared = (shared & PERM_PASSTHROUGH) |
(c->shared_perm & PERM_UNCHANGED);
} }
@@ -132,7 +134,7 @@ static bool cor_recurse_is_first_non_filter(BlockDriverState *bs,
} }
static BlockDriver bdrv_copy_on_read = { BlockDriver bdrv_copy_on_read = {
.format_name = "copy-on-read", .format_name = "copy-on-read",
.bdrv_open = cor_open, .bdrv_open = cor_open,

View File

@@ -63,13 +63,9 @@ void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
const char *fmt = BlockdevDriver_str(options->driver); const char *fmt = BlockdevDriver_str(options->driver);
BlockDriver *drv = bdrv_find_format(fmt); BlockDriver *drv = bdrv_find_format(fmt);
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 /* If the driver is in the schema, we know that it exists. But it may not
* be whitelisted. */ * be whitelisted. */
assert(drv);
if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) { if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
error_setg(errp, "Driver is not whitelisted"); error_setg(errp, "Driver is not whitelisted");
return; return;

View File

@@ -28,7 +28,6 @@
#include "qapi/qapi-visit-crypto.h" #include "qapi/qapi-visit-crypto.h"
#include "qapi/qobject-input-visitor.h" #include "qapi/qobject-input-visitor.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/module.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "crypto.h" #include "crypto.h"
@@ -258,8 +257,7 @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
QCryptoBlock *crypto = NULL; QCryptoBlock *crypto = NULL;
struct BlockCryptoCreateData data; struct BlockCryptoCreateData data;
blk = blk_new(bdrv_get_aio_context(bs), blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
ret = blk_insert_bs(blk, bs, errp); ret = blk_insert_bs(blk, bs, errp);
if (ret < 0) { if (ret < 0) {
@@ -627,7 +625,7 @@ static const char *const block_crypto_strong_runtime_opts[] = {
NULL NULL
}; };
static BlockDriver bdrv_crypto_luks = { BlockDriver bdrv_crypto_luks = {
.format_name = "luks", .format_name = "luks",
.instance_size = sizeof(BlockCrypto), .instance_size = sizeof(BlockCrypto),
.bdrv_probe = block_crypto_probe_luks, .bdrv_probe = block_crypto_probe_luks,

View File

@@ -18,8 +18,8 @@
* *
*/ */
#ifndef BLOCK_CRYPTO_H #ifndef BLOCK_CRYPTO_H__
#define BLOCK_CRYPTO_H #define BLOCK_CRYPTO_H__
#define BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, helpstr) \ #define BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, helpstr) \
{ \ { \
@@ -94,4 +94,4 @@ block_crypto_create_opts_init(QDict *opts, Error **errp);
QCryptoBlockOpenOptions * QCryptoBlockOpenOptions *
block_crypto_open_opts_init(QDict *opts, Error **errp); block_crypto_open_opts_init(QDict *opts, Error **errp);
#endif /* BLOCK_CRYPTO_H */ #endif /* BLOCK_CRYPTO_H__ */

View File

@@ -25,7 +25,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/option.h" #include "qemu/option.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
@@ -80,7 +79,6 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
#define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5 #define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5
struct BDRVCURLState; struct BDRVCURLState;
struct CURLState;
static bool libcurl_initialized; static bool libcurl_initialized;
@@ -98,7 +96,6 @@ typedef struct CURLAIOCB {
typedef struct CURLSocket { typedef struct CURLSocket {
int fd; int fd;
struct CURLState *state;
QLIST_ENTRY(CURLSocket) next; QLIST_ENTRY(CURLSocket) next;
} CURLSocket; } CURLSocket;
@@ -139,6 +136,7 @@ typedef struct BDRVCURLState {
static void curl_clean_state(CURLState *s); static void curl_clean_state(CURLState *s);
static void curl_multi_do(void *arg); static void curl_multi_do(void *arg);
static void curl_multi_read(void *arg);
#ifdef NEED_CURL_TIMER_CALLBACK #ifdef NEED_CURL_TIMER_CALLBACK
/* Called from curl_multi_do_locked, with s->mutex held. */ /* Called from curl_multi_do_locked, with s->mutex held. */
@@ -171,29 +169,33 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
QLIST_FOREACH(socket, &state->sockets, next) { QLIST_FOREACH(socket, &state->sockets, next) {
if (socket->fd == fd) { if (socket->fd == fd) {
if (action == CURL_POLL_REMOVE) {
QLIST_REMOVE(socket, next);
g_free(socket);
}
break; break;
} }
} }
if (!socket) { if (!socket) {
socket = g_new0(CURLSocket, 1); socket = g_new0(CURLSocket, 1);
socket->fd = fd; socket->fd = fd;
socket->state = state;
QLIST_INSERT_HEAD(&state->sockets, socket, next); QLIST_INSERT_HEAD(&state->sockets, socket, next);
} }
socket = NULL;
trace_curl_sock_cb(action, (int)fd); trace_curl_sock_cb(action, (int)fd);
switch (action) { switch (action) {
case CURL_POLL_IN: case CURL_POLL_IN:
aio_set_fd_handler(s->aio_context, fd, false, aio_set_fd_handler(s->aio_context, fd, false,
curl_multi_do, NULL, NULL, socket); curl_multi_read, NULL, NULL, state);
break; break;
case CURL_POLL_OUT: case CURL_POLL_OUT:
aio_set_fd_handler(s->aio_context, fd, false, aio_set_fd_handler(s->aio_context, fd, false,
NULL, curl_multi_do, NULL, socket); NULL, curl_multi_do, NULL, state);
break; break;
case CURL_POLL_INOUT: case CURL_POLL_INOUT:
aio_set_fd_handler(s->aio_context, fd, false, aio_set_fd_handler(s->aio_context, fd, false,
curl_multi_do, curl_multi_do, NULL, socket); curl_multi_read, curl_multi_do, NULL, state);
break; break;
case CURL_POLL_REMOVE: case CURL_POLL_REMOVE:
aio_set_fd_handler(s->aio_context, fd, false, aio_set_fd_handler(s->aio_context, fd, false,
@@ -201,11 +203,6 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
break; break;
} }
if (action == CURL_POLL_REMOVE) {
QLIST_REMOVE(socket, next);
g_free(socket);
}
return 0; return 0;
} }
@@ -229,6 +226,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
{ {
CURLState *s = ((CURLState*)opaque); CURLState *s = ((CURLState*)opaque);
size_t realsize = size * nmemb; size_t realsize = size * nmemb;
int i;
trace_curl_read_cb(realsize); trace_curl_read_cb(realsize);
@@ -244,6 +242,32 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
memcpy(s->orig_buf + s->buf_off, ptr, realsize); memcpy(s->orig_buf + s->buf_off, ptr, realsize);
s->buf_off += realsize; s->buf_off += realsize;
for(i=0; i<CURL_NUM_ACB; i++) {
CURLAIOCB *acb = s->acb[i];
if (!acb)
continue;
if ((s->buf_off >= acb->end)) {
size_t request_length = acb->bytes;
qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
acb->end - acb->start);
if (acb->end - acb->start < request_length) {
size_t offset = acb->end - acb->start;
qemu_iovec_memset(acb->qiov, offset, 0,
request_length - offset);
}
acb->ret = 0;
s->acb[i] = NULL;
qemu_mutex_unlock(&s->s->mutex);
aio_co_wake(acb->co);
qemu_mutex_lock(&s->s->mutex);
}
}
read_end: read_end:
/* curl will error out if we do not return this value */ /* curl will error out if we do not return this value */
return size * nmemb; return size * nmemb;
@@ -324,14 +348,13 @@ static void curl_multi_check_completion(BDRVCURLState *s)
break; break;
if (msg->msg == CURLMSG_DONE) { if (msg->msg == CURLMSG_DONE) {
int i;
CURLState *state = NULL; CURLState *state = NULL;
bool error = msg->data.result != CURLE_OK;
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
(char **)&state); (char **)&state);
if (error) { /* ACBs for successful messages get completed in curl_read_cb */
if (msg->data.result != CURLE_OK) {
int i;
static int errcount = 100; static int errcount = 100;
/* Don't lose the original error message from curl, since /* Don't lose the original error message from curl, since
@@ -343,35 +366,20 @@ static void curl_multi_check_completion(BDRVCURLState *s)
error_report("curl: further errors suppressed"); error_report("curl: further errors suppressed");
} }
} }
}
for (i = 0; i < CURL_NUM_ACB; i++) { for (i = 0; i < CURL_NUM_ACB; i++) {
CURLAIOCB *acb = state->acb[i]; CURLAIOCB *acb = state->acb[i];
if (acb == NULL) { if (acb == NULL) {
continue; continue;
}
if (!error) {
/* Assert that we have read all data */
assert(state->buf_off >= acb->end);
qemu_iovec_from_buf(acb->qiov, 0,
state->orig_buf + acb->start,
acb->end - acb->start);
if (acb->end - acb->start < acb->bytes) {
size_t offset = acb->end - acb->start;
qemu_iovec_memset(acb->qiov, offset, 0,
acb->bytes - offset);
} }
}
acb->ret = error ? -EIO : 0; acb->ret = -EIO;
state->acb[i] = NULL; state->acb[i] = NULL;
qemu_mutex_unlock(&s->mutex); qemu_mutex_unlock(&s->mutex);
aio_co_wake(acb->co); aio_co_wake(acb->co);
qemu_mutex_lock(&s->mutex); qemu_mutex_lock(&s->mutex);
}
} }
curl_clean_state(state); curl_clean_state(state);
@@ -381,30 +389,42 @@ static void curl_multi_check_completion(BDRVCURLState *s)
} }
/* Called with s->mutex held. */ /* Called with s->mutex held. */
static void curl_multi_do_locked(CURLSocket *socket) static void curl_multi_do_locked(CURLState *s)
{ {
BDRVCURLState *s = socket->state->s; CURLSocket *socket, *next_socket;
int running; int running;
int r; int r;
if (!s->multi) { if (!s->s->multi) {
return; return;
} }
do { /* Need to use _SAFE because curl_multi_socket_action() may trigger
r = curl_multi_socket_action(s->multi, socket->fd, 0, &running); * curl_sock_cb() which might modify this list */
} while (r == CURLM_CALL_MULTI_PERFORM); QLIST_FOREACH_SAFE(socket, &s->sockets, next, next_socket) {
do {
r = curl_multi_socket_action(s->s->multi, socket->fd, 0, &running);
} while (r == CURLM_CALL_MULTI_PERFORM);
}
} }
static void curl_multi_do(void *arg) static void curl_multi_do(void *arg)
{ {
CURLSocket *socket = arg; CURLState *s = (CURLState *)arg;
BDRVCURLState *s = socket->state->s;
qemu_mutex_lock(&s->mutex); qemu_mutex_lock(&s->s->mutex);
curl_multi_do_locked(socket); curl_multi_do_locked(s);
curl_multi_check_completion(s); qemu_mutex_unlock(&s->s->mutex);
qemu_mutex_unlock(&s->mutex); }
static void curl_multi_read(void *arg)
{
CURLState *s = (CURLState *)arg;
qemu_mutex_lock(&s->s->mutex);
curl_multi_do_locked(s);
curl_multi_check_completion(s->s);
qemu_mutex_unlock(&s->s->mutex);
} }
static void curl_multi_timeout_do(void *arg) static void curl_multi_timeout_do(void *arg)

View File

@@ -23,16 +23,34 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu-common.h"
#include "trace.h" #include "trace.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "block/blockjob.h" #include "block/blockjob.h"
/**
* A BdrvDirtyBitmap can be in four possible user-visible states:
* (1) Active: successor is NULL, and disabled is false: full r/w mode
* (2) Disabled: successor is NULL, and disabled is true: qualified r/w mode,
* guest writes are dropped, but monitor writes are possible,
* through commands like merge and clear.
* (3) Frozen: successor is not NULL.
* A frozen bitmap cannot be renamed, deleted, cleared, set,
* enabled, merged to, etc. A frozen bitmap can only abdicate()
* or reclaim().
* In this state, the anonymous successor bitmap may be either
* Active and recording writes from the guest (e.g. backup jobs),
* but it can be Disabled and not recording writes.
* (4) Locked: Whether Active or Disabled, the user cannot modify this bitmap
* in any way from the monitor.
*/
struct BdrvDirtyBitmap { struct BdrvDirtyBitmap {
QemuMutex *mutex; QemuMutex *mutex;
HBitmap *bitmap; /* Dirty bitmap implementation */ HBitmap *bitmap; /* Dirty bitmap implementation */
HBitmap *meta; /* Meta dirty bitmap */ HBitmap *meta; /* Meta dirty bitmap */
bool busy; /* Bitmap is busy, it can't be used via QMP */ bool qmp_locked; /* Bitmap is locked, it can't be modified
BdrvDirtyBitmap *successor; /* Anonymous child, if any. */ through QMP */
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
char *name; /* Optional non-empty unique ID */ char *name; /* Optional non-empty unique ID */
int64_t size; /* Size of the bitmap, in bytes */ int64_t size; /* Size of the bitmap, in bytes */
bool disabled; /* Bitmap is disabled. It ignores all writes to bool disabled; /* Bitmap is disabled. It ignores all writes to
@@ -45,9 +63,6 @@ struct BdrvDirtyBitmap {
and this bitmap must remain unchanged while and this bitmap must remain unchanged while
this flag is set. */ this flag is set. */
bool persistent; /* bitmap must be saved to owner disk image */ bool persistent; /* bitmap must be saved to owner disk image */
bool inconsistent; /* bitmap is persistent, but inconsistent.
It cannot be used at all in any way, except
a QMP user can remove it. */
bool migration; /* Bitmap is selected for migration, it should bool migration; /* Bitmap is selected for migration, it should
not be stored on the next inactivation not be stored on the next inactivation
(persistent flag doesn't matter until next (persistent flag doesn't matter until next
@@ -168,58 +183,41 @@ const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
} }
/* Called with BQL taken. */ /* Called with BQL taken. */
bool bdrv_dirty_bitmap_has_successor(BdrvDirtyBitmap *bitmap) bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
{ {
return bitmap->successor; return bitmap->successor;
} }
static bool bdrv_dirty_bitmap_busy(const BdrvDirtyBitmap *bitmap) /* Both conditions disallow user-modification via QMP. */
{ bool bdrv_dirty_bitmap_user_locked(BdrvDirtyBitmap *bitmap) {
return bitmap->busy; return bdrv_dirty_bitmap_frozen(bitmap) ||
bdrv_dirty_bitmap_qmp_locked(bitmap);
} }
void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy) void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked)
{ {
qemu_mutex_lock(bitmap->mutex); qemu_mutex_lock(bitmap->mutex);
bitmap->busy = busy; bitmap->qmp_locked = qmp_locked;
qemu_mutex_unlock(bitmap->mutex); qemu_mutex_unlock(bitmap->mutex);
} }
bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap)
{
return bitmap->qmp_locked;
}
/* Called with BQL taken. */ /* Called with BQL taken. */
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap) bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
{ {
return !bitmap->disabled; return !(bitmap->disabled || bitmap->successor);
} }
/** /* Called with BQL taken. */
* bdrv_dirty_bitmap_status: This API is now deprecated.
* Called with BQL taken.
*
* A BdrvDirtyBitmap can be in four possible user-visible states:
* (1) Active: successor is NULL, and disabled is false: full r/w mode
* (2) Disabled: successor is NULL, and disabled is true: qualified r/w mode,
* guest writes are dropped, but monitor writes are possible,
* through commands like merge and clear.
* (3) Frozen: successor is not NULL.
* A frozen bitmap cannot be renamed, deleted, cleared, set,
* enabled, merged to, etc. A frozen bitmap can only abdicate()
* or reclaim().
* In this state, the anonymous successor bitmap may be either
* Active and recording writes from the guest (e.g. backup jobs),
* or it can be Disabled and not recording writes.
* (4) Locked: Whether Active or Disabled, the user cannot modify this bitmap
* in any way from the monitor.
* (5) Inconsistent: This is a persistent bitmap whose "in use" bit is set, and
* is unusable by QEMU. It can be deleted to remove it from
* the qcow2.
*/
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap) DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
{ {
if (bdrv_dirty_bitmap_inconsistent(bitmap)) { if (bdrv_dirty_bitmap_frozen(bitmap)) {
return DIRTY_BITMAP_STATUS_INCONSISTENT;
} else if (bdrv_dirty_bitmap_has_successor(bitmap)) {
return DIRTY_BITMAP_STATUS_FROZEN; return DIRTY_BITMAP_STATUS_FROZEN;
} else if (bdrv_dirty_bitmap_busy(bitmap)) { } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) {
return DIRTY_BITMAP_STATUS_LOCKED; return DIRTY_BITMAP_STATUS_LOCKED;
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) { } else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
return DIRTY_BITMAP_STATUS_DISABLED; return DIRTY_BITMAP_STATUS_DISABLED;
@@ -228,44 +226,9 @@ DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
} }
} }
/* Called with BQL taken. */
static bool bdrv_dirty_bitmap_recording(BdrvDirtyBitmap *bitmap)
{
return !bitmap->disabled || (bitmap->successor &&
!bitmap->successor->disabled);
}
int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags,
Error **errp)
{
if ((flags & BDRV_BITMAP_BUSY) && bdrv_dirty_bitmap_busy(bitmap)) {
error_setg(errp, "Bitmap '%s' is currently in use by another"
" operation and cannot be used", bitmap->name);
return -1;
}
if ((flags & BDRV_BITMAP_RO) && bdrv_dirty_bitmap_readonly(bitmap)) {
error_setg(errp, "Bitmap '%s' is readonly and cannot be modified",
bitmap->name);
return -1;
}
if ((flags & BDRV_BITMAP_INCONSISTENT) &&
bdrv_dirty_bitmap_inconsistent(bitmap)) {
error_setg(errp, "Bitmap '%s' is inconsistent and cannot be used",
bitmap->name);
error_append_hint(errp, "Try block-dirty-bitmap-remove to delete"
" this bitmap from disk");
return -1;
}
return 0;
}
/** /**
* Create a successor bitmap destined to replace this bitmap after an operation. * Create a successor bitmap destined to replace this bitmap after an operation.
* Requires that the bitmap is not marked busy and has no successor. * Requires that the bitmap is not frozen and has no successor.
* The successor will be enabled if the parent bitmap was.
* Called with BQL taken. * Called with BQL taken.
*/ */
int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
@@ -274,14 +237,12 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
uint64_t granularity; uint64_t granularity;
BdrvDirtyBitmap *child; BdrvDirtyBitmap *child;
if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY, errp)) { if (bdrv_dirty_bitmap_frozen(bitmap)) {
return -1; error_setg(errp, "Cannot create a successor for a bitmap that is "
} "currently frozen");
if (bdrv_dirty_bitmap_has_successor(bitmap)) {
error_setg(errp, "Cannot create a successor for a bitmap that already "
"has one");
return -1; return -1;
} }
assert(!bitmap->successor);
/* Create an anonymous successor */ /* Create an anonymous successor */
granularity = bdrv_dirty_bitmap_granularity(bitmap); granularity = bdrv_dirty_bitmap_granularity(bitmap);
@@ -292,16 +253,15 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
/* Successor will be on or off based on our current state. */ /* Successor will be on or off based on our current state. */
child->disabled = bitmap->disabled; child->disabled = bitmap->disabled;
bitmap->disabled = true;
/* Install the successor and mark the parent as busy */ /* Install the successor and freeze the parent */
bitmap->successor = child; bitmap->successor = child;
bitmap->busy = true;
return 0; return 0;
} }
void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap) void bdrv_enable_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap)
{ {
assert(!bdrv_dirty_bitmap_frozen(bitmap));
bitmap->disabled = false; bitmap->disabled = false;
} }
@@ -318,8 +278,7 @@ void bdrv_dirty_bitmap_enable_successor(BdrvDirtyBitmap *bitmap)
static void bdrv_release_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap) static void bdrv_release_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap)
{ {
assert(!bitmap->active_iterators); assert(!bitmap->active_iterators);
assert(!bdrv_dirty_bitmap_busy(bitmap)); assert(!bdrv_dirty_bitmap_frozen(bitmap));
assert(!bdrv_dirty_bitmap_has_successor(bitmap));
assert(!bitmap->meta); assert(!bitmap->meta);
QLIST_REMOVE(bitmap, list); QLIST_REMOVE(bitmap, list);
hbitmap_free(bitmap->bitmap); hbitmap_free(bitmap->bitmap);
@@ -351,7 +310,6 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
bitmap->successor = NULL; bitmap->successor = NULL;
successor->persistent = bitmap->persistent; successor->persistent = bitmap->persistent;
bitmap->persistent = false; bitmap->persistent = false;
bitmap->busy = false;
bdrv_release_dirty_bitmap(bs, bitmap); bdrv_release_dirty_bitmap(bs, bitmap);
return successor; return successor;
@@ -360,8 +318,7 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
/** /**
* In cases of failure where we can no longer safely delete the parent, * In cases of failure where we can no longer safely delete the parent,
* we may wish to re-join the parent and child/successor. * we may wish to re-join the parent and child/successor.
* The merged parent will be marked as not busy. * The merged parent will be un-frozen, but not explicitly re-enabled.
* The marged parent will be enabled if and only if the successor was enabled.
* Called within bdrv_dirty_bitmap_lock..unlock and with BQL taken. * Called within bdrv_dirty_bitmap_lock..unlock and with BQL taken.
*/ */
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
@@ -379,9 +336,6 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
error_setg(errp, "Merging of parent and successor bitmap failed"); error_setg(errp, "Merging of parent and successor bitmap failed");
return NULL; return NULL;
} }
parent->disabled = successor->disabled;
parent->busy = false;
bdrv_release_dirty_bitmap_locked(successor); bdrv_release_dirty_bitmap_locked(successor);
parent->successor = NULL; parent->successor = NULL;
@@ -412,8 +366,7 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes)
bdrv_dirty_bitmaps_lock(bs); bdrv_dirty_bitmaps_lock(bs);
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) { QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
assert(!bdrv_dirty_bitmap_busy(bitmap)); assert(!bdrv_dirty_bitmap_frozen(bitmap));
assert(!bdrv_dirty_bitmap_has_successor(bitmap));
assert(!bitmap->active_iterators); assert(!bitmap->active_iterators);
hbitmap_truncate(bitmap->bitmap, bytes); hbitmap_truncate(bitmap->bitmap, bytes);
bitmap->size = bytes; bitmap->size = bytes;
@@ -431,7 +384,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
/** /**
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()). * Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
* There must not be any busy bitmaps attached. * There must not be any frozen bitmaps attached.
* This function does not remove persistent bitmaps from the storage. * This function does not remove persistent bitmaps from the storage.
* Called with BQL taken. * Called with BQL taken.
*/ */
@@ -468,6 +421,7 @@ void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
{ {
bdrv_dirty_bitmap_lock(bitmap); bdrv_dirty_bitmap_lock(bitmap);
assert(!bdrv_dirty_bitmap_frozen(bitmap));
bitmap->disabled = true; bitmap->disabled = true;
bdrv_dirty_bitmap_unlock(bitmap); bdrv_dirty_bitmap_unlock(bitmap);
} }
@@ -494,11 +448,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
info->has_name = !!bm->name; info->has_name = !!bm->name;
info->name = g_strdup(bm->name); info->name = g_strdup(bm->name);
info->status = bdrv_dirty_bitmap_status(bm); info->status = bdrv_dirty_bitmap_status(bm);
info->recording = bdrv_dirty_bitmap_recording(bm);
info->busy = bdrv_dirty_bitmap_busy(bm);
info->persistent = bm->persistent; info->persistent = bm->persistent;
info->has_inconsistent = bm->inconsistent;
info->inconsistent = bm->inconsistent;
entry->value = info; entry->value = info;
*plist = entry; *plist = entry;
plist = &entry->next; plist = &entry->next;
@@ -581,6 +531,7 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes) int64_t offset, int64_t bytes)
{ {
assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap)); assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_set(bitmap->bitmap, offset, bytes); hbitmap_set(bitmap->bitmap, offset, bytes);
} }
@@ -597,6 +548,7 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap, void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes) int64_t offset, int64_t bytes)
{ {
assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap)); assert(!bdrv_dirty_bitmap_readonly(bitmap));
hbitmap_reset(bitmap->bitmap, offset, bytes); hbitmap_reset(bitmap->bitmap, offset, bytes);
} }
@@ -739,23 +691,13 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs)
} }
/* Called with BQL taken. */ /* Called with BQL taken. */
void bdrv_dirty_bitmap_set_persistence(BdrvDirtyBitmap *bitmap, bool persistent) void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
{ {
qemu_mutex_lock(bitmap->mutex); qemu_mutex_lock(bitmap->mutex);
bitmap->persistent = persistent; bitmap->persistent = persistent;
qemu_mutex_unlock(bitmap->mutex); qemu_mutex_unlock(bitmap->mutex);
} }
/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap)
{
qemu_mutex_lock(bitmap->mutex);
assert(bitmap->persistent == true);
bitmap->inconsistent = true;
bitmap->disabled = true;
qemu_mutex_unlock(bitmap->mutex);
}
/* Called with BQL taken. */ /* Called with BQL taken. */
void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration) void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration)
{ {
@@ -764,16 +706,11 @@ void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration)
qemu_mutex_unlock(bitmap->mutex); qemu_mutex_unlock(bitmap->mutex);
} }
bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap) bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
{ {
return bitmap->persistent && !bitmap->migration; return bitmap->persistent && !bitmap->migration;
} }
bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap)
{
return bitmap->inconsistent;
}
bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs) bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs)
{ {
BdrvDirtyBitmap *bm; BdrvDirtyBitmap *bm;
@@ -815,16 +752,20 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
{ {
bool ret; bool ret;
qemu_mutex_lock(dest->mutex); /* only bitmaps from one bds are supported */
if (src->mutex != dest->mutex) { assert(dest->mutex == src->mutex);
qemu_mutex_lock(src->mutex);
}
if (bdrv_dirty_bitmap_check(dest, BDRV_BITMAP_DEFAULT, errp)) { qemu_mutex_lock(dest->mutex);
if (bdrv_dirty_bitmap_user_locked(dest)) {
error_setg(errp, "Bitmap '%s' is currently in use by another"
" operation and cannot be modified", dest->name);
goto out; goto out;
} }
if (bdrv_dirty_bitmap_check(src, BDRV_BITMAP_ALLOW_RO, errp)) { if (bdrv_dirty_bitmap_readonly(dest)) {
error_setg(errp, "Bitmap '%s' is readonly and cannot be modified",
dest->name);
goto out; goto out;
} }
@@ -844,7 +785,4 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
out: out:
qemu_mutex_unlock(dest->mutex); qemu_mutex_unlock(dest->mutex);
if (src->mutex != dest->mutex) {
qemu_mutex_unlock(src->mutex);
}
} }

View File

@@ -23,6 +23,7 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "dmg.h" #include "dmg.h"
#include <bzlib.h> #include <bzlib.h>

View File

@@ -23,6 +23,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu-common.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "qemu/bswap.h" #include "qemu/bswap.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"

View File

@@ -26,6 +26,7 @@
#ifndef BLOCK_DMG_H #ifndef BLOCK_DMG_H
#define BLOCK_DMG_H #define BLOCK_DMG_H
#include "qemu-common.h"
#include "block/block_int.h" #include "block/block_int.h"
#include <zlib.h> #include <zlib.h>

View File

@@ -23,7 +23,6 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
@@ -145,10 +144,6 @@ typedef struct BDRVRawState {
uint64_t locked_perm; uint64_t locked_perm;
uint64_t locked_shared_perm; uint64_t locked_shared_perm;
int perm_change_fd;
int perm_change_flags;
BDRVReopenState *reopen_state;
#ifdef CONFIG_XFS #ifdef CONFIG_XFS
bool is_xfs:1; bool is_xfs:1;
#endif #endif
@@ -159,7 +154,6 @@ typedef struct BDRVRawState {
bool page_cache_inconsistent:1; bool page_cache_inconsistent:1;
bool has_fallocate; bool has_fallocate;
bool needs_alignment; bool needs_alignment;
bool drop_cache;
bool check_cache_dropped; bool check_cache_dropped;
PRManager *pr_mgr; PRManager *pr_mgr;
@@ -168,7 +162,6 @@ typedef struct BDRVRawState {
typedef struct BDRVRawReopenState { typedef struct BDRVRawReopenState {
int fd; int fd;
int open_flags; int open_flags;
bool drop_cache;
bool check_cache_dropped; bool check_cache_dropped;
} BDRVRawReopenState; } BDRVRawReopenState;
@@ -323,7 +316,6 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
char *buf; char *buf;
size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize()); size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize());
size_t alignments[] = {1, 512, 1024, 2048, 4096};
/* For SCSI generic devices the alignment is not really used. /* For SCSI generic devices the alignment is not really used.
With buffered I/O, we don't have any restrictions. */ With buffered I/O, we don't have any restrictions. */
@@ -350,38 +342,25 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
} }
#endif #endif
/* /* If we could not get the sizes so far, we can only guess them */
* If we could not get the sizes so far, we can only guess them. First try if (!s->buf_align) {
* to detect request alignment, since it is more likely to succeed. Then
* try to detect buf_align, which cannot be detected in some cases (e.g.
* Gluster). If buf_align cannot be detected, we fallback to the value of
* request_alignment.
*/
if (!bs->bl.request_alignment) {
int i;
size_t align; size_t align;
buf = qemu_memalign(max_align, max_align); buf = qemu_memalign(max_align, 2 * max_align);
for (i = 0; i < ARRAY_SIZE(alignments); i++) { for (align = 512; align <= max_align; align <<= 1) {
align = alignments[i]; if (raw_is_io_aligned(fd, buf + align, max_align)) {
if (raw_is_io_aligned(fd, buf, align)) { s->buf_align = align;
/* Fallback to safe value. */
bs->bl.request_alignment = (align != 1) ? align : max_align;
break; break;
} }
} }
qemu_vfree(buf); qemu_vfree(buf);
} }
if (!s->buf_align) { if (!bs->bl.request_alignment) {
int i;
size_t align; size_t align;
buf = qemu_memalign(max_align, 2 * max_align); buf = qemu_memalign(s->buf_align, max_align);
for (i = 0; i < ARRAY_SIZE(alignments); i++) { for (align = 512; align <= max_align; align <<= 1) {
align = alignments[i]; if (raw_is_io_aligned(fd, buf, align)) {
if (raw_is_io_aligned(fd, buf + align, max_align)) { bs->bl.request_alignment = align;
/* Fallback to request_aligment. */
s->buf_align = (align != 1) ? align : bs->bl.request_alignment;
break; break;
} }
} }
@@ -394,21 +373,13 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
} }
} }
static void raw_parse_flags(int bdrv_flags, int *open_flags, bool has_writers) static void raw_parse_flags(int bdrv_flags, int *open_flags)
{ {
bool read_write = false;
assert(open_flags != NULL); assert(open_flags != NULL);
*open_flags |= O_BINARY; *open_flags |= O_BINARY;
*open_flags &= ~O_ACCMODE; *open_flags &= ~O_ACCMODE;
if (bdrv_flags & BDRV_O_RDWR) {
if (bdrv_flags & BDRV_O_AUTO_RDONLY) {
read_write = has_writers;
} else if (bdrv_flags & BDRV_O_RDWR) {
read_write = true;
}
if (read_write) {
*open_flags |= O_RDWR; *open_flags |= O_RDWR;
} else { } else {
*open_flags |= O_RDONLY; *open_flags |= O_RDONLY;
@@ -451,13 +422,6 @@ static QemuOptsList raw_runtime_opts = {
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "id of persistent reservation manager object (default: none)", .help = "id of persistent reservation manager object (default: none)",
}, },
#if defined(__linux__)
{
.name = "drop-cache",
.type = QEMU_OPT_BOOL,
.help = "invalidate page cache during live migration (default: on)",
},
#endif
{ {
.name = "x-check-cache-dropped", .name = "x-check-cache-dropped",
.type = QEMU_OPT_BOOL, .type = QEMU_OPT_BOOL,
@@ -467,8 +431,6 @@ static QemuOptsList raw_runtime_opts = {
}, },
}; };
static const char *const mutable_opts[] = { "x-check-cache-dropped", NULL };
static int raw_open_common(BlockDriverState *bs, QDict *options, static int raw_open_common(BlockDriverState *bs, QDict *options,
int bdrv_flags, int open_flags, int bdrv_flags, int open_flags,
bool device, Error **errp) bool device, Error **errp)
@@ -549,17 +511,28 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
} }
} }
s->drop_cache = qemu_opt_get_bool(opts, "drop-cache", true);
s->check_cache_dropped = qemu_opt_get_bool(opts, "x-check-cache-dropped", s->check_cache_dropped = qemu_opt_get_bool(opts, "x-check-cache-dropped",
false); false);
s->open_flags = open_flags; s->open_flags = open_flags;
raw_parse_flags(bdrv_flags, &s->open_flags, false); raw_parse_flags(bdrv_flags, &s->open_flags);
s->fd = -1; s->fd = -1;
fd = qemu_open(filename, s->open_flags, 0644); fd = qemu_open(filename, s->open_flags, 0644);
ret = fd < 0 ? -errno : 0; ret = fd < 0 ? -errno : 0;
if (ret == -EACCES || ret == -EROFS) {
/* Try to degrade to read-only, but if it doesn't work, still use the
* normal error message. */
if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
bdrv_flags &= ~BDRV_O_RDWR;
raw_parse_flags(bdrv_flags, &s->open_flags);
assert(!(s->open_flags & O_CREAT));
fd = qemu_open(filename, s->open_flags);
ret = fd < 0 ? -errno : 0;
}
}
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not open '%s'", filename); error_setg_errno(errp, -ret, "Could not open '%s'", filename);
if (ret == -EROFS) { if (ret == -EROFS) {
@@ -668,7 +641,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
} }
#endif #endif
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP;
ret = 0; ret = 0;
fail: fail:
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) { if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
@@ -831,18 +804,6 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
switch (op) { switch (op) {
case RAW_PL_PREPARE: case RAW_PL_PREPARE:
if ((s->perm | new_perm) == s->perm &&
(s->shared_perm & new_shared) == s->shared_perm)
{
/*
* We are going to unlock bytes, it should not fail. If it fail due
* to some fs-dependent permission-unrelated reasons (which occurs
* sometimes on NFS and leads to abort in bdrv_replace_child) we
* can't prevent such errors by any check here. And we ignore them
* anyway in ABORT and COMMIT.
*/
return 0;
}
ret = raw_apply_lock_bytes(s, s->fd, s->perm | new_perm, ret = raw_apply_lock_bytes(s, s->fd, s->perm | new_perm,
~s->shared_perm | ~new_shared, ~s->shared_perm | ~new_shared,
false, errp); false, errp);
@@ -881,77 +842,13 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
return ret; return ret;
} }
static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
int *open_flags, uint64_t perm, bool force_dup,
Error **errp)
{
BDRVRawState *s = bs->opaque;
int fd = -1;
int ret;
bool has_writers = perm &
(BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_RESIZE);
int fcntl_flags = O_APPEND | O_NONBLOCK;
#ifdef O_NOATIME
fcntl_flags |= O_NOATIME;
#endif
*open_flags = 0;
if (s->type == FTYPE_CD) {
*open_flags |= O_NONBLOCK;
}
raw_parse_flags(flags, open_flags, has_writers);
#ifdef O_ASYNC
/* Not all operating systems have O_ASYNC, and those that don't
* will not let us track the state into rs->open_flags (typically
* you achieve the same effect with an ioctl, for example I_SETSIG
* on Solaris). But we do not use O_ASYNC, so that's fine.
*/
assert((s->open_flags & O_ASYNC) == 0);
#endif
if (!force_dup && *open_flags == s->open_flags) {
/* We're lucky, the existing fd is fine */
return s->fd;
}
if ((*open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
/* dup the original fd */
fd = qemu_dup(s->fd);
if (fd >= 0) {
ret = fcntl_setfl(fd, *open_flags);
if (ret) {
qemu_close(fd);
fd = -1;
}
}
}
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
if (fd == -1) {
const char *normalized_filename = bs->filename;
ret = raw_normalize_devicepath(&normalized_filename, errp);
if (ret >= 0) {
assert(!(*open_flags & O_CREAT));
fd = qemu_open(normalized_filename, *open_flags);
if (fd == -1) {
error_setg_errno(errp, errno, "Could not reopen file");
return -1;
}
}
}
return fd;
}
static int raw_reopen_prepare(BDRVReopenState *state, static int raw_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp) BlockReopenQueue *queue, Error **errp)
{ {
BDRVRawState *s; BDRVRawState *s;
BDRVRawReopenState *rs; BDRVRawReopenState *rs;
QemuOpts *opts; QemuOpts *opts;
int ret; int ret = 0;
Error *local_err = NULL; Error *local_err = NULL;
assert(state != NULL); assert(state != NULL);
@@ -961,6 +858,7 @@ static int raw_reopen_prepare(BDRVReopenState *state,
state->opaque = g_new0(BDRVRawReopenState, 1); state->opaque = g_new0(BDRVRawReopenState, 1);
rs = state->opaque; rs = state->opaque;
rs->fd = -1;
/* Handle options changes */ /* Handle options changes */
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort); opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
@@ -971,7 +869,6 @@ static int raw_reopen_prepare(BDRVReopenState *state,
goto out; goto out;
} }
rs->drop_cache = qemu_opt_get_bool_del(opts, "drop-cache", true);
rs->check_cache_dropped = rs->check_cache_dropped =
qemu_opt_get_bool_del(opts, "x-check-cache-dropped", false); qemu_opt_get_bool_del(opts, "x-check-cache-dropped", false);
@@ -980,12 +877,50 @@ static int raw_reopen_prepare(BDRVReopenState *state,
* bdrv_reopen_prepare() will detect changes and complain. */ * bdrv_reopen_prepare() will detect changes and complain. */
qemu_opts_to_qdict(opts, state->options); qemu_opts_to_qdict(opts, state->options);
rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags, if (s->type == FTYPE_CD) {
state->perm, true, &local_err); rs->open_flags |= O_NONBLOCK;
if (local_err) { }
error_propagate(errp, local_err);
ret = -1; raw_parse_flags(state->flags, &rs->open_flags);
goto out;
int fcntl_flags = O_APPEND | O_NONBLOCK;
#ifdef O_NOATIME
fcntl_flags |= O_NOATIME;
#endif
#ifdef O_ASYNC
/* Not all operating systems have O_ASYNC, and those that don't
* will not let us track the state into rs->open_flags (typically
* you achieve the same effect with an ioctl, for example I_SETSIG
* on Solaris). But we do not use O_ASYNC, so that's fine.
*/
assert((s->open_flags & O_ASYNC) == 0);
#endif
if ((rs->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
/* dup the original fd */
rs->fd = qemu_dup(s->fd);
if (rs->fd >= 0) {
ret = fcntl_setfl(rs->fd, rs->open_flags);
if (ret) {
qemu_close(rs->fd);
rs->fd = -1;
}
}
}
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
if (rs->fd == -1) {
const char *normalized_filename = state->bs->filename;
ret = raw_normalize_devicepath(&normalized_filename, errp);
if (ret >= 0) {
assert(!(rs->open_flags & O_CREAT));
rs->fd = qemu_open(normalized_filename, rs->open_flags);
if (rs->fd == -1) {
error_setg_errno(errp, errno, "Could not reopen file");
ret = -1;
}
}
} }
/* Fail already reopen_prepare() if we can't get a working O_DIRECT /* Fail already reopen_prepare() if we can't get a working O_DIRECT
@@ -993,19 +928,13 @@ static int raw_reopen_prepare(BDRVReopenState *state,
if (rs->fd != -1) { if (rs->fd != -1) {
raw_probe_alignment(state->bs, rs->fd, &local_err); raw_probe_alignment(state->bs, rs->fd, &local_err);
if (local_err) { if (local_err) {
qemu_close(rs->fd);
rs->fd = -1;
error_propagate(errp, local_err); error_propagate(errp, local_err);
ret = -EINVAL; ret = -EINVAL;
goto out_fd;
} }
} }
s->reopen_state = state;
ret = 0;
out_fd:
if (ret < 0) {
qemu_close(rs->fd);
rs->fd = -1;
}
out: out:
qemu_opts_del(opts); qemu_opts_del(opts);
return ret; return ret;
@@ -1015,26 +944,29 @@ static void raw_reopen_commit(BDRVReopenState *state)
{ {
BDRVRawReopenState *rs = state->opaque; BDRVRawReopenState *rs = state->opaque;
BDRVRawState *s = state->bs->opaque; BDRVRawState *s = state->bs->opaque;
Error *local_err = NULL;
s->drop_cache = rs->drop_cache;
s->check_cache_dropped = rs->check_cache_dropped; s->check_cache_dropped = rs->check_cache_dropped;
s->open_flags = rs->open_flags; s->open_flags = rs->open_flags;
/* Copy locks to the new fd before closing the old one. */
raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
s->locked_shared_perm, false, &local_err);
if (local_err) {
/* shouldn't fail in a sane host, but report it just in case. */
error_report_err(local_err);
}
qemu_close(s->fd); qemu_close(s->fd);
s->fd = rs->fd; s->fd = rs->fd;
g_free(state->opaque); g_free(state->opaque);
state->opaque = NULL; state->opaque = NULL;
assert(s->reopen_state == state);
s->reopen_state = NULL;
} }
static void raw_reopen_abort(BDRVReopenState *state) static void raw_reopen_abort(BDRVReopenState *state)
{ {
BDRVRawReopenState *rs = state->opaque; BDRVRawReopenState *rs = state->opaque;
BDRVRawState *s = state->bs->opaque;
/* nothing to do if NULL, we didn't get far enough */ /* nothing to do if NULL, we didn't get far enough */
if (rs == NULL) { if (rs == NULL) {
@@ -1047,18 +979,17 @@ static void raw_reopen_abort(BDRVReopenState *state)
} }
g_free(state->opaque); g_free(state->opaque);
state->opaque = NULL; state->opaque = NULL;
assert(s->reopen_state == state);
s->reopen_state = NULL;
} }
static int sg_get_max_transfer_length(int fd) static int hdev_get_max_transfer_length(BlockDriverState *bs, int fd)
{ {
#ifdef BLKSECTGET #ifdef BLKSECTGET
int max_bytes = 0; int max_bytes = 0;
short max_sectors = 0;
if (ioctl(fd, BLKSECTGET, &max_bytes) == 0) { if (bs->sg && ioctl(fd, BLKSECTGET, &max_bytes) == 0) {
return max_bytes; return max_bytes;
} else if (!bs->sg && ioctl(fd, BLKSECTGET, &max_sectors) == 0) {
return max_sectors << BDRV_SECTOR_BITS;
} else { } else {
return -errno; return -errno;
} }
@@ -1067,31 +998,25 @@ static int sg_get_max_transfer_length(int fd)
#endif #endif
} }
static int sg_get_max_segments(int fd) static int hdev_get_max_segments(const struct stat *st)
{ {
#ifdef CONFIG_LINUX #ifdef CONFIG_LINUX
char buf[32]; char buf[32];
const char *end; const char *end;
char *sysfspath = NULL; char *sysfspath;
int ret; int ret;
int sysfd = -1; int fd = -1;
long max_segments; long max_segments;
struct stat st;
if (fstat(fd, &st)) {
ret = -errno;
goto out;
}
sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/max_segments", sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/max_segments",
major(st.st_rdev), minor(st.st_rdev)); major(st->st_rdev), minor(st->st_rdev));
sysfd = open(sysfspath, O_RDONLY); fd = open(sysfspath, O_RDONLY);
if (sysfd == -1) { if (fd == -1) {
ret = -errno; ret = -errno;
goto out; goto out;
} }
do { do {
ret = read(sysfd, buf, sizeof(buf) - 1); ret = read(fd, buf, sizeof(buf) - 1);
} while (ret == -1 && errno == EINTR); } while (ret == -1 && errno == EINTR);
if (ret < 0) { if (ret < 0) {
ret = -errno; ret = -errno;
@@ -1108,8 +1033,8 @@ static int sg_get_max_segments(int fd)
} }
out: out:
if (sysfd != -1) { if (fd != -1) {
close(sysfd); close(fd);
} }
g_free(sysfspath); g_free(sysfspath);
return ret; return ret;
@@ -1121,17 +1046,19 @@ out:
static void raw_refresh_limits(BlockDriverState *bs, Error **errp) static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
struct stat st;
if (bs->sg) { if (!fstat(s->fd, &st)) {
int ret = sg_get_max_transfer_length(s->fd); if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) {
int ret = hdev_get_max_transfer_length(bs, s->fd);
if (ret > 0 && ret <= BDRV_REQUEST_MAX_BYTES) { if (ret > 0 && ret <= BDRV_REQUEST_MAX_BYTES) {
bs->bl.max_transfer = pow2floor(ret); bs->bl.max_transfer = pow2floor(ret);
} }
ret = hdev_get_max_segments(&st);
ret = sg_get_max_segments(s->fd); if (ret > 0) {
if (ret > 0) { bs->bl.max_transfer = MIN(bs->bl.max_transfer,
bs->bl.max_transfer = MIN(bs->bl.max_transfer, ret * getpagesize()); ret * getpagesize());
}
} }
} }
@@ -1459,6 +1386,46 @@ out:
} }
} }
#ifdef CONFIG_XFS
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
{
struct xfs_flock64 fl;
int err;
memset(&fl, 0, sizeof(fl));
fl.l_whence = SEEK_SET;
fl.l_start = offset;
fl.l_len = bytes;
if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) {
err = errno;
trace_file_xfs_write_zeroes(strerror(errno));
return -err;
}
return 0;
}
static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
{
struct xfs_flock64 fl;
int err;
memset(&fl, 0, sizeof(fl));
fl.l_whence = SEEK_SET;
fl.l_start = offset;
fl.l_len = bytes;
if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
err = errno;
trace_file_xfs_discard(strerror(errno));
return -err;
}
return 0;
}
#endif
static int translate_err(int err) static int translate_err(int err)
{ {
if (err == -ENODEV || err == -ENOSYS || err == -EOPNOTSUPP || if (err == -ENODEV || err == -ENOSYS || err == -EOPNOTSUPP ||
@@ -1490,19 +1457,14 @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb)
} }
#ifdef BLKZEROOUT #ifdef BLKZEROOUT
/* The BLKZEROOUT implementation in the kernel doesn't set do {
* BLKDEV_ZERO_NOFALLBACK, so we can't call this if we have to avoid slow uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes };
* fallbacks. */ if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) {
if (!(aiocb->aio_type & QEMU_AIO_NO_FALLBACK)) { return 0;
do { }
uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes }; } while (errno == EINTR);
if (ioctl(aiocb->aio_fildes, BLKZEROOUT, range) == 0) {
return 0;
}
} while (errno == EINTR);
ret = translate_err(-errno); ret = translate_err(-errno);
}
#endif #endif
if (ret == -ENOTSUP) { if (ret == -ENOTSUP) {
@@ -1514,8 +1476,10 @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb)
static int handle_aiocb_write_zeroes(void *opaque) static int handle_aiocb_write_zeroes(void *opaque)
{ {
RawPosixAIOData *aiocb = opaque; RawPosixAIOData *aiocb = opaque;
#ifdef CONFIG_FALLOCATE #if defined(CONFIG_FALLOCATE) || defined(CONFIG_XFS)
BDRVRawState *s = aiocb->bs->opaque; BDRVRawState *s = aiocb->bs->opaque;
#endif
#ifdef CONFIG_FALLOCATE
int64_t len; int64_t len;
#endif #endif
@@ -1523,6 +1487,12 @@ static int handle_aiocb_write_zeroes(void *opaque)
return handle_aiocb_write_zeroes_block(aiocb); return handle_aiocb_write_zeroes_block(aiocb);
} }
#ifdef CONFIG_XFS
if (s->is_xfs) {
return xfs_write_zeroes(s, aiocb->aio_offset, aiocb->aio_nbytes);
}
#endif
#ifdef CONFIG_FALLOCATE_ZERO_RANGE #ifdef CONFIG_FALLOCATE_ZERO_RANGE
if (s->has_write_zeroes) { if (s->has_write_zeroes) {
int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE, int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE,
@@ -1585,6 +1555,14 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque)
} }
#endif #endif
#ifdef CONFIG_XFS
if (s->is_xfs) {
/* xfs_discard() guarantees that the discarded area reads as all-zero
* afterwards, so we can use it here. */
return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
}
#endif
/* If we couldn't manage to unmap while guaranteed that the area reads as /* If we couldn't manage to unmap while guaranteed that the area reads as
* all-zero afterwards, just write zeroes without unmapping */ * all-zero afterwards, just write zeroes without unmapping */
ret = handle_aiocb_write_zeroes(aiocb); ret = handle_aiocb_write_zeroes(aiocb);
@@ -1661,6 +1639,12 @@ static int handle_aiocb_discard(void *opaque)
ret = -errno; ret = -errno;
#endif #endif
} else { } else {
#ifdef CONFIG_XFS
if (s->is_xfs) {
return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes);
}
#endif
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE #ifdef CONFIG_FALLOCATE_PUNCH_HOLE
ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
aiocb->aio_offset, aiocb->aio_nbytes); aiocb->aio_offset, aiocb->aio_nbytes);
@@ -1674,43 +1658,6 @@ static int handle_aiocb_discard(void *opaque)
return ret; return ret;
} }
/*
* Help alignment probing by allocating the first block.
*
* When reading with direct I/O from unallocated area on Gluster backed by XFS,
* reading succeeds regardless of request length. In this case we fallback to
* safe alignment which is not optimal. Allocating the first block avoids this
* fallback.
*
* fd may be opened with O_DIRECT, but we don't know the buffer alignment or
* request alignment, so we use safe values.
*
* Returns: 0 on success, -errno on failure. Since this is an optimization,
* caller may ignore failures.
*/
static int allocate_first_block(int fd, size_t max_size)
{
size_t write_size = (max_size < MAX_BLOCKSIZE)
? BDRV_SECTOR_SIZE
: MAX_BLOCKSIZE;
size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize());
void *buf;
ssize_t n;
int ret;
buf = qemu_memalign(max_align, write_size);
memset(buf, 0, write_size);
do {
n = pwrite(fd, buf, write_size, 0);
} while (n == -1 && errno == EINTR);
ret = (n == -1) ? -errno : 0;
qemu_vfree(buf);
return ret;
}
static int handle_aiocb_truncate(void *opaque) static int handle_aiocb_truncate(void *opaque)
{ {
RawPosixAIOData *aiocb = opaque; RawPosixAIOData *aiocb = opaque;
@@ -1750,17 +1697,6 @@ static int handle_aiocb_truncate(void *opaque)
/* posix_fallocate() doesn't set errno. */ /* posix_fallocate() doesn't set errno. */
error_setg_errno(errp, -result, error_setg_errno(errp, -result,
"Could not preallocate new data"); "Could not preallocate new data");
} else if (current_length == 0) {
/*
* posix_fallocate() uses fallocate() if the filesystem
* supports it, or fallback to manually writing zeroes. If
* fallocate() was used, unaligned reads from the fallocated
* area in raw_probe_alignment() will succeed, hence we need to
* allocate the first block.
*
* Optimize future alignment probing; ignore failures.
*/
allocate_first_block(fd, offset);
} }
} else { } else {
result = 0; result = 0;
@@ -1822,9 +1758,6 @@ static int handle_aiocb_truncate(void *opaque)
if (ftruncate(fd, offset) != 0) { if (ftruncate(fd, offset) != 0) {
result = -errno; result = -errno;
error_setg_errno(errp, -result, "Could not resize file"); error_setg_errno(errp, -result, "Could not resize file");
} else if (current_length == 0 && offset > current_length) {
/* Optimize future alignment probing; ignore failures. */
allocate_first_block(fd, offset);
} }
return result; return result;
default: default:
@@ -2482,8 +2415,6 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
off_t data = 0, hole = 0; off_t data = 0, hole = 0;
int ret; int ret;
assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
ret = fd_open(bs); ret = fd_open(bs);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@@ -2509,20 +2440,6 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
/* On a data extent, compute bytes to the end of the extent, /* On a data extent, compute bytes to the end of the extent,
* possibly including a partial sector at EOF. */ * possibly including a partial sector at EOF. */
*pnum = MIN(bytes, hole - offset); *pnum = MIN(bytes, hole - offset);
/*
* We are not allowed to return partial sectors, though, so
* round up if necessary.
*/
if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
int64_t file_length = raw_getlength(bs);
if (file_length > 0) {
/* Ignore errors, this is just a safeguard */
assert(hole == file_length);
}
*pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
}
ret = BDRV_BLOCK_DATA; ret = BDRV_BLOCK_DATA;
} else { } else {
/* On a hole, compute bytes to the beginning of the next extent. */ /* On a hole, compute bytes to the beginning of the next extent. */
@@ -2614,10 +2531,6 @@ static void coroutine_fn raw_co_invalidate_cache(BlockDriverState *bs,
return; return;
} }
if (!s->drop_cache) {
return;
}
if (s->open_flags & O_DIRECT) { if (s->open_flags & O_DIRECT) {
return; /* No host kernel page cache */ return; /* No host kernel page cache */
} }
@@ -2688,42 +2601,6 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
RawPosixAIOData acb; RawPosixAIOData acb;
ThreadPoolFunc *handler; ThreadPoolFunc *handler;
#ifdef CONFIG_FALLOCATE
if (offset + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) {
BdrvTrackedRequest *req;
uint64_t end;
/*
* This is a workaround for a bug in the Linux XFS driver,
* where writes submitted through the AIO interface will be
* discarded if they happen beyond a concurrently running
* fallocate() that increases the file length (i.e., both the
* write and the fallocate() happen beyond the EOF).
*
* To work around it, we extend the tracked request for this
* zero write until INT64_MAX (effectively infinity), and mark
* it as serializing.
*
* We have to enable this workaround for all filesystems and
* AIO modes (not just XFS with aio=native), because for
* remote filesystems we do not know the host configuration.
*/
req = bdrv_co_get_self_request(bs);
assert(req);
assert(req->type == BDRV_TRACKED_WRITE);
assert(req->offset <= offset);
assert(req->offset + req->bytes >= offset + bytes);
end = INT64_MAX & -(uint64_t)bs->bl.request_alignment;
req->bytes = end - req->offset;
req->overlap_bytes = req->bytes;
bdrv_mark_request_serialising(req, bs->bl.request_alignment);
bdrv_wait_serialising_requests(req);
}
#endif
acb = (RawPosixAIOData) { acb = (RawPosixAIOData) {
.bs = bs, .bs = bs,
.aio_fildes = s->fd, .aio_fildes = s->fd,
@@ -2735,9 +2612,6 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
if (blkdev) { if (blkdev) {
acb.aio_type |= QEMU_AIO_BLKDEV; acb.aio_type |= QEMU_AIO_BLKDEV;
} }
if (flags & BDRV_REQ_NO_FALLBACK) {
acb.aio_type |= QEMU_AIO_NO_FALLBACK;
}
if (flags & BDRV_REQ_MAY_UNMAP) { if (flags & BDRV_REQ_MAY_UNMAP) {
acb.aio_type |= QEMU_AIO_DISCARD; acb.aio_type |= QEMU_AIO_DISCARD;
@@ -2781,11 +2655,7 @@ static QemuOptsList raw_create_opts = {
{ {
.name = BLOCK_OPT_PREALLOC, .name = BLOCK_OPT_PREALLOC,
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "Preallocation mode (allowed values: off" .help = "Preallocation mode (allowed values: off, falloc, full)"
#ifdef CONFIG_POSIX_FALLOCATE
", falloc"
#endif
", full)"
}, },
{ /* end of list */ } { /* end of list */ }
} }
@@ -2794,81 +2664,12 @@ static QemuOptsList raw_create_opts = {
static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared, static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
Error **errp) Error **errp)
{ {
BDRVRawState *s = bs->opaque; return raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
BDRVRawReopenState *rs = NULL;
int open_flags;
int ret;
if (s->perm_change_fd) {
/*
* In the context of reopen, this function may be called several times
* (directly and recursively while change permissions of the parent).
* This is even true for children that don't inherit from the original
* reopen node, so s->reopen_state is not set.
*
* Ignore all but the first call.
*/
return 0;
}
if (s->reopen_state) {
/* We already have a new file descriptor to set permissions for */
assert(s->reopen_state->perm == perm);
assert(s->reopen_state->shared_perm == shared);
rs = s->reopen_state->opaque;
s->perm_change_fd = rs->fd;
s->perm_change_flags = rs->open_flags;
} else {
/* We may need a new fd if auto-read-only switches the mode */
ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, perm,
false, errp);
if (ret < 0) {
return ret;
} else if (ret != s->fd) {
s->perm_change_fd = ret;
s->perm_change_flags = open_flags;
}
}
/* Prepare permissions on old fd to avoid conflicts between old and new,
* but keep everything locked that new will need. */
ret = raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
if (ret < 0) {
goto fail;
}
/* Copy locks to the new fd */
if (s->perm_change_fd) {
ret = raw_apply_lock_bytes(NULL, s->perm_change_fd, perm, ~shared,
false, errp);
if (ret < 0) {
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
goto fail;
}
}
return 0;
fail:
if (s->perm_change_fd && !s->reopen_state) {
qemu_close(s->perm_change_fd);
}
s->perm_change_fd = 0;
return ret;
} }
static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared) static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
/* For reopen, we have already switched to the new fd (.bdrv_set_perm is
* called after .bdrv_reopen_commit) */
if (s->perm_change_fd && s->fd != s->perm_change_fd) {
qemu_close(s->fd);
s->fd = s->perm_change_fd;
s->open_flags = s->perm_change_flags;
}
s->perm_change_fd = 0;
raw_handle_perm_lock(bs, RAW_PL_COMMIT, perm, shared, NULL); raw_handle_perm_lock(bs, RAW_PL_COMMIT, perm, shared, NULL);
s->perm = perm; s->perm = perm;
s->shared_perm = shared; s->shared_perm = shared;
@@ -2876,15 +2677,6 @@ static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
static void raw_abort_perm_update(BlockDriverState *bs) static void raw_abort_perm_update(BlockDriverState *bs)
{ {
BDRVRawState *s = bs->opaque;
/* For reopen, .bdrv_reopen_abort is called afterwards and will close
* the file descriptor. */
if (s->perm_change_fd && !s->reopen_state) {
qemu_close(s->perm_change_fd);
}
s->perm_change_fd = 0;
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL); raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
} }
@@ -2974,7 +2766,6 @@ BlockDriver bdrv_file = {
.bdrv_set_perm = raw_set_perm, .bdrv_set_perm = raw_set_perm,
.bdrv_abort_perm_update = raw_abort_perm_update, .bdrv_abort_perm_update = raw_abort_perm_update,
.create_opts = &raw_create_opts, .create_opts = &raw_create_opts,
.mutable_opts = mutable_opts,
}; };
/***********************************************/ /***********************************************/
@@ -3426,7 +3217,6 @@ static BlockDriver bdrv_host_device = {
.bdrv_reopen_abort = raw_reopen_abort, .bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts, .bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts, .create_opts = &raw_create_opts,
.mutable_opts = mutable_opts,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache, .bdrv_co_invalidate_cache = raw_co_invalidate_cache,
.bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes, .bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,
@@ -3553,7 +3343,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_abort = raw_reopen_abort, .bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts, .bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts, .create_opts = &raw_create_opts,
.mutable_opts = mutable_opts,
.bdrv_co_invalidate_cache = raw_co_invalidate_cache, .bdrv_co_invalidate_cache = raw_co_invalidate_cache,
@@ -3687,7 +3476,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_reopen_abort = raw_reopen_abort, .bdrv_reopen_abort = raw_reopen_abort,
.bdrv_co_create_opts = hdev_co_create_opts, .bdrv_co_create_opts = hdev_co_create_opts,
.create_opts = &raw_create_opts, .create_opts = &raw_create_opts,
.mutable_opts = mutable_opts,
.bdrv_co_preadv = raw_co_preadv, .bdrv_co_preadv = raw_co_preadv,
.bdrv_co_pwritev = raw_co_pwritev, .bdrv_co_pwritev = raw_co_pwritev,

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