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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
if (cflags & CF_PCREL) {
|
|
||||||
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. */
|
/* Use the pc value already stored in tb->pc. */
|
||||||
qatomic_set(&jc->array[h].tb, tb);
|
qatomic_set(&cpu->tb_jmp_cache->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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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);
|
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;
|
||||||
|
|||||||
388
audio/audio.c
388
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;
|
||||||
|
blck = MIN (dead, left);
|
||||||
|
if (!blck) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
isamp = samples;
|
||||||
|
osamp = blck;
|
||||||
|
st_rate_flow_mix (
|
||||||
|
sw->rate,
|
||||||
|
sw->buf + pos,
|
||||||
|
sw->hw->mix_buf->samples + wpos,
|
||||||
|
&isamp,
|
||||||
|
&osamp
|
||||||
|
);
|
||||||
|
ret += isamp;
|
||||||
|
samples -= isamp;
|
||||||
|
pos += isamp;
|
||||||
|
live += osamp;
|
||||||
|
wpos = (wpos + osamp) % hwsamples;
|
||||||
|
total += osamp;
|
||||||
|
}
|
||||||
|
|
||||||
sw->total_hw_samples_mixed += total_out;
|
sw->total_hw_samples_mixed += total;
|
||||||
sw->empty = sw->total_hw_samples_mixed == 0;
|
sw->empty = sw->total_hw_samples_mixed == 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* Upsampling may leave one audio frame in the resample buffer. Decrement
|
|
||||||
* total_in by one if there was a leftover frame from the previous resample
|
|
||||||
* pass in the resample buffer. Increment total_in by one if the current
|
|
||||||
* resample pass left one frame in the resample buffer.
|
|
||||||
*/
|
|
||||||
if (frames_in_max - total_in == 1) {
|
|
||||||
/* copy one leftover audio frame to the beginning of the buffer */
|
|
||||||
*sw->resample_buf.buffer = *(sw->resample_buf.buffer + total_in);
|
|
||||||
total_in += 1 - sw->resample_buf.pos;
|
|
||||||
sw->resample_buf.pos = 1;
|
|
||||||
} else if (total_in >= sw->resample_buf.pos) {
|
|
||||||
total_in -= sw->resample_buf.pos;
|
|
||||||
sw->resample_buf.pos = 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,7 +63,7 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,9 +71,8 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
|
|||||||
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) {
|
||||||
|
|
||||||
|
/* Safety catch to make sure we have input samples. */
|
||||||
if (ibuf >= iend) {
|
if (ibuf >= iend) {
|
||||||
*osamp = 0;
|
break;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ilast = rate->ilast;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
/* 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,
|
|
||||||
CryptoDevBackendOpInfo *op_info)
|
|
||||||
{
|
|
||||||
enum QCryptodevBackendAlgType algtype = op_info->algtype;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
|
|
||||||
CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
|
|
||||||
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);
|
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
int cryptodev_backend_crypto_operation(
|
||||||
CryptoDevBackend *backend,
|
CryptoDevBackend *backend,
|
||||||
CryptoDevBackendOpInfo *op_info)
|
void *opaque1,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb, void *opaque2)
|
||||||
{
|
{
|
||||||
int ret;
|
VirtIOCryptoReq *req = opaque1;
|
||||||
|
CryptoDevBackendOpInfo *op_info = &req->op_info;
|
||||||
|
enum CryptoDevBackendAlgType algtype = req->flags;
|
||||||
|
|
||||||
if (!throttle_enabled(&backend->tc)) {
|
if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
|
||||||
goto do_account;
|
&& (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
|
||||||
|
error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
|
||||||
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (throttle_schedule_timer(&backend->ts, &backend->tt, true) ||
|
return cryptodev_backend_operation(backend, op_info, queue_index,
|
||||||
!QTAILQ_EMPTY(&backend->opinfos)) {
|
cb, opaque2);
|
||||||
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,8 +22,7 @@ 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;
|
||||||
@@ -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"
|
||||||
|
|||||||
14
block/nfs.c
14
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"
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
@@ -303,7 +300,6 @@ 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)) {
|
|
||||||
kernel_found = true;
|
|
||||||
break;
|
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;
|
||||||
|
|||||||
@@ -88,20 +88,6 @@ typedef struct IMAGE_NT_HEADERS64 {
|
|||||||
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;
|
||||||
@@ -116,7 +102,6 @@ typedef struct 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,14 +217,15 @@ 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
|
||||||
|
to emulate. The impdef algorithm used by QEMU
|
||||||
is non-cryptographic but significantly faster.
|
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"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user