Compare commits
16 Commits
v8.0.0
...
fixed-ram-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0efb212fb | ||
|
|
9e086f2e2a | ||
|
|
cc57d6c75f | ||
|
|
c204cfeeb7 | ||
|
|
d5cd94bbaf | ||
|
|
4c2f145632 | ||
|
|
fb56e2387b | ||
|
|
5686566113 | ||
|
|
4c16cca0e1 | ||
|
|
895c40ce0a | ||
|
|
cad3bc2be3 | ||
|
|
ea1efd3d17 | ||
|
|
3ce4e2e8d5 | ||
|
|
c1eef47d79 | ||
|
|
80f68f67a9 | ||
|
|
4ed18df9df |
111
.cirrus.yml
Normal file
111
.cirrus.yml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
env:
|
||||||
|
CIRRUS_CLONE_DEPTH: 1
|
||||||
|
|
||||||
|
windows_msys2_task:
|
||||||
|
timeout_in: 90m
|
||||||
|
windows_container:
|
||||||
|
image: cirrusci/windowsservercore:2019
|
||||||
|
os_version: 2019
|
||||||
|
cpu: 8
|
||||||
|
memory: 8G
|
||||||
|
env:
|
||||||
|
CIRRUS_SHELL: powershell
|
||||||
|
MSYS: winsymlinks:native
|
||||||
|
MSYSTEM: MINGW64
|
||||||
|
MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-base-x86_64-20220603.sfx.exe
|
||||||
|
MSYS2_FINGERPRINT: 0
|
||||||
|
MSYS2_PACKAGES: "
|
||||||
|
diffutils git grep make pkg-config sed
|
||||||
|
mingw-w64-x86_64-python
|
||||||
|
mingw-w64-x86_64-python-sphinx
|
||||||
|
mingw-w64-x86_64-toolchain
|
||||||
|
mingw-w64-x86_64-SDL2
|
||||||
|
mingw-w64-x86_64-SDL2_image
|
||||||
|
mingw-w64-x86_64-gtk3
|
||||||
|
mingw-w64-x86_64-glib2
|
||||||
|
mingw-w64-x86_64-ninja
|
||||||
|
mingw-w64-x86_64-jemalloc
|
||||||
|
mingw-w64-x86_64-lzo2
|
||||||
|
mingw-w64-x86_64-zstd
|
||||||
|
mingw-w64-x86_64-libjpeg-turbo
|
||||||
|
mingw-w64-x86_64-pixman
|
||||||
|
mingw-w64-x86_64-libgcrypt
|
||||||
|
mingw-w64-x86_64-libpng
|
||||||
|
mingw-w64-x86_64-libssh
|
||||||
|
mingw-w64-x86_64-snappy
|
||||||
|
mingw-w64-x86_64-libusb
|
||||||
|
mingw-w64-x86_64-usbredir
|
||||||
|
mingw-w64-x86_64-libtasn1
|
||||||
|
mingw-w64-x86_64-nettle
|
||||||
|
mingw-w64-x86_64-cyrus-sasl
|
||||||
|
mingw-w64-x86_64-curl
|
||||||
|
mingw-w64-x86_64-gnutls
|
||||||
|
mingw-w64-x86_64-libnfs
|
||||||
|
"
|
||||||
|
CHERE_INVOKING: 1
|
||||||
|
msys2_cache:
|
||||||
|
folder: C:\tools\archive
|
||||||
|
reupload_on_changes: false
|
||||||
|
# These env variables are used to generate fingerprint to trigger the cache procedure
|
||||||
|
# If wanna to force re-populate msys2, increase MSYS2_FINGERPRINT
|
||||||
|
fingerprint_script:
|
||||||
|
- |
|
||||||
|
echo $env:CIRRUS_TASK_NAME
|
||||||
|
echo $env:MSYS2_URL
|
||||||
|
echo $env:MSYS2_FINGERPRINT
|
||||||
|
echo $env:MSYS2_PACKAGES
|
||||||
|
populate_script:
|
||||||
|
- |
|
||||||
|
md -Force C:\tools\archive\pkg
|
||||||
|
$start_time = Get-Date
|
||||||
|
bitsadmin /transfer msys_download /dynamic /download /priority FOREGROUND $env:MSYS2_URL C:\tools\archive\base.exe
|
||||||
|
Write-Output "Download time taken: $((Get-Date).Subtract($start_time))"
|
||||||
|
cd C:\tools
|
||||||
|
C:\tools\archive\base.exe -y
|
||||||
|
del -Force C:\tools\archive\base.exe
|
||||||
|
Write-Output "Base install time taken: $((Get-Date).Subtract($start_time))"
|
||||||
|
$start_time = Get-Date
|
||||||
|
|
||||||
|
((Get-Content -path C:\tools\msys64\etc\\post-install\\07-pacman-key.post -Raw) -replace '--refresh-keys', '--version') | Set-Content -Path C:\tools\msys64\etc\\post-install\\07-pacman-key.post
|
||||||
|
C:\tools\msys64\usr\bin\bash.exe -lc "sed -i 's/^CheckSpace/#CheckSpace/g' /etc/pacman.conf"
|
||||||
|
C:\tools\msys64\usr\bin\bash.exe -lc "export"
|
||||||
|
C:\tools\msys64\usr\bin\pacman.exe --noconfirm -Sy
|
||||||
|
echo Y | C:\tools\msys64\usr\bin\pacman.exe --noconfirm -Suu --overwrite=*
|
||||||
|
taskkill /F /FI "MODULES eq msys-2.0.dll"
|
||||||
|
tasklist
|
||||||
|
C:\tools\msys64\usr\bin\bash.exe -lc "mv -f /etc/pacman.conf.pacnew /etc/pacman.conf || true"
|
||||||
|
C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Syuu --overwrite=*"
|
||||||
|
Write-Output "Core install time taken: $((Get-Date).Subtract($start_time))"
|
||||||
|
$start_time = Get-Date
|
||||||
|
|
||||||
|
C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -S --needed $env:MSYS2_PACKAGES"
|
||||||
|
Write-Output "Package install time taken: $((Get-Date).Subtract($start_time))"
|
||||||
|
$start_time = Get-Date
|
||||||
|
|
||||||
|
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\etc\mtab
|
||||||
|
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\dev\fd
|
||||||
|
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\dev\stderr
|
||||||
|
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\dev\stdin
|
||||||
|
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\dev\stdout
|
||||||
|
del -Force -Recurse -ErrorAction SilentlyContinue C:\tools\msys64\var\cache\pacman\pkg
|
||||||
|
tar cf C:\tools\archive\msys64.tar -C C:\tools\ msys64
|
||||||
|
|
||||||
|
Write-Output "Package archive time taken: $((Get-Date).Subtract($start_time))"
|
||||||
|
del -Force -Recurse -ErrorAction SilentlyContinue c:\tools\msys64
|
||||||
|
install_script:
|
||||||
|
- |
|
||||||
|
$start_time = Get-Date
|
||||||
|
cd C:\tools
|
||||||
|
ls C:\tools\archive\msys64.tar
|
||||||
|
tar xf C:\tools\archive\msys64.tar
|
||||||
|
Write-Output "Extract msys2 time taken: $((Get-Date).Subtract($start_time))"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- C:\tools\msys64\usr\bin\bash.exe -lc "../configure --python=python3
|
||||||
|
--target-list-exclude=i386-softmmu,ppc64-softmmu,aarch64-softmmu,mips64-softmmu,mipsel-softmmu,sh4-softmmu"
|
||||||
|
- C:\tools\msys64\usr\bin\bash.exe -lc "make -j8"
|
||||||
|
- exit $LastExitCode
|
||||||
|
test_script:
|
||||||
|
- C:\tools\msys64\usr\bin\bash.exe -lc "cd build && make V=1 check"
|
||||||
|
- exit $LastExitCode
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#
|
|
||||||
# List of code-formatting clean ups the git blame can ignore
|
|
||||||
#
|
|
||||||
# git blame --ignore-revs-file .git-blame-ignore-revs
|
|
||||||
#
|
|
||||||
# or
|
|
||||||
#
|
|
||||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
|
||||||
#
|
|
||||||
|
|
||||||
# gdbstub: clean-up indents
|
|
||||||
ad9e4585b3c7425759d3eea697afbca71d2c2082
|
|
||||||
|
|
||||||
# e1000e: fix code style
|
|
||||||
0eadd56bf53ab196a16d492d7dd31c62e1c24c32
|
|
||||||
|
|
||||||
# target/riscv: coding style fixes
|
|
||||||
8c7feddddd9218b407792120bcfda0347ed16205
|
|
||||||
|
|
||||||
# replace TABs with spaces
|
|
||||||
48805df9c22a0700fba4b3b548fafaa21726ca68
|
|
||||||
@@ -75,5 +75,5 @@
|
|||||||
- if: '$QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
- if: '$QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
||||||
when: manual
|
when: manual
|
||||||
|
|
||||||
# Jobs can run if any jobs they depend on were successful
|
# Jobs can run if any jobs they depend on were successfull
|
||||||
- when: on_success
|
- when: on_success
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ build-system-alpine:
|
|||||||
- job: amd64-alpine-container
|
- job: amd64-alpine-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: alpine
|
IMAGE: alpine
|
||||||
TARGETS: avr-softmmu loongarch64-softmmu mips64-softmmu mipsel-softmmu
|
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||||
|
microblazeel-softmmu mips64el-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
CONFIGURE_ARGS: --enable-docs --enable-trace-backends=log,simple,syslog
|
CONFIGURE_ARGS: --enable-docs --enable-trace-backends=log,simple,syslog
|
||||||
|
|
||||||
@@ -71,8 +72,8 @@ build-system-debian:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE: debian-amd64
|
IMAGE: debian-amd64
|
||||||
CONFIGURE_ARGS: --with-coroutine=sigaltstack
|
CONFIGURE_ARGS: --with-coroutine=sigaltstack
|
||||||
TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu
|
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
|
||||||
sparc-softmmu xtensaeb-softmmu
|
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
|
|
||||||
check-system-debian:
|
check-system-debian:
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
include:
|
include:
|
||||||
- local: '/.gitlab-ci.d/crossbuild-template.yml'
|
- local: '/.gitlab-ci.d/crossbuild-template.yml'
|
||||||
|
|
||||||
|
cross-armel-system:
|
||||||
|
extends: .cross_system_build_job
|
||||||
|
needs:
|
||||||
|
job: armel-debian-cross-container
|
||||||
|
variables:
|
||||||
|
IMAGE: debian-armel-cross
|
||||||
|
|
||||||
cross-armel-user:
|
cross-armel-user:
|
||||||
extends: .cross_user_build_job
|
extends: .cross_user_build_job
|
||||||
needs:
|
needs:
|
||||||
@@ -8,6 +15,13 @@ cross-armel-user:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE: debian-armel-cross
|
IMAGE: debian-armel-cross
|
||||||
|
|
||||||
|
cross-armhf-system:
|
||||||
|
extends: .cross_system_build_job
|
||||||
|
needs:
|
||||||
|
job: armhf-debian-cross-container
|
||||||
|
variables:
|
||||||
|
IMAGE: debian-armhf-cross
|
||||||
|
|
||||||
cross-armhf-user:
|
cross-armhf-user:
|
||||||
extends: .cross_user_build_job
|
extends: .cross_user_build_job
|
||||||
needs:
|
needs:
|
||||||
@@ -29,6 +43,16 @@ cross-arm64-user:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE: debian-arm64-cross
|
IMAGE: debian-arm64-cross
|
||||||
|
|
||||||
|
cross-i386-system:
|
||||||
|
extends:
|
||||||
|
- .cross_system_build_job
|
||||||
|
- .cross_test_artifacts
|
||||||
|
needs:
|
||||||
|
job: i386-fedora-cross-container
|
||||||
|
variables:
|
||||||
|
IMAGE: fedora-i386-cross
|
||||||
|
MAKE_CHECK_ARGS: check-qtest
|
||||||
|
|
||||||
cross-i386-user:
|
cross-i386-user:
|
||||||
extends:
|
extends:
|
||||||
- .cross_user_build_job
|
- .cross_user_build_job
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
# All centos-stream-8 jobs should run successfully in an environment
|
|
||||||
# setup by the scripts/ci/setup/stream/8/build-environment.yml task
|
|
||||||
# "Installation of extra packages to build QEMU"
|
|
||||||
|
|
||||||
centos-stream-8-x86_64:
|
centos-stream-8-x86_64:
|
||||||
extends: .custom_runner_template
|
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
needs: []
|
needs: []
|
||||||
stage: build
|
stage: build
|
||||||
@@ -13,6 +8,15 @@ centos-stream-8-x86_64:
|
|||||||
rules:
|
rules:
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
- if: "$CENTOS_STREAM_8_x86_64_RUNNER_AVAILABLE"
|
- if: "$CENTOS_STREAM_8_x86_64_RUNNER_AVAILABLE"
|
||||||
|
artifacts:
|
||||||
|
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||||
|
when: on_failure
|
||||||
|
expire_in: 7 days
|
||||||
|
paths:
|
||||||
|
- build/tests/results/latest/results.xml
|
||||||
|
- build/tests/results/latest/test-results
|
||||||
|
reports:
|
||||||
|
junit: build/tests/results/latest/results.xml
|
||||||
before_script:
|
before_script:
|
||||||
- JOBS=$(expr $(nproc) + 1)
|
- JOBS=$(expr $(nproc) + 1)
|
||||||
script:
|
script:
|
||||||
@@ -21,4 +25,6 @@ centos-stream-8-x86_64:
|
|||||||
- ../scripts/ci/org.centos/stream/8/x86_64/configure
|
- ../scripts/ci/org.centos/stream/8/x86_64/configure
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
||||||
- make -j"$JOBS"
|
- make -j"$JOBS"
|
||||||
- make NINJA=":" check check-avocado
|
- make NINJA=":" check
|
||||||
|
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
||||||
|
- ../scripts/ci/org.centos/stream/8/x86_64/test-avocado
|
||||||
|
|||||||
85
.gitlab-ci.d/edk2.yml
Normal file
85
.gitlab-ci.d/edk2.yml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# All jobs needing docker-edk2 must use the same rules it uses.
|
||||||
|
.edk2_job_rules:
|
||||||
|
rules:
|
||||||
|
# Forks don't get pipelines unless QEMU_CI=1 or QEMU_CI=2 is set
|
||||||
|
- if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
||||||
|
when: never
|
||||||
|
|
||||||
|
# In forks, if QEMU_CI=1 is set, then create manual job
|
||||||
|
# if any of the files affecting the build are touched
|
||||||
|
- if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
||||||
|
changes:
|
||||||
|
- .gitlab-ci.d/edk2.yml
|
||||||
|
- .gitlab-ci.d/edk2/Dockerfile
|
||||||
|
- roms/edk2/*
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
# In forks, if QEMU_CI=1 is set, then create manual job
|
||||||
|
# if the branch/tag starts with 'edk2'
|
||||||
|
- if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project" && $CI_COMMIT_REF_NAME =~ /^edk2/'
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
# In forks, if QEMU_CI=1 is set, then create manual job
|
||||||
|
# if last commit msg contains 'EDK2' (case insensitive)
|
||||||
|
- if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project" && $CI_COMMIT_MESSAGE =~ /edk2/i'
|
||||||
|
when: manual
|
||||||
|
|
||||||
|
# Run if any files affecting the build output are touched
|
||||||
|
- changes:
|
||||||
|
- .gitlab-ci.d/edk2.yml
|
||||||
|
- .gitlab-ci.d/edk2/Dockerfile
|
||||||
|
- roms/edk2/*
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
# Run if the branch/tag starts with 'edk2'
|
||||||
|
- if: '$CI_COMMIT_REF_NAME =~ /^edk2/'
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
# Run if last commit msg contains 'EDK2' (case insensitive)
|
||||||
|
- if: '$CI_COMMIT_MESSAGE =~ /edk2/i'
|
||||||
|
when: on_success
|
||||||
|
|
||||||
|
docker-edk2:
|
||||||
|
extends: .edk2_job_rules
|
||||||
|
stage: containers
|
||||||
|
image: docker:19.03.1
|
||||||
|
services:
|
||||||
|
- docker:19.03.1-dind
|
||||||
|
variables:
|
||||||
|
GIT_DEPTH: 3
|
||||||
|
IMAGE_TAG: $CI_REGISTRY_IMAGE:edk2-cross-build
|
||||||
|
# We don't use TLS
|
||||||
|
DOCKER_HOST: tcp://docker:2375
|
||||||
|
DOCKER_TLS_CERTDIR: ""
|
||||||
|
before_script:
|
||||||
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
|
script:
|
||||||
|
- docker pull $IMAGE_TAG || true
|
||||||
|
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||||
|
--tag $IMAGE_TAG .gitlab-ci.d/edk2
|
||||||
|
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||||
|
- docker push $IMAGE_TAG
|
||||||
|
|
||||||
|
build-edk2:
|
||||||
|
extends: .edk2_job_rules
|
||||||
|
stage: build
|
||||||
|
needs: ['docker-edk2']
|
||||||
|
artifacts:
|
||||||
|
paths: # 'artifacts.zip' will contains the following files:
|
||||||
|
- pc-bios/edk2*bz2
|
||||||
|
- pc-bios/edk2-licenses.txt
|
||||||
|
- edk2-stdout.log
|
||||||
|
- edk2-stderr.log
|
||||||
|
image: $CI_REGISTRY_IMAGE:edk2-cross-build
|
||||||
|
variables:
|
||||||
|
GIT_DEPTH: 3
|
||||||
|
script: # Clone the required submodules and build EDK2
|
||||||
|
- git submodule update --init roms/edk2
|
||||||
|
- git -C roms/edk2 submodule update --init --
|
||||||
|
ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
|
||||||
|
BaseTools/Source/C/BrotliCompress/brotli
|
||||||
|
CryptoPkg/Library/OpensslLib/openssl
|
||||||
|
MdeModulePkg/Library/BrotliCustomDecompressLib/brotli
|
||||||
|
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||||
|
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||||
|
- make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2
|
||||||
27
.gitlab-ci.d/edk2/Dockerfile
Normal file
27
.gitlab-ci.d/edk2/Dockerfile
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#
|
||||||
|
# Docker image to cross-compile EDK2 firmware binaries
|
||||||
|
#
|
||||||
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
|
MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
|
|
||||||
|
# Install packages required to build EDK2
|
||||||
|
RUN apt update \
|
||||||
|
&& \
|
||||||
|
\
|
||||||
|
DEBIAN_FRONTEND=noninteractive \
|
||||||
|
apt install --assume-yes --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
ca-certificates \
|
||||||
|
dos2unix \
|
||||||
|
gcc-aarch64-linux-gnu \
|
||||||
|
gcc-arm-linux-gnueabi \
|
||||||
|
git \
|
||||||
|
iasl \
|
||||||
|
make \
|
||||||
|
nasm \
|
||||||
|
python3 \
|
||||||
|
uuid-dev \
|
||||||
|
&& \
|
||||||
|
\
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
@@ -42,9 +42,9 @@
|
|||||||
docker-opensbi:
|
docker-opensbi:
|
||||||
extends: .opensbi_job_rules
|
extends: .opensbi_job_rules
|
||||||
stage: containers
|
stage: containers
|
||||||
image: docker:stable
|
image: docker:19.03.1
|
||||||
services:
|
services:
|
||||||
- docker:stable-dind
|
- docker:19.03.1-dind
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: 3
|
GIT_DEPTH: 3
|
||||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
IMAGE_TAG: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ RUN apt update \
|
|||||||
ca-certificates \
|
ca-certificates \
|
||||||
git \
|
git \
|
||||||
make \
|
make \
|
||||||
python3 \
|
|
||||||
wget \
|
wget \
|
||||||
&& \
|
&& \
|
||||||
\
|
\
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
include:
|
include:
|
||||||
- local: '/.gitlab-ci.d/base.yml'
|
- local: '/.gitlab-ci.d/base.yml'
|
||||||
- local: '/.gitlab-ci.d/stages.yml'
|
- local: '/.gitlab-ci.d/stages.yml'
|
||||||
|
- local: '/.gitlab-ci.d/edk2.yml'
|
||||||
- local: '/.gitlab-ci.d/opensbi.yml'
|
- local: '/.gitlab-ci.d/opensbi.yml'
|
||||||
- local: '/.gitlab-ci.d/containers.yml'
|
- local: '/.gitlab-ci.d/containers.yml'
|
||||||
- local: '/.gitlab-ci.d/crossbuilds.yml'
|
- local: '/.gitlab-ci.d/crossbuilds.yml'
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ msys2-64bit:
|
|||||||
mingw-w64-x86_64-SDL2
|
mingw-w64-x86_64-SDL2
|
||||||
mingw-w64-x86_64-SDL2_image
|
mingw-w64-x86_64-SDL2_image
|
||||||
mingw-w64-x86_64-snappy
|
mingw-w64-x86_64-snappy
|
||||||
mingw-w64-x86_64-spice
|
|
||||||
mingw-w64-x86_64-usbredir
|
mingw-w64-x86_64-usbredir
|
||||||
mingw-w64-x86_64-zstd "
|
mingw-w64-x86_64-zstd "
|
||||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||||
@@ -109,7 +108,6 @@ msys2-32bit:
|
|||||||
mingw-w64-i686-SDL2
|
mingw-w64-i686-SDL2
|
||||||
mingw-w64-i686-SDL2_image
|
mingw-w64-i686-SDL2_image
|
||||||
mingw-w64-i686-snappy
|
mingw-w64-i686-snappy
|
||||||
mingw-w64-i686-spice
|
|
||||||
mingw-w64-i686-usbredir
|
mingw-w64-i686-usbredir
|
||||||
mingw-w64-i686-zstd "
|
mingw-w64-i686-zstd "
|
||||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||||
|
|||||||
1
.mailmap
1
.mailmap
@@ -56,7 +56,6 @@ Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <aleksandar.rikalo@rt-rk.com>
|
|||||||
Alexander Graf <agraf@csgraf.de> <agraf@suse.de>
|
Alexander Graf <agraf@csgraf.de> <agraf@suse.de>
|
||||||
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
|
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
|
||||||
Christian Borntraeger <borntraeger@linux.ibm.com> <borntraeger@de.ibm.com>
|
Christian Borntraeger <borntraeger@linux.ibm.com> <borntraeger@de.ibm.com>
|
||||||
Damien Hedde <damien.hedde@dahe.fr> <damien.hedde@greensocs.com>
|
|
||||||
Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
|
Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
|
||||||
Frederic Konrad <konrad.frederic@yahoo.fr> <fred.konrad@greensocs.com>
|
Frederic Konrad <konrad.frederic@yahoo.fr> <fred.konrad@greensocs.com>
|
||||||
Frederic Konrad <konrad.frederic@yahoo.fr> <konrad@adacore.com>
|
Frederic Konrad <konrad.frederic@yahoo.fr> <konrad@adacore.com>
|
||||||
|
|||||||
87
MAINTAINERS
87
MAINTAINERS
@@ -64,20 +64,6 @@ L: qemu-devel@nongnu.org
|
|||||||
F: *
|
F: *
|
||||||
F: */
|
F: */
|
||||||
|
|
||||||
Project policy and developer guides
|
|
||||||
R: Alex Bennée <alex.bennee@linaro.org>
|
|
||||||
R: Daniel P. Berrangé <berrange@redhat.com>
|
|
||||||
R: Thomas Huth <thuth@redhat.com>
|
|
||||||
R: Markus Armbruster <armbru@redhat.com>
|
|
||||||
R: Philippe Mathieu-Daudé <philmd@linaro.org>
|
|
||||||
W: https://www.qemu.org/docs/master/devel/index.html
|
|
||||||
S: Odd Fixes
|
|
||||||
F: docs/devel/style.rst
|
|
||||||
F: docs/devel/code-of-conduct.rst
|
|
||||||
F: docs/devel/conflict-resolution.rst
|
|
||||||
F: docs/devel/submitting-a-patch.rst
|
|
||||||
F: docs/devel/submitting-a-pull-request.rst
|
|
||||||
|
|
||||||
Responsible Disclosure, Reporting Security Issues
|
Responsible Disclosure, Reporting Security Issues
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
W: https://wiki.qemu.org/SecurityProcess
|
W: https://wiki.qemu.org/SecurityProcess
|
||||||
@@ -150,8 +136,6 @@ F: docs/devel/decodetree.rst
|
|||||||
F: docs/devel/tcg*
|
F: docs/devel/tcg*
|
||||||
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/tb-flush.h
|
|
||||||
F: include/exec/target_long.h
|
|
||||||
F: include/exec/helper*.h
|
F: include/exec/helper*.h
|
||||||
F: include/sysemu/cpus.h
|
F: include/sysemu/cpus.h
|
||||||
F: include/sysemu/tcg.h
|
F: include/sysemu/tcg.h
|
||||||
@@ -271,9 +255,9 @@ F: docs/system/cpu-models-mips.rst.inc
|
|||||||
F: tests/tcg/mips/
|
F: tests/tcg/mips/
|
||||||
|
|
||||||
NiosII TCG CPUs
|
NiosII TCG CPUs
|
||||||
R: Chris Wulff <crwulff@gmail.com>
|
M: Chris Wulff <crwulff@gmail.com>
|
||||||
R: Marek Vasut <marex@denx.de>
|
M: Marek Vasut <marex@denx.de>
|
||||||
S: Orphan
|
S: Maintained
|
||||||
F: target/nios2/
|
F: target/nios2/
|
||||||
F: hw/nios2/
|
F: hw/nios2/
|
||||||
F: disas/nios2.c
|
F: disas/nios2.c
|
||||||
@@ -385,7 +369,6 @@ S: Maintained
|
|||||||
F: target/xtensa/
|
F: target/xtensa/
|
||||||
F: hw/xtensa/
|
F: hw/xtensa/
|
||||||
F: tests/tcg/xtensa/
|
F: tests/tcg/xtensa/
|
||||||
F: tests/tcg/xtensaeb/
|
|
||||||
F: disas/xtensa.c
|
F: disas/xtensa.c
|
||||||
F: include/hw/xtensa/xtensa-isa.h
|
F: include/hw/xtensa/xtensa-isa.h
|
||||||
F: configs/devices/xtensa*/default.mak
|
F: configs/devices/xtensa*/default.mak
|
||||||
@@ -460,15 +443,6 @@ F: target/i386/kvm/
|
|||||||
F: target/i386/sev*
|
F: target/i386/sev*
|
||||||
F: scripts/kvm/vmxcap
|
F: scripts/kvm/vmxcap
|
||||||
|
|
||||||
Xen emulation on X86 KVM CPUs
|
|
||||||
M: David Woodhouse <dwmw2@infradead.org>
|
|
||||||
M: Paul Durrant <paul@xen.org>
|
|
||||||
S: Supported
|
|
||||||
F: include/sysemu/kvm_xen.h
|
|
||||||
F: target/i386/kvm/xen*
|
|
||||||
F: hw/i386/kvm/xen*
|
|
||||||
F: tests/avocado/xen_guest.py
|
|
||||||
|
|
||||||
Guest CPU Cores (other accelerators)
|
Guest CPU Cores (other accelerators)
|
||||||
------------------------------------
|
------------------------------------
|
||||||
Overall
|
Overall
|
||||||
@@ -1025,6 +999,12 @@ S: Maintained
|
|||||||
F: hw/ssi/xlnx-versal-ospi.c
|
F: hw/ssi/xlnx-versal-ospi.c
|
||||||
F: include/hw/ssi/xlnx-versal-ospi.h
|
F: include/hw/ssi/xlnx-versal-ospi.h
|
||||||
|
|
||||||
|
ARM ACPI Subsystem
|
||||||
|
M: Shannon Zhao <shannon.zhaosl@gmail.com>
|
||||||
|
L: qemu-arm@nongnu.org
|
||||||
|
S: Maintained
|
||||||
|
F: hw/arm/virt-acpi-build.c
|
||||||
|
|
||||||
STM32F100
|
STM32F100
|
||||||
M: Alexandre Iooss <erdnaxe@crans.org>
|
M: Alexandre Iooss <erdnaxe@crans.org>
|
||||||
L: qemu-arm@nongnu.org
|
L: qemu-arm@nongnu.org
|
||||||
@@ -1912,18 +1892,6 @@ F: docs/specs/acpi_nvdimm.rst
|
|||||||
F: docs/specs/acpi_pci_hotplug.rst
|
F: docs/specs/acpi_pci_hotplug.rst
|
||||||
F: docs/specs/acpi_hw_reduced_hotplug.rst
|
F: docs/specs/acpi_hw_reduced_hotplug.rst
|
||||||
|
|
||||||
ARM ACPI Subsystem
|
|
||||||
M: Shannon Zhao <shannon.zhaosl@gmail.com>
|
|
||||||
L: qemu-arm@nongnu.org
|
|
||||||
S: Maintained
|
|
||||||
F: hw/arm/virt-acpi-build.c
|
|
||||||
|
|
||||||
RISC-V ACPI Subsystem
|
|
||||||
M: Sunil V L <sunilvl@ventanamicro.com>
|
|
||||||
L: qemu-riscv@nongnu.org
|
|
||||||
S: Maintained
|
|
||||||
F: hw/riscv/virt-acpi-build.c
|
|
||||||
|
|
||||||
ACPI/VIOT
|
ACPI/VIOT
|
||||||
M: Jean-Philippe Brucker <jean-philippe@linaro.org>
|
M: Jean-Philippe Brucker <jean-philippe@linaro.org>
|
||||||
S: Supported
|
S: Supported
|
||||||
@@ -2133,6 +2101,7 @@ T: git https://github.com/borntraeger/qemu.git s390-next
|
|||||||
L: qemu-s390x@nongnu.org
|
L: qemu-s390x@nongnu.org
|
||||||
|
|
||||||
virtiofs
|
virtiofs
|
||||||
|
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: hw/virtio/vhost-user-fs*
|
F: hw/virtio/vhost-user-fs*
|
||||||
@@ -2250,28 +2219,14 @@ F: docs/specs/rocker.txt
|
|||||||
|
|
||||||
e1000x
|
e1000x
|
||||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||||
R: Akihiko Odaki <akihiko.odaki@daynix.com>
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/net/e1000x*
|
F: hw/net/e1000x*
|
||||||
|
|
||||||
e1000e
|
e1000e
|
||||||
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
|
||||||
R: Akihiko Odaki <akihiko.odaki@daynix.com>
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/net/e1000e*
|
F: hw/net/e1000e*
|
||||||
F: tests/qtest/fuzz-e1000e-test.c
|
F: tests/qtest/fuzz-e1000e-test.c
|
||||||
F: tests/qtest/e1000e-test.c
|
|
||||||
F: tests/qtest/libqos/e1000e.*
|
|
||||||
|
|
||||||
igb
|
|
||||||
M: Akihiko Odaki <akihiko.odaki@daynix.com>
|
|
||||||
R: Sriram Yagnaraman <sriram.yagnaraman@est.tech>
|
|
||||||
S: Maintained
|
|
||||||
F: docs/system/devices/igb.rst
|
|
||||||
F: hw/net/igb*
|
|
||||||
F: tests/avocado/igb.py
|
|
||||||
F: tests/qtest/igb-test.c
|
|
||||||
F: tests/qtest/libqos/igb.c
|
|
||||||
|
|
||||||
eepro100
|
eepro100
|
||||||
M: Stefan Weil <sw@weilnetz.de>
|
M: Stefan Weil <sw@weilnetz.de>
|
||||||
@@ -2535,7 +2490,6 @@ Subsystems
|
|||||||
----------
|
----------
|
||||||
Overall Audio backends
|
Overall Audio backends
|
||||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
F: audio/
|
F: audio/
|
||||||
X: audio/alsaaudio.c
|
X: audio/alsaaudio.c
|
||||||
@@ -2681,6 +2635,7 @@ T: git https://gitlab.com/jsnow/qemu.git jobs
|
|||||||
T: git https://gitlab.com/vsementsov/qemu.git block
|
T: git https://gitlab.com/vsementsov/qemu.git block
|
||||||
|
|
||||||
Compute Express Link
|
Compute Express Link
|
||||||
|
M: Ben Widawsky <ben.widawsky@intel.com>
|
||||||
M: Jonathan Cameron <jonathan.cameron@huawei.com>
|
M: Jonathan Cameron <jonathan.cameron@huawei.com>
|
||||||
R: Fan Ni <fan.ni@samsung.com>
|
R: Fan Ni <fan.ni@samsung.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
@@ -2780,11 +2735,9 @@ S: Maintained
|
|||||||
F: docs/system/gdb.rst
|
F: docs/system/gdb.rst
|
||||||
F: gdbstub/*
|
F: gdbstub/*
|
||||||
F: include/exec/gdbstub.h
|
F: include/exec/gdbstub.h
|
||||||
F: include/gdbstub/*
|
|
||||||
F: gdb-xml/
|
F: gdb-xml/
|
||||||
F: tests/tcg/multiarch/gdbstub/
|
F: tests/tcg/multiarch/gdbstub/
|
||||||
F: scripts/feature_to_c.sh
|
F: scripts/feature_to_c.sh
|
||||||
F: scripts/probe-gdb-support.py
|
|
||||||
|
|
||||||
Memory API
|
Memory API
|
||||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
@@ -2832,7 +2785,6 @@ F: docs/spice-port-fqdn.txt
|
|||||||
|
|
||||||
Graphics
|
Graphics
|
||||||
M: Gerd Hoffmann <kraxel@redhat.com>
|
M: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
F: ui/
|
F: ui/
|
||||||
F: include/ui/
|
F: include/ui/
|
||||||
@@ -2876,7 +2828,7 @@ F: tests/unit/test-rcu-*.c
|
|||||||
F: util/rcu.c
|
F: util/rcu.c
|
||||||
|
|
||||||
Human Monitor (HMP)
|
Human Monitor (HMP)
|
||||||
M: Dr. David Alan Gilbert <dave@treblig.org>
|
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: monitor/monitor-internal.h
|
F: monitor/monitor-internal.h
|
||||||
F: monitor/misc.c
|
F: monitor/misc.c
|
||||||
@@ -2916,11 +2868,9 @@ T: git https://gitlab.com/ehabkost/qemu.git machine-next
|
|||||||
|
|
||||||
Cryptodev Backends
|
Cryptodev Backends
|
||||||
M: Gonglei <arei.gonglei@huawei.com>
|
M: Gonglei <arei.gonglei@huawei.com>
|
||||||
M: zhenwei pi <pizhenwei@bytedance.com>
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: include/sysemu/cryptodev*.h
|
F: include/sysemu/cryptodev*.h
|
||||||
F: backends/cryptodev*.c
|
F: backends/cryptodev*.c
|
||||||
F: qapi/cryptodev.json
|
|
||||||
|
|
||||||
Python library
|
Python library
|
||||||
M: John Snow <jsnow@redhat.com>
|
M: John Snow <jsnow@redhat.com>
|
||||||
@@ -3149,6 +3099,7 @@ F: scripts/checkpatch.pl
|
|||||||
|
|
||||||
Migration
|
Migration
|
||||||
M: Juan Quintela <quintela@redhat.com>
|
M: Juan Quintela <quintela@redhat.com>
|
||||||
|
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/core/vmstate-if.c
|
F: hw/core/vmstate-if.c
|
||||||
F: include/hw/vmstate-if.h
|
F: include/hw/vmstate-if.h
|
||||||
@@ -3357,6 +3308,8 @@ F: roms/edk2
|
|||||||
F: roms/edk2-*
|
F: roms/edk2-*
|
||||||
F: tests/data/uefi-boot-images/
|
F: tests/data/uefi-boot-images/
|
||||||
F: tests/uefi-test-tools/
|
F: tests/uefi-test-tools/
|
||||||
|
F: .gitlab-ci.d/edk2.yml
|
||||||
|
F: .gitlab-ci.d/edk2/
|
||||||
|
|
||||||
VT-d Emulation
|
VT-d Emulation
|
||||||
M: Michael S. Tsirkin <mst@redhat.com>
|
M: Michael S. Tsirkin <mst@redhat.com>
|
||||||
@@ -3376,7 +3329,7 @@ F: .gitlab-ci.d/opensbi/
|
|||||||
|
|
||||||
Clock framework
|
Clock framework
|
||||||
M: Luc Michel <luc@lmichel.fr>
|
M: Luc Michel <luc@lmichel.fr>
|
||||||
R: Damien Hedde <damien.hedde@dahe.fr>
|
R: Damien Hedde <damien.hedde@greensocs.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: include/hw/clock.h
|
F: include/hw/clock.h
|
||||||
F: include/hw/qdev-clock.h
|
F: include/hw/qdev-clock.h
|
||||||
@@ -3831,7 +3784,8 @@ W: https://cirrus-ci.com/github/qemu/qemu
|
|||||||
Windows Hosted Continuous Integration
|
Windows Hosted Continuous Integration
|
||||||
M: Yonggang Luo <luoyonggang@gmail.com>
|
M: Yonggang Luo <luoyonggang@gmail.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: .gitlab-ci.d/windows.yml
|
F: .cirrus.yml
|
||||||
|
W: https://cirrus-ci.com/github/qemu/qemu
|
||||||
|
|
||||||
Guest Test Compilation Support
|
Guest Test Compilation Support
|
||||||
M: Alex Bennée <alex.bennee@linaro.org>
|
M: Alex Bennée <alex.bennee@linaro.org>
|
||||||
@@ -3920,8 +3874,3 @@ Performance Tools and Tests
|
|||||||
M: Ahmed Karaman <ahmedkhaledkaraman@gmail.com>
|
M: Ahmed Karaman <ahmedkhaledkaraman@gmail.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: scripts/performance/
|
F: scripts/performance/
|
||||||
|
|
||||||
Code Coverage Tools
|
|
||||||
M: Alex Bennée <alex.bennee@linaro.org>
|
|
||||||
S: Odd Fixes
|
|
||||||
F: scripts/coverage/
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "qemu/accel.h"
|
#include "qemu/accel.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "accel-softmmu.h"
|
#include "accel-softmmu.h"
|
||||||
|
|
||||||
int accel_init_machine(AccelState *accel, MachineState *ms)
|
int accel_init_machine(AccelState *accel, MachineState *ms)
|
||||||
|
|||||||
@@ -86,13 +86,6 @@ static bool kvm_cpus_are_resettable(void)
|
|||||||
return !kvm_enabled() || kvm_cpu_check_are_resettable();
|
return !kvm_enabled() || kvm_cpu_check_are_resettable();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
|
||||||
static int kvm_update_guest_debug_ops(CPUState *cpu)
|
|
||||||
{
|
|
||||||
return kvm_update_guest_debug(cpu, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void kvm_accel_ops_class_init(ObjectClass *oc, void *data)
|
static void kvm_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||||
@@ -106,7 +99,6 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, void *data)
|
|||||||
ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
|
ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
|
||||||
|
|
||||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
||||||
ops->update_guest_debug = kvm_update_guest_debug_ops;
|
|
||||||
ops->supports_guest_debug = kvm_supports_guest_debug;
|
ops->supports_guest_debug = kvm_supports_guest_debug;
|
||||||
ops->insert_breakpoint = kvm_insert_breakpoint;
|
ops->insert_breakpoint = kvm_insert_breakpoint;
|
||||||
ops->remove_breakpoint = kvm_remove_breakpoint;
|
ops->remove_breakpoint = kvm_remove_breakpoint;
|
||||||
|
|||||||
@@ -685,15 +685,6 @@ static uint32_t kvm_dirty_ring_reap_one(KVMState *s, CPUState *cpu)
|
|||||||
uint32_t ring_size = s->kvm_dirty_ring_size;
|
uint32_t ring_size = s->kvm_dirty_ring_size;
|
||||||
uint32_t count = 0, fetch = cpu->kvm_fetch_index;
|
uint32_t count = 0, fetch = cpu->kvm_fetch_index;
|
||||||
|
|
||||||
/*
|
|
||||||
* It's possible that we race with vcpu creation code where the vcpu is
|
|
||||||
* put onto the vcpus list but not yet initialized the dirty ring
|
|
||||||
* structures. If so, skip it.
|
|
||||||
*/
|
|
||||||
if (!cpu->created) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(dirty_gfns && ring_size);
|
assert(dirty_gfns && ring_size);
|
||||||
trace_kvm_dirty_ring_reap_vcpu(cpu->cpu_index);
|
trace_kvm_dirty_ring_reap_vcpu(cpu->cpu_index);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "exec/tb-flush.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
|
|
||||||
void tb_flush(CPUState *cpu)
|
void tb_flush(CPUState *cpu)
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "qemu/plugin.h"
|
|
||||||
|
|
||||||
bool tcg_allowed;
|
bool tcg_allowed;
|
||||||
|
|
||||||
@@ -66,8 +65,6 @@ void cpu_loop_exit(CPUState *cpu)
|
|||||||
{
|
{
|
||||||
/* Undo the setting in cpu_tb_exec. */
|
/* Undo the setting in cpu_tb_exec. */
|
||||||
cpu->can_do_io = 1;
|
cpu->can_do_io = 1;
|
||||||
/* Undo any setting in generated code. */
|
|
||||||
qemu_plugin_disable_mem_helpers(cpu);
|
|
||||||
siglongjmp(cpu->jmp_env, 1);
|
siglongjmp(cpu->jmp_env, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
|
|||||||
|
|
||||||
if (cflags & CF_PCREL) {
|
if (cflags & CF_PCREL) {
|
||||||
/* Use acquire to ensure current load of pc from jc. */
|
/* Use acquire to ensure current load of pc from jc. */
|
||||||
tb = qatomic_load_acquire(&jc->array[hash].tb);
|
tb = qatomic_load_acquire(&jc->array[hash].tb);
|
||||||
|
|
||||||
if (likely(tb &&
|
if (likely(tb &&
|
||||||
jc->array[hash].pc == pc &&
|
jc->array[hash].pc == pc &&
|
||||||
@@ -272,7 +272,7 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
jc->array[hash].pc = pc;
|
jc->array[hash].pc = pc;
|
||||||
/* Ensure pc is written first. */
|
/* Use store_release on tb to ensure pc is written first. */
|
||||||
qatomic_store_release(&jc->array[hash].tb, tb);
|
qatomic_store_release(&jc->array[hash].tb, tb);
|
||||||
} else {
|
} else {
|
||||||
/* Use rcu_read to ensure current load of pc from *tb. */
|
/* Use rcu_read to ensure current load of pc from *tb. */
|
||||||
@@ -459,7 +459,6 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
|||||||
qemu_thread_jit_execute();
|
qemu_thread_jit_execute();
|
||||||
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
||||||
cpu->can_do_io = 1;
|
cpu->can_do_io = 1;
|
||||||
qemu_plugin_disable_mem_helpers(cpu);
|
|
||||||
/*
|
/*
|
||||||
* TODO: Delay swapping back to the read-write region of the TB
|
* TODO: Delay swapping back to the read-write region of the TB
|
||||||
* until we actually need to modify the TB. The read-only copy,
|
* until we actually need to modify the TB. The read-only copy,
|
||||||
@@ -527,6 +526,7 @@ static void cpu_exec_exit(CPUState *cpu)
|
|||||||
if (cc->tcg_ops->cpu_exec_exit) {
|
if (cc->tcg_ops->cpu_exec_exit) {
|
||||||
cc->tcg_ops->cpu_exec_exit(cpu);
|
cc->tcg_ops->cpu_exec_exit(cpu);
|
||||||
}
|
}
|
||||||
|
QEMU_PLUGIN_ASSERT(cpu->plugin_mem_cbs == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_exec_step_atomic(CPUState *cpu)
|
void cpu_exec_step_atomic(CPUState *cpu)
|
||||||
@@ -580,6 +580,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
}
|
}
|
||||||
assert_no_pages_locked();
|
assert_no_pages_locked();
|
||||||
|
qemu_plugin_disable_mem_helpers(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -971,27 +972,18 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc)
|
|||||||
|
|
||||||
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
||||||
if (tb == NULL) {
|
if (tb == NULL) {
|
||||||
CPUJumpCache *jc;
|
|
||||||
uint32_t h;
|
uint32_t h;
|
||||||
|
|
||||||
mmap_lock();
|
mmap_lock();
|
||||||
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We add the TB in the virtual pc hash table
|
* We add the TB in the virtual pc hash table
|
||||||
* for the fast lookup
|
* for the fast lookup
|
||||||
*/
|
*/
|
||||||
h = tb_jmp_cache_hash_func(pc);
|
h = tb_jmp_cache_hash_func(pc);
|
||||||
jc = cpu->tb_jmp_cache;
|
/* Use the pc value already stored in tb->pc. */
|
||||||
if (cflags & CF_PCREL) {
|
qatomic_set(&cpu->tb_jmp_cache->array[h].tb, tb);
|
||||||
jc->array[h].pc = pc;
|
|
||||||
/* Ensure pc is written first. */
|
|
||||||
qatomic_store_release(&jc->array[h].tb, tb);
|
|
||||||
} else {
|
|
||||||
/* Use the pc value already stored in tb->pc. */
|
|
||||||
qatomic_set(&jc->array[h].tb, tb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
@@ -1012,6 +1004,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc)
|
|||||||
|
|
||||||
cpu_loop_exec_tb(cpu, tb, pc, &last_tb, &tb_exit);
|
cpu_loop_exec_tb(cpu, tb, pc, &last_tb, &tb_exit);
|
||||||
|
|
||||||
|
QEMU_PLUGIN_ASSERT(cpu->plugin_mem_cbs == NULL);
|
||||||
/* Try to align the host and virtual clocks
|
/* Try to align the host and virtual clocks
|
||||||
if the guest is in advance */
|
if the guest is in advance */
|
||||||
align_clocks(sc, cpu);
|
align_clocks(sc, cpu);
|
||||||
@@ -1036,6 +1029,7 @@ static int cpu_exec_setjmp(CPUState *cpu, SyncClocks *sc)
|
|||||||
if (qemu_mutex_iothread_locked()) {
|
if (qemu_mutex_iothread_locked()) {
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
}
|
}
|
||||||
|
qemu_plugin_disable_mem_helpers(cpu);
|
||||||
|
|
||||||
assert_no_pages_locked();
|
assert_no_pages_locked();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
#include "tcg/tcg-temp-internal.h"
|
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/plugin-gen.h"
|
#include "exec/plugin-gen.h"
|
||||||
|
|||||||
@@ -19,11 +19,9 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/interval-tree.h"
|
#include "qemu/interval-tree.h"
|
||||||
#include "qemu/qtree.h"
|
|
||||||
#include "exec/cputlb.h"
|
#include "exec/cputlb.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/tb-flush.h"
|
|
||||||
#include "exec/translate-all.h"
|
#include "exec/translate-all.h"
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
@@ -127,29 +125,29 @@ static void tb_remove(TranslationBlock *tb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: For now, still shared with translate-all.c for system mode. */
|
/* TODO: For now, still shared with translate-all.c for system mode. */
|
||||||
#define PAGE_FOR_EACH_TB(start, last, pagedesc, T, N) \
|
#define PAGE_FOR_EACH_TB(start, end, pagedesc, T, N) \
|
||||||
for (T = foreach_tb_first(start, last), \
|
for (T = foreach_tb_first(start, end), \
|
||||||
N = foreach_tb_next(T, start, last); \
|
N = foreach_tb_next(T, start, end); \
|
||||||
T != NULL; \
|
T != NULL; \
|
||||||
T = N, N = foreach_tb_next(N, start, last))
|
T = N, N = foreach_tb_next(N, start, end))
|
||||||
|
|
||||||
typedef TranslationBlock *PageForEachNext;
|
typedef TranslationBlock *PageForEachNext;
|
||||||
|
|
||||||
static PageForEachNext foreach_tb_first(tb_page_addr_t start,
|
static PageForEachNext foreach_tb_first(tb_page_addr_t start,
|
||||||
tb_page_addr_t last)
|
tb_page_addr_t end)
|
||||||
{
|
{
|
||||||
IntervalTreeNode *n = interval_tree_iter_first(&tb_root, start, last);
|
IntervalTreeNode *n = interval_tree_iter_first(&tb_root, start, end - 1);
|
||||||
return n ? container_of(n, TranslationBlock, itree) : NULL;
|
return n ? container_of(n, TranslationBlock, itree) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PageForEachNext foreach_tb_next(PageForEachNext tb,
|
static PageForEachNext foreach_tb_next(PageForEachNext tb,
|
||||||
tb_page_addr_t start,
|
tb_page_addr_t start,
|
||||||
tb_page_addr_t last)
|
tb_page_addr_t end)
|
||||||
{
|
{
|
||||||
IntervalTreeNode *n;
|
IntervalTreeNode *n;
|
||||||
|
|
||||||
if (tb) {
|
if (tb) {
|
||||||
n = interval_tree_iter_next(&tb->itree, start, last);
|
n = interval_tree_iter_next(&tb->itree, start, end - 1);
|
||||||
if (n) {
|
if (n) {
|
||||||
return container_of(n, TranslationBlock, itree);
|
return container_of(n, TranslationBlock, itree);
|
||||||
}
|
}
|
||||||
@@ -315,12 +313,12 @@ struct page_entry {
|
|||||||
* See also: page_collection_lock().
|
* See also: page_collection_lock().
|
||||||
*/
|
*/
|
||||||
struct page_collection {
|
struct page_collection {
|
||||||
QTree *tree;
|
GTree *tree;
|
||||||
struct page_entry *max;
|
struct page_entry *max;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int PageForEachNext;
|
typedef int PageForEachNext;
|
||||||
#define PAGE_FOR_EACH_TB(start, last, pagedesc, tb, n) \
|
#define PAGE_FOR_EACH_TB(start, end, pagedesc, tb, n) \
|
||||||
TB_FOR_EACH_TAGGED((pagedesc)->first_tb, tb, n, page_next)
|
TB_FOR_EACH_TAGGED((pagedesc)->first_tb, tb, n, page_next)
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_TCG
|
#ifdef CONFIG_DEBUG_TCG
|
||||||
@@ -468,7 +466,7 @@ static bool page_trylock_add(struct page_collection *set, tb_page_addr_t addr)
|
|||||||
struct page_entry *pe;
|
struct page_entry *pe;
|
||||||
PageDesc *pd;
|
PageDesc *pd;
|
||||||
|
|
||||||
pe = q_tree_lookup(set->tree, &index);
|
pe = g_tree_lookup(set->tree, &index);
|
||||||
if (pe) {
|
if (pe) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -479,7 +477,7 @@ static bool page_trylock_add(struct page_collection *set, tb_page_addr_t addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pe = page_entry_new(pd, index);
|
pe = page_entry_new(pd, index);
|
||||||
q_tree_insert(set->tree, &pe->index, pe);
|
g_tree_insert(set->tree, &pe->index, pe);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is either (1) the first insertion or (2) a page whose index
|
* If this is either (1) the first insertion or (2) a page whose index
|
||||||
@@ -511,30 +509,30 @@ static gint tb_page_addr_cmp(gconstpointer ap, gconstpointer bp, gpointer udata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock a range of pages ([@start,@last]) as well as the pages of all
|
* Lock a range of pages ([@start,@end[) as well as the pages of all
|
||||||
* intersecting TBs.
|
* intersecting TBs.
|
||||||
* Locking order: acquire locks in ascending order of page index.
|
* Locking order: acquire locks in ascending order of page index.
|
||||||
*/
|
*/
|
||||||
static struct page_collection *page_collection_lock(tb_page_addr_t start,
|
static struct page_collection *page_collection_lock(tb_page_addr_t start,
|
||||||
tb_page_addr_t last)
|
tb_page_addr_t end)
|
||||||
{
|
{
|
||||||
struct page_collection *set = g_malloc(sizeof(*set));
|
struct page_collection *set = g_malloc(sizeof(*set));
|
||||||
tb_page_addr_t index;
|
tb_page_addr_t index;
|
||||||
PageDesc *pd;
|
PageDesc *pd;
|
||||||
|
|
||||||
start >>= TARGET_PAGE_BITS;
|
start >>= TARGET_PAGE_BITS;
|
||||||
last >>= TARGET_PAGE_BITS;
|
end >>= TARGET_PAGE_BITS;
|
||||||
g_assert(start <= last);
|
g_assert(start <= end);
|
||||||
|
|
||||||
set->tree = q_tree_new_full(tb_page_addr_cmp, NULL, NULL,
|
set->tree = g_tree_new_full(tb_page_addr_cmp, NULL, NULL,
|
||||||
page_entry_destroy);
|
page_entry_destroy);
|
||||||
set->max = NULL;
|
set->max = NULL;
|
||||||
assert_no_pages_locked();
|
assert_no_pages_locked();
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
q_tree_foreach(set->tree, page_entry_lock, NULL);
|
g_tree_foreach(set->tree, page_entry_lock, NULL);
|
||||||
|
|
||||||
for (index = start; index <= last; index++) {
|
for (index = start; index <= end; index++) {
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
PageForEachNext n;
|
PageForEachNext n;
|
||||||
|
|
||||||
@@ -543,7 +541,7 @@ static struct page_collection *page_collection_lock(tb_page_addr_t start,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (page_trylock_add(set, index << TARGET_PAGE_BITS)) {
|
if (page_trylock_add(set, index << TARGET_PAGE_BITS)) {
|
||||||
q_tree_foreach(set->tree, page_entry_unlock, NULL);
|
g_tree_foreach(set->tree, page_entry_unlock, NULL);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
assert_page_locked(pd);
|
assert_page_locked(pd);
|
||||||
@@ -552,7 +550,7 @@ static struct page_collection *page_collection_lock(tb_page_addr_t start,
|
|||||||
(tb_page_addr1(tb) != -1 &&
|
(tb_page_addr1(tb) != -1 &&
|
||||||
page_trylock_add(set, tb_page_addr1(tb)))) {
|
page_trylock_add(set, tb_page_addr1(tb)))) {
|
||||||
/* drop all locks, and reacquire in order */
|
/* drop all locks, and reacquire in order */
|
||||||
q_tree_foreach(set->tree, page_entry_unlock, NULL);
|
g_tree_foreach(set->tree, page_entry_unlock, NULL);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,7 +561,7 @@ static struct page_collection *page_collection_lock(tb_page_addr_t start,
|
|||||||
static void page_collection_unlock(struct page_collection *set)
|
static void page_collection_unlock(struct page_collection *set)
|
||||||
{
|
{
|
||||||
/* entries are unlocked and freed via page_entry_destroy */
|
/* entries are unlocked and freed via page_entry_destroy */
|
||||||
q_tree_destroy(set->tree);
|
g_tree_destroy(set->tree);
|
||||||
g_free(set);
|
g_free(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,14 +989,14 @@ TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
|||||||
* Called with mmap_lock held for user-mode emulation.
|
* Called with mmap_lock held for user-mode emulation.
|
||||||
* NOTE: this function must not be called while a TB is running.
|
* NOTE: this function must not be called while a TB is running.
|
||||||
*/
|
*/
|
||||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last)
|
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
|
||||||
{
|
{
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
PageForEachNext n;
|
PageForEachNext n;
|
||||||
|
|
||||||
assert_memory_lock();
|
assert_memory_lock();
|
||||||
|
|
||||||
PAGE_FOR_EACH_TB(start, last, unused, tb, n) {
|
PAGE_FOR_EACH_TB(start, end, unused, tb, n) {
|
||||||
tb_phys_invalidate__locked(tb);
|
tb_phys_invalidate__locked(tb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1010,11 +1008,11 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last)
|
|||||||
*/
|
*/
|
||||||
void tb_invalidate_phys_page(tb_page_addr_t addr)
|
void tb_invalidate_phys_page(tb_page_addr_t addr)
|
||||||
{
|
{
|
||||||
tb_page_addr_t start, last;
|
tb_page_addr_t start, end;
|
||||||
|
|
||||||
start = addr & TARGET_PAGE_MASK;
|
start = addr & TARGET_PAGE_MASK;
|
||||||
last = addr | ~TARGET_PAGE_MASK;
|
end = start + TARGET_PAGE_SIZE;
|
||||||
tb_invalidate_phys_range(start, last);
|
tb_invalidate_phys_range(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1030,7 +1028,6 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
|
|||||||
bool current_tb_modified;
|
bool current_tb_modified;
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
PageForEachNext n;
|
PageForEachNext n;
|
||||||
tb_page_addr_t last;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Without precise smc semantics, or when outside of a TB,
|
* Without precise smc semantics, or when outside of a TB,
|
||||||
@@ -1047,11 +1044,10 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
|
|||||||
assert_memory_lock();
|
assert_memory_lock();
|
||||||
current_tb = tcg_tb_lookup(pc);
|
current_tb = tcg_tb_lookup(pc);
|
||||||
|
|
||||||
last = addr | ~TARGET_PAGE_MASK;
|
|
||||||
addr &= TARGET_PAGE_MASK;
|
addr &= TARGET_PAGE_MASK;
|
||||||
current_tb_modified = false;
|
current_tb_modified = false;
|
||||||
|
|
||||||
PAGE_FOR_EACH_TB(addr, last, unused, tb, n) {
|
PAGE_FOR_EACH_TB(addr, addr + TARGET_PAGE_SIZE, unused, tb, n) {
|
||||||
if (current_tb == tb &&
|
if (current_tb == tb &&
|
||||||
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
|
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
|
||||||
/*
|
/*
|
||||||
@@ -1083,10 +1079,11 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
|
|||||||
static void
|
static void
|
||||||
tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||||
PageDesc *p, tb_page_addr_t start,
|
PageDesc *p, tb_page_addr_t start,
|
||||||
tb_page_addr_t last,
|
tb_page_addr_t end,
|
||||||
uintptr_t retaddr)
|
uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
|
tb_page_addr_t tb_start, tb_end;
|
||||||
PageForEachNext n;
|
PageForEachNext n;
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
#ifdef TARGET_HAS_PRECISE_SMC
|
||||||
bool current_tb_modified = false;
|
bool current_tb_modified = false;
|
||||||
@@ -1094,22 +1091,22 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
|||||||
#endif /* TARGET_HAS_PRECISE_SMC */
|
#endif /* TARGET_HAS_PRECISE_SMC */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We remove all the TBs in the range [start, last].
|
* We remove all the TBs in the range [start, end[.
|
||||||
* XXX: see if in some cases it could be faster to invalidate all the code
|
* XXX: see if in some cases it could be faster to invalidate all the code
|
||||||
*/
|
*/
|
||||||
PAGE_FOR_EACH_TB(start, last, p, tb, n) {
|
PAGE_FOR_EACH_TB(start, end, p, tb, n) {
|
||||||
tb_page_addr_t tb_start, tb_last;
|
|
||||||
|
|
||||||
/* NOTE: this is subtle as a TB may span two physical pages */
|
/* NOTE: this is subtle as a TB may span two physical pages */
|
||||||
tb_start = tb_page_addr0(tb);
|
|
||||||
tb_last = tb_start + tb->size - 1;
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
tb_last = MIN(tb_last, tb_start | ~TARGET_PAGE_MASK);
|
/* NOTE: tb_end may be after the end of the page, but
|
||||||
|
it is not a problem */
|
||||||
|
tb_start = tb_page_addr0(tb);
|
||||||
|
tb_end = tb_start + tb->size;
|
||||||
} else {
|
} else {
|
||||||
tb_start = tb_page_addr1(tb);
|
tb_start = tb_page_addr1(tb);
|
||||||
tb_last = tb_start + (tb_last & ~TARGET_PAGE_MASK);
|
tb_end = tb_start + ((tb_page_addr0(tb) + tb->size)
|
||||||
|
& ~TARGET_PAGE_MASK);
|
||||||
}
|
}
|
||||||
if (!(tb_last < start || tb_start > last)) {
|
if (!(tb_end <= start || tb_start >= end)) {
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
#ifdef TARGET_HAS_PRECISE_SMC
|
||||||
if (current_tb == tb &&
|
if (current_tb == tb &&
|
||||||
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
|
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
|
||||||
@@ -1151,7 +1148,7 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
|||||||
void tb_invalidate_phys_page(tb_page_addr_t addr)
|
void tb_invalidate_phys_page(tb_page_addr_t addr)
|
||||||
{
|
{
|
||||||
struct page_collection *pages;
|
struct page_collection *pages;
|
||||||
tb_page_addr_t start, last;
|
tb_page_addr_t start, end;
|
||||||
PageDesc *p;
|
PageDesc *p;
|
||||||
|
|
||||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
p = page_find(addr >> TARGET_PAGE_BITS);
|
||||||
@@ -1160,37 +1157,35 @@ void tb_invalidate_phys_page(tb_page_addr_t addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
start = addr & TARGET_PAGE_MASK;
|
start = addr & TARGET_PAGE_MASK;
|
||||||
last = addr | ~TARGET_PAGE_MASK;
|
end = start + TARGET_PAGE_SIZE;
|
||||||
pages = page_collection_lock(start, last);
|
pages = page_collection_lock(start, end);
|
||||||
tb_invalidate_phys_page_range__locked(pages, p, start, last, 0);
|
tb_invalidate_phys_page_range__locked(pages, p, start, end, 0);
|
||||||
page_collection_unlock(pages);
|
page_collection_unlock(pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invalidate all TBs which intersect with the target physical address range
|
* Invalidate all TBs which intersect with the target physical address range
|
||||||
* [start;last]. NOTE: start and end may refer to *different* physical pages.
|
* [start;end[. NOTE: start and end may refer to *different* physical pages.
|
||||||
* 'is_cpu_write_access' should be true if called from a real cpu write
|
* 'is_cpu_write_access' should be true if called from a real cpu write
|
||||||
* access: the virtual CPU will exit the current TB if code is modified inside
|
* access: the virtual CPU will exit the current TB if code is modified inside
|
||||||
* this TB.
|
* this TB.
|
||||||
*/
|
*/
|
||||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last)
|
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
|
||||||
{
|
{
|
||||||
struct page_collection *pages;
|
struct page_collection *pages;
|
||||||
tb_page_addr_t index, index_last;
|
tb_page_addr_t next;
|
||||||
|
|
||||||
pages = page_collection_lock(start, last);
|
pages = page_collection_lock(start, end);
|
||||||
|
for (next = (start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||||
index_last = last >> TARGET_PAGE_BITS;
|
start < end;
|
||||||
for (index = start >> TARGET_PAGE_BITS; index <= index_last; index++) {
|
start = next, next += TARGET_PAGE_SIZE) {
|
||||||
PageDesc *pd = page_find(index);
|
PageDesc *pd = page_find(start >> TARGET_PAGE_BITS);
|
||||||
tb_page_addr_t bound;
|
tb_page_addr_t bound = MIN(next, end);
|
||||||
|
|
||||||
if (pd == NULL) {
|
if (pd == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert_page_locked(pd);
|
assert_page_locked(pd);
|
||||||
bound = (index << TARGET_PAGE_BITS) | ~TARGET_PAGE_MASK;
|
|
||||||
bound = MIN(bound, last);
|
|
||||||
tb_invalidate_phys_page_range__locked(pages, pd, start, bound, 0);
|
tb_invalidate_phys_page_range__locked(pages, pd, start, bound, 0);
|
||||||
}
|
}
|
||||||
page_collection_unlock(pages);
|
page_collection_unlock(pages);
|
||||||
@@ -1211,7 +1206,7 @@ static void tb_invalidate_phys_page_fast__locked(struct page_collection *pages,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_page_locked(p);
|
assert_page_locked(p);
|
||||||
tb_invalidate_phys_page_range__locked(pages, p, start, start + len - 1, ra);
|
tb_invalidate_phys_page_range__locked(pages, p, start, start + len, ra);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1225,7 +1220,7 @@ void tb_invalidate_phys_range_fast(ram_addr_t ram_addr,
|
|||||||
{
|
{
|
||||||
struct page_collection *pages;
|
struct page_collection *pages;
|
||||||
|
|
||||||
pages = page_collection_lock(ram_addr, ram_addr + size - 1);
|
pages = page_collection_lock(ram_addr, ram_addr + size);
|
||||||
tb_invalidate_phys_page_fast__locked(pages, ram_addr, size, retaddr);
|
tb_invalidate_phys_page_fast__locked(pages, ram_addr, size, retaddr);
|
||||||
page_collection_unlock(pages);
|
page_collection_unlock(pages);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ void tcg_cpu_init_cflags(CPUState *cpu, bool parallel)
|
|||||||
|
|
||||||
cflags |= parallel ? CF_PARALLEL : 0;
|
cflags |= parallel ? CF_PARALLEL : 0;
|
||||||
cflags |= icount_enabled() ? CF_USE_ICOUNT : 0;
|
cflags |= icount_enabled() ? CF_USE_ICOUNT : 0;
|
||||||
cpu->tcg_cflags |= cflags;
|
cpu->tcg_cflags = cflags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcg_cpus_destroy(CPUState *cpu)
|
void tcg_cpus_destroy(CPUState *cpu)
|
||||||
|
|||||||
@@ -47,7 +47,6 @@
|
|||||||
#include "exec/cputlb.h"
|
#include "exec/cputlb.h"
|
||||||
#include "exec/translate-all.h"
|
#include "exec/translate-all.h"
|
||||||
#include "exec/translator.h"
|
#include "exec/translator.h"
|
||||||
#include "exec/tb-flush.h"
|
|
||||||
#include "qemu/bitmap.h"
|
#include "qemu/bitmap.h"
|
||||||
#include "qemu/qemu-print.h"
|
#include "qemu/qemu-print.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
@@ -572,7 +571,7 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr)
|
|||||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||||
addr = get_page_addr_code(env, pc);
|
addr = get_page_addr_code(env, pc);
|
||||||
if (addr != -1) {
|
if (addr != -1) {
|
||||||
tb_invalidate_phys_range(addr, addr);
|
tb_invalidate_phys_range(addr, addr + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -480,22 +480,24 @@ static bool pageflags_set_clear(target_ulong start, target_ulong last,
|
|||||||
* The flag PAGE_WRITE_ORG is positioned automatically depending
|
* The flag PAGE_WRITE_ORG is positioned automatically depending
|
||||||
* on PAGE_WRITE. The mmap_lock should already be held.
|
* on PAGE_WRITE. The mmap_lock should already be held.
|
||||||
*/
|
*/
|
||||||
void page_set_flags(target_ulong start, target_ulong last, int flags)
|
void page_set_flags(target_ulong start, target_ulong end, int flags)
|
||||||
{
|
{
|
||||||
|
target_ulong last;
|
||||||
bool reset = false;
|
bool reset = false;
|
||||||
bool inval_tb = false;
|
bool inval_tb = false;
|
||||||
|
|
||||||
/* This function should never be called with addresses outside the
|
/* This function should never be called with addresses outside the
|
||||||
guest address space. If this assert fires, it probably indicates
|
guest address space. If this assert fires, it probably indicates
|
||||||
a missing call to h2g_valid. */
|
a missing call to h2g_valid. */
|
||||||
assert(start <= last);
|
assert(start < end);
|
||||||
assert(last <= GUEST_ADDR_MAX);
|
assert(end - 1 <= GUEST_ADDR_MAX);
|
||||||
/* Only set PAGE_ANON with new mappings. */
|
/* Only set PAGE_ANON with new mappings. */
|
||||||
assert(!(flags & PAGE_ANON) || (flags & PAGE_RESET));
|
assert(!(flags & PAGE_ANON) || (flags & PAGE_RESET));
|
||||||
assert_memory_lock();
|
assert_memory_lock();
|
||||||
|
|
||||||
start &= TARGET_PAGE_MASK;
|
start = start & TARGET_PAGE_MASK;
|
||||||
last |= ~TARGET_PAGE_MASK;
|
end = TARGET_PAGE_ALIGN(end);
|
||||||
|
last = end - 1;
|
||||||
|
|
||||||
if (!(flags & PAGE_VALID)) {
|
if (!(flags & PAGE_VALID)) {
|
||||||
flags = 0;
|
flags = 0;
|
||||||
@@ -508,7 +510,7 @@ void page_set_flags(target_ulong start, target_ulong last, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!flags || reset) {
|
if (!flags || reset) {
|
||||||
page_reset_target_data(start, last);
|
page_reset_target_data(start, end);
|
||||||
inval_tb |= pageflags_unset(start, last);
|
inval_tb |= pageflags_unset(start, last);
|
||||||
}
|
}
|
||||||
if (flags) {
|
if (flags) {
|
||||||
@@ -516,7 +518,7 @@ void page_set_flags(target_ulong start, target_ulong last, int flags)
|
|||||||
~(reset ? 0 : PAGE_STICKY));
|
~(reset ? 0 : PAGE_STICKY));
|
||||||
}
|
}
|
||||||
if (inval_tb) {
|
if (inval_tb) {
|
||||||
tb_invalidate_phys_range(start, last);
|
tb_invalidate_phys_range(start, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,14 +816,15 @@ typedef struct TargetPageDataNode {
|
|||||||
|
|
||||||
static IntervalTreeRoot targetdata_root;
|
static IntervalTreeRoot targetdata_root;
|
||||||
|
|
||||||
void page_reset_target_data(target_ulong start, target_ulong last)
|
void page_reset_target_data(target_ulong start, target_ulong end)
|
||||||
{
|
{
|
||||||
IntervalTreeNode *n, *next;
|
IntervalTreeNode *n, *next;
|
||||||
|
target_ulong last;
|
||||||
|
|
||||||
assert_memory_lock();
|
assert_memory_lock();
|
||||||
|
|
||||||
start &= TARGET_PAGE_MASK;
|
start = start & TARGET_PAGE_MASK;
|
||||||
last |= ~TARGET_PAGE_MASK;
|
last = TARGET_PAGE_ALIGN(end) - 1;
|
||||||
|
|
||||||
for (n = interval_tree_iter_first(&targetdata_root, start, last),
|
for (n = interval_tree_iter_first(&targetdata_root, start, last),
|
||||||
next = n ? interval_tree_iter_next(n, start, last) : NULL;
|
next = n ? interval_tree_iter_next(n, start, last) : NULL;
|
||||||
@@ -884,7 +887,7 @@ void *page_get_target_data(target_ulong address)
|
|||||||
return t->data[(page - region) >> TARGET_PAGE_BITS];
|
return t->data[(page - region) >> TARGET_PAGE_BITS];
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void page_reset_target_data(target_ulong start, target_ulong last) { }
|
void page_reset_target_data(target_ulong start, target_ulong end) { }
|
||||||
#endif /* TARGET_PAGE_DATA_SIZE */
|
#endif /* TARGET_PAGE_DATA_SIZE */
|
||||||
|
|
||||||
/* The softmmu versions of these helpers are in cputlb.c. */
|
/* The softmmu versions of these helpers are in cputlb.c. */
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "hw/xen/xen_native.h"
|
|
||||||
#include "hw/xen/xen-legacy-backend.h"
|
#include "hw/xen/xen-legacy-backend.h"
|
||||||
#include "hw/xen/xen_pt.h"
|
#include "hw/xen/xen_pt.h"
|
||||||
#include "chardev/char.h"
|
#include "chardev/char.h"
|
||||||
@@ -30,12 +29,83 @@ xc_interface *xen_xc;
|
|||||||
xenforeignmemory_handle *xen_fmem;
|
xenforeignmemory_handle *xen_fmem;
|
||||||
xendevicemodel_handle *xen_dmod;
|
xendevicemodel_handle *xen_dmod;
|
||||||
|
|
||||||
static void xenstore_record_dm_state(const char *state)
|
static int store_dev_info(int domid, Chardev *cs, const char *string)
|
||||||
|
{
|
||||||
|
struct xs_handle *xs = NULL;
|
||||||
|
char *path = NULL;
|
||||||
|
char *newpath = NULL;
|
||||||
|
char *pts = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
/* Only continue if we're talking to a pty. */
|
||||||
|
if (!CHARDEV_IS_PTY(cs)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pts = cs->filename + 4;
|
||||||
|
|
||||||
|
/* We now have everything we need to set the xenstore entry. */
|
||||||
|
xs = xs_open(0);
|
||||||
|
if (xs == NULL) {
|
||||||
|
fprintf(stderr, "Could not contact XenStore\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = xs_get_domain_path(xs, domid);
|
||||||
|
if (path == NULL) {
|
||||||
|
fprintf(stderr, "xs_get_domain_path() error\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
newpath = realloc(path, (strlen(path) + strlen(string) +
|
||||||
|
strlen("/tty") + 1));
|
||||||
|
if (newpath == NULL) {
|
||||||
|
fprintf(stderr, "realloc error\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
path = newpath;
|
||||||
|
|
||||||
|
strcat(path, string);
|
||||||
|
strcat(path, "/tty");
|
||||||
|
if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) {
|
||||||
|
fprintf(stderr, "xs_write for '%s' fail", string);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(path);
|
||||||
|
xs_close(xs);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xenstore_store_pv_console_info(int i, Chardev *chr)
|
||||||
|
{
|
||||||
|
if (i == 0) {
|
||||||
|
store_dev_info(xen_domid, chr, "/console");
|
||||||
|
} else {
|
||||||
|
char buf[32];
|
||||||
|
snprintf(buf, sizeof(buf), "/device/console/%d", i);
|
||||||
|
store_dev_info(xen_domid, chr, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void xenstore_record_dm_state(struct xs_handle *xs, const char *state)
|
||||||
{
|
{
|
||||||
char path[50];
|
char path[50];
|
||||||
|
|
||||||
|
if (xs == NULL) {
|
||||||
|
error_report("xenstore connection not initialized");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(path, sizeof (path), "device-model/%u/state", xen_domid);
|
snprintf(path, sizeof (path), "device-model/%u/state", xen_domid);
|
||||||
if (!qemu_xen_xs_write(xenstore, XBT_NULL, path, state, strlen(state))) {
|
/*
|
||||||
|
* This call may fail when running restricted so don't make it fatal in
|
||||||
|
* that case. Toolstacks should instead use QMP to listen for state changes.
|
||||||
|
*/
|
||||||
|
if (!xs_write(xs, XBT_NULL, path, state, strlen(state)) &&
|
||||||
|
!xen_domid_restrict) {
|
||||||
error_report("error recording dm state");
|
error_report("error recording dm state");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -47,7 +117,7 @@ static void xen_change_state_handler(void *opaque, bool running,
|
|||||||
{
|
{
|
||||||
if (running) {
|
if (running) {
|
||||||
/* record state running */
|
/* record state running */
|
||||||
xenstore_record_dm_state("running");
|
xenstore_record_dm_state(xenstore, "running");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,15 +166,7 @@ static int xen_init(MachineState *ms)
|
|||||||
xc_interface_close(xen_xc);
|
xc_interface_close(xen_xc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
qemu_add_vm_change_state_handler(xen_change_state_handler, NULL);
|
||||||
/*
|
|
||||||
* The XenStore write would fail when running restricted so don't attempt
|
|
||||||
* it in that case. Toolstacks should instead use QMP to listen for state
|
|
||||||
* changes.
|
|
||||||
*/
|
|
||||||
if (!xen_domid_restrict) {
|
|
||||||
qemu_add_vm_change_state_handler(xen_change_state_handler, NULL);
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* opt out of system RAM being allocated by generic code
|
* opt out of system RAM being allocated by generic code
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -222,7 +222,11 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pfds = g_new0(struct pollfd, count);
|
pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
|
||||||
|
if (!pfds) {
|
||||||
|
dolog ("Could not initialize poll mode\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
err = snd_pcm_poll_descriptors (handle, pfds, count);
|
err = snd_pcm_poll_descriptors (handle, pfds, count);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
@@ -913,23 +917,28 @@ static void *alsa_audio_init(Audiodev *dev)
|
|||||||
alsa_init_per_direction(aopts->in);
|
alsa_init_per_direction(aopts->in);
|
||||||
alsa_init_per_direction(aopts->out);
|
alsa_init_per_direction(aopts->out);
|
||||||
|
|
||||||
/* don't set has_* so alsa_open can identify it wasn't set by the user */
|
/*
|
||||||
|
* 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) {
|
if (!dev->u.alsa.out->has_period_length) {
|
||||||
/* 256 frames assuming 44100Hz */
|
/* 1024 frames assuming 44100Hz */
|
||||||
dev->u.alsa.out->period_length = 5805;
|
dev->u.alsa.out->period_length = 1024 * 1000000 / 44100;
|
||||||
}
|
}
|
||||||
if (!dev->u.alsa.out->has_buffer_length) {
|
if (!dev->u.alsa.out->has_buffer_length) {
|
||||||
/* 4096 frames assuming 44100Hz */
|
/* 4096 frames assuming 44100Hz */
|
||||||
dev->u.alsa.out->buffer_length = 92880;
|
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) {
|
if (!dev->u.alsa.in->has_period_length) {
|
||||||
/* 256 frames assuming 44100Hz */
|
dev->u.alsa.in->period_length = 0;
|
||||||
dev->u.alsa.in->period_length = 5805;
|
|
||||||
}
|
}
|
||||||
if (!dev->u.alsa.in->has_buffer_length) {
|
if (!dev->u.alsa.in->has_buffer_length) {
|
||||||
/* 4096 frames assuming 44100Hz */
|
dev->u.alsa.in->buffer_length = 0;
|
||||||
dev->u.alsa.in->buffer_length = 92880;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
|
|||||||
390
audio/audio.c
390
audio/audio.c
@@ -33,7 +33,6 @@
|
|||||||
#include "qapi/qapi-visit-audio.h"
|
#include "qapi/qapi-visit-audio.h"
|
||||||
#include "qapi/qapi-commands-audio.h"
|
#include "qapi/qapi-commands-audio.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/log.h"
|
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qemu/help_option.h"
|
#include "qemu/help_option.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
@@ -149,6 +148,26 @@ static inline int audio_bits_to_index (int bits)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *audio_calloc (const char *funcname, int nmemb, size_t size)
|
||||||
|
{
|
||||||
|
int cond;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = nmemb * size;
|
||||||
|
cond = !nmemb || !size;
|
||||||
|
cond |= nmemb < 0;
|
||||||
|
cond |= len < size;
|
||||||
|
|
||||||
|
if (audio_bug ("audio_calloc", cond)) {
|
||||||
|
AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
|
||||||
|
funcname);
|
||||||
|
AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_malloc0 (len);
|
||||||
|
}
|
||||||
|
|
||||||
void AUD_vlog (const char *cap, const char *fmt, va_list ap)
|
void AUD_vlog (const char *cap, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
if (cap) {
|
if (cap) {
|
||||||
@@ -381,6 +400,13 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
|||||||
/*
|
/*
|
||||||
* Capture
|
* Capture
|
||||||
*/
|
*/
|
||||||
|
static void noop_conv (struct st_sample *dst, const void *src, int samples)
|
||||||
|
{
|
||||||
|
(void) src;
|
||||||
|
(void) dst;
|
||||||
|
(void) samples;
|
||||||
|
}
|
||||||
|
|
||||||
static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
|
static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
|
||||||
struct audsettings *as)
|
struct audsettings *as)
|
||||||
{
|
{
|
||||||
@@ -478,8 +504,15 @@ static int audio_attach_capture (HWVoiceOut *hw)
|
|||||||
sw->info = hw->info;
|
sw->info = hw->info;
|
||||||
sw->empty = 1;
|
sw->empty = 1;
|
||||||
sw->active = hw->enabled;
|
sw->active = hw->enabled;
|
||||||
|
sw->conv = noop_conv;
|
||||||
|
sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
|
||||||
sw->vol = nominal_volume;
|
sw->vol = nominal_volume;
|
||||||
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
|
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
|
||||||
|
if (!sw->rate) {
|
||||||
|
dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
|
||||||
|
g_free (sw);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
|
QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
|
||||||
QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
|
QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
|
||||||
#ifdef DEBUG_CAPTURE
|
#ifdef DEBUG_CAPTURE
|
||||||
@@ -514,8 +547,8 @@ static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
|
|||||||
static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
|
static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
|
||||||
{
|
{
|
||||||
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
|
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
|
||||||
if (audio_bug(__func__, live > hw->conv_buf.size)) {
|
if (audio_bug(__func__, live > hw->conv_buf->size)) {
|
||||||
dolog("live=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
|
dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return live;
|
return live;
|
||||||
@@ -524,13 +557,13 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
|
|||||||
static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
|
static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
|
||||||
{
|
{
|
||||||
size_t conv = 0;
|
size_t conv = 0;
|
||||||
STSampleBuffer *conv_buf = &hw->conv_buf;
|
STSampleBuffer *conv_buf = hw->conv_buf;
|
||||||
|
|
||||||
while (samples) {
|
while (samples) {
|
||||||
uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
|
uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
|
||||||
size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
|
size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
|
||||||
|
|
||||||
hw->conv(conv_buf->buffer + conv_buf->pos, src, proc);
|
hw->conv(conv_buf->samples + conv_buf->pos, src, proc);
|
||||||
conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
|
conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
|
||||||
samples -= proc;
|
samples -= proc;
|
||||||
conv += proc;
|
conv += proc;
|
||||||
@@ -542,65 +575,56 @@ static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
|
|||||||
/*
|
/*
|
||||||
* Soft voice (capture)
|
* Soft voice (capture)
|
||||||
*/
|
*/
|
||||||
static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
|
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||||
size_t frames_in_max, size_t frames_out_max,
|
|
||||||
size_t *total_in, size_t *total_out)
|
|
||||||
{
|
{
|
||||||
HWVoiceIn *hw = sw->hw;
|
HWVoiceIn *hw = sw->hw;
|
||||||
struct st_sample *src, *dst;
|
size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
|
||||||
size_t live, rpos, frames_in, frames_out;
|
struct st_sample *src, *dst = sw->buf;
|
||||||
|
|
||||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
|
||||||
rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
|
|
||||||
|
|
||||||
/* resample conv_buf from rpos to end of buffer */
|
|
||||||
src = hw->conv_buf.buffer + rpos;
|
|
||||||
frames_in = MIN(frames_in_max, hw->conv_buf.size - rpos);
|
|
||||||
dst = sw->resample_buf.buffer;
|
|
||||||
frames_out = frames_out_max;
|
|
||||||
st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
|
|
||||||
rpos += frames_in;
|
|
||||||
*total_in = frames_in;
|
|
||||||
*total_out = frames_out;
|
|
||||||
|
|
||||||
/* resample conv_buf from start of buffer if there are input frames left */
|
|
||||||
if (frames_in_max - frames_in && rpos == hw->conv_buf.size) {
|
|
||||||
src = hw->conv_buf.buffer;
|
|
||||||
frames_in = frames_in_max - frames_in;
|
|
||||||
dst += frames_out;
|
|
||||||
frames_out = frames_out_max - frames_out;
|
|
||||||
st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
|
|
||||||
*total_in += frames_in;
|
|
||||||
*total_out += frames_out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
|
|
||||||
{
|
|
||||||
HWVoiceIn *hw = sw->hw;
|
|
||||||
size_t live, frames_out_max, total_in, total_out;
|
|
||||||
|
|
||||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
if (!live) {
|
if (!live) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (audio_bug(__func__, live > hw->conv_buf.size)) {
|
if (audio_bug(__func__, live > hw->conv_buf->size)) {
|
||||||
dolog("live_in=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
|
dolog("live_in=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
frames_out_max = MIN(buf_len / sw->info.bytes_per_frame,
|
rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size);
|
||||||
sw->resample_buf.size);
|
|
||||||
|
|
||||||
audio_pcm_sw_resample_in(sw, live, frames_out_max, &total_in, &total_out);
|
samples = size / sw->info.bytes_per_frame;
|
||||||
|
|
||||||
|
swlim = (live * sw->ratio) >> 32;
|
||||||
|
swlim = MIN (swlim, samples);
|
||||||
|
|
||||||
|
while (swlim) {
|
||||||
|
src = hw->conv_buf->samples + rpos;
|
||||||
|
if (hw->conv_buf->pos > rpos) {
|
||||||
|
isamp = hw->conv_buf->pos - rpos;
|
||||||
|
} else {
|
||||||
|
isamp = hw->conv_buf->size - rpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isamp) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
osamp = swlim;
|
||||||
|
|
||||||
|
st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
|
||||||
|
swlim -= osamp;
|
||||||
|
rpos = (rpos + isamp) % hw->conv_buf->size;
|
||||||
|
dst += osamp;
|
||||||
|
ret += osamp;
|
||||||
|
total += isamp;
|
||||||
|
}
|
||||||
|
|
||||||
if (!hw->pcm_ops->volume_in) {
|
if (!hw->pcm_ops->volume_in) {
|
||||||
mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
|
mixeng_volume (sw->buf, ret, &sw->vol);
|
||||||
}
|
}
|
||||||
sw->clip(buf, sw->resample_buf.buffer, total_out);
|
|
||||||
|
|
||||||
sw->total_hw_samples_acquired += total_in;
|
sw->clip (buf, sw->buf, ret);
|
||||||
return total_out * sw->info.bytes_per_frame;
|
sw->total_hw_samples_acquired += total;
|
||||||
|
return ret * sw->info.bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -636,8 +660,8 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
|||||||
if (nb_live1) {
|
if (nb_live1) {
|
||||||
size_t live = smin;
|
size_t live = smin;
|
||||||
|
|
||||||
if (audio_bug(__func__, live > hw->mix_buf.size)) {
|
if (audio_bug(__func__, live > hw->mix_buf->size)) {
|
||||||
dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
|
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return live;
|
return live;
|
||||||
@@ -654,17 +678,17 @@ static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)
|
|||||||
static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
|
static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
|
||||||
{
|
{
|
||||||
size_t clipped = 0;
|
size_t clipped = 0;
|
||||||
size_t pos = hw->mix_buf.pos;
|
size_t pos = hw->mix_buf->pos;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
st_sample *src = hw->mix_buf.buffer + pos;
|
st_sample *src = hw->mix_buf->samples + pos;
|
||||||
uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
|
uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
|
||||||
size_t samples_till_end_of_buf = hw->mix_buf.size - pos;
|
size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
|
||||||
size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
|
size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
|
||||||
|
|
||||||
hw->clip(dst, src, samples_to_clip);
|
hw->clip(dst, src, samples_to_clip);
|
||||||
|
|
||||||
pos = (pos + samples_to_clip) % hw->mix_buf.size;
|
pos = (pos + samples_to_clip) % hw->mix_buf->size;
|
||||||
len -= samples_to_clip;
|
len -= samples_to_clip;
|
||||||
clipped += samples_to_clip;
|
clipped += samples_to_clip;
|
||||||
}
|
}
|
||||||
@@ -673,113 +697,84 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
|
|||||||
/*
|
/*
|
||||||
* Soft voice (playback)
|
* Soft voice (playback)
|
||||||
*/
|
*/
|
||||||
static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
|
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||||
size_t frames_in_max, size_t frames_out_max,
|
|
||||||
size_t *total_in, size_t *total_out)
|
|
||||||
{
|
{
|
||||||
HWVoiceOut *hw = sw->hw;
|
size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
|
||||||
struct st_sample *src, *dst;
|
size_t hw_free;
|
||||||
size_t live, wpos, frames_in, frames_out;
|
size_t ret = 0, pos = 0, total = 0;
|
||||||
|
|
||||||
live = sw->total_hw_samples_mixed;
|
if (!sw) {
|
||||||
wpos = (hw->mix_buf.pos + live) % hw->mix_buf.size;
|
return size;
|
||||||
|
|
||||||
/* write to mix_buf from wpos to end of buffer */
|
|
||||||
src = sw->resample_buf.buffer;
|
|
||||||
frames_in = frames_in_max;
|
|
||||||
dst = hw->mix_buf.buffer + wpos;
|
|
||||||
frames_out = MIN(frames_out_max, hw->mix_buf.size - wpos);
|
|
||||||
st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
|
|
||||||
wpos += frames_out;
|
|
||||||
*total_in = frames_in;
|
|
||||||
*total_out = frames_out;
|
|
||||||
|
|
||||||
/* write to mix_buf from start of buffer if there are input frames left */
|
|
||||||
if (frames_in_max - frames_in > 0 && wpos == hw->mix_buf.size) {
|
|
||||||
src += frames_in;
|
|
||||||
frames_in = frames_in_max - frames_in;
|
|
||||||
dst = hw->mix_buf.buffer;
|
|
||||||
frames_out = frames_out_max - frames_out;
|
|
||||||
st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
|
|
||||||
*total_in += frames_in;
|
|
||||||
*total_out += frames_out;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
|
hwsamples = sw->hw->mix_buf->size;
|
||||||
{
|
|
||||||
HWVoiceOut *hw = sw->hw;
|
|
||||||
size_t live, dead, hw_free, sw_max, fe_max;
|
|
||||||
size_t frames_in_max, frames_out_max, total_in, total_out;
|
|
||||||
|
|
||||||
live = sw->total_hw_samples_mixed;
|
live = sw->total_hw_samples_mixed;
|
||||||
if (audio_bug(__func__, live > hw->mix_buf.size)) {
|
if (audio_bug(__func__, live > hwsamples)) {
|
||||||
dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
|
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hwsamples);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (live == hw->mix_buf.size) {
|
if (live == hwsamples) {
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
dolog ("%s is full %zu\n", sw->name, live);
|
dolog ("%s is full %zu\n", sw->name, live);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dead = hw->mix_buf.size - live;
|
wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
|
||||||
hw_free = audio_pcm_hw_get_free(hw);
|
|
||||||
|
dead = hwsamples - live;
|
||||||
|
hw_free = audio_pcm_hw_get_free(sw->hw);
|
||||||
hw_free = hw_free > live ? hw_free - live : 0;
|
hw_free = hw_free > live ? hw_free - live : 0;
|
||||||
frames_out_max = MIN(dead, hw_free);
|
samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
|
||||||
sw_max = st_rate_frames_in(sw->rate, frames_out_max);
|
samples = MIN(samples, size / sw->info.bytes_per_frame);
|
||||||
fe_max = MIN(buf_len / sw->info.bytes_per_frame + sw->resample_buf.pos,
|
if (samples) {
|
||||||
sw->resample_buf.size);
|
sw->conv(sw->buf, buf, samples);
|
||||||
frames_in_max = MIN(sw_max, fe_max);
|
|
||||||
|
|
||||||
if (!frames_in_max) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frames_in_max > sw->resample_buf.pos) {
|
|
||||||
sw->conv(sw->resample_buf.buffer + sw->resample_buf.pos,
|
|
||||||
buf, frames_in_max - sw->resample_buf.pos);
|
|
||||||
if (!sw->hw->pcm_ops->volume_out) {
|
if (!sw->hw->pcm_ops->volume_out) {
|
||||||
mixeng_volume(sw->resample_buf.buffer + sw->resample_buf.pos,
|
mixeng_volume(sw->buf, samples, &sw->vol);
|
||||||
frames_in_max - sw->resample_buf.pos, &sw->vol);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
|
while (samples) {
|
||||||
&total_in, &total_out);
|
dead = hwsamples - live;
|
||||||
|
left = hwsamples - wpos;
|
||||||
sw->total_hw_samples_mixed += total_out;
|
blck = MIN (dead, left);
|
||||||
sw->empty = sw->total_hw_samples_mixed == 0;
|
if (!blck) {
|
||||||
|
break;
|
||||||
/*
|
}
|
||||||
* Upsampling may leave one audio frame in the resample buffer. Decrement
|
isamp = samples;
|
||||||
* total_in by one if there was a leftover frame from the previous resample
|
osamp = blck;
|
||||||
* pass in the resample buffer. Increment total_in by one if the current
|
st_rate_flow_mix (
|
||||||
* resample pass left one frame in the resample buffer.
|
sw->rate,
|
||||||
*/
|
sw->buf + pos,
|
||||||
if (frames_in_max - total_in == 1) {
|
sw->hw->mix_buf->samples + wpos,
|
||||||
/* copy one leftover audio frame to the beginning of the buffer */
|
&isamp,
|
||||||
*sw->resample_buf.buffer = *(sw->resample_buf.buffer + total_in);
|
&osamp
|
||||||
total_in += 1 - sw->resample_buf.pos;
|
);
|
||||||
sw->resample_buf.pos = 1;
|
ret += isamp;
|
||||||
} else if (total_in >= sw->resample_buf.pos) {
|
samples -= isamp;
|
||||||
total_in -= sw->resample_buf.pos;
|
pos += isamp;
|
||||||
sw->resample_buf.pos = 0;
|
live += osamp;
|
||||||
|
wpos = (wpos + osamp) % hwsamples;
|
||||||
|
total += osamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw->total_hw_samples_mixed += total;
|
||||||
|
sw->empty = sw->total_hw_samples_mixed == 0;
|
||||||
|
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
dolog (
|
dolog (
|
||||||
"%s: write size %zu written %zu total mixed %zu\n",
|
"%s: write size %zu ret %zu total sw %zu\n",
|
||||||
SW_NAME(sw),
|
SW_NAME (sw),
|
||||||
buf_len / sw->info.bytes_per_frame,
|
size / sw->info.bytes_per_frame,
|
||||||
total_in,
|
ret,
|
||||||
sw->total_hw_samples_mixed
|
sw->total_hw_samples_mixed
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return total_in * sw->info.bytes_per_frame;
|
return ret * sw->info.bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
@@ -997,6 +992,18 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audio_frontend_frames_in() - returns the number of frames the resampling
|
||||||
|
* code generates from frames_in frames
|
||||||
|
*
|
||||||
|
* @sw: audio recording frontend
|
||||||
|
* @frames_in: number of frames
|
||||||
|
*/
|
||||||
|
static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in)
|
||||||
|
{
|
||||||
|
return (int64_t)frames_in * sw->ratio >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
static size_t audio_get_avail (SWVoiceIn *sw)
|
static size_t audio_get_avail (SWVoiceIn *sw)
|
||||||
{
|
{
|
||||||
size_t live;
|
size_t live;
|
||||||
@@ -1006,21 +1013,33 @@ static size_t audio_get_avail (SWVoiceIn *sw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
if (audio_bug(__func__, live > sw->hw->conv_buf.size)) {
|
if (audio_bug(__func__, live > sw->hw->conv_buf->size)) {
|
||||||
dolog("live=%zu sw->hw->conv_buf.size=%zu\n", live,
|
dolog("live=%zu sw->hw->conv_buf->size=%zu\n", live,
|
||||||
sw->hw->conv_buf.size);
|
sw->hw->conv_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ldebug (
|
ldebug (
|
||||||
"%s: get_avail live %zu frontend frames %u\n",
|
"%s: get_avail live %zu frontend frames %zu\n",
|
||||||
SW_NAME (sw),
|
SW_NAME (sw),
|
||||||
live, st_rate_frames_out(sw->rate, live)
|
live, audio_frontend_frames_in(sw, live)
|
||||||
);
|
);
|
||||||
|
|
||||||
return live;
|
return live;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audio_frontend_frames_out() - returns the number of frames needed to
|
||||||
|
* get frames_out frames after resampling
|
||||||
|
*
|
||||||
|
* @sw: audio playback frontend
|
||||||
|
* @frames_out: number of frames
|
||||||
|
*/
|
||||||
|
static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out)
|
||||||
|
{
|
||||||
|
return ((int64_t)frames_out << 32) / sw->ratio;
|
||||||
|
}
|
||||||
|
|
||||||
static size_t audio_get_free(SWVoiceOut *sw)
|
static size_t audio_get_free(SWVoiceOut *sw)
|
||||||
{
|
{
|
||||||
size_t live, dead;
|
size_t live, dead;
|
||||||
@@ -1031,17 +1050,17 @@ static size_t audio_get_free(SWVoiceOut *sw)
|
|||||||
|
|
||||||
live = sw->total_hw_samples_mixed;
|
live = sw->total_hw_samples_mixed;
|
||||||
|
|
||||||
if (audio_bug(__func__, live > sw->hw->mix_buf.size)) {
|
if (audio_bug(__func__, live > sw->hw->mix_buf->size)) {
|
||||||
dolog("live=%zu sw->hw->mix_buf.size=%zu\n", live,
|
dolog("live=%zu sw->hw->mix_buf->size=%zu\n", live,
|
||||||
sw->hw->mix_buf.size);
|
sw->hw->mix_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dead = sw->hw->mix_buf.size - live;
|
dead = sw->hw->mix_buf->size - live;
|
||||||
|
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
dolog("%s: get_free live %zu dead %zu frontend frames %u\n",
|
dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
|
||||||
SW_NAME(sw), live, dead, st_rate_frames_in(sw->rate, dead));
|
SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return dead;
|
return dead;
|
||||||
@@ -1057,40 +1076,32 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
|
|||||||
|
|
||||||
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||||
SWVoiceOut *sw = &sc->sw;
|
SWVoiceOut *sw = &sc->sw;
|
||||||
size_t rpos2 = rpos;
|
int rpos2 = rpos;
|
||||||
|
|
||||||
n = samples;
|
n = samples;
|
||||||
while (n) {
|
while (n) {
|
||||||
size_t till_end_of_hw = hw->mix_buf.size - rpos2;
|
size_t till_end_of_hw = hw->mix_buf->size - rpos2;
|
||||||
size_t to_read = MIN(till_end_of_hw, n);
|
size_t to_write = MIN(till_end_of_hw, n);
|
||||||
size_t live, frames_in, frames_out;
|
size_t bytes = to_write * hw->info.bytes_per_frame;
|
||||||
|
size_t written;
|
||||||
|
|
||||||
sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
|
sw->buf = hw->mix_buf->samples + rpos2;
|
||||||
sw->resample_buf.size = to_read;
|
written = audio_pcm_sw_write (sw, NULL, bytes);
|
||||||
live = sw->total_hw_samples_mixed;
|
if (written - bytes) {
|
||||||
|
dolog("Could not mix %zu bytes into a capture "
|
||||||
audio_pcm_sw_resample_out(sw,
|
|
||||||
to_read, sw->hw->mix_buf.size - live,
|
|
||||||
&frames_in, &frames_out);
|
|
||||||
|
|
||||||
sw->total_hw_samples_mixed += frames_out;
|
|
||||||
sw->empty = sw->total_hw_samples_mixed == 0;
|
|
||||||
|
|
||||||
if (to_read - frames_in) {
|
|
||||||
dolog("Could not mix %zu frames into a capture "
|
|
||||||
"buffer, mixed %zu\n",
|
"buffer, mixed %zu\n",
|
||||||
to_read, frames_in);
|
bytes, written);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n -= to_read;
|
n -= to_write;
|
||||||
rpos2 = (rpos2 + to_read) % hw->mix_buf.size;
|
rpos2 = (rpos2 + to_write) % hw->mix_buf->size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n = MIN(samples, hw->mix_buf.size - rpos);
|
n = MIN(samples, hw->mix_buf->size - rpos);
|
||||||
mixeng_clear(hw->mix_buf.buffer + rpos, n);
|
mixeng_clear(hw->mix_buf->samples + rpos, n);
|
||||||
mixeng_clear(hw->mix_buf.buffer, samples - n);
|
mixeng_clear(hw->mix_buf->samples, samples - n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
||||||
@@ -1116,7 +1127,7 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
|||||||
|
|
||||||
live -= proc;
|
live -= proc;
|
||||||
clipped += proc;
|
clipped += proc;
|
||||||
hw->mix_buf.pos = (hw->mix_buf.pos + proc) % hw->mix_buf.size;
|
hw->mix_buf->pos = (hw->mix_buf->pos + proc) % hw->mix_buf->size;
|
||||||
|
|
||||||
if (proc == 0 || proc < decr) {
|
if (proc == 0 || proc < decr) {
|
||||||
break;
|
break;
|
||||||
@@ -1170,14 +1181,12 @@ static void audio_run_out (AudioState *s)
|
|||||||
size_t free;
|
size_t free;
|
||||||
|
|
||||||
if (hw_free > sw->total_hw_samples_mixed) {
|
if (hw_free > sw->total_hw_samples_mixed) {
|
||||||
free = st_rate_frames_in(sw->rate,
|
free = audio_frontend_frames_out(sw,
|
||||||
MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
|
MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
|
||||||
} else {
|
} else {
|
||||||
free = 0;
|
free = 0;
|
||||||
}
|
}
|
||||||
if (free > sw->resample_buf.pos) {
|
if (free > 0) {
|
||||||
free = MIN(free, sw->resample_buf.size)
|
|
||||||
- sw->resample_buf.pos;
|
|
||||||
sw->callback.fn(sw->callback.opaque,
|
sw->callback.fn(sw->callback.opaque,
|
||||||
free * sw->info.bytes_per_frame);
|
free * sw->info.bytes_per_frame);
|
||||||
}
|
}
|
||||||
@@ -1189,8 +1198,8 @@ static void audio_run_out (AudioState *s)
|
|||||||
live = 0;
|
live = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bug(__func__, live > hw->mix_buf.size)) {
|
if (audio_bug(__func__, live > hw->mix_buf->size)) {
|
||||||
dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
|
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1218,13 +1227,13 @@ static void audio_run_out (AudioState *s)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_rpos = hw->mix_buf.pos;
|
prev_rpos = hw->mix_buf->pos;
|
||||||
played = audio_pcm_hw_run_out(hw, live);
|
played = audio_pcm_hw_run_out(hw, live);
|
||||||
replay_audio_out(&played);
|
replay_audio_out(&played);
|
||||||
if (audio_bug(__func__, hw->mix_buf.pos >= hw->mix_buf.size)) {
|
if (audio_bug(__func__, hw->mix_buf->pos >= hw->mix_buf->size)) {
|
||||||
dolog("hw->mix_buf.pos=%zu hw->mix_buf.size=%zu played=%zu\n",
|
dolog("hw->mix_buf->pos=%zu hw->mix_buf->size=%zu played=%zu\n",
|
||||||
hw->mix_buf.pos, hw->mix_buf.size, played);
|
hw->mix_buf->pos, hw->mix_buf->size, played);
|
||||||
hw->mix_buf.pos = 0;
|
hw->mix_buf->pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
@@ -1305,10 +1314,10 @@ static void audio_run_in (AudioState *s)
|
|||||||
|
|
||||||
if (replay_mode != REPLAY_MODE_PLAY) {
|
if (replay_mode != REPLAY_MODE_PLAY) {
|
||||||
captured = audio_pcm_hw_run_in(
|
captured = audio_pcm_hw_run_in(
|
||||||
hw, hw->conv_buf.size - audio_pcm_hw_get_live_in(hw));
|
hw, hw->conv_buf->size - audio_pcm_hw_get_live_in(hw));
|
||||||
}
|
}
|
||||||
replay_audio_in(&captured, hw->conv_buf.buffer, &hw->conv_buf.pos,
|
replay_audio_in(&captured, hw->conv_buf->samples, &hw->conv_buf->pos,
|
||||||
hw->conv_buf.size);
|
hw->conv_buf->size);
|
||||||
|
|
||||||
min = audio_pcm_hw_find_min_in (hw);
|
min = audio_pcm_hw_find_min_in (hw);
|
||||||
hw->total_samples_captured += captured - min;
|
hw->total_samples_captured += captured - min;
|
||||||
@@ -1321,9 +1330,8 @@ static void audio_run_in (AudioState *s)
|
|||||||
size_t sw_avail = audio_get_avail(sw);
|
size_t sw_avail = audio_get_avail(sw);
|
||||||
size_t avail;
|
size_t avail;
|
||||||
|
|
||||||
avail = st_rate_frames_out(sw->rate, sw_avail);
|
avail = audio_frontend_frames_in(sw, sw_avail);
|
||||||
if (avail > 0) {
|
if (avail > 0) {
|
||||||
avail = MIN(avail, sw->resample_buf.size);
|
|
||||||
sw->callback.fn(sw->callback.opaque,
|
sw->callback.fn(sw->callback.opaque,
|
||||||
avail * sw->info.bytes_per_frame);
|
avail * sw->info.bytes_per_frame);
|
||||||
}
|
}
|
||||||
@@ -1342,14 +1350,14 @@ static void audio_run_capture (AudioState *s)
|
|||||||
SWVoiceOut *sw;
|
SWVoiceOut *sw;
|
||||||
|
|
||||||
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
|
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
|
||||||
rpos = hw->mix_buf.pos;
|
rpos = hw->mix_buf->pos;
|
||||||
while (live) {
|
while (live) {
|
||||||
size_t left = hw->mix_buf.size - rpos;
|
size_t left = hw->mix_buf->size - rpos;
|
||||||
size_t to_capture = MIN(live, left);
|
size_t to_capture = MIN(live, left);
|
||||||
struct st_sample *src;
|
struct st_sample *src;
|
||||||
struct capture_callback *cb;
|
struct capture_callback *cb;
|
||||||
|
|
||||||
src = hw->mix_buf.buffer + rpos;
|
src = hw->mix_buf->samples + rpos;
|
||||||
hw->clip (cap->buf, src, to_capture);
|
hw->clip (cap->buf, src, to_capture);
|
||||||
mixeng_clear (src, to_capture);
|
mixeng_clear (src, to_capture);
|
||||||
|
|
||||||
@@ -1357,10 +1365,10 @@ static void audio_run_capture (AudioState *s)
|
|||||||
cb->ops.capture (cb->opaque, cap->buf,
|
cb->ops.capture (cb->opaque, cap->buf,
|
||||||
to_capture * hw->info.bytes_per_frame);
|
to_capture * hw->info.bytes_per_frame);
|
||||||
}
|
}
|
||||||
rpos = (rpos + to_capture) % hw->mix_buf.size;
|
rpos = (rpos + to_capture) % hw->mix_buf->size;
|
||||||
live -= to_capture;
|
live -= to_capture;
|
||||||
}
|
}
|
||||||
hw->mix_buf.pos = rpos;
|
hw->mix_buf->pos = rpos;
|
||||||
|
|
||||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||||
if (!sw->active && sw->empty) {
|
if (!sw->active && sw->empty) {
|
||||||
@@ -1919,7 +1927,7 @@ CaptureVoiceOut *AUD_add_capture(
|
|||||||
|
|
||||||
audio_pcm_init_info (&hw->info, as);
|
audio_pcm_init_info (&hw->info, as);
|
||||||
|
|
||||||
cap->buf = g_malloc0_n(hw->mix_buf.size, hw->info.bytes_per_frame);
|
cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
|
||||||
|
|
||||||
if (hw->info.is_float) {
|
if (hw->info.is_float) {
|
||||||
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
||||||
@@ -1971,7 +1979,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
|
|||||||
sw = sw1;
|
sw = sw1;
|
||||||
}
|
}
|
||||||
QLIST_REMOVE (cap, entries);
|
QLIST_REMOVE (cap, entries);
|
||||||
g_free(cap->hw.mix_buf.buffer);
|
g_free (cap->hw.mix_buf);
|
||||||
g_free (cap->buf);
|
g_free (cap->buf);
|
||||||
g_free (cap);
|
g_free (cap);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ typedef struct SWVoiceCap SWVoiceCap;
|
|||||||
|
|
||||||
typedef struct STSampleBuffer {
|
typedef struct STSampleBuffer {
|
||||||
size_t pos, size;
|
size_t pos, size;
|
||||||
st_sample *buffer;
|
st_sample samples[];
|
||||||
} STSampleBuffer;
|
} STSampleBuffer;
|
||||||
|
|
||||||
typedef struct HWVoiceOut {
|
typedef struct HWVoiceOut {
|
||||||
@@ -71,7 +71,7 @@ typedef struct HWVoiceOut {
|
|||||||
f_sample *clip;
|
f_sample *clip;
|
||||||
uint64_t ts_helper;
|
uint64_t ts_helper;
|
||||||
|
|
||||||
STSampleBuffer mix_buf;
|
STSampleBuffer *mix_buf;
|
||||||
void *buf_emul;
|
void *buf_emul;
|
||||||
size_t pos_emul, pending_emul, size_emul;
|
size_t pos_emul, pending_emul, size_emul;
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ typedef struct HWVoiceIn {
|
|||||||
size_t total_samples_captured;
|
size_t total_samples_captured;
|
||||||
uint64_t ts_helper;
|
uint64_t ts_helper;
|
||||||
|
|
||||||
STSampleBuffer conv_buf;
|
STSampleBuffer *conv_buf;
|
||||||
void *buf_emul;
|
void *buf_emul;
|
||||||
size_t pos_emul, pending_emul, size_emul;
|
size_t pos_emul, pending_emul, size_emul;
|
||||||
|
|
||||||
@@ -108,7 +108,8 @@ struct SWVoiceOut {
|
|||||||
AudioState *s;
|
AudioState *s;
|
||||||
struct audio_pcm_info info;
|
struct audio_pcm_info info;
|
||||||
t_sample *conv;
|
t_sample *conv;
|
||||||
STSampleBuffer resample_buf;
|
int64_t ratio;
|
||||||
|
struct st_sample *buf;
|
||||||
void *rate;
|
void *rate;
|
||||||
size_t total_hw_samples_mixed;
|
size_t total_hw_samples_mixed;
|
||||||
int active;
|
int active;
|
||||||
@@ -125,9 +126,10 @@ struct SWVoiceIn {
|
|||||||
AudioState *s;
|
AudioState *s;
|
||||||
int active;
|
int active;
|
||||||
struct audio_pcm_info info;
|
struct audio_pcm_info info;
|
||||||
|
int64_t ratio;
|
||||||
void *rate;
|
void *rate;
|
||||||
size_t total_hw_samples_acquired;
|
size_t total_hw_samples_acquired;
|
||||||
STSampleBuffer resample_buf;
|
struct st_sample *buf;
|
||||||
f_sample *clip;
|
f_sample *clip;
|
||||||
HWVoiceIn *hw;
|
HWVoiceIn *hw;
|
||||||
char *name;
|
char *name;
|
||||||
@@ -143,14 +145,14 @@ struct audio_driver {
|
|||||||
void *(*init) (Audiodev *);
|
void *(*init) (Audiodev *);
|
||||||
void (*fini) (void *);
|
void (*fini) (void *);
|
||||||
#ifdef CONFIG_GIO
|
#ifdef CONFIG_GIO
|
||||||
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager, bool p2p);
|
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager);
|
||||||
#endif
|
#endif
|
||||||
struct audio_pcm_ops *pcm_ops;
|
struct audio_pcm_ops *pcm_ops;
|
||||||
int can_be_default;
|
int can_be_default;
|
||||||
int max_voices_out;
|
int max_voices_out;
|
||||||
int max_voices_in;
|
int max_voices_in;
|
||||||
size_t voice_size_out;
|
int voice_size_out;
|
||||||
size_t voice_size_in;
|
int voice_size_in;
|
||||||
QLIST_ENTRY(audio_driver) next;
|
QLIST_ENTRY(audio_driver) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -249,6 +251,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
|
|||||||
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
|
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
|
||||||
|
|
||||||
int audio_bug (const char *funcname, int cond);
|
int audio_bug (const char *funcname, int cond);
|
||||||
|
void *audio_calloc (const char *funcname, int nmemb, size_t size);
|
||||||
|
|
||||||
void audio_run(AudioState *s, const char *msg);
|
void audio_run(AudioState *s, const char *msg);
|
||||||
|
|
||||||
@@ -291,6 +294,9 @@ static inline size_t audio_ring_posb(size_t pos, size_t dist, size_t len)
|
|||||||
#define ldebug(fmt, ...) (void)0
|
#define ldebug(fmt, ...) (void)0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define AUDIO_STRINGIFY_(n) #n
|
||||||
|
#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
|
||||||
|
|
||||||
typedef struct AudiodevListEntry {
|
typedef struct AudiodevListEntry {
|
||||||
Audiodev *dev;
|
Audiodev *dev;
|
||||||
QSIMPLEQ_ENTRY(AudiodevListEntry) next;
|
QSIMPLEQ_ENTRY(AudiodevListEntry) next;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
|
|||||||
struct audio_driver *drv)
|
struct audio_driver *drv)
|
||||||
{
|
{
|
||||||
int max_voices = glue (drv->max_voices_, TYPE);
|
int max_voices = glue (drv->max_voices_, TYPE);
|
||||||
size_t voice_size = glue(drv->voice_size_, TYPE);
|
int voice_size = glue (drv->voice_size_, TYPE);
|
||||||
|
|
||||||
if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
|
if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
|
||||||
if (!max_voices) {
|
if (!max_voices) {
|
||||||
@@ -63,17 +63,16 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bug(__func__, voice_size && !max_voices)) {
|
if (audio_bug(__func__, voice_size && !max_voices)) {
|
||||||
dolog("drv=`%s' voice_size=%zu max_voices=0\n",
|
dolog ("drv=`%s' voice_size=%d max_voices=0\n",
|
||||||
drv->name, voice_size);
|
drv->name, voice_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
|
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
|
||||||
{
|
{
|
||||||
g_free(hw->buf_emul);
|
g_free(hw->buf_emul);
|
||||||
g_free(HWBUF.buffer);
|
g_free (HWBUF);
|
||||||
HWBUF.buffer = NULL;
|
HWBUF = NULL;
|
||||||
HWBUF.size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
|
static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
|
||||||
@@ -84,67 +83,56 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
|
|||||||
dolog("Attempted to allocate empty buffer\n");
|
dolog("Attempted to allocate empty buffer\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
HWBUF.buffer = g_new0(st_sample, samples);
|
HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
|
||||||
HWBUF.size = samples;
|
HWBUF->size = samples;
|
||||||
HWBUF.pos = 0;
|
|
||||||
} else {
|
} else {
|
||||||
HWBUF.buffer = NULL;
|
HWBUF = NULL;
|
||||||
HWBUF.size = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
|
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
|
||||||
{
|
{
|
||||||
g_free(sw->resample_buf.buffer);
|
g_free (sw->buf);
|
||||||
sw->resample_buf.buffer = NULL;
|
|
||||||
sw->resample_buf.size = 0;
|
|
||||||
|
|
||||||
if (sw->rate) {
|
if (sw->rate) {
|
||||||
st_rate_stop (sw->rate);
|
st_rate_stop (sw->rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw->buf = NULL;
|
||||||
sw->rate = NULL;
|
sw->rate = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
|
static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
|
||||||
{
|
{
|
||||||
HW *hw = sw->hw;
|
int samples;
|
||||||
uint64_t samples;
|
|
||||||
|
|
||||||
if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
|
if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);
|
#ifdef DAC
|
||||||
if (samples == 0) {
|
samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
|
||||||
uint64_t f_fe_min;
|
#else
|
||||||
uint64_t f_be = (uint32_t)hw->info.freq;
|
samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
|
sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
|
||||||
f_fe_min = (f_be + HWBUF.size - 1) / HWBUF.size;
|
if (!sw->buf) {
|
||||||
qemu_log_mask(LOG_UNIMP,
|
dolog ("Could not allocate buffer for `%s' (%d samples)\n",
|
||||||
AUDIO_CAP ": The guest selected a " NAME " sample rate"
|
SW_NAME (sw), samples);
|
||||||
" of %d Hz for %s. Only sample rates >= %" PRIu64 " Hz"
|
|
||||||
" are supported.\n",
|
|
||||||
sw->info.freq, sw->name, f_fe_min);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate one additional audio frame that is needed for upsampling
|
|
||||||
* if the resample buffer size is small. For large buffer sizes take
|
|
||||||
* care of overflows and truncation.
|
|
||||||
*/
|
|
||||||
samples = samples < SIZE_MAX ? samples + 1 : SIZE_MAX;
|
|
||||||
sw->resample_buf.buffer = g_new0(st_sample, samples);
|
|
||||||
sw->resample_buf.size = samples;
|
|
||||||
sw->resample_buf.pos = 0;
|
|
||||||
|
|
||||||
#ifdef DAC
|
#ifdef DAC
|
||||||
sw->rate = st_rate_start(sw->info.freq, hw->info.freq);
|
sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
|
||||||
#else
|
#else
|
||||||
sw->rate = st_rate_start(hw->info.freq, sw->info.freq);
|
sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
|
||||||
#endif
|
#endif
|
||||||
|
if (!sw->rate) {
|
||||||
|
g_free (sw->buf);
|
||||||
|
sw->buf = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,8 +149,11 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
|||||||
sw->hw = hw;
|
sw->hw = hw;
|
||||||
sw->active = 0;
|
sw->active = 0;
|
||||||
#ifdef DAC
|
#ifdef DAC
|
||||||
|
sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
|
||||||
sw->total_hw_samples_mixed = 0;
|
sw->total_hw_samples_mixed = 0;
|
||||||
sw->empty = 1;
|
sw->empty = 1;
|
||||||
|
#else
|
||||||
|
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (sw->info.is_float) {
|
if (sw->info.is_float) {
|
||||||
@@ -273,11 +264,13 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE));
|
||||||
* Since glue(s->nb_hw_voices_, TYPE) is != 0, glue(drv->voice_size_, TYPE)
|
if (!hw) {
|
||||||
* is guaranteed to be != 0. See the audio_init_nb_voices_* functions.
|
dolog ("Can not allocate voice `%s' size %d\n",
|
||||||
*/
|
drv->name, glue (drv->voice_size_, TYPE));
|
||||||
hw = g_malloc0(glue(drv->voice_size_, TYPE));
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
hw->s = s;
|
hw->s = s;
|
||||||
hw->pcm_ops = drv->pcm_ops;
|
hw->pcm_ops = drv->pcm_ops;
|
||||||
|
|
||||||
@@ -425,28 +418,33 @@ static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
|
|||||||
hw_as = *as;
|
hw_as = *as;
|
||||||
}
|
}
|
||||||
|
|
||||||
sw = g_new0(SW, 1);
|
sw = audio_calloc(__func__, 1, sizeof(*sw));
|
||||||
|
if (!sw) {
|
||||||
|
dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
|
||||||
|
sw_name ? sw_name : "unknown", sizeof (*sw));
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
sw->s = s;
|
sw->s = s;
|
||||||
|
|
||||||
hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
|
hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
|
||||||
if (!hw) {
|
if (!hw) {
|
||||||
dolog("Could not create a backend for voice `%s'\n", sw_name);
|
goto err2;
|
||||||
goto err1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
|
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
|
||||||
|
|
||||||
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
|
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
|
||||||
goto err2;
|
goto err3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sw;
|
return sw;
|
||||||
|
|
||||||
err2:
|
err3:
|
||||||
glue (audio_pcm_hw_del_sw_, TYPE) (sw);
|
glue (audio_pcm_hw_del_sw_, TYPE) (sw);
|
||||||
glue (audio_pcm_hw_gc_, TYPE) (&hw);
|
glue (audio_pcm_hw_gc_, TYPE) (&hw);
|
||||||
|
err2:
|
||||||
|
g_free (sw);
|
||||||
err1:
|
err1:
|
||||||
g_free(sw);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,8 +515,8 @@ SW *glue (AUD_open_, TYPE) (
|
|||||||
HW *hw = sw->hw;
|
HW *hw = sw->hw;
|
||||||
|
|
||||||
if (!hw) {
|
if (!hw) {
|
||||||
dolog("Internal logic error: voice `%s' has no backend\n",
|
dolog ("Internal logic error voice `%s' has no hardware store\n",
|
||||||
SW_NAME(sw));
|
SW_NAME (sw));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,6 +527,7 @@ SW *glue (AUD_open_, TYPE) (
|
|||||||
} else {
|
} else {
|
||||||
sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
|
sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
|
||||||
if (!sw) {
|
if (!sw) {
|
||||||
|
dolog ("Failed to create voice `%s'\n", name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
|
|
||||||
typedef struct DBusAudio {
|
typedef struct DBusAudio {
|
||||||
GDBusObjectManagerServer *server;
|
GDBusObjectManagerServer *server;
|
||||||
bool p2p;
|
|
||||||
GDBusObjectSkeleton *audio;
|
GDBusObjectSkeleton *audio;
|
||||||
QemuDBusDisplay1Audio *iface;
|
QemuDBusDisplay1Audio *iface;
|
||||||
GHashTable *out_listeners;
|
GHashTable *out_listeners;
|
||||||
@@ -449,8 +448,7 @@ dbus_audio_register_listener(AudioState *s,
|
|||||||
bool out)
|
bool out)
|
||||||
{
|
{
|
||||||
DBusAudio *da = s->drv_opaque;
|
DBusAudio *da = s->drv_opaque;
|
||||||
const char *sender =
|
const char *sender = g_dbus_method_invocation_get_sender(invocation);
|
||||||
da->p2p ? "p2p" : g_dbus_method_invocation_get_sender(invocation);
|
|
||||||
g_autoptr(GDBusConnection) listener_conn = NULL;
|
g_autoptr(GDBusConnection) listener_conn = NULL;
|
||||||
g_autoptr(GError) err = NULL;
|
g_autoptr(GError) err = NULL;
|
||||||
g_autoptr(GSocket) socket = NULL;
|
g_autoptr(GSocket) socket = NULL;
|
||||||
@@ -593,7 +591,7 @@ dbus_audio_register_in_listener(AudioState *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
|
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server)
|
||||||
{
|
{
|
||||||
DBusAudio *da = s->drv_opaque;
|
DBusAudio *da = s->drv_opaque;
|
||||||
|
|
||||||
@@ -601,7 +599,6 @@ dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
|
|||||||
g_assert(!da->server);
|
g_assert(!da->server);
|
||||||
|
|
||||||
da->server = g_object_ref(server);
|
da->server = g_object_ref(server);
|
||||||
da->p2p = p2p;
|
|
||||||
|
|
||||||
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
|
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
|
||||||
da->iface = qemu_dbus_display1_audio_skeleton_new();
|
da->iface = qemu_dbus_display1_audio_skeleton_new();
|
||||||
|
|||||||
@@ -414,7 +414,12 @@ struct rate {
|
|||||||
*/
|
*/
|
||||||
void *st_rate_start (int inrate, int outrate)
|
void *st_rate_start (int inrate, int outrate)
|
||||||
{
|
{
|
||||||
struct rate *rate = g_new0(struct rate, 1);
|
struct rate *rate = audio_calloc(__func__, 1, sizeof(*rate));
|
||||||
|
|
||||||
|
if (!rate) {
|
||||||
|
dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
rate->opos = 0;
|
rate->opos = 0;
|
||||||
|
|
||||||
@@ -440,86 +445,6 @@ void st_rate_stop (void *opaque)
|
|||||||
g_free (opaque);
|
g_free (opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* st_rate_frames_out() - returns the number of frames the resampling code
|
|
||||||
* generates from frames_in frames
|
|
||||||
*
|
|
||||||
* @opaque: pointer to struct rate
|
|
||||||
* @frames_in: number of frames
|
|
||||||
*
|
|
||||||
* When upsampling, there may be more than one correct result. In this case,
|
|
||||||
* the function returns the maximum number of output frames the resampling
|
|
||||||
* code can generate.
|
|
||||||
*/
|
|
||||||
uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in)
|
|
||||||
{
|
|
||||||
struct rate *rate = opaque;
|
|
||||||
uint64_t opos_end, opos_delta;
|
|
||||||
uint32_t ipos_end;
|
|
||||||
uint32_t frames_out;
|
|
||||||
|
|
||||||
if (rate->opos_inc == 1ULL << 32) {
|
|
||||||
return frames_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* no output frame without at least one input frame */
|
|
||||||
if (!frames_in) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* last frame read was at rate->ipos - 1 */
|
|
||||||
ipos_end = rate->ipos - 1 + frames_in;
|
|
||||||
opos_end = (uint64_t)ipos_end << 32;
|
|
||||||
|
|
||||||
/* last frame written was at rate->opos - rate->opos_inc */
|
|
||||||
if (opos_end + rate->opos_inc <= rate->opos) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
opos_delta = opos_end - rate->opos + rate->opos_inc;
|
|
||||||
frames_out = opos_delta / rate->opos_inc;
|
|
||||||
|
|
||||||
return opos_delta % rate->opos_inc ? frames_out : frames_out - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* st_rate_frames_in() - returns the number of frames needed to
|
|
||||||
* get frames_out frames after resampling
|
|
||||||
*
|
|
||||||
* @opaque: pointer to struct rate
|
|
||||||
* @frames_out: number of frames
|
|
||||||
*
|
|
||||||
* When downsampling, there may be more than one correct result. In this
|
|
||||||
* case, the function returns the maximum number of input frames needed.
|
|
||||||
*/
|
|
||||||
uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out)
|
|
||||||
{
|
|
||||||
struct rate *rate = opaque;
|
|
||||||
uint64_t opos_start, opos_end;
|
|
||||||
uint32_t ipos_start, ipos_end;
|
|
||||||
|
|
||||||
if (rate->opos_inc == 1ULL << 32) {
|
|
||||||
return frames_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frames_out) {
|
|
||||||
opos_start = rate->opos;
|
|
||||||
ipos_start = rate->ipos;
|
|
||||||
} else {
|
|
||||||
uint64_t offset;
|
|
||||||
|
|
||||||
/* add offset = ceil(opos_inc) to opos and ipos to avoid an underflow */
|
|
||||||
offset = (rate->opos_inc + (1ULL << 32) - 1) & ~((1ULL << 32) - 1);
|
|
||||||
opos_start = rate->opos + offset;
|
|
||||||
ipos_start = rate->ipos + (offset >> 32);
|
|
||||||
}
|
|
||||||
/* last frame written was at opos_start - rate->opos_inc */
|
|
||||||
opos_end = opos_start - rate->opos_inc + rate->opos_inc * frames_out;
|
|
||||||
ipos_end = (opos_end >> 32) + 1;
|
|
||||||
|
|
||||||
/* last frame read was at ipos_start - 1 */
|
|
||||||
return ipos_end + 1 > ipos_start ? ipos_end + 1 - ipos_start : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mixeng_clear (struct st_sample *buf, int len)
|
void mixeng_clear (struct st_sample *buf, int len)
|
||||||
{
|
{
|
||||||
memset (buf, 0, len * sizeof (struct st_sample));
|
memset (buf, 0, len * sizeof (struct st_sample));
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
|||||||
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
|
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||||
size_t *isamp, size_t *osamp);
|
size_t *isamp, size_t *osamp);
|
||||||
void st_rate_stop (void *opaque);
|
void st_rate_stop (void *opaque);
|
||||||
uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in);
|
|
||||||
uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out);
|
|
||||||
void mixeng_clear (struct st_sample *buf, int len);
|
void mixeng_clear (struct st_sample *buf, int len);
|
||||||
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
|
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
|||||||
int64_t t;
|
int64_t t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ilast = rate->ilast;
|
||||||
|
|
||||||
istart = ibuf;
|
istart = ibuf;
|
||||||
iend = ibuf + *isamp;
|
iend = ibuf + *isamp;
|
||||||
|
|
||||||
@@ -57,17 +59,15 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* without input samples, there's nothing to do */
|
while (obuf < oend) {
|
||||||
if (ibuf >= iend) {
|
|
||||||
*osamp = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ilast = rate->ilast;
|
/* Safety catch to make sure we have input samples. */
|
||||||
|
if (ibuf >= iend) {
|
||||||
while (true) {
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* read as many input samples so that ipos > opos */
|
/* read as many input samples so that ipos > opos */
|
||||||
|
|
||||||
while (rate->ipos <= (rate->opos >> 32)) {
|
while (rate->ipos <= (rate->opos >> 32)) {
|
||||||
ilast = *ibuf++;
|
ilast = *ibuf++;
|
||||||
rate->ipos++;
|
rate->ipos++;
|
||||||
@@ -78,11 +78,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure that the next output sample can be written */
|
|
||||||
if (obuf >= oend) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
icur = *ibuf;
|
icur = *ibuf;
|
||||||
|
|
||||||
/* wrap ipos and opos around long before they overflow */
|
/* wrap ipos and opos around long before they overflow */
|
||||||
|
|||||||
@@ -59,19 +59,6 @@ struct CryptoDevBackendBuiltin {
|
|||||||
CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
|
CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cryptodev_builtin_init_akcipher(CryptoDevBackend *backend)
|
|
||||||
{
|
|
||||||
QCryptoAkCipherOptions opts;
|
|
||||||
|
|
||||||
opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
|
|
||||||
opts.u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
|
|
||||||
if (qcrypto_akcipher_supports(&opts)) {
|
|
||||||
backend->conf.crypto_services |=
|
|
||||||
(1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER);
|
|
||||||
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_builtin_init(
|
static void cryptodev_builtin_init(
|
||||||
CryptoDevBackend *backend, Error **errp)
|
CryptoDevBackend *backend, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -85,18 +72,21 @@ static void cryptodev_builtin_init(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc = cryptodev_backend_new_client();
|
cc = cryptodev_backend_new_client(
|
||||||
|
"cryptodev-builtin", NULL);
|
||||||
cc->info_str = g_strdup_printf("cryptodev-builtin0");
|
cc->info_str = g_strdup_printf("cryptodev-builtin0");
|
||||||
cc->queue_index = 0;
|
cc->queue_index = 0;
|
||||||
cc->type = QCRYPTODEV_BACKEND_TYPE_BUILTIN;
|
cc->type = CRYPTODEV_BACKEND_TYPE_BUILTIN;
|
||||||
backend->conf.peers.ccs[0] = cc;
|
backend->conf.peers.ccs[0] = cc;
|
||||||
|
|
||||||
backend->conf.crypto_services =
|
backend->conf.crypto_services =
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
|
1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
|
1u << VIRTIO_CRYPTO_SERVICE_HASH |
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
|
1u << VIRTIO_CRYPTO_SERVICE_MAC |
|
||||||
|
1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
|
||||||
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
||||||
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
||||||
|
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
|
||||||
/*
|
/*
|
||||||
* Set the Maximum length of crypto request.
|
* Set the Maximum length of crypto request.
|
||||||
* Why this value? Just avoid to overflow when
|
* Why this value? Just avoid to overflow when
|
||||||
@@ -105,7 +95,6 @@ static void cryptodev_builtin_init(
|
|||||||
backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
|
backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
|
||||||
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
|
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
|
||||||
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
|
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
|
||||||
cryptodev_builtin_init_akcipher(backend);
|
|
||||||
|
|
||||||
cryptodev_backend_set_ready(backend, true);
|
cryptodev_backend_set_ready(backend, true);
|
||||||
}
|
}
|
||||||
@@ -539,14 +528,17 @@ static int cryptodev_builtin_asym_operation(
|
|||||||
|
|
||||||
static int cryptodev_builtin_operation(
|
static int cryptodev_builtin_operation(
|
||||||
CryptoDevBackend *backend,
|
CryptoDevBackend *backend,
|
||||||
CryptoDevBackendOpInfo *op_info)
|
CryptoDevBackendOpInfo *op_info,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb,
|
||||||
|
void *opaque)
|
||||||
{
|
{
|
||||||
CryptoDevBackendBuiltin *builtin =
|
CryptoDevBackendBuiltin *builtin =
|
||||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||||
CryptoDevBackendBuiltinSession *sess;
|
CryptoDevBackendBuiltinSession *sess;
|
||||||
CryptoDevBackendSymOpInfo *sym_op_info;
|
CryptoDevBackendSymOpInfo *sym_op_info;
|
||||||
CryptoDevBackendAsymOpInfo *asym_op_info;
|
CryptoDevBackendAsymOpInfo *asym_op_info;
|
||||||
QCryptodevBackendAlgType algtype = op_info->algtype;
|
enum CryptoDevBackendAlgType algtype = op_info->algtype;
|
||||||
int status = -VIRTIO_CRYPTO_ERR;
|
int status = -VIRTIO_CRYPTO_ERR;
|
||||||
Error *local_error = NULL;
|
Error *local_error = NULL;
|
||||||
|
|
||||||
@@ -558,11 +550,11 @@ static int cryptodev_builtin_operation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sess = builtin->sessions[op_info->session_id];
|
sess = builtin->sessions[op_info->session_id];
|
||||||
if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
|
if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
|
||||||
sym_op_info = op_info->u.sym_op_info;
|
sym_op_info = op_info->u.sym_op_info;
|
||||||
status = cryptodev_builtin_sym_operation(sess, sym_op_info,
|
status = cryptodev_builtin_sym_operation(sess, sym_op_info,
|
||||||
&local_error);
|
&local_error);
|
||||||
} else if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
|
} else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
|
||||||
asym_op_info = op_info->u.asym_op_info;
|
asym_op_info = op_info->u.asym_op_info;
|
||||||
status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
|
status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
|
||||||
asym_op_info, &local_error);
|
asym_op_info, &local_error);
|
||||||
@@ -571,8 +563,8 @@ static int cryptodev_builtin_operation(
|
|||||||
if (local_error) {
|
if (local_error) {
|
||||||
error_report_err(local_error);
|
error_report_err(local_error);
|
||||||
}
|
}
|
||||||
if (op_info->cb) {
|
if (cb) {
|
||||||
op_info->cb(op_info->opaque, status);
|
cb(opaque, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* HMP commands related to cryptodev
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Bytedance.Inc
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* zhenwei pi<pizhenwei@bytedance.com>
|
|
||||||
*
|
|
||||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include "monitor/hmp.h"
|
|
||||||
#include "monitor/monitor.h"
|
|
||||||
#include "qapi/qapi-commands-cryptodev.h"
|
|
||||||
#include "qapi/qmp/qdict.h"
|
|
||||||
|
|
||||||
|
|
||||||
void hmp_info_cryptodev(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
QCryptodevInfoList *il;
|
|
||||||
QCryptodevBackendServiceTypeList *sl;
|
|
||||||
QCryptodevBackendClientList *cl;
|
|
||||||
|
|
||||||
for (il = qmp_query_cryptodev(NULL); il; il = il->next) {
|
|
||||||
g_autofree char *services = NULL;
|
|
||||||
QCryptodevInfo *info = il->value;
|
|
||||||
char *tmp_services;
|
|
||||||
|
|
||||||
/* build a string like 'service=[akcipher|mac|hash|cipher]' */
|
|
||||||
for (sl = info->service; sl; sl = sl->next) {
|
|
||||||
const char *service = QCryptodevBackendServiceType_str(sl->value);
|
|
||||||
|
|
||||||
if (!services) {
|
|
||||||
services = g_strdup(service);
|
|
||||||
} else {
|
|
||||||
tmp_services = g_strjoin("|", services, service, NULL);
|
|
||||||
g_free(services);
|
|
||||||
services = tmp_services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
monitor_printf(mon, "%s: service=[%s]\n", info->id, services);
|
|
||||||
|
|
||||||
for (cl = info->client; cl; cl = cl->next) {
|
|
||||||
QCryptodevBackendClient *client = cl->value;
|
|
||||||
monitor_printf(mon, " queue %" PRIu32 ": type=%s\n",
|
|
||||||
client->queue,
|
|
||||||
QCryptodevBackendType_str(client->type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qapi_free_QCryptodevInfoList(il);
|
|
||||||
}
|
|
||||||
@@ -223,14 +223,14 @@ static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc = cryptodev_backend_new_client();
|
cc = cryptodev_backend_new_client("cryptodev-lkcf", NULL);
|
||||||
cc->info_str = g_strdup_printf("cryptodev-lkcf0");
|
cc->info_str = g_strdup_printf("cryptodev-lkcf0");
|
||||||
cc->queue_index = 0;
|
cc->queue_index = 0;
|
||||||
cc->type = QCRYPTODEV_BACKEND_TYPE_LKCF;
|
cc->type = CRYPTODEV_BACKEND_TYPE_LKCF;
|
||||||
backend->conf.peers.ccs[0] = cc;
|
backend->conf.peers.ccs[0] = cc;
|
||||||
|
|
||||||
backend->conf.crypto_services =
|
backend->conf.crypto_services =
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER;
|
1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
|
||||||
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
|
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
|
||||||
lkcf->running = true;
|
lkcf->running = true;
|
||||||
|
|
||||||
@@ -469,12 +469,15 @@ static void *cryptodev_lkcf_worker(void *arg)
|
|||||||
|
|
||||||
static int cryptodev_lkcf_operation(
|
static int cryptodev_lkcf_operation(
|
||||||
CryptoDevBackend *backend,
|
CryptoDevBackend *backend,
|
||||||
CryptoDevBackendOpInfo *op_info)
|
CryptoDevBackendOpInfo *op_info,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb,
|
||||||
|
void *opaque)
|
||||||
{
|
{
|
||||||
CryptoDevBackendLKCF *lkcf =
|
CryptoDevBackendLKCF *lkcf =
|
||||||
CRYPTODEV_BACKEND_LKCF(backend);
|
CRYPTODEV_BACKEND_LKCF(backend);
|
||||||
CryptoDevBackendLKCFSession *sess;
|
CryptoDevBackendLKCFSession *sess;
|
||||||
QCryptodevBackendAlgType algtype = op_info->algtype;
|
enum CryptoDevBackendAlgType algtype = op_info->algtype;
|
||||||
CryptoDevLKCFTask *task;
|
CryptoDevLKCFTask *task;
|
||||||
|
|
||||||
if (op_info->session_id >= MAX_SESSIONS ||
|
if (op_info->session_id >= MAX_SESSIONS ||
|
||||||
@@ -485,15 +488,15 @@ static int cryptodev_lkcf_operation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sess = lkcf->sess[op_info->session_id];
|
sess = lkcf->sess[op_info->session_id];
|
||||||
if (algtype != QCRYPTODEV_BACKEND_ALG_ASYM) {
|
if (algtype != CRYPTODEV_BACKEND_ALG_ASYM) {
|
||||||
error_report("algtype not supported: %u", algtype);
|
error_report("algtype not supported: %u", algtype);
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = g_new0(CryptoDevLKCFTask, 1);
|
task = g_new0(CryptoDevLKCFTask, 1);
|
||||||
task->op_info = op_info;
|
task->op_info = op_info;
|
||||||
task->cb = op_info->cb;
|
task->cb = cb;
|
||||||
task->opaque = op_info->opaque;
|
task->opaque = opaque;
|
||||||
task->sess = sess;
|
task->sess = sess;
|
||||||
task->lkcf = lkcf;
|
task->lkcf = lkcf;
|
||||||
task->status = -VIRTIO_CRYPTO_ERR;
|
task->status = -VIRTIO_CRYPTO_ERR;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ cryptodev_vhost_user_get_vhost(
|
|||||||
{
|
{
|
||||||
CryptoDevBackendVhostUser *s =
|
CryptoDevBackendVhostUser *s =
|
||||||
CRYPTODEV_BACKEND_VHOST_USER(b);
|
CRYPTODEV_BACKEND_VHOST_USER(b);
|
||||||
assert(cc->type == QCRYPTODEV_BACKEND_TYPE_VHOST_USER);
|
assert(cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER);
|
||||||
assert(queue < MAX_CRYPTO_QUEUE_NUM);
|
assert(queue < MAX_CRYPTO_QUEUE_NUM);
|
||||||
|
|
||||||
return s->vhost_crypto[queue];
|
return s->vhost_crypto[queue];
|
||||||
@@ -198,11 +198,12 @@ static void cryptodev_vhost_user_init(
|
|||||||
s->opened = true;
|
s->opened = true;
|
||||||
|
|
||||||
for (i = 0; i < queues; i++) {
|
for (i = 0; i < queues; i++) {
|
||||||
cc = cryptodev_backend_new_client();
|
cc = cryptodev_backend_new_client(
|
||||||
|
"cryptodev-vhost-user", NULL);
|
||||||
cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
|
cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
|
||||||
i, chr->label);
|
i, chr->label);
|
||||||
cc->queue_index = i;
|
cc->queue_index = i;
|
||||||
cc->type = QCRYPTODEV_BACKEND_TYPE_VHOST_USER;
|
cc->type = CRYPTODEV_BACKEND_TYPE_VHOST_USER;
|
||||||
|
|
||||||
backend->conf.peers.ccs[i] = cc;
|
backend->conf.peers.ccs[i] = cc;
|
||||||
|
|
||||||
@@ -221,9 +222,9 @@ static void cryptodev_vhost_user_init(
|
|||||||
cryptodev_vhost_user_event, NULL, s, NULL, true);
|
cryptodev_vhost_user_event, NULL, s, NULL, true);
|
||||||
|
|
||||||
backend->conf.crypto_services =
|
backend->conf.crypto_services =
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
|
1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
|
1u << VIRTIO_CRYPTO_SERVICE_HASH |
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
|
1u << VIRTIO_CRYPTO_SERVICE_MAC;
|
||||||
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
||||||
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ cryptodev_get_vhost(CryptoDevBackendClient *cc,
|
|||||||
|
|
||||||
switch (cc->type) {
|
switch (cc->type) {
|
||||||
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
||||||
case QCRYPTODEV_BACKEND_TYPE_VHOST_USER:
|
case CRYPTODEV_BACKEND_TYPE_VHOST_USER:
|
||||||
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, b, queue);
|
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, b, queue);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@@ -195,7 +195,7 @@ int cryptodev_vhost_start(VirtIODevice *dev, int total_queues)
|
|||||||
* because vhost user doesn't interrupt masking/unmasking
|
* because vhost user doesn't interrupt masking/unmasking
|
||||||
* properly.
|
* properly.
|
||||||
*/
|
*/
|
||||||
if (cc->type == QCRYPTODEV_BACKEND_TYPE_VHOST_USER) {
|
if (cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER) {
|
||||||
dev->use_guest_notifier_mask = false;
|
dev->use_guest_notifier_mask = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,92 +23,29 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sysemu/cryptodev.h"
|
#include "sysemu/cryptodev.h"
|
||||||
#include "sysemu/stats.h"
|
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qapi/qapi-commands-cryptodev.h"
|
|
||||||
#include "qapi/qapi-types-stats.h"
|
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/main-loop.h"
|
|
||||||
#include "qom/object_interfaces.h"
|
#include "qom/object_interfaces.h"
|
||||||
#include "hw/virtio/virtio-crypto.h"
|
#include "hw/virtio/virtio-crypto.h"
|
||||||
|
|
||||||
#define SYM_ENCRYPT_OPS_STR "sym-encrypt-ops"
|
|
||||||
#define SYM_DECRYPT_OPS_STR "sym-decrypt-ops"
|
|
||||||
#define SYM_ENCRYPT_BYTES_STR "sym-encrypt-bytes"
|
|
||||||
#define SYM_DECRYPT_BYTES_STR "sym-decrypt-bytes"
|
|
||||||
|
|
||||||
#define ASYM_ENCRYPT_OPS_STR "asym-encrypt-ops"
|
|
||||||
#define ASYM_DECRYPT_OPS_STR "asym-decrypt-ops"
|
|
||||||
#define ASYM_SIGN_OPS_STR "asym-sign-ops"
|
|
||||||
#define ASYM_VERIFY_OPS_STR "asym-verify-ops"
|
|
||||||
#define ASYM_ENCRYPT_BYTES_STR "asym-encrypt-bytes"
|
|
||||||
#define ASYM_DECRYPT_BYTES_STR "asym-decrypt-bytes"
|
|
||||||
#define ASYM_SIGN_BYTES_STR "asym-sign-bytes"
|
|
||||||
#define ASYM_VERIFY_BYTES_STR "asym-verify-bytes"
|
|
||||||
|
|
||||||
typedef struct StatsArgs {
|
|
||||||
union StatsResultsType {
|
|
||||||
StatsResultList **stats;
|
|
||||||
StatsSchemaList **schema;
|
|
||||||
} result;
|
|
||||||
strList *names;
|
|
||||||
Error **errp;
|
|
||||||
} StatsArgs;
|
|
||||||
|
|
||||||
static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
|
static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
|
||||||
|
|
||||||
static int qmp_query_cryptodev_foreach(Object *obj, void *data)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend;
|
|
||||||
QCryptodevInfoList **infolist = data;
|
|
||||||
uint32_t services, i;
|
|
||||||
|
|
||||||
if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
|
CryptoDevBackendClient *
|
||||||
return 0;
|
cryptodev_backend_new_client(const char *model,
|
||||||
}
|
const char *name)
|
||||||
|
|
||||||
QCryptodevInfo *info = g_new0(QCryptodevInfo, 1);
|
|
||||||
info->id = g_strdup(object_get_canonical_path_component(obj));
|
|
||||||
|
|
||||||
backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
services = backend->conf.crypto_services;
|
|
||||||
for (i = 0; i < QCRYPTODEV_BACKEND_SERVICE__MAX; i++) {
|
|
||||||
if (services & (1 << i)) {
|
|
||||||
QAPI_LIST_PREPEND(info->service, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < backend->conf.peers.queues; i++) {
|
|
||||||
CryptoDevBackendClient *cc = backend->conf.peers.ccs[i];
|
|
||||||
QCryptodevBackendClient *client = g_new0(QCryptodevBackendClient, 1);
|
|
||||||
|
|
||||||
client->queue = cc->queue_index;
|
|
||||||
client->type = cc->type;
|
|
||||||
QAPI_LIST_PREPEND(info->client, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
QAPI_LIST_PREPEND(*infolist, info);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCryptodevInfoList *qmp_query_cryptodev(Error **errp)
|
|
||||||
{
|
|
||||||
QCryptodevInfoList *list = NULL;
|
|
||||||
Object *objs = container_get(object_get_root(), "/objects");
|
|
||||||
|
|
||||||
object_child_foreach(objs, qmp_query_cryptodev_foreach, &list);
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
CryptoDevBackendClient *cryptodev_backend_new_client(void)
|
|
||||||
{
|
{
|
||||||
CryptoDevBackendClient *cc;
|
CryptoDevBackendClient *cc;
|
||||||
|
|
||||||
cc = g_new0(CryptoDevBackendClient, 1);
|
cc = g_new0(CryptoDevBackendClient, 1);
|
||||||
|
cc->model = g_strdup(model);
|
||||||
|
if (name) {
|
||||||
|
cc->name = g_strdup(name);
|
||||||
|
}
|
||||||
|
|
||||||
QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
|
QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
|
||||||
|
|
||||||
return cc;
|
return cc;
|
||||||
@@ -118,6 +55,8 @@ void cryptodev_backend_free_client(
|
|||||||
CryptoDevBackendClient *cc)
|
CryptoDevBackendClient *cc)
|
||||||
{
|
{
|
||||||
QTAILQ_REMOVE(&crypto_clients, cc, next);
|
QTAILQ_REMOVE(&crypto_clients, cc, next);
|
||||||
|
g_free(cc->name);
|
||||||
|
g_free(cc->model);
|
||||||
g_free(cc->info_str);
|
g_free(cc->info_str);
|
||||||
g_free(cc);
|
g_free(cc);
|
||||||
}
|
}
|
||||||
@@ -132,9 +71,6 @@ void cryptodev_backend_cleanup(
|
|||||||
if (bc->cleanup) {
|
if (bc->cleanup) {
|
||||||
bc->cleanup(backend, errp);
|
bc->cleanup(backend, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(backend->sym_stat);
|
|
||||||
g_free(backend->asym_stat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cryptodev_backend_create_session(
|
int cryptodev_backend_create_session(
|
||||||
@@ -171,111 +107,38 @@ int cryptodev_backend_close_session(
|
|||||||
|
|
||||||
static int cryptodev_backend_operation(
|
static int cryptodev_backend_operation(
|
||||||
CryptoDevBackend *backend,
|
CryptoDevBackend *backend,
|
||||||
CryptoDevBackendOpInfo *op_info)
|
CryptoDevBackendOpInfo *op_info,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb,
|
||||||
|
void *opaque)
|
||||||
{
|
{
|
||||||
CryptoDevBackendClass *bc =
|
CryptoDevBackendClass *bc =
|
||||||
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
||||||
|
|
||||||
if (bc->do_op) {
|
if (bc->do_op) {
|
||||||
return bc->do_op(backend, op_info);
|
return bc->do_op(backend, op_info, queue_index, cb, opaque);
|
||||||
}
|
}
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cryptodev_backend_account(CryptoDevBackend *backend,
|
int cryptodev_backend_crypto_operation(
|
||||||
CryptoDevBackendOpInfo *op_info)
|
CryptoDevBackend *backend,
|
||||||
|
void *opaque1,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb, void *opaque2)
|
||||||
{
|
{
|
||||||
enum QCryptodevBackendAlgType algtype = op_info->algtype;
|
VirtIOCryptoReq *req = opaque1;
|
||||||
int len;
|
CryptoDevBackendOpInfo *op_info = &req->op_info;
|
||||||
|
enum CryptoDevBackendAlgType algtype = req->flags;
|
||||||
|
|
||||||
if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
|
if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
|
||||||
CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
|
&& (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
|
||||||
len = asym_op_info->src_len;
|
|
||||||
switch (op_info->op_code) {
|
|
||||||
case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
|
|
||||||
CryptodevAsymStatIncEncrypt(backend, len);
|
|
||||||
break;
|
|
||||||
case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
|
|
||||||
CryptodevAsymStatIncDecrypt(backend, len);
|
|
||||||
break;
|
|
||||||
case VIRTIO_CRYPTO_AKCIPHER_SIGN:
|
|
||||||
CryptodevAsymStatIncSign(backend, len);
|
|
||||||
break;
|
|
||||||
case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
|
|
||||||
CryptodevAsymStatIncVerify(backend, len);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
||||||
}
|
|
||||||
} else if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
|
|
||||||
CryptoDevBackendSymOpInfo *sym_op_info = op_info->u.sym_op_info;
|
|
||||||
len = sym_op_info->src_len;
|
|
||||||
switch (op_info->op_code) {
|
|
||||||
case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
|
|
||||||
CryptodevSymStatIncEncrypt(backend, len);
|
|
||||||
break;
|
|
||||||
case VIRTIO_CRYPTO_CIPHER_DECRYPT:
|
|
||||||
CryptodevSymStatIncDecrypt(backend, len);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
|
error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return cryptodev_backend_operation(backend, op_info, queue_index,
|
||||||
}
|
cb, opaque2);
|
||||||
|
|
||||||
static void cryptodev_backend_throttle_timer_cb(void *opaque)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = (CryptoDevBackend *)opaque;
|
|
||||||
CryptoDevBackendOpInfo *op_info, *tmpop;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(op_info, &backend->opinfos, next, tmpop) {
|
|
||||||
QTAILQ_REMOVE(&backend->opinfos, op_info, next);
|
|
||||||
ret = cryptodev_backend_account(backend, op_info);
|
|
||||||
if (ret < 0) {
|
|
||||||
op_info->cb(op_info->opaque, ret);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
throttle_account(&backend->ts, true, ret);
|
|
||||||
cryptodev_backend_operation(backend, op_info);
|
|
||||||
if (throttle_enabled(&backend->tc) &&
|
|
||||||
throttle_schedule_timer(&backend->ts, &backend->tt, true)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cryptodev_backend_crypto_operation(
|
|
||||||
CryptoDevBackend *backend,
|
|
||||||
CryptoDevBackendOpInfo *op_info)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!throttle_enabled(&backend->tc)) {
|
|
||||||
goto do_account;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (throttle_schedule_timer(&backend->ts, &backend->tt, true) ||
|
|
||||||
!QTAILQ_EMPTY(&backend->opinfos)) {
|
|
||||||
QTAILQ_INSERT_TAIL(&backend->opinfos, op_info, next);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_account:
|
|
||||||
ret = cryptodev_backend_account(backend, op_info);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
throttle_account(&backend->ts, true, ret);
|
|
||||||
|
|
||||||
return cryptodev_backend_operation(backend, op_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -306,111 +169,15 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
|
|||||||
backend->conf.peers.queues = value;
|
backend->conf.peers.queues = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cryptodev_backend_set_throttle(CryptoDevBackend *backend, int field,
|
|
||||||
uint64_t value, Error **errp)
|
|
||||||
{
|
|
||||||
uint64_t orig = backend->tc.buckets[field].avg;
|
|
||||||
bool enabled = throttle_enabled(&backend->tc);
|
|
||||||
|
|
||||||
if (orig == value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
backend->tc.buckets[field].avg = value;
|
|
||||||
if (!throttle_enabled(&backend->tc)) {
|
|
||||||
throttle_timers_destroy(&backend->tt);
|
|
||||||
cryptodev_backend_throttle_timer_cb(backend); /* drain opinfos */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!throttle_is_valid(&backend->tc, errp)) {
|
|
||||||
backend->tc.buckets[field].avg = orig; /* revert change */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!enabled) {
|
|
||||||
throttle_init(&backend->ts);
|
|
||||||
throttle_timers_init(&backend->tt, qemu_get_aio_context(),
|
|
||||||
QEMU_CLOCK_REALTIME,
|
|
||||||
cryptodev_backend_throttle_timer_cb, /* FIXME */
|
|
||||||
cryptodev_backend_throttle_timer_cb, backend);
|
|
||||||
}
|
|
||||||
|
|
||||||
throttle_config(&backend->ts, QEMU_CLOCK_REALTIME, &backend->tc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_get_bps(Object *obj, Visitor *v,
|
|
||||||
const char *name, void *opaque,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
uint64_t value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
|
|
||||||
|
|
||||||
visit_type_uint64(v, name, &value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_set_bps(Object *obj, Visitor *v, const char *name,
|
|
||||||
void *opaque, Error **errp)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
uint64_t value;
|
|
||||||
|
|
||||||
if (!visit_type_uint64(v, name, &value, errp)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_get_ops(Object *obj, Visitor *v, const char *name,
|
|
||||||
void *opaque, Error **errp)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
uint64_t value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
|
|
||||||
|
|
||||||
visit_type_uint64(v, name, &value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_set_ops(Object *obj, Visitor *v,
|
|
||||||
const char *name, void *opaque,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
uint64_t value;
|
|
||||||
|
|
||||||
if (!visit_type_uint64(v, name, &value, errp)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
||||||
{
|
{
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
||||||
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
||||||
uint32_t services;
|
|
||||||
uint64_t value;
|
|
||||||
|
|
||||||
QTAILQ_INIT(&backend->opinfos);
|
|
||||||
value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
|
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
|
|
||||||
value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
|
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
|
|
||||||
|
|
||||||
if (bc->init) {
|
if (bc->init) {
|
||||||
bc->init(backend, errp);
|
bc->init(backend, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
services = backend->conf.crypto_services;
|
|
||||||
if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
|
|
||||||
backend->sym_stat = g_new0(CryptodevBackendSymStat, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
|
|
||||||
backend->asym_stat = g_new0(CryptodevBackendAsymStat, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
||||||
@@ -441,12 +208,8 @@ cryptodev_backend_can_be_deleted(UserCreatable *uc)
|
|||||||
|
|
||||||
static void cryptodev_backend_instance_init(Object *obj)
|
static void cryptodev_backend_instance_init(Object *obj)
|
||||||
{
|
{
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
|
|
||||||
/* Initialize devices' queues property to 1 */
|
/* Initialize devices' queues property to 1 */
|
||||||
object_property_set_int(obj, "queues", 1, NULL);
|
object_property_set_int(obj, "queues", 1, NULL);
|
||||||
|
|
||||||
throttle_config_init(&backend->tc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cryptodev_backend_finalize(Object *obj)
|
static void cryptodev_backend_finalize(Object *obj)
|
||||||
@@ -454,137 +217,6 @@ static void cryptodev_backend_finalize(Object *obj)
|
|||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
||||||
|
|
||||||
cryptodev_backend_cleanup(backend, NULL);
|
cryptodev_backend_cleanup(backend, NULL);
|
||||||
if (throttle_enabled(&backend->tc)) {
|
|
||||||
throttle_timers_destroy(&backend->tt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static StatsList *cryptodev_backend_stats_add(const char *name, int64_t *val,
|
|
||||||
StatsList *stats_list)
|
|
||||||
{
|
|
||||||
Stats *stats = g_new0(Stats, 1);
|
|
||||||
|
|
||||||
stats->name = g_strdup(name);
|
|
||||||
stats->value = g_new0(StatsValue, 1);
|
|
||||||
stats->value->type = QTYPE_QNUM;
|
|
||||||
stats->value->u.scalar = *val;
|
|
||||||
|
|
||||||
QAPI_LIST_PREPEND(stats_list, stats);
|
|
||||||
return stats_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cryptodev_backend_stats_query(Object *obj, void *data)
|
|
||||||
{
|
|
||||||
StatsArgs *stats_args = data;
|
|
||||||
StatsResultList **stats_results = stats_args->result.stats;
|
|
||||||
StatsList *stats_list = NULL;
|
|
||||||
StatsResult *entry;
|
|
||||||
CryptoDevBackend *backend;
|
|
||||||
CryptodevBackendSymStat *sym_stat;
|
|
||||||
CryptodevBackendAsymStat *asym_stat;
|
|
||||||
|
|
||||||
if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
sym_stat = backend->sym_stat;
|
|
||||||
if (sym_stat) {
|
|
||||||
stats_list = cryptodev_backend_stats_add(SYM_ENCRYPT_OPS_STR,
|
|
||||||
&sym_stat->encrypt_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(SYM_DECRYPT_OPS_STR,
|
|
||||||
&sym_stat->decrypt_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(SYM_ENCRYPT_BYTES_STR,
|
|
||||||
&sym_stat->encrypt_bytes, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(SYM_DECRYPT_BYTES_STR,
|
|
||||||
&sym_stat->decrypt_bytes, stats_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
asym_stat = backend->asym_stat;
|
|
||||||
if (asym_stat) {
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_ENCRYPT_OPS_STR,
|
|
||||||
&asym_stat->encrypt_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_DECRYPT_OPS_STR,
|
|
||||||
&asym_stat->decrypt_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_SIGN_OPS_STR,
|
|
||||||
&asym_stat->sign_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_VERIFY_OPS_STR,
|
|
||||||
&asym_stat->verify_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_ENCRYPT_BYTES_STR,
|
|
||||||
&asym_stat->encrypt_bytes, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_DECRYPT_BYTES_STR,
|
|
||||||
&asym_stat->decrypt_bytes, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_SIGN_BYTES_STR,
|
|
||||||
&asym_stat->sign_bytes, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_VERIFY_BYTES_STR,
|
|
||||||
&asym_stat->verify_bytes, stats_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = g_new0(StatsResult, 1);
|
|
||||||
entry->provider = STATS_PROVIDER_CRYPTODEV;
|
|
||||||
entry->qom_path = g_strdup(object_get_canonical_path(obj));
|
|
||||||
entry->stats = stats_list;
|
|
||||||
QAPI_LIST_PREPEND(*stats_results, entry);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_stats_cb(StatsResultList **result,
|
|
||||||
StatsTarget target,
|
|
||||||
strList *names, strList *targets,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
switch (target) {
|
|
||||||
case STATS_TARGET_CRYPTODEV:
|
|
||||||
{
|
|
||||||
Object *objs = container_get(object_get_root(), "/objects");
|
|
||||||
StatsArgs stats_args;
|
|
||||||
stats_args.result.stats = result;
|
|
||||||
stats_args.names = names;
|
|
||||||
stats_args.errp = errp;
|
|
||||||
|
|
||||||
object_child_foreach(objs, cryptodev_backend_stats_query, &stats_args);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static StatsSchemaValueList *cryptodev_backend_schemas_add(const char *name,
|
|
||||||
StatsSchemaValueList *list)
|
|
||||||
{
|
|
||||||
StatsSchemaValueList *schema_entry = g_new0(StatsSchemaValueList, 1);
|
|
||||||
|
|
||||||
schema_entry->value = g_new0(StatsSchemaValue, 1);
|
|
||||||
schema_entry->value->type = STATS_TYPE_CUMULATIVE;
|
|
||||||
schema_entry->value->name = g_strdup(name);
|
|
||||||
schema_entry->next = list;
|
|
||||||
|
|
||||||
return schema_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_schemas_cb(StatsSchemaList **result,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
StatsSchemaValueList *stats_list = NULL;
|
|
||||||
const char *sym_stats[] = { SYM_ENCRYPT_OPS_STR, SYM_DECRYPT_OPS_STR,
|
|
||||||
SYM_ENCRYPT_BYTES_STR, SYM_DECRYPT_BYTES_STR };
|
|
||||||
const char *asym_stats[] = { ASYM_ENCRYPT_OPS_STR, ASYM_DECRYPT_OPS_STR,
|
|
||||||
ASYM_SIGN_OPS_STR, ASYM_VERIFY_OPS_STR,
|
|
||||||
ASYM_ENCRYPT_BYTES_STR, ASYM_DECRYPT_BYTES_STR,
|
|
||||||
ASYM_SIGN_BYTES_STR, ASYM_VERIFY_BYTES_STR };
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(sym_stats); i++) {
|
|
||||||
stats_list = cryptodev_backend_schemas_add(sym_stats[i], stats_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(asym_stats); i++) {
|
|
||||||
stats_list = cryptodev_backend_schemas_add(asym_stats[i], stats_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
add_stats_schema(result, STATS_PROVIDER_CRYPTODEV, STATS_TARGET_CRYPTODEV,
|
|
||||||
stats_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -600,17 +232,6 @@ cryptodev_backend_class_init(ObjectClass *oc, void *data)
|
|||||||
cryptodev_backend_get_queues,
|
cryptodev_backend_get_queues,
|
||||||
cryptodev_backend_set_queues,
|
cryptodev_backend_set_queues,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
object_class_property_add(oc, "throttle-bps", "uint64",
|
|
||||||
cryptodev_backend_get_bps,
|
|
||||||
cryptodev_backend_set_bps,
|
|
||||||
NULL, NULL);
|
|
||||||
object_class_property_add(oc, "throttle-ops", "uint64",
|
|
||||||
cryptodev_backend_get_ops,
|
|
||||||
cryptodev_backend_set_ops,
|
|
||||||
NULL, NULL);
|
|
||||||
|
|
||||||
add_stats_callbacks(STATS_PROVIDER_CRYPTODEV, cryptodev_backend_stats_cb,
|
|
||||||
cryptodev_backend_schemas_cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo cryptodev_backend_info = {
|
static const TypeInfo cryptodev_backend_info = {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
softmmu_ss.add([files(
|
softmmu_ss.add([files(
|
||||||
'cryptodev-builtin.c',
|
'cryptodev-builtin.c',
|
||||||
'cryptodev-hmp-cmds.c',
|
|
||||||
'cryptodev.c',
|
'cryptodev.c',
|
||||||
'hostmem-ram.c',
|
'hostmem-ram.c',
|
||||||
'hostmem.c',
|
'hostmem.c',
|
||||||
|
|||||||
@@ -573,13 +573,13 @@ static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
|
|||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fds[1]);
|
closesocket(fds[1]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_exit:
|
err_exit:
|
||||||
close(fds[0]);
|
closesocket(fds[0]);
|
||||||
close(fds[1]);
|
closesocket(fds[1]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
34
block.c
34
block.c
@@ -4918,7 +4918,6 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
|
|||||||
qdict_del(bs->options, "backing");
|
qdict_del(bs->options, "backing");
|
||||||
|
|
||||||
bdrv_refresh_limits(bs, NULL, NULL);
|
bdrv_refresh_limits(bs, NULL, NULL);
|
||||||
bdrv_refresh_total_sectors(bs, bs->total_sectors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -5850,7 +5849,7 @@ int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs)
|
|||||||
if (!drv)
|
if (!drv)
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
|
|
||||||
if (bs->bl.has_variable_length) {
|
if (drv->has_variable_length) {
|
||||||
int ret = bdrv_co_refresh_total_sectors(bs, bs->total_sectors);
|
int ret = bdrv_co_refresh_total_sectors(bs, bs->total_sectors);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -5859,28 +5858,6 @@ int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs)
|
|||||||
return bs->total_sectors;
|
return bs->total_sectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This wrapper is written by hand because this function is in the hot I/O path,
|
|
||||||
* via blk_get_geometry.
|
|
||||||
*/
|
|
||||||
int64_t coroutine_mixed_fn bdrv_nb_sectors(BlockDriverState *bs)
|
|
||||||
{
|
|
||||||
BlockDriver *drv = bs->drv;
|
|
||||||
IO_CODE();
|
|
||||||
|
|
||||||
if (!drv)
|
|
||||||
return -ENOMEDIUM;
|
|
||||||
|
|
||||||
if (bs->bl.has_variable_length) {
|
|
||||||
int ret = bdrv_refresh_total_sectors(bs, bs->total_sectors);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bs->total_sectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return length in bytes on success, -errno on error.
|
* Return length in bytes on success, -errno on error.
|
||||||
* The length is always a multiple of BDRV_SECTOR_SIZE.
|
* The length is always a multiple of BDRV_SECTOR_SIZE.
|
||||||
@@ -5901,6 +5878,15 @@ int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs)
|
|||||||
return ret * BDRV_SECTOR_SIZE;
|
return ret * BDRV_SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* return 0 as number of sectors if no device present or error */
|
||||||
|
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
|
||||||
|
{
|
||||||
|
int64_t nb_sectors = bdrv_nb_sectors(bs);
|
||||||
|
IO_CODE();
|
||||||
|
|
||||||
|
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
|
||||||
|
}
|
||||||
|
|
||||||
bool bdrv_is_sg(BlockDriverState *bs)
|
bool bdrv_is_sg(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
IO_CODE();
|
IO_CODE();
|
||||||
|
|||||||
@@ -1615,53 +1615,26 @@ int64_t coroutine_fn blk_co_getlength(BlockBackend *blk)
|
|||||||
return bdrv_co_getlength(blk_bs(blk));
|
return bdrv_co_getlength(blk_bs(blk));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
|
||||||
|
{
|
||||||
|
IO_CODE();
|
||||||
|
if (!blk_bs(blk)) {
|
||||||
|
*nb_sectors_ptr = 0;
|
||||||
|
} else {
|
||||||
|
bdrv_get_geometry(blk_bs(blk), nb_sectors_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk)
|
int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = blk_bs(blk);
|
|
||||||
|
|
||||||
IO_CODE();
|
IO_CODE();
|
||||||
GRAPH_RDLOCK_GUARD();
|
GRAPH_RDLOCK_GUARD();
|
||||||
|
|
||||||
if (!bs) {
|
if (!blk_co_is_available(blk)) {
|
||||||
return -ENOMEDIUM;
|
return -ENOMEDIUM;
|
||||||
} else {
|
|
||||||
return bdrv_co_nb_sectors(bs);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
return bdrv_co_nb_sectors(blk_bs(blk));
|
||||||
* This wrapper is written by hand because this function is in the hot I/O path,
|
|
||||||
* via blk_get_geometry.
|
|
||||||
*/
|
|
||||||
int64_t coroutine_mixed_fn blk_nb_sectors(BlockBackend *blk)
|
|
||||||
{
|
|
||||||
BlockDriverState *bs = blk_bs(blk);
|
|
||||||
|
|
||||||
IO_CODE();
|
|
||||||
|
|
||||||
if (!bs) {
|
|
||||||
return -ENOMEDIUM;
|
|
||||||
} else {
|
|
||||||
return bdrv_nb_sectors(bs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return 0 as number of sectors if no device present or error */
|
|
||||||
void coroutine_fn blk_co_get_geometry(BlockBackend *blk,
|
|
||||||
uint64_t *nb_sectors_ptr)
|
|
||||||
{
|
|
||||||
int64_t ret = blk_co_nb_sectors(blk);
|
|
||||||
*nb_sectors_ptr = ret < 0 ? 0 : ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This wrapper is written by hand because this function is in the hot I/O path.
|
|
||||||
*/
|
|
||||||
void coroutine_mixed_fn blk_get_geometry(BlockBackend *blk,
|
|
||||||
uint64_t *nb_sectors_ptr)
|
|
||||||
{
|
|
||||||
int64_t ret = blk_nb_sectors(blk);
|
|
||||||
*nb_sectors_ptr = ret < 0 ? 0 : ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset,
|
BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset,
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ static BlockDriver bdrv_copy_on_read = {
|
|||||||
.bdrv_co_eject = cor_co_eject,
|
.bdrv_co_eject = cor_co_eject,
|
||||||
.bdrv_co_lock_medium = cor_co_lock_medium,
|
.bdrv_co_lock_medium = cor_co_lock_medium,
|
||||||
|
|
||||||
|
.has_variable_length = true,
|
||||||
.is_filter = true,
|
.is_filter = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "dmg.h"
|
#include "dmg.h"
|
||||||
|
|
||||||
/* Work around a -Wstrict-prototypes warning in LZFSE headers */
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
|
||||||
#include <lzfse.h>
|
#include <lzfse.h>
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
static int dmg_uncompress_lzfse_do(char *next_in, unsigned int avail_in,
|
static int dmg_uncompress_lzfse_do(char *next_in, unsigned int avail_in,
|
||||||
char *next_out, unsigned int avail_out)
|
char *next_out, unsigned int avail_out)
|
||||||
|
|||||||
@@ -673,16 +673,7 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
|
|||||||
do {
|
do {
|
||||||
int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
|
int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
|
||||||
|
|
||||||
ret = blk_pwrite_zeroes(exp->common.blk, offset, size,
|
ret = blk_pdiscard(exp->common.blk, offset, size);
|
||||||
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK);
|
|
||||||
if (ret == -ENOTSUP) {
|
|
||||||
/*
|
|
||||||
* fallocate() specifies to return EOPNOTSUPP for unsupported
|
|
||||||
* operations
|
|
||||||
*/
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += size;
|
offset += size;
|
||||||
length -= size;
|
length -= size;
|
||||||
} while (ret == 0 && length > 0);
|
} while (ret == 0 && length > 0);
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ struct virtio_blk_inhdr {
|
|||||||
unsigned char status;
|
unsigned char status;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool coroutine_fn
|
static bool virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
|
||||||
virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
|
uint64_t sector, size_t size)
|
||||||
uint64_t sector, size_t size)
|
|
||||||
{
|
{
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
uint64_t total_sectors;
|
uint64_t total_sectors;
|
||||||
@@ -42,7 +41,7 @@ virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
|
|||||||
if ((sector << VIRTIO_BLK_SECTOR_BITS) % block_size) {
|
if ((sector << VIRTIO_BLK_SECTOR_BITS) % block_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
blk_co_get_geometry(blk, &total_sectors);
|
blk_get_geometry(blk, &total_sectors);
|
||||||
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
|
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3743,12 +3743,6 @@ static void cdrom_parse_filename(const char *filename, QDict *options,
|
|||||||
{
|
{
|
||||||
bdrv_parse_filename_strip_prefix(filename, "host_cdrom:", options);
|
bdrv_parse_filename_strip_prefix(filename, "host_cdrom:", options);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cdrom_refresh_limits(BlockDriverState *bs, Error **errp)
|
|
||||||
{
|
|
||||||
bs->bl.has_variable_length = true;
|
|
||||||
raw_refresh_limits(bs, errp);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@@ -3844,13 +3838,14 @@ static BlockDriver bdrv_host_cdrom = {
|
|||||||
.bdrv_co_preadv = raw_co_preadv,
|
.bdrv_co_preadv = raw_co_preadv,
|
||||||
.bdrv_co_pwritev = raw_co_pwritev,
|
.bdrv_co_pwritev = raw_co_pwritev,
|
||||||
.bdrv_co_flush_to_disk = raw_co_flush_to_disk,
|
.bdrv_co_flush_to_disk = raw_co_flush_to_disk,
|
||||||
.bdrv_refresh_limits = cdrom_refresh_limits,
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
.bdrv_co_io_plug = raw_co_io_plug,
|
.bdrv_co_io_plug = raw_co_io_plug,
|
||||||
.bdrv_co_io_unplug = raw_co_io_unplug,
|
.bdrv_co_io_unplug = raw_co_io_unplug,
|
||||||
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
|
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
|
||||||
|
|
||||||
.bdrv_co_truncate = raw_co_truncate,
|
.bdrv_co_truncate = raw_co_truncate,
|
||||||
.bdrv_co_getlength = raw_co_getlength,
|
.bdrv_co_getlength = raw_co_getlength,
|
||||||
|
.has_variable_length = true,
|
||||||
.bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size,
|
.bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size,
|
||||||
|
|
||||||
/* removable device support */
|
/* removable device support */
|
||||||
@@ -3972,13 +3967,14 @@ static BlockDriver bdrv_host_cdrom = {
|
|||||||
.bdrv_co_preadv = raw_co_preadv,
|
.bdrv_co_preadv = raw_co_preadv,
|
||||||
.bdrv_co_pwritev = raw_co_pwritev,
|
.bdrv_co_pwritev = raw_co_pwritev,
|
||||||
.bdrv_co_flush_to_disk = raw_co_flush_to_disk,
|
.bdrv_co_flush_to_disk = raw_co_flush_to_disk,
|
||||||
.bdrv_refresh_limits = cdrom_refresh_limits,
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
.bdrv_co_io_plug = raw_co_io_plug,
|
.bdrv_co_io_plug = raw_co_io_plug,
|
||||||
.bdrv_co_io_unplug = raw_co_io_unplug,
|
.bdrv_co_io_unplug = raw_co_io_unplug,
|
||||||
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
|
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
|
||||||
|
|
||||||
.bdrv_co_truncate = raw_co_truncate,
|
.bdrv_co_truncate = raw_co_truncate,
|
||||||
.bdrv_co_getlength = raw_co_getlength,
|
.bdrv_co_getlength = raw_co_getlength,
|
||||||
|
.has_variable_length = true,
|
||||||
.bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size,
|
.bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size,
|
||||||
|
|
||||||
/* removable device support */
|
/* removable device support */
|
||||||
|
|||||||
@@ -838,7 +838,6 @@ static void hdev_refresh_limits(BlockDriverState *bs, Error **errp)
|
|||||||
{
|
{
|
||||||
/* XXX Does Windows support AIO on less than 512-byte alignment? */
|
/* XXX Does Windows support AIO on less than 512-byte alignment? */
|
||||||
bs->bl.request_alignment = 512;
|
bs->bl.request_alignment = 512;
|
||||||
bs->bl.has_variable_length = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
@@ -934,6 +933,7 @@ static BlockDriver bdrv_host_device = {
|
|||||||
.bdrv_attach_aio_context = raw_attach_aio_context,
|
.bdrv_attach_aio_context = raw_attach_aio_context,
|
||||||
|
|
||||||
.bdrv_co_getlength = raw_co_getlength,
|
.bdrv_co_getlength = raw_co_getlength,
|
||||||
|
.has_variable_length = true,
|
||||||
.bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size,
|
.bdrv_co_get_allocated_file_size = raw_co_get_allocated_file_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ static BlockDriver bdrv_compress = {
|
|||||||
.bdrv_co_eject = compress_co_eject,
|
.bdrv_co_eject = compress_co_eject,
|
||||||
.bdrv_co_lock_medium = compress_co_lock_medium,
|
.bdrv_co_lock_medium = compress_co_lock_medium,
|
||||||
|
|
||||||
|
.has_variable_length = true,
|
||||||
.is_filter = true,
|
.is_filter = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -190,10 +190,6 @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp)
|
|||||||
bdrv_merge_limits(&bs->bl, &c->bs->bl);
|
bdrv_merge_limits(&bs->bl, &c->bs->bl);
|
||||||
have_limits = true;
|
have_limits = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->role & BDRV_CHILD_FILTERED) {
|
|
||||||
bs->bl.has_variable_length |= c->bs->bl.has_variable_length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!have_limits) {
|
if (!have_limits) {
|
||||||
|
|||||||
@@ -48,7 +48,6 @@
|
|||||||
#include "qemu/option.h"
|
#include "qemu/option.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "monitor/monitor.h"
|
#include "monitor/monitor.h"
|
||||||
#include "monitor/hmp.h"
|
#include "monitor/hmp.h"
|
||||||
|
|||||||
24
block/nfs.c
24
block/nfs.c
@@ -726,8 +726,10 @@ nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data,
|
|||||||
if (task->ret < 0) {
|
if (task->ret < 0) {
|
||||||
error_report("NFS Error: %s", nfs_get_error(nfs));
|
error_report("NFS Error: %s", nfs_get_error(nfs));
|
||||||
}
|
}
|
||||||
replay_bh_schedule_oneshot_event(task->client->aio_context,
|
|
||||||
nfs_co_generic_bh_cb, task);
|
/* Set task->complete before reading bs->wakeup. */
|
||||||
|
qatomic_mb_set(&task->complete, 1);
|
||||||
|
bdrv_wakeup(task->bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t coroutine_fn nfs_co_get_allocated_file_size(BlockDriverState *bs)
|
static int64_t coroutine_fn nfs_co_get_allocated_file_size(BlockDriverState *bs)
|
||||||
@@ -741,19 +743,15 @@ static int64_t coroutine_fn nfs_co_get_allocated_file_size(BlockDriverState *bs)
|
|||||||
return client->st_blocks * 512;
|
return client->st_blocks * 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
nfs_co_init_task(bs, &task);
|
task.bs = bs;
|
||||||
task.st = &st;
|
task.st = &st;
|
||||||
WITH_QEMU_LOCK_GUARD(&client->mutex) {
|
if (nfs_fstat_async(client->context, client->fh, nfs_get_allocated_file_size_cb,
|
||||||
if (nfs_fstat_async(client->context, client->fh, nfs_get_allocated_file_size_cb,
|
&task) != 0) {
|
||||||
&task) != 0) {
|
return -ENOMEM;
|
||||||
return -ENOMEM;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
nfs_set_events(client);
|
nfs_set_events(client);
|
||||||
}
|
BDRV_POLL_WHILE(bs, !task.complete);
|
||||||
while (!task.complete) {
|
|
||||||
qemu_coroutine_yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
|
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,6 +558,7 @@ BlockDriver bdrv_preallocate_filter = {
|
|||||||
.bdrv_set_perm = preallocate_set_perm,
|
.bdrv_set_perm = preallocate_set_perm,
|
||||||
.bdrv_child_perm = preallocate_child_perm,
|
.bdrv_child_perm = preallocate_child_perm,
|
||||||
|
|
||||||
|
.has_variable_length = true,
|
||||||
.is_filter = true,
|
.is_filter = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -594,6 +594,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
qemu_coroutine_enter(qemu_coroutine_create(bdrv_qed_open_entry, &qoc));
|
qemu_coroutine_enter(qemu_coroutine_create(bdrv_qed_open_entry, &qoc));
|
||||||
BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
|
BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
|
||||||
}
|
}
|
||||||
|
BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS);
|
||||||
return qoc.ret;
|
return qoc.ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -377,8 +377,6 @@ raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|||||||
|
|
||||||
static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
{
|
{
|
||||||
bs->bl.has_variable_length = bs->file->bs->bl.has_variable_length;
|
|
||||||
|
|
||||||
if (bs->probed) {
|
if (bs->probed) {
|
||||||
/* To make it easier to protect the first sector, any probed
|
/* To make it easier to protect the first sector, any probed
|
||||||
* image is restricted to read-modify-write on sub-sector
|
* image is restricted to read-modify-write on sub-sector
|
||||||
@@ -625,6 +623,7 @@ BlockDriver bdrv_raw = {
|
|||||||
.bdrv_co_truncate = &raw_co_truncate,
|
.bdrv_co_truncate = &raw_co_truncate,
|
||||||
.bdrv_co_getlength = &raw_co_getlength,
|
.bdrv_co_getlength = &raw_co_getlength,
|
||||||
.is_format = true,
|
.is_format = true,
|
||||||
|
.has_variable_length = true,
|
||||||
.bdrv_measure = &raw_measure,
|
.bdrv_measure = &raw_measure,
|
||||||
.bdrv_co_get_info = &raw_co_get_info,
|
.bdrv_co_get_info = &raw_co_get_info,
|
||||||
.bdrv_refresh_limits = &raw_refresh_limits,
|
.bdrv_refresh_limits = &raw_refresh_limits,
|
||||||
|
|||||||
@@ -762,6 +762,7 @@ static BlockDriver bdrv_replication = {
|
|||||||
|
|
||||||
.is_filter = true,
|
.is_filter = true,
|
||||||
|
|
||||||
|
.has_variable_length = true,
|
||||||
.strong_runtime_opts = replication_strong_runtime_opts,
|
.strong_runtime_opts = replication_strong_runtime_opts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -981,7 +981,7 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
|
|||||||
sector_write = merged_sector;
|
sector_write = merged_sector;
|
||||||
} else if (i == sectors - 1 && trailing_length) {
|
} else if (i == sectors - 1 && trailing_length) {
|
||||||
/* partial sector at the end of the buffer */
|
/* partial sector at the end of the buffer */
|
||||||
ret = bdrv_pread(bs->file, file_offset + trailing_length,
|
ret = bdrv_pread(bs->file, file_offset,
|
||||||
VHDX_LOG_SECTOR_SIZE - trailing_length,
|
VHDX_LOG_SECTOR_SIZE - trailing_length,
|
||||||
merged_sector + trailing_length, 0);
|
merged_sector + trailing_length, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
@@ -38,8 +38,6 @@
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
|
|
||||||
#include "include/gdbstub/syscalls.h"
|
|
||||||
|
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
#include "signal-common.h"
|
#include "signal-common.h"
|
||||||
#include "user/syscall-trace.h"
|
#include "user/syscall-trace.h"
|
||||||
|
|||||||
@@ -44,7 +44,6 @@
|
|||||||
#include "trace/control.h"
|
#include "trace/control.h"
|
||||||
#include "crypto/init.h"
|
#include "crypto/init.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "gdbstub/user.h"
|
|
||||||
|
|
||||||
#include "host-os.h"
|
#include "host-os.h"
|
||||||
#include "target_arch_cpu.h"
|
#include "target_arch_cpu.h"
|
||||||
@@ -68,9 +67,13 @@ bool have_guest_base;
|
|||||||
# if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
|
# if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
|
||||||
# if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
|
# if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
|
||||||
(TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
|
(TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
|
||||||
# define MAX_RESERVED_VA 0xfffffffful
|
/*
|
||||||
|
* There are a number of places where we assign reserved_va to a variable
|
||||||
|
* of type abi_ulong and expect it to fit. Avoid the last page.
|
||||||
|
*/
|
||||||
|
# define MAX_RESERVED_VA (0xfffffffful & TARGET_PAGE_MASK)
|
||||||
# else
|
# else
|
||||||
# define MAX_RESERVED_VA ((1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1)
|
# define MAX_RESERVED_VA (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# define MAX_RESERVED_VA 0
|
# define MAX_RESERVED_VA 0
|
||||||
@@ -462,7 +465,7 @@ int main(int argc, char **argv)
|
|||||||
envlist_free(envlist);
|
envlist_free(envlist);
|
||||||
|
|
||||||
if (reserved_va) {
|
if (reserved_va) {
|
||||||
mmap_next_start = reserved_va + 1;
|
mmap_next_start = reserved_va;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
page_set_flags(start, start + len - 1, prot | PAGE_VALID);
|
page_set_flags(start, start + len, prot | PAGE_VALID);
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error:
|
||||||
@@ -234,7 +234,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
|
|||||||
size = HOST_PAGE_ALIGN(size) + alignment;
|
size = HOST_PAGE_ALIGN(size) + alignment;
|
||||||
end_addr = start + size;
|
end_addr = start + size;
|
||||||
if (end_addr > reserved_va) {
|
if (end_addr > reserved_va) {
|
||||||
end_addr = reserved_va + 1;
|
end_addr = reserved_va;
|
||||||
}
|
}
|
||||||
addr = end_addr - qemu_host_page_size;
|
addr = end_addr - qemu_host_page_size;
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
|
|||||||
if (looped) {
|
if (looped) {
|
||||||
return (abi_ulong)-1;
|
return (abi_ulong)-1;
|
||||||
}
|
}
|
||||||
end_addr = reserved_va + 1;
|
end_addr = reserved_va;
|
||||||
addr = end_addr - qemu_host_page_size;
|
addr = end_addr - qemu_host_page_size;
|
||||||
looped = 1;
|
looped = 1;
|
||||||
continue;
|
continue;
|
||||||
@@ -656,7 +656,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
the_end1:
|
the_end1:
|
||||||
page_set_flags(start, start + len - 1, prot | PAGE_VALID);
|
page_set_flags(start, start + len, prot | PAGE_VALID);
|
||||||
the_end:
|
the_end:
|
||||||
#ifdef DEBUG_MMAP
|
#ifdef DEBUG_MMAP
|
||||||
printf("ret=0x" TARGET_ABI_FMT_lx "\n", start);
|
printf("ret=0x" TARGET_ABI_FMT_lx "\n", start);
|
||||||
@@ -767,7 +767,7 @@ int target_munmap(abi_ulong start, abi_ulong len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
page_set_flags(start, start + len - 1, 0);
|
page_set_flags(start, start + len, 0);
|
||||||
}
|
}
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
#include "gdbstub/user.h"
|
|
||||||
#include "signal-common.h"
|
#include "signal-common.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "hw/core/tcg-cpu-ops.h"
|
#include "hw/core/tcg-cpu-ops.h"
|
||||||
|
|||||||
@@ -44,39 +44,39 @@
|
|||||||
|
|
||||||
#define ESC 0x1B
|
#define ESC 0x1B
|
||||||
|
|
||||||
#define BAUM_REQ_DisplayData 0x01
|
#define BAUM_REQ_DisplayData 0x01
|
||||||
#define BAUM_REQ_GetVersionNumber 0x05
|
#define BAUM_REQ_GetVersionNumber 0x05
|
||||||
#define BAUM_REQ_GetKeys 0x08
|
#define BAUM_REQ_GetKeys 0x08
|
||||||
#define BAUM_REQ_SetMode 0x12
|
#define BAUM_REQ_SetMode 0x12
|
||||||
#define BAUM_REQ_SetProtocol 0x15
|
#define BAUM_REQ_SetProtocol 0x15
|
||||||
#define BAUM_REQ_GetDeviceIdentity 0x84
|
#define BAUM_REQ_GetDeviceIdentity 0x84
|
||||||
#define BAUM_REQ_GetSerialNumber 0x8A
|
#define BAUM_REQ_GetSerialNumber 0x8A
|
||||||
|
|
||||||
#define BAUM_RSP_CellCount 0x01
|
#define BAUM_RSP_CellCount 0x01
|
||||||
#define BAUM_RSP_VersionNumber 0x05
|
#define BAUM_RSP_VersionNumber 0x05
|
||||||
#define BAUM_RSP_ModeSetting 0x11
|
#define BAUM_RSP_ModeSetting 0x11
|
||||||
#define BAUM_RSP_CommunicationChannel 0x16
|
#define BAUM_RSP_CommunicationChannel 0x16
|
||||||
#define BAUM_RSP_PowerdownSignal 0x17
|
#define BAUM_RSP_PowerdownSignal 0x17
|
||||||
#define BAUM_RSP_HorizontalSensors 0x20
|
#define BAUM_RSP_HorizontalSensors 0x20
|
||||||
#define BAUM_RSP_VerticalSensors 0x21
|
#define BAUM_RSP_VerticalSensors 0x21
|
||||||
#define BAUM_RSP_RoutingKeys 0x22
|
#define BAUM_RSP_RoutingKeys 0x22
|
||||||
#define BAUM_RSP_Switches 0x23
|
#define BAUM_RSP_Switches 0x23
|
||||||
#define BAUM_RSP_TopKeys 0x24
|
#define BAUM_RSP_TopKeys 0x24
|
||||||
#define BAUM_RSP_HorizontalSensor 0x25
|
#define BAUM_RSP_HorizontalSensor 0x25
|
||||||
#define BAUM_RSP_VerticalSensor 0x26
|
#define BAUM_RSP_VerticalSensor 0x26
|
||||||
#define BAUM_RSP_RoutingKey 0x27
|
#define BAUM_RSP_RoutingKey 0x27
|
||||||
#define BAUM_RSP_FrontKeys6 0x28
|
#define BAUM_RSP_FrontKeys6 0x28
|
||||||
#define BAUM_RSP_BackKeys6 0x29
|
#define BAUM_RSP_BackKeys6 0x29
|
||||||
#define BAUM_RSP_CommandKeys 0x2B
|
#define BAUM_RSP_CommandKeys 0x2B
|
||||||
#define BAUM_RSP_FrontKeys10 0x2C
|
#define BAUM_RSP_FrontKeys10 0x2C
|
||||||
#define BAUM_RSP_BackKeys10 0x2D
|
#define BAUM_RSP_BackKeys10 0x2D
|
||||||
#define BAUM_RSP_EntryKeys 0x33
|
#define BAUM_RSP_EntryKeys 0x33
|
||||||
#define BAUM_RSP_JoyStick 0x34
|
#define BAUM_RSP_JoyStick 0x34
|
||||||
#define BAUM_RSP_ErrorCode 0x40
|
#define BAUM_RSP_ErrorCode 0x40
|
||||||
#define BAUM_RSP_InfoBlock 0x42
|
#define BAUM_RSP_InfoBlock 0x42
|
||||||
#define BAUM_RSP_DeviceIdentity 0x84
|
#define BAUM_RSP_DeviceIdentity 0x84
|
||||||
#define BAUM_RSP_SerialNumber 0x8A
|
#define BAUM_RSP_SerialNumber 0x8A
|
||||||
#define BAUM_RSP_BluetoothName 0x8C
|
#define BAUM_RSP_BluetoothName 0x8C
|
||||||
|
|
||||||
#define BAUM_TL1 0x01
|
#define BAUM_TL1 0x01
|
||||||
#define BAUM_TL2 0x02
|
#define BAUM_TL2 0x02
|
||||||
|
|||||||
@@ -1175,10 +1175,12 @@ bool qmp_add_client_char(int fd, bool has_skipauth, bool skipauth,
|
|||||||
|
|
||||||
if (!s) {
|
if (!s) {
|
||||||
error_setg(errp, "protocol '%s' is invalid", protocol);
|
error_setg(errp, "protocol '%s' is invalid", protocol);
|
||||||
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (qemu_chr_add_client(s, fd) < 0) {
|
if (qemu_chr_add_client(s, fd) < 0) {
|
||||||
error_setg(errp, "failed to add client");
|
error_setg(errp, "failed to add client");
|
||||||
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
|
||||||
TARGET_HAS_BFLT=y
|
TARGET_HAS_BFLT=y
|
||||||
CONFIG_SEMIHOSTING=y
|
CONFIG_SEMIHOSTING=y
|
||||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_SUPPORTS_MTTCG=y
|
TARGET_SUPPORTS_MTTCG=y
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml gdb-xml/aarch64-pauth.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
||||||
TARGET_NEED_FDT=y
|
TARGET_NEED_FDT=y
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_BIG_ENDIAN=y
|
TARGET_BIG_ENDIAN=y
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
|
||||||
TARGET_HAS_BFLT=y
|
TARGET_HAS_BFLT=y
|
||||||
CONFIG_SEMIHOSTING=y
|
CONFIG_SEMIHOSTING=y
|
||||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||||
|
|||||||
24
configure
vendored
24
configure
vendored
@@ -230,8 +230,6 @@ stack_protector=""
|
|||||||
safe_stack=""
|
safe_stack=""
|
||||||
use_containers="yes"
|
use_containers="yes"
|
||||||
gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb")
|
gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb")
|
||||||
gdb_arches=""
|
|
||||||
glib_has_gslice="no"
|
|
||||||
|
|
||||||
if test -e "$source_path/.git"
|
if test -e "$source_path/.git"
|
||||||
then
|
then
|
||||||
@@ -1495,17 +1493,6 @@ for i in $glib_modules; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Check whether glib has gslice, which we have to avoid for correctness.
|
|
||||||
# TODO: remove this check and the corresponding workaround (qtree) when
|
|
||||||
# the minimum supported glib is >= $glib_dropped_gslice_version.
|
|
||||||
glib_dropped_gslice_version=2.75.3
|
|
||||||
for i in $glib_modules; do
|
|
||||||
if ! $pkg_config --atleast-version=$glib_dropped_gslice_version $i; then
|
|
||||||
glib_has_gslice="yes"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
glib_bindir="$($pkg_config --variable=bindir glib-2.0)"
|
glib_bindir="$($pkg_config --variable=bindir glib-2.0)"
|
||||||
if test -z "$glib_bindir" ; then
|
if test -z "$glib_bindir" ; then
|
||||||
glib_bindir="$($pkg_config --variable=prefix glib-2.0)"/bin
|
glib_bindir="$($pkg_config --variable=prefix glib-2.0)"/bin
|
||||||
@@ -2275,7 +2262,6 @@ fi
|
|||||||
# tests might fail. Prefer to keep the relevant files in their own
|
# tests might fail. Prefer to keep the relevant files in their own
|
||||||
# directory and symlink the directory instead.
|
# directory and symlink the directory instead.
|
||||||
LINKS="Makefile"
|
LINKS="Makefile"
|
||||||
LINKS="$LINKS docs/config"
|
|
||||||
LINKS="$LINKS pc-bios/optionrom/Makefile"
|
LINKS="$LINKS pc-bios/optionrom/Makefile"
|
||||||
LINKS="$LINKS pc-bios/s390-ccw/Makefile"
|
LINKS="$LINKS pc-bios/s390-ccw/Makefile"
|
||||||
LINKS="$LINKS pc-bios/vof/Makefile"
|
LINKS="$LINKS pc-bios/vof/Makefile"
|
||||||
@@ -2409,7 +2395,6 @@ if test -n "$gdb_bin"; then
|
|||||||
gdb_version=$($gdb_bin --version | head -n 1)
|
gdb_version=$($gdb_bin --version | head -n 1)
|
||||||
if version_ge ${gdb_version##* } 9.1; then
|
if version_ge ${gdb_version##* } 9.1; then
|
||||||
echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
|
echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
|
||||||
gdb_arches=$("$source_path/scripts/probe-gdb-support.py" $gdb_bin)
|
|
||||||
else
|
else
|
||||||
gdb_bin=""
|
gdb_bin=""
|
||||||
fi
|
fi
|
||||||
@@ -2432,9 +2417,6 @@ echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
|||||||
echo "GLIB_LIBS=$glib_libs" >> $config_host_mak
|
echo "GLIB_LIBS=$glib_libs" >> $config_host_mak
|
||||||
echo "GLIB_BINDIR=$glib_bindir" >> $config_host_mak
|
echo "GLIB_BINDIR=$glib_bindir" >> $config_host_mak
|
||||||
echo "GLIB_VERSION=$($pkg_config --modversion glib-2.0)" >> $config_host_mak
|
echo "GLIB_VERSION=$($pkg_config --modversion glib-2.0)" >> $config_host_mak
|
||||||
if test "$glib_has_gslice" = "yes" ; then
|
|
||||||
echo "HAVE_GLIB_WITH_SLICE_ALLOCATOR=y" >> $config_host_mak
|
|
||||||
fi
|
|
||||||
echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak
|
echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak
|
||||||
echo "EXESUF=$EXESUF" >> $config_host_mak
|
echo "EXESUF=$EXESUF" >> $config_host_mak
|
||||||
|
|
||||||
@@ -2537,12 +2519,6 @@ for target in $target_list; do
|
|||||||
write_target_makefile "build-tcg-tests-$target" >> "$config_target_mak"
|
write_target_makefile "build-tcg-tests-$target" >> "$config_target_mak"
|
||||||
echo "BUILD_STATIC=$build_static" >> "$config_target_mak"
|
echo "BUILD_STATIC=$build_static" >> "$config_target_mak"
|
||||||
echo "QEMU=$PWD/$qemu" >> "$config_target_mak"
|
echo "QEMU=$PWD/$qemu" >> "$config_target_mak"
|
||||||
|
|
||||||
# will GDB work with these binaries?
|
|
||||||
if test "${gdb_arches#*$arch}" != "$gdb_arches"; then
|
|
||||||
echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
|
echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
|
||||||
tcg_tests_targets="$tcg_tests_targets $target"
|
tcg_tests_targets="$tcg_tests_targets $target"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
|
static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < ps->block_nr; i++) {
|
for (i = 0; i < ps->block_nr; i++) {
|
||||||
if (ps->block[i].paddr <= pa &&
|
if (ps->block[i].paddr <= pa &&
|
||||||
pa <= ps->block[i].paddr + ps->block[i].size) {
|
pa <= ps->block[i].paddr + ps->block[i].size) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
#define SYM_URL_BASE "https://msdl.microsoft.com/download/symbols/"
|
#define SYM_URL_BASE "https://msdl.microsoft.com/download/symbols/"
|
||||||
#define PDB_NAME "ntkrnlmp.pdb"
|
#define PDB_NAME "ntkrnlmp.pdb"
|
||||||
#define PE_NAME "ntoskrnl.exe"
|
|
||||||
|
|
||||||
#define INITIAL_MXCSR 0x1f80
|
#define INITIAL_MXCSR 0x1f80
|
||||||
|
|
||||||
@@ -283,16 +282,14 @@ static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (i = 0; i < ps->block_nr; i++) {
|
for (i = 0; i < ps->block_nr; i++) {
|
||||||
h.PhysicalMemoryBlock.NumberOfPages +=
|
h.PhysicalMemoryBlock.NumberOfPages += ps->block[i].size / ELF2DMP_PAGE_SIZE;
|
||||||
ps->block[i].size / ELF2DMP_PAGE_SIZE;
|
|
||||||
h.PhysicalMemoryBlock.Run[i] = (WinDumpPhyMemRun64) {
|
h.PhysicalMemoryBlock.Run[i] = (WinDumpPhyMemRun64) {
|
||||||
.BasePage = ps->block[i].paddr / ELF2DMP_PAGE_SIZE,
|
.BasePage = ps->block[i].paddr / ELF2DMP_PAGE_SIZE,
|
||||||
.PageCount = ps->block[i].size / ELF2DMP_PAGE_SIZE,
|
.PageCount = ps->block[i].size / ELF2DMP_PAGE_SIZE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
h.RequiredDumpSpace +=
|
h.RequiredDumpSpace += h.PhysicalMemoryBlock.NumberOfPages << ELF2DMP_PAGE_BITS;
|
||||||
h.PhysicalMemoryBlock.NumberOfPages << ELF2DMP_PAGE_BITS;
|
|
||||||
|
|
||||||
*hdr = h;
|
*hdr = h;
|
||||||
|
|
||||||
@@ -302,8 +299,7 @@ static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
|
|||||||
static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
||||||
struct va_space *vs, QEMU_Elf *qe)
|
struct va_space *vs, QEMU_Elf *qe)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < qe->state_nr; i++) {
|
for (i = 0; i < qe->state_nr; i++) {
|
||||||
uint64_t Prcb;
|
uint64_t Prcb;
|
||||||
uint64_t Context;
|
uint64_t Context;
|
||||||
@@ -334,45 +330,6 @@ static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pe_get_data_dir_entry(uint64_t base, void *start_addr, int idx,
|
|
||||||
void *entry, size_t size, struct va_space *vs)
|
|
||||||
{
|
|
||||||
const char e_magic[2] = "MZ";
|
|
||||||
const char Signature[4] = "PE\0\0";
|
|
||||||
IMAGE_DOS_HEADER *dos_hdr = start_addr;
|
|
||||||
IMAGE_NT_HEADERS64 nt_hdrs;
|
|
||||||
IMAGE_FILE_HEADER *file_hdr = &nt_hdrs.FileHeader;
|
|
||||||
IMAGE_OPTIONAL_HEADER64 *opt_hdr = &nt_hdrs.OptionalHeader;
|
|
||||||
IMAGE_DATA_DIRECTORY *data_dir = nt_hdrs.OptionalHeader.DataDirectory;
|
|
||||||
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(*dos_hdr) >= ELF2DMP_PAGE_SIZE);
|
|
||||||
|
|
||||||
if (memcmp(&dos_hdr->e_magic, e_magic, sizeof(e_magic))) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (va_space_rw(vs, base + dos_hdr->e_lfanew,
|
|
||||||
&nt_hdrs, sizeof(nt_hdrs), 0)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memcmp(&nt_hdrs.Signature, Signature, sizeof(Signature)) ||
|
|
||||||
file_hdr->Machine != 0x8664 || opt_hdr->Magic != 0x020b) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (va_space_rw(vs,
|
|
||||||
base + data_dir[idx].VirtualAddress,
|
|
||||||
entry, size, 0)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Data directory entry #%d: RVA = 0x%08"PRIx32"\n", idx,
|
|
||||||
(uint32_t)data_dir[idx].VirtualAddress);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_dump(struct pa_space *ps,
|
static int write_dump(struct pa_space *ps,
|
||||||
WinDumpHeader64 *hdr, const char *name)
|
WinDumpHeader64 *hdr, const char *name)
|
||||||
{
|
{
|
||||||
@@ -406,38 +363,45 @@ static int write_dump(struct pa_space *ps,
|
|||||||
return fclose(dmp_file);
|
return fclose(dmp_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pe_check_export_name(uint64_t base, void *start_addr,
|
|
||||||
struct va_space *vs)
|
|
||||||
{
|
|
||||||
IMAGE_EXPORT_DIRECTORY export_dir;
|
|
||||||
const char *pe_name;
|
|
||||||
|
|
||||||
if (pe_get_data_dir_entry(base, start_addr, IMAGE_FILE_EXPORT_DIRECTORY,
|
|
||||||
&export_dir, sizeof(export_dir), vs)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pe_name = va_space_resolve(vs, base + export_dir.Name);
|
|
||||||
if (!pe_name) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !strcmp(pe_name, PE_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pe_get_pdb_symstore_hash(uint64_t base, void *start_addr,
|
static int pe_get_pdb_symstore_hash(uint64_t base, void *start_addr,
|
||||||
char *hash, struct va_space *vs)
|
char *hash, struct va_space *vs)
|
||||||
{
|
{
|
||||||
|
const char e_magic[2] = "MZ";
|
||||||
|
const char Signature[4] = "PE\0\0";
|
||||||
const char sign_rsds[4] = "RSDS";
|
const char sign_rsds[4] = "RSDS";
|
||||||
|
IMAGE_DOS_HEADER *dos_hdr = start_addr;
|
||||||
|
IMAGE_NT_HEADERS64 nt_hdrs;
|
||||||
|
IMAGE_FILE_HEADER *file_hdr = &nt_hdrs.FileHeader;
|
||||||
|
IMAGE_OPTIONAL_HEADER64 *opt_hdr = &nt_hdrs.OptionalHeader;
|
||||||
|
IMAGE_DATA_DIRECTORY *data_dir = nt_hdrs.OptionalHeader.DataDirectory;
|
||||||
IMAGE_DEBUG_DIRECTORY debug_dir;
|
IMAGE_DEBUG_DIRECTORY debug_dir;
|
||||||
OMFSignatureRSDS rsds;
|
OMFSignatureRSDS rsds;
|
||||||
char *pdb_name;
|
char *pdb_name;
|
||||||
size_t pdb_name_sz;
|
size_t pdb_name_sz;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (pe_get_data_dir_entry(base, start_addr, IMAGE_FILE_DEBUG_DIRECTORY,
|
QEMU_BUILD_BUG_ON(sizeof(*dos_hdr) >= ELF2DMP_PAGE_SIZE);
|
||||||
&debug_dir, sizeof(debug_dir), vs)) {
|
|
||||||
eprintf("Failed to get Debug Directory\n");
|
if (memcmp(&dos_hdr->e_magic, e_magic, sizeof(e_magic))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (va_space_rw(vs, base + dos_hdr->e_lfanew,
|
||||||
|
&nt_hdrs, sizeof(nt_hdrs), 0)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(&nt_hdrs.Signature, Signature, sizeof(Signature)) ||
|
||||||
|
file_hdr->Machine != 0x8664 || opt_hdr->Magic != 0x020b) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Debug Directory RVA = 0x%08"PRIx32"\n",
|
||||||
|
(uint32_t)data_dir[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress);
|
||||||
|
|
||||||
|
if (va_space_rw(vs,
|
||||||
|
base + data_dir[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress,
|
||||||
|
&debug_dir, sizeof(debug_dir), 0)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,7 +473,6 @@ int main(int argc, char *argv[])
|
|||||||
uint64_t KdDebuggerDataBlock;
|
uint64_t KdDebuggerDataBlock;
|
||||||
KDDEBUGGER_DATA64 *kdbg;
|
KDDEBUGGER_DATA64 *kdbg;
|
||||||
uint64_t KdVersionBlock;
|
uint64_t KdVersionBlock;
|
||||||
bool kernel_found = false;
|
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
eprintf("usage:\n\t%s elf_file dmp_file\n", argv[0]);
|
eprintf("usage:\n\t%s elf_file dmp_file\n", argv[0]);
|
||||||
@@ -557,14 +520,11 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*(uint16_t *)nt_start_addr == 0x5a4d) { /* MZ */
|
if (*(uint16_t *)nt_start_addr == 0x5a4d) { /* MZ */
|
||||||
if (pe_check_export_name(KernBase, nt_start_addr, &vs)) {
|
break;
|
||||||
kernel_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!kernel_found) {
|
if (!nt_start_addr) {
|
||||||
eprintf("Failed to find NT kernel image\n");
|
eprintf("Failed to find NT kernel image\n");
|
||||||
err = 1;
|
err = 1;
|
||||||
goto out_ps;
|
goto out_ps;
|
||||||
|
|||||||
@@ -33,90 +33,75 @@ typedef struct IMAGE_DOS_HEADER {
|
|||||||
} __attribute__ ((packed)) IMAGE_DOS_HEADER;
|
} __attribute__ ((packed)) IMAGE_DOS_HEADER;
|
||||||
|
|
||||||
typedef struct IMAGE_FILE_HEADER {
|
typedef struct IMAGE_FILE_HEADER {
|
||||||
uint16_t Machine;
|
uint16_t Machine;
|
||||||
uint16_t NumberOfSections;
|
uint16_t NumberOfSections;
|
||||||
uint32_t TimeDateStamp;
|
uint32_t TimeDateStamp;
|
||||||
uint32_t PointerToSymbolTable;
|
uint32_t PointerToSymbolTable;
|
||||||
uint32_t NumberOfSymbols;
|
uint32_t NumberOfSymbols;
|
||||||
uint16_t SizeOfOptionalHeader;
|
uint16_t SizeOfOptionalHeader;
|
||||||
uint16_t Characteristics;
|
uint16_t Characteristics;
|
||||||
} __attribute__ ((packed)) IMAGE_FILE_HEADER;
|
} __attribute__ ((packed)) IMAGE_FILE_HEADER;
|
||||||
|
|
||||||
typedef struct IMAGE_DATA_DIRECTORY {
|
typedef struct IMAGE_DATA_DIRECTORY {
|
||||||
uint32_t VirtualAddress;
|
uint32_t VirtualAddress;
|
||||||
uint32_t Size;
|
uint32_t Size;
|
||||||
} __attribute__ ((packed)) IMAGE_DATA_DIRECTORY;
|
} __attribute__ ((packed)) IMAGE_DATA_DIRECTORY;
|
||||||
|
|
||||||
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
||||||
|
|
||||||
typedef struct IMAGE_OPTIONAL_HEADER64 {
|
typedef struct IMAGE_OPTIONAL_HEADER64 {
|
||||||
uint16_t Magic; /* 0x20b */
|
uint16_t Magic; /* 0x20b */
|
||||||
uint8_t MajorLinkerVersion;
|
uint8_t MajorLinkerVersion;
|
||||||
uint8_t MinorLinkerVersion;
|
uint8_t MinorLinkerVersion;
|
||||||
uint32_t SizeOfCode;
|
uint32_t SizeOfCode;
|
||||||
uint32_t SizeOfInitializedData;
|
uint32_t SizeOfInitializedData;
|
||||||
uint32_t SizeOfUninitializedData;
|
uint32_t SizeOfUninitializedData;
|
||||||
uint32_t AddressOfEntryPoint;
|
uint32_t AddressOfEntryPoint;
|
||||||
uint32_t BaseOfCode;
|
uint32_t BaseOfCode;
|
||||||
uint64_t ImageBase;
|
uint64_t ImageBase;
|
||||||
uint32_t SectionAlignment;
|
uint32_t SectionAlignment;
|
||||||
uint32_t FileAlignment;
|
uint32_t FileAlignment;
|
||||||
uint16_t MajorOperatingSystemVersion;
|
uint16_t MajorOperatingSystemVersion;
|
||||||
uint16_t MinorOperatingSystemVersion;
|
uint16_t MinorOperatingSystemVersion;
|
||||||
uint16_t MajorImageVersion;
|
uint16_t MajorImageVersion;
|
||||||
uint16_t MinorImageVersion;
|
uint16_t MinorImageVersion;
|
||||||
uint16_t MajorSubsystemVersion;
|
uint16_t MajorSubsystemVersion;
|
||||||
uint16_t MinorSubsystemVersion;
|
uint16_t MinorSubsystemVersion;
|
||||||
uint32_t Win32VersionValue;
|
uint32_t Win32VersionValue;
|
||||||
uint32_t SizeOfImage;
|
uint32_t SizeOfImage;
|
||||||
uint32_t SizeOfHeaders;
|
uint32_t SizeOfHeaders;
|
||||||
uint32_t CheckSum;
|
uint32_t CheckSum;
|
||||||
uint16_t Subsystem;
|
uint16_t Subsystem;
|
||||||
uint16_t DllCharacteristics;
|
uint16_t DllCharacteristics;
|
||||||
uint64_t SizeOfStackReserve;
|
uint64_t SizeOfStackReserve;
|
||||||
uint64_t SizeOfStackCommit;
|
uint64_t SizeOfStackCommit;
|
||||||
uint64_t SizeOfHeapReserve;
|
uint64_t SizeOfHeapReserve;
|
||||||
uint64_t SizeOfHeapCommit;
|
uint64_t SizeOfHeapCommit;
|
||||||
uint32_t LoaderFlags;
|
uint32_t LoaderFlags;
|
||||||
uint32_t NumberOfRvaAndSizes;
|
uint32_t NumberOfRvaAndSizes;
|
||||||
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
||||||
} __attribute__ ((packed)) IMAGE_OPTIONAL_HEADER64;
|
} __attribute__ ((packed)) IMAGE_OPTIONAL_HEADER64;
|
||||||
|
|
||||||
typedef struct IMAGE_NT_HEADERS64 {
|
typedef struct IMAGE_NT_HEADERS64 {
|
||||||
uint32_t Signature;
|
uint32_t Signature;
|
||||||
IMAGE_FILE_HEADER FileHeader;
|
IMAGE_FILE_HEADER FileHeader;
|
||||||
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
||||||
} __attribute__ ((packed)) IMAGE_NT_HEADERS64;
|
} __attribute__ ((packed)) IMAGE_NT_HEADERS64;
|
||||||
|
|
||||||
typedef struct IMAGE_EXPORT_DIRECTORY {
|
|
||||||
uint32_t Characteristics;
|
|
||||||
uint32_t TimeDateStamp;
|
|
||||||
uint16_t MajorVersion;
|
|
||||||
uint16_t MinorVersion;
|
|
||||||
uint32_t Name;
|
|
||||||
uint32_t Base;
|
|
||||||
uint32_t NumberOfFunctions;
|
|
||||||
uint32_t NumberOfNames;
|
|
||||||
uint32_t AddressOfFunctions;
|
|
||||||
uint32_t AddressOfNames;
|
|
||||||
uint32_t AddressOfNameOrdinals;
|
|
||||||
} __attribute__ ((packed)) IMAGE_EXPORT_DIRECTORY;
|
|
||||||
|
|
||||||
typedef struct IMAGE_DEBUG_DIRECTORY {
|
typedef struct IMAGE_DEBUG_DIRECTORY {
|
||||||
uint32_t Characteristics;
|
uint32_t Characteristics;
|
||||||
uint32_t TimeDateStamp;
|
uint32_t TimeDateStamp;
|
||||||
uint16_t MajorVersion;
|
uint16_t MajorVersion;
|
||||||
uint16_t MinorVersion;
|
uint16_t MinorVersion;
|
||||||
uint32_t Type;
|
uint32_t Type;
|
||||||
uint32_t SizeOfData;
|
uint32_t SizeOfData;
|
||||||
uint32_t AddressOfRawData;
|
uint32_t AddressOfRawData;
|
||||||
uint32_t PointerToRawData;
|
uint32_t PointerToRawData;
|
||||||
} __attribute__ ((packed)) IMAGE_DEBUG_DIRECTORY;
|
} __attribute__ ((packed)) IMAGE_DEBUG_DIRECTORY;
|
||||||
|
|
||||||
#define IMAGE_DEBUG_TYPE_CODEVIEW 2
|
#define IMAGE_DEBUG_TYPE_CODEVIEW 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define IMAGE_FILE_EXPORT_DIRECTORY 0
|
|
||||||
#define IMAGE_FILE_DEBUG_DIRECTORY 6
|
#define IMAGE_FILE_DEBUG_DIRECTORY 6
|
||||||
|
|
||||||
typedef struct guid_t {
|
typedef struct guid_t {
|
||||||
|
|||||||
@@ -4,12 +4,7 @@
|
|||||||
# This maps email domains to nice easy to read company names
|
# This maps email domains to nice easy to read company names
|
||||||
#
|
#
|
||||||
|
|
||||||
linux.alibaba.com Alibaba
|
|
||||||
amazon.com Amazon
|
|
||||||
amazon.co.uk Amazon
|
|
||||||
amazon.de Amazon
|
|
||||||
amd.com AMD
|
amd.com AMD
|
||||||
aspeedtech.com ASPEED Technology Inc.
|
|
||||||
baidu.com Baidu
|
baidu.com Baidu
|
||||||
bytedance.com ByteDance
|
bytedance.com ByteDance
|
||||||
cmss.chinamobile.com China Mobile
|
cmss.chinamobile.com China Mobile
|
||||||
@@ -17,7 +12,6 @@ citrix.com Citrix
|
|||||||
crudebyte.com Crudebyte
|
crudebyte.com Crudebyte
|
||||||
chinatelecom.cn China Telecom
|
chinatelecom.cn China Telecom
|
||||||
eldorado.org.br Instituto de Pesquisas Eldorado
|
eldorado.org.br Instituto de Pesquisas Eldorado
|
||||||
fb.com Facebook
|
|
||||||
fujitsu.com Fujitsu
|
fujitsu.com Fujitsu
|
||||||
google.com Google
|
google.com Google
|
||||||
greensocs.com GreenSocs
|
greensocs.com GreenSocs
|
||||||
@@ -37,18 +31,15 @@ oracle.com Oracle
|
|||||||
proxmox.com Proxmox
|
proxmox.com Proxmox
|
||||||
quicinc.com Qualcomm Innovation Center
|
quicinc.com Qualcomm Innovation Center
|
||||||
redhat.com Red Hat
|
redhat.com Red Hat
|
||||||
rev.ng rev.ng Labs
|
|
||||||
rt-rk.com RT-RK
|
rt-rk.com RT-RK
|
||||||
samsung.com Samsung
|
samsung.com Samsung
|
||||||
siemens.com Siemens
|
siemens.com Siemens
|
||||||
sifive.com SiFive
|
sifive.com SiFive
|
||||||
suse.com SUSE
|
suse.com SUSE
|
||||||
suse.de SUSE
|
suse.de SUSE
|
||||||
syrmia.com SYRMIA
|
|
||||||
ventanamicro.com Ventana Micro Systems
|
|
||||||
virtuozzo.com Virtuozzo
|
virtuozzo.com Virtuozzo
|
||||||
vrull.eu VRULL
|
|
||||||
wdc.com Western Digital
|
wdc.com Western Digital
|
||||||
windriver.com Wind River
|
windriver.com Wind River
|
||||||
|
xilinx.com Xilinx
|
||||||
yadro.com YADRO
|
yadro.com YADRO
|
||||||
yandex-team.ru Yandex
|
yandex-team.ru Yandex
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#
|
|
||||||
# Alibaba contributors including its subsidiaries
|
|
||||||
#
|
|
||||||
|
|
||||||
# c-sky.com, now part of T-Head, wholly-owned entity of Alibaba Group
|
|
||||||
ren_guo@c-sky.com
|
|
||||||
zhiwei_liu@c-sky.com
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# AMD acquired Xilinx and contributors have been slowly updating emails
|
|
||||||
|
|
||||||
edgar.iglesias@xilinx.com
|
|
||||||
fnu.vikram@xilinx.com
|
|
||||||
francisco.iglesias@xilinx.com
|
|
||||||
sai.pavan.boddu@xilinx.com
|
|
||||||
stefano.stabellini@xilinx.com
|
|
||||||
tong.ho@xilinx.com
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#
|
|
||||||
# Some Facebook contributors also occasionally use personal email addresses.
|
|
||||||
#
|
|
||||||
|
|
||||||
peter@pjd.dev
|
|
||||||
@@ -12,4 +12,3 @@ jcfaracco@gmail.com
|
|||||||
joel@jms.id.au
|
joel@jms.id.au
|
||||||
sjitindarsingh@gmail.com
|
sjitindarsingh@gmail.com
|
||||||
tommusta@gmail.com
|
tommusta@gmail.com
|
||||||
idan.horowitz@gmail.com
|
|
||||||
|
|||||||
@@ -37,8 +37,3 @@ akihiko.odaki@gmail.com
|
|||||||
paul@nowt.org
|
paul@nowt.org
|
||||||
git@xen0n.name
|
git@xen0n.name
|
||||||
simon@simonsafar.com
|
simon@simonsafar.com
|
||||||
research_trasio@irq.a4lg.com
|
|
||||||
shentey@gmail.com
|
|
||||||
bmeng@tinylab.org
|
|
||||||
strahinja.p.jankovic@gmail.com
|
|
||||||
Jason@zx2c4.com
|
|
||||||
|
|||||||
13
cpu.c
13
cpu.c
@@ -31,18 +31,16 @@
|
|||||||
#include "hw/core/sysemu-cpu-ops.h"
|
#include "hw/core/sysemu-cpu-ops.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#endif
|
#endif
|
||||||
#include "sysemu/cpus.h"
|
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
|
#include "sysemu/kvm.h"
|
||||||
#include "exec/replay-core.h"
|
#include "exec/replay-core.h"
|
||||||
#include "exec/cpu-common.h"
|
#include "exec/cpu-common.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/tb-flush.h"
|
|
||||||
#include "exec/translate-all.h"
|
#include "exec/translate-all.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
#include "hw/core/accel-cpu.h"
|
#include "hw/core/accel-cpu.h"
|
||||||
#include "trace/trace-root.h"
|
#include "trace/trace-root.h"
|
||||||
#include "qemu/accel.h"
|
#include "qemu/accel.h"
|
||||||
#include "qemu/plugin.h"
|
|
||||||
|
|
||||||
uintptr_t qemu_host_page_size;
|
uintptr_t qemu_host_page_size;
|
||||||
intptr_t qemu_host_page_mask;
|
intptr_t qemu_host_page_mask;
|
||||||
@@ -327,14 +325,9 @@ void cpu_single_step(CPUState *cpu, int enabled)
|
|||||||
{
|
{
|
||||||
if (cpu->singlestep_enabled != enabled) {
|
if (cpu->singlestep_enabled != enabled) {
|
||||||
cpu->singlestep_enabled = enabled;
|
cpu->singlestep_enabled = enabled;
|
||||||
|
if (kvm_enabled()) {
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
kvm_update_guest_debug(cpu, 0);
|
||||||
const AccelOpsClass *ops = cpus_get_accel();
|
|
||||||
if (ops->update_guest_debug) {
|
|
||||||
ops->update_guest_debug(cpu);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
trace_breakpoint_singlestep(cpu->cpu_index, enabled);
|
trace_breakpoint_singlestep(cpu->cpu_index, enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ qcrypto_afalg_socket_bind(const char *type, const char *name,
|
|||||||
|
|
||||||
if (bind(sbind, (const struct sockaddr *)&salg, sizeof(salg)) != 0) {
|
if (bind(sbind, (const struct sockaddr *)&salg, sizeof(salg)) != 0) {
|
||||||
error_setg_errno(errp, errno, "Failed to bind socket");
|
error_setg_errno(errp, errno, "Failed to bind socket");
|
||||||
close(sbind);
|
closesocket(sbind);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,11 +105,11 @@ void qcrypto_afalg_comm_free(QCryptoAFAlg *afalg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (afalg->tfmfd != -1) {
|
if (afalg->tfmfd != -1) {
|
||||||
close(afalg->tfmfd);
|
closesocket(afalg->tfmfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (afalg->opfd != -1) {
|
if (afalg->opfd != -1) {
|
||||||
close(afalg->opfd);
|
closesocket(afalg->opfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(afalg);
|
g_free(afalg);
|
||||||
|
|||||||
@@ -1014,7 +1014,6 @@ static const char rv_vreg_name_sym[32][4] = {
|
|||||||
#define rv_fmt_rd_offset "O\t0,o"
|
#define rv_fmt_rd_offset "O\t0,o"
|
||||||
#define rv_fmt_rd_rs1_rs2 "O\t0,1,2"
|
#define rv_fmt_rd_rs1_rs2 "O\t0,1,2"
|
||||||
#define rv_fmt_frd_rs1 "O\t3,1"
|
#define rv_fmt_frd_rs1 "O\t3,1"
|
||||||
#define rv_fmt_frd_frs1 "O\t3,4"
|
|
||||||
#define rv_fmt_rd_frs1 "O\t0,4"
|
#define rv_fmt_rd_frs1 "O\t0,4"
|
||||||
#define rv_fmt_rd_frs1_frs2 "O\t0,4,5"
|
#define rv_fmt_rd_frs1_frs2 "O\t0,4,5"
|
||||||
#define rv_fmt_frd_frs1_frs2 "O\t3,4,5"
|
#define rv_fmt_frd_frs1_frs2 "O\t3,4,5"
|
||||||
@@ -1581,15 +1580,15 @@ const rv_opcode_data opcode_data[] = {
|
|||||||
{ "snez", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
{ "snez", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
||||||
{ "sltz", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
{ "sltz", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "sgtz", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
{ "sgtz", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
||||||
{ "fmv.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fmv.s", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fabs.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fabs.s", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fneg.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fneg.s", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fmv.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fmv.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fabs.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fabs.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fneg.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fneg.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fmv.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fmv.q", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fabs.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fabs.q", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fneg.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fneg.q", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "beqz", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 },
|
{ "beqz", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 },
|
||||||
{ "bnez", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 },
|
{ "bnez", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 },
|
||||||
{ "blez", rv_codec_sb, rv_fmt_rs2_offset, NULL, 0, 0, 0 },
|
{ "blez", rv_codec_sb, rv_fmt_rs2_offset, NULL, 0, 0, 0 },
|
||||||
@@ -1646,9 +1645,9 @@ const rv_opcode_data opcode_data[] = {
|
|||||||
{ "max", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "max", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
{ "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
{ "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
{ "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "ctzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
{ "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "cpopw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
{ "cpopw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "slli.uw", rv_codec_i_sh6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 },
|
{ "slli.uw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 },
|
||||||
{ "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
{ "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
{ "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
@@ -2618,10 +2617,10 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
|||||||
switch (((inst >> 12) & 0b111)) {
|
switch (((inst >> 12) & 0b111)) {
|
||||||
case 0: op = rv_op_addiw; break;
|
case 0: op = rv_op_addiw; break;
|
||||||
case 1:
|
case 1:
|
||||||
switch (((inst >> 26) & 0b111111)) {
|
switch (((inst >> 25) & 0b1111111)) {
|
||||||
case 0: op = rv_op_slliw; break;
|
case 0: op = rv_op_slliw; break;
|
||||||
case 2: op = rv_op_slli_uw; break;
|
case 4: op = rv_op_slli_uw; break;
|
||||||
case 24:
|
case 48:
|
||||||
switch ((inst >> 20) & 0b11111) {
|
switch ((inst >> 20) & 0b11111) {
|
||||||
case 0b00000: op = rv_op_clzw; break;
|
case 0b00000: op = rv_op_clzw; break;
|
||||||
case 0b00001: op = rv_op_ctzw; break;
|
case 0b00001: op = rv_op_ctzw; break;
|
||||||
|
|||||||
@@ -67,8 +67,7 @@ Non-supported architectures may be removed in the future following the
|
|||||||
Linux OS, macOS, FreeBSD, NetBSD, OpenBSD
|
Linux OS, macOS, FreeBSD, NetBSD, OpenBSD
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
The project aims to support the most recent major version at all times for
|
The project aims to support the most recent major version at all times. Support
|
||||||
up to five years after its initial release. Support
|
|
||||||
for the previous major version will be dropped 2 years after the new major
|
for the previous major version will be dropped 2 years after the new major
|
||||||
version is released or when the vendor itself drops support, whichever comes
|
version is released or when the vendor itself drops support, whichever comes
|
||||||
first. In this context, third-party efforts to extend the lifetime of a distro
|
first. In this context, third-party efforts to extend the lifetime of a distro
|
||||||
|
|||||||
@@ -196,17 +196,6 @@ CI coverage support may bitrot away before the deprecation process
|
|||||||
completes. The little endian variants of MIPS (both 32 and 64 bit) are
|
completes. The little endian variants of MIPS (both 32 and 64 bit) are
|
||||||
still a supported host architecture.
|
still a supported host architecture.
|
||||||
|
|
||||||
System emulation on 32-bit x86 hosts (since 8.0)
|
|
||||||
''''''''''''''''''''''''''''''''''''''''''''''''
|
|
||||||
|
|
||||||
Support for 32-bit x86 host deployments is increasingly uncommon in mainstream
|
|
||||||
OS distributions given the widespread availability of 64-bit x86 hardware.
|
|
||||||
The QEMU project no longer considers 32-bit x86 support for system emulation to
|
|
||||||
be an effective use of its limited resources, and thus intends to discontinue
|
|
||||||
it. Since all recent x86 hardware from the past >10 years is capable of the
|
|
||||||
64-bit x86 extensions, a corresponding 64-bit OS should be used instead.
|
|
||||||
|
|
||||||
|
|
||||||
QEMU API (QAPI) events
|
QEMU API (QAPI) events
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|||||||
@@ -56,10 +56,8 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "virt"
|
type = "virt"
|
||||||
gic-version = "host"
|
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
gic-version = "host"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
size = "1024"
|
size = "1024"
|
||||||
|
|||||||
@@ -62,10 +62,8 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "virt"
|
type = "virt"
|
||||||
gic-version = "host"
|
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
gic-version = "host"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
size = "1024"
|
size = "1024"
|
||||||
|
|||||||
@@ -61,8 +61,6 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "q35"
|
type = "q35"
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
|
|||||||
@@ -55,8 +55,6 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "q35"
|
type = "q35"
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
|
|||||||
@@ -60,8 +60,6 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "q35"
|
type = "q35"
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ provides macros that fall in three camps:
|
|||||||
|
|
||||||
- weak atomic access and manual memory barriers: ``qatomic_read()``,
|
- weak atomic access and manual memory barriers: ``qatomic_read()``,
|
||||||
``qatomic_set()``, ``smp_rmb()``, ``smp_wmb()``, ``smp_mb()``,
|
``qatomic_set()``, ``smp_rmb()``, ``smp_wmb()``, ``smp_mb()``,
|
||||||
``smp_mb_acquire()``, ``smp_mb_release()``, ``smp_read_barrier_depends()``,
|
``smp_mb_acquire()``, ``smp_mb_release()``, ``smp_read_barrier_depends()``;
|
||||||
``smp_mb__before_rmw()``, ``smp_mb__after_rmw()``;
|
|
||||||
|
|
||||||
- sequentially consistent atomic access: everything else.
|
- sequentially consistent atomic access: everything else.
|
||||||
|
|
||||||
@@ -469,19 +468,13 @@ and memory barriers, and the equivalents in QEMU:
|
|||||||
In QEMU, the second kind is named ``atomic_OP_fetch``.
|
In QEMU, the second kind is named ``atomic_OP_fetch``.
|
||||||
|
|
||||||
- different atomic read-modify-write operations in Linux imply
|
- different atomic read-modify-write operations in Linux imply
|
||||||
a different set of memory barriers. In QEMU, all of them enforce
|
a different set of memory barriers; in QEMU, all of them enforce
|
||||||
sequential consistency: there is a single order in which the
|
sequential consistency.
|
||||||
program sees them happen.
|
|
||||||
|
|
||||||
- however, according to the C11 memory model that QEMU uses, this order
|
- in QEMU, ``qatomic_read()`` and ``qatomic_set()`` do not participate in
|
||||||
does not propagate to other memory accesses on either side of the
|
the total ordering enforced by sequentially-consistent operations.
|
||||||
read-modify-write operation. As far as those are concerned, the
|
This is because QEMU uses the C11 memory model. The following example
|
||||||
operation consist of just a load-acquire followed by a store-release.
|
is correct in Linux but not in QEMU:
|
||||||
Stores that precede the RMW operation, and loads that follow it, can
|
|
||||||
still be reordered and will happen *in the middle* of the read-modify-write
|
|
||||||
operation!
|
|
||||||
|
|
||||||
Therefore, the following example is correct in Linux but not in QEMU:
|
|
||||||
|
|
||||||
+----------------------------------+--------------------------------+
|
+----------------------------------+--------------------------------+
|
||||||
| Linux (correct) | QEMU (incorrect) |
|
| Linux (correct) | QEMU (incorrect) |
|
||||||
@@ -495,24 +488,9 @@ and memory barriers, and the equivalents in QEMU:
|
|||||||
because the read of ``y`` can be moved (by either the processor or the
|
because the read of ``y`` can be moved (by either the processor or the
|
||||||
compiler) before the write of ``x``.
|
compiler) before the write of ``x``.
|
||||||
|
|
||||||
Fixing this requires a full memory barrier between the write of ``x`` and
|
Fixing this requires an ``smp_mb()`` memory barrier between the write
|
||||||
the read of ``y``. QEMU provides ``smp_mb__before_rmw()`` and
|
of ``x`` and the read of ``y``. In the common case where only one thread
|
||||||
``smp_mb__after_rmw()``; they act both as an optimization,
|
writes ``x``, it is also possible to write it like this:
|
||||||
avoiding the memory barrier on processors where it is unnecessary,
|
|
||||||
and as a clarification of this corner case of the C11 memory model:
|
|
||||||
|
|
||||||
+--------------------------------+
|
|
||||||
| QEMU (correct) |
|
|
||||||
+================================+
|
|
||||||
| :: |
|
|
||||||
| |
|
|
||||||
| a = qatomic_fetch_add(&x, 2);|
|
|
||||||
| smp_mb__after_rmw(); |
|
|
||||||
| b = qatomic_read(&y); |
|
|
||||||
+--------------------------------+
|
|
||||||
|
|
||||||
In the common case where only one thread writes ``x``, it is also possible
|
|
||||||
to write it like this:
|
|
||||||
|
|
||||||
+--------------------------------+
|
+--------------------------------+
|
||||||
| QEMU (correct) |
|
| QEMU (correct) |
|
||||||
|
|||||||
@@ -59,37 +59,22 @@ System memory dirty pages tracking
|
|||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
A ``log_global_start`` and ``log_global_stop`` memory listener callback informs
|
A ``log_global_start`` and ``log_global_stop`` memory listener callback informs
|
||||||
the VFIO dirty tracking module to start and stop dirty page tracking. A
|
the VFIO IOMMU module to start and stop dirty page tracking. A ``log_sync``
|
||||||
``log_sync`` memory listener callback queries the dirty page bitmap from the
|
memory listener callback marks those system memory pages as dirty which are
|
||||||
dirty tracking module and marks system memory pages which were DMA-ed by the
|
used for DMA by the VFIO device. The dirty pages bitmap is queried per
|
||||||
VFIO device as dirty. The dirty page bitmap is queried per container.
|
container. All pages pinned by the vendor driver through external APIs have to
|
||||||
|
be marked as dirty during migration. When there are CPU writes, CPU dirty page
|
||||||
Currently there are two ways dirty page tracking can be done:
|
tracking can identify dirtied pages, but any page pinned by the vendor driver
|
||||||
(1) Device dirty tracking:
|
can also be written by the device. There is currently no device or IOMMU
|
||||||
In this method the device is responsible to log and report its DMAs. This
|
support for dirty page tracking in hardware.
|
||||||
method can be used only if the device is capable of tracking its DMAs.
|
|
||||||
Discovering device capability, starting and stopping dirty tracking, and
|
|
||||||
syncing the dirty bitmaps from the device are done using the DMA logging uAPI.
|
|
||||||
More info about the uAPI can be found in the comments of the
|
|
||||||
``vfio_device_feature_dma_logging_control`` and
|
|
||||||
``vfio_device_feature_dma_logging_report`` structures in the header file
|
|
||||||
linux-headers/linux/vfio.h.
|
|
||||||
|
|
||||||
(2) VFIO IOMMU module:
|
|
||||||
In this method dirty tracking is done by IOMMU. However, there is currently no
|
|
||||||
IOMMU support for dirty page tracking. For this reason, all pages are
|
|
||||||
perpetually marked dirty, unless the device driver pins pages through external
|
|
||||||
APIs in which case only those pinned pages are perpetually marked dirty.
|
|
||||||
|
|
||||||
If the above two methods are not supported, all pages are perpetually marked
|
|
||||||
dirty by QEMU.
|
|
||||||
|
|
||||||
By default, dirty pages are tracked during pre-copy as well as stop-and-copy
|
By default, dirty pages are tracked during pre-copy as well as stop-and-copy
|
||||||
phase. So, a page marked as dirty will be copied to the destination in both
|
phase. So, a page pinned by the vendor driver will be copied to the destination
|
||||||
phases. Copying dirty pages in pre-copy phase helps QEMU to predict if it can
|
in both phases. Copying dirty pages in pre-copy phase helps QEMU to predict if
|
||||||
achieve its downtime tolerances. If QEMU during pre-copy phase keeps finding
|
it can achieve its downtime tolerances. If QEMU during pre-copy phase keeps
|
||||||
dirty pages continuously, then it understands that even in stop-and-copy phase,
|
finding dirty pages continuously, then it understands that even in stop-and-copy
|
||||||
it is likely to find dirty pages and can predict the downtime accordingly.
|
phase, it is likely to find dirty pages and can predict the downtime
|
||||||
|
accordingly.
|
||||||
|
|
||||||
QEMU also provides a per device opt-out option ``pre-copy-dirty-page-tracking``
|
QEMU also provides a per device opt-out option ``pre-copy-dirty-page-tracking``
|
||||||
which disables querying the dirty bitmap during pre-copy phase. If it is set to
|
which disables querying the dirty bitmap during pre-copy phase. If it is set to
|
||||||
@@ -104,8 +89,7 @@ phase of migration. In that case, the unmap ioctl returns any dirty pages in
|
|||||||
that range and QEMU reports corresponding guest physical pages dirty. During
|
that range and QEMU reports corresponding guest physical pages dirty. During
|
||||||
stop-and-copy phase, an IOMMU notifier is used to get a callback for mapped
|
stop-and-copy phase, an IOMMU notifier is used to get a callback for mapped
|
||||||
pages and then dirty pages bitmap is fetched from VFIO IOMMU modules for those
|
pages and then dirty pages bitmap is fetched from VFIO IOMMU modules for those
|
||||||
mapped ranges. If device dirty tracking is enabled with vIOMMU, live migration
|
mapped ranges.
|
||||||
will be blocked.
|
|
||||||
|
|
||||||
Flow of state changes during Live migration
|
Flow of state changes during Live migration
|
||||||
===========================================
|
===========================================
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ if sphinx_build.found()
|
|||||||
SPHINX_ARGS = ['env', 'CONFDIR=' + qemu_confdir, sphinx_build, '-q']
|
SPHINX_ARGS = ['env', 'CONFDIR=' + qemu_confdir, sphinx_build, '-q']
|
||||||
# If we're making warnings fatal, apply this to Sphinx runs as well
|
# If we're making warnings fatal, apply this to Sphinx runs as well
|
||||||
if get_option('werror')
|
if get_option('werror')
|
||||||
SPHINX_ARGS += [ '-W', '-Dkerneldoc_werror=1' ]
|
SPHINX_ARGS += [ '-W' ]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# This is a bit awkward but works: create a trivial document and
|
# This is a bit awkward but works: create a trivial document and
|
||||||
|
|||||||
@@ -74,10 +74,6 @@ class KernelDocDirective(Directive):
|
|||||||
# Sphinx versions
|
# Sphinx versions
|
||||||
cmd += ['-sphinx-version', sphinx.__version__]
|
cmd += ['-sphinx-version', sphinx.__version__]
|
||||||
|
|
||||||
# Pass through the warnings-as-errors flag
|
|
||||||
if env.config.kerneldoc_werror:
|
|
||||||
cmd += ['-Werror']
|
|
||||||
|
|
||||||
filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
|
filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
|
||||||
export_file_patterns = []
|
export_file_patterns = []
|
||||||
|
|
||||||
@@ -171,7 +167,6 @@ def setup(app):
|
|||||||
app.add_config_value('kerneldoc_bin', None, 'env')
|
app.add_config_value('kerneldoc_bin', None, 'env')
|
||||||
app.add_config_value('kerneldoc_srctree', None, 'env')
|
app.add_config_value('kerneldoc_srctree', None, 'env')
|
||||||
app.add_config_value('kerneldoc_verbosity', 1, 'env')
|
app.add_config_value('kerneldoc_verbosity', 1, 'env')
|
||||||
app.add_config_value('kerneldoc_werror', 0, 'env')
|
|
||||||
|
|
||||||
app.add_directive('kernel-doc', KernelDocDirective)
|
app.add_directive('kernel-doc', KernelDocDirective)
|
||||||
|
|
||||||
|
|||||||
@@ -177,32 +177,39 @@ are named with the prefix "kvm-". KVM VCPU features may be probed,
|
|||||||
enabled, and disabled in the same way as other CPU features. Below is
|
enabled, and disabled in the same way as other CPU features. Below is
|
||||||
the list of KVM VCPU features and their descriptions.
|
the list of KVM VCPU features and their descriptions.
|
||||||
|
|
||||||
``kvm-no-adjvtime``
|
kvm-no-adjvtime By default kvm-no-adjvtime is disabled. This
|
||||||
By default kvm-no-adjvtime is disabled. This means that by default
|
means that by default the virtual time
|
||||||
the virtual time adjustment is enabled (vtime is not *not* adjusted).
|
adjustment is enabled (vtime is not *not*
|
||||||
|
adjusted).
|
||||||
|
|
||||||
When virtual time adjustment is enabled each time the VM transitions
|
When virtual time adjustment is enabled each
|
||||||
back to running state the VCPU's virtual counter is updated to
|
time the VM transitions back to running state
|
||||||
ensure stopped time is not counted. This avoids time jumps
|
the VCPU's virtual counter is updated to ensure
|
||||||
surprising guest OSes and applications, as long as they use the
|
stopped time is not counted. This avoids time
|
||||||
virtual counter for timekeeping. However it has the side effect of
|
jumps surprising guest OSes and applications,
|
||||||
the virtual and physical counters diverging. All timekeeping based
|
as long as they use the virtual counter for
|
||||||
on the virtual counter will appear to lag behind any timekeeping
|
timekeeping. However it has the side effect of
|
||||||
that does not subtract VM stopped time. The guest may resynchronize
|
the virtual and physical counters diverging.
|
||||||
its virtual counter with other time sources as needed.
|
All timekeeping based on the virtual counter
|
||||||
|
will appear to lag behind any timekeeping that
|
||||||
|
does not subtract VM stopped time. The guest
|
||||||
|
may resynchronize its virtual counter with
|
||||||
|
other time sources as needed.
|
||||||
|
|
||||||
Enable kvm-no-adjvtime to disable virtual time adjustment, also
|
Enable kvm-no-adjvtime to disable virtual time
|
||||||
restoring the legacy (pre-5.0) behavior.
|
adjustment, also restoring the legacy (pre-5.0)
|
||||||
|
behavior.
|
||||||
|
|
||||||
``kvm-steal-time``
|
kvm-steal-time Since v5.2, kvm-steal-time is enabled by
|
||||||
Since v5.2, kvm-steal-time is enabled by default when KVM is
|
default when KVM is enabled, the feature is
|
||||||
enabled, the feature is supported, and the guest is 64-bit.
|
supported, and the guest is 64-bit.
|
||||||
|
|
||||||
When kvm-steal-time is enabled a 64-bit guest can account for time
|
When kvm-steal-time is enabled a 64-bit guest
|
||||||
its CPUs were not running due to the host not scheduling the
|
can account for time its CPUs were not running
|
||||||
corresponding VCPU threads. The accounting statistics may influence
|
due to the host not scheduling the corresponding
|
||||||
the guest scheduler behavior and/or be exposed to the guest
|
VCPU threads. The accounting statistics may
|
||||||
userspace.
|
influence the guest scheduler behavior and/or be
|
||||||
|
exposed to the guest userspace.
|
||||||
|
|
||||||
TCG VCPU Features
|
TCG VCPU Features
|
||||||
=================
|
=================
|
||||||
@@ -210,15 +217,16 @@ TCG VCPU Features
|
|||||||
TCG VCPU features are CPU features that are specific to TCG.
|
TCG VCPU features are CPU features that are specific to TCG.
|
||||||
Below is the list of TCG VCPU features and their descriptions.
|
Below is the list of TCG VCPU features and their descriptions.
|
||||||
|
|
||||||
``pauth-impdef``
|
pauth-impdef When ``FEAT_Pauth`` is enabled, either the
|
||||||
When ``FEAT_Pauth`` is enabled, either the *impdef* (Implementation
|
*impdef* (Implementation Defined) algorithm
|
||||||
Defined) algorithm is enabled or the *architected* QARMA algorithm
|
is enabled or the *architected* QARMA algorithm
|
||||||
is enabled. By default the impdef algorithm is disabled, and QARMA
|
is enabled. By default the impdef algorithm
|
||||||
is enabled.
|
is disabled, and QARMA is enabled.
|
||||||
|
|
||||||
The architected QARMA algorithm has good cryptographic properties,
|
The architected QARMA algorithm has good
|
||||||
but can be quite slow to emulate. The impdef algorithm used by QEMU
|
cryptographic properties, but can be quite slow
|
||||||
is non-cryptographic but significantly faster.
|
to emulate. The impdef algorithm used by QEMU
|
||||||
|
is non-cryptographic but significantly faster.
|
||||||
|
|
||||||
SVE CPU Properties
|
SVE CPU Properties
|
||||||
==================
|
==================
|
||||||
|
|||||||
@@ -93,4 +93,3 @@ Emulated Devices
|
|||||||
devices/virtio-pmem.rst
|
devices/virtio-pmem.rst
|
||||||
devices/vhost-user-rng.rst
|
devices/vhost-user-rng.rst
|
||||||
devices/canokey.rst
|
devices/canokey.rst
|
||||||
devices/igb.rst
|
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
.. _igb:
|
|
||||||
|
|
||||||
igb
|
|
||||||
---
|
|
||||||
|
|
||||||
igb is a family of Intel's gigabit ethernet controllers. In QEMU, 82576
|
|
||||||
emulation is implemented in particular. Its datasheet is available at [1]_.
|
|
||||||
|
|
||||||
This implementation is expected to be useful to test SR-IOV networking without
|
|
||||||
requiring physical hardware.
|
|
||||||
|
|
||||||
Limitations
|
|
||||||
===========
|
|
||||||
|
|
||||||
This igb implementation was tested with Linux Test Project [2]_ and Windows HLK
|
|
||||||
[3]_ during the initial development. The command used when testing with LTP is:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
network.sh -6mta
|
|
||||||
|
|
||||||
Be aware that this implementation lacks many functionalities available with the
|
|
||||||
actual hardware, and you may experience various failures if you try to use it
|
|
||||||
with a different operating system other than Linux and Windows or if you try
|
|
||||||
functionalities not covered by the tests.
|
|
||||||
|
|
||||||
Using igb
|
|
||||||
=========
|
|
||||||
|
|
||||||
Using igb should be nothing different from using another network device. See
|
|
||||||
:ref:`pcsys_005fnetwork` in general.
|
|
||||||
|
|
||||||
However, you may also need to perform additional steps to activate SR-IOV
|
|
||||||
feature on your guest. For Linux, refer to [4]_.
|
|
||||||
|
|
||||||
Developing igb
|
|
||||||
==============
|
|
||||||
|
|
||||||
igb is the successor of e1000e, and e1000e is the successor of e1000 in turn.
|
|
||||||
As these devices are very similar, if you make a change for igb and the same
|
|
||||||
change can be applied to e1000e and e1000, please do so.
|
|
||||||
|
|
||||||
Please do not forget to run tests before submitting a change. As tests included
|
|
||||||
in QEMU is very minimal, run some application which is likely to be affected by
|
|
||||||
the change to confirm it works in an integrated system.
|
|
||||||
|
|
||||||
Testing igb
|
|
||||||
===========
|
|
||||||
|
|
||||||
A qtest of the basic functionality is available. Run the below at the build
|
|
||||||
directory:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
meson test qtest-x86_64/qos-test
|
|
||||||
|
|
||||||
ethtool can test register accesses, interrupts, etc. It is automated as an
|
|
||||||
Avocado test and can be ran with the following command:
|
|
||||||
|
|
||||||
.. code:: shell
|
|
||||||
|
|
||||||
make check-avocado AVOCADO_TESTS=tests/avocado/igb.py
|
|
||||||
|
|
||||||
References
|
|
||||||
==========
|
|
||||||
|
|
||||||
.. [1] https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eb-gigabit-ethernet-controller-datasheet.pdf
|
|
||||||
.. [2] https://github.com/linux-test-project/ltp
|
|
||||||
.. [3] https://learn.microsoft.com/en-us/windows-hardware/test/hlk/
|
|
||||||
.. [4] https://docs.kernel.org/PCI/pci-iov-howto.html
|
|
||||||
@@ -9,8 +9,6 @@ KVM has support for hosting Xen guests, intercepting Xen hypercalls and event
|
|||||||
channel (Xen PV interrupt) delivery. This allows guests which expect to be
|
channel (Xen PV interrupt) delivery. This allows guests which expect to be
|
||||||
run under Xen to be hosted in QEMU under Linux/KVM instead.
|
run under Xen to be hosted in QEMU under Linux/KVM instead.
|
||||||
|
|
||||||
Using the split irqchip is mandatory for Xen support.
|
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@@ -19,14 +17,14 @@ accelerator, for example for Xen 4.10:
|
|||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
|qemu_system| --accel kvm,xen-version=0x4000a,kernel-irqchip=split
|
|qemu_system| --accel kvm,xen-version=0x4000a
|
||||||
|
|
||||||
Additionally, virtual APIC support can be advertised to the guest through the
|
Additionally, virtual APIC support can be advertised to the guest through the
|
||||||
``xen-vapic`` CPU flag:
|
``xen-vapic`` CPU flag:
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
|qemu_system| --accel kvm,xen-version=0x4000a,kernel-irqchip=split --cpu host,+xen_vapic
|
|qemu_system| --accel kvm,xen-version=0x4000a --cpu host,+xen_vapic
|
||||||
|
|
||||||
When Xen support is enabled, QEMU changes hypervisor identification (CPUID
|
When Xen support is enabled, QEMU changes hypervisor identification (CPUID
|
||||||
0x40000000..0x4000000A) to Xen. The KVM identification and features are not
|
0x40000000..0x4000000A) to Xen. The KVM identification and features are not
|
||||||
@@ -35,25 +33,11 @@ moves to leaves 0x40000100..0x4000010A.
|
|||||||
|
|
||||||
The Xen platform device is enabled automatically for a Xen guest. This allows
|
The Xen platform device is enabled automatically for a Xen guest. This allows
|
||||||
a guest to unplug all emulated devices, in order to use Xen PV block and network
|
a guest to unplug all emulated devices, in order to use Xen PV block and network
|
||||||
drivers instead. Under Xen, the boot disk is typically available both via IDE
|
drivers instead. Note that until the Xen PV device back ends are enabled to work
|
||||||
emulation, and as a PV block device. Guest bootloaders typically use IDE to load
|
with Xen mode in QEMU, that is unlikely to cause significant joy. Linux guests
|
||||||
the guest kernel, which then unplugs the IDE and continues with the Xen PV block
|
can be dissuaded from this by adding 'xen_emul_unplug=never' on their command
|
||||||
device.
|
line, and it can also be noted that AHCI disk controllers are exempt from being
|
||||||
|
unplugged, as are passthrough VFIO PCI devices.
|
||||||
This configuration can be achieved as follows
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
|qemu_system| -M pc --accel kvm,xen-version=0x4000a,kernel-irqchip=split \\
|
|
||||||
-drive file=${GUEST_IMAGE},if=none,id=disk,file.locking=off -device xen-disk,drive=disk,vdev=xvda \\
|
|
||||||
-drive file=${GUEST_IMAGE},index=2,media=disk,file.locking=off,if=ide
|
|
||||||
|
|
||||||
It is necessary to use the pc machine type, as the q35 machine uses AHCI instead
|
|
||||||
of legacy IDE, and AHCI disks are not unplugged through the Xen PV unplug
|
|
||||||
mechanism.
|
|
||||||
|
|
||||||
VirtIO devices can also be used; Linux guests may need to be dissuaded from
|
|
||||||
umplugging them by adding 'xen_emul_unplug=never' on their command line.
|
|
||||||
|
|
||||||
Properties
|
Properties
|
||||||
----------
|
----------
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ endian options, ``qemu-system-mips``, ``qemu-system-mipsel``
|
|||||||
``qemu-system-mips64`` and ``qemu-system-mips64el``. Five different
|
``qemu-system-mips64`` and ``qemu-system-mips64el``. Five different
|
||||||
machine types are emulated:
|
machine types are emulated:
|
||||||
|
|
||||||
|
- A generic ISA PC-like machine \"mips\"
|
||||||
|
|
||||||
- The MIPS Malta prototype board \"malta\"
|
- The MIPS Malta prototype board \"malta\"
|
||||||
|
|
||||||
- An ACER Pica \"pica61\". This machine needs the 64-bit emulator.
|
- An ACER Pica \"pica61\". This machine needs the 64-bit emulator.
|
||||||
@@ -17,6 +19,18 @@ machine types are emulated:
|
|||||||
- A MIPS Magnum R4000 machine \"magnum\". This machine needs the
|
- A MIPS Magnum R4000 machine \"magnum\". This machine needs the
|
||||||
64-bit emulator.
|
64-bit emulator.
|
||||||
|
|
||||||
|
The generic emulation is supported by Debian 'Etch' and is able to
|
||||||
|
install Debian into a virtual disk image. The following devices are
|
||||||
|
emulated:
|
||||||
|
|
||||||
|
- A range of MIPS CPUs, default is the 24Kf
|
||||||
|
|
||||||
|
- PC style serial port
|
||||||
|
|
||||||
|
- PC style IDE disk
|
||||||
|
|
||||||
|
- NE2000 network card
|
||||||
|
|
||||||
The Malta emulation supports the following devices:
|
The Malta emulation supports the following devices:
|
||||||
|
|
||||||
- Core board with MIPS 24Kf CPU and Galileo system controller
|
- Core board with MIPS 24Kf CPU and Galileo system controller
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include "qapi/qapi-commands-dump.h"
|
#include "qapi/qapi-commands-dump.h"
|
||||||
#include "qapi/qapi-events-dump.h"
|
#include "qapi/qapi-events-dump.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "hw/misc/vmcoreinfo.h"
|
#include "hw/misc/vmcoreinfo.h"
|
||||||
#include "migration/blocker.h"
|
#include "migration/blocker.h"
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sysemu/dump.h"
|
#include "sysemu/dump.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "exec/cpu-defs.h"
|
#include "exec/cpu-defs.h"
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user