Compare commits
5 Commits
qemu-openb
...
singlestep
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34370ee6ff | ||
|
|
9953b32e77 | ||
|
|
0da2fd84e1 | ||
|
|
b82417e8bf | ||
|
|
0b72719af8 |
17
.cirrus.yml
17
.cirrus.yml
@@ -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)
|
|
||||||
|
|||||||
@@ -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
4
.gitignore
vendored
@@ -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*
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
12
.gitmodules
vendored
12
.gitmodules
vendored
@@ -39,19 +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
|
|
||||||
|
|||||||
302
.patchew.yml
302
.patchew.yml
@@ -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
|
|
||||||
87
.travis.yml
87
.travis.yml
@@ -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,7 +42,6 @@ addons:
|
|||||||
packages:
|
packages:
|
||||||
- glib
|
- glib
|
||||||
- pixman
|
- pixman
|
||||||
- gnu-sed
|
|
||||||
|
|
||||||
|
|
||||||
# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
|
# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
|
||||||
@@ -62,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
|
||||||
@@ -83,21 +81,10 @@ matrix:
|
|||||||
- CONFIG="--disable-system"
|
- CONFIG="--disable-system"
|
||||||
|
|
||||||
|
|
||||||
# we split the system builds as it takes a while to build them all
|
|
||||||
- env:
|
- env:
|
||||||
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
|
- CONFIG="--disable-user"
|
||||||
|
|
||||||
|
|
||||||
- env:
|
|
||||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
|
||||||
|
|
||||||
|
|
||||||
# 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"
|
||||||
|
|
||||||
@@ -108,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
|
||||||
@@ -128,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:
|
||||||
@@ -140,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:
|
||||||
@@ -148,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"
|
||||||
@@ -201,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"
|
||||||
@@ -231,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:
|
||||||
@@ -249,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
|
||||||
@@ -270,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
|
||||||
@@ -279,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"
|
|
||||||
|
|||||||
47
CODING_STYLE
47
CODING_STYLE
@@ -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 '=',
|
||||||
|
|||||||
36
Kconfig.host
36
Kconfig.host
@@ -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
|
|
||||||
303
MAINTAINERS
303
MAINTAINERS
@@ -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>
|
||||||
@@ -391,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
|
||||||
@@ -399,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
|
||||||
@@ -421,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*
|
||||||
@@ -459,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
|
||||||
------------
|
------------
|
||||||
@@ -559,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
|
||||||
@@ -635,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>
|
||||||
@@ -657,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>
|
||||||
@@ -673,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>
|
||||||
@@ -713,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>
|
||||||
@@ -740,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>
|
||||||
@@ -862,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
|
||||||
@@ -928,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>
|
||||||
@@ -989,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
|
||||||
@@ -1038,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
|
||||||
@@ -1063,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*
|
||||||
@@ -1070,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
|
||||||
@@ -1122,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>
|
||||||
@@ -1153,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
|
||||||
-------------
|
-------------
|
||||||
@@ -1184,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
|
||||||
|
|
||||||
@@ -1195,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
|
||||||
@@ -1223,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>
|
||||||
@@ -1387,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>
|
||||||
@@ -1456,7 +1403,6 @@ 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
|
||||||
|
|
||||||
@@ -1478,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>
|
||||||
@@ -1498,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
|
||||||
@@ -1525,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>
|
||||||
@@ -1669,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
|
||||||
@@ -1700,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
|
||||||
@@ -1714,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
|
||||||
----------
|
----------
|
||||||
@@ -1834,13 +1764,13 @@ S: Supported
|
|||||||
F: scripts/coverity-model.c
|
F: scripts/coverity-model.c
|
||||||
|
|
||||||
CPU
|
CPU
|
||||||
|
L: qemu-devel@nongnu.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: qom/cpu.c
|
F: qom/cpu.c
|
||||||
F: include/qom/cpu.h
|
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
|
||||||
@@ -1865,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/
|
||||||
|
|
||||||
@@ -1918,16 +1847,11 @@ 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>
|
||||||
@@ -2008,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
|
||||||
@@ -2042,10 +1962,8 @@ F: tests/check-qom-proplist.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/
|
||||||
@@ -2059,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
|
||||||
@@ -2140,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
|
||||||
@@ -2215,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
|
||||||
@@ -2246,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
|
||||||
@@ -2293,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
|
||||||
@@ -2307,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
|
||||||
@@ -2340,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/
|
||||||
@@ -2427,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
|
||||||
@@ -2572,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/
|
||||||
@@ -2598,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
|
||||||
@@ -2610,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
|
||||||
-------------
|
-------------
|
||||||
@@ -2637,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
|
|
||||||
|
|||||||
270
Makefile
270
Makefile
@@ -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)
|
||||||
|
|
||||||
@@ -91,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
|
||||||
@@ -129,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)
|
||||||
@@ -153,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')
|
||||||
|
|
||||||
@@ -287,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,\
|
||||||
@@ -302,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: ;
|
||||||
@@ -318,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
|
||||||
@@ -349,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 > $@, \
|
||||||
@@ -365,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 $@; \
|
||||||
@@ -424,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 \
|
||||||
@@ -439,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 $@; \
|
||||||
@@ -466,11 +426,9 @@ SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
|
|||||||
|
|
||||||
$(SOFTMMU_SUBDIR_RULES): $(authz-obj-y)
|
$(SOFTMMU_SUBDIR_RULES): $(authz-obj-y)
|
||||||
$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
|
$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
|
||||||
$(SOFTMMU_SUBDIR_RULES): $(chardev-obj-y)
|
|
||||||
$(SOFTMMU_SUBDIR_RULES): $(crypto-obj-y)
|
$(SOFTMMU_SUBDIR_RULES): $(crypto-obj-y)
|
||||||
$(SOFTMMU_SUBDIR_RULES): $(io-obj-y)
|
$(SOFTMMU_SUBDIR_RULES): $(io-obj-y)
|
||||||
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
|
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
|
||||||
$(SOFTMMU_SUBDIR_RULES): $(edk2-decompressed)
|
|
||||||
|
|
||||||
subdir-%:
|
subdir-%:
|
||||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
|
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
|
||||||
@@ -500,11 +458,8 @@ CAP_CFLAGS += -DCAPSTONE_HAS_X86
|
|||||||
subdir-capstone: .git-submodule-status
|
subdir-capstone: .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))
|
||||||
|
|
||||||
subdir-slirp: .git-submodule-status
|
$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) $(slirp-obj-y) \
|
||||||
$(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)")
|
$(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
|
||||||
|
|
||||||
$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) \
|
|
||||||
$(qom-obj-y) $(crypto-user-obj-$(CONFIG_USER_ONLY))
|
|
||||||
|
|
||||||
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
|
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
|
||||||
# Only keep -O and -g cflags
|
# Only keep -O and -g cflags
|
||||||
@@ -524,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)
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
@@ -636,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))), \
|
||||||
@@ -667,20 +609,15 @@ clean:
|
|||||||
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 \
|
for d in $(ALL_SUBDIRS); do \
|
||||||
@@ -696,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
|
||||||
@@ -732,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
|
||||||
@@ -764,31 +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
|
||||||
|
|
||||||
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)"
|
||||||
@@ -833,8 +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))
|
|
||||||
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
|
||||||
@@ -849,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
|
||||||
@@ -862,21 +753,6 @@ 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@,$(DESTDIR)$(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"; \
|
||||||
@@ -941,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 \
|
||||||
@@ -964,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","$@")
|
||||||
|
|
||||||
@@ -1012,7 +865,7 @@ 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
|
||||||
@@ -1021,7 +874,7 @@ qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \
|
|||||||
qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
|
qemu-img.texi qemu-nbd.texi qemu-options.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 \
|
||||||
@@ -1040,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
|
||||||
@@ -1109,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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -46,7 +47,6 @@ 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 += 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
|
||||||
@@ -84,8 +84,8 @@ common-obj-$(CONFIG_FDT) += device_tree.o
|
|||||||
######################################################################
|
######################################################################
|
||||||
# qapi
|
# qapi
|
||||||
|
|
||||||
|
common-obj-y += qmp.o hmp.o
|
||||||
common-obj-y += qapi/
|
common-obj-y += qapi/
|
||||||
common-obj-y += monitor/
|
|
||||||
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)
|
||||||
|
|||||||
@@ -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,7 +37,9 @@ 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
|
||||||
@@ -103,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
|
||||||
@@ -148,10 +145,9 @@ 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 numa.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 += 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
|
||||||
@@ -167,36 +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
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -221,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
|
||||||
@@ -237,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
|
|
||||||
|
|||||||
@@ -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/
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,7 +88,6 @@ 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;
|
||||||
@@ -292,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;
|
||||||
@@ -869,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -887,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -905,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -924,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1602,7 +1593,7 @@ static int kvm_init(MachineState *ms)
|
|||||||
|
|
||||||
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);
|
||||||
@@ -1682,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
|
||||||
@@ -1809,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2100,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2251,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()) {
|
||||||
@@ -2283,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)
|
||||||
@@ -2332,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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
454
accel/tcg/softmmu_template.h
Normal file
454
accel/tcg/softmmu_template.h
Normal 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
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ 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;
|
|
||||||
|
|
||||||
/* We must handle PC addresses from two different sources:
|
/* We must handle PC addresses from two different sources:
|
||||||
* a call return address and a signal frame address.
|
* a call return address and a signal frame address.
|
||||||
@@ -147,17 +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);
|
||||||
|
|
||||||
/*
|
cc = CPU_GET_CLASS(cpu);
|
||||||
* There is no way the target can handle this other than raising
|
/* see if it is an MMU fault */
|
||||||
* an exception. Undo signal and retaddr state prior to longjmp.
|
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.
|
||||||
*/
|
*/
|
||||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
|
||||||
helper_retaddr = 0;
|
helper_retaddr = 0;
|
||||||
|
|
||||||
cc = CPU_GET_CLASS(cpu);
|
if (ret < 0) {
|
||||||
access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
return 0; /* not an MMU fault */
|
||||||
cc->tlb_fill(cpu, address, 0, access_type, MMU_USER_IDX, false, pc);
|
}
|
||||||
g_assert_not_reached();
|
|
||||||
|
/* 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__)
|
||||||
@@ -680,7 +698,7 @@ 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);
|
||||||
}
|
}
|
||||||
helper_retaddr = retaddr;
|
helper_retaddr = retaddr;
|
||||||
return g2h(addr);
|
return g2h(addr);
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
924
audio/audio.c
924
audio/audio.c
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
196
audio/ossaudio.c
196
audio/ossaudio.c
@@ -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,
|
||||||
|
|||||||
152
audio/paaudio.c
152
audio/paaudio.c
@@ -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 = -1;
|
|
||||||
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,
|
||||||
|
|||||||
239
audio/sdlaudio.c
239
audio/sdlaudio.c
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
266
block/backup.c
266
block/backup.c
@@ -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, end - 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,7 +204,7 @@ 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) {
|
||||||
if (!hbitmap_get(job->copy_bitmap, start)) {
|
if (!hbitmap_get(job->copy_bitmap, start / job->cluster_size)) {
|
||||||
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 */
|
||||||
@@ -298,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);
|
||||||
|
|
||||||
@@ -317,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)
|
||||||
@@ -368,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)
|
||||||
@@ -421,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);
|
||||||
|
|
||||||
@@ -469,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);
|
||||||
@@ -478,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;
|
||||||
}
|
}
|
||||||
@@ -494,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,
|
||||||
@@ -544,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);
|
||||||
@@ -609,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,
|
||||||
@@ -627,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);
|
||||||
@@ -645,9 +667,33 @@ 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->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));
|
||||||
@@ -663,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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -126,11 +124,6 @@ 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)
|
||||||
{
|
{
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
@@ -299,15 +294,25 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||||||
commit_top_bs->implicit = true;
|
commit_top_bs->implicit = 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. */
|
||||||
@@ -325,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
|
||||||
@@ -349,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;
|
||||||
@@ -363,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. */
|
||||||
@@ -393,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;
|
||||||
@@ -421,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) {
|
||||||
@@ -440,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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -134,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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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__ */
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
@@ -380,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;
|
||||||
@@ -437,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,
|
||||||
@@ -453,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)
|
||||||
@@ -535,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) {
|
||||||
@@ -654,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)) {
|
||||||
@@ -817,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);
|
||||||
@@ -867,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);
|
||||||
@@ -947,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);
|
||||||
@@ -957,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);
|
||||||
|
|
||||||
@@ -966,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
|
||||||
@@ -979,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;
|
||||||
@@ -1001,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) {
|
||||||
@@ -1033,9 +979,6 @@ 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 hdev_get_max_transfer_length(BlockDriverState *bs, int fd)
|
static int hdev_get_max_transfer_length(BlockDriverState *bs, int fd)
|
||||||
@@ -1446,22 +1389,9 @@ out:
|
|||||||
#ifdef CONFIG_XFS
|
#ifdef CONFIG_XFS
|
||||||
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
|
||||||
{
|
{
|
||||||
int64_t len;
|
|
||||||
struct xfs_flock64 fl;
|
struct xfs_flock64 fl;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
len = lseek(s->fd, 0, SEEK_END);
|
|
||||||
if (len < 0) {
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset + bytes > len) {
|
|
||||||
/* XFS_IOC_ZERO_RANGE does not increase the file length */
|
|
||||||
if (ftruncate(s->fd, offset + bytes) < 0) {
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&fl, 0, sizeof(fl));
|
memset(&fl, 0, sizeof(fl));
|
||||||
fl.l_whence = SEEK_SET;
|
fl.l_whence = SEEK_SET;
|
||||||
fl.l_start = offset;
|
fl.l_start = offset;
|
||||||
@@ -1527,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) {
|
||||||
@@ -2490,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;
|
||||||
@@ -2517,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. */
|
||||||
@@ -2622,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 */
|
||||||
}
|
}
|
||||||
@@ -2707,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;
|
||||||
@@ -2753,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 */ }
|
||||||
}
|
}
|
||||||
@@ -2766,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;
|
||||||
@@ -2848,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2946,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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/***********************************************/
|
/***********************************************/
|
||||||
@@ -3398,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,
|
||||||
|
|
||||||
@@ -3525,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,
|
||||||
|
|
||||||
|
|
||||||
@@ -3659,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,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/units.h"
|
|
||||||
#include <glusterfs/api/glfs.h>
|
#include <glusterfs/api/glfs.h>
|
||||||
#include "block/block_int.h"
|
#include "block/block_int.h"
|
||||||
#include "block/qdict.h"
|
#include "block/qdict.h"
|
||||||
@@ -18,14 +17,9 @@
|
|||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qemu/uri.h"
|
#include "qemu/uri.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/module.h"
|
|
||||||
#include "qemu/option.h"
|
#include "qemu/option.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
|
|
||||||
#ifdef CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT
|
|
||||||
# define glfs_ftruncate(fd, offset) glfs_ftruncate(fd, offset, NULL, NULL)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GLUSTER_OPT_FILENAME "filename"
|
#define GLUSTER_OPT_FILENAME "filename"
|
||||||
#define GLUSTER_OPT_VOLUME "volume"
|
#define GLUSTER_OPT_VOLUME "volume"
|
||||||
#define GLUSTER_OPT_PATH "path"
|
#define GLUSTER_OPT_PATH "path"
|
||||||
@@ -43,12 +37,6 @@
|
|||||||
#define GLUSTER_DEBUG_MAX 9
|
#define GLUSTER_DEBUG_MAX 9
|
||||||
#define GLUSTER_OPT_LOGFILE "logfile"
|
#define GLUSTER_OPT_LOGFILE "logfile"
|
||||||
#define GLUSTER_LOGFILE_DEFAULT "-" /* handled in libgfapi as /dev/stderr */
|
#define GLUSTER_LOGFILE_DEFAULT "-" /* handled in libgfapi as /dev/stderr */
|
||||||
/*
|
|
||||||
* Several versions of GlusterFS (3.12? -> 6.0.1) fail when the transfer size
|
|
||||||
* is greater or equal to 1024 MiB, so we are limiting the transfer size to 512
|
|
||||||
* MiB to avoid this rare issue.
|
|
||||||
*/
|
|
||||||
#define GLUSTER_MAX_TRANSFER (512 * MiB)
|
|
||||||
|
|
||||||
#define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n"
|
#define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n"
|
||||||
|
|
||||||
@@ -98,14 +86,7 @@ static QemuOptsList qemu_gluster_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, full)"
|
||||||
#ifdef CONFIG_GLUSTERFS_FALLOCATE
|
|
||||||
", falloc"
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_GLUSTERFS_ZEROFILL
|
|
||||||
", full"
|
|
||||||
#endif
|
|
||||||
")"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = GLUSTER_OPT_DEBUG,
|
.name = GLUSTER_OPT_DEBUG,
|
||||||
@@ -744,11 +725,7 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
|
|||||||
/*
|
/*
|
||||||
* AIO callback routine called from GlusterFS thread.
|
* AIO callback routine called from GlusterFS thread.
|
||||||
*/
|
*/
|
||||||
static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
|
static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
||||||
#ifdef CONFIG_GLUSTERFS_IOCB_HAS_STAT
|
|
||||||
struct glfs_stat *pre, struct glfs_stat *post,
|
|
||||||
#endif
|
|
||||||
void *arg)
|
|
||||||
{
|
{
|
||||||
GlusterAIOCB *acb = (GlusterAIOCB *)arg;
|
GlusterAIOCB *acb = (GlusterAIOCB *)arg;
|
||||||
|
|
||||||
@@ -902,11 +879,6 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp)
|
|
||||||
{
|
|
||||||
bs->bl.max_transfer = GLUSTER_MAX_TRANSFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
|
||||||
BlockReopenQueue *queue, Error **errp)
|
BlockReopenQueue *queue, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -1564,7 +1536,6 @@ static BlockDriver bdrv_gluster = {
|
|||||||
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
||||||
#endif
|
#endif
|
||||||
.bdrv_co_block_status = qemu_gluster_co_block_status,
|
.bdrv_co_block_status = qemu_gluster_co_block_status,
|
||||||
.bdrv_refresh_limits = qemu_gluster_refresh_limits,
|
|
||||||
.create_opts = &qemu_gluster_create_opts,
|
.create_opts = &qemu_gluster_create_opts,
|
||||||
.strong_runtime_opts = gluster_strong_open_opts,
|
.strong_runtime_opts = gluster_strong_open_opts,
|
||||||
};
|
};
|
||||||
@@ -1595,7 +1566,6 @@ static BlockDriver bdrv_gluster_tcp = {
|
|||||||
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
||||||
#endif
|
#endif
|
||||||
.bdrv_co_block_status = qemu_gluster_co_block_status,
|
.bdrv_co_block_status = qemu_gluster_co_block_status,
|
||||||
.bdrv_refresh_limits = qemu_gluster_refresh_limits,
|
|
||||||
.create_opts = &qemu_gluster_create_opts,
|
.create_opts = &qemu_gluster_create_opts,
|
||||||
.strong_runtime_opts = gluster_strong_open_opts,
|
.strong_runtime_opts = gluster_strong_open_opts,
|
||||||
};
|
};
|
||||||
@@ -1626,7 +1596,6 @@ static BlockDriver bdrv_gluster_unix = {
|
|||||||
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
||||||
#endif
|
#endif
|
||||||
.bdrv_co_block_status = qemu_gluster_co_block_status,
|
.bdrv_co_block_status = qemu_gluster_co_block_status,
|
||||||
.bdrv_refresh_limits = qemu_gluster_refresh_limits,
|
|
||||||
.create_opts = &qemu_gluster_create_opts,
|
.create_opts = &qemu_gluster_create_opts,
|
||||||
.strong_runtime_opts = gluster_strong_open_opts,
|
.strong_runtime_opts = gluster_strong_open_opts,
|
||||||
};
|
};
|
||||||
@@ -1663,7 +1632,6 @@ static BlockDriver bdrv_gluster_rdma = {
|
|||||||
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
.bdrv_co_pwrite_zeroes = qemu_gluster_co_pwrite_zeroes,
|
||||||
#endif
|
#endif
|
||||||
.bdrv_co_block_status = qemu_gluster_co_block_status,
|
.bdrv_co_block_status = qemu_gluster_co_block_status,
|
||||||
.bdrv_refresh_limits = qemu_gluster_refresh_limits,
|
|
||||||
.create_opts = &qemu_gluster_create_opts,
|
.create_opts = &qemu_gluster_create_opts,
|
||||||
.strong_runtime_opts = gluster_strong_open_opts,
|
.strong_runtime_opts = gluster_strong_open_opts,
|
||||||
};
|
};
|
||||||
|
|||||||
93
block/io.c
93
block/io.c
@@ -422,12 +422,11 @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(bs->quiesce_counter > 0);
|
assert(bs->quiesce_counter > 0);
|
||||||
|
old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
|
||||||
|
|
||||||
/* Re-enable things in child-to-parent order */
|
/* Re-enable things in child-to-parent order */
|
||||||
bdrv_drain_invoke(bs, false);
|
bdrv_drain_invoke(bs, false);
|
||||||
bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
|
bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
|
||||||
|
|
||||||
old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter);
|
|
||||||
if (old_quiesce_counter == 1) {
|
if (old_quiesce_counter == 1) {
|
||||||
aio_enable_external(bdrv_get_aio_context(bs));
|
aio_enable_external(bdrv_get_aio_context(bs));
|
||||||
}
|
}
|
||||||
@@ -770,7 +769,7 @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
|
|||||||
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
||||||
size_t size)
|
size_t size)
|
||||||
{
|
{
|
||||||
if (size > BDRV_REQUEST_MAX_BYTES) {
|
if (size > BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,6 +837,42 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset,
|
|||||||
return rwco.ret;
|
return rwco.ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a synchronous request using coroutines
|
||||||
|
*/
|
||||||
|
static int bdrv_rw_co(BdrvChild *child, int64_t sector_num, uint8_t *buf,
|
||||||
|
int nb_sectors, bool is_write, BdrvRequestFlags flags)
|
||||||
|
{
|
||||||
|
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf,
|
||||||
|
nb_sectors * BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
|
if (nb_sectors < 0 || nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bdrv_prwv_co(child, sector_num << BDRV_SECTOR_BITS,
|
||||||
|
&qiov, is_write, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return < 0 if error. See bdrv_write() for the return codes */
|
||||||
|
int bdrv_read(BdrvChild *child, int64_t sector_num,
|
||||||
|
uint8_t *buf, int nb_sectors)
|
||||||
|
{
|
||||||
|
return bdrv_rw_co(child, sector_num, buf, nb_sectors, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return < 0 if error. Important errors are:
|
||||||
|
-EIO generic I/O error (may happen for all errors)
|
||||||
|
-ENOMEDIUM No media inserted.
|
||||||
|
-EINVAL Invalid sector number or nb_sectors
|
||||||
|
-EACCES Trying to write a read-only device
|
||||||
|
*/
|
||||||
|
int bdrv_write(BdrvChild *child, int64_t sector_num,
|
||||||
|
const uint8_t *buf, int nb_sectors)
|
||||||
|
{
|
||||||
|
return bdrv_rw_co(child, sector_num, (uint8_t *)buf, nb_sectors, true, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset,
|
||||||
int bytes, BdrvRequestFlags flags)
|
int bytes, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
@@ -874,6 +909,8 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
|
|||||||
}
|
}
|
||||||
ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL);
|
ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
error_report("error getting block status at offset %" PRId64 ": %s",
|
||||||
|
offset, strerror(-ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (ret & BDRV_BLOCK_ZERO) {
|
if (ret & BDRV_BLOCK_ZERO) {
|
||||||
@@ -882,6 +919,8 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags)
|
|||||||
}
|
}
|
||||||
ret = bdrv_pwrite_zeroes(child, offset, bytes, flags);
|
ret = bdrv_pwrite_zeroes(child, offset, bytes, flags);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
error_report("error writing zeroes at offset %" PRId64 ": %s",
|
||||||
|
offset, strerror(-ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
offset += bytes;
|
offset += bytes;
|
||||||
@@ -900,7 +939,6 @@ int bdrv_preadv(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
|
|||||||
return qiov->size;
|
return qiov->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See bdrv_pwrite() for the return codes */
|
|
||||||
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
|
int bdrv_pread(BdrvChild *child, int64_t offset, void *buf, int bytes)
|
||||||
{
|
{
|
||||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
||||||
@@ -924,12 +962,6 @@ int bdrv_pwritev(BdrvChild *child, int64_t offset, QEMUIOVector *qiov)
|
|||||||
return qiov->size;
|
return qiov->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return no. of bytes on success or < 0 on error. Important errors are:
|
|
||||||
-EIO generic I/O error (may happen for all errors)
|
|
||||||
-ENOMEDIUM No media inserted.
|
|
||||||
-EINVAL Invalid offset or number of bytes
|
|
||||||
-EACCES Trying to write a read-only device
|
|
||||||
*/
|
|
||||||
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes)
|
int bdrv_pwrite(BdrvChild *child, int64_t offset, const void *buf, int bytes)
|
||||||
{
|
{
|
||||||
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
|
||||||
@@ -987,7 +1019,6 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
|
|||||||
unsigned int nb_sectors;
|
unsigned int nb_sectors;
|
||||||
|
|
||||||
assert(!(flags & ~BDRV_REQ_MASK));
|
assert(!(flags & ~BDRV_REQ_MASK));
|
||||||
assert(!(flags & BDRV_REQ_NO_FALLBACK));
|
|
||||||
|
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
@@ -1018,7 +1049,7 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
|
|||||||
|
|
||||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||||
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||||
assert(bytes <= BDRV_REQUEST_MAX_BYTES);
|
assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
|
||||||
assert(drv->bdrv_co_readv);
|
assert(drv->bdrv_co_readv);
|
||||||
|
|
||||||
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
|
return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
|
||||||
@@ -1034,7 +1065,6 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
assert(!(flags & ~BDRV_REQ_MASK));
|
assert(!(flags & ~BDRV_REQ_MASK));
|
||||||
assert(!(flags & BDRV_REQ_NO_FALLBACK));
|
|
||||||
|
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
@@ -1071,7 +1101,7 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
|
|||||||
|
|
||||||
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||||
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
|
||||||
assert(bytes <= BDRV_REQUEST_MAX_BYTES);
|
assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
|
||||||
|
|
||||||
assert(drv->bdrv_co_writev);
|
assert(drv->bdrv_co_writev);
|
||||||
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov,
|
ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov,
|
||||||
@@ -1441,10 +1471,6 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & ~bs->supported_zero_flags) & BDRV_REQ_NO_FALLBACK) {
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(alignment % bs->bl.request_alignment == 0);
|
assert(alignment % bs->bl.request_alignment == 0);
|
||||||
head = offset % alignment;
|
head = offset % alignment;
|
||||||
tail = (offset + bytes) % alignment;
|
tail = (offset + bytes) % alignment;
|
||||||
@@ -1488,7 +1514,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
assert(!bs->supported_zero_flags);
|
assert(!bs->supported_zero_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0 && !(flags & BDRV_REQ_NO_FALLBACK)) {
|
if (ret == -ENOTSUP) {
|
||||||
/* Fall back to bounce buffer if write zeroes is unsupported */
|
/* Fall back to bounce buffer if write zeroes is unsupported */
|
||||||
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
|
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;
|
||||||
|
|
||||||
@@ -2093,12 +2119,6 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
|
|||||||
*/
|
*/
|
||||||
assert(*pnum && QEMU_IS_ALIGNED(*pnum, align) &&
|
assert(*pnum && QEMU_IS_ALIGNED(*pnum, align) &&
|
||||||
align > offset - aligned_offset);
|
align > offset - aligned_offset);
|
||||||
if (ret & BDRV_BLOCK_RECURSE) {
|
|
||||||
assert(ret & BDRV_BLOCK_DATA);
|
|
||||||
assert(ret & BDRV_BLOCK_OFFSET_VALID);
|
|
||||||
assert(!(ret & BDRV_BLOCK_ZERO));
|
|
||||||
}
|
|
||||||
|
|
||||||
*pnum -= offset - aligned_offset;
|
*pnum -= offset - aligned_offset;
|
||||||
if (*pnum > bytes) {
|
if (*pnum > bytes) {
|
||||||
*pnum = bytes;
|
*pnum = bytes;
|
||||||
@@ -2129,8 +2149,7 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (want_zero && ret & BDRV_BLOCK_RECURSE &&
|
if (want_zero && local_file && local_file != bs &&
|
||||||
local_file && local_file != bs &&
|
|
||||||
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
|
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
|
||||||
(ret & BDRV_BLOCK_OFFSET_VALID)) {
|
(ret & BDRV_BLOCK_OFFSET_VALID)) {
|
||||||
int64_t file_pnum;
|
int64_t file_pnum;
|
||||||
@@ -2632,7 +2651,7 @@ int bdrv_flush(BlockDriverState *bs)
|
|||||||
typedef struct DiscardCo {
|
typedef struct DiscardCo {
|
||||||
BdrvChild *child;
|
BdrvChild *child;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
int64_t bytes;
|
int bytes;
|
||||||
int ret;
|
int ret;
|
||||||
} DiscardCo;
|
} DiscardCo;
|
||||||
static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
|
static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
|
||||||
@@ -2643,15 +2662,14 @@ static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
|
|||||||
aio_wait_kick();
|
aio_wait_kick();
|
||||||
}
|
}
|
||||||
|
|
||||||
int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
|
int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
|
||||||
int64_t bytes)
|
|
||||||
{
|
{
|
||||||
BdrvTrackedRequest req;
|
BdrvTrackedRequest req;
|
||||||
int max_pdiscard, ret;
|
int max_pdiscard, ret;
|
||||||
int head, tail, align;
|
int head, tail, align;
|
||||||
BlockDriverState *bs = child->bs;
|
BlockDriverState *bs = child->bs;
|
||||||
|
|
||||||
if (!bs || !bs->drv || !bdrv_is_inserted(bs)) {
|
if (!bs || !bs->drv) {
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2659,8 +2677,9 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
|
|||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset < 0 || bytes < 0 || bytes > INT64_MAX - offset) {
|
ret = bdrv_check_byte_request(bs, offset, bytes);
|
||||||
return -EIO;
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do nothing if disabled. */
|
/* Do nothing if disabled. */
|
||||||
@@ -2695,7 +2714,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
|
|||||||
assert(max_pdiscard >= bs->bl.request_alignment);
|
assert(max_pdiscard >= bs->bl.request_alignment);
|
||||||
|
|
||||||
while (bytes > 0) {
|
while (bytes > 0) {
|
||||||
int64_t num = bytes;
|
int num = bytes;
|
||||||
|
|
||||||
if (head) {
|
if (head) {
|
||||||
/* Make small requests to get to alignment boundaries. */
|
/* Make small requests to get to alignment boundaries. */
|
||||||
@@ -2757,7 +2776,7 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes)
|
int bdrv_pdiscard(BdrvChild *child, int64_t offset, int bytes)
|
||||||
{
|
{
|
||||||
Coroutine *co;
|
Coroutine *co;
|
||||||
DiscardCo rwco = {
|
DiscardCo rwco = {
|
||||||
@@ -2934,10 +2953,6 @@ static int coroutine_fn bdrv_co_copy_range_internal(
|
|||||||
BdrvTrackedRequest req;
|
BdrvTrackedRequest req;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* TODO We can support BDRV_REQ_NO_FALLBACK here */
|
|
||||||
assert(!(read_flags & BDRV_REQ_NO_FALLBACK));
|
|
||||||
assert(!(write_flags & BDRV_REQ_NO_FALLBACK));
|
|
||||||
|
|
||||||
if (!dst || !dst->bs) {
|
if (!dst || !dst->bs) {
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/module.h"
|
|
||||||
#include "qemu/option.h"
|
#include "qemu/option.h"
|
||||||
|
|
||||||
static QemuOptsList qemu_iscsi_opts = {
|
static QemuOptsList qemu_iscsi_opts = {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user