Compare commits
16 Commits
v8.0.0-rc2
...
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
|
||||||
@@ -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>
|
||||||
|
|||||||
64
MAINTAINERS
64
MAINTAINERS
@@ -136,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
|
||||||
@@ -257,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
|
||||||
@@ -371,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
|
||||||
@@ -446,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
|
||||||
@@ -1011,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
|
||||||
@@ -1898,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
|
||||||
@@ -2237,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>
|
||||||
@@ -2522,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
|
||||||
@@ -2668,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
|
||||||
@@ -2767,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>
|
||||||
@@ -2819,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/
|
||||||
@@ -2903,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>
|
||||||
@@ -3345,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>
|
||||||
@@ -3364,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
|
||||||
@@ -3819,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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1003,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);
|
||||||
@@ -1027,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"
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "hw/xen/xen_native.h"
|
|
||||||
#include "hw/xen/xen-legacy-backend.h"
|
#include "hw/xen/xen-legacy-backend.h"
|
||||||
#include "hw/xen/xen_pt.h"
|
#include "hw/xen/xen_pt.h"
|
||||||
#include "chardev/char.h"
|
#include "chardev/char.h"
|
||||||
@@ -30,12 +29,83 @@ xc_interface *xen_xc;
|
|||||||
xenforeignmemory_handle *xen_fmem;
|
xenforeignmemory_handle *xen_fmem;
|
||||||
xendevicemodel_handle *xen_dmod;
|
xendevicemodel_handle *xen_dmod;
|
||||||
|
|
||||||
static void xenstore_record_dm_state(const char *state)
|
static int store_dev_info(int domid, Chardev *cs, const char *string)
|
||||||
|
{
|
||||||
|
struct xs_handle *xs = NULL;
|
||||||
|
char *path = NULL;
|
||||||
|
char *newpath = NULL;
|
||||||
|
char *pts = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
/* Only continue if we're talking to a pty. */
|
||||||
|
if (!CHARDEV_IS_PTY(cs)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pts = cs->filename + 4;
|
||||||
|
|
||||||
|
/* We now have everything we need to set the xenstore entry. */
|
||||||
|
xs = xs_open(0);
|
||||||
|
if (xs == NULL) {
|
||||||
|
fprintf(stderr, "Could not contact XenStore\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = xs_get_domain_path(xs, domid);
|
||||||
|
if (path == NULL) {
|
||||||
|
fprintf(stderr, "xs_get_domain_path() error\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
newpath = realloc(path, (strlen(path) + strlen(string) +
|
||||||
|
strlen("/tty") + 1));
|
||||||
|
if (newpath == NULL) {
|
||||||
|
fprintf(stderr, "realloc error\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
path = newpath;
|
||||||
|
|
||||||
|
strcat(path, string);
|
||||||
|
strcat(path, "/tty");
|
||||||
|
if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) {
|
||||||
|
fprintf(stderr, "xs_write for '%s' fail", string);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(path);
|
||||||
|
xs_close(xs);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xenstore_store_pv_console_info(int i, Chardev *chr)
|
||||||
|
{
|
||||||
|
if (i == 0) {
|
||||||
|
store_dev_info(xen_domid, chr, "/console");
|
||||||
|
} else {
|
||||||
|
char buf[32];
|
||||||
|
snprintf(buf, sizeof(buf), "/device/console/%d", i);
|
||||||
|
store_dev_info(xen_domid, chr, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void xenstore_record_dm_state(struct xs_handle *xs, const char *state)
|
||||||
{
|
{
|
||||||
char path[50];
|
char path[50];
|
||||||
|
|
||||||
|
if (xs == NULL) {
|
||||||
|
error_report("xenstore connection not initialized");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(path, sizeof (path), "device-model/%u/state", xen_domid);
|
snprintf(path, sizeof (path), "device-model/%u/state", xen_domid);
|
||||||
if (!qemu_xen_xs_write(xenstore, XBT_NULL, path, state, strlen(state))) {
|
/*
|
||||||
|
* This call may fail when running restricted so don't make it fatal in
|
||||||
|
* that case. Toolstacks should instead use QMP to listen for state changes.
|
||||||
|
*/
|
||||||
|
if (!xs_write(xs, XBT_NULL, path, state, strlen(state)) &&
|
||||||
|
!xen_domid_restrict) {
|
||||||
error_report("error recording dm state");
|
error_report("error recording dm state");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -47,7 +117,7 @@ static void xen_change_state_handler(void *opaque, bool running,
|
|||||||
{
|
{
|
||||||
if (running) {
|
if (running) {
|
||||||
/* record state running */
|
/* record state running */
|
||||||
xenstore_record_dm_state("running");
|
xenstore_record_dm_state(xenstore, "running");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,15 +166,7 @@ static int xen_init(MachineState *ms)
|
|||||||
xc_interface_close(xen_xc);
|
xc_interface_close(xen_xc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
qemu_add_vm_change_state_handler(xen_change_state_handler, NULL);
|
||||||
/*
|
|
||||||
* The XenStore write would fail when running restricted so don't attempt
|
|
||||||
* it in that case. Toolstacks should instead use QMP to listen for state
|
|
||||||
* changes.
|
|
||||||
*/
|
|
||||||
if (!xen_domid_restrict) {
|
|
||||||
qemu_add_vm_change_state_handler(xen_change_state_handler, NULL);
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* opt out of system RAM being allocated by generic code
|
* opt out of system RAM being allocated by generic code
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -222,7 +222,11 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pfds = g_new0(struct pollfd, count);
|
pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
|
||||||
|
if (!pfds) {
|
||||||
|
dolog ("Could not initialize poll mode\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
err = snd_pcm_poll_descriptors (handle, pfds, count);
|
err = snd_pcm_poll_descriptors (handle, pfds, count);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
@@ -913,23 +917,28 @@ static void *alsa_audio_init(Audiodev *dev)
|
|||||||
alsa_init_per_direction(aopts->in);
|
alsa_init_per_direction(aopts->in);
|
||||||
alsa_init_per_direction(aopts->out);
|
alsa_init_per_direction(aopts->out);
|
||||||
|
|
||||||
/* don't set has_* so alsa_open can identify it wasn't set by the user */
|
/*
|
||||||
|
* need to define them, as otherwise alsa produces no sound
|
||||||
|
* doesn't set has_* so alsa_open can identify it wasn't set by the user
|
||||||
|
*/
|
||||||
if (!dev->u.alsa.out->has_period_length) {
|
if (!dev->u.alsa.out->has_period_length) {
|
||||||
/* 256 frames assuming 44100Hz */
|
/* 1024 frames assuming 44100Hz */
|
||||||
dev->u.alsa.out->period_length = 5805;
|
dev->u.alsa.out->period_length = 1024 * 1000000 / 44100;
|
||||||
}
|
}
|
||||||
if (!dev->u.alsa.out->has_buffer_length) {
|
if (!dev->u.alsa.out->has_buffer_length) {
|
||||||
/* 4096 frames assuming 44100Hz */
|
/* 4096 frames assuming 44100Hz */
|
||||||
dev->u.alsa.out->buffer_length = 92880;
|
dev->u.alsa.out->buffer_length = 4096ll * 1000000 / 44100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OptsVisitor sets unspecified optional fields to zero, but do not depend
|
||||||
|
* on it...
|
||||||
|
*/
|
||||||
if (!dev->u.alsa.in->has_period_length) {
|
if (!dev->u.alsa.in->has_period_length) {
|
||||||
/* 256 frames assuming 44100Hz */
|
dev->u.alsa.in->period_length = 0;
|
||||||
dev->u.alsa.in->period_length = 5805;
|
|
||||||
}
|
}
|
||||||
if (!dev->u.alsa.in->has_buffer_length) {
|
if (!dev->u.alsa.in->has_buffer_length) {
|
||||||
/* 4096 frames assuming 44100Hz */
|
dev->u.alsa.in->buffer_length = 0;
|
||||||
dev->u.alsa.in->buffer_length = 92880;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
|
|||||||
390
audio/audio.c
390
audio/audio.c
@@ -33,7 +33,6 @@
|
|||||||
#include "qapi/qapi-visit-audio.h"
|
#include "qapi/qapi-visit-audio.h"
|
||||||
#include "qapi/qapi-commands-audio.h"
|
#include "qapi/qapi-commands-audio.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/log.h"
|
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qemu/help_option.h"
|
#include "qemu/help_option.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
@@ -149,6 +148,26 @@ static inline int audio_bits_to_index (int bits)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *audio_calloc (const char *funcname, int nmemb, size_t size)
|
||||||
|
{
|
||||||
|
int cond;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = nmemb * size;
|
||||||
|
cond = !nmemb || !size;
|
||||||
|
cond |= nmemb < 0;
|
||||||
|
cond |= len < size;
|
||||||
|
|
||||||
|
if (audio_bug ("audio_calloc", cond)) {
|
||||||
|
AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
|
||||||
|
funcname);
|
||||||
|
AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_malloc0 (len);
|
||||||
|
}
|
||||||
|
|
||||||
void AUD_vlog (const char *cap, const char *fmt, va_list ap)
|
void AUD_vlog (const char *cap, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
if (cap) {
|
if (cap) {
|
||||||
@@ -381,6 +400,13 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
|||||||
/*
|
/*
|
||||||
* Capture
|
* Capture
|
||||||
*/
|
*/
|
||||||
|
static void noop_conv (struct st_sample *dst, const void *src, int samples)
|
||||||
|
{
|
||||||
|
(void) src;
|
||||||
|
(void) dst;
|
||||||
|
(void) samples;
|
||||||
|
}
|
||||||
|
|
||||||
static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
|
static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
|
||||||
struct audsettings *as)
|
struct audsettings *as)
|
||||||
{
|
{
|
||||||
@@ -478,8 +504,15 @@ static int audio_attach_capture (HWVoiceOut *hw)
|
|||||||
sw->info = hw->info;
|
sw->info = hw->info;
|
||||||
sw->empty = 1;
|
sw->empty = 1;
|
||||||
sw->active = hw->enabled;
|
sw->active = hw->enabled;
|
||||||
|
sw->conv = noop_conv;
|
||||||
|
sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
|
||||||
sw->vol = nominal_volume;
|
sw->vol = nominal_volume;
|
||||||
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
|
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
|
||||||
|
if (!sw->rate) {
|
||||||
|
dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
|
||||||
|
g_free (sw);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
|
QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
|
||||||
QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
|
QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
|
||||||
#ifdef DEBUG_CAPTURE
|
#ifdef DEBUG_CAPTURE
|
||||||
@@ -514,8 +547,8 @@ static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
|
|||||||
static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
|
static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
|
||||||
{
|
{
|
||||||
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
|
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
|
||||||
if (audio_bug(__func__, live > hw->conv_buf.size)) {
|
if (audio_bug(__func__, live > hw->conv_buf->size)) {
|
||||||
dolog("live=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
|
dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return live;
|
return live;
|
||||||
@@ -524,13 +557,13 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
|
|||||||
static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
|
static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
|
||||||
{
|
{
|
||||||
size_t conv = 0;
|
size_t conv = 0;
|
||||||
STSampleBuffer *conv_buf = &hw->conv_buf;
|
STSampleBuffer *conv_buf = hw->conv_buf;
|
||||||
|
|
||||||
while (samples) {
|
while (samples) {
|
||||||
uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
|
uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
|
||||||
size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
|
size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
|
||||||
|
|
||||||
hw->conv(conv_buf->buffer + conv_buf->pos, src, proc);
|
hw->conv(conv_buf->samples + conv_buf->pos, src, proc);
|
||||||
conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
|
conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
|
||||||
samples -= proc;
|
samples -= proc;
|
||||||
conv += proc;
|
conv += proc;
|
||||||
@@ -542,65 +575,56 @@ static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
|
|||||||
/*
|
/*
|
||||||
* Soft voice (capture)
|
* Soft voice (capture)
|
||||||
*/
|
*/
|
||||||
static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
|
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||||
size_t frames_in_max, size_t frames_out_max,
|
|
||||||
size_t *total_in, size_t *total_out)
|
|
||||||
{
|
{
|
||||||
HWVoiceIn *hw = sw->hw;
|
HWVoiceIn *hw = sw->hw;
|
||||||
struct st_sample *src, *dst;
|
size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
|
||||||
size_t live, rpos, frames_in, frames_out;
|
struct st_sample *src, *dst = sw->buf;
|
||||||
|
|
||||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
|
||||||
rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
|
|
||||||
|
|
||||||
/* resample conv_buf from rpos to end of buffer */
|
|
||||||
src = hw->conv_buf.buffer + rpos;
|
|
||||||
frames_in = MIN(frames_in_max, hw->conv_buf.size - rpos);
|
|
||||||
dst = sw->resample_buf.buffer;
|
|
||||||
frames_out = frames_out_max;
|
|
||||||
st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
|
|
||||||
rpos += frames_in;
|
|
||||||
*total_in = frames_in;
|
|
||||||
*total_out = frames_out;
|
|
||||||
|
|
||||||
/* resample conv_buf from start of buffer if there are input frames left */
|
|
||||||
if (frames_in_max - frames_in && rpos == hw->conv_buf.size) {
|
|
||||||
src = hw->conv_buf.buffer;
|
|
||||||
frames_in = frames_in_max - frames_in;
|
|
||||||
dst += frames_out;
|
|
||||||
frames_out = frames_out_max - frames_out;
|
|
||||||
st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
|
|
||||||
*total_in += frames_in;
|
|
||||||
*total_out += frames_out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
|
|
||||||
{
|
|
||||||
HWVoiceIn *hw = sw->hw;
|
|
||||||
size_t live, frames_out_max, total_in, total_out;
|
|
||||||
|
|
||||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
if (!live) {
|
if (!live) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (audio_bug(__func__, live > hw->conv_buf.size)) {
|
if (audio_bug(__func__, live > hw->conv_buf->size)) {
|
||||||
dolog("live_in=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
|
dolog("live_in=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
frames_out_max = MIN(buf_len / sw->info.bytes_per_frame,
|
rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size);
|
||||||
sw->resample_buf.size);
|
|
||||||
|
|
||||||
audio_pcm_sw_resample_in(sw, live, frames_out_max, &total_in, &total_out);
|
samples = size / sw->info.bytes_per_frame;
|
||||||
|
|
||||||
|
swlim = (live * sw->ratio) >> 32;
|
||||||
|
swlim = MIN (swlim, samples);
|
||||||
|
|
||||||
|
while (swlim) {
|
||||||
|
src = hw->conv_buf->samples + rpos;
|
||||||
|
if (hw->conv_buf->pos > rpos) {
|
||||||
|
isamp = hw->conv_buf->pos - rpos;
|
||||||
|
} else {
|
||||||
|
isamp = hw->conv_buf->size - rpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isamp) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
osamp = swlim;
|
||||||
|
|
||||||
|
st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
|
||||||
|
swlim -= osamp;
|
||||||
|
rpos = (rpos + isamp) % hw->conv_buf->size;
|
||||||
|
dst += osamp;
|
||||||
|
ret += osamp;
|
||||||
|
total += isamp;
|
||||||
|
}
|
||||||
|
|
||||||
if (!hw->pcm_ops->volume_in) {
|
if (!hw->pcm_ops->volume_in) {
|
||||||
mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
|
mixeng_volume (sw->buf, ret, &sw->vol);
|
||||||
}
|
}
|
||||||
sw->clip(buf, sw->resample_buf.buffer, total_out);
|
|
||||||
|
|
||||||
sw->total_hw_samples_acquired += total_in;
|
sw->clip (buf, sw->buf, ret);
|
||||||
return total_out * sw->info.bytes_per_frame;
|
sw->total_hw_samples_acquired += total;
|
||||||
|
return ret * sw->info.bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -636,8 +660,8 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
|||||||
if (nb_live1) {
|
if (nb_live1) {
|
||||||
size_t live = smin;
|
size_t live = smin;
|
||||||
|
|
||||||
if (audio_bug(__func__, live > hw->mix_buf.size)) {
|
if (audio_bug(__func__, live > hw->mix_buf->size)) {
|
||||||
dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
|
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return live;
|
return live;
|
||||||
@@ -654,17 +678,17 @@ static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)
|
|||||||
static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
|
static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
|
||||||
{
|
{
|
||||||
size_t clipped = 0;
|
size_t clipped = 0;
|
||||||
size_t pos = hw->mix_buf.pos;
|
size_t pos = hw->mix_buf->pos;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
st_sample *src = hw->mix_buf.buffer + pos;
|
st_sample *src = hw->mix_buf->samples + pos;
|
||||||
uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
|
uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
|
||||||
size_t samples_till_end_of_buf = hw->mix_buf.size - pos;
|
size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
|
||||||
size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
|
size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
|
||||||
|
|
||||||
hw->clip(dst, src, samples_to_clip);
|
hw->clip(dst, src, samples_to_clip);
|
||||||
|
|
||||||
pos = (pos + samples_to_clip) % hw->mix_buf.size;
|
pos = (pos + samples_to_clip) % hw->mix_buf->size;
|
||||||
len -= samples_to_clip;
|
len -= samples_to_clip;
|
||||||
clipped += samples_to_clip;
|
clipped += samples_to_clip;
|
||||||
}
|
}
|
||||||
@@ -673,113 +697,84 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
|
|||||||
/*
|
/*
|
||||||
* Soft voice (playback)
|
* Soft voice (playback)
|
||||||
*/
|
*/
|
||||||
static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
|
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||||
size_t frames_in_max, size_t frames_out_max,
|
|
||||||
size_t *total_in, size_t *total_out)
|
|
||||||
{
|
{
|
||||||
HWVoiceOut *hw = sw->hw;
|
size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
|
||||||
struct st_sample *src, *dst;
|
size_t hw_free;
|
||||||
size_t live, wpos, frames_in, frames_out;
|
size_t ret = 0, pos = 0, total = 0;
|
||||||
|
|
||||||
live = sw->total_hw_samples_mixed;
|
if (!sw) {
|
||||||
wpos = (hw->mix_buf.pos + live) % hw->mix_buf.size;
|
return size;
|
||||||
|
|
||||||
/* write to mix_buf from wpos to end of buffer */
|
|
||||||
src = sw->resample_buf.buffer;
|
|
||||||
frames_in = frames_in_max;
|
|
||||||
dst = hw->mix_buf.buffer + wpos;
|
|
||||||
frames_out = MIN(frames_out_max, hw->mix_buf.size - wpos);
|
|
||||||
st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
|
|
||||||
wpos += frames_out;
|
|
||||||
*total_in = frames_in;
|
|
||||||
*total_out = frames_out;
|
|
||||||
|
|
||||||
/* write to mix_buf from start of buffer if there are input frames left */
|
|
||||||
if (frames_in_max - frames_in > 0 && wpos == hw->mix_buf.size) {
|
|
||||||
src += frames_in;
|
|
||||||
frames_in = frames_in_max - frames_in;
|
|
||||||
dst = hw->mix_buf.buffer;
|
|
||||||
frames_out = frames_out_max - frames_out;
|
|
||||||
st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
|
|
||||||
*total_in += frames_in;
|
|
||||||
*total_out += frames_out;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
|
hwsamples = sw->hw->mix_buf->size;
|
||||||
{
|
|
||||||
HWVoiceOut *hw = sw->hw;
|
|
||||||
size_t live, dead, hw_free, sw_max, fe_max;
|
|
||||||
size_t frames_in_max, frames_out_max, total_in, total_out;
|
|
||||||
|
|
||||||
live = sw->total_hw_samples_mixed;
|
live = sw->total_hw_samples_mixed;
|
||||||
if (audio_bug(__func__, live > hw->mix_buf.size)) {
|
if (audio_bug(__func__, live > hwsamples)) {
|
||||||
dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
|
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hwsamples);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (live == hw->mix_buf.size) {
|
if (live == hwsamples) {
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
dolog ("%s is full %zu\n", sw->name, live);
|
dolog ("%s is full %zu\n", sw->name, live);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dead = hw->mix_buf.size - live;
|
wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
|
||||||
hw_free = audio_pcm_hw_get_free(hw);
|
|
||||||
|
dead = hwsamples - live;
|
||||||
|
hw_free = audio_pcm_hw_get_free(sw->hw);
|
||||||
hw_free = hw_free > live ? hw_free - live : 0;
|
hw_free = hw_free > live ? hw_free - live : 0;
|
||||||
frames_out_max = MIN(dead, hw_free);
|
samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
|
||||||
sw_max = st_rate_frames_in(sw->rate, frames_out_max);
|
samples = MIN(samples, size / sw->info.bytes_per_frame);
|
||||||
fe_max = MIN(buf_len / sw->info.bytes_per_frame + sw->resample_buf.pos,
|
if (samples) {
|
||||||
sw->resample_buf.size);
|
sw->conv(sw->buf, buf, samples);
|
||||||
frames_in_max = MIN(sw_max, fe_max);
|
|
||||||
|
|
||||||
if (!frames_in_max) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frames_in_max > sw->resample_buf.pos) {
|
|
||||||
sw->conv(sw->resample_buf.buffer + sw->resample_buf.pos,
|
|
||||||
buf, frames_in_max - sw->resample_buf.pos);
|
|
||||||
if (!sw->hw->pcm_ops->volume_out) {
|
if (!sw->hw->pcm_ops->volume_out) {
|
||||||
mixeng_volume(sw->resample_buf.buffer + sw->resample_buf.pos,
|
mixeng_volume(sw->buf, samples, &sw->vol);
|
||||||
frames_in_max - sw->resample_buf.pos, &sw->vol);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
|
while (samples) {
|
||||||
&total_in, &total_out);
|
dead = hwsamples - live;
|
||||||
|
left = hwsamples - wpos;
|
||||||
sw->total_hw_samples_mixed += total_out;
|
blck = MIN (dead, left);
|
||||||
sw->empty = sw->total_hw_samples_mixed == 0;
|
if (!blck) {
|
||||||
|
break;
|
||||||
/*
|
}
|
||||||
* Upsampling may leave one audio frame in the resample buffer. Decrement
|
isamp = samples;
|
||||||
* total_in by one if there was a leftover frame from the previous resample
|
osamp = blck;
|
||||||
* pass in the resample buffer. Increment total_in by one if the current
|
st_rate_flow_mix (
|
||||||
* resample pass left one frame in the resample buffer.
|
sw->rate,
|
||||||
*/
|
sw->buf + pos,
|
||||||
if (frames_in_max - total_in == 1) {
|
sw->hw->mix_buf->samples + wpos,
|
||||||
/* copy one leftover audio frame to the beginning of the buffer */
|
&isamp,
|
||||||
*sw->resample_buf.buffer = *(sw->resample_buf.buffer + total_in);
|
&osamp
|
||||||
total_in += 1 - sw->resample_buf.pos;
|
);
|
||||||
sw->resample_buf.pos = 1;
|
ret += isamp;
|
||||||
} else if (total_in >= sw->resample_buf.pos) {
|
samples -= isamp;
|
||||||
total_in -= sw->resample_buf.pos;
|
pos += isamp;
|
||||||
sw->resample_buf.pos = 0;
|
live += osamp;
|
||||||
|
wpos = (wpos + osamp) % hwsamples;
|
||||||
|
total += osamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw->total_hw_samples_mixed += total;
|
||||||
|
sw->empty = sw->total_hw_samples_mixed == 0;
|
||||||
|
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
dolog (
|
dolog (
|
||||||
"%s: write size %zu written %zu total mixed %zu\n",
|
"%s: write size %zu ret %zu total sw %zu\n",
|
||||||
SW_NAME(sw),
|
SW_NAME (sw),
|
||||||
buf_len / sw->info.bytes_per_frame,
|
size / sw->info.bytes_per_frame,
|
||||||
total_in,
|
ret,
|
||||||
sw->total_hw_samples_mixed
|
sw->total_hw_samples_mixed
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return total_in * sw->info.bytes_per_frame;
|
return ret * sw->info.bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
@@ -997,6 +992,18 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audio_frontend_frames_in() - returns the number of frames the resampling
|
||||||
|
* code generates from frames_in frames
|
||||||
|
*
|
||||||
|
* @sw: audio recording frontend
|
||||||
|
* @frames_in: number of frames
|
||||||
|
*/
|
||||||
|
static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in)
|
||||||
|
{
|
||||||
|
return (int64_t)frames_in * sw->ratio >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
static size_t audio_get_avail (SWVoiceIn *sw)
|
static size_t audio_get_avail (SWVoiceIn *sw)
|
||||||
{
|
{
|
||||||
size_t live;
|
size_t live;
|
||||||
@@ -1006,21 +1013,33 @@ static size_t audio_get_avail (SWVoiceIn *sw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
if (audio_bug(__func__, live > sw->hw->conv_buf.size)) {
|
if (audio_bug(__func__, live > sw->hw->conv_buf->size)) {
|
||||||
dolog("live=%zu sw->hw->conv_buf.size=%zu\n", live,
|
dolog("live=%zu sw->hw->conv_buf->size=%zu\n", live,
|
||||||
sw->hw->conv_buf.size);
|
sw->hw->conv_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ldebug (
|
ldebug (
|
||||||
"%s: get_avail live %zu frontend frames %u\n",
|
"%s: get_avail live %zu frontend frames %zu\n",
|
||||||
SW_NAME (sw),
|
SW_NAME (sw),
|
||||||
live, st_rate_frames_out(sw->rate, live)
|
live, audio_frontend_frames_in(sw, live)
|
||||||
);
|
);
|
||||||
|
|
||||||
return live;
|
return live;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audio_frontend_frames_out() - returns the number of frames needed to
|
||||||
|
* get frames_out frames after resampling
|
||||||
|
*
|
||||||
|
* @sw: audio playback frontend
|
||||||
|
* @frames_out: number of frames
|
||||||
|
*/
|
||||||
|
static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out)
|
||||||
|
{
|
||||||
|
return ((int64_t)frames_out << 32) / sw->ratio;
|
||||||
|
}
|
||||||
|
|
||||||
static size_t audio_get_free(SWVoiceOut *sw)
|
static size_t audio_get_free(SWVoiceOut *sw)
|
||||||
{
|
{
|
||||||
size_t live, dead;
|
size_t live, dead;
|
||||||
@@ -1031,17 +1050,17 @@ static size_t audio_get_free(SWVoiceOut *sw)
|
|||||||
|
|
||||||
live = sw->total_hw_samples_mixed;
|
live = sw->total_hw_samples_mixed;
|
||||||
|
|
||||||
if (audio_bug(__func__, live > sw->hw->mix_buf.size)) {
|
if (audio_bug(__func__, live > sw->hw->mix_buf->size)) {
|
||||||
dolog("live=%zu sw->hw->mix_buf.size=%zu\n", live,
|
dolog("live=%zu sw->hw->mix_buf->size=%zu\n", live,
|
||||||
sw->hw->mix_buf.size);
|
sw->hw->mix_buf->size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dead = sw->hw->mix_buf.size - live;
|
dead = sw->hw->mix_buf->size - live;
|
||||||
|
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
dolog("%s: get_free live %zu dead %zu frontend frames %u\n",
|
dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
|
||||||
SW_NAME(sw), live, dead, st_rate_frames_in(sw->rate, dead));
|
SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return dead;
|
return dead;
|
||||||
@@ -1057,40 +1076,32 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
|
|||||||
|
|
||||||
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||||
SWVoiceOut *sw = &sc->sw;
|
SWVoiceOut *sw = &sc->sw;
|
||||||
size_t rpos2 = rpos;
|
int rpos2 = rpos;
|
||||||
|
|
||||||
n = samples;
|
n = samples;
|
||||||
while (n) {
|
while (n) {
|
||||||
size_t till_end_of_hw = hw->mix_buf.size - rpos2;
|
size_t till_end_of_hw = hw->mix_buf->size - rpos2;
|
||||||
size_t to_read = MIN(till_end_of_hw, n);
|
size_t to_write = MIN(till_end_of_hw, n);
|
||||||
size_t live, frames_in, frames_out;
|
size_t bytes = to_write * hw->info.bytes_per_frame;
|
||||||
|
size_t written;
|
||||||
|
|
||||||
sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
|
sw->buf = hw->mix_buf->samples + rpos2;
|
||||||
sw->resample_buf.size = to_read;
|
written = audio_pcm_sw_write (sw, NULL, bytes);
|
||||||
live = sw->total_hw_samples_mixed;
|
if (written - bytes) {
|
||||||
|
dolog("Could not mix %zu bytes into a capture "
|
||||||
audio_pcm_sw_resample_out(sw,
|
|
||||||
to_read, sw->hw->mix_buf.size - live,
|
|
||||||
&frames_in, &frames_out);
|
|
||||||
|
|
||||||
sw->total_hw_samples_mixed += frames_out;
|
|
||||||
sw->empty = sw->total_hw_samples_mixed == 0;
|
|
||||||
|
|
||||||
if (to_read - frames_in) {
|
|
||||||
dolog("Could not mix %zu frames into a capture "
|
|
||||||
"buffer, mixed %zu\n",
|
"buffer, mixed %zu\n",
|
||||||
to_read, frames_in);
|
bytes, written);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
n -= to_read;
|
n -= to_write;
|
||||||
rpos2 = (rpos2 + to_read) % hw->mix_buf.size;
|
rpos2 = (rpos2 + to_write) % hw->mix_buf->size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n = MIN(samples, hw->mix_buf.size - rpos);
|
n = MIN(samples, hw->mix_buf->size - rpos);
|
||||||
mixeng_clear(hw->mix_buf.buffer + rpos, n);
|
mixeng_clear(hw->mix_buf->samples + rpos, n);
|
||||||
mixeng_clear(hw->mix_buf.buffer, samples - n);
|
mixeng_clear(hw->mix_buf->samples, samples - n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
||||||
@@ -1116,7 +1127,7 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
|||||||
|
|
||||||
live -= proc;
|
live -= proc;
|
||||||
clipped += proc;
|
clipped += proc;
|
||||||
hw->mix_buf.pos = (hw->mix_buf.pos + proc) % hw->mix_buf.size;
|
hw->mix_buf->pos = (hw->mix_buf->pos + proc) % hw->mix_buf->size;
|
||||||
|
|
||||||
if (proc == 0 || proc < decr) {
|
if (proc == 0 || proc < decr) {
|
||||||
break;
|
break;
|
||||||
@@ -1170,14 +1181,12 @@ static void audio_run_out (AudioState *s)
|
|||||||
size_t free;
|
size_t free;
|
||||||
|
|
||||||
if (hw_free > sw->total_hw_samples_mixed) {
|
if (hw_free > sw->total_hw_samples_mixed) {
|
||||||
free = st_rate_frames_in(sw->rate,
|
free = audio_frontend_frames_out(sw,
|
||||||
MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
|
MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
|
||||||
} else {
|
} else {
|
||||||
free = 0;
|
free = 0;
|
||||||
}
|
}
|
||||||
if (free > sw->resample_buf.pos) {
|
if (free > 0) {
|
||||||
free = MIN(free, sw->resample_buf.size)
|
|
||||||
- sw->resample_buf.pos;
|
|
||||||
sw->callback.fn(sw->callback.opaque,
|
sw->callback.fn(sw->callback.opaque,
|
||||||
free * sw->info.bytes_per_frame);
|
free * sw->info.bytes_per_frame);
|
||||||
}
|
}
|
||||||
@@ -1189,8 +1198,8 @@ static void audio_run_out (AudioState *s)
|
|||||||
live = 0;
|
live = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bug(__func__, live > hw->mix_buf.size)) {
|
if (audio_bug(__func__, live > hw->mix_buf->size)) {
|
||||||
dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
|
dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1218,13 +1227,13 @@ static void audio_run_out (AudioState *s)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_rpos = hw->mix_buf.pos;
|
prev_rpos = hw->mix_buf->pos;
|
||||||
played = audio_pcm_hw_run_out(hw, live);
|
played = audio_pcm_hw_run_out(hw, live);
|
||||||
replay_audio_out(&played);
|
replay_audio_out(&played);
|
||||||
if (audio_bug(__func__, hw->mix_buf.pos >= hw->mix_buf.size)) {
|
if (audio_bug(__func__, hw->mix_buf->pos >= hw->mix_buf->size)) {
|
||||||
dolog("hw->mix_buf.pos=%zu hw->mix_buf.size=%zu played=%zu\n",
|
dolog("hw->mix_buf->pos=%zu hw->mix_buf->size=%zu played=%zu\n",
|
||||||
hw->mix_buf.pos, hw->mix_buf.size, played);
|
hw->mix_buf->pos, hw->mix_buf->size, played);
|
||||||
hw->mix_buf.pos = 0;
|
hw->mix_buf->pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_OUT
|
#ifdef DEBUG_OUT
|
||||||
@@ -1305,10 +1314,10 @@ static void audio_run_in (AudioState *s)
|
|||||||
|
|
||||||
if (replay_mode != REPLAY_MODE_PLAY) {
|
if (replay_mode != REPLAY_MODE_PLAY) {
|
||||||
captured = audio_pcm_hw_run_in(
|
captured = audio_pcm_hw_run_in(
|
||||||
hw, hw->conv_buf.size - audio_pcm_hw_get_live_in(hw));
|
hw, hw->conv_buf->size - audio_pcm_hw_get_live_in(hw));
|
||||||
}
|
}
|
||||||
replay_audio_in(&captured, hw->conv_buf.buffer, &hw->conv_buf.pos,
|
replay_audio_in(&captured, hw->conv_buf->samples, &hw->conv_buf->pos,
|
||||||
hw->conv_buf.size);
|
hw->conv_buf->size);
|
||||||
|
|
||||||
min = audio_pcm_hw_find_min_in (hw);
|
min = audio_pcm_hw_find_min_in (hw);
|
||||||
hw->total_samples_captured += captured - min;
|
hw->total_samples_captured += captured - min;
|
||||||
@@ -1321,9 +1330,8 @@ static void audio_run_in (AudioState *s)
|
|||||||
size_t sw_avail = audio_get_avail(sw);
|
size_t sw_avail = audio_get_avail(sw);
|
||||||
size_t avail;
|
size_t avail;
|
||||||
|
|
||||||
avail = st_rate_frames_out(sw->rate, sw_avail);
|
avail = audio_frontend_frames_in(sw, sw_avail);
|
||||||
if (avail > 0) {
|
if (avail > 0) {
|
||||||
avail = MIN(avail, sw->resample_buf.size);
|
|
||||||
sw->callback.fn(sw->callback.opaque,
|
sw->callback.fn(sw->callback.opaque,
|
||||||
avail * sw->info.bytes_per_frame);
|
avail * sw->info.bytes_per_frame);
|
||||||
}
|
}
|
||||||
@@ -1342,14 +1350,14 @@ static void audio_run_capture (AudioState *s)
|
|||||||
SWVoiceOut *sw;
|
SWVoiceOut *sw;
|
||||||
|
|
||||||
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
|
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
|
||||||
rpos = hw->mix_buf.pos;
|
rpos = hw->mix_buf->pos;
|
||||||
while (live) {
|
while (live) {
|
||||||
size_t left = hw->mix_buf.size - rpos;
|
size_t left = hw->mix_buf->size - rpos;
|
||||||
size_t to_capture = MIN(live, left);
|
size_t to_capture = MIN(live, left);
|
||||||
struct st_sample *src;
|
struct st_sample *src;
|
||||||
struct capture_callback *cb;
|
struct capture_callback *cb;
|
||||||
|
|
||||||
src = hw->mix_buf.buffer + rpos;
|
src = hw->mix_buf->samples + rpos;
|
||||||
hw->clip (cap->buf, src, to_capture);
|
hw->clip (cap->buf, src, to_capture);
|
||||||
mixeng_clear (src, to_capture);
|
mixeng_clear (src, to_capture);
|
||||||
|
|
||||||
@@ -1357,10 +1365,10 @@ static void audio_run_capture (AudioState *s)
|
|||||||
cb->ops.capture (cb->opaque, cap->buf,
|
cb->ops.capture (cb->opaque, cap->buf,
|
||||||
to_capture * hw->info.bytes_per_frame);
|
to_capture * hw->info.bytes_per_frame);
|
||||||
}
|
}
|
||||||
rpos = (rpos + to_capture) % hw->mix_buf.size;
|
rpos = (rpos + to_capture) % hw->mix_buf->size;
|
||||||
live -= to_capture;
|
live -= to_capture;
|
||||||
}
|
}
|
||||||
hw->mix_buf.pos = rpos;
|
hw->mix_buf->pos = rpos;
|
||||||
|
|
||||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||||
if (!sw->active && sw->empty) {
|
if (!sw->active && sw->empty) {
|
||||||
@@ -1919,7 +1927,7 @@ CaptureVoiceOut *AUD_add_capture(
|
|||||||
|
|
||||||
audio_pcm_init_info (&hw->info, as);
|
audio_pcm_init_info (&hw->info, as);
|
||||||
|
|
||||||
cap->buf = g_malloc0_n(hw->mix_buf.size, hw->info.bytes_per_frame);
|
cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
|
||||||
|
|
||||||
if (hw->info.is_float) {
|
if (hw->info.is_float) {
|
||||||
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
||||||
@@ -1971,7 +1979,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
|
|||||||
sw = sw1;
|
sw = sw1;
|
||||||
}
|
}
|
||||||
QLIST_REMOVE (cap, entries);
|
QLIST_REMOVE (cap, entries);
|
||||||
g_free(cap->hw.mix_buf.buffer);
|
g_free (cap->hw.mix_buf);
|
||||||
g_free (cap->buf);
|
g_free (cap->buf);
|
||||||
g_free (cap);
|
g_free (cap);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ typedef struct SWVoiceCap SWVoiceCap;
|
|||||||
|
|
||||||
typedef struct STSampleBuffer {
|
typedef struct STSampleBuffer {
|
||||||
size_t pos, size;
|
size_t pos, size;
|
||||||
st_sample *buffer;
|
st_sample samples[];
|
||||||
} STSampleBuffer;
|
} STSampleBuffer;
|
||||||
|
|
||||||
typedef struct HWVoiceOut {
|
typedef struct HWVoiceOut {
|
||||||
@@ -71,7 +71,7 @@ typedef struct HWVoiceOut {
|
|||||||
f_sample *clip;
|
f_sample *clip;
|
||||||
uint64_t ts_helper;
|
uint64_t ts_helper;
|
||||||
|
|
||||||
STSampleBuffer mix_buf;
|
STSampleBuffer *mix_buf;
|
||||||
void *buf_emul;
|
void *buf_emul;
|
||||||
size_t pos_emul, pending_emul, size_emul;
|
size_t pos_emul, pending_emul, size_emul;
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ typedef struct HWVoiceIn {
|
|||||||
size_t total_samples_captured;
|
size_t total_samples_captured;
|
||||||
uint64_t ts_helper;
|
uint64_t ts_helper;
|
||||||
|
|
||||||
STSampleBuffer conv_buf;
|
STSampleBuffer *conv_buf;
|
||||||
void *buf_emul;
|
void *buf_emul;
|
||||||
size_t pos_emul, pending_emul, size_emul;
|
size_t pos_emul, pending_emul, size_emul;
|
||||||
|
|
||||||
@@ -108,7 +108,8 @@ struct SWVoiceOut {
|
|||||||
AudioState *s;
|
AudioState *s;
|
||||||
struct audio_pcm_info info;
|
struct audio_pcm_info info;
|
||||||
t_sample *conv;
|
t_sample *conv;
|
||||||
STSampleBuffer resample_buf;
|
int64_t ratio;
|
||||||
|
struct st_sample *buf;
|
||||||
void *rate;
|
void *rate;
|
||||||
size_t total_hw_samples_mixed;
|
size_t total_hw_samples_mixed;
|
||||||
int active;
|
int active;
|
||||||
@@ -125,9 +126,10 @@ struct SWVoiceIn {
|
|||||||
AudioState *s;
|
AudioState *s;
|
||||||
int active;
|
int active;
|
||||||
struct audio_pcm_info info;
|
struct audio_pcm_info info;
|
||||||
|
int64_t ratio;
|
||||||
void *rate;
|
void *rate;
|
||||||
size_t total_hw_samples_acquired;
|
size_t total_hw_samples_acquired;
|
||||||
STSampleBuffer resample_buf;
|
struct st_sample *buf;
|
||||||
f_sample *clip;
|
f_sample *clip;
|
||||||
HWVoiceIn *hw;
|
HWVoiceIn *hw;
|
||||||
char *name;
|
char *name;
|
||||||
@@ -143,14 +145,14 @@ struct audio_driver {
|
|||||||
void *(*init) (Audiodev *);
|
void *(*init) (Audiodev *);
|
||||||
void (*fini) (void *);
|
void (*fini) (void *);
|
||||||
#ifdef CONFIG_GIO
|
#ifdef CONFIG_GIO
|
||||||
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager, bool p2p);
|
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager);
|
||||||
#endif
|
#endif
|
||||||
struct audio_pcm_ops *pcm_ops;
|
struct audio_pcm_ops *pcm_ops;
|
||||||
int can_be_default;
|
int can_be_default;
|
||||||
int max_voices_out;
|
int max_voices_out;
|
||||||
int max_voices_in;
|
int max_voices_in;
|
||||||
size_t voice_size_out;
|
int voice_size_out;
|
||||||
size_t voice_size_in;
|
int voice_size_in;
|
||||||
QLIST_ENTRY(audio_driver) next;
|
QLIST_ENTRY(audio_driver) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -249,6 +251,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
|
|||||||
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
|
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
|
||||||
|
|
||||||
int audio_bug (const char *funcname, int cond);
|
int audio_bug (const char *funcname, int cond);
|
||||||
|
void *audio_calloc (const char *funcname, int nmemb, size_t size);
|
||||||
|
|
||||||
void audio_run(AudioState *s, const char *msg);
|
void audio_run(AudioState *s, const char *msg);
|
||||||
|
|
||||||
@@ -291,6 +294,9 @@ static inline size_t audio_ring_posb(size_t pos, size_t dist, size_t len)
|
|||||||
#define ldebug(fmt, ...) (void)0
|
#define ldebug(fmt, ...) (void)0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define AUDIO_STRINGIFY_(n) #n
|
||||||
|
#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
|
||||||
|
|
||||||
typedef struct AudiodevListEntry {
|
typedef struct AudiodevListEntry {
|
||||||
Audiodev *dev;
|
Audiodev *dev;
|
||||||
QSIMPLEQ_ENTRY(AudiodevListEntry) next;
|
QSIMPLEQ_ENTRY(AudiodevListEntry) next;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
|
|||||||
struct audio_driver *drv)
|
struct audio_driver *drv)
|
||||||
{
|
{
|
||||||
int max_voices = glue (drv->max_voices_, TYPE);
|
int max_voices = glue (drv->max_voices_, TYPE);
|
||||||
size_t voice_size = glue(drv->voice_size_, TYPE);
|
int voice_size = glue (drv->voice_size_, TYPE);
|
||||||
|
|
||||||
if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
|
if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
|
||||||
if (!max_voices) {
|
if (!max_voices) {
|
||||||
@@ -63,17 +63,16 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (audio_bug(__func__, voice_size && !max_voices)) {
|
if (audio_bug(__func__, voice_size && !max_voices)) {
|
||||||
dolog("drv=`%s' voice_size=%zu max_voices=0\n",
|
dolog ("drv=`%s' voice_size=%d max_voices=0\n",
|
||||||
drv->name, voice_size);
|
drv->name, voice_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
|
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
|
||||||
{
|
{
|
||||||
g_free(hw->buf_emul);
|
g_free(hw->buf_emul);
|
||||||
g_free(HWBUF.buffer);
|
g_free (HWBUF);
|
||||||
HWBUF.buffer = NULL;
|
HWBUF = NULL;
|
||||||
HWBUF.size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
|
static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
|
||||||
@@ -84,67 +83,56 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
|
|||||||
dolog("Attempted to allocate empty buffer\n");
|
dolog("Attempted to allocate empty buffer\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
HWBUF.buffer = g_new0(st_sample, samples);
|
HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
|
||||||
HWBUF.size = samples;
|
HWBUF->size = samples;
|
||||||
HWBUF.pos = 0;
|
|
||||||
} else {
|
} else {
|
||||||
HWBUF.buffer = NULL;
|
HWBUF = NULL;
|
||||||
HWBUF.size = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
|
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
|
||||||
{
|
{
|
||||||
g_free(sw->resample_buf.buffer);
|
g_free (sw->buf);
|
||||||
sw->resample_buf.buffer = NULL;
|
|
||||||
sw->resample_buf.size = 0;
|
|
||||||
|
|
||||||
if (sw->rate) {
|
if (sw->rate) {
|
||||||
st_rate_stop (sw->rate);
|
st_rate_stop (sw->rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw->buf = NULL;
|
||||||
sw->rate = NULL;
|
sw->rate = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
|
static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
|
||||||
{
|
{
|
||||||
HW *hw = sw->hw;
|
int samples;
|
||||||
uint64_t samples;
|
|
||||||
|
|
||||||
if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
|
if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);
|
#ifdef DAC
|
||||||
if (samples == 0) {
|
samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
|
||||||
uint64_t f_fe_min;
|
#else
|
||||||
uint64_t f_be = (uint32_t)hw->info.freq;
|
samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
|
sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
|
||||||
f_fe_min = (f_be + HWBUF.size - 1) / HWBUF.size;
|
if (!sw->buf) {
|
||||||
qemu_log_mask(LOG_UNIMP,
|
dolog ("Could not allocate buffer for `%s' (%d samples)\n",
|
||||||
AUDIO_CAP ": The guest selected a " NAME " sample rate"
|
SW_NAME (sw), samples);
|
||||||
" of %d Hz for %s. Only sample rates >= %" PRIu64 " Hz"
|
|
||||||
" are supported.\n",
|
|
||||||
sw->info.freq, sw->name, f_fe_min);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate one additional audio frame that is needed for upsampling
|
|
||||||
* if the resample buffer size is small. For large buffer sizes take
|
|
||||||
* care of overflows and truncation.
|
|
||||||
*/
|
|
||||||
samples = samples < SIZE_MAX ? samples + 1 : SIZE_MAX;
|
|
||||||
sw->resample_buf.buffer = g_new0(st_sample, samples);
|
|
||||||
sw->resample_buf.size = samples;
|
|
||||||
sw->resample_buf.pos = 0;
|
|
||||||
|
|
||||||
#ifdef DAC
|
#ifdef DAC
|
||||||
sw->rate = st_rate_start(sw->info.freq, hw->info.freq);
|
sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
|
||||||
#else
|
#else
|
||||||
sw->rate = st_rate_start(hw->info.freq, sw->info.freq);
|
sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
|
||||||
#endif
|
#endif
|
||||||
|
if (!sw->rate) {
|
||||||
|
g_free (sw->buf);
|
||||||
|
sw->buf = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,8 +149,11 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
|||||||
sw->hw = hw;
|
sw->hw = hw;
|
||||||
sw->active = 0;
|
sw->active = 0;
|
||||||
#ifdef DAC
|
#ifdef DAC
|
||||||
|
sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
|
||||||
sw->total_hw_samples_mixed = 0;
|
sw->total_hw_samples_mixed = 0;
|
||||||
sw->empty = 1;
|
sw->empty = 1;
|
||||||
|
#else
|
||||||
|
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (sw->info.is_float) {
|
if (sw->info.is_float) {
|
||||||
@@ -273,11 +264,13 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
hw = audio_calloc(__func__, 1, glue(drv->voice_size_, TYPE));
|
||||||
* Since glue(s->nb_hw_voices_, TYPE) is != 0, glue(drv->voice_size_, TYPE)
|
if (!hw) {
|
||||||
* is guaranteed to be != 0. See the audio_init_nb_voices_* functions.
|
dolog ("Can not allocate voice `%s' size %d\n",
|
||||||
*/
|
drv->name, glue (drv->voice_size_, TYPE));
|
||||||
hw = g_malloc0(glue(drv->voice_size_, TYPE));
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
hw->s = s;
|
hw->s = s;
|
||||||
hw->pcm_ops = drv->pcm_ops;
|
hw->pcm_ops = drv->pcm_ops;
|
||||||
|
|
||||||
@@ -425,28 +418,33 @@ static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
|
|||||||
hw_as = *as;
|
hw_as = *as;
|
||||||
}
|
}
|
||||||
|
|
||||||
sw = g_new0(SW, 1);
|
sw = audio_calloc(__func__, 1, sizeof(*sw));
|
||||||
|
if (!sw) {
|
||||||
|
dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
|
||||||
|
sw_name ? sw_name : "unknown", sizeof (*sw));
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
sw->s = s;
|
sw->s = s;
|
||||||
|
|
||||||
hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
|
hw = glue(audio_pcm_hw_add_, TYPE)(s, &hw_as);
|
||||||
if (!hw) {
|
if (!hw) {
|
||||||
dolog("Could not create a backend for voice `%s'\n", sw_name);
|
goto err2;
|
||||||
goto err1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
|
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
|
||||||
|
|
||||||
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
|
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
|
||||||
goto err2;
|
goto err3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sw;
|
return sw;
|
||||||
|
|
||||||
err2:
|
err3:
|
||||||
glue (audio_pcm_hw_del_sw_, TYPE) (sw);
|
glue (audio_pcm_hw_del_sw_, TYPE) (sw);
|
||||||
glue (audio_pcm_hw_gc_, TYPE) (&hw);
|
glue (audio_pcm_hw_gc_, TYPE) (&hw);
|
||||||
|
err2:
|
||||||
|
g_free (sw);
|
||||||
err1:
|
err1:
|
||||||
g_free(sw);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,8 +515,8 @@ SW *glue (AUD_open_, TYPE) (
|
|||||||
HW *hw = sw->hw;
|
HW *hw = sw->hw;
|
||||||
|
|
||||||
if (!hw) {
|
if (!hw) {
|
||||||
dolog("Internal logic error: voice `%s' has no backend\n",
|
dolog ("Internal logic error voice `%s' has no hardware store\n",
|
||||||
SW_NAME(sw));
|
SW_NAME (sw));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,6 +527,7 @@ SW *glue (AUD_open_, TYPE) (
|
|||||||
} else {
|
} else {
|
||||||
sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
|
sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
|
||||||
if (!sw) {
|
if (!sw) {
|
||||||
|
dolog ("Failed to create voice `%s'\n", name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
|
|
||||||
typedef struct DBusAudio {
|
typedef struct DBusAudio {
|
||||||
GDBusObjectManagerServer *server;
|
GDBusObjectManagerServer *server;
|
||||||
bool p2p;
|
|
||||||
GDBusObjectSkeleton *audio;
|
GDBusObjectSkeleton *audio;
|
||||||
QemuDBusDisplay1Audio *iface;
|
QemuDBusDisplay1Audio *iface;
|
||||||
GHashTable *out_listeners;
|
GHashTable *out_listeners;
|
||||||
@@ -449,8 +448,7 @@ dbus_audio_register_listener(AudioState *s,
|
|||||||
bool out)
|
bool out)
|
||||||
{
|
{
|
||||||
DBusAudio *da = s->drv_opaque;
|
DBusAudio *da = s->drv_opaque;
|
||||||
const char *sender =
|
const char *sender = g_dbus_method_invocation_get_sender(invocation);
|
||||||
da->p2p ? "p2p" : g_dbus_method_invocation_get_sender(invocation);
|
|
||||||
g_autoptr(GDBusConnection) listener_conn = NULL;
|
g_autoptr(GDBusConnection) listener_conn = NULL;
|
||||||
g_autoptr(GError) err = NULL;
|
g_autoptr(GError) err = NULL;
|
||||||
g_autoptr(GSocket) socket = NULL;
|
g_autoptr(GSocket) socket = NULL;
|
||||||
@@ -593,7 +591,7 @@ dbus_audio_register_in_listener(AudioState *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
|
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server)
|
||||||
{
|
{
|
||||||
DBusAudio *da = s->drv_opaque;
|
DBusAudio *da = s->drv_opaque;
|
||||||
|
|
||||||
@@ -601,7 +599,6 @@ dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
|
|||||||
g_assert(!da->server);
|
g_assert(!da->server);
|
||||||
|
|
||||||
da->server = g_object_ref(server);
|
da->server = g_object_ref(server);
|
||||||
da->p2p = p2p;
|
|
||||||
|
|
||||||
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
|
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
|
||||||
da->iface = qemu_dbus_display1_audio_skeleton_new();
|
da->iface = qemu_dbus_display1_audio_skeleton_new();
|
||||||
|
|||||||
@@ -414,7 +414,12 @@ struct rate {
|
|||||||
*/
|
*/
|
||||||
void *st_rate_start (int inrate, int outrate)
|
void *st_rate_start (int inrate, int outrate)
|
||||||
{
|
{
|
||||||
struct rate *rate = g_new0(struct rate, 1);
|
struct rate *rate = audio_calloc(__func__, 1, sizeof(*rate));
|
||||||
|
|
||||||
|
if (!rate) {
|
||||||
|
dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
rate->opos = 0;
|
rate->opos = 0;
|
||||||
|
|
||||||
@@ -440,86 +445,6 @@ void st_rate_stop (void *opaque)
|
|||||||
g_free (opaque);
|
g_free (opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* st_rate_frames_out() - returns the number of frames the resampling code
|
|
||||||
* generates from frames_in frames
|
|
||||||
*
|
|
||||||
* @opaque: pointer to struct rate
|
|
||||||
* @frames_in: number of frames
|
|
||||||
*
|
|
||||||
* When upsampling, there may be more than one correct result. In this case,
|
|
||||||
* the function returns the maximum number of output frames the resampling
|
|
||||||
* code can generate.
|
|
||||||
*/
|
|
||||||
uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in)
|
|
||||||
{
|
|
||||||
struct rate *rate = opaque;
|
|
||||||
uint64_t opos_end, opos_delta;
|
|
||||||
uint32_t ipos_end;
|
|
||||||
uint32_t frames_out;
|
|
||||||
|
|
||||||
if (rate->opos_inc == 1ULL << 32) {
|
|
||||||
return frames_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* no output frame without at least one input frame */
|
|
||||||
if (!frames_in) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* last frame read was at rate->ipos - 1 */
|
|
||||||
ipos_end = rate->ipos - 1 + frames_in;
|
|
||||||
opos_end = (uint64_t)ipos_end << 32;
|
|
||||||
|
|
||||||
/* last frame written was at rate->opos - rate->opos_inc */
|
|
||||||
if (opos_end + rate->opos_inc <= rate->opos) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
opos_delta = opos_end - rate->opos + rate->opos_inc;
|
|
||||||
frames_out = opos_delta / rate->opos_inc;
|
|
||||||
|
|
||||||
return opos_delta % rate->opos_inc ? frames_out : frames_out - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* st_rate_frames_in() - returns the number of frames needed to
|
|
||||||
* get frames_out frames after resampling
|
|
||||||
*
|
|
||||||
* @opaque: pointer to struct rate
|
|
||||||
* @frames_out: number of frames
|
|
||||||
*
|
|
||||||
* When downsampling, there may be more than one correct result. In this
|
|
||||||
* case, the function returns the maximum number of input frames needed.
|
|
||||||
*/
|
|
||||||
uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out)
|
|
||||||
{
|
|
||||||
struct rate *rate = opaque;
|
|
||||||
uint64_t opos_start, opos_end;
|
|
||||||
uint32_t ipos_start, ipos_end;
|
|
||||||
|
|
||||||
if (rate->opos_inc == 1ULL << 32) {
|
|
||||||
return frames_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frames_out) {
|
|
||||||
opos_start = rate->opos;
|
|
||||||
ipos_start = rate->ipos;
|
|
||||||
} else {
|
|
||||||
uint64_t offset;
|
|
||||||
|
|
||||||
/* add offset = ceil(opos_inc) to opos and ipos to avoid an underflow */
|
|
||||||
offset = (rate->opos_inc + (1ULL << 32) - 1) & ~((1ULL << 32) - 1);
|
|
||||||
opos_start = rate->opos + offset;
|
|
||||||
ipos_start = rate->ipos + (offset >> 32);
|
|
||||||
}
|
|
||||||
/* last frame written was at opos_start - rate->opos_inc */
|
|
||||||
opos_end = opos_start - rate->opos_inc + rate->opos_inc * frames_out;
|
|
||||||
ipos_end = (opos_end >> 32) + 1;
|
|
||||||
|
|
||||||
/* last frame read was at ipos_start - 1 */
|
|
||||||
return ipos_end + 1 > ipos_start ? ipos_end + 1 - ipos_start : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mixeng_clear (struct st_sample *buf, int len)
|
void mixeng_clear (struct st_sample *buf, int len)
|
||||||
{
|
{
|
||||||
memset (buf, 0, len * sizeof (struct st_sample));
|
memset (buf, 0, len * sizeof (struct st_sample));
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
|||||||
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
|
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||||
size_t *isamp, size_t *osamp);
|
size_t *isamp, size_t *osamp);
|
||||||
void st_rate_stop (void *opaque);
|
void st_rate_stop (void *opaque);
|
||||||
uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in);
|
|
||||||
uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out);
|
|
||||||
void mixeng_clear (struct st_sample *buf, int len);
|
void mixeng_clear (struct st_sample *buf, int len);
|
||||||
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
|
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
|||||||
int64_t t;
|
int64_t t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ilast = rate->ilast;
|
||||||
|
|
||||||
istart = ibuf;
|
istart = ibuf;
|
||||||
iend = ibuf + *isamp;
|
iend = ibuf + *isamp;
|
||||||
|
|
||||||
@@ -57,17 +59,15 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* without input samples, there's nothing to do */
|
while (obuf < oend) {
|
||||||
if (ibuf >= iend) {
|
|
||||||
*osamp = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ilast = rate->ilast;
|
/* Safety catch to make sure we have input samples. */
|
||||||
|
if (ibuf >= iend) {
|
||||||
while (true) {
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* read as many input samples so that ipos > opos */
|
/* read as many input samples so that ipos > opos */
|
||||||
|
|
||||||
while (rate->ipos <= (rate->opos >> 32)) {
|
while (rate->ipos <= (rate->opos >> 32)) {
|
||||||
ilast = *ibuf++;
|
ilast = *ibuf++;
|
||||||
rate->ipos++;
|
rate->ipos++;
|
||||||
@@ -78,11 +78,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure that the next output sample can be written */
|
|
||||||
if (obuf >= oend) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
icur = *ibuf;
|
icur = *ibuf;
|
||||||
|
|
||||||
/* wrap ipos and opos around long before they overflow */
|
/* wrap ipos and opos around long before they overflow */
|
||||||
|
|||||||
@@ -59,19 +59,6 @@ struct CryptoDevBackendBuiltin {
|
|||||||
CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
|
CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cryptodev_builtin_init_akcipher(CryptoDevBackend *backend)
|
|
||||||
{
|
|
||||||
QCryptoAkCipherOptions opts;
|
|
||||||
|
|
||||||
opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
|
|
||||||
opts.u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
|
|
||||||
if (qcrypto_akcipher_supports(&opts)) {
|
|
||||||
backend->conf.crypto_services |=
|
|
||||||
(1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER);
|
|
||||||
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_builtin_init(
|
static void cryptodev_builtin_init(
|
||||||
CryptoDevBackend *backend, Error **errp)
|
CryptoDevBackend *backend, Error **errp)
|
||||||
{
|
{
|
||||||
@@ -85,18 +72,21 @@ static void cryptodev_builtin_init(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc = cryptodev_backend_new_client();
|
cc = cryptodev_backend_new_client(
|
||||||
|
"cryptodev-builtin", NULL);
|
||||||
cc->info_str = g_strdup_printf("cryptodev-builtin0");
|
cc->info_str = g_strdup_printf("cryptodev-builtin0");
|
||||||
cc->queue_index = 0;
|
cc->queue_index = 0;
|
||||||
cc->type = QCRYPTODEV_BACKEND_TYPE_BUILTIN;
|
cc->type = CRYPTODEV_BACKEND_TYPE_BUILTIN;
|
||||||
backend->conf.peers.ccs[0] = cc;
|
backend->conf.peers.ccs[0] = cc;
|
||||||
|
|
||||||
backend->conf.crypto_services =
|
backend->conf.crypto_services =
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
|
1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
|
1u << VIRTIO_CRYPTO_SERVICE_HASH |
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
|
1u << VIRTIO_CRYPTO_SERVICE_MAC |
|
||||||
|
1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
|
||||||
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
||||||
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
||||||
|
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
|
||||||
/*
|
/*
|
||||||
* Set the Maximum length of crypto request.
|
* Set the Maximum length of crypto request.
|
||||||
* Why this value? Just avoid to overflow when
|
* Why this value? Just avoid to overflow when
|
||||||
@@ -105,7 +95,6 @@ static void cryptodev_builtin_init(
|
|||||||
backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
|
backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
|
||||||
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
|
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
|
||||||
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
|
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
|
||||||
cryptodev_builtin_init_akcipher(backend);
|
|
||||||
|
|
||||||
cryptodev_backend_set_ready(backend, true);
|
cryptodev_backend_set_ready(backend, true);
|
||||||
}
|
}
|
||||||
@@ -539,14 +528,17 @@ static int cryptodev_builtin_asym_operation(
|
|||||||
|
|
||||||
static int cryptodev_builtin_operation(
|
static int cryptodev_builtin_operation(
|
||||||
CryptoDevBackend *backend,
|
CryptoDevBackend *backend,
|
||||||
CryptoDevBackendOpInfo *op_info)
|
CryptoDevBackendOpInfo *op_info,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb,
|
||||||
|
void *opaque)
|
||||||
{
|
{
|
||||||
CryptoDevBackendBuiltin *builtin =
|
CryptoDevBackendBuiltin *builtin =
|
||||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||||
CryptoDevBackendBuiltinSession *sess;
|
CryptoDevBackendBuiltinSession *sess;
|
||||||
CryptoDevBackendSymOpInfo *sym_op_info;
|
CryptoDevBackendSymOpInfo *sym_op_info;
|
||||||
CryptoDevBackendAsymOpInfo *asym_op_info;
|
CryptoDevBackendAsymOpInfo *asym_op_info;
|
||||||
QCryptodevBackendAlgType algtype = op_info->algtype;
|
enum CryptoDevBackendAlgType algtype = op_info->algtype;
|
||||||
int status = -VIRTIO_CRYPTO_ERR;
|
int status = -VIRTIO_CRYPTO_ERR;
|
||||||
Error *local_error = NULL;
|
Error *local_error = NULL;
|
||||||
|
|
||||||
@@ -558,11 +550,11 @@ static int cryptodev_builtin_operation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sess = builtin->sessions[op_info->session_id];
|
sess = builtin->sessions[op_info->session_id];
|
||||||
if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
|
if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
|
||||||
sym_op_info = op_info->u.sym_op_info;
|
sym_op_info = op_info->u.sym_op_info;
|
||||||
status = cryptodev_builtin_sym_operation(sess, sym_op_info,
|
status = cryptodev_builtin_sym_operation(sess, sym_op_info,
|
||||||
&local_error);
|
&local_error);
|
||||||
} else if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
|
} else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
|
||||||
asym_op_info = op_info->u.asym_op_info;
|
asym_op_info = op_info->u.asym_op_info;
|
||||||
status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
|
status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
|
||||||
asym_op_info, &local_error);
|
asym_op_info, &local_error);
|
||||||
@@ -571,8 +563,8 @@ static int cryptodev_builtin_operation(
|
|||||||
if (local_error) {
|
if (local_error) {
|
||||||
error_report_err(local_error);
|
error_report_err(local_error);
|
||||||
}
|
}
|
||||||
if (op_info->cb) {
|
if (cb) {
|
||||||
op_info->cb(op_info->opaque, status);
|
cb(opaque, status);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* HMP commands related to cryptodev
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Bytedance.Inc
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* zhenwei pi<pizhenwei@bytedance.com>
|
|
||||||
*
|
|
||||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include "monitor/hmp.h"
|
|
||||||
#include "monitor/monitor.h"
|
|
||||||
#include "qapi/qapi-commands-cryptodev.h"
|
|
||||||
#include "qapi/qmp/qdict.h"
|
|
||||||
|
|
||||||
|
|
||||||
void hmp_info_cryptodev(Monitor *mon, const QDict *qdict)
|
|
||||||
{
|
|
||||||
QCryptodevInfoList *il;
|
|
||||||
QCryptodevBackendServiceTypeList *sl;
|
|
||||||
QCryptodevBackendClientList *cl;
|
|
||||||
|
|
||||||
for (il = qmp_query_cryptodev(NULL); il; il = il->next) {
|
|
||||||
g_autofree char *services = NULL;
|
|
||||||
QCryptodevInfo *info = il->value;
|
|
||||||
char *tmp_services;
|
|
||||||
|
|
||||||
/* build a string like 'service=[akcipher|mac|hash|cipher]' */
|
|
||||||
for (sl = info->service; sl; sl = sl->next) {
|
|
||||||
const char *service = QCryptodevBackendServiceType_str(sl->value);
|
|
||||||
|
|
||||||
if (!services) {
|
|
||||||
services = g_strdup(service);
|
|
||||||
} else {
|
|
||||||
tmp_services = g_strjoin("|", services, service, NULL);
|
|
||||||
g_free(services);
|
|
||||||
services = tmp_services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
monitor_printf(mon, "%s: service=[%s]\n", info->id, services);
|
|
||||||
|
|
||||||
for (cl = info->client; cl; cl = cl->next) {
|
|
||||||
QCryptodevBackendClient *client = cl->value;
|
|
||||||
monitor_printf(mon, " queue %" PRIu32 ": type=%s\n",
|
|
||||||
client->queue,
|
|
||||||
QCryptodevBackendType_str(client->type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qapi_free_QCryptodevInfoList(il);
|
|
||||||
}
|
|
||||||
@@ -223,14 +223,14 @@ static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc = cryptodev_backend_new_client();
|
cc = cryptodev_backend_new_client("cryptodev-lkcf", NULL);
|
||||||
cc->info_str = g_strdup_printf("cryptodev-lkcf0");
|
cc->info_str = g_strdup_printf("cryptodev-lkcf0");
|
||||||
cc->queue_index = 0;
|
cc->queue_index = 0;
|
||||||
cc->type = QCRYPTODEV_BACKEND_TYPE_LKCF;
|
cc->type = CRYPTODEV_BACKEND_TYPE_LKCF;
|
||||||
backend->conf.peers.ccs[0] = cc;
|
backend->conf.peers.ccs[0] = cc;
|
||||||
|
|
||||||
backend->conf.crypto_services =
|
backend->conf.crypto_services =
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER;
|
1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
|
||||||
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
|
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
|
||||||
lkcf->running = true;
|
lkcf->running = true;
|
||||||
|
|
||||||
@@ -469,12 +469,15 @@ static void *cryptodev_lkcf_worker(void *arg)
|
|||||||
|
|
||||||
static int cryptodev_lkcf_operation(
|
static int cryptodev_lkcf_operation(
|
||||||
CryptoDevBackend *backend,
|
CryptoDevBackend *backend,
|
||||||
CryptoDevBackendOpInfo *op_info)
|
CryptoDevBackendOpInfo *op_info,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb,
|
||||||
|
void *opaque)
|
||||||
{
|
{
|
||||||
CryptoDevBackendLKCF *lkcf =
|
CryptoDevBackendLKCF *lkcf =
|
||||||
CRYPTODEV_BACKEND_LKCF(backend);
|
CRYPTODEV_BACKEND_LKCF(backend);
|
||||||
CryptoDevBackendLKCFSession *sess;
|
CryptoDevBackendLKCFSession *sess;
|
||||||
QCryptodevBackendAlgType algtype = op_info->algtype;
|
enum CryptoDevBackendAlgType algtype = op_info->algtype;
|
||||||
CryptoDevLKCFTask *task;
|
CryptoDevLKCFTask *task;
|
||||||
|
|
||||||
if (op_info->session_id >= MAX_SESSIONS ||
|
if (op_info->session_id >= MAX_SESSIONS ||
|
||||||
@@ -485,15 +488,15 @@ static int cryptodev_lkcf_operation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sess = lkcf->sess[op_info->session_id];
|
sess = lkcf->sess[op_info->session_id];
|
||||||
if (algtype != QCRYPTODEV_BACKEND_ALG_ASYM) {
|
if (algtype != CRYPTODEV_BACKEND_ALG_ASYM) {
|
||||||
error_report("algtype not supported: %u", algtype);
|
error_report("algtype not supported: %u", algtype);
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = g_new0(CryptoDevLKCFTask, 1);
|
task = g_new0(CryptoDevLKCFTask, 1);
|
||||||
task->op_info = op_info;
|
task->op_info = op_info;
|
||||||
task->cb = op_info->cb;
|
task->cb = cb;
|
||||||
task->opaque = op_info->opaque;
|
task->opaque = opaque;
|
||||||
task->sess = sess;
|
task->sess = sess;
|
||||||
task->lkcf = lkcf;
|
task->lkcf = lkcf;
|
||||||
task->status = -VIRTIO_CRYPTO_ERR;
|
task->status = -VIRTIO_CRYPTO_ERR;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ cryptodev_vhost_user_get_vhost(
|
|||||||
{
|
{
|
||||||
CryptoDevBackendVhostUser *s =
|
CryptoDevBackendVhostUser *s =
|
||||||
CRYPTODEV_BACKEND_VHOST_USER(b);
|
CRYPTODEV_BACKEND_VHOST_USER(b);
|
||||||
assert(cc->type == QCRYPTODEV_BACKEND_TYPE_VHOST_USER);
|
assert(cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER);
|
||||||
assert(queue < MAX_CRYPTO_QUEUE_NUM);
|
assert(queue < MAX_CRYPTO_QUEUE_NUM);
|
||||||
|
|
||||||
return s->vhost_crypto[queue];
|
return s->vhost_crypto[queue];
|
||||||
@@ -198,11 +198,12 @@ static void cryptodev_vhost_user_init(
|
|||||||
s->opened = true;
|
s->opened = true;
|
||||||
|
|
||||||
for (i = 0; i < queues; i++) {
|
for (i = 0; i < queues; i++) {
|
||||||
cc = cryptodev_backend_new_client();
|
cc = cryptodev_backend_new_client(
|
||||||
|
"cryptodev-vhost-user", NULL);
|
||||||
cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
|
cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
|
||||||
i, chr->label);
|
i, chr->label);
|
||||||
cc->queue_index = i;
|
cc->queue_index = i;
|
||||||
cc->type = QCRYPTODEV_BACKEND_TYPE_VHOST_USER;
|
cc->type = CRYPTODEV_BACKEND_TYPE_VHOST_USER;
|
||||||
|
|
||||||
backend->conf.peers.ccs[i] = cc;
|
backend->conf.peers.ccs[i] = cc;
|
||||||
|
|
||||||
@@ -221,9 +222,9 @@ static void cryptodev_vhost_user_init(
|
|||||||
cryptodev_vhost_user_event, NULL, s, NULL, true);
|
cryptodev_vhost_user_event, NULL, s, NULL, true);
|
||||||
|
|
||||||
backend->conf.crypto_services =
|
backend->conf.crypto_services =
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
|
1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
|
1u << VIRTIO_CRYPTO_SERVICE_HASH |
|
||||||
1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
|
1u << VIRTIO_CRYPTO_SERVICE_MAC;
|
||||||
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
||||||
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ cryptodev_get_vhost(CryptoDevBackendClient *cc,
|
|||||||
|
|
||||||
switch (cc->type) {
|
switch (cc->type) {
|
||||||
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
|
||||||
case QCRYPTODEV_BACKEND_TYPE_VHOST_USER:
|
case CRYPTODEV_BACKEND_TYPE_VHOST_USER:
|
||||||
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, b, queue);
|
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, b, queue);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@@ -195,7 +195,7 @@ int cryptodev_vhost_start(VirtIODevice *dev, int total_queues)
|
|||||||
* because vhost user doesn't interrupt masking/unmasking
|
* because vhost user doesn't interrupt masking/unmasking
|
||||||
* properly.
|
* properly.
|
||||||
*/
|
*/
|
||||||
if (cc->type == QCRYPTODEV_BACKEND_TYPE_VHOST_USER) {
|
if (cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER) {
|
||||||
dev->use_guest_notifier_mask = false;
|
dev->use_guest_notifier_mask = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,92 +23,29 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sysemu/cryptodev.h"
|
#include "sysemu/cryptodev.h"
|
||||||
#include "sysemu/stats.h"
|
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qapi/qapi-commands-cryptodev.h"
|
|
||||||
#include "qapi/qapi-types-stats.h"
|
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/main-loop.h"
|
|
||||||
#include "qom/object_interfaces.h"
|
#include "qom/object_interfaces.h"
|
||||||
#include "hw/virtio/virtio-crypto.h"
|
#include "hw/virtio/virtio-crypto.h"
|
||||||
|
|
||||||
#define SYM_ENCRYPT_OPS_STR "sym-encrypt-ops"
|
|
||||||
#define SYM_DECRYPT_OPS_STR "sym-decrypt-ops"
|
|
||||||
#define SYM_ENCRYPT_BYTES_STR "sym-encrypt-bytes"
|
|
||||||
#define SYM_DECRYPT_BYTES_STR "sym-decrypt-bytes"
|
|
||||||
|
|
||||||
#define ASYM_ENCRYPT_OPS_STR "asym-encrypt-ops"
|
|
||||||
#define ASYM_DECRYPT_OPS_STR "asym-decrypt-ops"
|
|
||||||
#define ASYM_SIGN_OPS_STR "asym-sign-ops"
|
|
||||||
#define ASYM_VERIFY_OPS_STR "asym-verify-ops"
|
|
||||||
#define ASYM_ENCRYPT_BYTES_STR "asym-encrypt-bytes"
|
|
||||||
#define ASYM_DECRYPT_BYTES_STR "asym-decrypt-bytes"
|
|
||||||
#define ASYM_SIGN_BYTES_STR "asym-sign-bytes"
|
|
||||||
#define ASYM_VERIFY_BYTES_STR "asym-verify-bytes"
|
|
||||||
|
|
||||||
typedef struct StatsArgs {
|
|
||||||
union StatsResultsType {
|
|
||||||
StatsResultList **stats;
|
|
||||||
StatsSchemaList **schema;
|
|
||||||
} result;
|
|
||||||
strList *names;
|
|
||||||
Error **errp;
|
|
||||||
} StatsArgs;
|
|
||||||
|
|
||||||
static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
|
static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
|
||||||
|
|
||||||
static int qmp_query_cryptodev_foreach(Object *obj, void *data)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend;
|
|
||||||
QCryptodevInfoList **infolist = data;
|
|
||||||
uint32_t services, i;
|
|
||||||
|
|
||||||
if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
|
CryptoDevBackendClient *
|
||||||
return 0;
|
cryptodev_backend_new_client(const char *model,
|
||||||
}
|
const char *name)
|
||||||
|
|
||||||
QCryptodevInfo *info = g_new0(QCryptodevInfo, 1);
|
|
||||||
info->id = g_strdup(object_get_canonical_path_component(obj));
|
|
||||||
|
|
||||||
backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
services = backend->conf.crypto_services;
|
|
||||||
for (i = 0; i < QCRYPTODEV_BACKEND_SERVICE__MAX; i++) {
|
|
||||||
if (services & (1 << i)) {
|
|
||||||
QAPI_LIST_PREPEND(info->service, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < backend->conf.peers.queues; i++) {
|
|
||||||
CryptoDevBackendClient *cc = backend->conf.peers.ccs[i];
|
|
||||||
QCryptodevBackendClient *client = g_new0(QCryptodevBackendClient, 1);
|
|
||||||
|
|
||||||
client->queue = cc->queue_index;
|
|
||||||
client->type = cc->type;
|
|
||||||
QAPI_LIST_PREPEND(info->client, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
QAPI_LIST_PREPEND(*infolist, info);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCryptodevInfoList *qmp_query_cryptodev(Error **errp)
|
|
||||||
{
|
|
||||||
QCryptodevInfoList *list = NULL;
|
|
||||||
Object *objs = container_get(object_get_root(), "/objects");
|
|
||||||
|
|
||||||
object_child_foreach(objs, qmp_query_cryptodev_foreach, &list);
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
CryptoDevBackendClient *cryptodev_backend_new_client(void)
|
|
||||||
{
|
{
|
||||||
CryptoDevBackendClient *cc;
|
CryptoDevBackendClient *cc;
|
||||||
|
|
||||||
cc = g_new0(CryptoDevBackendClient, 1);
|
cc = g_new0(CryptoDevBackendClient, 1);
|
||||||
|
cc->model = g_strdup(model);
|
||||||
|
if (name) {
|
||||||
|
cc->name = g_strdup(name);
|
||||||
|
}
|
||||||
|
|
||||||
QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
|
QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
|
||||||
|
|
||||||
return cc;
|
return cc;
|
||||||
@@ -118,6 +55,8 @@ void cryptodev_backend_free_client(
|
|||||||
CryptoDevBackendClient *cc)
|
CryptoDevBackendClient *cc)
|
||||||
{
|
{
|
||||||
QTAILQ_REMOVE(&crypto_clients, cc, next);
|
QTAILQ_REMOVE(&crypto_clients, cc, next);
|
||||||
|
g_free(cc->name);
|
||||||
|
g_free(cc->model);
|
||||||
g_free(cc->info_str);
|
g_free(cc->info_str);
|
||||||
g_free(cc);
|
g_free(cc);
|
||||||
}
|
}
|
||||||
@@ -132,9 +71,6 @@ void cryptodev_backend_cleanup(
|
|||||||
if (bc->cleanup) {
|
if (bc->cleanup) {
|
||||||
bc->cleanup(backend, errp);
|
bc->cleanup(backend, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(backend->sym_stat);
|
|
||||||
g_free(backend->asym_stat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cryptodev_backend_create_session(
|
int cryptodev_backend_create_session(
|
||||||
@@ -171,111 +107,38 @@ int cryptodev_backend_close_session(
|
|||||||
|
|
||||||
static int cryptodev_backend_operation(
|
static int cryptodev_backend_operation(
|
||||||
CryptoDevBackend *backend,
|
CryptoDevBackend *backend,
|
||||||
CryptoDevBackendOpInfo *op_info)
|
CryptoDevBackendOpInfo *op_info,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb,
|
||||||
|
void *opaque)
|
||||||
{
|
{
|
||||||
CryptoDevBackendClass *bc =
|
CryptoDevBackendClass *bc =
|
||||||
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
CRYPTODEV_BACKEND_GET_CLASS(backend);
|
||||||
|
|
||||||
if (bc->do_op) {
|
if (bc->do_op) {
|
||||||
return bc->do_op(backend, op_info);
|
return bc->do_op(backend, op_info, queue_index, cb, opaque);
|
||||||
}
|
}
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cryptodev_backend_account(CryptoDevBackend *backend,
|
int cryptodev_backend_crypto_operation(
|
||||||
CryptoDevBackendOpInfo *op_info)
|
CryptoDevBackend *backend,
|
||||||
|
void *opaque1,
|
||||||
|
uint32_t queue_index,
|
||||||
|
CryptoDevCompletionFunc cb, void *opaque2)
|
||||||
{
|
{
|
||||||
enum QCryptodevBackendAlgType algtype = op_info->algtype;
|
VirtIOCryptoReq *req = opaque1;
|
||||||
int len;
|
CryptoDevBackendOpInfo *op_info = &req->op_info;
|
||||||
|
enum CryptoDevBackendAlgType algtype = req->flags;
|
||||||
|
|
||||||
if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
|
if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
|
||||||
CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
|
&& (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
|
||||||
len = asym_op_info->src_len;
|
|
||||||
switch (op_info->op_code) {
|
|
||||||
case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
|
|
||||||
CryptodevAsymStatIncEncrypt(backend, len);
|
|
||||||
break;
|
|
||||||
case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
|
|
||||||
CryptodevAsymStatIncDecrypt(backend, len);
|
|
||||||
break;
|
|
||||||
case VIRTIO_CRYPTO_AKCIPHER_SIGN:
|
|
||||||
CryptodevAsymStatIncSign(backend, len);
|
|
||||||
break;
|
|
||||||
case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
|
|
||||||
CryptodevAsymStatIncVerify(backend, len);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
||||||
}
|
|
||||||
} else if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
|
|
||||||
CryptoDevBackendSymOpInfo *sym_op_info = op_info->u.sym_op_info;
|
|
||||||
len = sym_op_info->src_len;
|
|
||||||
switch (op_info->op_code) {
|
|
||||||
case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
|
|
||||||
CryptodevSymStatIncEncrypt(backend, len);
|
|
||||||
break;
|
|
||||||
case VIRTIO_CRYPTO_CIPHER_DECRYPT:
|
|
||||||
CryptodevSymStatIncDecrypt(backend, len);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
|
error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
|
||||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return cryptodev_backend_operation(backend, op_info, queue_index,
|
||||||
}
|
cb, opaque2);
|
||||||
|
|
||||||
static void cryptodev_backend_throttle_timer_cb(void *opaque)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = (CryptoDevBackend *)opaque;
|
|
||||||
CryptoDevBackendOpInfo *op_info, *tmpop;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
QTAILQ_FOREACH_SAFE(op_info, &backend->opinfos, next, tmpop) {
|
|
||||||
QTAILQ_REMOVE(&backend->opinfos, op_info, next);
|
|
||||||
ret = cryptodev_backend_account(backend, op_info);
|
|
||||||
if (ret < 0) {
|
|
||||||
op_info->cb(op_info->opaque, ret);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
throttle_account(&backend->ts, true, ret);
|
|
||||||
cryptodev_backend_operation(backend, op_info);
|
|
||||||
if (throttle_enabled(&backend->tc) &&
|
|
||||||
throttle_schedule_timer(&backend->ts, &backend->tt, true)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cryptodev_backend_crypto_operation(
|
|
||||||
CryptoDevBackend *backend,
|
|
||||||
CryptoDevBackendOpInfo *op_info)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!throttle_enabled(&backend->tc)) {
|
|
||||||
goto do_account;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (throttle_schedule_timer(&backend->ts, &backend->tt, true) ||
|
|
||||||
!QTAILQ_EMPTY(&backend->opinfos)) {
|
|
||||||
QTAILQ_INSERT_TAIL(&backend->opinfos, op_info, next);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_account:
|
|
||||||
ret = cryptodev_backend_account(backend, op_info);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
throttle_account(&backend->ts, true, ret);
|
|
||||||
|
|
||||||
return cryptodev_backend_operation(backend, op_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -306,111 +169,15 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
|
|||||||
backend->conf.peers.queues = value;
|
backend->conf.peers.queues = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cryptodev_backend_set_throttle(CryptoDevBackend *backend, int field,
|
|
||||||
uint64_t value, Error **errp)
|
|
||||||
{
|
|
||||||
uint64_t orig = backend->tc.buckets[field].avg;
|
|
||||||
bool enabled = throttle_enabled(&backend->tc);
|
|
||||||
|
|
||||||
if (orig == value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
backend->tc.buckets[field].avg = value;
|
|
||||||
if (!throttle_enabled(&backend->tc)) {
|
|
||||||
throttle_timers_destroy(&backend->tt);
|
|
||||||
cryptodev_backend_throttle_timer_cb(backend); /* drain opinfos */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!throttle_is_valid(&backend->tc, errp)) {
|
|
||||||
backend->tc.buckets[field].avg = orig; /* revert change */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!enabled) {
|
|
||||||
throttle_init(&backend->ts);
|
|
||||||
throttle_timers_init(&backend->tt, qemu_get_aio_context(),
|
|
||||||
QEMU_CLOCK_REALTIME,
|
|
||||||
cryptodev_backend_throttle_timer_cb, /* FIXME */
|
|
||||||
cryptodev_backend_throttle_timer_cb, backend);
|
|
||||||
}
|
|
||||||
|
|
||||||
throttle_config(&backend->ts, QEMU_CLOCK_REALTIME, &backend->tc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_get_bps(Object *obj, Visitor *v,
|
|
||||||
const char *name, void *opaque,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
uint64_t value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
|
|
||||||
|
|
||||||
visit_type_uint64(v, name, &value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_set_bps(Object *obj, Visitor *v, const char *name,
|
|
||||||
void *opaque, Error **errp)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
uint64_t value;
|
|
||||||
|
|
||||||
if (!visit_type_uint64(v, name, &value, errp)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_get_ops(Object *obj, Visitor *v, const char *name,
|
|
||||||
void *opaque, Error **errp)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
uint64_t value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
|
|
||||||
|
|
||||||
visit_type_uint64(v, name, &value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_set_ops(Object *obj, Visitor *v,
|
|
||||||
const char *name, void *opaque,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
uint64_t value;
|
|
||||||
|
|
||||||
if (!visit_type_uint64(v, name, &value, errp)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
||||||
{
|
{
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
|
||||||
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
|
||||||
uint32_t services;
|
|
||||||
uint64_t value;
|
|
||||||
|
|
||||||
QTAILQ_INIT(&backend->opinfos);
|
|
||||||
value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
|
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
|
|
||||||
value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
|
|
||||||
cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
|
|
||||||
|
|
||||||
if (bc->init) {
|
if (bc->init) {
|
||||||
bc->init(backend, errp);
|
bc->init(backend, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
services = backend->conf.crypto_services;
|
|
||||||
if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
|
|
||||||
backend->sym_stat = g_new0(CryptodevBackendSymStat, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
|
|
||||||
backend->asym_stat = g_new0(CryptodevBackendAsymStat, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
||||||
@@ -441,12 +208,8 @@ cryptodev_backend_can_be_deleted(UserCreatable *uc)
|
|||||||
|
|
||||||
static void cryptodev_backend_instance_init(Object *obj)
|
static void cryptodev_backend_instance_init(Object *obj)
|
||||||
{
|
{
|
||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
|
|
||||||
/* Initialize devices' queues property to 1 */
|
/* Initialize devices' queues property to 1 */
|
||||||
object_property_set_int(obj, "queues", 1, NULL);
|
object_property_set_int(obj, "queues", 1, NULL);
|
||||||
|
|
||||||
throttle_config_init(&backend->tc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cryptodev_backend_finalize(Object *obj)
|
static void cryptodev_backend_finalize(Object *obj)
|
||||||
@@ -454,137 +217,6 @@ static void cryptodev_backend_finalize(Object *obj)
|
|||||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
||||||
|
|
||||||
cryptodev_backend_cleanup(backend, NULL);
|
cryptodev_backend_cleanup(backend, NULL);
|
||||||
if (throttle_enabled(&backend->tc)) {
|
|
||||||
throttle_timers_destroy(&backend->tt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static StatsList *cryptodev_backend_stats_add(const char *name, int64_t *val,
|
|
||||||
StatsList *stats_list)
|
|
||||||
{
|
|
||||||
Stats *stats = g_new0(Stats, 1);
|
|
||||||
|
|
||||||
stats->name = g_strdup(name);
|
|
||||||
stats->value = g_new0(StatsValue, 1);
|
|
||||||
stats->value->type = QTYPE_QNUM;
|
|
||||||
stats->value->u.scalar = *val;
|
|
||||||
|
|
||||||
QAPI_LIST_PREPEND(stats_list, stats);
|
|
||||||
return stats_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cryptodev_backend_stats_query(Object *obj, void *data)
|
|
||||||
{
|
|
||||||
StatsArgs *stats_args = data;
|
|
||||||
StatsResultList **stats_results = stats_args->result.stats;
|
|
||||||
StatsList *stats_list = NULL;
|
|
||||||
StatsResult *entry;
|
|
||||||
CryptoDevBackend *backend;
|
|
||||||
CryptodevBackendSymStat *sym_stat;
|
|
||||||
CryptodevBackendAsymStat *asym_stat;
|
|
||||||
|
|
||||||
if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
backend = CRYPTODEV_BACKEND(obj);
|
|
||||||
sym_stat = backend->sym_stat;
|
|
||||||
if (sym_stat) {
|
|
||||||
stats_list = cryptodev_backend_stats_add(SYM_ENCRYPT_OPS_STR,
|
|
||||||
&sym_stat->encrypt_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(SYM_DECRYPT_OPS_STR,
|
|
||||||
&sym_stat->decrypt_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(SYM_ENCRYPT_BYTES_STR,
|
|
||||||
&sym_stat->encrypt_bytes, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(SYM_DECRYPT_BYTES_STR,
|
|
||||||
&sym_stat->decrypt_bytes, stats_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
asym_stat = backend->asym_stat;
|
|
||||||
if (asym_stat) {
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_ENCRYPT_OPS_STR,
|
|
||||||
&asym_stat->encrypt_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_DECRYPT_OPS_STR,
|
|
||||||
&asym_stat->decrypt_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_SIGN_OPS_STR,
|
|
||||||
&asym_stat->sign_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_VERIFY_OPS_STR,
|
|
||||||
&asym_stat->verify_ops, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_ENCRYPT_BYTES_STR,
|
|
||||||
&asym_stat->encrypt_bytes, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_DECRYPT_BYTES_STR,
|
|
||||||
&asym_stat->decrypt_bytes, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_SIGN_BYTES_STR,
|
|
||||||
&asym_stat->sign_bytes, stats_list);
|
|
||||||
stats_list = cryptodev_backend_stats_add(ASYM_VERIFY_BYTES_STR,
|
|
||||||
&asym_stat->verify_bytes, stats_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = g_new0(StatsResult, 1);
|
|
||||||
entry->provider = STATS_PROVIDER_CRYPTODEV;
|
|
||||||
entry->qom_path = g_strdup(object_get_canonical_path(obj));
|
|
||||||
entry->stats = stats_list;
|
|
||||||
QAPI_LIST_PREPEND(*stats_results, entry);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_stats_cb(StatsResultList **result,
|
|
||||||
StatsTarget target,
|
|
||||||
strList *names, strList *targets,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
switch (target) {
|
|
||||||
case STATS_TARGET_CRYPTODEV:
|
|
||||||
{
|
|
||||||
Object *objs = container_get(object_get_root(), "/objects");
|
|
||||||
StatsArgs stats_args;
|
|
||||||
stats_args.result.stats = result;
|
|
||||||
stats_args.names = names;
|
|
||||||
stats_args.errp = errp;
|
|
||||||
|
|
||||||
object_child_foreach(objs, cryptodev_backend_stats_query, &stats_args);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static StatsSchemaValueList *cryptodev_backend_schemas_add(const char *name,
|
|
||||||
StatsSchemaValueList *list)
|
|
||||||
{
|
|
||||||
StatsSchemaValueList *schema_entry = g_new0(StatsSchemaValueList, 1);
|
|
||||||
|
|
||||||
schema_entry->value = g_new0(StatsSchemaValue, 1);
|
|
||||||
schema_entry->value->type = STATS_TYPE_CUMULATIVE;
|
|
||||||
schema_entry->value->name = g_strdup(name);
|
|
||||||
schema_entry->next = list;
|
|
||||||
|
|
||||||
return schema_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cryptodev_backend_schemas_cb(StatsSchemaList **result,
|
|
||||||
Error **errp)
|
|
||||||
{
|
|
||||||
StatsSchemaValueList *stats_list = NULL;
|
|
||||||
const char *sym_stats[] = { SYM_ENCRYPT_OPS_STR, SYM_DECRYPT_OPS_STR,
|
|
||||||
SYM_ENCRYPT_BYTES_STR, SYM_DECRYPT_BYTES_STR };
|
|
||||||
const char *asym_stats[] = { ASYM_ENCRYPT_OPS_STR, ASYM_DECRYPT_OPS_STR,
|
|
||||||
ASYM_SIGN_OPS_STR, ASYM_VERIFY_OPS_STR,
|
|
||||||
ASYM_ENCRYPT_BYTES_STR, ASYM_DECRYPT_BYTES_STR,
|
|
||||||
ASYM_SIGN_BYTES_STR, ASYM_VERIFY_BYTES_STR };
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(sym_stats); i++) {
|
|
||||||
stats_list = cryptodev_backend_schemas_add(sym_stats[i], stats_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(asym_stats); i++) {
|
|
||||||
stats_list = cryptodev_backend_schemas_add(asym_stats[i], stats_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
add_stats_schema(result, STATS_PROVIDER_CRYPTODEV, STATS_TARGET_CRYPTODEV,
|
|
||||||
stats_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -600,17 +232,6 @@ cryptodev_backend_class_init(ObjectClass *oc, void *data)
|
|||||||
cryptodev_backend_get_queues,
|
cryptodev_backend_get_queues,
|
||||||
cryptodev_backend_set_queues,
|
cryptodev_backend_set_queues,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
object_class_property_add(oc, "throttle-bps", "uint64",
|
|
||||||
cryptodev_backend_get_bps,
|
|
||||||
cryptodev_backend_set_bps,
|
|
||||||
NULL, NULL);
|
|
||||||
object_class_property_add(oc, "throttle-ops", "uint64",
|
|
||||||
cryptodev_backend_get_ops,
|
|
||||||
cryptodev_backend_set_ops,
|
|
||||||
NULL, NULL);
|
|
||||||
|
|
||||||
add_stats_callbacks(STATS_PROVIDER_CRYPTODEV, cryptodev_backend_stats_cb,
|
|
||||||
cryptodev_backend_schemas_cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo cryptodev_backend_info = {
|
static const TypeInfo cryptodev_backend_info = {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
softmmu_ss.add([files(
|
softmmu_ss.add([files(
|
||||||
'cryptodev-builtin.c',
|
'cryptodev-builtin.c',
|
||||||
'cryptodev-hmp-cmds.c',
|
|
||||||
'cryptodev.c',
|
'cryptodev.c',
|
||||||
'hostmem-ram.c',
|
'hostmem-ram.c',
|
||||||
'hostmem.c',
|
'hostmem.c',
|
||||||
|
|||||||
@@ -573,13 +573,13 @@ static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
|
|||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fds[1]);
|
closesocket(fds[1]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_exit:
|
err_exit:
|
||||||
close(fds[0]);
|
closesocket(fds[0]);
|
||||||
close(fds[1]);
|
closesocket(fds[1]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
block.c
5
block.c
@@ -5879,10 +5879,9 @@ int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* return 0 as number of sectors if no device present or error */
|
/* return 0 as number of sectors if no device present or error */
|
||||||
void coroutine_fn bdrv_co_get_geometry(BlockDriverState *bs,
|
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
|
||||||
uint64_t *nb_sectors_ptr)
|
|
||||||
{
|
{
|
||||||
int64_t nb_sectors = bdrv_co_nb_sectors(bs);
|
int64_t nb_sectors = bdrv_nb_sectors(bs);
|
||||||
IO_CODE();
|
IO_CODE();
|
||||||
|
|
||||||
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
|
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
|
||||||
|
|||||||
@@ -1615,16 +1615,13 @@ int64_t coroutine_fn blk_co_getlength(BlockBackend *blk)
|
|||||||
return bdrv_co_getlength(blk_bs(blk));
|
return bdrv_co_getlength(blk_bs(blk));
|
||||||
}
|
}
|
||||||
|
|
||||||
void coroutine_fn blk_co_get_geometry(BlockBackend *blk,
|
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
|
||||||
uint64_t *nb_sectors_ptr)
|
|
||||||
{
|
{
|
||||||
IO_CODE();
|
IO_CODE();
|
||||||
GRAPH_RDLOCK_GUARD();
|
|
||||||
|
|
||||||
if (!blk_bs(blk)) {
|
if (!blk_bs(blk)) {
|
||||||
*nb_sectors_ptr = 0;
|
*nb_sectors_ptr = 0;
|
||||||
} else {
|
} else {
|
||||||
bdrv_co_get_geometry(blk_bs(blk), nb_sectors_ptr);
|
bdrv_get_geometry(blk_bs(blk), nb_sectors_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -673,16 +673,7 @@ static void fuse_fallocate(fuse_req_t req, fuse_ino_t inode, int mode,
|
|||||||
do {
|
do {
|
||||||
int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
|
int size = MIN(length, BDRV_REQUEST_MAX_BYTES);
|
||||||
|
|
||||||
ret = blk_pwrite_zeroes(exp->common.blk, offset, size,
|
ret = blk_pdiscard(exp->common.blk, offset, size);
|
||||||
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK);
|
|
||||||
if (ret == -ENOTSUP) {
|
|
||||||
/*
|
|
||||||
* fallocate() specifies to return EOPNOTSUPP for unsupported
|
|
||||||
* operations
|
|
||||||
*/
|
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += size;
|
offset += size;
|
||||||
length -= size;
|
length -= size;
|
||||||
} while (ret == 0 && length > 0);
|
} while (ret == 0 && length > 0);
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ struct virtio_blk_inhdr {
|
|||||||
unsigned char status;
|
unsigned char status;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool coroutine_fn
|
static bool virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
|
||||||
virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
|
uint64_t sector, size_t size)
|
||||||
uint64_t sector, size_t size)
|
|
||||||
{
|
{
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
uint64_t total_sectors;
|
uint64_t total_sectors;
|
||||||
@@ -42,7 +41,7 @@ virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
|
|||||||
if ((sector << VIRTIO_BLK_SECTOR_BITS) % block_size) {
|
if ((sector << VIRTIO_BLK_SECTOR_BITS) % block_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
blk_co_get_geometry(blk, &total_sectors);
|
blk_get_geometry(blk, &total_sectors);
|
||||||
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
|
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
#include "gdbstub/user.h"
|
|
||||||
#include "signal-common.h"
|
#include "signal-common.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "hw/core/tcg-cpu-ops.h"
|
#include "hw/core/tcg-cpu-ops.h"
|
||||||
|
|||||||
@@ -44,39 +44,39 @@
|
|||||||
|
|
||||||
#define ESC 0x1B
|
#define ESC 0x1B
|
||||||
|
|
||||||
#define BAUM_REQ_DisplayData 0x01
|
#define BAUM_REQ_DisplayData 0x01
|
||||||
#define BAUM_REQ_GetVersionNumber 0x05
|
#define BAUM_REQ_GetVersionNumber 0x05
|
||||||
#define BAUM_REQ_GetKeys 0x08
|
#define BAUM_REQ_GetKeys 0x08
|
||||||
#define BAUM_REQ_SetMode 0x12
|
#define BAUM_REQ_SetMode 0x12
|
||||||
#define BAUM_REQ_SetProtocol 0x15
|
#define BAUM_REQ_SetProtocol 0x15
|
||||||
#define BAUM_REQ_GetDeviceIdentity 0x84
|
#define BAUM_REQ_GetDeviceIdentity 0x84
|
||||||
#define BAUM_REQ_GetSerialNumber 0x8A
|
#define BAUM_REQ_GetSerialNumber 0x8A
|
||||||
|
|
||||||
#define BAUM_RSP_CellCount 0x01
|
#define BAUM_RSP_CellCount 0x01
|
||||||
#define BAUM_RSP_VersionNumber 0x05
|
#define BAUM_RSP_VersionNumber 0x05
|
||||||
#define BAUM_RSP_ModeSetting 0x11
|
#define BAUM_RSP_ModeSetting 0x11
|
||||||
#define BAUM_RSP_CommunicationChannel 0x16
|
#define BAUM_RSP_CommunicationChannel 0x16
|
||||||
#define BAUM_RSP_PowerdownSignal 0x17
|
#define BAUM_RSP_PowerdownSignal 0x17
|
||||||
#define BAUM_RSP_HorizontalSensors 0x20
|
#define BAUM_RSP_HorizontalSensors 0x20
|
||||||
#define BAUM_RSP_VerticalSensors 0x21
|
#define BAUM_RSP_VerticalSensors 0x21
|
||||||
#define BAUM_RSP_RoutingKeys 0x22
|
#define BAUM_RSP_RoutingKeys 0x22
|
||||||
#define BAUM_RSP_Switches 0x23
|
#define BAUM_RSP_Switches 0x23
|
||||||
#define BAUM_RSP_TopKeys 0x24
|
#define BAUM_RSP_TopKeys 0x24
|
||||||
#define BAUM_RSP_HorizontalSensor 0x25
|
#define BAUM_RSP_HorizontalSensor 0x25
|
||||||
#define BAUM_RSP_VerticalSensor 0x26
|
#define BAUM_RSP_VerticalSensor 0x26
|
||||||
#define BAUM_RSP_RoutingKey 0x27
|
#define BAUM_RSP_RoutingKey 0x27
|
||||||
#define BAUM_RSP_FrontKeys6 0x28
|
#define BAUM_RSP_FrontKeys6 0x28
|
||||||
#define BAUM_RSP_BackKeys6 0x29
|
#define BAUM_RSP_BackKeys6 0x29
|
||||||
#define BAUM_RSP_CommandKeys 0x2B
|
#define BAUM_RSP_CommandKeys 0x2B
|
||||||
#define BAUM_RSP_FrontKeys10 0x2C
|
#define BAUM_RSP_FrontKeys10 0x2C
|
||||||
#define BAUM_RSP_BackKeys10 0x2D
|
#define BAUM_RSP_BackKeys10 0x2D
|
||||||
#define BAUM_RSP_EntryKeys 0x33
|
#define BAUM_RSP_EntryKeys 0x33
|
||||||
#define BAUM_RSP_JoyStick 0x34
|
#define BAUM_RSP_JoyStick 0x34
|
||||||
#define BAUM_RSP_ErrorCode 0x40
|
#define BAUM_RSP_ErrorCode 0x40
|
||||||
#define BAUM_RSP_InfoBlock 0x42
|
#define BAUM_RSP_InfoBlock 0x42
|
||||||
#define BAUM_RSP_DeviceIdentity 0x84
|
#define BAUM_RSP_DeviceIdentity 0x84
|
||||||
#define BAUM_RSP_SerialNumber 0x8A
|
#define BAUM_RSP_SerialNumber 0x8A
|
||||||
#define BAUM_RSP_BluetoothName 0x8C
|
#define BAUM_RSP_BluetoothName 0x8C
|
||||||
|
|
||||||
#define BAUM_TL1 0x01
|
#define BAUM_TL1 0x01
|
||||||
#define BAUM_TL2 0x02
|
#define BAUM_TL2 0x02
|
||||||
|
|||||||
@@ -1175,10 +1175,12 @@ bool qmp_add_client_char(int fd, bool has_skipauth, bool skipauth,
|
|||||||
|
|
||||||
if (!s) {
|
if (!s) {
|
||||||
error_setg(errp, "protocol '%s' is invalid", protocol);
|
error_setg(errp, "protocol '%s' is invalid", protocol);
|
||||||
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (qemu_chr_add_client(s, fd) < 0) {
|
if (qemu_chr_add_client(s, fd) < 0) {
|
||||||
error_setg(errp, "failed to add client");
|
error_setg(errp, "failed to add client");
|
||||||
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
|
||||||
TARGET_HAS_BFLT=y
|
TARGET_HAS_BFLT=y
|
||||||
CONFIG_SEMIHOSTING=y
|
CONFIG_SEMIHOSTING=y
|
||||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_SUPPORTS_MTTCG=y
|
TARGET_SUPPORTS_MTTCG=y
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml gdb-xml/aarch64-pauth.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
||||||
TARGET_NEED_FDT=y
|
TARGET_NEED_FDT=y
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_BIG_ENDIAN=y
|
TARGET_BIG_ENDIAN=y
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
|
||||||
TARGET_HAS_BFLT=y
|
TARGET_HAS_BFLT=y
|
||||||
CONFIG_SEMIHOSTING=y
|
CONFIG_SEMIHOSTING=y
|
||||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||||
|
|||||||
9
configure
vendored
9
configure
vendored
@@ -230,7 +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=""
|
|
||||||
|
|
||||||
if test -e "$source_path/.git"
|
if test -e "$source_path/.git"
|
||||||
then
|
then
|
||||||
@@ -2263,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"
|
||||||
@@ -2397,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
|
||||||
@@ -2522,12 +2519,6 @@ for target in $target_list; do
|
|||||||
write_target_makefile "build-tcg-tests-$target" >> "$config_target_mak"
|
write_target_makefile "build-tcg-tests-$target" >> "$config_target_mak"
|
||||||
echo "BUILD_STATIC=$build_static" >> "$config_target_mak"
|
echo "BUILD_STATIC=$build_static" >> "$config_target_mak"
|
||||||
echo "QEMU=$PWD/$qemu" >> "$config_target_mak"
|
echo "QEMU=$PWD/$qemu" >> "$config_target_mak"
|
||||||
|
|
||||||
# will GDB work with these binaries?
|
|
||||||
if test "${gdb_arches#*$arch}" != "$gdb_arches"; then
|
|
||||||
echo "HOST_GDB_SUPPORTS_ARCH=y" >> "$config_target_mak"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
|
echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
|
||||||
tcg_tests_targets="$tcg_tests_targets $target"
|
tcg_tests_targets="$tcg_tests_targets $target"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
|
static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < ps->block_nr; i++) {
|
for (i = 0; i < ps->block_nr; i++) {
|
||||||
if (ps->block[i].paddr <= pa &&
|
if (ps->block[i].paddr <= pa &&
|
||||||
pa <= ps->block[i].paddr + ps->block[i].size) {
|
pa <= ps->block[i].paddr + ps->block[i].size) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
#define SYM_URL_BASE "https://msdl.microsoft.com/download/symbols/"
|
#define SYM_URL_BASE "https://msdl.microsoft.com/download/symbols/"
|
||||||
#define PDB_NAME "ntkrnlmp.pdb"
|
#define PDB_NAME "ntkrnlmp.pdb"
|
||||||
#define PE_NAME "ntoskrnl.exe"
|
|
||||||
|
|
||||||
#define INITIAL_MXCSR 0x1f80
|
#define INITIAL_MXCSR 0x1f80
|
||||||
|
|
||||||
@@ -283,16 +282,14 @@ static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (i = 0; i < ps->block_nr; i++) {
|
for (i = 0; i < ps->block_nr; i++) {
|
||||||
h.PhysicalMemoryBlock.NumberOfPages +=
|
h.PhysicalMemoryBlock.NumberOfPages += ps->block[i].size / ELF2DMP_PAGE_SIZE;
|
||||||
ps->block[i].size / ELF2DMP_PAGE_SIZE;
|
|
||||||
h.PhysicalMemoryBlock.Run[i] = (WinDumpPhyMemRun64) {
|
h.PhysicalMemoryBlock.Run[i] = (WinDumpPhyMemRun64) {
|
||||||
.BasePage = ps->block[i].paddr / ELF2DMP_PAGE_SIZE,
|
.BasePage = ps->block[i].paddr / ELF2DMP_PAGE_SIZE,
|
||||||
.PageCount = ps->block[i].size / ELF2DMP_PAGE_SIZE,
|
.PageCount = ps->block[i].size / ELF2DMP_PAGE_SIZE,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
h.RequiredDumpSpace +=
|
h.RequiredDumpSpace += h.PhysicalMemoryBlock.NumberOfPages << ELF2DMP_PAGE_BITS;
|
||||||
h.PhysicalMemoryBlock.NumberOfPages << ELF2DMP_PAGE_BITS;
|
|
||||||
|
|
||||||
*hdr = h;
|
*hdr = h;
|
||||||
|
|
||||||
@@ -302,8 +299,7 @@ static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
|
|||||||
static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
||||||
struct va_space *vs, QEMU_Elf *qe)
|
struct va_space *vs, QEMU_Elf *qe)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < qe->state_nr; i++) {
|
for (i = 0; i < qe->state_nr; i++) {
|
||||||
uint64_t Prcb;
|
uint64_t Prcb;
|
||||||
uint64_t Context;
|
uint64_t Context;
|
||||||
@@ -334,45 +330,6 @@ static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pe_get_data_dir_entry(uint64_t base, void *start_addr, int idx,
|
|
||||||
void *entry, size_t size, struct va_space *vs)
|
|
||||||
{
|
|
||||||
const char e_magic[2] = "MZ";
|
|
||||||
const char Signature[4] = "PE\0\0";
|
|
||||||
IMAGE_DOS_HEADER *dos_hdr = start_addr;
|
|
||||||
IMAGE_NT_HEADERS64 nt_hdrs;
|
|
||||||
IMAGE_FILE_HEADER *file_hdr = &nt_hdrs.FileHeader;
|
|
||||||
IMAGE_OPTIONAL_HEADER64 *opt_hdr = &nt_hdrs.OptionalHeader;
|
|
||||||
IMAGE_DATA_DIRECTORY *data_dir = nt_hdrs.OptionalHeader.DataDirectory;
|
|
||||||
|
|
||||||
QEMU_BUILD_BUG_ON(sizeof(*dos_hdr) >= ELF2DMP_PAGE_SIZE);
|
|
||||||
|
|
||||||
if (memcmp(&dos_hdr->e_magic, e_magic, sizeof(e_magic))) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (va_space_rw(vs, base + dos_hdr->e_lfanew,
|
|
||||||
&nt_hdrs, sizeof(nt_hdrs), 0)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memcmp(&nt_hdrs.Signature, Signature, sizeof(Signature)) ||
|
|
||||||
file_hdr->Machine != 0x8664 || opt_hdr->Magic != 0x020b) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (va_space_rw(vs,
|
|
||||||
base + data_dir[idx].VirtualAddress,
|
|
||||||
entry, size, 0)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Data directory entry #%d: RVA = 0x%08"PRIx32"\n", idx,
|
|
||||||
(uint32_t)data_dir[idx].VirtualAddress);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_dump(struct pa_space *ps,
|
static int write_dump(struct pa_space *ps,
|
||||||
WinDumpHeader64 *hdr, const char *name)
|
WinDumpHeader64 *hdr, const char *name)
|
||||||
{
|
{
|
||||||
@@ -406,38 +363,45 @@ static int write_dump(struct pa_space *ps,
|
|||||||
return fclose(dmp_file);
|
return fclose(dmp_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pe_check_export_name(uint64_t base, void *start_addr,
|
|
||||||
struct va_space *vs)
|
|
||||||
{
|
|
||||||
IMAGE_EXPORT_DIRECTORY export_dir;
|
|
||||||
const char *pe_name;
|
|
||||||
|
|
||||||
if (pe_get_data_dir_entry(base, start_addr, IMAGE_FILE_EXPORT_DIRECTORY,
|
|
||||||
&export_dir, sizeof(export_dir), vs)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pe_name = va_space_resolve(vs, base + export_dir.Name);
|
|
||||||
if (!pe_name) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !strcmp(pe_name, PE_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pe_get_pdb_symstore_hash(uint64_t base, void *start_addr,
|
static int pe_get_pdb_symstore_hash(uint64_t base, void *start_addr,
|
||||||
char *hash, struct va_space *vs)
|
char *hash, struct va_space *vs)
|
||||||
{
|
{
|
||||||
|
const char e_magic[2] = "MZ";
|
||||||
|
const char Signature[4] = "PE\0\0";
|
||||||
const char sign_rsds[4] = "RSDS";
|
const char sign_rsds[4] = "RSDS";
|
||||||
|
IMAGE_DOS_HEADER *dos_hdr = start_addr;
|
||||||
|
IMAGE_NT_HEADERS64 nt_hdrs;
|
||||||
|
IMAGE_FILE_HEADER *file_hdr = &nt_hdrs.FileHeader;
|
||||||
|
IMAGE_OPTIONAL_HEADER64 *opt_hdr = &nt_hdrs.OptionalHeader;
|
||||||
|
IMAGE_DATA_DIRECTORY *data_dir = nt_hdrs.OptionalHeader.DataDirectory;
|
||||||
IMAGE_DEBUG_DIRECTORY debug_dir;
|
IMAGE_DEBUG_DIRECTORY debug_dir;
|
||||||
OMFSignatureRSDS rsds;
|
OMFSignatureRSDS rsds;
|
||||||
char *pdb_name;
|
char *pdb_name;
|
||||||
size_t pdb_name_sz;
|
size_t pdb_name_sz;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (pe_get_data_dir_entry(base, start_addr, IMAGE_FILE_DEBUG_DIRECTORY,
|
QEMU_BUILD_BUG_ON(sizeof(*dos_hdr) >= ELF2DMP_PAGE_SIZE);
|
||||||
&debug_dir, sizeof(debug_dir), vs)) {
|
|
||||||
eprintf("Failed to get Debug Directory\n");
|
if (memcmp(&dos_hdr->e_magic, e_magic, sizeof(e_magic))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (va_space_rw(vs, base + dos_hdr->e_lfanew,
|
||||||
|
&nt_hdrs, sizeof(nt_hdrs), 0)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(&nt_hdrs.Signature, Signature, sizeof(Signature)) ||
|
||||||
|
file_hdr->Machine != 0x8664 || opt_hdr->Magic != 0x020b) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Debug Directory RVA = 0x%08"PRIx32"\n",
|
||||||
|
(uint32_t)data_dir[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress);
|
||||||
|
|
||||||
|
if (va_space_rw(vs,
|
||||||
|
base + data_dir[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress,
|
||||||
|
&debug_dir, sizeof(debug_dir), 0)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,7 +473,6 @@ int main(int argc, char *argv[])
|
|||||||
uint64_t KdDebuggerDataBlock;
|
uint64_t KdDebuggerDataBlock;
|
||||||
KDDEBUGGER_DATA64 *kdbg;
|
KDDEBUGGER_DATA64 *kdbg;
|
||||||
uint64_t KdVersionBlock;
|
uint64_t KdVersionBlock;
|
||||||
bool kernel_found = false;
|
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
eprintf("usage:\n\t%s elf_file dmp_file\n", argv[0]);
|
eprintf("usage:\n\t%s elf_file dmp_file\n", argv[0]);
|
||||||
@@ -557,14 +520,11 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*(uint16_t *)nt_start_addr == 0x5a4d) { /* MZ */
|
if (*(uint16_t *)nt_start_addr == 0x5a4d) { /* MZ */
|
||||||
if (pe_check_export_name(KernBase, nt_start_addr, &vs)) {
|
break;
|
||||||
kernel_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!kernel_found) {
|
if (!nt_start_addr) {
|
||||||
eprintf("Failed to find NT kernel image\n");
|
eprintf("Failed to find NT kernel image\n");
|
||||||
err = 1;
|
err = 1;
|
||||||
goto out_ps;
|
goto out_ps;
|
||||||
|
|||||||
@@ -33,90 +33,75 @@ typedef struct IMAGE_DOS_HEADER {
|
|||||||
} __attribute__ ((packed)) IMAGE_DOS_HEADER;
|
} __attribute__ ((packed)) IMAGE_DOS_HEADER;
|
||||||
|
|
||||||
typedef struct IMAGE_FILE_HEADER {
|
typedef struct IMAGE_FILE_HEADER {
|
||||||
uint16_t Machine;
|
uint16_t Machine;
|
||||||
uint16_t NumberOfSections;
|
uint16_t NumberOfSections;
|
||||||
uint32_t TimeDateStamp;
|
uint32_t TimeDateStamp;
|
||||||
uint32_t PointerToSymbolTable;
|
uint32_t PointerToSymbolTable;
|
||||||
uint32_t NumberOfSymbols;
|
uint32_t NumberOfSymbols;
|
||||||
uint16_t SizeOfOptionalHeader;
|
uint16_t SizeOfOptionalHeader;
|
||||||
uint16_t Characteristics;
|
uint16_t Characteristics;
|
||||||
} __attribute__ ((packed)) IMAGE_FILE_HEADER;
|
} __attribute__ ((packed)) IMAGE_FILE_HEADER;
|
||||||
|
|
||||||
typedef struct IMAGE_DATA_DIRECTORY {
|
typedef struct IMAGE_DATA_DIRECTORY {
|
||||||
uint32_t VirtualAddress;
|
uint32_t VirtualAddress;
|
||||||
uint32_t Size;
|
uint32_t Size;
|
||||||
} __attribute__ ((packed)) IMAGE_DATA_DIRECTORY;
|
} __attribute__ ((packed)) IMAGE_DATA_DIRECTORY;
|
||||||
|
|
||||||
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
||||||
|
|
||||||
typedef struct IMAGE_OPTIONAL_HEADER64 {
|
typedef struct IMAGE_OPTIONAL_HEADER64 {
|
||||||
uint16_t Magic; /* 0x20b */
|
uint16_t Magic; /* 0x20b */
|
||||||
uint8_t MajorLinkerVersion;
|
uint8_t MajorLinkerVersion;
|
||||||
uint8_t MinorLinkerVersion;
|
uint8_t MinorLinkerVersion;
|
||||||
uint32_t SizeOfCode;
|
uint32_t SizeOfCode;
|
||||||
uint32_t SizeOfInitializedData;
|
uint32_t SizeOfInitializedData;
|
||||||
uint32_t SizeOfUninitializedData;
|
uint32_t SizeOfUninitializedData;
|
||||||
uint32_t AddressOfEntryPoint;
|
uint32_t AddressOfEntryPoint;
|
||||||
uint32_t BaseOfCode;
|
uint32_t BaseOfCode;
|
||||||
uint64_t ImageBase;
|
uint64_t ImageBase;
|
||||||
uint32_t SectionAlignment;
|
uint32_t SectionAlignment;
|
||||||
uint32_t FileAlignment;
|
uint32_t FileAlignment;
|
||||||
uint16_t MajorOperatingSystemVersion;
|
uint16_t MajorOperatingSystemVersion;
|
||||||
uint16_t MinorOperatingSystemVersion;
|
uint16_t MinorOperatingSystemVersion;
|
||||||
uint16_t MajorImageVersion;
|
uint16_t MajorImageVersion;
|
||||||
uint16_t MinorImageVersion;
|
uint16_t MinorImageVersion;
|
||||||
uint16_t MajorSubsystemVersion;
|
uint16_t MajorSubsystemVersion;
|
||||||
uint16_t MinorSubsystemVersion;
|
uint16_t MinorSubsystemVersion;
|
||||||
uint32_t Win32VersionValue;
|
uint32_t Win32VersionValue;
|
||||||
uint32_t SizeOfImage;
|
uint32_t SizeOfImage;
|
||||||
uint32_t SizeOfHeaders;
|
uint32_t SizeOfHeaders;
|
||||||
uint32_t CheckSum;
|
uint32_t CheckSum;
|
||||||
uint16_t Subsystem;
|
uint16_t Subsystem;
|
||||||
uint16_t DllCharacteristics;
|
uint16_t DllCharacteristics;
|
||||||
uint64_t SizeOfStackReserve;
|
uint64_t SizeOfStackReserve;
|
||||||
uint64_t SizeOfStackCommit;
|
uint64_t SizeOfStackCommit;
|
||||||
uint64_t SizeOfHeapReserve;
|
uint64_t SizeOfHeapReserve;
|
||||||
uint64_t SizeOfHeapCommit;
|
uint64_t SizeOfHeapCommit;
|
||||||
uint32_t LoaderFlags;
|
uint32_t LoaderFlags;
|
||||||
uint32_t NumberOfRvaAndSizes;
|
uint32_t NumberOfRvaAndSizes;
|
||||||
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
||||||
} __attribute__ ((packed)) IMAGE_OPTIONAL_HEADER64;
|
} __attribute__ ((packed)) IMAGE_OPTIONAL_HEADER64;
|
||||||
|
|
||||||
typedef struct IMAGE_NT_HEADERS64 {
|
typedef struct IMAGE_NT_HEADERS64 {
|
||||||
uint32_t Signature;
|
uint32_t Signature;
|
||||||
IMAGE_FILE_HEADER FileHeader;
|
IMAGE_FILE_HEADER FileHeader;
|
||||||
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
|
||||||
} __attribute__ ((packed)) IMAGE_NT_HEADERS64;
|
} __attribute__ ((packed)) IMAGE_NT_HEADERS64;
|
||||||
|
|
||||||
typedef struct IMAGE_EXPORT_DIRECTORY {
|
|
||||||
uint32_t Characteristics;
|
|
||||||
uint32_t TimeDateStamp;
|
|
||||||
uint16_t MajorVersion;
|
|
||||||
uint16_t MinorVersion;
|
|
||||||
uint32_t Name;
|
|
||||||
uint32_t Base;
|
|
||||||
uint32_t NumberOfFunctions;
|
|
||||||
uint32_t NumberOfNames;
|
|
||||||
uint32_t AddressOfFunctions;
|
|
||||||
uint32_t AddressOfNames;
|
|
||||||
uint32_t AddressOfNameOrdinals;
|
|
||||||
} __attribute__ ((packed)) IMAGE_EXPORT_DIRECTORY;
|
|
||||||
|
|
||||||
typedef struct IMAGE_DEBUG_DIRECTORY {
|
typedef struct IMAGE_DEBUG_DIRECTORY {
|
||||||
uint32_t Characteristics;
|
uint32_t Characteristics;
|
||||||
uint32_t TimeDateStamp;
|
uint32_t TimeDateStamp;
|
||||||
uint16_t MajorVersion;
|
uint16_t MajorVersion;
|
||||||
uint16_t MinorVersion;
|
uint16_t MinorVersion;
|
||||||
uint32_t Type;
|
uint32_t Type;
|
||||||
uint32_t SizeOfData;
|
uint32_t SizeOfData;
|
||||||
uint32_t AddressOfRawData;
|
uint32_t AddressOfRawData;
|
||||||
uint32_t PointerToRawData;
|
uint32_t PointerToRawData;
|
||||||
} __attribute__ ((packed)) IMAGE_DEBUG_DIRECTORY;
|
} __attribute__ ((packed)) IMAGE_DEBUG_DIRECTORY;
|
||||||
|
|
||||||
#define IMAGE_DEBUG_TYPE_CODEVIEW 2
|
#define IMAGE_DEBUG_TYPE_CODEVIEW 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define IMAGE_FILE_EXPORT_DIRECTORY 0
|
|
||||||
#define IMAGE_FILE_DEBUG_DIRECTORY 6
|
#define IMAGE_FILE_DEBUG_DIRECTORY 6
|
||||||
|
|
||||||
typedef struct guid_t {
|
typedef struct guid_t {
|
||||||
|
|||||||
@@ -4,12 +4,7 @@
|
|||||||
# This maps email domains to nice easy to read company names
|
# This maps email domains to nice easy to read company names
|
||||||
#
|
#
|
||||||
|
|
||||||
linux.alibaba.com Alibaba
|
|
||||||
amazon.com Amazon
|
|
||||||
amazon.co.uk Amazon
|
|
||||||
amazon.de Amazon
|
|
||||||
amd.com AMD
|
amd.com AMD
|
||||||
aspeedtech.com ASPEED Technology Inc.
|
|
||||||
baidu.com Baidu
|
baidu.com Baidu
|
||||||
bytedance.com ByteDance
|
bytedance.com ByteDance
|
||||||
cmss.chinamobile.com China Mobile
|
cmss.chinamobile.com China Mobile
|
||||||
@@ -17,7 +12,6 @@ citrix.com Citrix
|
|||||||
crudebyte.com Crudebyte
|
crudebyte.com Crudebyte
|
||||||
chinatelecom.cn China Telecom
|
chinatelecom.cn China Telecom
|
||||||
eldorado.org.br Instituto de Pesquisas Eldorado
|
eldorado.org.br Instituto de Pesquisas Eldorado
|
||||||
fb.com Facebook
|
|
||||||
fujitsu.com Fujitsu
|
fujitsu.com Fujitsu
|
||||||
google.com Google
|
google.com Google
|
||||||
greensocs.com GreenSocs
|
greensocs.com GreenSocs
|
||||||
@@ -37,18 +31,15 @@ oracle.com Oracle
|
|||||||
proxmox.com Proxmox
|
proxmox.com Proxmox
|
||||||
quicinc.com Qualcomm Innovation Center
|
quicinc.com Qualcomm Innovation Center
|
||||||
redhat.com Red Hat
|
redhat.com Red Hat
|
||||||
rev.ng rev.ng Labs
|
|
||||||
rt-rk.com RT-RK
|
rt-rk.com RT-RK
|
||||||
samsung.com Samsung
|
samsung.com Samsung
|
||||||
siemens.com Siemens
|
siemens.com Siemens
|
||||||
sifive.com SiFive
|
sifive.com SiFive
|
||||||
suse.com SUSE
|
suse.com SUSE
|
||||||
suse.de SUSE
|
suse.de SUSE
|
||||||
syrmia.com SYRMIA
|
|
||||||
ventanamicro.com Ventana Micro Systems
|
|
||||||
virtuozzo.com Virtuozzo
|
virtuozzo.com Virtuozzo
|
||||||
vrull.eu VRULL
|
|
||||||
wdc.com Western Digital
|
wdc.com Western Digital
|
||||||
windriver.com Wind River
|
windriver.com Wind River
|
||||||
|
xilinx.com Xilinx
|
||||||
yadro.com YADRO
|
yadro.com YADRO
|
||||||
yandex-team.ru Yandex
|
yandex-team.ru Yandex
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#
|
|
||||||
# Alibaba contributors including its subsidiaries
|
|
||||||
#
|
|
||||||
|
|
||||||
# c-sky.com, now part of T-Head, wholly-owned entity of Alibaba Group
|
|
||||||
ren_guo@c-sky.com
|
|
||||||
zhiwei_liu@c-sky.com
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# AMD acquired Xilinx and contributors have been slowly updating emails
|
|
||||||
|
|
||||||
edgar.iglesias@xilinx.com
|
|
||||||
fnu.vikram@xilinx.com
|
|
||||||
francisco.iglesias@xilinx.com
|
|
||||||
sai.pavan.boddu@xilinx.com
|
|
||||||
stefano.stabellini@xilinx.com
|
|
||||||
tong.ho@xilinx.com
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#
|
|
||||||
# Some Facebook contributors also occasionally use personal email addresses.
|
|
||||||
#
|
|
||||||
|
|
||||||
peter@pjd.dev
|
|
||||||
@@ -12,4 +12,3 @@ jcfaracco@gmail.com
|
|||||||
joel@jms.id.au
|
joel@jms.id.au
|
||||||
sjitindarsingh@gmail.com
|
sjitindarsingh@gmail.com
|
||||||
tommusta@gmail.com
|
tommusta@gmail.com
|
||||||
idan.horowitz@gmail.com
|
|
||||||
|
|||||||
@@ -37,8 +37,3 @@ akihiko.odaki@gmail.com
|
|||||||
paul@nowt.org
|
paul@nowt.org
|
||||||
git@xen0n.name
|
git@xen0n.name
|
||||||
simon@simonsafar.com
|
simon@simonsafar.com
|
||||||
research_trasio@irq.a4lg.com
|
|
||||||
shentey@gmail.com
|
|
||||||
bmeng@tinylab.org
|
|
||||||
strahinja.p.jankovic@gmail.com
|
|
||||||
Jason@zx2c4.com
|
|
||||||
|
|||||||
13
cpu.c
13
cpu.c
@@ -31,18 +31,16 @@
|
|||||||
#include "hw/core/sysemu-cpu-ops.h"
|
#include "hw/core/sysemu-cpu-ops.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#endif
|
#endif
|
||||||
#include "sysemu/cpus.h"
|
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
|
#include "sysemu/kvm.h"
|
||||||
#include "exec/replay-core.h"
|
#include "exec/replay-core.h"
|
||||||
#include "exec/cpu-common.h"
|
#include "exec/cpu-common.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/tb-flush.h"
|
|
||||||
#include "exec/translate-all.h"
|
#include "exec/translate-all.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
#include "hw/core/accel-cpu.h"
|
#include "hw/core/accel-cpu.h"
|
||||||
#include "trace/trace-root.h"
|
#include "trace/trace-root.h"
|
||||||
#include "qemu/accel.h"
|
#include "qemu/accel.h"
|
||||||
#include "qemu/plugin.h"
|
|
||||||
|
|
||||||
uintptr_t qemu_host_page_size;
|
uintptr_t qemu_host_page_size;
|
||||||
intptr_t qemu_host_page_mask;
|
intptr_t qemu_host_page_mask;
|
||||||
@@ -327,14 +325,9 @@ void cpu_single_step(CPUState *cpu, int enabled)
|
|||||||
{
|
{
|
||||||
if (cpu->singlestep_enabled != enabled) {
|
if (cpu->singlestep_enabled != enabled) {
|
||||||
cpu->singlestep_enabled = enabled;
|
cpu->singlestep_enabled = enabled;
|
||||||
|
if (kvm_enabled()) {
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
kvm_update_guest_debug(cpu, 0);
|
||||||
const AccelOpsClass *ops = cpus_get_accel();
|
|
||||||
if (ops->update_guest_debug) {
|
|
||||||
ops->update_guest_debug(cpu);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
trace_breakpoint_singlestep(cpu->cpu_index, enabled);
|
trace_breakpoint_singlestep(cpu->cpu_index, enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ qcrypto_afalg_socket_bind(const char *type, const char *name,
|
|||||||
|
|
||||||
if (bind(sbind, (const struct sockaddr *)&salg, sizeof(salg)) != 0) {
|
if (bind(sbind, (const struct sockaddr *)&salg, sizeof(salg)) != 0) {
|
||||||
error_setg_errno(errp, errno, "Failed to bind socket");
|
error_setg_errno(errp, errno, "Failed to bind socket");
|
||||||
close(sbind);
|
closesocket(sbind);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,11 +105,11 @@ void qcrypto_afalg_comm_free(QCryptoAFAlg *afalg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (afalg->tfmfd != -1) {
|
if (afalg->tfmfd != -1) {
|
||||||
close(afalg->tfmfd);
|
closesocket(afalg->tfmfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (afalg->opfd != -1) {
|
if (afalg->opfd != -1) {
|
||||||
close(afalg->opfd);
|
closesocket(afalg->opfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(afalg);
|
g_free(afalg);
|
||||||
|
|||||||
@@ -1014,7 +1014,6 @@ static const char rv_vreg_name_sym[32][4] = {
|
|||||||
#define rv_fmt_rd_offset "O\t0,o"
|
#define rv_fmt_rd_offset "O\t0,o"
|
||||||
#define rv_fmt_rd_rs1_rs2 "O\t0,1,2"
|
#define rv_fmt_rd_rs1_rs2 "O\t0,1,2"
|
||||||
#define rv_fmt_frd_rs1 "O\t3,1"
|
#define rv_fmt_frd_rs1 "O\t3,1"
|
||||||
#define rv_fmt_frd_frs1 "O\t3,4"
|
|
||||||
#define rv_fmt_rd_frs1 "O\t0,4"
|
#define rv_fmt_rd_frs1 "O\t0,4"
|
||||||
#define rv_fmt_rd_frs1_frs2 "O\t0,4,5"
|
#define rv_fmt_rd_frs1_frs2 "O\t0,4,5"
|
||||||
#define rv_fmt_frd_frs1_frs2 "O\t3,4,5"
|
#define rv_fmt_frd_frs1_frs2 "O\t3,4,5"
|
||||||
@@ -1581,15 +1580,15 @@ const rv_opcode_data opcode_data[] = {
|
|||||||
{ "snez", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
{ "snez", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
||||||
{ "sltz", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
{ "sltz", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "sgtz", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
{ "sgtz", rv_codec_r, rv_fmt_rd_rs2, NULL, 0, 0, 0 },
|
||||||
{ "fmv.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fmv.s", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fabs.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fabs.s", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fneg.s", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fneg.s", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fmv.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fmv.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fabs.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fabs.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fneg.d", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fneg.d", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fmv.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fmv.q", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fabs.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fabs.q", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "fneg.q", rv_codec_r, rv_fmt_frd_frs1, NULL, 0, 0, 0 },
|
{ "fneg.q", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "beqz", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 },
|
{ "beqz", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 },
|
||||||
{ "bnez", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 },
|
{ "bnez", rv_codec_sb, rv_fmt_rs1_offset, NULL, 0, 0, 0 },
|
||||||
{ "blez", rv_codec_sb, rv_fmt_rs2_offset, NULL, 0, 0, 0 },
|
{ "blez", rv_codec_sb, rv_fmt_rs2_offset, NULL, 0, 0, 0 },
|
||||||
@@ -1646,9 +1645,9 @@ const rv_opcode_data opcode_data[] = {
|
|||||||
{ "max", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "max", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
{ "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
{ "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
{ "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "ctzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
{ "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "cpopw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
{ "cpopw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||||
{ "slli.uw", rv_codec_i_sh6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 },
|
{ "slli.uw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 },
|
||||||
{ "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
{ "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "rolw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
{ "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
{ "rorw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||||
@@ -2618,10 +2617,10 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
|||||||
switch (((inst >> 12) & 0b111)) {
|
switch (((inst >> 12) & 0b111)) {
|
||||||
case 0: op = rv_op_addiw; break;
|
case 0: op = rv_op_addiw; break;
|
||||||
case 1:
|
case 1:
|
||||||
switch (((inst >> 26) & 0b111111)) {
|
switch (((inst >> 25) & 0b1111111)) {
|
||||||
case 0: op = rv_op_slliw; break;
|
case 0: op = rv_op_slliw; break;
|
||||||
case 2: op = rv_op_slli_uw; break;
|
case 4: op = rv_op_slli_uw; break;
|
||||||
case 24:
|
case 48:
|
||||||
switch ((inst >> 20) & 0b11111) {
|
switch ((inst >> 20) & 0b11111) {
|
||||||
case 0b00000: op = rv_op_clzw; break;
|
case 0b00000: op = rv_op_clzw; break;
|
||||||
case 0b00001: op = rv_op_ctzw; break;
|
case 0b00001: op = rv_op_ctzw; break;
|
||||||
|
|||||||
@@ -67,8 +67,7 @@ Non-supported architectures may be removed in the future following the
|
|||||||
Linux OS, macOS, FreeBSD, NetBSD, OpenBSD
|
Linux OS, macOS, FreeBSD, NetBSD, OpenBSD
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
The project aims to support the most recent major version at all times for
|
The project aims to support the most recent major version at all times. Support
|
||||||
up to five years after its initial release. Support
|
|
||||||
for the previous major version will be dropped 2 years after the new major
|
for the previous major version will be dropped 2 years after the new major
|
||||||
version is released or when the vendor itself drops support, whichever comes
|
version is released or when the vendor itself drops support, whichever comes
|
||||||
first. In this context, third-party efforts to extend the lifetime of a distro
|
first. In this context, third-party efforts to extend the lifetime of a distro
|
||||||
|
|||||||
@@ -196,17 +196,6 @@ CI coverage support may bitrot away before the deprecation process
|
|||||||
completes. The little endian variants of MIPS (both 32 and 64 bit) are
|
completes. The little endian variants of MIPS (both 32 and 64 bit) are
|
||||||
still a supported host architecture.
|
still a supported host architecture.
|
||||||
|
|
||||||
System emulation on 32-bit x86 hosts (since 8.0)
|
|
||||||
''''''''''''''''''''''''''''''''''''''''''''''''
|
|
||||||
|
|
||||||
Support for 32-bit x86 host deployments is increasingly uncommon in mainstream
|
|
||||||
OS distributions given the widespread availability of 64-bit x86 hardware.
|
|
||||||
The QEMU project no longer considers 32-bit x86 support for system emulation to
|
|
||||||
be an effective use of its limited resources, and thus intends to discontinue
|
|
||||||
it. Since all recent x86 hardware from the past >10 years is capable of the
|
|
||||||
64-bit x86 extensions, a corresponding 64-bit OS should be used instead.
|
|
||||||
|
|
||||||
|
|
||||||
QEMU API (QAPI) events
|
QEMU API (QAPI) events
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|||||||
@@ -56,10 +56,8 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "virt"
|
type = "virt"
|
||||||
gic-version = "host"
|
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
gic-version = "host"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
size = "1024"
|
size = "1024"
|
||||||
|
|||||||
@@ -62,10 +62,8 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "virt"
|
type = "virt"
|
||||||
gic-version = "host"
|
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
gic-version = "host"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
size = "1024"
|
size = "1024"
|
||||||
|
|||||||
@@ -61,8 +61,6 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "q35"
|
type = "q35"
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
|
|||||||
@@ -55,8 +55,6 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "q35"
|
type = "q35"
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
|
|||||||
@@ -60,8 +60,6 @@
|
|||||||
|
|
||||||
[machine]
|
[machine]
|
||||||
type = "q35"
|
type = "q35"
|
||||||
|
|
||||||
[accel]
|
|
||||||
accel = "kvm"
|
accel = "kvm"
|
||||||
|
|
||||||
[memory]
|
[memory]
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ provides macros that fall in three camps:
|
|||||||
|
|
||||||
- weak atomic access and manual memory barriers: ``qatomic_read()``,
|
- weak atomic access and manual memory barriers: ``qatomic_read()``,
|
||||||
``qatomic_set()``, ``smp_rmb()``, ``smp_wmb()``, ``smp_mb()``,
|
``qatomic_set()``, ``smp_rmb()``, ``smp_wmb()``, ``smp_mb()``,
|
||||||
``smp_mb_acquire()``, ``smp_mb_release()``, ``smp_read_barrier_depends()``,
|
``smp_mb_acquire()``, ``smp_mb_release()``, ``smp_read_barrier_depends()``;
|
||||||
``smp_mb__before_rmw()``, ``smp_mb__after_rmw()``;
|
|
||||||
|
|
||||||
- sequentially consistent atomic access: everything else.
|
- sequentially consistent atomic access: everything else.
|
||||||
|
|
||||||
@@ -469,19 +468,13 @@ and memory barriers, and the equivalents in QEMU:
|
|||||||
In QEMU, the second kind is named ``atomic_OP_fetch``.
|
In QEMU, the second kind is named ``atomic_OP_fetch``.
|
||||||
|
|
||||||
- different atomic read-modify-write operations in Linux imply
|
- different atomic read-modify-write operations in Linux imply
|
||||||
a different set of memory barriers. In QEMU, all of them enforce
|
a different set of memory barriers; in QEMU, all of them enforce
|
||||||
sequential consistency: there is a single order in which the
|
sequential consistency.
|
||||||
program sees them happen.
|
|
||||||
|
|
||||||
- however, according to the C11 memory model that QEMU uses, this order
|
- in QEMU, ``qatomic_read()`` and ``qatomic_set()`` do not participate in
|
||||||
does not propagate to other memory accesses on either side of the
|
the total ordering enforced by sequentially-consistent operations.
|
||||||
read-modify-write operation. As far as those are concerned, the
|
This is because QEMU uses the C11 memory model. The following example
|
||||||
operation consist of just a load-acquire followed by a store-release.
|
is correct in Linux but not in QEMU:
|
||||||
Stores that precede the RMW operation, and loads that follow it, can
|
|
||||||
still be reordered and will happen *in the middle* of the read-modify-write
|
|
||||||
operation!
|
|
||||||
|
|
||||||
Therefore, the following example is correct in Linux but not in QEMU:
|
|
||||||
|
|
||||||
+----------------------------------+--------------------------------+
|
+----------------------------------+--------------------------------+
|
||||||
| Linux (correct) | QEMU (incorrect) |
|
| Linux (correct) | QEMU (incorrect) |
|
||||||
@@ -495,24 +488,9 @@ and memory barriers, and the equivalents in QEMU:
|
|||||||
because the read of ``y`` can be moved (by either the processor or the
|
because the read of ``y`` can be moved (by either the processor or the
|
||||||
compiler) before the write of ``x``.
|
compiler) before the write of ``x``.
|
||||||
|
|
||||||
Fixing this requires a full memory barrier between the write of ``x`` and
|
Fixing this requires an ``smp_mb()`` memory barrier between the write
|
||||||
the read of ``y``. QEMU provides ``smp_mb__before_rmw()`` and
|
of ``x`` and the read of ``y``. In the common case where only one thread
|
||||||
``smp_mb__after_rmw()``; they act both as an optimization,
|
writes ``x``, it is also possible to write it like this:
|
||||||
avoiding the memory barrier on processors where it is unnecessary,
|
|
||||||
and as a clarification of this corner case of the C11 memory model:
|
|
||||||
|
|
||||||
+--------------------------------+
|
|
||||||
| QEMU (correct) |
|
|
||||||
+================================+
|
|
||||||
| :: |
|
|
||||||
| |
|
|
||||||
| a = qatomic_fetch_add(&x, 2);|
|
|
||||||
| smp_mb__after_rmw(); |
|
|
||||||
| b = qatomic_read(&y); |
|
|
||||||
+--------------------------------+
|
|
||||||
|
|
||||||
In the common case where only one thread writes ``x``, it is also possible
|
|
||||||
to write it like this:
|
|
||||||
|
|
||||||
+--------------------------------+
|
+--------------------------------+
|
||||||
| QEMU (correct) |
|
| QEMU (correct) |
|
||||||
|
|||||||
@@ -59,37 +59,22 @@ System memory dirty pages tracking
|
|||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
A ``log_global_start`` and ``log_global_stop`` memory listener callback informs
|
A ``log_global_start`` and ``log_global_stop`` memory listener callback informs
|
||||||
the VFIO dirty tracking module to start and stop dirty page tracking. A
|
the VFIO IOMMU module to start and stop dirty page tracking. A ``log_sync``
|
||||||
``log_sync`` memory listener callback queries the dirty page bitmap from the
|
memory listener callback marks those system memory pages as dirty which are
|
||||||
dirty tracking module and marks system memory pages which were DMA-ed by the
|
used for DMA by the VFIO device. The dirty pages bitmap is queried per
|
||||||
VFIO device as dirty. The dirty page bitmap is queried per container.
|
container. All pages pinned by the vendor driver through external APIs have to
|
||||||
|
be marked as dirty during migration. When there are CPU writes, CPU dirty page
|
||||||
Currently there are two ways dirty page tracking can be done:
|
tracking can identify dirtied pages, but any page pinned by the vendor driver
|
||||||
(1) Device dirty tracking:
|
can also be written by the device. There is currently no device or IOMMU
|
||||||
In this method the device is responsible to log and report its DMAs. This
|
support for dirty page tracking in hardware.
|
||||||
method can be used only if the device is capable of tracking its DMAs.
|
|
||||||
Discovering device capability, starting and stopping dirty tracking, and
|
|
||||||
syncing the dirty bitmaps from the device are done using the DMA logging uAPI.
|
|
||||||
More info about the uAPI can be found in the comments of the
|
|
||||||
``vfio_device_feature_dma_logging_control`` and
|
|
||||||
``vfio_device_feature_dma_logging_report`` structures in the header file
|
|
||||||
linux-headers/linux/vfio.h.
|
|
||||||
|
|
||||||
(2) VFIO IOMMU module:
|
|
||||||
In this method dirty tracking is done by IOMMU. However, there is currently no
|
|
||||||
IOMMU support for dirty page tracking. For this reason, all pages are
|
|
||||||
perpetually marked dirty, unless the device driver pins pages through external
|
|
||||||
APIs in which case only those pinned pages are perpetually marked dirty.
|
|
||||||
|
|
||||||
If the above two methods are not supported, all pages are perpetually marked
|
|
||||||
dirty by QEMU.
|
|
||||||
|
|
||||||
By default, dirty pages are tracked during pre-copy as well as stop-and-copy
|
By default, dirty pages are tracked during pre-copy as well as stop-and-copy
|
||||||
phase. So, a page marked as dirty will be copied to the destination in both
|
phase. So, a page pinned by the vendor driver will be copied to the destination
|
||||||
phases. Copying dirty pages in pre-copy phase helps QEMU to predict if it can
|
in both phases. Copying dirty pages in pre-copy phase helps QEMU to predict if
|
||||||
achieve its downtime tolerances. If QEMU during pre-copy phase keeps finding
|
it can achieve its downtime tolerances. If QEMU during pre-copy phase keeps
|
||||||
dirty pages continuously, then it understands that even in stop-and-copy phase,
|
finding dirty pages continuously, then it understands that even in stop-and-copy
|
||||||
it is likely to find dirty pages and can predict the downtime accordingly.
|
phase, it is likely to find dirty pages and can predict the downtime
|
||||||
|
accordingly.
|
||||||
|
|
||||||
QEMU also provides a per device opt-out option ``pre-copy-dirty-page-tracking``
|
QEMU also provides a per device opt-out option ``pre-copy-dirty-page-tracking``
|
||||||
which disables querying the dirty bitmap during pre-copy phase. If it is set to
|
which disables querying the dirty bitmap during pre-copy phase. If it is set to
|
||||||
@@ -104,8 +89,7 @@ phase of migration. In that case, the unmap ioctl returns any dirty pages in
|
|||||||
that range and QEMU reports corresponding guest physical pages dirty. During
|
that range and QEMU reports corresponding guest physical pages dirty. During
|
||||||
stop-and-copy phase, an IOMMU notifier is used to get a callback for mapped
|
stop-and-copy phase, an IOMMU notifier is used to get a callback for mapped
|
||||||
pages and then dirty pages bitmap is fetched from VFIO IOMMU modules for those
|
pages and then dirty pages bitmap is fetched from VFIO IOMMU modules for those
|
||||||
mapped ranges. If device dirty tracking is enabled with vIOMMU, live migration
|
mapped ranges.
|
||||||
will be blocked.
|
|
||||||
|
|
||||||
Flow of state changes during Live migration
|
Flow of state changes during Live migration
|
||||||
===========================================
|
===========================================
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ if sphinx_build.found()
|
|||||||
SPHINX_ARGS = ['env', 'CONFDIR=' + qemu_confdir, sphinx_build, '-q']
|
SPHINX_ARGS = ['env', 'CONFDIR=' + qemu_confdir, sphinx_build, '-q']
|
||||||
# If we're making warnings fatal, apply this to Sphinx runs as well
|
# If we're making warnings fatal, apply this to Sphinx runs as well
|
||||||
if get_option('werror')
|
if get_option('werror')
|
||||||
SPHINX_ARGS += [ '-W', '-Dkerneldoc_werror=1' ]
|
SPHINX_ARGS += [ '-W' ]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# This is a bit awkward but works: create a trivial document and
|
# This is a bit awkward but works: create a trivial document and
|
||||||
|
|||||||
@@ -74,10 +74,6 @@ class KernelDocDirective(Directive):
|
|||||||
# Sphinx versions
|
# Sphinx versions
|
||||||
cmd += ['-sphinx-version', sphinx.__version__]
|
cmd += ['-sphinx-version', sphinx.__version__]
|
||||||
|
|
||||||
# Pass through the warnings-as-errors flag
|
|
||||||
if env.config.kerneldoc_werror:
|
|
||||||
cmd += ['-Werror']
|
|
||||||
|
|
||||||
filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
|
filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
|
||||||
export_file_patterns = []
|
export_file_patterns = []
|
||||||
|
|
||||||
@@ -171,7 +167,6 @@ def setup(app):
|
|||||||
app.add_config_value('kerneldoc_bin', None, 'env')
|
app.add_config_value('kerneldoc_bin', None, 'env')
|
||||||
app.add_config_value('kerneldoc_srctree', None, 'env')
|
app.add_config_value('kerneldoc_srctree', None, 'env')
|
||||||
app.add_config_value('kerneldoc_verbosity', 1, 'env')
|
app.add_config_value('kerneldoc_verbosity', 1, 'env')
|
||||||
app.add_config_value('kerneldoc_werror', 0, 'env')
|
|
||||||
|
|
||||||
app.add_directive('kernel-doc', KernelDocDirective)
|
app.add_directive('kernel-doc', KernelDocDirective)
|
||||||
|
|
||||||
|
|||||||
@@ -177,32 +177,39 @@ are named with the prefix "kvm-". KVM VCPU features may be probed,
|
|||||||
enabled, and disabled in the same way as other CPU features. Below is
|
enabled, and disabled in the same way as other CPU features. Below is
|
||||||
the list of KVM VCPU features and their descriptions.
|
the list of KVM VCPU features and their descriptions.
|
||||||
|
|
||||||
``kvm-no-adjvtime``
|
kvm-no-adjvtime By default kvm-no-adjvtime is disabled. This
|
||||||
By default kvm-no-adjvtime is disabled. This means that by default
|
means that by default the virtual time
|
||||||
the virtual time adjustment is enabled (vtime is not *not* adjusted).
|
adjustment is enabled (vtime is not *not*
|
||||||
|
adjusted).
|
||||||
|
|
||||||
When virtual time adjustment is enabled each time the VM transitions
|
When virtual time adjustment is enabled each
|
||||||
back to running state the VCPU's virtual counter is updated to
|
time the VM transitions back to running state
|
||||||
ensure stopped time is not counted. This avoids time jumps
|
the VCPU's virtual counter is updated to ensure
|
||||||
surprising guest OSes and applications, as long as they use the
|
stopped time is not counted. This avoids time
|
||||||
virtual counter for timekeeping. However it has the side effect of
|
jumps surprising guest OSes and applications,
|
||||||
the virtual and physical counters diverging. All timekeeping based
|
as long as they use the virtual counter for
|
||||||
on the virtual counter will appear to lag behind any timekeeping
|
timekeeping. However it has the side effect of
|
||||||
that does not subtract VM stopped time. The guest may resynchronize
|
the virtual and physical counters diverging.
|
||||||
its virtual counter with other time sources as needed.
|
All timekeeping based on the virtual counter
|
||||||
|
will appear to lag behind any timekeeping that
|
||||||
|
does not subtract VM stopped time. The guest
|
||||||
|
may resynchronize its virtual counter with
|
||||||
|
other time sources as needed.
|
||||||
|
|
||||||
Enable kvm-no-adjvtime to disable virtual time adjustment, also
|
Enable kvm-no-adjvtime to disable virtual time
|
||||||
restoring the legacy (pre-5.0) behavior.
|
adjustment, also restoring the legacy (pre-5.0)
|
||||||
|
behavior.
|
||||||
|
|
||||||
``kvm-steal-time``
|
kvm-steal-time Since v5.2, kvm-steal-time is enabled by
|
||||||
Since v5.2, kvm-steal-time is enabled by default when KVM is
|
default when KVM is enabled, the feature is
|
||||||
enabled, the feature is supported, and the guest is 64-bit.
|
supported, and the guest is 64-bit.
|
||||||
|
|
||||||
When kvm-steal-time is enabled a 64-bit guest can account for time
|
When kvm-steal-time is enabled a 64-bit guest
|
||||||
its CPUs were not running due to the host not scheduling the
|
can account for time its CPUs were not running
|
||||||
corresponding VCPU threads. The accounting statistics may influence
|
due to the host not scheduling the corresponding
|
||||||
the guest scheduler behavior and/or be exposed to the guest
|
VCPU threads. The accounting statistics may
|
||||||
userspace.
|
influence the guest scheduler behavior and/or be
|
||||||
|
exposed to the guest userspace.
|
||||||
|
|
||||||
TCG VCPU Features
|
TCG VCPU Features
|
||||||
=================
|
=================
|
||||||
@@ -210,15 +217,16 @@ TCG VCPU Features
|
|||||||
TCG VCPU features are CPU features that are specific to TCG.
|
TCG VCPU features are CPU features that are specific to TCG.
|
||||||
Below is the list of TCG VCPU features and their descriptions.
|
Below is the list of TCG VCPU features and their descriptions.
|
||||||
|
|
||||||
``pauth-impdef``
|
pauth-impdef When ``FEAT_Pauth`` is enabled, either the
|
||||||
When ``FEAT_Pauth`` is enabled, either the *impdef* (Implementation
|
*impdef* (Implementation Defined) algorithm
|
||||||
Defined) algorithm is enabled or the *architected* QARMA algorithm
|
is enabled or the *architected* QARMA algorithm
|
||||||
is enabled. By default the impdef algorithm is disabled, and QARMA
|
is enabled. By default the impdef algorithm
|
||||||
is enabled.
|
is disabled, and QARMA is enabled.
|
||||||
|
|
||||||
The architected QARMA algorithm has good cryptographic properties,
|
The architected QARMA algorithm has good
|
||||||
but can be quite slow to emulate. The impdef algorithm used by QEMU
|
cryptographic properties, but can be quite slow
|
||||||
is non-cryptographic but significantly faster.
|
to emulate. The impdef algorithm used by QEMU
|
||||||
|
is non-cryptographic but significantly faster.
|
||||||
|
|
||||||
SVE CPU Properties
|
SVE CPU Properties
|
||||||
==================
|
==================
|
||||||
|
|||||||
@@ -93,4 +93,3 @@ Emulated Devices
|
|||||||
devices/virtio-pmem.rst
|
devices/virtio-pmem.rst
|
||||||
devices/vhost-user-rng.rst
|
devices/vhost-user-rng.rst
|
||||||
devices/canokey.rst
|
devices/canokey.rst
|
||||||
devices/igb.rst
|
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
.. _igb:
|
|
||||||
|
|
||||||
igb
|
|
||||||
---
|
|
||||||
|
|
||||||
igb is a family of Intel's gigabit ethernet controllers. In QEMU, 82576
|
|
||||||
emulation is implemented in particular. Its datasheet is available at [1]_.
|
|
||||||
|
|
||||||
This implementation is expected to be useful to test SR-IOV networking without
|
|
||||||
requiring physical hardware.
|
|
||||||
|
|
||||||
Limitations
|
|
||||||
===========
|
|
||||||
|
|
||||||
This igb implementation was tested with Linux Test Project [2]_ and Windows HLK
|
|
||||||
[3]_ during the initial development. The command used when testing with LTP is:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
network.sh -6mta
|
|
||||||
|
|
||||||
Be aware that this implementation lacks many functionalities available with the
|
|
||||||
actual hardware, and you may experience various failures if you try to use it
|
|
||||||
with a different operating system other than Linux and Windows or if you try
|
|
||||||
functionalities not covered by the tests.
|
|
||||||
|
|
||||||
Using igb
|
|
||||||
=========
|
|
||||||
|
|
||||||
Using igb should be nothing different from using another network device. See
|
|
||||||
:ref:`pcsys_005fnetwork` in general.
|
|
||||||
|
|
||||||
However, you may also need to perform additional steps to activate SR-IOV
|
|
||||||
feature on your guest. For Linux, refer to [4]_.
|
|
||||||
|
|
||||||
Developing igb
|
|
||||||
==============
|
|
||||||
|
|
||||||
igb is the successor of e1000e, and e1000e is the successor of e1000 in turn.
|
|
||||||
As these devices are very similar, if you make a change for igb and the same
|
|
||||||
change can be applied to e1000e and e1000, please do so.
|
|
||||||
|
|
||||||
Please do not forget to run tests before submitting a change. As tests included
|
|
||||||
in QEMU is very minimal, run some application which is likely to be affected by
|
|
||||||
the change to confirm it works in an integrated system.
|
|
||||||
|
|
||||||
Testing igb
|
|
||||||
===========
|
|
||||||
|
|
||||||
A qtest of the basic functionality is available. Run the below at the build
|
|
||||||
directory:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
meson test qtest-x86_64/qos-test
|
|
||||||
|
|
||||||
ethtool can test register accesses, interrupts, etc. It is automated as an
|
|
||||||
Avocado test and can be ran with the following command:
|
|
||||||
|
|
||||||
.. code:: shell
|
|
||||||
|
|
||||||
make check-avocado AVOCADO_TESTS=tests/avocado/igb.py
|
|
||||||
|
|
||||||
References
|
|
||||||
==========
|
|
||||||
|
|
||||||
.. [1] https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eb-gigabit-ethernet-controller-datasheet.pdf
|
|
||||||
.. [2] https://github.com/linux-test-project/ltp
|
|
||||||
.. [3] https://learn.microsoft.com/en-us/windows-hardware/test/hlk/
|
|
||||||
.. [4] https://docs.kernel.org/PCI/pci-iov-howto.html
|
|
||||||
@@ -9,8 +9,6 @@ KVM has support for hosting Xen guests, intercepting Xen hypercalls and event
|
|||||||
channel (Xen PV interrupt) delivery. This allows guests which expect to be
|
channel (Xen PV interrupt) delivery. This allows guests which expect to be
|
||||||
run under Xen to be hosted in QEMU under Linux/KVM instead.
|
run under Xen to be hosted in QEMU under Linux/KVM instead.
|
||||||
|
|
||||||
Using the split irqchip is mandatory for Xen support.
|
|
||||||
|
|
||||||
Setup
|
Setup
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@@ -19,14 +17,14 @@ accelerator, for example for Xen 4.10:
|
|||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
|qemu_system| --accel kvm,xen-version=0x4000a,kernel-irqchip=split
|
|qemu_system| --accel kvm,xen-version=0x4000a
|
||||||
|
|
||||||
Additionally, virtual APIC support can be advertised to the guest through the
|
Additionally, virtual APIC support can be advertised to the guest through the
|
||||||
``xen-vapic`` CPU flag:
|
``xen-vapic`` CPU flag:
|
||||||
|
|
||||||
.. parsed-literal::
|
.. parsed-literal::
|
||||||
|
|
||||||
|qemu_system| --accel kvm,xen-version=0x4000a,kernel-irqchip=split --cpu host,+xen_vapic
|
|qemu_system| --accel kvm,xen-version=0x4000a --cpu host,+xen_vapic
|
||||||
|
|
||||||
When Xen support is enabled, QEMU changes hypervisor identification (CPUID
|
When Xen support is enabled, QEMU changes hypervisor identification (CPUID
|
||||||
0x40000000..0x4000000A) to Xen. The KVM identification and features are not
|
0x40000000..0x4000000A) to Xen. The KVM identification and features are not
|
||||||
@@ -35,25 +33,11 @@ moves to leaves 0x40000100..0x4000010A.
|
|||||||
|
|
||||||
The Xen platform device is enabled automatically for a Xen guest. This allows
|
The Xen platform device is enabled automatically for a Xen guest. This allows
|
||||||
a guest to unplug all emulated devices, in order to use Xen PV block and network
|
a guest to unplug all emulated devices, in order to use Xen PV block and network
|
||||||
drivers instead. Under Xen, the boot disk is typically available both via IDE
|
drivers instead. Note that until the Xen PV device back ends are enabled to work
|
||||||
emulation, and as a PV block device. Guest bootloaders typically use IDE to load
|
with Xen mode in QEMU, that is unlikely to cause significant joy. Linux guests
|
||||||
the guest kernel, which then unplugs the IDE and continues with the Xen PV block
|
can be dissuaded from this by adding 'xen_emul_unplug=never' on their command
|
||||||
device.
|
line, and it can also be noted that AHCI disk controllers are exempt from being
|
||||||
|
unplugged, as are passthrough VFIO PCI devices.
|
||||||
This configuration can be achieved as follows
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
|qemu_system| -M pc --accel kvm,xen-version=0x4000a,kernel-irqchip=split \\
|
|
||||||
-drive file=${GUEST_IMAGE},if=none,id=disk,file.locking=off -device xen-disk,drive=disk,vdev=xvda \\
|
|
||||||
-drive file=${GUEST_IMAGE},index=2,media=disk,file.locking=off,if=ide
|
|
||||||
|
|
||||||
It is necessary to use the pc machine type, as the q35 machine uses AHCI instead
|
|
||||||
of legacy IDE, and AHCI disks are not unplugged through the Xen PV unplug
|
|
||||||
mechanism.
|
|
||||||
|
|
||||||
VirtIO devices can also be used; Linux guests may need to be dissuaded from
|
|
||||||
umplugging them by adding 'xen_emul_unplug=never' on their command line.
|
|
||||||
|
|
||||||
Properties
|
Properties
|
||||||
----------
|
----------
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ endian options, ``qemu-system-mips``, ``qemu-system-mipsel``
|
|||||||
``qemu-system-mips64`` and ``qemu-system-mips64el``. Five different
|
``qemu-system-mips64`` and ``qemu-system-mips64el``. Five different
|
||||||
machine types are emulated:
|
machine types are emulated:
|
||||||
|
|
||||||
|
- A generic ISA PC-like machine \"mips\"
|
||||||
|
|
||||||
- The MIPS Malta prototype board \"malta\"
|
- The MIPS Malta prototype board \"malta\"
|
||||||
|
|
||||||
- An ACER Pica \"pica61\". This machine needs the 64-bit emulator.
|
- An ACER Pica \"pica61\". This machine needs the 64-bit emulator.
|
||||||
@@ -17,6 +19,18 @@ machine types are emulated:
|
|||||||
- A MIPS Magnum R4000 machine \"magnum\". This machine needs the
|
- A MIPS Magnum R4000 machine \"magnum\". This machine needs the
|
||||||
64-bit emulator.
|
64-bit emulator.
|
||||||
|
|
||||||
|
The generic emulation is supported by Debian 'Etch' and is able to
|
||||||
|
install Debian into a virtual disk image. The following devices are
|
||||||
|
emulated:
|
||||||
|
|
||||||
|
- A range of MIPS CPUs, default is the 24Kf
|
||||||
|
|
||||||
|
- PC style serial port
|
||||||
|
|
||||||
|
- PC style IDE disk
|
||||||
|
|
||||||
|
- NE2000 network card
|
||||||
|
|
||||||
The Malta emulation supports the following devices:
|
The Malta emulation supports the following devices:
|
||||||
|
|
||||||
- Core board with MIPS 24Kf CPU and Galileo system controller
|
- Core board with MIPS 24Kf CPU and Galileo system controller
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include "qapi/qapi-commands-dump.h"
|
#include "qapi/qapi-commands-dump.h"
|
||||||
#include "qapi/qapi-events-dump.h"
|
#include "qapi/qapi-events-dump.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "hw/misc/vmcoreinfo.h"
|
#include "hw/misc/vmcoreinfo.h"
|
||||||
#include "migration/blocker.h"
|
#include "migration/blocker.h"
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sysemu/dump.h"
|
#include "sysemu/dump.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
#include "exec/cpu-defs.h"
|
#include "exec/cpu-defs.h"
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
Copying and distribution of this file, with or without modification,
|
|
||||||
are permitted in any medium without royalty provided the copyright
|
|
||||||
notice and this notice are preserved. -->
|
|
||||||
|
|
||||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
|
||||||
<feature name="org.gnu.gdb.aarch64.pauth">
|
|
||||||
<reg name="pauth_dmask" bitsize="64"/>
|
|
||||||
<reg name="pauth_cmask" bitsize="64"/>
|
|
||||||
<reg name="pauth_dmask_high" bitsize="64"/>
|
|
||||||
<reg name="pauth_cmask_high" bitsize="64"/>
|
|
||||||
</feature>
|
|
||||||
|
|
||||||
1656
gdbstub/gdbstub.c
1656
gdbstub/gdbstub.c
File diff suppressed because it is too large
Load Diff
@@ -6,220 +6,14 @@
|
|||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GDBSTUB_INTERNALS_H
|
#ifndef _INTERNALS_H_
|
||||||
#define GDBSTUB_INTERNALS_H
|
#define _INTERNALS_H_
|
||||||
|
|
||||||
#include "exec/cpu-common.h"
|
#include "exec/cpu-common.h"
|
||||||
|
|
||||||
#define MAX_PACKET_LENGTH 4096
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Shared structures and definitions
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum {
|
|
||||||
GDB_SIGNAL_0 = 0,
|
|
||||||
GDB_SIGNAL_INT = 2,
|
|
||||||
GDB_SIGNAL_QUIT = 3,
|
|
||||||
GDB_SIGNAL_TRAP = 5,
|
|
||||||
GDB_SIGNAL_ABRT = 6,
|
|
||||||
GDB_SIGNAL_ALRM = 14,
|
|
||||||
GDB_SIGNAL_IO = 23,
|
|
||||||
GDB_SIGNAL_XCPU = 24,
|
|
||||||
GDB_SIGNAL_UNKNOWN = 143
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct GDBProcess {
|
|
||||||
uint32_t pid;
|
|
||||||
bool attached;
|
|
||||||
|
|
||||||
char target_xml[1024];
|
|
||||||
} GDBProcess;
|
|
||||||
|
|
||||||
enum RSState {
|
|
||||||
RS_INACTIVE,
|
|
||||||
RS_IDLE,
|
|
||||||
RS_GETLINE,
|
|
||||||
RS_GETLINE_ESC,
|
|
||||||
RS_GETLINE_RLE,
|
|
||||||
RS_CHKSUM1,
|
|
||||||
RS_CHKSUM2,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct GDBState {
|
|
||||||
bool init; /* have we been initialised? */
|
|
||||||
CPUState *c_cpu; /* current CPU for step/continue ops */
|
|
||||||
CPUState *g_cpu; /* current CPU for other ops */
|
|
||||||
CPUState *query_cpu; /* for q{f|s}ThreadInfo */
|
|
||||||
enum RSState state; /* parsing state */
|
|
||||||
char line_buf[MAX_PACKET_LENGTH];
|
|
||||||
int line_buf_index;
|
|
||||||
int line_sum; /* running checksum */
|
|
||||||
int line_csum; /* checksum at the end of the packet */
|
|
||||||
GByteArray *last_packet;
|
|
||||||
int signal;
|
|
||||||
bool multiprocess;
|
|
||||||
GDBProcess *processes;
|
|
||||||
int process_num;
|
|
||||||
GString *str_buf;
|
|
||||||
GByteArray *mem_buf;
|
|
||||||
int sstep_flags;
|
|
||||||
int supported_sstep_flags;
|
|
||||||
} GDBState;
|
|
||||||
|
|
||||||
/* lives in main gdbstub.c */
|
|
||||||
extern GDBState gdbserver_state;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inline utility function, convert from int to hex and back
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline int fromhex(int v)
|
|
||||||
{
|
|
||||||
if (v >= '0' && v <= '9') {
|
|
||||||
return v - '0';
|
|
||||||
} else if (v >= 'A' && v <= 'F') {
|
|
||||||
return v - 'A' + 10;
|
|
||||||
} else if (v >= 'a' && v <= 'f') {
|
|
||||||
return v - 'a' + 10;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int tohex(int v)
|
|
||||||
{
|
|
||||||
if (v < 10) {
|
|
||||||
return v + '0';
|
|
||||||
} else {
|
|
||||||
return v - 10 + 'a';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Connection helpers for both softmmu and user backends
|
|
||||||
*/
|
|
||||||
|
|
||||||
void gdb_put_strbuf(void);
|
|
||||||
int gdb_put_packet(const char *buf);
|
|
||||||
int gdb_put_packet_binary(const char *buf, int len, bool dump);
|
|
||||||
void gdb_hextomem(GByteArray *mem, const char *buf, int len);
|
|
||||||
void gdb_memtohex(GString *buf, const uint8_t *mem, int len);
|
|
||||||
void gdb_memtox(GString *buf, const char *mem, int len);
|
|
||||||
void gdb_read_byte(uint8_t ch);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Packet acknowledgement - we handle this slightly differently
|
|
||||||
* between user and softmmu mode, mainly to deal with the differences
|
|
||||||
* between the flexible chardev and the direct fd approaches.
|
|
||||||
*
|
|
||||||
* We currently don't support a negotiated QStartNoAckMode
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gdb_got_immediate_ack() - check ok to continue
|
|
||||||
*
|
|
||||||
* Returns true to continue, false to re-transmit for user only, the
|
|
||||||
* softmmu stub always returns true.
|
|
||||||
*/
|
|
||||||
bool gdb_got_immediate_ack(void);
|
|
||||||
/* utility helpers */
|
|
||||||
CPUState *gdb_first_attached_cpu(void);
|
|
||||||
void gdb_append_thread_id(CPUState *cpu, GString *buf);
|
|
||||||
int gdb_get_cpu_index(CPUState *cpu);
|
|
||||||
unsigned int gdb_get_max_cpus(void); /* both */
|
|
||||||
bool gdb_can_reverse(void); /* softmmu, stub for user */
|
|
||||||
|
|
||||||
void gdb_create_default_process(GDBState *s);
|
|
||||||
|
|
||||||
/* signal mapping, common for softmmu, specialised for user-mode */
|
|
||||||
int gdb_signal_to_target(int sig);
|
|
||||||
int gdb_target_signal_to_gdb(int sig);
|
|
||||||
|
|
||||||
int gdb_get_char(void); /* user only */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gdb_continue() - handle continue in mode specific way.
|
|
||||||
*/
|
|
||||||
void gdb_continue(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gdb_continue_partial() - handle partial continue in mode specific way.
|
|
||||||
*/
|
|
||||||
int gdb_continue_partial(char *newstates);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helpers with separate softmmu and user implementations
|
|
||||||
*/
|
|
||||||
void gdb_put_buffer(const uint8_t *buf, int len);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Command handlers - either specialised or softmmu or user only
|
|
||||||
*/
|
|
||||||
void gdb_init_gdbserver_state(void);
|
|
||||||
|
|
||||||
typedef enum GDBThreadIdKind {
|
|
||||||
GDB_ONE_THREAD = 0,
|
|
||||||
GDB_ALL_THREADS, /* One process, all threads */
|
|
||||||
GDB_ALL_PROCESSES,
|
|
||||||
GDB_READ_THREAD_ERR
|
|
||||||
} GDBThreadIdKind;
|
|
||||||
|
|
||||||
typedef union GdbCmdVariant {
|
|
||||||
const char *data;
|
|
||||||
uint8_t opcode;
|
|
||||||
unsigned long val_ul;
|
|
||||||
unsigned long long val_ull;
|
|
||||||
struct {
|
|
||||||
GDBThreadIdKind kind;
|
|
||||||
uint32_t pid;
|
|
||||||
uint32_t tid;
|
|
||||||
} thread_id;
|
|
||||||
} GdbCmdVariant;
|
|
||||||
|
|
||||||
#define get_param(p, i) (&g_array_index(p, GdbCmdVariant, i))
|
|
||||||
|
|
||||||
void gdb_handle_query_rcmd(GArray *params, void *user_ctx); /* softmmu */
|
|
||||||
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
|
|
||||||
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
|
|
||||||
|
|
||||||
void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */
|
|
||||||
|
|
||||||
/* softmmu only */
|
|
||||||
void gdb_handle_query_qemu_phy_mem_mode(GArray *params, void *user_ctx);
|
|
||||||
void gdb_handle_set_qemu_phy_mem_mode(GArray *params, void *user_ctx);
|
|
||||||
|
|
||||||
/* sycall handling */
|
|
||||||
void gdb_handle_file_io(GArray *params, void *user_ctx);
|
|
||||||
bool gdb_handled_syscall(void);
|
|
||||||
void gdb_disable_syscalls(void);
|
|
||||||
void gdb_syscall_reset(void);
|
|
||||||
|
|
||||||
/* user/softmmu specific syscall handling */
|
|
||||||
void gdb_syscall_handling(const char *syscall_packet);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Break/Watch point support - there is an implementation for softmmu
|
|
||||||
* and user mode.
|
|
||||||
*/
|
|
||||||
bool gdb_supports_guest_debug(void);
|
bool gdb_supports_guest_debug(void);
|
||||||
int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len);
|
int gdb_breakpoint_insert(CPUState *cs, int type, vaddr addr, vaddr len);
|
||||||
int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len);
|
int gdb_breakpoint_remove(CPUState *cs, int type, vaddr addr, vaddr len);
|
||||||
void gdb_breakpoint_remove_all(CPUState *cs);
|
void gdb_breakpoint_remove_all(CPUState *cs);
|
||||||
|
|
||||||
/**
|
#endif /* _INTERNALS_H_ */
|
||||||
* gdb_target_memory_rw_debug() - handle debug access to memory
|
|
||||||
* @cs: CPUState
|
|
||||||
* @addr: nominal address, could be an entire physical address
|
|
||||||
* @buf: data
|
|
||||||
* @len: length of access
|
|
||||||
* @is_write: is it a write operation
|
|
||||||
*
|
|
||||||
* This function is specialised depending on the mode we are running
|
|
||||||
* in. For softmmu guests we can switch the interpretation of the
|
|
||||||
* address to a physical address.
|
|
||||||
*/
|
|
||||||
int gdb_target_memory_rw_debug(CPUState *cs, hwaddr addr,
|
|
||||||
uint8_t *buf, int len, bool is_write);
|
|
||||||
|
|
||||||
#endif /* GDBSTUB_INTERNALS_H */
|
|
||||||
|
|||||||
@@ -4,34 +4,6 @@
|
|||||||
# types such as hwaddr.
|
# types such as hwaddr.
|
||||||
#
|
#
|
||||||
|
|
||||||
# We need to build the core gdb code via a library to be able to tweak
|
specific_ss.add(files('gdbstub.c'))
|
||||||
# cflags so:
|
softmmu_ss.add(files('softmmu.c'))
|
||||||
|
user_ss.add(files('user.c'))
|
||||||
gdb_user_ss = ss.source_set()
|
|
||||||
gdb_softmmu_ss = ss.source_set()
|
|
||||||
|
|
||||||
# We build two versions of gdbstub, one for each mode
|
|
||||||
gdb_user_ss.add(files('gdbstub.c', 'user.c'))
|
|
||||||
gdb_softmmu_ss.add(files('gdbstub.c', 'softmmu.c'))
|
|
||||||
|
|
||||||
gdb_user_ss = gdb_user_ss.apply(config_host, strict: false)
|
|
||||||
gdb_softmmu_ss = gdb_softmmu_ss.apply(config_host, strict: false)
|
|
||||||
|
|
||||||
libgdb_user = static_library('gdb_user',
|
|
||||||
gdb_user_ss.sources() + genh,
|
|
||||||
name_suffix: 'fa',
|
|
||||||
c_args: '-DCONFIG_USER_ONLY')
|
|
||||||
|
|
||||||
libgdb_softmmu = static_library('gdb_softmmu',
|
|
||||||
gdb_softmmu_ss.sources() + genh,
|
|
||||||
name_suffix: 'fa')
|
|
||||||
|
|
||||||
gdb_user = declare_dependency(link_whole: libgdb_user)
|
|
||||||
user_ss.add(gdb_user)
|
|
||||||
gdb_softmmu = declare_dependency(link_whole: libgdb_softmmu)
|
|
||||||
softmmu_ss.add(gdb_softmmu)
|
|
||||||
|
|
||||||
common_ss.add(files('syscalls.c'))
|
|
||||||
|
|
||||||
# The user-target is specialised by the guest
|
|
||||||
specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-target.c'))
|
|
||||||
|
|||||||
@@ -4,617 +4,16 @@
|
|||||||
* Debug integration depends on support from the individual
|
* Debug integration depends on support from the individual
|
||||||
* accelerators so most of this involves calling the ops helpers.
|
* accelerators so most of this involves calling the ops helpers.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
|
||||||
* Copyright (c) 2022 Linaro Ltd
|
* Copyright (c) 2022 Linaro Ltd
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: LGPL-2.0+
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qapi/error.h"
|
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "qemu/cutils.h"
|
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
#include "gdbstub/syscalls.h"
|
|
||||||
#include "exec/hwaddr.h"
|
|
||||||
#include "exec/tb-flush.h"
|
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "sysemu/runstate.h"
|
|
||||||
#include "sysemu/replay.h"
|
|
||||||
#include "hw/core/cpu.h"
|
|
||||||
#include "hw/cpu/cluster.h"
|
|
||||||
#include "hw/boards.h"
|
|
||||||
#include "chardev/char.h"
|
|
||||||
#include "chardev/char-fe.h"
|
|
||||||
#include "monitor/monitor.h"
|
|
||||||
#include "trace.h"
|
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
|
|
||||||
/* System emulation specific state */
|
|
||||||
typedef struct {
|
|
||||||
CharBackend chr;
|
|
||||||
Chardev *mon_chr;
|
|
||||||
} GDBSystemState;
|
|
||||||
|
|
||||||
GDBSystemState gdbserver_system_state;
|
|
||||||
|
|
||||||
static void reset_gdbserver_state(void)
|
|
||||||
{
|
|
||||||
g_free(gdbserver_state.processes);
|
|
||||||
gdbserver_state.processes = NULL;
|
|
||||||
gdbserver_state.process_num = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the GDB index for a given vCPU state.
|
|
||||||
*
|
|
||||||
* In system mode GDB numbers CPUs from 1 as 0 is reserved as an "any
|
|
||||||
* cpu" index.
|
|
||||||
*/
|
|
||||||
int gdb_get_cpu_index(CPUState *cpu)
|
|
||||||
{
|
|
||||||
return cpu->cpu_index + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We check the status of the last message in the chardev receive code
|
|
||||||
*/
|
|
||||||
bool gdb_got_immediate_ack(void)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GDB Connection management. For system emulation we do all of this
|
|
||||||
* via our existing Chardev infrastructure which allows us to support
|
|
||||||
* network and unix sockets.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void gdb_put_buffer(const uint8_t *buf, int len)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* XXX this blocks entire thread. Rewrite to use
|
|
||||||
* qemu_chr_fe_write and background I/O callbacks
|
|
||||||
*/
|
|
||||||
qemu_chr_fe_write_all(&gdbserver_system_state.chr, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gdb_chr_event(void *opaque, QEMUChrEvent event)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
GDBState *s = (GDBState *) opaque;
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
case CHR_EVENT_OPENED:
|
|
||||||
/* Start with first process attached, others detached */
|
|
||||||
for (i = 0; i < s->process_num; i++) {
|
|
||||||
s->processes[i].attached = !i;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->c_cpu = gdb_first_attached_cpu();
|
|
||||||
s->g_cpu = s->c_cpu;
|
|
||||||
|
|
||||||
vm_stop(RUN_STATE_PAUSED);
|
|
||||||
replay_gdb_attached();
|
|
||||||
gdb_has_xml = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In softmmu mode we stop the VM and wait to send the syscall packet
|
|
||||||
* until notification that the CPU has stopped. This must be done
|
|
||||||
* because if the packet is sent now the reply from the syscall
|
|
||||||
* request could be received while the CPU is still in the running
|
|
||||||
* state, which can cause packets to be dropped and state transition
|
|
||||||
* 'T' packets to be sent while the syscall is still being processed.
|
|
||||||
*/
|
|
||||||
void gdb_syscall_handling(const char *syscall_packet)
|
|
||||||
{
|
|
||||||
vm_stop(RUN_STATE_DEBUG);
|
|
||||||
qemu_cpu_kick(gdbserver_state.c_cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gdb_vm_state_change(void *opaque, bool running, RunState state)
|
|
||||||
{
|
|
||||||
CPUState *cpu = gdbserver_state.c_cpu;
|
|
||||||
g_autoptr(GString) buf = g_string_new(NULL);
|
|
||||||
g_autoptr(GString) tid = g_string_new(NULL);
|
|
||||||
const char *type;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (running || gdbserver_state.state == RS_INACTIVE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is there a GDB syscall waiting to be sent? */
|
|
||||||
if (gdb_handled_syscall()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cpu == NULL) {
|
|
||||||
/* No process attached */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gdb_append_thread_id(cpu, tid);
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case RUN_STATE_DEBUG:
|
|
||||||
if (cpu->watchpoint_hit) {
|
|
||||||
switch (cpu->watchpoint_hit->flags & BP_MEM_ACCESS) {
|
|
||||||
case BP_MEM_READ:
|
|
||||||
type = "r";
|
|
||||||
break;
|
|
||||||
case BP_MEM_ACCESS:
|
|
||||||
type = "a";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
type = "";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
trace_gdbstub_hit_watchpoint(type,
|
|
||||||
gdb_get_cpu_index(cpu),
|
|
||||||
cpu->watchpoint_hit->vaddr);
|
|
||||||
g_string_printf(buf, "T%02xthread:%s;%swatch:%" VADDR_PRIx ";",
|
|
||||||
GDB_SIGNAL_TRAP, tid->str, type,
|
|
||||||
cpu->watchpoint_hit->vaddr);
|
|
||||||
cpu->watchpoint_hit = NULL;
|
|
||||||
goto send_packet;
|
|
||||||
} else {
|
|
||||||
trace_gdbstub_hit_break();
|
|
||||||
}
|
|
||||||
tb_flush(cpu);
|
|
||||||
ret = GDB_SIGNAL_TRAP;
|
|
||||||
break;
|
|
||||||
case RUN_STATE_PAUSED:
|
|
||||||
trace_gdbstub_hit_paused();
|
|
||||||
ret = GDB_SIGNAL_INT;
|
|
||||||
break;
|
|
||||||
case RUN_STATE_SHUTDOWN:
|
|
||||||
trace_gdbstub_hit_shutdown();
|
|
||||||
ret = GDB_SIGNAL_QUIT;
|
|
||||||
break;
|
|
||||||
case RUN_STATE_IO_ERROR:
|
|
||||||
trace_gdbstub_hit_io_error();
|
|
||||||
ret = GDB_SIGNAL_IO;
|
|
||||||
break;
|
|
||||||
case RUN_STATE_WATCHDOG:
|
|
||||||
trace_gdbstub_hit_watchdog();
|
|
||||||
ret = GDB_SIGNAL_ALRM;
|
|
||||||
break;
|
|
||||||
case RUN_STATE_INTERNAL_ERROR:
|
|
||||||
trace_gdbstub_hit_internal_error();
|
|
||||||
ret = GDB_SIGNAL_ABRT;
|
|
||||||
break;
|
|
||||||
case RUN_STATE_SAVE_VM:
|
|
||||||
case RUN_STATE_RESTORE_VM:
|
|
||||||
return;
|
|
||||||
case RUN_STATE_FINISH_MIGRATE:
|
|
||||||
ret = GDB_SIGNAL_XCPU;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
trace_gdbstub_hit_unknown(state);
|
|
||||||
ret = GDB_SIGNAL_UNKNOWN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gdb_set_stop_cpu(cpu);
|
|
||||||
g_string_printf(buf, "T%02xthread:%s;", ret, tid->str);
|
|
||||||
|
|
||||||
send_packet:
|
|
||||||
gdb_put_packet(buf->str);
|
|
||||||
|
|
||||||
/* disable single step if it was enabled */
|
|
||||||
cpu_single_step(cpu, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
static void gdb_sigterm_handler(int signal)
|
|
||||||
{
|
|
||||||
if (runstate_is_running()) {
|
|
||||||
vm_stop(RUN_STATE_PAUSED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len)
|
|
||||||
{
|
|
||||||
g_autoptr(GString) hex_buf = g_string_new("O");
|
|
||||||
gdb_memtohex(hex_buf, buf, len);
|
|
||||||
gdb_put_packet(hex_buf->str);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gdb_monitor_open(Chardev *chr, ChardevBackend *backend,
|
|
||||||
bool *be_opened, Error **errp)
|
|
||||||
{
|
|
||||||
*be_opened = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void char_gdb_class_init(ObjectClass *oc, void *data)
|
|
||||||
{
|
|
||||||
ChardevClass *cc = CHARDEV_CLASS(oc);
|
|
||||||
|
|
||||||
cc->internal = true;
|
|
||||||
cc->open = gdb_monitor_open;
|
|
||||||
cc->chr_write = gdb_monitor_write;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TYPE_CHARDEV_GDB "chardev-gdb"
|
|
||||||
|
|
||||||
static const TypeInfo char_gdb_type_info = {
|
|
||||||
.name = TYPE_CHARDEV_GDB,
|
|
||||||
.parent = TYPE_CHARDEV,
|
|
||||||
.class_init = char_gdb_class_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int gdb_chr_can_receive(void *opaque)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We can handle an arbitrarily large amount of data.
|
|
||||||
* Pick the maximum packet size, which is as good as anything.
|
|
||||||
*/
|
|
||||||
return MAX_PACKET_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
gdb_read_byte(buf[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int find_cpu_clusters(Object *child, void *opaque)
|
|
||||||
{
|
|
||||||
if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) {
|
|
||||||
GDBState *s = (GDBState *) opaque;
|
|
||||||
CPUClusterState *cluster = CPU_CLUSTER(child);
|
|
||||||
GDBProcess *process;
|
|
||||||
|
|
||||||
s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
|
|
||||||
|
|
||||||
process = &s->processes[s->process_num - 1];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GDB process IDs -1 and 0 are reserved. To avoid subtle errors at
|
|
||||||
* runtime, we enforce here that the machine does not use a cluster ID
|
|
||||||
* that would lead to PID 0.
|
|
||||||
*/
|
|
||||||
assert(cluster->cluster_id != UINT32_MAX);
|
|
||||||
process->pid = cluster->cluster_id + 1;
|
|
||||||
process->attached = false;
|
|
||||||
process->target_xml[0] = '\0';
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return object_child_foreach(child, find_cpu_clusters, opaque);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pid_order(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
GDBProcess *pa = (GDBProcess *) a;
|
|
||||||
GDBProcess *pb = (GDBProcess *) b;
|
|
||||||
|
|
||||||
if (pa->pid < pb->pid) {
|
|
||||||
return -1;
|
|
||||||
} else if (pa->pid > pb->pid) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void create_processes(GDBState *s)
|
|
||||||
{
|
|
||||||
object_child_foreach(object_get_root(), find_cpu_clusters, s);
|
|
||||||
|
|
||||||
if (gdbserver_state.processes) {
|
|
||||||
/* Sort by PID */
|
|
||||||
qsort(gdbserver_state.processes,
|
|
||||||
gdbserver_state.process_num,
|
|
||||||
sizeof(gdbserver_state.processes[0]),
|
|
||||||
pid_order);
|
|
||||||
}
|
|
||||||
|
|
||||||
gdb_create_default_process(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
int gdbserver_start(const char *device)
|
|
||||||
{
|
|
||||||
trace_gdbstub_op_start(device);
|
|
||||||
|
|
||||||
char gdbstub_device_name[128];
|
|
||||||
Chardev *chr = NULL;
|
|
||||||
Chardev *mon_chr;
|
|
||||||
|
|
||||||
if (!first_cpu) {
|
|
||||||
error_report("gdbstub: meaningless to attach gdb to a "
|
|
||||||
"machine without any CPU.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gdb_supports_guest_debug()) {
|
|
||||||
error_report("gdbstub: current accelerator doesn't "
|
|
||||||
"support guest debugging");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!device) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (strcmp(device, "none") != 0) {
|
|
||||||
if (strstart(device, "tcp:", NULL)) {
|
|
||||||
/* enforce required TCP attributes */
|
|
||||||
snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
|
|
||||||
"%s,wait=off,nodelay=on,server=on", device);
|
|
||||||
device = gdbstub_device_name;
|
|
||||||
}
|
|
||||||
#ifndef _WIN32
|
|
||||||
else if (strcmp(device, "stdio") == 0) {
|
|
||||||
struct sigaction act;
|
|
||||||
|
|
||||||
memset(&act, 0, sizeof(act));
|
|
||||||
act.sa_handler = gdb_sigterm_handler;
|
|
||||||
sigaction(SIGINT, &act, NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* FIXME: it's a bit weird to allow using a mux chardev here
|
|
||||||
* and implicitly setup a monitor. We may want to break this.
|
|
||||||
*/
|
|
||||||
chr = qemu_chr_new_noreplay("gdb", device, true, NULL);
|
|
||||||
if (!chr) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gdbserver_state.init) {
|
|
||||||
gdb_init_gdbserver_state();
|
|
||||||
|
|
||||||
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
|
|
||||||
|
|
||||||
/* Initialize a monitor terminal for gdb */
|
|
||||||
mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
|
|
||||||
NULL, NULL, &error_abort);
|
|
||||||
monitor_init_hmp(mon_chr, false, &error_abort);
|
|
||||||
} else {
|
|
||||||
qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
|
|
||||||
mon_chr = gdbserver_system_state.mon_chr;
|
|
||||||
reset_gdbserver_state();
|
|
||||||
}
|
|
||||||
|
|
||||||
create_processes(&gdbserver_state);
|
|
||||||
|
|
||||||
if (chr) {
|
|
||||||
qemu_chr_fe_init(&gdbserver_system_state.chr, chr, &error_abort);
|
|
||||||
qemu_chr_fe_set_handlers(&gdbserver_system_state.chr,
|
|
||||||
gdb_chr_can_receive,
|
|
||||||
gdb_chr_receive, gdb_chr_event,
|
|
||||||
NULL, &gdbserver_state, NULL, true);
|
|
||||||
}
|
|
||||||
gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
|
|
||||||
gdbserver_system_state.mon_chr = mon_chr;
|
|
||||||
gdb_syscall_reset();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_types(void)
|
|
||||||
{
|
|
||||||
type_register_static(&char_gdb_type_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_init(register_types);
|
|
||||||
|
|
||||||
/* Tell the remote gdb that the process has exited. */
|
|
||||||
void gdb_exit(int code)
|
|
||||||
{
|
|
||||||
char buf[4];
|
|
||||||
|
|
||||||
if (!gdbserver_state.init) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_gdbstub_op_exiting((uint8_t)code);
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
|
|
||||||
gdb_put_packet(buf);
|
|
||||||
|
|
||||||
qemu_chr_fe_deinit(&gdbserver_system_state.chr, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Memory access
|
|
||||||
*/
|
|
||||||
static int phy_memory_mode;
|
|
||||||
|
|
||||||
int gdb_target_memory_rw_debug(CPUState *cpu, hwaddr addr,
|
|
||||||
uint8_t *buf, int len, bool is_write)
|
|
||||||
{
|
|
||||||
CPUClass *cc;
|
|
||||||
|
|
||||||
if (phy_memory_mode) {
|
|
||||||
if (is_write) {
|
|
||||||
cpu_physical_memory_write(addr, buf, len);
|
|
||||||
} else {
|
|
||||||
cpu_physical_memory_read(addr, buf, len);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cc = CPU_GET_CLASS(cpu);
|
|
||||||
if (cc->memory_rw_debug) {
|
|
||||||
return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* cpu helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned int gdb_get_max_cpus(void)
|
|
||||||
{
|
|
||||||
MachineState *ms = MACHINE(qdev_get_machine());
|
|
||||||
return ms->smp.max_cpus;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gdb_can_reverse(void)
|
|
||||||
{
|
|
||||||
return replay_mode == REPLAY_MODE_PLAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Softmmu specific command helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
void gdb_handle_query_qemu_phy_mem_mode(GArray *params,
|
|
||||||
void *user_ctx)
|
|
||||||
{
|
|
||||||
g_string_printf(gdbserver_state.str_buf, "%d", phy_memory_mode);
|
|
||||||
gdb_put_strbuf();
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_handle_set_qemu_phy_mem_mode(GArray *params, void *user_ctx)
|
|
||||||
{
|
|
||||||
if (!params->len) {
|
|
||||||
gdb_put_packet("E22");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_param(params, 0)->val_ul) {
|
|
||||||
phy_memory_mode = 0;
|
|
||||||
} else {
|
|
||||||
phy_memory_mode = 1;
|
|
||||||
}
|
|
||||||
gdb_put_packet("OK");
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_handle_query_rcmd(GArray *params, void *user_ctx)
|
|
||||||
{
|
|
||||||
const guint8 zero = 0;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (!params->len) {
|
|
||||||
gdb_put_packet("E22");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = strlen(get_param(params, 0)->data);
|
|
||||||
if (len % 2) {
|
|
||||||
gdb_put_packet("E01");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_assert(gdbserver_state.mem_buf->len == 0);
|
|
||||||
len = len / 2;
|
|
||||||
gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len);
|
|
||||||
g_byte_array_append(gdbserver_state.mem_buf, &zero, 1);
|
|
||||||
qemu_chr_be_write(gdbserver_system_state.mon_chr,
|
|
||||||
gdbserver_state.mem_buf->data,
|
|
||||||
gdbserver_state.mem_buf->len);
|
|
||||||
gdb_put_packet("OK");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Execution state helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
void gdb_handle_query_attached(GArray *params, void *user_ctx)
|
|
||||||
{
|
|
||||||
gdb_put_packet("1");
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_continue(void)
|
|
||||||
{
|
|
||||||
if (!runstate_needs_reset()) {
|
|
||||||
trace_gdbstub_op_continue();
|
|
||||||
vm_start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Resume execution, per CPU actions.
|
|
||||||
*/
|
|
||||||
int gdb_continue_partial(char *newstates)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
int res = 0;
|
|
||||||
int flag = 0;
|
|
||||||
|
|
||||||
if (!runstate_needs_reset()) {
|
|
||||||
bool step_requested = false;
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
if (newstates[cpu->cpu_index] == 's') {
|
|
||||||
step_requested = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vm_prepare_start(step_requested)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
switch (newstates[cpu->cpu_index]) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
break; /* nothing to do here */
|
|
||||||
case 's':
|
|
||||||
trace_gdbstub_op_stepping(cpu->cpu_index);
|
|
||||||
cpu_single_step(cpu, gdbserver_state.sstep_flags);
|
|
||||||
cpu_resume(cpu);
|
|
||||||
flag = 1;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
trace_gdbstub_op_continue_cpu(cpu->cpu_index);
|
|
||||||
cpu_resume(cpu);
|
|
||||||
flag = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flag) {
|
|
||||||
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Signal Handling - in system mode we only need SIGINT and SIGTRAP; other
|
|
||||||
* signals are not yet supported.
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum {
|
|
||||||
TARGET_SIGINT = 2,
|
|
||||||
TARGET_SIGTRAP = 5
|
|
||||||
};
|
|
||||||
|
|
||||||
int gdb_signal_to_target(int sig)
|
|
||||||
{
|
|
||||||
switch (sig) {
|
|
||||||
case 2:
|
|
||||||
return TARGET_SIGINT;
|
|
||||||
case 5:
|
|
||||||
return TARGET_SIGTRAP;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Break/Watch point helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool gdb_supports_guest_debug(void)
|
bool gdb_supports_guest_debug(void)
|
||||||
{
|
{
|
||||||
const AccelOpsClass *ops = cpus_get_accel();
|
const AccelOpsClass *ops = cpus_get_accel();
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
/*
|
|
||||||
* GDB Syscall Handling
|
|
||||||
*
|
|
||||||
* GDB can execute syscalls on the guests behalf, currently used by
|
|
||||||
* the various semihosting extensions.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
|
||||||
* Copyright (c) 2023 Linaro Ltd
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.0+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "semihosting/semihost.h"
|
|
||||||
#include "sysemu/runstate.h"
|
|
||||||
#include "gdbstub/user.h"
|
|
||||||
#include "gdbstub/syscalls.h"
|
|
||||||
#include "trace.h"
|
|
||||||
#include "internals.h"
|
|
||||||
|
|
||||||
/* Syscall specific state */
|
|
||||||
typedef struct {
|
|
||||||
char syscall_buf[256];
|
|
||||||
gdb_syscall_complete_cb current_syscall_cb;
|
|
||||||
} GDBSyscallState;
|
|
||||||
|
|
||||||
static GDBSyscallState gdbserver_syscall_state;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return true if there is a GDB currently connected to the stub
|
|
||||||
* and attached to a CPU
|
|
||||||
*/
|
|
||||||
static bool gdb_attached(void)
|
|
||||||
{
|
|
||||||
return gdbserver_state.init && gdbserver_state.c_cpu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum {
|
|
||||||
GDB_SYS_UNKNOWN,
|
|
||||||
GDB_SYS_ENABLED,
|
|
||||||
GDB_SYS_DISABLED,
|
|
||||||
} gdb_syscall_mode;
|
|
||||||
|
|
||||||
/* Decide if either remote gdb syscalls or native file IO should be used. */
|
|
||||||
int use_gdb_syscalls(void)
|
|
||||||
{
|
|
||||||
SemihostingTarget target = semihosting_get_target();
|
|
||||||
if (target == SEMIHOSTING_TARGET_NATIVE) {
|
|
||||||
/* -semihosting-config target=native */
|
|
||||||
return false;
|
|
||||||
} else if (target == SEMIHOSTING_TARGET_GDB) {
|
|
||||||
/* -semihosting-config target=gdb */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -semihosting-config target=auto */
|
|
||||||
/* On the first call check if gdb is connected and remember. */
|
|
||||||
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
|
|
||||||
gdb_syscall_mode = gdb_attached() ? GDB_SYS_ENABLED : GDB_SYS_DISABLED;
|
|
||||||
}
|
|
||||||
return gdb_syscall_mode == GDB_SYS_ENABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* called when the stub detaches */
|
|
||||||
void gdb_disable_syscalls(void)
|
|
||||||
{
|
|
||||||
gdb_syscall_mode = GDB_SYS_DISABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_syscall_reset(void)
|
|
||||||
{
|
|
||||||
gdbserver_syscall_state.current_syscall_cb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gdb_handled_syscall(void)
|
|
||||||
{
|
|
||||||
if (gdbserver_syscall_state.current_syscall_cb) {
|
|
||||||
gdb_put_packet(gdbserver_syscall_state.syscall_buf);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Send a gdb syscall request.
|
|
||||||
* This accepts limited printf-style format specifiers, specifically:
|
|
||||||
* %x - target_ulong argument printed in hex.
|
|
||||||
* %lx - 64-bit argument printed in hex.
|
|
||||||
* %s - string pointer (target_ulong) and length (int) pair.
|
|
||||||
*/
|
|
||||||
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
char *p, *p_end;
|
|
||||||
va_list va;
|
|
||||||
|
|
||||||
if (!gdb_attached()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gdbserver_syscall_state.current_syscall_cb = cb;
|
|
||||||
va_start(va, fmt);
|
|
||||||
|
|
||||||
p = gdbserver_syscall_state.syscall_buf;
|
|
||||||
p_end = p + sizeof(gdbserver_syscall_state.syscall_buf);
|
|
||||||
*(p++) = 'F';
|
|
||||||
while (*fmt) {
|
|
||||||
if (*fmt == '%') {
|
|
||||||
uint64_t i64;
|
|
||||||
uint32_t i32;
|
|
||||||
|
|
||||||
fmt++;
|
|
||||||
switch (*fmt++) {
|
|
||||||
case 'x':
|
|
||||||
i32 = va_arg(va, uint32_t);
|
|
||||||
p += snprintf(p, p_end - p, "%" PRIx32, i32);
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
if (*(fmt++) != 'x') {
|
|
||||||
goto bad_format;
|
|
||||||
}
|
|
||||||
i64 = va_arg(va, uint64_t);
|
|
||||||
p += snprintf(p, p_end - p, "%" PRIx64, i64);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
i64 = va_arg(va, uint64_t);
|
|
||||||
i32 = va_arg(va, uint32_t);
|
|
||||||
p += snprintf(p, p_end - p, "%" PRIx64 "/%x" PRIx32, i64, i32);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
bad_format:
|
|
||||||
error_report("gdbstub: Bad syscall format string '%s'",
|
|
||||||
fmt - 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*(p++) = *(fmt++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
va_end(va);
|
|
||||||
gdb_syscall_handling(gdbserver_syscall_state.syscall_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GDB Command Handlers
|
|
||||||
*/
|
|
||||||
|
|
||||||
void gdb_handle_file_io(GArray *params, void *user_ctx)
|
|
||||||
{
|
|
||||||
if (params->len >= 1 && gdbserver_syscall_state.current_syscall_cb) {
|
|
||||||
uint64_t ret;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
ret = get_param(params, 0)->val_ull;
|
|
||||||
if (params->len >= 2) {
|
|
||||||
err = get_param(params, 1)->val_ull;
|
|
||||||
} else {
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert GDB error numbers back to host error numbers. */
|
|
||||||
#define E(X) case GDB_E##X: err = E##X; break
|
|
||||||
switch (err) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
E(PERM);
|
|
||||||
E(NOENT);
|
|
||||||
E(INTR);
|
|
||||||
E(BADF);
|
|
||||||
E(ACCES);
|
|
||||||
E(FAULT);
|
|
||||||
E(BUSY);
|
|
||||||
E(EXIST);
|
|
||||||
E(NODEV);
|
|
||||||
E(NOTDIR);
|
|
||||||
E(ISDIR);
|
|
||||||
E(INVAL);
|
|
||||||
E(NFILE);
|
|
||||||
E(MFILE);
|
|
||||||
E(FBIG);
|
|
||||||
E(NOSPC);
|
|
||||||
E(SPIPE);
|
|
||||||
E(ROFS);
|
|
||||||
E(NAMETOOLONG);
|
|
||||||
default:
|
|
||||||
err = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#undef E
|
|
||||||
|
|
||||||
gdbserver_syscall_state.current_syscall_cb(gdbserver_state.c_cpu,
|
|
||||||
ret, err);
|
|
||||||
gdbserver_syscall_state.current_syscall_cb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params->len >= 3 && get_param(params, 2)->opcode == (uint8_t)'C') {
|
|
||||||
gdb_put_packet("T02");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gdb_continue();
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,7 @@ gdbstub_op_continue(void) "Continuing all CPUs"
|
|||||||
gdbstub_op_continue_cpu(int cpu_index) "Continuing CPU %d"
|
gdbstub_op_continue_cpu(int cpu_index) "Continuing CPU %d"
|
||||||
gdbstub_op_stepping(int cpu_index) "Stepping CPU %d"
|
gdbstub_op_stepping(int cpu_index) "Stepping CPU %d"
|
||||||
gdbstub_op_extra_info(const char *info) "Thread extra info: %s"
|
gdbstub_op_extra_info(const char *info) "Thread extra info: %s"
|
||||||
|
gdbstub_hit_watchpoint(const char *type, int cpu_gdb_index, uint64_t vaddr) "Watchpoint hit, type=\"%s\" cpu=%d, vaddr=0x%" PRIx64 ""
|
||||||
gdbstub_hit_internal_error(void) "RUN_STATE_INTERNAL_ERROR"
|
gdbstub_hit_internal_error(void) "RUN_STATE_INTERNAL_ERROR"
|
||||||
gdbstub_hit_break(void) "RUN_STATE_DEBUG"
|
gdbstub_hit_break(void) "RUN_STATE_DEBUG"
|
||||||
gdbstub_hit_paused(void) "RUN_STATE_PAUSED"
|
gdbstub_hit_paused(void) "RUN_STATE_PAUSED"
|
||||||
@@ -26,6 +27,3 @@ gdbstub_err_invalid_repeat(uint8_t ch) "got invalid RLE count: 0x%02x"
|
|||||||
gdbstub_err_invalid_rle(void) "got invalid RLE sequence"
|
gdbstub_err_invalid_rle(void) "got invalid RLE sequence"
|
||||||
gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x%02x"
|
gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x%02x"
|
||||||
gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x"
|
gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x"
|
||||||
|
|
||||||
# softmmu.c
|
|
||||||
gdbstub_hit_watchpoint(const char *type, int cpu_gdb_index, uint64_t vaddr) "Watchpoint hit, type=\"%s\" cpu=%d, vaddr=0x%" PRIx64 ""
|
|
||||||
|
|||||||
@@ -1,283 +0,0 @@
|
|||||||
/*
|
|
||||||
* Target specific user-mode handling
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
|
||||||
* Copyright (c) 2022 Linaro Ltd
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.0+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include "exec/gdbstub.h"
|
|
||||||
#include "qemu.h"
|
|
||||||
#include "internals.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Map target signal numbers to GDB protocol signal numbers and vice
|
|
||||||
* versa. For user emulation's currently supported systems, we can
|
|
||||||
* assume most signals are defined.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int gdb_signal_table[] = {
|
|
||||||
0,
|
|
||||||
TARGET_SIGHUP,
|
|
||||||
TARGET_SIGINT,
|
|
||||||
TARGET_SIGQUIT,
|
|
||||||
TARGET_SIGILL,
|
|
||||||
TARGET_SIGTRAP,
|
|
||||||
TARGET_SIGABRT,
|
|
||||||
-1, /* SIGEMT */
|
|
||||||
TARGET_SIGFPE,
|
|
||||||
TARGET_SIGKILL,
|
|
||||||
TARGET_SIGBUS,
|
|
||||||
TARGET_SIGSEGV,
|
|
||||||
TARGET_SIGSYS,
|
|
||||||
TARGET_SIGPIPE,
|
|
||||||
TARGET_SIGALRM,
|
|
||||||
TARGET_SIGTERM,
|
|
||||||
TARGET_SIGURG,
|
|
||||||
TARGET_SIGSTOP,
|
|
||||||
TARGET_SIGTSTP,
|
|
||||||
TARGET_SIGCONT,
|
|
||||||
TARGET_SIGCHLD,
|
|
||||||
TARGET_SIGTTIN,
|
|
||||||
TARGET_SIGTTOU,
|
|
||||||
TARGET_SIGIO,
|
|
||||||
TARGET_SIGXCPU,
|
|
||||||
TARGET_SIGXFSZ,
|
|
||||||
TARGET_SIGVTALRM,
|
|
||||||
TARGET_SIGPROF,
|
|
||||||
TARGET_SIGWINCH,
|
|
||||||
-1, /* SIGLOST */
|
|
||||||
TARGET_SIGUSR1,
|
|
||||||
TARGET_SIGUSR2,
|
|
||||||
#ifdef TARGET_SIGPWR
|
|
||||||
TARGET_SIGPWR,
|
|
||||||
#else
|
|
||||||
-1,
|
|
||||||
#endif
|
|
||||||
-1, /* SIGPOLL */
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
#ifdef __SIGRTMIN
|
|
||||||
__SIGRTMIN + 1,
|
|
||||||
__SIGRTMIN + 2,
|
|
||||||
__SIGRTMIN + 3,
|
|
||||||
__SIGRTMIN + 4,
|
|
||||||
__SIGRTMIN + 5,
|
|
||||||
__SIGRTMIN + 6,
|
|
||||||
__SIGRTMIN + 7,
|
|
||||||
__SIGRTMIN + 8,
|
|
||||||
__SIGRTMIN + 9,
|
|
||||||
__SIGRTMIN + 10,
|
|
||||||
__SIGRTMIN + 11,
|
|
||||||
__SIGRTMIN + 12,
|
|
||||||
__SIGRTMIN + 13,
|
|
||||||
__SIGRTMIN + 14,
|
|
||||||
__SIGRTMIN + 15,
|
|
||||||
__SIGRTMIN + 16,
|
|
||||||
__SIGRTMIN + 17,
|
|
||||||
__SIGRTMIN + 18,
|
|
||||||
__SIGRTMIN + 19,
|
|
||||||
__SIGRTMIN + 20,
|
|
||||||
__SIGRTMIN + 21,
|
|
||||||
__SIGRTMIN + 22,
|
|
||||||
__SIGRTMIN + 23,
|
|
||||||
__SIGRTMIN + 24,
|
|
||||||
__SIGRTMIN + 25,
|
|
||||||
__SIGRTMIN + 26,
|
|
||||||
__SIGRTMIN + 27,
|
|
||||||
__SIGRTMIN + 28,
|
|
||||||
__SIGRTMIN + 29,
|
|
||||||
__SIGRTMIN + 30,
|
|
||||||
__SIGRTMIN + 31,
|
|
||||||
-1, /* SIGCANCEL */
|
|
||||||
__SIGRTMIN,
|
|
||||||
__SIGRTMIN + 32,
|
|
||||||
__SIGRTMIN + 33,
|
|
||||||
__SIGRTMIN + 34,
|
|
||||||
__SIGRTMIN + 35,
|
|
||||||
__SIGRTMIN + 36,
|
|
||||||
__SIGRTMIN + 37,
|
|
||||||
__SIGRTMIN + 38,
|
|
||||||
__SIGRTMIN + 39,
|
|
||||||
__SIGRTMIN + 40,
|
|
||||||
__SIGRTMIN + 41,
|
|
||||||
__SIGRTMIN + 42,
|
|
||||||
__SIGRTMIN + 43,
|
|
||||||
__SIGRTMIN + 44,
|
|
||||||
__SIGRTMIN + 45,
|
|
||||||
__SIGRTMIN + 46,
|
|
||||||
__SIGRTMIN + 47,
|
|
||||||
__SIGRTMIN + 48,
|
|
||||||
__SIGRTMIN + 49,
|
|
||||||
__SIGRTMIN + 50,
|
|
||||||
__SIGRTMIN + 51,
|
|
||||||
__SIGRTMIN + 52,
|
|
||||||
__SIGRTMIN + 53,
|
|
||||||
__SIGRTMIN + 54,
|
|
||||||
__SIGRTMIN + 55,
|
|
||||||
__SIGRTMIN + 56,
|
|
||||||
__SIGRTMIN + 57,
|
|
||||||
__SIGRTMIN + 58,
|
|
||||||
__SIGRTMIN + 59,
|
|
||||||
__SIGRTMIN + 60,
|
|
||||||
__SIGRTMIN + 61,
|
|
||||||
__SIGRTMIN + 62,
|
|
||||||
__SIGRTMIN + 63,
|
|
||||||
__SIGRTMIN + 64,
|
|
||||||
__SIGRTMIN + 65,
|
|
||||||
__SIGRTMIN + 66,
|
|
||||||
__SIGRTMIN + 67,
|
|
||||||
__SIGRTMIN + 68,
|
|
||||||
__SIGRTMIN + 69,
|
|
||||||
__SIGRTMIN + 70,
|
|
||||||
__SIGRTMIN + 71,
|
|
||||||
__SIGRTMIN + 72,
|
|
||||||
__SIGRTMIN + 73,
|
|
||||||
__SIGRTMIN + 74,
|
|
||||||
__SIGRTMIN + 75,
|
|
||||||
__SIGRTMIN + 76,
|
|
||||||
__SIGRTMIN + 77,
|
|
||||||
__SIGRTMIN + 78,
|
|
||||||
__SIGRTMIN + 79,
|
|
||||||
__SIGRTMIN + 80,
|
|
||||||
__SIGRTMIN + 81,
|
|
||||||
__SIGRTMIN + 82,
|
|
||||||
__SIGRTMIN + 83,
|
|
||||||
__SIGRTMIN + 84,
|
|
||||||
__SIGRTMIN + 85,
|
|
||||||
__SIGRTMIN + 86,
|
|
||||||
__SIGRTMIN + 87,
|
|
||||||
__SIGRTMIN + 88,
|
|
||||||
__SIGRTMIN + 89,
|
|
||||||
__SIGRTMIN + 90,
|
|
||||||
__SIGRTMIN + 91,
|
|
||||||
__SIGRTMIN + 92,
|
|
||||||
__SIGRTMIN + 93,
|
|
||||||
__SIGRTMIN + 94,
|
|
||||||
__SIGRTMIN + 95,
|
|
||||||
-1, /* SIGINFO */
|
|
||||||
-1, /* UNKNOWN */
|
|
||||||
-1, /* DEFAULT */
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
-1
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
int gdb_signal_to_target(int sig)
|
|
||||||
{
|
|
||||||
if (sig < ARRAY_SIZE(gdb_signal_table)) {
|
|
||||||
return gdb_signal_table[sig];
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int gdb_target_signal_to_gdb(int sig)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < ARRAY_SIZE(gdb_signal_table); i++) {
|
|
||||||
if (gdb_signal_table[i] == sig) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return GDB_SIGNAL_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gdb_get_cpu_index(CPUState *cpu)
|
|
||||||
{
|
|
||||||
TaskState *ts = (TaskState *) cpu->opaque;
|
|
||||||
return ts ? ts->ts_tid : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* User-mode specific command helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
void gdb_handle_query_offsets(GArray *params, void *user_ctx)
|
|
||||||
{
|
|
||||||
TaskState *ts;
|
|
||||||
|
|
||||||
ts = gdbserver_state.c_cpu->opaque;
|
|
||||||
g_string_printf(gdbserver_state.str_buf,
|
|
||||||
"Text=" TARGET_ABI_FMT_lx
|
|
||||||
";Data=" TARGET_ABI_FMT_lx
|
|
||||||
";Bss=" TARGET_ABI_FMT_lx,
|
|
||||||
ts->info->code_offset,
|
|
||||||
ts->info->data_offset,
|
|
||||||
ts->info->data_offset);
|
|
||||||
gdb_put_strbuf();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CONFIG_LINUX)
|
|
||||||
/* Partial user only duplicate of helper in gdbstub.c */
|
|
||||||
static inline int target_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
|
||||||
uint8_t *buf, int len, bool is_write)
|
|
||||||
{
|
|
||||||
CPUClass *cc;
|
|
||||||
cc = CPU_GET_CLASS(cpu);
|
|
||||||
if (cc->memory_rw_debug) {
|
|
||||||
return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
|
|
||||||
}
|
|
||||||
return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
|
|
||||||
{
|
|
||||||
TaskState *ts;
|
|
||||||
unsigned long offset, len, saved_auxv, auxv_len;
|
|
||||||
|
|
||||||
if (params->len < 2) {
|
|
||||||
gdb_put_packet("E22");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = get_param(params, 0)->val_ul;
|
|
||||||
len = get_param(params, 1)->val_ul;
|
|
||||||
ts = gdbserver_state.c_cpu->opaque;
|
|
||||||
saved_auxv = ts->info->saved_auxv;
|
|
||||||
auxv_len = ts->info->auxv_len;
|
|
||||||
|
|
||||||
if (offset >= auxv_len) {
|
|
||||||
gdb_put_packet("E00");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > (MAX_PACKET_LENGTH - 5) / 2) {
|
|
||||||
len = (MAX_PACKET_LENGTH - 5) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < auxv_len - offset) {
|
|
||||||
g_string_assign(gdbserver_state.str_buf, "m");
|
|
||||||
} else {
|
|
||||||
g_string_assign(gdbserver_state.str_buf, "l");
|
|
||||||
len = auxv_len - offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_byte_array_set_size(gdbserver_state.mem_buf, len);
|
|
||||||
if (target_memory_rw_debug(gdbserver_state.g_cpu, saved_auxv + offset,
|
|
||||||
gdbserver_state.mem_buf->data, len, false)) {
|
|
||||||
gdb_put_packet("E14");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gdb_memtox(gdbserver_state.str_buf,
|
|
||||||
(const char *)gdbserver_state.mem_buf->data, len);
|
|
||||||
gdb_put_packet_binary(gdbserver_state.str_buf->str,
|
|
||||||
gdbserver_state.str_buf->len, true);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
423
gdbstub/user.c
423
gdbstub/user.c
@@ -3,423 +3,16 @@
|
|||||||
*
|
*
|
||||||
* We know for user-mode we are using TCG so we can call stuff directly.
|
* We know for user-mode we are using TCG so we can call stuff directly.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
|
||||||
* Copyright (c) 2022 Linaro Ltd
|
* Copyright (c) 2022 Linaro Ltd
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: LGPL-2.0+
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/cutils.h"
|
|
||||||
#include "qemu/sockets.h"
|
|
||||||
#include "exec/hwaddr.h"
|
|
||||||
#include "exec/tb-flush.h"
|
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
#include "gdbstub/syscalls.h"
|
|
||||||
#include "gdbstub/user.h"
|
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
#include "trace.h"
|
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
|
|
||||||
/* User-mode specific state */
|
|
||||||
typedef struct {
|
|
||||||
int fd;
|
|
||||||
char *socket_path;
|
|
||||||
int running_state;
|
|
||||||
} GDBUserState;
|
|
||||||
|
|
||||||
static GDBUserState gdbserver_user_state;
|
|
||||||
|
|
||||||
int gdb_get_char(void)
|
|
||||||
{
|
|
||||||
uint8_t ch;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
ret = recv(gdbserver_user_state.fd, &ch, 1, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (errno == ECONNRESET) {
|
|
||||||
gdbserver_user_state.fd = -1;
|
|
||||||
}
|
|
||||||
if (errno != EINTR) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (ret == 0) {
|
|
||||||
close(gdbserver_user_state.fd);
|
|
||||||
gdbserver_user_state.fd = -1;
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gdb_got_immediate_ack(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = gdb_get_char();
|
|
||||||
if (i < 0) {
|
|
||||||
/* no response, continue anyway */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == '+') {
|
|
||||||
/* received correctly, continue */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* anything else, including '-' then try again */
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_put_buffer(const uint8_t *buf, int len)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
ret = send(gdbserver_user_state.fd, buf, len, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (errno != EINTR) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buf += ret;
|
|
||||||
len -= ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tell the remote gdb that the process has exited. */
|
|
||||||
void gdb_exit(int code)
|
|
||||||
{
|
|
||||||
char buf[4];
|
|
||||||
|
|
||||||
if (!gdbserver_state.init) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (gdbserver_user_state.socket_path) {
|
|
||||||
unlink(gdbserver_user_state.socket_path);
|
|
||||||
}
|
|
||||||
if (gdbserver_user_state.fd < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_gdbstub_op_exiting((uint8_t)code);
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
|
|
||||||
gdb_put_packet(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
int gdb_handlesig(CPUState *cpu, int sig)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
|
|
||||||
return sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* disable single step if it was enabled */
|
|
||||||
cpu_single_step(cpu, 0);
|
|
||||||
tb_flush(cpu);
|
|
||||||
|
|
||||||
if (sig != 0) {
|
|
||||||
gdb_set_stop_cpu(cpu);
|
|
||||||
g_string_printf(gdbserver_state.str_buf,
|
|
||||||
"T%02xthread:", gdb_target_signal_to_gdb(sig));
|
|
||||||
gdb_append_thread_id(cpu, gdbserver_state.str_buf);
|
|
||||||
g_string_append_c(gdbserver_state.str_buf, ';');
|
|
||||||
gdb_put_strbuf();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* gdb_put_packet() might have detected that the peer terminated the
|
|
||||||
* connection.
|
|
||||||
*/
|
|
||||||
if (gdbserver_user_state.fd < 0) {
|
|
||||||
return sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
sig = 0;
|
|
||||||
gdbserver_state.state = RS_IDLE;
|
|
||||||
gdbserver_user_state.running_state = 0;
|
|
||||||
while (gdbserver_user_state.running_state == 0) {
|
|
||||||
n = read(gdbserver_user_state.fd, buf, 256);
|
|
||||||
if (n > 0) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
gdb_read_byte(buf[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* XXX: Connection closed. Should probably wait for another
|
|
||||||
* connection before continuing.
|
|
||||||
*/
|
|
||||||
if (n == 0) {
|
|
||||||
close(gdbserver_user_state.fd);
|
|
||||||
}
|
|
||||||
gdbserver_user_state.fd = -1;
|
|
||||||
return sig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sig = gdbserver_state.signal;
|
|
||||||
gdbserver_state.signal = 0;
|
|
||||||
return sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tell the remote gdb that the process has exited due to SIG. */
|
|
||||||
void gdb_signalled(CPUArchState *env, int sig)
|
|
||||||
{
|
|
||||||
char buf[4];
|
|
||||||
|
|
||||||
if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "X%02x", gdb_target_signal_to_gdb(sig));
|
|
||||||
gdb_put_packet(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gdb_accept_init(int fd)
|
|
||||||
{
|
|
||||||
gdb_init_gdbserver_state();
|
|
||||||
gdb_create_default_process(&gdbserver_state);
|
|
||||||
gdbserver_state.processes[0].attached = true;
|
|
||||||
gdbserver_state.c_cpu = gdb_first_attached_cpu();
|
|
||||||
gdbserver_state.g_cpu = gdbserver_state.c_cpu;
|
|
||||||
gdbserver_user_state.fd = fd;
|
|
||||||
gdb_has_xml = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool gdb_accept_socket(int gdb_fd)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
fd = accept(gdb_fd, NULL, NULL);
|
|
||||||
if (fd < 0 && errno != EINTR) {
|
|
||||||
perror("accept socket");
|
|
||||||
return false;
|
|
||||||
} else if (fd >= 0) {
|
|
||||||
qemu_set_cloexec(fd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gdb_accept_init(fd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gdbserver_open_socket(const char *path)
|
|
||||||
{
|
|
||||||
struct sockaddr_un sockaddr = {};
|
|
||||||
int fd, ret;
|
|
||||||
|
|
||||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
if (fd < 0) {
|
|
||||||
perror("create socket");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockaddr.sun_family = AF_UNIX;
|
|
||||||
pstrcpy(sockaddr.sun_path, sizeof(sockaddr.sun_path) - 1, path);
|
|
||||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("bind socket");
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ret = listen(fd, 1);
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("listen socket");
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool gdb_accept_tcp(int gdb_fd)
|
|
||||||
{
|
|
||||||
struct sockaddr_in sockaddr = {};
|
|
||||||
socklen_t len;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
len = sizeof(sockaddr);
|
|
||||||
fd = accept(gdb_fd, (struct sockaddr *)&sockaddr, &len);
|
|
||||||
if (fd < 0 && errno != EINTR) {
|
|
||||||
perror("accept");
|
|
||||||
return false;
|
|
||||||
} else if (fd >= 0) {
|
|
||||||
qemu_set_cloexec(fd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set short latency */
|
|
||||||
if (socket_set_nodelay(fd)) {
|
|
||||||
perror("setsockopt");
|
|
||||||
close(fd);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
gdb_accept_init(fd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gdbserver_open_port(int port)
|
|
||||||
{
|
|
||||||
struct sockaddr_in sockaddr;
|
|
||||||
int fd, ret;
|
|
||||||
|
|
||||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
|
||||||
if (fd < 0) {
|
|
||||||
perror("socket");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
qemu_set_cloexec(fd);
|
|
||||||
|
|
||||||
socket_set_fast_reuse(fd);
|
|
||||||
|
|
||||||
sockaddr.sin_family = AF_INET;
|
|
||||||
sockaddr.sin_port = htons(port);
|
|
||||||
sockaddr.sin_addr.s_addr = 0;
|
|
||||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("bind");
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ret = listen(fd, 1);
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("listen");
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gdbserver_start(const char *port_or_path)
|
|
||||||
{
|
|
||||||
int port = g_ascii_strtoull(port_or_path, NULL, 10);
|
|
||||||
int gdb_fd;
|
|
||||||
|
|
||||||
if (port > 0) {
|
|
||||||
gdb_fd = gdbserver_open_port(port);
|
|
||||||
} else {
|
|
||||||
gdb_fd = gdbserver_open_socket(port_or_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gdb_fd < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port > 0 && gdb_accept_tcp(gdb_fd)) {
|
|
||||||
return 0;
|
|
||||||
} else if (gdb_accept_socket(gdb_fd)) {
|
|
||||||
gdbserver_user_state.socket_path = g_strdup(port_or_path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* gone wrong */
|
|
||||||
close(gdb_fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable gdb stub for child processes. */
|
|
||||||
void gdbserver_fork(CPUState *cpu)
|
|
||||||
{
|
|
||||||
if (!gdbserver_state.init || gdbserver_user_state.fd < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
close(gdbserver_user_state.fd);
|
|
||||||
gdbserver_user_state.fd = -1;
|
|
||||||
cpu_breakpoint_remove_all(cpu, BP_GDB);
|
|
||||||
/* no cpu_watchpoint_remove_all for user-mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Execution state helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
void gdb_handle_query_attached(GArray *params, void *user_ctx)
|
|
||||||
{
|
|
||||||
gdb_put_packet("0");
|
|
||||||
}
|
|
||||||
|
|
||||||
void gdb_continue(void)
|
|
||||||
{
|
|
||||||
gdbserver_user_state.running_state = 1;
|
|
||||||
trace_gdbstub_op_continue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Resume execution, for user-mode emulation it's equivalent to
|
|
||||||
* gdb_continue.
|
|
||||||
*/
|
|
||||||
int gdb_continue_partial(char *newstates)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
int res = 0;
|
|
||||||
/*
|
|
||||||
* This is not exactly accurate, but it's an improvement compared to the
|
|
||||||
* previous situation, where only one CPU would be single-stepped.
|
|
||||||
*/
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
if (newstates[cpu->cpu_index] == 's') {
|
|
||||||
trace_gdbstub_op_stepping(cpu->cpu_index);
|
|
||||||
cpu_single_step(cpu, gdbserver_state.sstep_flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gdbserver_user_state.running_state = 1;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Memory access helpers
|
|
||||||
*/
|
|
||||||
int gdb_target_memory_rw_debug(CPUState *cpu, hwaddr addr,
|
|
||||||
uint8_t *buf, int len, bool is_write)
|
|
||||||
{
|
|
||||||
CPUClass *cc;
|
|
||||||
|
|
||||||
cc = CPU_GET_CLASS(cpu);
|
|
||||||
if (cc->memory_rw_debug) {
|
|
||||||
return cc->memory_rw_debug(cpu, addr, buf, len, is_write);
|
|
||||||
}
|
|
||||||
return cpu_memory_rw_debug(cpu, addr, buf, len, is_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* cpu helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned int gdb_get_max_cpus(void)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
unsigned int max_cpus = 1;
|
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus;
|
|
||||||
}
|
|
||||||
|
|
||||||
return max_cpus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* replay not supported for user-mode */
|
|
||||||
bool gdb_can_reverse(void)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Break/Watch point helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool gdb_supports_guest_debug(void)
|
bool gdb_supports_guest_debug(void)
|
||||||
{
|
{
|
||||||
/* user-mode == TCG == supported */
|
/* user-mode == TCG == supported */
|
||||||
@@ -472,17 +65,3 @@ void gdb_breakpoint_remove_all(CPUState *cs)
|
|||||||
{
|
{
|
||||||
cpu_breakpoint_remove_all(cs, BP_GDB);
|
cpu_breakpoint_remove_all(cs, BP_GDB);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* For user-mode syscall support we send the system call immediately
|
|
||||||
* and then return control to gdb for it to process the syscall request.
|
|
||||||
* Since the protocol requires that gdb hands control back to us
|
|
||||||
* using a "here are the results" F packet, we don't need to check
|
|
||||||
* gdb_handlesig's return value (which is the signal to deliver if
|
|
||||||
* execution was resumed via a continue packet).
|
|
||||||
*/
|
|
||||||
void gdb_syscall_handling(const char *syscall_packet)
|
|
||||||
{
|
|
||||||
gdb_put_packet(syscall_packet);
|
|
||||||
gdb_handlesig(gdbserver_state.c_cpu, 0);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -31,11 +31,8 @@ EmailMap contrib/gitdm/domain-map
|
|||||||
# identifiable corporate emails. Please keep this list sorted.
|
# identifiable corporate emails. Please keep this list sorted.
|
||||||
#
|
#
|
||||||
|
|
||||||
GroupMap contrib/gitdm/group-map-alibaba Alibaba
|
|
||||||
GroupMap contrib/gitdm/group-map-amd AMD
|
|
||||||
GroupMap contrib/gitdm/group-map-cadence Cadence Design Systems
|
GroupMap contrib/gitdm/group-map-cadence Cadence Design Systems
|
||||||
GroupMap contrib/gitdm/group-map-codeweavers CodeWeavers
|
GroupMap contrib/gitdm/group-map-codeweavers CodeWeavers
|
||||||
GroupMap contrib/gitdm/group-map-facebook Facebook
|
|
||||||
GroupMap contrib/gitdm/group-map-ibm IBM
|
GroupMap contrib/gitdm/group-map-ibm IBM
|
||||||
GroupMap contrib/gitdm/group-map-janustech Janus Technologies
|
GroupMap contrib/gitdm/group-map-janustech Janus Technologies
|
||||||
GroupMap contrib/gitdm/group-map-netflix Netflix
|
GroupMap contrib/gitdm/group-map-netflix Netflix
|
||||||
|
|||||||
@@ -993,17 +993,3 @@ SRST
|
|||||||
``info virtio-queue-element`` *path* *queue* [*index*]
|
``info virtio-queue-element`` *path* *queue* [*index*]
|
||||||
Display element of a given virtio queue
|
Display element of a given virtio queue
|
||||||
ERST
|
ERST
|
||||||
|
|
||||||
{
|
|
||||||
.name = "cryptodev",
|
|
||||||
.args_type = "",
|
|
||||||
.params = "",
|
|
||||||
.help = "show the crypto devices",
|
|
||||||
.cmd = hmp_info_cryptodev,
|
|
||||||
.flags = "p",
|
|
||||||
},
|
|
||||||
|
|
||||||
SRST
|
|
||||||
``info cryptodev``
|
|
||||||
Show the crypto devices.
|
|
||||||
ERST
|
|
||||||
|
|||||||
@@ -1486,7 +1486,6 @@ SRST
|
|||||||
Inject an MCE on the given CPU (x86 only).
|
Inject an MCE on the given CPU (x86 only).
|
||||||
ERST
|
ERST
|
||||||
|
|
||||||
#ifdef CONFIG_POSIX
|
|
||||||
{
|
{
|
||||||
.name = "getfd",
|
.name = "getfd",
|
||||||
.args_type = "fdname:s",
|
.args_type = "fdname:s",
|
||||||
@@ -1502,7 +1501,6 @@ SRST
|
|||||||
mechanism on unix sockets, it is stored using the name *fdname* for
|
mechanism on unix sockets, it is stored using the name *fdname* for
|
||||||
later use by other monitor commands.
|
later use by other monitor commands.
|
||||||
ERST
|
ERST
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
{
|
||||||
.name = "closefd",
|
.name = "closefd",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ fs_ss.add(files(
|
|||||||
))
|
))
|
||||||
fs_ss.add(when: 'CONFIG_LINUX', if_true: files('9p-util-linux.c'))
|
fs_ss.add(when: 'CONFIG_LINUX', if_true: files('9p-util-linux.c'))
|
||||||
fs_ss.add(when: 'CONFIG_DARWIN', if_true: files('9p-util-darwin.c'))
|
fs_ss.add(when: 'CONFIG_DARWIN', if_true: files('9p-util-darwin.c'))
|
||||||
fs_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-9p-backend.c'))
|
fs_ss.add(when: 'CONFIG_XEN', if_true: files('xen-9p-backend.c'))
|
||||||
softmmu_ss.add_all(when: 'CONFIG_FSDEV_9P', if_true: fs_ss)
|
softmmu_ss.add_all(when: 'CONFIG_FSDEV_9P', if_true: fs_ss)
|
||||||
|
|
||||||
specific_ss.add(when: 'CONFIG_VIRTIO_9P', if_true: files('virtio-9p-device.c'))
|
specific_ss.add(when: 'CONFIG_VIRTIO_9P', if_true: files('virtio-9p-device.c'))
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "qemu/option.h"
|
#include "qemu/option.h"
|
||||||
#include "qemu/iov.h"
|
|
||||||
#include "fsdev/qemu-fsdev.h"
|
#include "fsdev/qemu-fsdev.h"
|
||||||
|
|
||||||
#define VERSIONS "1"
|
#define VERSIONS "1"
|
||||||
@@ -242,7 +241,7 @@ static void xen_9pfs_push_and_notify(V9fsPDU *pdu)
|
|||||||
xen_wmb();
|
xen_wmb();
|
||||||
|
|
||||||
ring->inprogress = false;
|
ring->inprogress = false;
|
||||||
qemu_xen_evtchn_notify(ring->evtchndev, ring->local_port);
|
xenevtchn_notify(ring->evtchndev, ring->local_port);
|
||||||
|
|
||||||
qemu_bh_schedule(ring->bh);
|
qemu_bh_schedule(ring->bh);
|
||||||
}
|
}
|
||||||
@@ -325,8 +324,8 @@ static void xen_9pfs_evtchn_event(void *opaque)
|
|||||||
Xen9pfsRing *ring = opaque;
|
Xen9pfsRing *ring = opaque;
|
||||||
evtchn_port_t port;
|
evtchn_port_t port;
|
||||||
|
|
||||||
port = qemu_xen_evtchn_pending(ring->evtchndev);
|
port = xenevtchn_pending(ring->evtchndev);
|
||||||
qemu_xen_evtchn_unmask(ring->evtchndev, port);
|
xenevtchn_unmask(ring->evtchndev, port);
|
||||||
|
|
||||||
qemu_bh_schedule(ring->bh);
|
qemu_bh_schedule(ring->bh);
|
||||||
}
|
}
|
||||||
@@ -338,10 +337,10 @@ static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
|
|||||||
|
|
||||||
for (i = 0; i < xen_9pdev->num_rings; i++) {
|
for (i = 0; i < xen_9pdev->num_rings; i++) {
|
||||||
if (xen_9pdev->rings[i].evtchndev != NULL) {
|
if (xen_9pdev->rings[i].evtchndev != NULL) {
|
||||||
qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev),
|
qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
qemu_xen_evtchn_unbind(xen_9pdev->rings[i].evtchndev,
|
xenevtchn_unbind(xen_9pdev->rings[i].evtchndev,
|
||||||
xen_9pdev->rings[i].local_port);
|
xen_9pdev->rings[i].local_port);
|
||||||
xen_9pdev->rings[i].evtchndev = NULL;
|
xen_9pdev->rings[i].evtchndev = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,13 +359,12 @@ static int xen_9pfs_free(struct XenLegacyDevice *xendev)
|
|||||||
if (xen_9pdev->rings[i].data != NULL) {
|
if (xen_9pdev->rings[i].data != NULL) {
|
||||||
xen_be_unmap_grant_refs(&xen_9pdev->xendev,
|
xen_be_unmap_grant_refs(&xen_9pdev->xendev,
|
||||||
xen_9pdev->rings[i].data,
|
xen_9pdev->rings[i].data,
|
||||||
xen_9pdev->rings[i].intf->ref,
|
|
||||||
(1 << xen_9pdev->rings[i].ring_order));
|
(1 << xen_9pdev->rings[i].ring_order));
|
||||||
}
|
}
|
||||||
if (xen_9pdev->rings[i].intf != NULL) {
|
if (xen_9pdev->rings[i].intf != NULL) {
|
||||||
xen_be_unmap_grant_ref(&xen_9pdev->xendev,
|
xen_be_unmap_grant_refs(&xen_9pdev->xendev,
|
||||||
xen_9pdev->rings[i].intf,
|
xen_9pdev->rings[i].intf,
|
||||||
xen_9pdev->rings[i].ref);
|
1);
|
||||||
}
|
}
|
||||||
if (xen_9pdev->rings[i].bh != NULL) {
|
if (xen_9pdev->rings[i].bh != NULL) {
|
||||||
qemu_bh_delete(xen_9pdev->rings[i].bh);
|
qemu_bh_delete(xen_9pdev->rings[i].bh);
|
||||||
@@ -449,12 +447,12 @@ static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
|
|||||||
xen_9pdev->rings[i].inprogress = false;
|
xen_9pdev->rings[i].inprogress = false;
|
||||||
|
|
||||||
|
|
||||||
xen_9pdev->rings[i].evtchndev = qemu_xen_evtchn_open();
|
xen_9pdev->rings[i].evtchndev = xenevtchn_open(NULL, 0);
|
||||||
if (xen_9pdev->rings[i].evtchndev == NULL) {
|
if (xen_9pdev->rings[i].evtchndev == NULL) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
qemu_set_cloexec(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev));
|
qemu_set_cloexec(xenevtchn_fd(xen_9pdev->rings[i].evtchndev));
|
||||||
xen_9pdev->rings[i].local_port = qemu_xen_evtchn_bind_interdomain
|
xen_9pdev->rings[i].local_port = xenevtchn_bind_interdomain
|
||||||
(xen_9pdev->rings[i].evtchndev,
|
(xen_9pdev->rings[i].evtchndev,
|
||||||
xendev->dom,
|
xendev->dom,
|
||||||
xen_9pdev->rings[i].evtchn);
|
xen_9pdev->rings[i].evtchn);
|
||||||
@@ -465,8 +463,8 @@ static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
|
xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
|
||||||
qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev),
|
qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
|
||||||
xen_9pfs_evtchn_event, NULL, &xen_9pdev->rings[i]);
|
xen_9pfs_evtchn_event, NULL, &xen_9pdev->rings[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
xen_9pdev->security_model = xenstore_read_be_str(xendev, "security_model");
|
xen_9pdev->security_model = xenstore_read_be_str(xendev, "security_model");
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
const VMStateDescription vmstate_acpi_pcihp_pci_status;
|
const VMStateDescription vmstate_acpi_pcihp_pci_status;
|
||||||
|
|
||||||
void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
|
void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
|
||||||
MemoryRegion *address_space_io, uint16_t io_base)
|
MemoryRegion *address_space_io, bool bridges_enabled,
|
||||||
|
uint16_t io_base)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -35,12 +36,8 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_pcihp_reset(AcpiPciHpState *s)
|
void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ static bool vmstate_test_use_pcihp(void *opaque)
|
|||||||
{
|
{
|
||||||
ICH9LPCPMRegs *s = opaque;
|
ICH9LPCPMRegs *s = opaque;
|
||||||
|
|
||||||
return s->acpi_pci_hotplug.use_acpi_hotplug_bridge;
|
return s->use_acpi_hotplug_bridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_pcihp_state = {
|
static const VMStateDescription vmstate_pcihp_state = {
|
||||||
@@ -277,8 +277,8 @@ static void pm_reset(void *opaque)
|
|||||||
}
|
}
|
||||||
pm->smi_en_wmask = ~0;
|
pm->smi_en_wmask = ~0;
|
||||||
|
|
||||||
if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
|
if (pm->use_acpi_hotplug_bridge) {
|
||||||
acpi_pcihp_reset(&pm->acpi_pci_hotplug);
|
acpi_pcihp_reset(&pm->acpi_pci_hotplug, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
acpi_update_sci(&pm->acpi_regs, pm->irq);
|
acpi_update_sci(&pm->acpi_regs, pm->irq);
|
||||||
@@ -316,11 +316,12 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
|
|||||||
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
|
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
|
if (pm->use_acpi_hotplug_bridge) {
|
||||||
acpi_pcihp_init(OBJECT(lpc_pci),
|
acpi_pcihp_init(OBJECT(lpc_pci),
|
||||||
&pm->acpi_pci_hotplug,
|
&pm->acpi_pci_hotplug,
|
||||||
pci_get_bus(lpc_pci),
|
pci_get_bus(lpc_pci),
|
||||||
pci_address_space_io(lpc_pci),
|
pci_address_space_io(lpc_pci),
|
||||||
|
true,
|
||||||
ACPI_PCIHP_ADDR_ICH9);
|
ACPI_PCIHP_ADDR_ICH9);
|
||||||
|
|
||||||
qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)),
|
qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)),
|
||||||
@@ -402,14 +403,14 @@ static bool ich9_pm_get_acpi_pci_hotplug(Object *obj, Error **errp)
|
|||||||
{
|
{
|
||||||
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
|
||||||
return s->pm.acpi_pci_hotplug.use_acpi_hotplug_bridge;
|
return s->pm.use_acpi_hotplug_bridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp)
|
static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp)
|
||||||
{
|
{
|
||||||
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
||||||
|
|
||||||
s->pm.acpi_pci_hotplug.use_acpi_hotplug_bridge = value;
|
s->pm.use_acpi_hotplug_bridge = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ich9_pm_get_keep_pci_slot_hpc(Object *obj, Error **errp)
|
static bool ich9_pm_get_keep_pci_slot_hpc(Object *obj, Error **errp)
|
||||||
@@ -434,7 +435,7 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
|
|||||||
pm->disable_s3 = 0;
|
pm->disable_s3 = 0;
|
||||||
pm->disable_s4 = 0;
|
pm->disable_s4 = 0;
|
||||||
pm->s4_val = 2;
|
pm->s4_val = 2;
|
||||||
pm->acpi_pci_hotplug.use_acpi_hotplug_bridge = true;
|
pm->use_acpi_hotplug_bridge = true;
|
||||||
pm->keep_pci_slot_hpc = true;
|
pm->keep_pci_slot_hpc = true;
|
||||||
pm->enable_tco = true;
|
pm->enable_tco = true;
|
||||||
|
|
||||||
@@ -578,12 +579,6 @@ void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ich9_pm_is_hotpluggable_bus(HotplugHandler *hotplug_dev, BusState *bus)
|
|
||||||
{
|
|
||||||
ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
|
|
||||||
return acpi_pcihp_is_hotpluggbale_bus(&lpc->pm.acpi_pci_hotplug, bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
|
void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
|
||||||
{
|
{
|
||||||
ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
|
ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user