Compare commits
72 Commits
submitted
...
wcet_syste
Author | SHA1 | Date | |
---|---|---|---|
85e0a3f630 | |||
ab54074925 | |||
f5b92c8907 | |||
f438967783 | |||
3493dfa219 | |||
a5a49c3292 | |||
8a379ba198 | |||
6ffc2bbe4f | |||
0cf10fb0ff | |||
404cb91655 | |||
ff823f26ff | |||
80af255c2e | |||
e62b0072ea | |||
6ec50ee9c3 | |||
88a0358a4e | |||
78dac2f524 | |||
9caef2e60f | |||
b781a3ebce | |||
5a1cf4d873 | |||
c1dba1b39d | |||
![]() |
54e1f5be86 | ||
![]() |
fddd169de5 | ||
![]() |
711bd602cc | ||
![]() |
e88636b4d4 | ||
![]() |
34833f361b | ||
![]() |
43583f0c07 | ||
![]() |
1ce084af08 | ||
![]() |
fec12fc888 | ||
![]() |
ef0cf1887e | ||
![]() |
71ba2adfeb | ||
![]() |
7629818574 | ||
![]() |
4658dfcbc0 | ||
![]() |
2b2eb343a0 | ||
![]() |
932333c5f0 | ||
![]() |
8c2d5911de | ||
![]() |
08e46e6d92 | ||
![]() |
df1c9c3039 | ||
![]() |
7204b8f3c6 | ||
![]() |
36c651c226 | ||
![]() |
fceaefb43f | ||
![]() |
7d71e6bfb0 | ||
![]() |
c2c7f108b8 | ||
![]() |
3488bb205d | ||
![]() |
cddfaf96ab | ||
![]() |
43a457841f | ||
![]() |
ebf660beb1 | ||
![]() |
bbbdedb386 | ||
![]() |
8319de607f | ||
![]() |
a759dc19ec | ||
![]() |
24101e36f1 | ||
![]() |
a43e057bd6 | ||
![]() |
3aa2c2cd67 | ||
![]() |
9e80a430ed | ||
![]() |
c66f5dfc12 | ||
![]() |
5cf977a2a1 | ||
![]() |
36cfd11a86 | ||
![]() |
246ccfbf44 | ||
![]() |
3ee93e456d | ||
![]() |
ec08035102 | ||
![]() |
f97853c8cb | ||
![]() |
abeee2a470 | ||
![]() |
ff6d391e10 | ||
![]() |
b19de1137b | ||
![]() |
3c6e5df1f6 | ||
![]() |
695c25e167 | ||
![]() |
23ba9f170f | ||
![]() |
f0dee5a40d | ||
![]() |
7637373b23 | ||
![]() |
4c34ef3d34 | ||
![]() |
9e41f16fca | ||
![]() |
3054f772de | ||
![]() |
aa77e375a5 |
@ -10,9 +10,9 @@ windows_msys2_task:
|
|||||||
memory: 8G
|
memory: 8G
|
||||||
env:
|
env:
|
||||||
CIRRUS_SHELL: powershell
|
CIRRUS_SHELL: powershell
|
||||||
MSYS: winsymlinks:native
|
MSYS: winsymlinks:nativestrict
|
||||||
MSYSTEM: MINGW64
|
MSYSTEM: MINGW64
|
||||||
MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-base-x86_64-20220603.sfx.exe
|
MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-04-19/msys2-base-x86_64-20210419.sfx.exe
|
||||||
MSYS2_FINGERPRINT: 0
|
MSYS2_FINGERPRINT: 0
|
||||||
MSYS2_PACKAGES: "
|
MSYS2_PACKAGES: "
|
||||||
diffutils git grep make pkg-config sed
|
diffutils git grep make pkg-config sed
|
||||||
@ -32,6 +32,7 @@ windows_msys2_task:
|
|||||||
mingw-w64-x86_64-libgcrypt
|
mingw-w64-x86_64-libgcrypt
|
||||||
mingw-w64-x86_64-libpng
|
mingw-w64-x86_64-libpng
|
||||||
mingw-w64-x86_64-libssh
|
mingw-w64-x86_64-libssh
|
||||||
|
mingw-w64-x86_64-libxml2
|
||||||
mingw-w64-x86_64-snappy
|
mingw-w64-x86_64-snappy
|
||||||
mingw-w64-x86_64-libusb
|
mingw-w64-x86_64-libusb
|
||||||
mingw-w64-x86_64-usbredir
|
mingw-w64-x86_64-usbredir
|
||||||
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1,4 +1,3 @@
|
|||||||
*.c.inc diff=c
|
*.c.inc diff=c
|
||||||
*.h.inc diff=c
|
*.h.inc diff=c
|
||||||
*.m diff=objc
|
|
||||||
*.py diff=python
|
*.py diff=python
|
||||||
|
34
.github/lockdown.yml
vendored
Normal file
34
.github/lockdown.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
|
||||||
|
|
||||||
|
# Close issues and pull requests
|
||||||
|
close: true
|
||||||
|
|
||||||
|
# Lock issues and pull requests
|
||||||
|
lock: true
|
||||||
|
|
||||||
|
issues:
|
||||||
|
comment: |
|
||||||
|
Thank you for your interest in the QEMU project.
|
||||||
|
|
||||||
|
This repository is a read-only mirror of the project's repostories hosted
|
||||||
|
at https://gitlab.com/qemu-project/qemu.git.
|
||||||
|
The project does not process issues filed on GitHub.
|
||||||
|
|
||||||
|
The project issues are tracked on GitLab:
|
||||||
|
https://gitlab.com/qemu-project/qemu/-/issues
|
||||||
|
|
||||||
|
QEMU welcomes bug report contributions. You can file new ones on:
|
||||||
|
https://gitlab.com/qemu-project/qemu/-/issues/new
|
||||||
|
|
||||||
|
pulls:
|
||||||
|
comment: |
|
||||||
|
Thank you for your interest in the QEMU project.
|
||||||
|
|
||||||
|
This repository is a read-only mirror of the project's repostories hosted
|
||||||
|
on https://gitlab.com/qemu-project/qemu.git.
|
||||||
|
The project does not process merge requests filed on GitHub.
|
||||||
|
|
||||||
|
QEMU welcomes contributions of code (either fixing bugs or adding new
|
||||||
|
functionality). However, we get a lot of patches, and so we have some
|
||||||
|
guidelines about contributing on the project website:
|
||||||
|
https://www.qemu.org/contribute/
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,15 +1,9 @@
|
|||||||
/qemu_libafl_bridge/Cargo.lock
|
|
||||||
/qemu_libafl_bridge/target/
|
|
||||||
/GNUmakefile
|
/GNUmakefile
|
||||||
/build/
|
/build/
|
||||||
/.cache/
|
|
||||||
/.vscode/
|
|
||||||
*.pyc
|
*.pyc
|
||||||
.sdk
|
.sdk
|
||||||
.stgit-*
|
.stgit-*
|
||||||
.git-submodule-status
|
.git-submodule-status
|
||||||
.clang-format
|
|
||||||
.gdb_history
|
|
||||||
cscope.*
|
cscope.*
|
||||||
tags
|
tags
|
||||||
TAGS
|
TAGS
|
||||||
@ -21,4 +15,6 @@ GTAGS
|
|||||||
*.depend_raw
|
*.depend_raw
|
||||||
*.swp
|
*.swp
|
||||||
*.patch
|
*.patch
|
||||||
*.gcov
|
.cache
|
||||||
|
*.axf
|
||||||
|
*.qcow2
|
@ -1,72 +0,0 @@
|
|||||||
|
|
||||||
# The order of rules defined here is critically important.
|
|
||||||
# They are evaluated in order and first match wins.
|
|
||||||
#
|
|
||||||
# Thus we group them into a number of stages, ordered from
|
|
||||||
# most restrictive to least restrictive
|
|
||||||
#
|
|
||||||
.base_job_template:
|
|
||||||
rules:
|
|
||||||
#############################################################
|
|
||||||
# Stage 1: exclude scenarios where we definitely don't
|
|
||||||
# want jobs to run
|
|
||||||
#############################################################
|
|
||||||
|
|
||||||
# Cirrus jobs can't run unless the creds / target repo are set
|
|
||||||
- if: '$QEMU_JOB_CIRRUS && ($CIRRUS_GITHUB_REPO == null || $CIRRUS_API_TOKEN == null)'
|
|
||||||
when: never
|
|
||||||
|
|
||||||
# Publishing jobs should only run on the default branch in upstream
|
|
||||||
- if: '$QEMU_JOB_PUBLISH == "1" && $CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH'
|
|
||||||
when: never
|
|
||||||
|
|
||||||
# Non-publishing jobs should only run on staging branches in upstream
|
|
||||||
- if: '$QEMU_JOB_PUBLISH != "1" && $CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/'
|
|
||||||
when: never
|
|
||||||
|
|
||||||
# Jobs only intended for forks should always be skipped on upstream
|
|
||||||
- if: '$QEMU_JOB_ONLY_FORKS == "1" && $CI_PROJECT_NAMESPACE == "qemu-project"'
|
|
||||||
when: never
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# Avocado jobs don't run in forks unless $QEMU_CI_AVOCADO_TESTING is set
|
|
||||||
- if: '$QEMU_JOB_AVOCADO && $QEMU_CI_AVOCADO_TESTING != "1" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
|
||||||
when: never
|
|
||||||
|
|
||||||
|
|
||||||
#############################################################
|
|
||||||
# Stage 2: fine tune execution of jobs in specific scenarios
|
|
||||||
# where the catch all logic is inapprorpaite
|
|
||||||
#############################################################
|
|
||||||
|
|
||||||
# Optional jobs should not be run unless manually triggered
|
|
||||||
- if: '$QEMU_JOB_OPTIONAL'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
# Skipped jobs should not be run unless manually triggered
|
|
||||||
- if: '$QEMU_JOB_SKIPPED'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
# Avocado jobs can be manually start in forks if $QEMU_CI_AVOCADO_TESTING is unset
|
|
||||||
- if: '$QEMU_JOB_AVOCADO && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
|
|
||||||
#############################################################
|
|
||||||
# Stage 3: catch all logic applying to any job not matching
|
|
||||||
# an earlier criteria
|
|
||||||
#############################################################
|
|
||||||
|
|
||||||
# Forks pipeline jobs don't start automatically unless
|
|
||||||
# QEMU_CI=2 is set
|
|
||||||
- if: '$QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
# Jobs can run if any jobs they depend on were successfull
|
|
||||||
- when: on_success
|
|
@ -1,5 +1,4 @@
|
|||||||
.native_build_job_template:
|
.native_build_job_template:
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
stage: build
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||||
before_script:
|
before_script:
|
||||||
@ -27,8 +26,7 @@
|
|||||||
make -j"$JOBS" $MAKE_CHECK_ARGS ;
|
make -j"$JOBS" $MAKE_CHECK_ARGS ;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
.common_test_job_template:
|
.native_test_job_template:
|
||||||
extends: .base_job_template
|
|
||||||
stage: test
|
stage: test
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||||
script:
|
script:
|
||||||
@ -39,18 +37,8 @@
|
|||||||
# Avoid recompiling by hiding ninja with NINJA=":"
|
# Avoid recompiling by hiding ninja with NINJA=":"
|
||||||
- make NINJA=":" $MAKE_CHECK_ARGS
|
- make NINJA=":" $MAKE_CHECK_ARGS
|
||||||
|
|
||||||
.native_test_job_template:
|
.acceptance_test_job_template:
|
||||||
extends: .common_test_job_template
|
extends: .native_test_job_template
|
||||||
artifacts:
|
|
||||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
|
||||||
expire_in: 7 days
|
|
||||||
paths:
|
|
||||||
- build/meson-logs/testlog.txt
|
|
||||||
reports:
|
|
||||||
junit: build/meson-logs/testlog.junit.xml
|
|
||||||
|
|
||||||
.avocado_test_job_template:
|
|
||||||
extends: .common_test_job_template
|
|
||||||
cache:
|
cache:
|
||||||
key: "${CI_JOB_NAME}-cache"
|
key: "${CI_JOB_NAME}-cache"
|
||||||
paths:
|
paths:
|
||||||
@ -79,5 +67,15 @@
|
|||||||
after_script:
|
after_script:
|
||||||
- cd build
|
- cd build
|
||||||
- du -chs ${CI_PROJECT_DIR}/avocado-cache
|
- du -chs ${CI_PROJECT_DIR}/avocado-cache
|
||||||
variables:
|
rules:
|
||||||
QEMU_JOB_AVOCADO: 1
|
# Only run these jobs if running on the mainstream namespace,
|
||||||
|
# or if the user set the QEMU_CI_AVOCADO_TESTING variable (either
|
||||||
|
# in its namespace setting or via git-push option, see documentation
|
||||||
|
# in /.gitlab-ci.yml of this repository).
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
|
||||||
|
when: on_success
|
||||||
|
- if: '$QEMU_CI_AVOCADO_TESTING'
|
||||||
|
when: on_success
|
||||||
|
# Otherwise, set to manual (the jobs are created but not run).
|
||||||
|
- when: manual
|
||||||
|
allow_failure: true
|
||||||
|
@ -24,16 +24,16 @@ check-system-alpine:
|
|||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: alpine
|
IMAGE: alpine
|
||||||
MAKE_CHECK_ARGS: check-unit check-qtest
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-system-alpine:
|
acceptance-system-alpine:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-system-alpine
|
- job: build-system-alpine
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: alpine
|
IMAGE: alpine
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
build-system-ubuntu:
|
build-system-ubuntu:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -41,7 +41,7 @@ build-system-ubuntu:
|
|||||||
job: amd64-ubuntu2004-container
|
job: amd64-ubuntu2004-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: ubuntu2004
|
IMAGE: ubuntu2004
|
||||||
CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-capstone
|
CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system
|
||||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||||
microblazeel-softmmu mips64el-softmmu
|
microblazeel-softmmu mips64el-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
@ -59,14 +59,14 @@ check-system-ubuntu:
|
|||||||
IMAGE: ubuntu2004
|
IMAGE: ubuntu2004
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-system-ubuntu:
|
acceptance-system-ubuntu:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-system-ubuntu
|
- job: build-system-ubuntu
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: ubuntu2004
|
IMAGE: ubuntu2004
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
build-system-debian:
|
build-system-debian:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -74,6 +74,7 @@ build-system-debian:
|
|||||||
job: amd64-debian-container
|
job: amd64-debian-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian-amd64
|
IMAGE: debian-amd64
|
||||||
|
CONFIGURE_ARGS: --enable-fdt=system
|
||||||
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
|
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
|
||||||
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
|
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
@ -91,26 +92,14 @@ check-system-debian:
|
|||||||
IMAGE: debian-amd64
|
IMAGE: debian-amd64
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-system-debian:
|
acceptance-system-debian:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-system-debian
|
- job: build-system-debian
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian-amd64
|
IMAGE: debian-amd64
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
crash-test-debian:
|
|
||||||
extends: .native_test_job_template
|
|
||||||
needs:
|
|
||||||
- job: build-system-debian
|
|
||||||
artifacts: true
|
|
||||||
variables:
|
|
||||||
IMAGE: debian-amd64
|
|
||||||
script:
|
|
||||||
- cd build
|
|
||||||
- make check-venv
|
|
||||||
- tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-i386
|
|
||||||
|
|
||||||
build-system-fedora:
|
build-system-fedora:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -119,7 +108,7 @@ build-system-fedora:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs
|
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs
|
||||||
--enable-fdt=system --enable-slirp --enable-capstone
|
--enable-fdt=system --enable-slirp=system --enable-capstone=system
|
||||||
TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu
|
TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu
|
||||||
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
@ -137,27 +126,14 @@ check-system-fedora:
|
|||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-system-fedora:
|
acceptance-system-fedora:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-system-fedora
|
- job: build-system-fedora
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
crash-test-fedora:
|
|
||||||
extends: .native_test_job_template
|
|
||||||
needs:
|
|
||||||
- job: build-system-fedora
|
|
||||||
artifacts: true
|
|
||||||
variables:
|
|
||||||
IMAGE: fedora
|
|
||||||
script:
|
|
||||||
- cd build
|
|
||||||
- make check-venv
|
|
||||||
- tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-ppc
|
|
||||||
- tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-riscv32
|
|
||||||
|
|
||||||
build-system-centos:
|
build-system-centos:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -166,8 +142,7 @@ build-system-centos:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE: centos8
|
IMAGE: centos8
|
||||||
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-fdt=system
|
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-fdt=system
|
||||||
--enable-modules --enable-trace-backends=dtrace --enable-docs
|
--enable-modules --enable-trace-backends=dtrace
|
||||||
--enable-vfio-user-server
|
|
||||||
TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu
|
TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu
|
||||||
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
|
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
@ -185,14 +160,14 @@ check-system-centos:
|
|||||||
IMAGE: centos8
|
IMAGE: centos8
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-system-centos:
|
acceptance-system-centos:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-system-centos
|
- job: build-system-centos
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: centos8
|
IMAGE: centos8
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
build-system-opensuse:
|
build-system-opensuse:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -217,16 +192,95 @@ check-system-opensuse:
|
|||||||
IMAGE: opensuse-leap
|
IMAGE: opensuse-leap
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-system-opensuse:
|
acceptance-system-opensuse:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-system-opensuse
|
- job: build-system-opensuse
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: opensuse-leap
|
IMAGE: opensuse-leap
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
|
|
||||||
|
build-disabled:
|
||||||
|
extends: .native_build_job_template
|
||||||
|
needs:
|
||||||
|
job: amd64-fedora-container
|
||||||
|
variables:
|
||||||
|
IMAGE: fedora
|
||||||
|
CONFIGURE_ARGS:
|
||||||
|
--disable-attr
|
||||||
|
--disable-auth-pam
|
||||||
|
--disable-avx2
|
||||||
|
--disable-bochs
|
||||||
|
--disable-brlapi
|
||||||
|
--disable-bzip2
|
||||||
|
--disable-cap-ng
|
||||||
|
--disable-capstone
|
||||||
|
--disable-cloop
|
||||||
|
--disable-coroutine-pool
|
||||||
|
--disable-curl
|
||||||
|
--disable-curses
|
||||||
|
--disable-dmg
|
||||||
|
--disable-docs
|
||||||
|
--disable-gcrypt
|
||||||
|
--disable-glusterfs
|
||||||
|
--disable-gnutls
|
||||||
|
--disable-gtk
|
||||||
|
--disable-guest-agent
|
||||||
|
--disable-iconv
|
||||||
|
--disable-keyring
|
||||||
|
--disable-kvm
|
||||||
|
--disable-libiscsi
|
||||||
|
--disable-libpmem
|
||||||
|
--disable-libssh
|
||||||
|
--disable-libudev
|
||||||
|
--disable-libusb
|
||||||
|
--disable-libxml2
|
||||||
|
--disable-linux-aio
|
||||||
|
--disable-live-block-migration
|
||||||
|
--disable-lzo
|
||||||
|
--disable-malloc-trim
|
||||||
|
--disable-mpath
|
||||||
|
--disable-nettle
|
||||||
|
--disable-numa
|
||||||
|
--disable-opengl
|
||||||
|
--disable-parallels
|
||||||
|
--disable-pie
|
||||||
|
--disable-qcow1
|
||||||
|
--disable-qed
|
||||||
|
--disable-qom-cast-debug
|
||||||
|
--disable-rbd
|
||||||
|
--disable-rdma
|
||||||
|
--disable-replication
|
||||||
|
--disable-sdl
|
||||||
|
--disable-seccomp
|
||||||
|
--disable-slirp
|
||||||
|
--disable-smartcard
|
||||||
|
--disable-snappy
|
||||||
|
--disable-sparse
|
||||||
|
--disable-spice
|
||||||
|
--disable-strip
|
||||||
|
--disable-tpm
|
||||||
|
--disable-usb-redir
|
||||||
|
--disable-vdi
|
||||||
|
--disable-vhost-crypto
|
||||||
|
--disable-vhost-net
|
||||||
|
--disable-vhost-scsi
|
||||||
|
--disable-vhost-kernel
|
||||||
|
--disable-vhost-user
|
||||||
|
--disable-vhost-vdpa
|
||||||
|
--disable-vhost-vsock
|
||||||
|
--disable-virglrenderer
|
||||||
|
--disable-vnc
|
||||||
|
--disable-vte
|
||||||
|
--disable-vvfat
|
||||||
|
--disable-xen
|
||||||
|
--disable-zstd
|
||||||
|
TARGETS: arm-softmmu i386-softmmu ppc64-softmmu mips64-softmmu
|
||||||
|
s390x-softmmu i386-linux-user
|
||||||
|
MAKE_CHECK_ARGS: check-qtest SPEED=slow
|
||||||
|
|
||||||
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by
|
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by
|
||||||
# the configure script. The container doesn't contain Xen headers so
|
# the configure script. The container doesn't contain Xen headers so
|
||||||
# Xen accelerator is not detected / selected. As result it build the
|
# Xen accelerator is not detected / selected. As result it build the
|
||||||
@ -251,11 +305,11 @@ build-tcg-disabled:
|
|||||||
- cd tests/qemu-iotests/
|
- cd tests/qemu-iotests/
|
||||||
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
|
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
|
||||||
052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163
|
052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163
|
||||||
170 171 183 184 192 194 208 221 226 227 236 253 277 image-fleecing
|
170 171 183 184 192 194 208 221 222 226 227 236 253 277
|
||||||
- ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122
|
- ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122
|
||||||
124 132 139 142 144 145 151 152 155 157 165 194 196 200 202
|
124 132 139 142 144 145 151 152 155 157 165 194 196 200 202
|
||||||
208 209 216 218 227 234 246 247 248 250 254 255 257 258
|
208 209 216 218 222 227 234 246 247 248 250 254 255 257 258
|
||||||
260 261 262 263 264 270 272 273 277 279 image-fleecing
|
260 261 262 263 264 270 272 273 277 279
|
||||||
|
|
||||||
build-user:
|
build-user:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -327,7 +381,6 @@ clang-user:
|
|||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
needs:
|
needs:
|
||||||
job: amd64-debian-user-cross-container
|
job: amd64-debian-user-cross-container
|
||||||
timeout: 70m
|
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian-all-test-cross
|
IMAGE: debian-all-test-cross
|
||||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system
|
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system
|
||||||
@ -339,10 +392,12 @@ clang-user:
|
|||||||
# On gitlab runners, default value sometimes end up calling 2 lds concurrently and
|
# On gitlab runners, default value sometimes end up calling 2 lds concurrently and
|
||||||
# triggers an Out-Of-Memory error
|
# triggers an Out-Of-Memory error
|
||||||
#
|
#
|
||||||
# Since slirp callbacks are used in QEMU Timers, we cannot use libslirp with
|
# Since slirp callbacks are used in QEMU Timers, slirp needs to be compiled together
|
||||||
# CFI builds, and thus have to disable it here.
|
# with QEMU and linked as a static library to avoid false positives in CFI checks.
|
||||||
|
# This can be accomplished by using -enable-slirp=git, which avoids the use of
|
||||||
|
# a system-wide version of the library
|
||||||
#
|
#
|
||||||
# Split in three sets of build/check/avocado to limit the execution time of each
|
# Split in three sets of build/check/acceptance to limit the execution time of each
|
||||||
# job
|
# job
|
||||||
build-cfi-aarch64:
|
build-cfi-aarch64:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -353,18 +408,20 @@ build-cfi-aarch64:
|
|||||||
AR: llvm-ar
|
AR: llvm-ar
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||||
--enable-safe-stack --disable-slirp
|
--enable-safe-stack --enable-slirp=git
|
||||||
TARGETS: aarch64-softmmu
|
TARGETS: aarch64-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
# FIXME: This job is often failing, likely due to out-of-memory problems in
|
timeout: 70m
|
||||||
# the constrained containers of the shared runners. Thus this is marked as
|
|
||||||
# skipped until the situation has been solved.
|
|
||||||
QEMU_JOB_SKIPPED: 1
|
|
||||||
timeout: 90m
|
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 days
|
expire_in: 2 days
|
||||||
paths:
|
paths:
|
||||||
- build
|
- build
|
||||||
|
rules:
|
||||||
|
# FIXME: This job is often failing, likely due to out-of-memory problems in
|
||||||
|
# the constrained containers of the shared runners. Thus this is marked as
|
||||||
|
# manual until the situation has been solved.
|
||||||
|
- when: manual
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
check-cfi-aarch64:
|
check-cfi-aarch64:
|
||||||
extends: .native_test_job_template
|
extends: .native_test_job_template
|
||||||
@ -375,14 +432,14 @@ check-cfi-aarch64:
|
|||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-cfi-aarch64:
|
acceptance-cfi-aarch64:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-cfi-aarch64
|
- job: build-cfi-aarch64
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
build-cfi-ppc64-s390x:
|
build-cfi-ppc64-s390x:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -393,18 +450,20 @@ build-cfi-ppc64-s390x:
|
|||||||
AR: llvm-ar
|
AR: llvm-ar
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||||
--enable-safe-stack --disable-slirp
|
--enable-safe-stack --enable-slirp=git
|
||||||
TARGETS: ppc64-softmmu s390x-softmmu
|
TARGETS: ppc64-softmmu s390x-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
# FIXME: This job is often failing, likely due to out-of-memory problems in
|
timeout: 70m
|
||||||
# the constrained containers of the shared runners. Thus this is marked as
|
|
||||||
# skipped until the situation has been solved.
|
|
||||||
QEMU_JOB_SKIPPED: 1
|
|
||||||
timeout: 80m
|
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 days
|
expire_in: 2 days
|
||||||
paths:
|
paths:
|
||||||
- build
|
- build
|
||||||
|
rules:
|
||||||
|
# FIXME: This job is often failing, likely due to out-of-memory problems in
|
||||||
|
# the constrained containers of the shared runners. Thus this is marked as
|
||||||
|
# manual until the situation has been solved.
|
||||||
|
- when: manual
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
check-cfi-ppc64-s390x:
|
check-cfi-ppc64-s390x:
|
||||||
extends: .native_test_job_template
|
extends: .native_test_job_template
|
||||||
@ -415,14 +474,14 @@ check-cfi-ppc64-s390x:
|
|||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-cfi-ppc64-s390x:
|
acceptance-cfi-ppc64-s390x:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-cfi-ppc64-s390x
|
- job: build-cfi-ppc64-s390x
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
build-cfi-x86_64:
|
build-cfi-x86_64:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -433,7 +492,7 @@ build-cfi-x86_64:
|
|||||||
AR: llvm-ar
|
AR: llvm-ar
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||||
--enable-safe-stack --disable-slirp
|
--enable-safe-stack --enable-slirp=git
|
||||||
TARGETS: x86_64-softmmu
|
TARGETS: x86_64-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
MAKE_CHECK_ARGS: check-build
|
||||||
timeout: 70m
|
timeout: 70m
|
||||||
@ -451,14 +510,14 @@ check-cfi-x86_64:
|
|||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
|
|
||||||
avocado-cfi-x86_64:
|
acceptance-cfi-x86_64:
|
||||||
extends: .avocado_test_job_template
|
extends: .acceptance_test_job_template
|
||||||
needs:
|
needs:
|
||||||
- job: build-cfi-x86_64
|
- job: build-cfi-x86_64
|
||||||
artifacts: true
|
artifacts: true
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora
|
IMAGE: fedora
|
||||||
MAKE_CHECK_ARGS: check-avocado
|
MAKE_CHECK_ARGS: check-acceptance
|
||||||
|
|
||||||
tsan-build:
|
tsan-build:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -467,10 +526,37 @@ tsan-build:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE: ubuntu2004
|
IMAGE: ubuntu2004
|
||||||
CONFIGURE_ARGS: --enable-tsan --cc=clang-10 --cxx=clang++-10
|
CONFIGURE_ARGS: --enable-tsan --cc=clang-10 --cxx=clang++-10
|
||||||
--enable-trace-backends=ust --enable-fdt=system --disable-slirp
|
--enable-trace-backends=ust --enable-fdt=system --enable-slirp=system
|
||||||
TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user
|
TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user
|
||||||
MAKE_CHECK_ARGS: bench V=1
|
MAKE_CHECK_ARGS: bench V=1
|
||||||
|
|
||||||
|
# These targets are on the way out
|
||||||
|
build-deprecated:
|
||||||
|
extends: .native_build_job_template
|
||||||
|
needs:
|
||||||
|
job: amd64-debian-user-cross-container
|
||||||
|
variables:
|
||||||
|
IMAGE: debian-all-test-cross
|
||||||
|
CONFIGURE_ARGS: --disable-tools
|
||||||
|
MAKE_CHECK_ARGS: build-tcg
|
||||||
|
TARGETS: ppc64abi32-linux-user
|
||||||
|
artifacts:
|
||||||
|
expire_in: 2 days
|
||||||
|
paths:
|
||||||
|
- build
|
||||||
|
|
||||||
|
# We split the check-tcg step as test failures are expected but we still
|
||||||
|
# want to catch the build breaking.
|
||||||
|
check-deprecated:
|
||||||
|
extends: .native_test_job_template
|
||||||
|
needs:
|
||||||
|
- job: build-deprecated
|
||||||
|
artifacts: true
|
||||||
|
variables:
|
||||||
|
IMAGE: debian-all-test-cross
|
||||||
|
MAKE_CHECK_ARGS: check-tcg
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
# gprof/gcov are GCC features
|
# gprof/gcov are GCC features
|
||||||
build-gprof-gcov:
|
build-gprof-gcov:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -494,17 +580,7 @@ check-gprof-gcov:
|
|||||||
IMAGE: ubuntu2004
|
IMAGE: ubuntu2004
|
||||||
MAKE_CHECK_ARGS: check
|
MAKE_CHECK_ARGS: check
|
||||||
after_script:
|
after_script:
|
||||||
- cd build
|
- ${CI_PROJECT_DIR}/scripts/ci/coverage-summary.sh
|
||||||
- gcovr --xml-pretty --exclude-unreachable-branches --print-summary
|
|
||||||
-o coverage.xml --root ${CI_PROJECT_DIR} . *.p
|
|
||||||
coverage: /^\s*lines:\s*\d+.\d+\%/
|
|
||||||
artifacts:
|
|
||||||
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
|
||||||
expire_in: 2 days
|
|
||||||
reports:
|
|
||||||
coverage_report:
|
|
||||||
coverage_format: cobertura
|
|
||||||
path: build/coverage.xml
|
|
||||||
|
|
||||||
build-oss-fuzz:
|
build-oss-fuzz:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -523,6 +599,8 @@ build-oss-fuzz:
|
|||||||
echo Testing ${fuzzer} ... ;
|
echo Testing ${fuzzer} ... ;
|
||||||
"${fuzzer}" -runs=1 -seed=1 || exit 1 ;
|
"${fuzzer}" -runs=1 -seed=1 || exit 1 ;
|
||||||
done
|
done
|
||||||
|
# Unrelated to fuzzer: run some tests with -fsanitize=address
|
||||||
|
- cd build-oss-fuzz && make check-qtest-i386 check-unit
|
||||||
|
|
||||||
build-tci:
|
build-tci:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
@ -571,25 +649,20 @@ build-without-default-devices:
|
|||||||
build-without-default-features:
|
build-without-default-features:
|
||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
needs:
|
needs:
|
||||||
job: amd64-fedora-container
|
job: amd64-debian-container
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora
|
IMAGE: debian-amd64
|
||||||
CONFIGURE_ARGS:
|
CONFIGURE_ARGS: --without-default-features --disable-user
|
||||||
--without-default-features
|
--target-list-exclude=arm-softmmu,i386-softmmu,mipsel-softmmu,mips64-softmmu,ppc-softmmu
|
||||||
--disable-capstone
|
MAKE_CHECK_ARGS: check-unit
|
||||||
--disable-pie
|
|
||||||
--disable-qom-cast-debug
|
|
||||||
--disable-strip
|
|
||||||
TARGETS: avr-softmmu i386-softmmu mips64-softmmu s390x-softmmu sh4-softmmu
|
|
||||||
sparc64-softmmu hexagon-linux-user i386-linux-user s390x-linux-user
|
|
||||||
MAKE_CHECK_ARGS: check-unit check-qtest SPEED=slow
|
|
||||||
|
|
||||||
build-libvhost-user:
|
build-libvhost-user:
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
stage: build
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/fedora:latest
|
image: $CI_REGISTRY_IMAGE/qemu/fedora:latest
|
||||||
needs:
|
needs:
|
||||||
job: amd64-fedora-container
|
job: amd64-fedora-container
|
||||||
|
before_script:
|
||||||
|
- dnf install -y meson ninja-build
|
||||||
script:
|
script:
|
||||||
- mkdir subprojects/libvhost-user/build
|
- mkdir subprojects/libvhost-user/build
|
||||||
- cd subprojects/libvhost-user/build
|
- cd subprojects/libvhost-user/build
|
||||||
@ -602,13 +675,10 @@ build-tools-and-docs-debian:
|
|||||||
extends: .native_build_job_template
|
extends: .native_build_job_template
|
||||||
needs:
|
needs:
|
||||||
job: amd64-debian-container
|
job: amd64-debian-container
|
||||||
# when running on 'master' we use pre-existing container
|
|
||||||
optional: true
|
|
||||||
variables:
|
variables:
|
||||||
IMAGE: debian-amd64
|
IMAGE: debian-amd64
|
||||||
MAKE_CHECK_ARGS: check-unit ctags TAGS cscope
|
MAKE_CHECK_ARGS: check-unit check-softfloat ctags TAGS cscope
|
||||||
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
|
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
|
||||||
QEMU_JOB_PUBLISH: 1
|
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 days
|
expire_in: 2 days
|
||||||
paths:
|
paths:
|
||||||
@ -628,7 +698,6 @@ build-tools-and-docs-debian:
|
|||||||
# that users can see the results of their commits, regardless
|
# that users can see the results of their commits, regardless
|
||||||
# of what topic branch they're currently using
|
# of what topic branch they're currently using
|
||||||
pages:
|
pages:
|
||||||
extends: .base_job_template
|
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest
|
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest
|
||||||
stage: test
|
stage: test
|
||||||
needs:
|
needs:
|
||||||
@ -646,5 +715,10 @@ pages:
|
|||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- public
|
- public
|
||||||
variables:
|
rules:
|
||||||
QEMU_JOB_PUBLISH: 1
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||||
|
when: on_success
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
|
||||||
|
when: never
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE != "qemu-project"'
|
||||||
|
when: on_success
|
||||||
|
@ -11,11 +11,9 @@
|
|||||||
# special care, because we can't just override it at the GitLab CI job
|
# special care, because we can't just override it at the GitLab CI job
|
||||||
# definition level or we risk breaking it completely.
|
# definition level or we risk breaking it completely.
|
||||||
.cirrus_build_job:
|
.cirrus_build_job:
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
stage: build
|
||||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
||||||
needs: []
|
needs: []
|
||||||
timeout: 80m
|
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
script:
|
script:
|
||||||
- source .gitlab-ci.d/cirrus/$NAME.vars
|
- source .gitlab-ci.d/cirrus/$NAME.vars
|
||||||
@ -37,12 +35,12 @@
|
|||||||
-e "s|[@]PIP3@|$PIP3|g"
|
-e "s|[@]PIP3@|$PIP3|g"
|
||||||
-e "s|[@]PYPI_PKGS@|$PYPI_PKGS|g"
|
-e "s|[@]PYPI_PKGS@|$PYPI_PKGS|g"
|
||||||
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
|
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
|
||||||
-e "s|[@]TEST_TARGETS@|$TEST_TARGETS|g"
|
-e "s|[@]TEST_TARGETSS@|$TEST_TARGETSS|g"
|
||||||
<.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml
|
<.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml
|
||||||
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
||||||
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
||||||
variables:
|
rules:
|
||||||
QEMU_JOB_CIRRUS: 1
|
- if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN"
|
||||||
|
|
||||||
x64-freebsd-12-build:
|
x64-freebsd-12-build:
|
||||||
extends: .cirrus_build_job
|
extends: .cirrus_build_job
|
||||||
@ -50,11 +48,14 @@ x64-freebsd-12-build:
|
|||||||
NAME: freebsd-12
|
NAME: freebsd-12
|
||||||
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
|
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
|
||||||
CIRRUS_VM_IMAGE_SELECTOR: image_family
|
CIRRUS_VM_IMAGE_SELECTOR: image_family
|
||||||
CIRRUS_VM_IMAGE_NAME: freebsd-12-3
|
CIRRUS_VM_IMAGE_NAME: freebsd-12-2
|
||||||
CIRRUS_VM_CPUS: 8
|
CIRRUS_VM_CPUS: 8
|
||||||
CIRRUS_VM_RAM: 8G
|
CIRRUS_VM_RAM: 8G
|
||||||
UPDATE_COMMAND: pkg update
|
UPDATE_COMMAND: pkg update
|
||||||
INSTALL_COMMAND: pkg install -y
|
INSTALL_COMMAND: pkg install -y
|
||||||
|
# TODO: Enable gnutls again once FreeBSD's libtasn1 got fixed
|
||||||
|
# See: https://gitlab.com/gnutls/libtasn1/-/merge_requests/71
|
||||||
|
CONFIGURE_ARGS: --disable-gnutls
|
||||||
TEST_TARGETS: check
|
TEST_TARGETS: check
|
||||||
|
|
||||||
x64-freebsd-13-build:
|
x64-freebsd-13-build:
|
||||||
@ -63,61 +64,24 @@ x64-freebsd-13-build:
|
|||||||
NAME: freebsd-13
|
NAME: freebsd-13
|
||||||
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
|
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
|
||||||
CIRRUS_VM_IMAGE_SELECTOR: image_family
|
CIRRUS_VM_IMAGE_SELECTOR: image_family
|
||||||
CIRRUS_VM_IMAGE_NAME: freebsd-13-1
|
CIRRUS_VM_IMAGE_NAME: freebsd-13-0
|
||||||
CIRRUS_VM_CPUS: 8
|
CIRRUS_VM_CPUS: 8
|
||||||
CIRRUS_VM_RAM: 8G
|
CIRRUS_VM_RAM: 8G
|
||||||
UPDATE_COMMAND: pkg update
|
UPDATE_COMMAND: pkg update
|
||||||
INSTALL_COMMAND: pkg install -y
|
INSTALL_COMMAND: pkg install -y
|
||||||
TEST_TARGETS: check
|
TEST_TARGETS: check
|
||||||
|
|
||||||
aarch64-macos-12-base-build:
|
x64-macos-11-base-build:
|
||||||
extends: .cirrus_build_job
|
extends: .cirrus_build_job
|
||||||
variables:
|
variables:
|
||||||
NAME: macos-12
|
NAME: macos-11
|
||||||
CIRRUS_VM_INSTANCE_TYPE: macos_instance
|
CIRRUS_VM_INSTANCE_TYPE: osx_instance
|
||||||
CIRRUS_VM_IMAGE_SELECTOR: image
|
CIRRUS_VM_IMAGE_SELECTOR: image
|
||||||
CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-monterey-base:latest
|
CIRRUS_VM_IMAGE_NAME: big-sur-base
|
||||||
CIRRUS_VM_CPUS: 12
|
CIRRUS_VM_CPUS: 12
|
||||||
CIRRUS_VM_RAM: 24G
|
CIRRUS_VM_RAM: 24G
|
||||||
UPDATE_COMMAND: brew update
|
UPDATE_COMMAND: brew update
|
||||||
INSTALL_COMMAND: brew install
|
INSTALL_COMMAND: brew install
|
||||||
PATH_EXTRA: /opt/homebrew/ccache/libexec:/opt/homebrew/gettext/bin
|
PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin
|
||||||
PKG_CONFIG_PATH: /opt/homebrew/curl/lib/pkgconfig:/opt/homebrew/ncurses/lib/pkgconfig:/opt/homebrew/readline/lib/pkgconfig
|
PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig
|
||||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
||||||
|
|
||||||
|
|
||||||
# The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job
|
|
||||||
.cirrus_kvm_job:
|
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
|
||||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
|
||||||
needs: []
|
|
||||||
timeout: 80m
|
|
||||||
script:
|
|
||||||
- sed -e "s|[@]CI_REPOSITORY_URL@|$CI_REPOSITORY_URL|g"
|
|
||||||
-e "s|[@]CI_COMMIT_REF_NAME@|$CI_COMMIT_REF_NAME|g"
|
|
||||||
-e "s|[@]CI_COMMIT_SHA@|$CI_COMMIT_SHA|g"
|
|
||||||
-e "s|[@]NAME@|$NAME|g"
|
|
||||||
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
|
|
||||||
-e "s|[@]TEST_TARGETS@|$TEST_TARGETS|g"
|
|
||||||
<.gitlab-ci.d/cirrus/kvm-build.yml >.gitlab-ci.d/cirrus/$NAME.yml
|
|
||||||
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
|
||||||
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
|
||||||
variables:
|
|
||||||
QEMU_JOB_CIRRUS: 1
|
|
||||||
QEMU_JOB_OPTIONAL: 1
|
|
||||||
|
|
||||||
|
|
||||||
x86-netbsd:
|
|
||||||
extends: .cirrus_kvm_job
|
|
||||||
variables:
|
|
||||||
NAME: netbsd
|
|
||||||
CONFIGURE_ARGS: --target-list=x86_64-softmmu,ppc64-softmmu,aarch64-softmmu
|
|
||||||
TEST_TARGETS: check
|
|
||||||
|
|
||||||
x86-openbsd:
|
|
||||||
extends: .cirrus_kvm_job
|
|
||||||
variables:
|
|
||||||
NAME: openbsd
|
|
||||||
CONFIGURE_ARGS: --target-list=i386-softmmu,riscv64-softmmu,mips64-softmmu
|
|
||||||
TEST_TARGETS: check
|
|
||||||
|
@ -13,7 +13,6 @@ env:
|
|||||||
PYTHON: "@PYTHON@"
|
PYTHON: "@PYTHON@"
|
||||||
MAKE: "@MAKE@"
|
MAKE: "@MAKE@"
|
||||||
CONFIGURE_ARGS: "@CONFIGURE_ARGS@"
|
CONFIGURE_ARGS: "@CONFIGURE_ARGS@"
|
||||||
TEST_TARGETS: "@TEST_TARGETS@"
|
|
||||||
|
|
||||||
build_task:
|
build_task:
|
||||||
install_script:
|
install_script:
|
||||||
@ -32,6 +31,5 @@ build_task:
|
|||||||
- $MAKE -j$(sysctl -n hw.ncpu)
|
- $MAKE -j$(sysctl -n hw.ncpu)
|
||||||
- for TARGET in $TEST_TARGETS ;
|
- for TARGET in $TEST_TARGETS ;
|
||||||
do
|
do
|
||||||
$MAKE -j$(sysctl -n hw.ncpu) $TARGET V=1
|
$MAKE -j$(sysctl -n hw.ncpu) $TARGET V=1 ;
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
done
|
done
|
||||||
|
@ -2,15 +2,12 @@
|
|||||||
#
|
#
|
||||||
# $ lcitool variables freebsd-12 qemu
|
# $ lcitool variables freebsd-12 qemu
|
||||||
#
|
#
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
|
||||||
|
|
||||||
|
PACKAGING_COMMAND='pkg'
|
||||||
CCACHE='/usr/local/bin/ccache'
|
CCACHE='/usr/local/bin/ccache'
|
||||||
CPAN_PKGS=''
|
|
||||||
CROSS_PKGS=''
|
|
||||||
MAKE='/usr/local/bin/gmake'
|
MAKE='/usr/local/bin/gmake'
|
||||||
NINJA='/usr/local/bin/ninja'
|
NINJA='/usr/local/bin/ninja'
|
||||||
PACKAGING_COMMAND='pkg'
|
|
||||||
PIP3='/usr/local/bin/pip-3.8'
|
|
||||||
PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
|
||||||
PYPI_PKGS=''
|
|
||||||
PYTHON='/usr/local/bin/python3'
|
PYTHON='/usr/local/bin/python3'
|
||||||
|
PIP3='/usr/local/bin/pip-3.8'
|
||||||
|
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||||
|
@ -2,15 +2,12 @@
|
|||||||
#
|
#
|
||||||
# $ lcitool variables freebsd-13 qemu
|
# $ lcitool variables freebsd-13 qemu
|
||||||
#
|
#
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
|
||||||
|
|
||||||
|
PACKAGING_COMMAND='pkg'
|
||||||
CCACHE='/usr/local/bin/ccache'
|
CCACHE='/usr/local/bin/ccache'
|
||||||
CPAN_PKGS=''
|
|
||||||
CROSS_PKGS=''
|
|
||||||
MAKE='/usr/local/bin/gmake'
|
MAKE='/usr/local/bin/gmake'
|
||||||
NINJA='/usr/local/bin/ninja'
|
NINJA='/usr/local/bin/ninja'
|
||||||
PACKAGING_COMMAND='pkg'
|
|
||||||
PIP3='/usr/local/bin/pip-3.8'
|
|
||||||
PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson ncurses nettle ninja opencv perl5 pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
|
||||||
PYPI_PKGS=''
|
|
||||||
PYTHON='/usr/local/bin/python3'
|
PYTHON='/usr/local/bin/python3'
|
||||||
|
PIP3='/usr/local/bin/pip-3.8'
|
||||||
|
PKGS='alsa-lib bash bzip2 ca_root_nss capstone4 ccache cdrkit-genisoimage ctags curl cyrus-sasl dbus diffutils gettext git glib gmake gnutls gsed gtk3 libepoxy libffi libgcrypt libjpeg-turbo libnfs libspice-server libssh libtasn1 libxml2 llvm lttng-ust lzo2 meson ncurses nettle ninja opencv p5-Test-Harness perl5 pixman pkgconf png py38-numpy py38-pillow py38-pip py38-sphinx py38-sphinx_rtd_theme py38-virtualenv py38-yaml python3 rpm2cpio sdl2 sdl2_image snappy spice-protocol tesseract texinfo usbredir virglrenderer vte3 zstd'
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
container:
|
|
||||||
image: fedora:35
|
|
||||||
cpu: 4
|
|
||||||
memory: 8Gb
|
|
||||||
kvm: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
CIRRUS_CLONE_DEPTH: 1
|
|
||||||
CI_REPOSITORY_URL: "@CI_REPOSITORY_URL@"
|
|
||||||
CI_COMMIT_REF_NAME: "@CI_COMMIT_REF_NAME@"
|
|
||||||
CI_COMMIT_SHA: "@CI_COMMIT_SHA@"
|
|
||||||
|
|
||||||
@NAME@_task:
|
|
||||||
@NAME@_vm_cache:
|
|
||||||
folder: $HOME/.cache/qemu-vm
|
|
||||||
install_script:
|
|
||||||
- dnf update -y
|
|
||||||
- dnf install -y git make openssh-clients qemu-img qemu-system-x86 wget
|
|
||||||
clone_script:
|
|
||||||
- git clone --depth 100 "$CI_REPOSITORY_URL" .
|
|
||||||
- git fetch origin "$CI_COMMIT_REF_NAME"
|
|
||||||
- git reset --hard "$CI_COMMIT_SHA"
|
|
||||||
build_script:
|
|
||||||
- if [ -f $HOME/.cache/qemu-vm/images/@NAME@.img ]; then
|
|
||||||
make vm-build-@NAME@ J=$(getconf _NPROCESSORS_ONLN)
|
|
||||||
EXTRA_CONFIGURE_OPTS="@CONFIGURE_ARGS@"
|
|
||||||
BUILD_TARGET="@TEST_TARGETS@" ;
|
|
||||||
else
|
|
||||||
make vm-build-@NAME@ J=$(getconf _NPROCESSORS_ONLN) BUILD_TARGET=help
|
|
||||||
EXTRA_CONFIGURE_OPTS="--disable-system --disable-user --disable-tools" ;
|
|
||||||
fi
|
|
15
.gitlab-ci.d/cirrus/macos-11.vars
Normal file
15
.gitlab-ci.d/cirrus/macos-11.vars
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# THIS FILE WAS AUTO-GENERATED
|
||||||
|
#
|
||||||
|
# $ lcitool variables macos-11 qemu
|
||||||
|
#
|
||||||
|
# https://gitlab.com/libvirt/libvirt-ci/-/commit/c7e275ab27ac0dcd09da290817b9adeea1fd1eb1
|
||||||
|
|
||||||
|
PACKAGING_COMMAND='brew'
|
||||||
|
CCACHE='/usr/local/bin/ccache'
|
||||||
|
MAKE='/usr/local/bin/gmake'
|
||||||
|
NINJA='/usr/local/bin/ninja'
|
||||||
|
PYTHON='/usr/local/bin/python3'
|
||||||
|
PIP3='/usr/local/bin/pip3'
|
||||||
|
PKGS='bash bc bzip2 capstone ccache cpanminus ctags curl dbus diffutils gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb libxml2 llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd'
|
||||||
|
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme virtualenv'
|
||||||
|
CPAN_PKGS='Test::Harness'
|
@ -1,16 +0,0 @@
|
|||||||
# THIS FILE WAS AUTO-GENERATED
|
|
||||||
#
|
|
||||||
# $ lcitool variables macos-12 qemu
|
|
||||||
#
|
|
||||||
# https://gitlab.com/libvirt/libvirt-ci
|
|
||||||
|
|
||||||
CCACHE='/opt/homebrew/bin/ccache'
|
|
||||||
CPAN_PKGS=''
|
|
||||||
CROSS_PKGS=''
|
|
||||||
MAKE='/opt/homebrew/bin/gmake'
|
|
||||||
NINJA='/opt/homebrew/bin/ninja'
|
|
||||||
PACKAGING_COMMAND='brew'
|
|
||||||
PIP3='/opt/homebrew/bin/pip3'
|
|
||||||
PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson ncurses nettle ninja perl pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy sparse spice-protocol tesseract texinfo usbredir vde vte3 zlib zstd'
|
|
||||||
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme'
|
|
||||||
PYTHON='/opt/homebrew/bin/python3'
|
|
@ -10,3 +10,8 @@ amd64-fedora-container:
|
|||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
variables:
|
variables:
|
||||||
NAME: fedora
|
NAME: fedora
|
||||||
|
|
||||||
|
amd64-debian10-container:
|
||||||
|
extends: .container_job_template
|
||||||
|
variables:
|
||||||
|
NAME: debian10
|
||||||
|
@ -1,49 +1,64 @@
|
|||||||
alpha-debian-cross-container:
|
alpha-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-alpha-cross
|
NAME: debian-alpha-cross
|
||||||
|
|
||||||
amd64-debian-cross-container:
|
amd64-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-amd64-cross
|
NAME: debian-amd64-cross
|
||||||
|
|
||||||
amd64-debian-user-cross-container:
|
amd64-debian-user-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-all-test-cross
|
NAME: debian-all-test-cross
|
||||||
|
|
||||||
arm64-debian-cross-container:
|
arm64-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-arm64-cross
|
NAME: debian-arm64-cross
|
||||||
|
|
||||||
|
arm64-test-debian-cross-container:
|
||||||
|
extends: .container_job_template
|
||||||
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian11-container']
|
||||||
|
variables:
|
||||||
|
NAME: debian-arm64-test-cross
|
||||||
|
|
||||||
armel-debian-cross-container:
|
armel-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-armel-cross
|
NAME: debian-armel-cross
|
||||||
|
|
||||||
armhf-debian-cross-container:
|
armhf-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-armhf-cross
|
NAME: debian-armhf-cross
|
||||||
|
|
||||||
# We never want to build hexagon in the CI system and by default we
|
# We never want to build hexagon in the CI system and by default we
|
||||||
# always want to refer to the master registry where it lives.
|
# always want to refer to the master registry where it lives.
|
||||||
hexagon-cross-container:
|
hexagon-cross-container:
|
||||||
extends: .base_job_template
|
|
||||||
image: docker:stable
|
image: docker:stable
|
||||||
stage: containers
|
stage: containers
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"'
|
||||||
|
when: never
|
||||||
|
- when: always
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-hexagon-cross
|
NAME: debian-hexagon-cross
|
||||||
GIT_DEPTH: 1
|
GIT_DEPTH: 1
|
||||||
QEMU_JOB_ONLY_FORKS: 1
|
|
||||||
services:
|
services:
|
||||||
- docker:dind
|
- docker:dind
|
||||||
before_script:
|
before_script:
|
||||||
@ -62,88 +77,92 @@ hexagon-cross-container:
|
|||||||
|
|
||||||
hppa-debian-cross-container:
|
hppa-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-hppa-cross
|
NAME: debian-hppa-cross
|
||||||
|
|
||||||
m68k-debian-cross-container:
|
m68k-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-m68k-cross
|
NAME: debian-m68k-cross
|
||||||
|
|
||||||
mips64-debian-cross-container:
|
mips64-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-mips64-cross
|
NAME: debian-mips64-cross
|
||||||
|
|
||||||
mips64el-debian-cross-container:
|
mips64el-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-mips64el-cross
|
NAME: debian-mips64el-cross
|
||||||
|
|
||||||
mips-debian-cross-container:
|
mips-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-mips-cross
|
NAME: debian-mips-cross
|
||||||
|
|
||||||
mipsel-debian-cross-container:
|
mipsel-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-mipsel-cross
|
NAME: debian-mipsel-cross
|
||||||
|
|
||||||
powerpc-test-cross-container:
|
powerpc-test-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian11-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-powerpc-test-cross
|
NAME: debian-powerpc-test-cross
|
||||||
|
|
||||||
ppc64el-debian-cross-container:
|
ppc64el-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-ppc64el-cross
|
NAME: debian-ppc64el-cross
|
||||||
|
|
||||||
riscv64-debian-cross-container:
|
riscv64-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
# as we are currently based on 'sid/unstable' we may break so...
|
needs: ['amd64-debian10-container']
|
||||||
allow_failure: true
|
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-riscv64-cross
|
NAME: debian-riscv64-cross
|
||||||
|
|
||||||
# we can however build TCG tests using a non-sid base
|
|
||||||
riscv64-debian-test-cross-container:
|
|
||||||
extends: .container_job_template
|
|
||||||
stage: containers
|
|
||||||
variables:
|
|
||||||
NAME: debian-riscv64-test-cross
|
|
||||||
|
|
||||||
s390x-debian-cross-container:
|
s390x-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-s390x-cross
|
NAME: debian-s390x-cross
|
||||||
|
|
||||||
sh4-debian-cross-container:
|
sh4-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-sh4-cross
|
NAME: debian-sh4-cross
|
||||||
|
|
||||||
sparc64-debian-cross-container:
|
sparc64-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-sparc64-cross
|
NAME: debian-sparc64-cross
|
||||||
|
|
||||||
tricore-debian-cross-container:
|
tricore-debian-cross-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-tricore-cross
|
NAME: debian-tricore-cross
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
.container_job_template:
|
.container_job_template:
|
||||||
extends: .base_job_template
|
|
||||||
image: docker:stable
|
image: docker:stable
|
||||||
stage: containers
|
stage: containers
|
||||||
services:
|
services:
|
||||||
|
@ -7,17 +7,33 @@ amd64-alpine-container:
|
|||||||
variables:
|
variables:
|
||||||
NAME: alpine
|
NAME: alpine
|
||||||
|
|
||||||
|
amd64-debian11-container:
|
||||||
|
extends: .container_job_template
|
||||||
|
variables:
|
||||||
|
NAME: debian11
|
||||||
|
|
||||||
amd64-debian-container:
|
amd64-debian-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
stage: containers
|
stage: containers-layer2
|
||||||
|
needs: ['amd64-debian10-container']
|
||||||
variables:
|
variables:
|
||||||
NAME: debian-amd64
|
NAME: debian-amd64
|
||||||
|
|
||||||
|
amd64-ubuntu1804-container:
|
||||||
|
extends: .container_job_template
|
||||||
|
variables:
|
||||||
|
NAME: ubuntu1804
|
||||||
|
|
||||||
amd64-ubuntu2004-container:
|
amd64-ubuntu2004-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
variables:
|
variables:
|
||||||
NAME: ubuntu2004
|
NAME: ubuntu2004
|
||||||
|
|
||||||
|
amd64-ubuntu-container:
|
||||||
|
extends: .container_job_template
|
||||||
|
variables:
|
||||||
|
NAME: ubuntu
|
||||||
|
|
||||||
amd64-opensuse-leap-container:
|
amd64-opensuse-leap-container:
|
||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
variables:
|
variables:
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
.cross_system_build_job:
|
.cross_system_build_job:
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
stage: build
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||||
timeout: 80m
|
timeout: 80m
|
||||||
@ -15,7 +14,7 @@
|
|||||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||||
- if grep -q "EXESUF=.exe" config-host.mak;
|
- if grep -q "EXESUF=.exe" config-host.mak;
|
||||||
then make installer;
|
then make installer;
|
||||||
version="$(git describe --match v[0-9]* 2>/dev/null || git rev-parse --short HEAD)";
|
version="$(git describe --match v[0-9]*)";
|
||||||
mv -v qemu-setup*.exe qemu-setup-${version}.exe;
|
mv -v qemu-setup*.exe qemu-setup-${version}.exe;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -25,7 +24,6 @@
|
|||||||
# KVM), and set extra options (such disabling other accelerators) via the
|
# KVM), and set extra options (such disabling other accelerators) via the
|
||||||
# $EXTRA_CONFIGURE_OPTS variable.
|
# $EXTRA_CONFIGURE_OPTS variable.
|
||||||
.cross_accel_build_job:
|
.cross_accel_build_job:
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
stage: build
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||||
timeout: 30m
|
timeout: 30m
|
||||||
@ -38,7 +36,6 @@
|
|||||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||||
|
|
||||||
.cross_user_build_job:
|
.cross_user_build_job:
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
stage: build
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||||
script:
|
script:
|
||||||
@ -46,8 +43,5 @@
|
|||||||
- cd build
|
- cd build
|
||||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||||
--disable-system --target-list-exclude="aarch64_be-linux-user
|
--disable-system
|
||||||
alpha-linux-user cris-linux-user m68k-linux-user microblazeel-linux-user
|
|
||||||
nios2-linux-user or1k-linux-user ppc-linux-user sparc-linux-user
|
|
||||||
xtensa-linux-user $CROSS_SKIP_TARGETS"
|
|
||||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||||
|
@ -62,14 +62,26 @@ cross-i386-user:
|
|||||||
cross-i386-tci:
|
cross-i386-tci:
|
||||||
extends: .cross_accel_build_job
|
extends: .cross_accel_build_job
|
||||||
timeout: 60m
|
timeout: 60m
|
||||||
needs:
|
|
||||||
job: i386-fedora-cross-container
|
|
||||||
variables:
|
variables:
|
||||||
IMAGE: fedora-i386-cross
|
IMAGE: fedora-i386-cross
|
||||||
ACCEL: tcg-interpreter
|
ACCEL: tcg-interpreter
|
||||||
EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user
|
EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user
|
||||||
MAKE_CHECK_ARGS: check check-tcg
|
MAKE_CHECK_ARGS: check check-tcg
|
||||||
|
|
||||||
|
cross-mips-system:
|
||||||
|
extends: .cross_system_build_job
|
||||||
|
needs:
|
||||||
|
job: mips-debian-cross-container
|
||||||
|
variables:
|
||||||
|
IMAGE: debian-mips-cross
|
||||||
|
|
||||||
|
cross-mips-user:
|
||||||
|
extends: .cross_user_build_job
|
||||||
|
needs:
|
||||||
|
job: mips-debian-cross-container
|
||||||
|
variables:
|
||||||
|
IMAGE: debian-mips-cross
|
||||||
|
|
||||||
cross-mipsel-system:
|
cross-mipsel-system:
|
||||||
extends: .cross_system_build_job
|
extends: .cross_system_build_job
|
||||||
needs:
|
needs:
|
||||||
@ -112,25 +124,6 @@ cross-ppc64el-user:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE: debian-ppc64el-cross
|
IMAGE: debian-ppc64el-cross
|
||||||
|
|
||||||
# The riscv64 cross-builds currently use a 'sid' container to get
|
|
||||||
# compilers and libraries. Until something more stable is found we
|
|
||||||
# allow_failure so as not to block CI.
|
|
||||||
cross-riscv64-system:
|
|
||||||
extends: .cross_system_build_job
|
|
||||||
allow_failure: true
|
|
||||||
needs:
|
|
||||||
job: riscv64-debian-cross-container
|
|
||||||
variables:
|
|
||||||
IMAGE: debian-riscv64-cross
|
|
||||||
|
|
||||||
cross-riscv64-user:
|
|
||||||
extends: .cross_user_build_job
|
|
||||||
allow_failure: true
|
|
||||||
needs:
|
|
||||||
job: riscv64-debian-cross-container
|
|
||||||
variables:
|
|
||||||
IMAGE: debian-riscv64-cross
|
|
||||||
|
|
||||||
cross-s390x-system:
|
cross-s390x-system:
|
||||||
extends: .cross_system_build_job
|
extends: .cross_system_build_job
|
||||||
needs:
|
needs:
|
||||||
|
@ -13,8 +13,226 @@
|
|||||||
variables:
|
variables:
|
||||||
GIT_STRATEGY: clone
|
GIT_STRATEGY: clone
|
||||||
|
|
||||||
include:
|
# All ubuntu-18.04 jobs should run successfully in an environment
|
||||||
- local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-s390x.yml'
|
# setup by the scripts/ci/setup/build-environment.yml task
|
||||||
- local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml'
|
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||||
- local: '/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml'
|
ubuntu-18.04-s390x-all-linux-static:
|
||||||
- local: '/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml'
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||||
|
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
- make --output-sync -j`nproc` check-tcg V=1
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-all:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-alldbg:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --enable-debug --disable-libssh
|
||||||
|
- make clean
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-clang:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-tci:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
|
||||||
|
ubuntu-18.04-s390x-notcg:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_18.04
|
||||||
|
- s390x
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --disable-tcg
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
# All ubuntu-20.04 jobs should run successfully in an environment
|
||||||
|
# setup by the scripts/ci/setup/qemu/build-environment.yml task
|
||||||
|
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
|
||||||
|
ubuntu-20.04-aarch64-all-linux-static:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
||||||
|
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
- make --output-sync -j`nproc` check-tcg V=1
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-all:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-alldbg:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --enable-debug --disable-libssh
|
||||||
|
- make clean
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-clang:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-tci:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --enable-tcg-interpreter
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
|
||||||
|
ubuntu-20.04-aarch64-notcg:
|
||||||
|
allow_failure: true
|
||||||
|
needs: []
|
||||||
|
stage: build
|
||||||
|
tags:
|
||||||
|
- ubuntu_20.04
|
||||||
|
- aarch64
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||||
|
when: manual
|
||||||
|
- if: "$S390X_RUNNER_AVAILABLE"
|
||||||
|
when: manual
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- ../configure --disable-libssh --disable-tcg
|
||||||
|
- make --output-sync -j`nproc`
|
||||||
|
- make --output-sync -j`nproc` check V=1
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
centos-stream-8-x86_64:
|
|
||||||
allow_failure: true
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- centos_stream_8
|
|
||||||
- x86_64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- 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:
|
|
||||||
- JOBS=$(expr $(nproc) + 1)
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../scripts/ci/org.centos/stream/8/x86_64/configure
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make -j"$JOBS"
|
|
||||||
- make NINJA=":" check
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
- ../scripts/ci/org.centos/stream/8/x86_64/test-avocado
|
|
@ -1,131 +0,0 @@
|
|||||||
# All ubuntu-20.04 jobs should run successfully in an environment
|
|
||||||
# setup by the scripts/ci/setup/build-environment.yml task
|
|
||||||
# "Install basic packages to build QEMU on Ubuntu 20.04/20.04"
|
|
||||||
|
|
||||||
ubuntu-20.04-s390x-all-linux-static:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
script:
|
|
||||||
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
|
|
||||||
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
- make --output-sync -j`nproc` check-tcg V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
|
|
||||||
ubuntu-20.04-s390x-all:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- s390x
|
|
||||||
timeout: 75m
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
|
|
||||||
ubuntu-20.04-s390x-alldbg:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --enable-debug --disable-libssh
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make clean
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
|
|
||||||
ubuntu-20.04-s390x-clang:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
|
|
||||||
ubuntu-20.04-s390x-tci:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --enable-tcg-interpreter
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
|
|
||||||
ubuntu-20.04-s390x-notcg:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_20.04
|
|
||||||
- s390x
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$S390X_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --disable-tcg
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc`
|
|
||||||
- make --output-sync -j`nproc` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
@ -1,25 +0,0 @@
|
|||||||
# All ubuntu-22.04 jobs should run successfully in an environment
|
|
||||||
# setup by the scripts/ci/setup/qemu/build-environment.yml task
|
|
||||||
# "Install basic packages to build QEMU on Ubuntu 20.04"
|
|
||||||
|
|
||||||
ubuntu-22.04-aarch32-all:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_22.04
|
|
||||||
- aarch32
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH32_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --cross-prefix=arm-linux-gnueabihf-
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc --ignore=40`
|
|
||||||
- make --output-sync -j`nproc --ignore=40` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
@ -1,130 +0,0 @@
|
|||||||
# All ubuntu-20.04 jobs should run successfully in an environment
|
|
||||||
# setup by the scripts/ci/setup/qemu/build-environment.yml task
|
|
||||||
# "Install basic packages to build QEMU on Ubuntu 20.04"
|
|
||||||
|
|
||||||
ubuntu-22.04-aarch64-all-linux-static:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_22.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
# Disable -static-pie due to build error with system libc:
|
|
||||||
# https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1987438
|
|
||||||
- ../configure --enable-debug --static --disable-system --disable-pie
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc --ignore=40`
|
|
||||||
- make --output-sync -j`nproc --ignore=40` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
- make --output-sync -j`nproc --ignore=40` check-tcg V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
|
|
||||||
ubuntu-22.04-aarch64-all:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_22.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc --ignore=40`
|
|
||||||
- make --output-sync -j`nproc --ignore=40` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
|
|
||||||
ubuntu-22.04-aarch64-alldbg:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_22.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --enable-debug
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make clean
|
|
||||||
- make --output-sync -j`nproc --ignore=40`
|
|
||||||
- make --output-sync -j`nproc --ignore=40` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
|
|
||||||
ubuntu-22.04-aarch64-clang:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_22.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc --ignore=40`
|
|
||||||
- make --output-sync -j`nproc --ignore=40` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
||||||
|
|
||||||
ubuntu-22.04-aarch64-tci:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_22.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --enable-tcg-interpreter
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc --ignore=40`
|
|
||||||
|
|
||||||
ubuntu-22.04-aarch64-notcg:
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
tags:
|
|
||||||
- ubuntu_22.04
|
|
||||||
- aarch64
|
|
||||||
rules:
|
|
||||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
|
||||||
when: manual
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- mkdir build
|
|
||||||
- cd build
|
|
||||||
- ../configure --disable-tcg
|
|
||||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
|
||||||
- make --output-sync -j`nproc --ignore=40`
|
|
||||||
- make --output-sync -j`nproc --ignore=40` check V=1
|
|
||||||
|| { cat meson-logs/testlog.txt; exit 1; } ;
|
|
@ -1,85 +1,56 @@
|
|||||||
# All jobs needing docker-edk2 must use the same rules it uses.
|
# All jobs needing docker-edk2 must use the same rules it uses.
|
||||||
.edk2_job_rules:
|
.edk2_job_rules:
|
||||||
rules:
|
rules: # Only run this job when ...
|
||||||
# Forks don't get pipelines unless QEMU_CI=1 or QEMU_CI=2 is set
|
- changes:
|
||||||
- if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
# this file is modified
|
||||||
when: never
|
- .gitlab-ci.d/edk2.yml
|
||||||
|
# or the Dockerfile is modified
|
||||||
# In forks, if QEMU_CI=1 is set, then create manual job
|
- .gitlab-ci.d/edk2/Dockerfile
|
||||||
# if any of the files affecting the build are touched
|
# or roms/edk2/ is modified (submodule updated)
|
||||||
- if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
- roms/edk2/*
|
||||||
changes:
|
when: on_success
|
||||||
- .gitlab-ci.d/edk2.yml
|
- if: '$CI_COMMIT_REF_NAME =~ /^edk2/' # or the branch/tag starts with 'edk2'
|
||||||
- .gitlab-ci.d/edk2/Dockerfile
|
when: on_success
|
||||||
- roms/edk2/*
|
- if: '$CI_COMMIT_MESSAGE =~ /edk2/i' # or last commit description contains 'EDK2'
|
||||||
when: manual
|
when: on_success
|
||||||
|
|
||||||
# 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:
|
docker-edk2:
|
||||||
extends: .edk2_job_rules
|
extends: .edk2_job_rules
|
||||||
stage: containers
|
stage: containers
|
||||||
image: docker:19.03.1
|
image: docker:19.03.1
|
||||||
services:
|
services:
|
||||||
- docker:19.03.1-dind
|
- docker:19.03.1-dind
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: 3
|
GIT_DEPTH: 3
|
||||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:edk2-cross-build
|
IMAGE_TAG: $CI_REGISTRY_IMAGE:edk2-cross-build
|
||||||
# We don't use TLS
|
# We don't use TLS
|
||||||
DOCKER_HOST: tcp://docker:2375
|
DOCKER_HOST: tcp://docker:2375
|
||||||
DOCKER_TLS_CERTDIR: ""
|
DOCKER_TLS_CERTDIR: ""
|
||||||
before_script:
|
before_script:
|
||||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
script:
|
script:
|
||||||
- docker pull $IMAGE_TAG || true
|
- docker pull $IMAGE_TAG || true
|
||||||
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||||
--tag $IMAGE_TAG .gitlab-ci.d/edk2
|
--tag $IMAGE_TAG .gitlab-ci.d/edk2
|
||||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||||
- docker push $IMAGE_TAG
|
- docker push $IMAGE_TAG
|
||||||
|
|
||||||
build-edk2:
|
build-edk2:
|
||||||
extends: .edk2_job_rules
|
extends: .edk2_job_rules
|
||||||
stage: build
|
stage: build
|
||||||
needs: ['docker-edk2']
|
needs: ['docker-edk2']
|
||||||
artifacts:
|
artifacts:
|
||||||
paths: # 'artifacts.zip' will contains the following files:
|
paths: # 'artifacts.zip' will contains the following files:
|
||||||
- pc-bios/edk2*bz2
|
- pc-bios/edk2*bz2
|
||||||
- pc-bios/edk2-licenses.txt
|
- pc-bios/edk2-licenses.txt
|
||||||
- edk2-stdout.log
|
- edk2-stdout.log
|
||||||
- edk2-stderr.log
|
- edk2-stderr.log
|
||||||
image: $CI_REGISTRY_IMAGE:edk2-cross-build
|
image: $CI_REGISTRY_IMAGE:edk2-cross-build
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: 3
|
GIT_DEPTH: 3
|
||||||
script: # Clone the required submodules and build EDK2
|
script: # Clone the required submodules and build EDK2
|
||||||
- git submodule update --init roms/edk2
|
- git submodule update --init roms/edk2
|
||||||
- git -C roms/edk2 submodule update --init --
|
- git -C roms/edk2 submodule update --init
|
||||||
ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
|
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||||
BaseTools/Source/C/BrotliCompress/brotli
|
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||||
CryptoPkg/Library/OpensslLib/openssl
|
- make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2
|
||||||
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
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#
|
#
|
||||||
# Docker image to cross-compile EDK2 firmware binaries
|
# Docker image to cross-compile EDK2 firmware binaries
|
||||||
#
|
#
|
||||||
FROM ubuntu:18.04
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
|
MAINTAINER Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||||
|
|
||||||
# Install packages required to build EDK2
|
# Install packages required to build EDK2
|
||||||
RUN apt update \
|
RUN apt update \
|
||||||
@ -20,7 +20,7 @@ RUN apt update \
|
|||||||
iasl \
|
iasl \
|
||||||
make \
|
make \
|
||||||
nasm \
|
nasm \
|
||||||
python3 \
|
python \
|
||||||
uuid-dev \
|
uuid-dev \
|
||||||
&& \
|
&& \
|
||||||
\
|
\
|
||||||
|
@ -1,85 +1,63 @@
|
|||||||
# All jobs needing docker-opensbi must use the same rules it uses.
|
# All jobs needing docker-opensbi must use the same rules it uses.
|
||||||
.opensbi_job_rules:
|
.opensbi_job_rules:
|
||||||
rules:
|
rules: # Only run this job when ...
|
||||||
# Forks don't get pipelines unless QEMU_CI=1 or QEMU_CI=2 is set
|
- changes:
|
||||||
- if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
# this file is modified
|
||||||
when: never
|
- .gitlab-ci.d/opensbi.yml
|
||||||
|
# or the Dockerfile is modified
|
||||||
# In forks, if QEMU_CI=1 is set, then create manual job
|
- .gitlab-ci.d/opensbi/Dockerfile
|
||||||
# if any files affecting the build output are touched
|
when: on_success
|
||||||
- if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project"'
|
- changes: # or roms/opensbi/ is modified (submodule updated)
|
||||||
changes:
|
- roms/opensbi/*
|
||||||
- .gitlab-ci.d/opensbi.yml
|
when: on_success
|
||||||
- .gitlab-ci.d/opensbi/Dockerfile
|
- if: '$CI_COMMIT_REF_NAME =~ /^opensbi/' # or the branch/tag starts with 'opensbi'
|
||||||
- roms/opensbi/*
|
when: on_success
|
||||||
when: manual
|
- if: '$CI_COMMIT_MESSAGE =~ /opensbi/i' # or last commit description contains 'OpenSBI'
|
||||||
|
when: on_success
|
||||||
# In forks, if QEMU_CI=1 is set, then create manual job
|
|
||||||
# if the branch/tag starts with 'opensbi'
|
|
||||||
- if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project" && $CI_COMMIT_REF_NAME =~ /^opensbi/'
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
# In forks, if QEMU_CI=1 is set, then create manual job
|
|
||||||
# if the last commit msg contains 'OpenSBI' (case insensitive)
|
|
||||||
- if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE != "qemu-project" && $CI_COMMIT_MESSAGE =~ /opensbi/i'
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
# Run if any files affecting the build output are touched
|
|
||||||
- changes:
|
|
||||||
- .gitlab-ci.d/opensbi.yml
|
|
||||||
- .gitlab-ci.d/opensbi/Dockerfile
|
|
||||||
- roms/opensbi/*
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
# Run if the branch/tag starts with 'opensbi'
|
|
||||||
- if: '$CI_COMMIT_REF_NAME =~ /^opensbi/'
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
# Run if the last commit msg contains 'OpenSBI' (case insensitive)
|
|
||||||
- if: '$CI_COMMIT_MESSAGE =~ /opensbi/i'
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
docker-opensbi:
|
docker-opensbi:
|
||||||
extends: .opensbi_job_rules
|
extends: .opensbi_job_rules
|
||||||
stage: containers
|
stage: containers
|
||||||
image: docker:19.03.1
|
image: docker:19.03.1
|
||||||
services:
|
services:
|
||||||
- docker:19.03.1-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
|
||||||
# We don't use TLS
|
# We don't use TLS
|
||||||
DOCKER_HOST: tcp://docker:2375
|
DOCKER_HOST: tcp://docker:2375
|
||||||
DOCKER_TLS_CERTDIR: ""
|
DOCKER_TLS_CERTDIR: ""
|
||||||
before_script:
|
before_script:
|
||||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
script:
|
script:
|
||||||
- docker pull $IMAGE_TAG || true
|
- docker pull $IMAGE_TAG || true
|
||||||
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
- docker build --cache-from $IMAGE_TAG --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||||
--tag $IMAGE_TAG .gitlab-ci.d/opensbi
|
--tag $IMAGE_TAG .gitlab-ci.d/opensbi
|
||||||
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||||
- docker push $IMAGE_TAG
|
- docker push $IMAGE_TAG
|
||||||
|
|
||||||
build-opensbi:
|
build-opensbi:
|
||||||
extends: .opensbi_job_rules
|
extends: .opensbi_job_rules
|
||||||
stage: build
|
stage: build
|
||||||
needs: ['docker-opensbi']
|
needs: ['docker-opensbi']
|
||||||
artifacts:
|
artifacts:
|
||||||
paths: # 'artifacts.zip' will contains the following files:
|
paths: # 'artifacts.zip' will contains the following files:
|
||||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
||||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
- pc-bios/opensbi-riscv32-generic-fw_dynamic.elf
|
||||||
- opensbi32-generic-stdout.log
|
- pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
||||||
- opensbi32-generic-stderr.log
|
- pc-bios/opensbi-riscv64-generic-fw_dynamic.elf
|
||||||
- opensbi64-generic-stdout.log
|
- opensbi32-generic-stdout.log
|
||||||
- opensbi64-generic-stderr.log
|
- opensbi32-generic-stderr.log
|
||||||
image: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
- opensbi64-generic-stdout.log
|
||||||
variables:
|
- opensbi64-generic-stderr.log
|
||||||
GIT_DEPTH: 3
|
image: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
||||||
script: # Clone the required submodules and build OpenSBI
|
variables:
|
||||||
- git submodule update --init roms/opensbi
|
GIT_DEPTH: 3
|
||||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
script: # Clone the required submodules and build OpenSBI
|
||||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
- git submodule update --init roms/opensbi
|
||||||
- make -j${JOBS} -C roms/opensbi clean
|
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||||
- make -j${JOBS} -C roms opensbi32-generic 2>&1 1>opensbi32-generic-stdout.log | tee -a opensbi32-generic-stderr.log >&2
|
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||||
- make -j${JOBS} -C roms/opensbi clean
|
- make -j${JOBS} -C roms/opensbi clean
|
||||||
- make -j${JOBS} -C roms opensbi64-generic 2>&1 1>opensbi64-generic-stdout.log | tee -a opensbi64-generic-stderr.log >&2
|
- make -j${JOBS} -C roms opensbi32-generic 2>&1 1>opensbi32-generic-stdout.log | tee -a opensbi32-generic-stderr.log >&2
|
||||||
|
- make -j${JOBS} -C roms/opensbi clean
|
||||||
|
- make -j${JOBS} -C roms opensbi64-generic 2>&1 1>opensbi64-generic-stdout.log | tee -a opensbi64-generic-stderr.log >&2
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
# https://gitlab.com/qemu-project/qemu/-/pipelines
|
# https://gitlab.com/qemu-project/qemu/-/pipelines
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- 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/edk2.yml'
|
||||||
- local: '/.gitlab-ci.d/opensbi.yml'
|
- local: '/.gitlab-ci.d/opensbi.yml'
|
||||||
@ -12,4 +11,3 @@ include:
|
|||||||
- local: '/.gitlab-ci.d/static_checks.yml'
|
- local: '/.gitlab-ci.d/static_checks.yml'
|
||||||
- local: '/.gitlab-ci.d/custom-runners.yml'
|
- local: '/.gitlab-ci.d/custom-runners.yml'
|
||||||
- local: '/.gitlab-ci.d/cirrus.yml'
|
- local: '/.gitlab-ci.d/cirrus.yml'
|
||||||
- local: '/.gitlab-ci.d/windows.yml'
|
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
# - test (for test stages, using build artefacts from a build stage)
|
# - test (for test stages, using build artefacts from a build stage)
|
||||||
stages:
|
stages:
|
||||||
- containers
|
- containers
|
||||||
|
- containers-layer2
|
||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
|
@ -1,30 +1,32 @@
|
|||||||
check-patch:
|
check-patch:
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
stage: build
|
||||||
image: python:3.10-alpine
|
image: $CI_REGISTRY_IMAGE/qemu/centos8:latest
|
||||||
needs: []
|
needs:
|
||||||
|
job: amd64-centos8-container
|
||||||
script:
|
script:
|
||||||
- .gitlab-ci.d/check-patch.py
|
- .gitlab-ci.d/check-patch.py
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: 1000
|
GIT_DEPTH: 1000
|
||||||
QEMU_JOB_ONLY_FORKS: 1
|
rules:
|
||||||
before_script:
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||||
- apk -U add git perl
|
when: never
|
||||||
allow_failure: true
|
- when: on_success
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
check-dco:
|
check-dco:
|
||||||
extends: .base_job_template
|
|
||||||
stage: build
|
stage: build
|
||||||
image: python:3.10-alpine
|
image: $CI_REGISTRY_IMAGE/qemu/centos8:latest
|
||||||
needs: []
|
needs:
|
||||||
|
job: amd64-centos8-container
|
||||||
script: .gitlab-ci.d/check-dco.py
|
script: .gitlab-ci.d/check-dco.py
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: 1000
|
GIT_DEPTH: 1000
|
||||||
before_script:
|
rules:
|
||||||
- apk -U add git
|
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||||
|
when: never
|
||||||
|
- when: on_success
|
||||||
|
|
||||||
check-python-pipenv:
|
check-python-pipenv:
|
||||||
extends: .base_job_template
|
|
||||||
stage: test
|
stage: test
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/python:latest
|
image: $CI_REGISTRY_IMAGE/qemu/python:latest
|
||||||
script:
|
script:
|
||||||
@ -35,7 +37,6 @@ check-python-pipenv:
|
|||||||
job: python-container
|
job: python-container
|
||||||
|
|
||||||
check-python-tox:
|
check-python-tox:
|
||||||
extends: .base_job_template
|
|
||||||
stage: test
|
stage: test
|
||||||
image: $CI_REGISTRY_IMAGE/qemu/python:latest
|
image: $CI_REGISTRY_IMAGE/qemu/python:latest
|
||||||
script:
|
script:
|
||||||
@ -43,6 +44,6 @@ check-python-tox:
|
|||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: 1
|
GIT_DEPTH: 1
|
||||||
QEMU_TOX_EXTRA_ARGS: --skip-missing-interpreters=false
|
QEMU_TOX_EXTRA_ARGS: --skip-missing-interpreters=false
|
||||||
QEMU_JOB_OPTIONAL: 1
|
|
||||||
needs:
|
needs:
|
||||||
job: python-container
|
job: python-container
|
||||||
|
allow_failure: true
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
.shared_msys2_builder:
|
|
||||||
extends: .base_job_template
|
|
||||||
tags:
|
|
||||||
- shared-windows
|
|
||||||
- windows
|
|
||||||
- windows-1809
|
|
||||||
cache:
|
|
||||||
key: "${CI_JOB_NAME}-cache"
|
|
||||||
paths:
|
|
||||||
- ${CI_PROJECT_DIR}/msys64/var/cache
|
|
||||||
needs: []
|
|
||||||
stage: build
|
|
||||||
timeout: 70m
|
|
||||||
before_script:
|
|
||||||
- If ( !(Test-Path -Path msys64\var\cache ) ) {
|
|
||||||
mkdir msys64\var\cache
|
|
||||||
}
|
|
||||||
- If ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) {
|
|
||||||
Invoke-WebRequest
|
|
||||||
"https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-base-x86_64-20220603.sfx.exe"
|
|
||||||
-outfile "msys64\var\cache\msys2.exe"
|
|
||||||
}
|
|
||||||
- msys64\var\cache\msys2.exe -y
|
|
||||||
- ((Get-Content -path .\msys64\etc\\post-install\\07-pacman-key.post -Raw)
|
|
||||||
-replace '--refresh-keys', '--version') |
|
|
||||||
Set-Content -Path ${CI_PROJECT_DIR}\msys64\etc\\post-install\\07-pacman-key.post
|
|
||||||
- .\msys64\usr\bin\bash -lc "sed -i 's/^CheckSpace/#CheckSpace/g' /etc/pacman.conf"
|
|
||||||
- .\msys64\usr\bin\bash -lc 'pacman --noconfirm -Syuu' # Core update
|
|
||||||
- .\msys64\usr\bin\bash -lc 'pacman --noconfirm -Syuu' # Normal update
|
|
||||||
- taskkill /F /FI "MODULES eq msys-2.0.dll"
|
|
||||||
|
|
||||||
msys2-64bit:
|
|
||||||
extends: .shared_msys2_builder
|
|
||||||
script:
|
|
||||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
|
||||||
bison diffutils flex
|
|
||||||
git grep make sed
|
|
||||||
mingw-w64-x86_64-capstone
|
|
||||||
mingw-w64-x86_64-curl
|
|
||||||
mingw-w64-x86_64-cyrus-sasl
|
|
||||||
mingw-w64-x86_64-gcc
|
|
||||||
mingw-w64-x86_64-glib2
|
|
||||||
mingw-w64-x86_64-gnutls
|
|
||||||
mingw-w64-x86_64-libnfs
|
|
||||||
mingw-w64-x86_64-libpng
|
|
||||||
mingw-w64-x86_64-libssh
|
|
||||||
mingw-w64-x86_64-libtasn1
|
|
||||||
mingw-w64-x86_64-libusb
|
|
||||||
mingw-w64-x86_64-nettle
|
|
||||||
mingw-w64-x86_64-ninja
|
|
||||||
mingw-w64-x86_64-pixman
|
|
||||||
mingw-w64-x86_64-pkgconf
|
|
||||||
mingw-w64-x86_64-python
|
|
||||||
mingw-w64-x86_64-SDL2
|
|
||||||
mingw-w64-x86_64-SDL2_image
|
|
||||||
mingw-w64-x86_64-snappy
|
|
||||||
mingw-w64-x86_64-usbredir
|
|
||||||
mingw-w64-x86_64-zstd "
|
|
||||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
|
||||||
- $env:MSYSTEM = 'MINGW64' # Start a 64 bit Mingw environment
|
|
||||||
- $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink
|
|
||||||
- .\msys64\usr\bin\bash -lc './configure --target-list=x86_64-softmmu
|
|
||||||
--enable-capstone --without-default-devices'
|
|
||||||
- .\msys64\usr\bin\bash -lc 'make'
|
|
||||||
- .\msys64\usr\bin\bash -lc 'make check || { cat build/meson-logs/testlog.txt; exit 1; } ;'
|
|
||||||
|
|
||||||
msys2-32bit:
|
|
||||||
extends: .shared_msys2_builder
|
|
||||||
script:
|
|
||||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
|
||||||
bison diffutils flex
|
|
||||||
git grep make sed
|
|
||||||
mingw-w64-i686-capstone
|
|
||||||
mingw-w64-i686-curl
|
|
||||||
mingw-w64-i686-cyrus-sasl
|
|
||||||
mingw-w64-i686-gcc
|
|
||||||
mingw-w64-i686-glib2
|
|
||||||
mingw-w64-i686-gnutls
|
|
||||||
mingw-w64-i686-gtk3
|
|
||||||
mingw-w64-i686-libgcrypt
|
|
||||||
mingw-w64-i686-libjpeg-turbo
|
|
||||||
mingw-w64-i686-libssh
|
|
||||||
mingw-w64-i686-libtasn1
|
|
||||||
mingw-w64-i686-libusb
|
|
||||||
mingw-w64-i686-lzo2
|
|
||||||
mingw-w64-i686-ninja
|
|
||||||
mingw-w64-i686-pixman
|
|
||||||
mingw-w64-i686-pkgconf
|
|
||||||
mingw-w64-i686-python
|
|
||||||
mingw-w64-i686-snappy
|
|
||||||
mingw-w64-i686-usbredir "
|
|
||||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
|
||||||
- $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinG environment
|
|
||||||
- $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink
|
|
||||||
- mkdir output
|
|
||||||
- cd output
|
|
||||||
- ..\msys64\usr\bin\bash -lc "../configure --target-list=ppc64-softmmu"
|
|
||||||
- ..\msys64\usr\bin\bash -lc 'make'
|
|
||||||
- ..\msys64\usr\bin\bash -lc 'make check || { cat meson-logs/testlog.txt; exit 1; } ;'
|
|
12
.gitmodules
vendored
12
.gitmodules
vendored
@ -31,6 +31,9 @@
|
|||||||
[submodule "ui/keycodemapdb"]
|
[submodule "ui/keycodemapdb"]
|
||||||
path = ui/keycodemapdb
|
path = ui/keycodemapdb
|
||||||
url = https://gitlab.com/qemu-project/keycodemapdb.git
|
url = https://gitlab.com/qemu-project/keycodemapdb.git
|
||||||
|
[submodule "capstone"]
|
||||||
|
path = capstone
|
||||||
|
url = https://gitlab.com/qemu-project/capstone.git
|
||||||
[submodule "roms/seabios-hppa"]
|
[submodule "roms/seabios-hppa"]
|
||||||
path = roms/seabios-hppa
|
path = roms/seabios-hppa
|
||||||
url = https://gitlab.com/qemu-project/seabios-hppa.git
|
url = https://gitlab.com/qemu-project/seabios-hppa.git
|
||||||
@ -46,6 +49,9 @@
|
|||||||
[submodule "roms/edk2"]
|
[submodule "roms/edk2"]
|
||||||
path = roms/edk2
|
path = roms/edk2
|
||||||
url = https://gitlab.com/qemu-project/edk2.git
|
url = https://gitlab.com/qemu-project/edk2.git
|
||||||
|
[submodule "slirp"]
|
||||||
|
path = slirp
|
||||||
|
url = https://gitlab.com/qemu-project/libslirp.git
|
||||||
[submodule "roms/opensbi"]
|
[submodule "roms/opensbi"]
|
||||||
path = roms/opensbi
|
path = roms/opensbi
|
||||||
url = https://gitlab.com/qemu-project/opensbi.git
|
url = https://gitlab.com/qemu-project/opensbi.git
|
||||||
@ -58,9 +64,3 @@
|
|||||||
[submodule "roms/vbootrom"]
|
[submodule "roms/vbootrom"]
|
||||||
path = roms/vbootrom
|
path = roms/vbootrom
|
||||||
url = https://gitlab.com/qemu-project/vbootrom.git
|
url = https://gitlab.com/qemu-project/vbootrom.git
|
||||||
[submodule "tests/lcitool/libvirt-ci"]
|
|
||||||
path = tests/lcitool/libvirt-ci
|
|
||||||
url = https://gitlab.com/libvirt/libvirt-ci.git
|
|
||||||
[submodule "subprojects/libvfio-user"]
|
|
||||||
path = subprojects/libvfio-user
|
|
||||||
url = https://gitlab.com/qemu-project/libvfio-user.git
|
|
||||||
|
21
.mailmap
21
.mailmap
@ -28,11 +28,7 @@ Thiemo Seufer <ths@networkno.de> ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
|
|||||||
malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
|
malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
|
||||||
|
|
||||||
# Corrupted Author fields
|
# Corrupted Author fields
|
||||||
Aaron Larson <alarson@ddci.com> alarson@ddci.com
|
|
||||||
Andreas Färber <andreas.faerber@web.de> Andreas Färber <andreas.faerber>
|
|
||||||
Jason Wang <jasowang@redhat.com> Jason Wang <jasowang>
|
|
||||||
Marek Dolata <mkdolata@us.ibm.com> mkdolata@us.ibm.com <mkdolata@us.ibm.com>
|
Marek Dolata <mkdolata@us.ibm.com> mkdolata@us.ibm.com <mkdolata@us.ibm.com>
|
||||||
Michael Ellerman <mpe@ellerman.id.au> michael@ozlabs.org <michael@ozlabs.org>
|
|
||||||
Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com>
|
Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com>
|
||||||
|
|
||||||
# There is also a:
|
# There is also a:
|
||||||
@ -54,34 +50,25 @@ Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <arikalo@wavecomp.com>
|
|||||||
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <aleksandar.rikalo@rt-rk.com>
|
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>
|
|
||||||
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@adacore.com> <fred.konrad@greensocs.com>
|
||||||
Frederic Konrad <konrad.frederic@yahoo.fr> <konrad@adacore.com>
|
|
||||||
Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
|
Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
|
||||||
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
|
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
|
||||||
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
||||||
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
|
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
|
||||||
Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org>
|
Leif Lindholm <leif@nuviainc.com> <leif.lindholm@linaro.org>
|
||||||
Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.com>
|
|
||||||
Radoslaw Biernacki <rad@semihalf.com> <radoslaw.biernacki@linaro.org>
|
Radoslaw Biernacki <rad@semihalf.com> <radoslaw.biernacki@linaro.org>
|
||||||
Paul Brook <paul@nowt.org> <paul@codesourcery.com>
|
|
||||||
Paul Burton <paulburton@kernel.org> <paul.burton@mips.com>
|
Paul Burton <paulburton@kernel.org> <paul.burton@mips.com>
|
||||||
Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com>
|
Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com>
|
||||||
Paul Burton <paulburton@kernel.org> <paul@archlinuxmips.org>
|
Paul Burton <paulburton@kernel.org> <paul@archlinuxmips.org>
|
||||||
Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com>
|
Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com>
|
||||||
Philippe Mathieu-Daudé <philmd@linaro.org> <f4bug@amsat.org>
|
|
||||||
Philippe Mathieu-Daudé <philmd@linaro.org> <philmd@redhat.com>
|
|
||||||
Philippe Mathieu-Daudé <philmd@linaro.org> <philmd@fungible.com>
|
|
||||||
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
|
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
|
||||||
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
||||||
|
|
||||||
# Also list preferred name forms where people have changed their
|
# Also list preferred name forms where people have changed their
|
||||||
# git author config, or had utf8/latin1 encoding issues.
|
# git author config, or had utf8/latin1 encoding issues.
|
||||||
Aaron Lindsay <aaron@os.amperecomputing.com>
|
Aaron Lindsay <aaron@os.amperecomputing.com>
|
||||||
Aaron Larson <alarson@ddci.com>
|
|
||||||
Alexey Gerasimenko <x1917x@gmail.com>
|
Alexey Gerasimenko <x1917x@gmail.com>
|
||||||
Alex Chen <alex.chen@huawei.com>
|
|
||||||
Alex Ivanov <void@aleksoft.net>
|
Alex Ivanov <void@aleksoft.net>
|
||||||
Andreas Färber <afaerber@suse.de>
|
Andreas Färber <afaerber@suse.de>
|
||||||
Bandan Das <bsd@redhat.com>
|
Bandan Das <bsd@redhat.com>
|
||||||
@ -112,11 +99,9 @@ Gautham R. Shenoy <ego@in.ibm.com>
|
|||||||
Gautham R. Shenoy <ego@linux.vnet.ibm.com>
|
Gautham R. Shenoy <ego@linux.vnet.ibm.com>
|
||||||
Gonglei (Arei) <arei.gonglei@huawei.com>
|
Gonglei (Arei) <arei.gonglei@huawei.com>
|
||||||
Guang Wang <wang.guang55@zte.com.cn>
|
Guang Wang <wang.guang55@zte.com.cn>
|
||||||
Haibin Zhang <haibinzhang@tencent.com>
|
|
||||||
Hailiang Zhang <zhang.zhanghailiang@huawei.com>
|
Hailiang Zhang <zhang.zhanghailiang@huawei.com>
|
||||||
Hanna Reitz <hreitz@redhat.com> <mreitz@redhat.com>
|
Hanna Reitz <hreitz@redhat.com> <mreitz@redhat.com>
|
||||||
Hervé Poussineau <hpoussin@reactos.org>
|
Hervé Poussineau <hpoussin@reactos.org>
|
||||||
Hyman Huang <huangy81@chinatelecom.cn>
|
|
||||||
Jakub Jermář <jakub@jermar.eu>
|
Jakub Jermář <jakub@jermar.eu>
|
||||||
Jakub Jermář <jakub.jermar@kernkonzept.com>
|
Jakub Jermář <jakub.jermar@kernkonzept.com>
|
||||||
Jean-Christophe Dubois <jcd@tribudubois.net>
|
Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||||
@ -150,11 +135,9 @@ Nicholas Thomas <nick@bytemark.co.uk>
|
|||||||
Nikunj A Dadhania <nikunj@linux.vnet.ibm.com>
|
Nikunj A Dadhania <nikunj@linux.vnet.ibm.com>
|
||||||
Orit Wasserman <owasserm@redhat.com>
|
Orit Wasserman <owasserm@redhat.com>
|
||||||
Paolo Bonzini <pbonzini@redhat.com>
|
Paolo Bonzini <pbonzini@redhat.com>
|
||||||
Pan Nengyuan <pannengyuan@huawei.com>
|
|
||||||
Pavel Dovgaluk <dovgaluk@ispras.ru>
|
Pavel Dovgaluk <dovgaluk@ispras.ru>
|
||||||
Pavel Dovgaluk <pavel.dovgaluk@gmail.com>
|
Pavel Dovgaluk <pavel.dovgaluk@gmail.com>
|
||||||
Pavel Dovgaluk <Pavel.Dovgaluk@ispras.ru>
|
Pavel Dovgaluk <Pavel.Dovgaluk@ispras.ru>
|
||||||
Peter Chubb <peter.chubb@nicta.com.au>
|
|
||||||
Peter Crosthwaite <crosthwaite.peter@gmail.com>
|
Peter Crosthwaite <crosthwaite.peter@gmail.com>
|
||||||
Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
||||||
Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||||
|
37
.travis.yml
37
.travis.yml
@ -1,3 +1,6 @@
|
|||||||
|
# The current Travis default is a VM based 16.04 Xenial on GCE
|
||||||
|
# Additional builds with specific requirements for a full VM need to
|
||||||
|
# be added as additional matrix: entries later on
|
||||||
os: linux
|
os: linux
|
||||||
dist: focal
|
dist: focal
|
||||||
language: c
|
language: c
|
||||||
@ -187,7 +190,7 @@ jobs:
|
|||||||
|
|
||||||
- name: "[s390x] GCC check-tcg"
|
- name: "[s390x] GCC check-tcg"
|
||||||
arch: s390x
|
arch: s390x
|
||||||
dist: focal
|
dist: bionic
|
||||||
addons:
|
addons:
|
||||||
apt_packages:
|
apt_packages:
|
||||||
- libaio-dev
|
- libaio-dev
|
||||||
@ -222,7 +225,7 @@ jobs:
|
|||||||
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
|
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
|
||||||
- |
|
- |
|
||||||
if [ "$BUILD_RC" -eq 0 ] ; then
|
if [ "$BUILD_RC" -eq 0 ] ; then
|
||||||
mv pc-bios/s390-ccw/*.img qemu-bundle/usr/local/share/qemu ;
|
mv pc-bios/s390-ccw/*.img pc-bios/ ;
|
||||||
${TEST_CMD} ;
|
${TEST_CMD} ;
|
||||||
else
|
else
|
||||||
$(exit $BUILD_RC);
|
$(exit $BUILD_RC);
|
||||||
@ -230,7 +233,7 @@ jobs:
|
|||||||
|
|
||||||
- name: "[s390x] GCC (other-softmmu)"
|
- name: "[s390x] GCC (other-softmmu)"
|
||||||
arch: s390x
|
arch: s390x
|
||||||
dist: focal
|
dist: bionic
|
||||||
addons:
|
addons:
|
||||||
apt_packages:
|
apt_packages:
|
||||||
- libaio-dev
|
- libaio-dev
|
||||||
@ -260,11 +263,10 @@ jobs:
|
|||||||
|
|
||||||
- name: "[s390x] GCC (user)"
|
- name: "[s390x] GCC (user)"
|
||||||
arch: s390x
|
arch: s390x
|
||||||
dist: focal
|
dist: bionic
|
||||||
addons:
|
addons:
|
||||||
apt_packages:
|
apt_packages:
|
||||||
- libgcrypt20-dev
|
- libgcrypt20-dev
|
||||||
- libglib2.0-dev
|
|
||||||
- libgnutls28-dev
|
- libgnutls28-dev
|
||||||
- ninja-build
|
- ninja-build
|
||||||
env:
|
env:
|
||||||
@ -272,7 +274,7 @@ jobs:
|
|||||||
|
|
||||||
- name: "[s390x] Clang (disable-tcg)"
|
- name: "[s390x] Clang (disable-tcg)"
|
||||||
arch: s390x
|
arch: s390x
|
||||||
dist: focal
|
dist: bionic
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt_packages:
|
apt_packages:
|
||||||
@ -303,3 +305,26 @@ jobs:
|
|||||||
- CONFIG="--disable-containers --disable-tcg --enable-kvm
|
- CONFIG="--disable-containers --disable-tcg --enable-kvm
|
||||||
--disable-tools --host-cc=clang --cxx=clang++"
|
--disable-tools --host-cc=clang --cxx=clang++"
|
||||||
- UNRELIABLE=true
|
- UNRELIABLE=true
|
||||||
|
|
||||||
|
# Release builds
|
||||||
|
# The make-release script expect a QEMU version, so our tag must start with a 'v'.
|
||||||
|
# This is the case when release candidate tags are created.
|
||||||
|
- name: "Release tarball"
|
||||||
|
if: tag IS present AND tag =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
||||||
|
env:
|
||||||
|
# We want to build from the release tarball
|
||||||
|
- BUILD_DIR="release/build/dir" SRC_DIR="../../.."
|
||||||
|
- BASE_CONFIG="--prefix=$PWD/dist"
|
||||||
|
- CONFIG="--target-list=x86_64-softmmu,aarch64-softmmu,armeb-linux-user,ppc-linux-user"
|
||||||
|
- TEST_CMD="make install -j${JOBS}"
|
||||||
|
- QEMU_VERSION="${TRAVIS_TAG:1}"
|
||||||
|
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||||
|
script:
|
||||||
|
- make -C ${SRC_DIR} qemu-${QEMU_VERSION}.tar.bz2
|
||||||
|
- ls -l ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2
|
||||||
|
- tar -xf ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2 && cd qemu-${QEMU_VERSION}
|
||||||
|
- mkdir -p release-build && cd release-build
|
||||||
|
- ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||||
|
- make install
|
||||||
|
allow_failures:
|
||||||
|
- env: UNRELIABLE=true
|
||||||
|
72
3k.c
Normal file
72
3k.c
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void libafl_qemu_main_loop( void );
|
||||||
|
void libafl_qemu_sys_init(int argc, char **argv, char **envp);
|
||||||
|
void libafl_qemu_cleanup( void );
|
||||||
|
|
||||||
|
void libafl_qemu_set_breakpoint( unsigned long int );
|
||||||
|
|
||||||
|
void libafl_qemu_remove_native_breakpoint( unsigned long int );
|
||||||
|
void libafl_qemu_set_native_breakpoint( unsigned long int );
|
||||||
|
void libafl_snapshot_save( const char* );
|
||||||
|
void libafl_snapshot_load( const char* );
|
||||||
|
|
||||||
|
void libafl_phys_read(uint32_t, uint8_t*, int);
|
||||||
|
|
||||||
|
void libafl_phys_write(uint32_t, uint8_t*, int);
|
||||||
|
|
||||||
|
int64_t icount_to_ns(int64_t icount);
|
||||||
|
|
||||||
|
int64_t libafl_get_clock( void );
|
||||||
|
int main(int argc, char **argv, char **envp)
|
||||||
|
{
|
||||||
|
unsigned char buf[32] = "_`abcdefghijklmnopqrstuvwxyz{|}~";
|
||||||
|
unsigned char buf2[32] = "0";
|
||||||
|
unsigned char buf3[32] = "z";
|
||||||
|
unsigned char buf4[32] = "a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
|
||||||
|
unsigned char buf5[32] = "b!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
|
||||||
|
libafl_qemu_sys_init(argc, argv, envp);
|
||||||
|
int pheader = 0x00006a4c;
|
||||||
|
// libafl_phys_read(0x20000110-0x20000100+pheader, buf,32);
|
||||||
|
// printf("FUZZ_INPUT[0]: %c\n", buf[0]);
|
||||||
|
// Start pre-run
|
||||||
|
libafl_qemu_set_native_breakpoint(0x4ce2);//send 217028
|
||||||
|
libafl_qemu_main_loop();
|
||||||
|
libafl_qemu_remove_native_breakpoint(0x4ce2);
|
||||||
|
// End pre-run
|
||||||
|
libafl_snapshot_save("Start");
|
||||||
|
libafl_qemu_set_native_breakpoint(0x4be0);
|
||||||
|
int64_t tmp = libafl_get_clock();
|
||||||
|
printf("snapshot icount: %ld, %ldns\n",tmp,icount_to_ns(tmp));
|
||||||
|
libafl_snapshot_load("Start");
|
||||||
|
tmp = libafl_get_clock();
|
||||||
|
printf("snapshot icount after load: %ld, %ldns\n",tmp,icount_to_ns(tmp));
|
||||||
|
|
||||||
|
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
|
||||||
|
libafl_qemu_main_loop();
|
||||||
|
printf("%ld für %s\n",libafl_get_clock(),buf);
|
||||||
|
libafl_snapshot_load("Start");
|
||||||
|
|
||||||
|
libafl_phys_write(0x20000110-0x20000100+pheader, buf2,32);
|
||||||
|
libafl_qemu_main_loop();
|
||||||
|
printf("%ld für %s\n",libafl_get_clock(),buf2);
|
||||||
|
libafl_snapshot_load("Start");
|
||||||
|
|
||||||
|
libafl_phys_write(0x20000110-0x20000100+pheader, buf3,32);
|
||||||
|
libafl_qemu_main_loop();
|
||||||
|
printf("%ld für %s\n",libafl_get_clock(),buf3);
|
||||||
|
libafl_snapshot_load("Start");
|
||||||
|
/*int counter = 3000;
|
||||||
|
do {
|
||||||
|
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
|
||||||
|
libafl_qemu_main_loop();
|
||||||
|
int64_t tmp = libafl_get_clock();
|
||||||
|
printf("%ld, %ldns\n",tmp,icount_to_ns(tmp));
|
||||||
|
libafl_snapshot_load("Start");
|
||||||
|
// puts("Reload has occured");
|
||||||
|
counter--;
|
||||||
|
} while (counter);*/
|
||||||
|
libafl_qemu_cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
11
Kconfig.host
11
Kconfig.host
@ -22,12 +22,15 @@ config TPM
|
|||||||
|
|
||||||
config VHOST_USER
|
config VHOST_USER
|
||||||
bool
|
bool
|
||||||
|
select VHOST
|
||||||
|
|
||||||
config VHOST_VDPA
|
config VHOST_VDPA
|
||||||
bool
|
bool
|
||||||
|
select VHOST
|
||||||
|
|
||||||
config VHOST_KERNEL
|
config VHOST_KERNEL
|
||||||
bool
|
bool
|
||||||
|
select VHOST
|
||||||
|
|
||||||
config VIRTFS
|
config VIRTFS
|
||||||
bool
|
bool
|
||||||
@ -38,11 +41,3 @@ config PVRDMA
|
|||||||
config MULTIPROCESS_ALLOWED
|
config MULTIPROCESS_ALLOWED
|
||||||
bool
|
bool
|
||||||
imply MULTIPROCESS
|
imply MULTIPROCESS
|
||||||
|
|
||||||
config FUZZ
|
|
||||||
bool
|
|
||||||
select SPARSE_MEM
|
|
||||||
|
|
||||||
config VFIO_USER_SERVER_ALLOWED
|
|
||||||
bool
|
|
||||||
imply VFIO_USER_SERVER
|
|
||||||
|
774
MAINTAINERS
774
MAINTAINERS
File diff suppressed because it is too large
Load Diff
60
Makefile
60
Makefile
@ -42,9 +42,6 @@ configure: ;
|
|||||||
ifneq ($(wildcard config-host.mak),)
|
ifneq ($(wildcard config-host.mak),)
|
||||||
include config-host.mak
|
include config-host.mak
|
||||||
|
|
||||||
include Makefile.prereqs
|
|
||||||
Makefile.prereqs: config-host.mak
|
|
||||||
|
|
||||||
git-submodule-update:
|
git-submodule-update:
|
||||||
.git-submodule-status: git-submodule-update config-host.mak
|
.git-submodule-status: git-submodule-update config-host.mak
|
||||||
Makefile: .git-submodule-status
|
Makefile: .git-submodule-status
|
||||||
@ -90,7 +87,7 @@ x := $(shell rm -rf meson-private meson-info meson-logs)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# 1. ensure config-host.mak is up-to-date
|
# 1. ensure config-host.mak is up-to-date
|
||||||
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh $(SRC_PATH)/VERSION
|
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
|
||||||
@echo config-host.mak is out-of-date, running configure
|
@echo config-host.mak is out-of-date, running configure
|
||||||
@if test -f meson-private/coredata.dat; then \
|
@if test -f meson-private/coredata.dat; then \
|
||||||
./config.status --skip-meson; \
|
./config.status --skip-meson; \
|
||||||
@ -127,12 +124,6 @@ ifneq ($(MESON),)
|
|||||||
Makefile.mtest: build.ninja scripts/mtest2make.py
|
Makefile.mtest: build.ninja scripts/mtest2make.py
|
||||||
$(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
|
$(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
|
||||||
-include Makefile.mtest
|
-include Makefile.mtest
|
||||||
|
|
||||||
.PHONY: update-buildoptions
|
|
||||||
all update-buildoptions: $(SRC_PATH)/scripts/meson-buildoptions.sh
|
|
||||||
$(SRC_PATH)/scripts/meson-buildoptions.sh: $(SRC_PATH)/meson_options.txt
|
|
||||||
$(MESON) introspect --buildoptions $(SRC_PATH)/meson.build | $(PYTHON) \
|
|
||||||
scripts/meson-buildoptions.py > $@.tmp && mv $@.tmp $@
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# 4. Rules to bridge to other makefiles
|
# 4. Rules to bridge to other makefiles
|
||||||
@ -146,9 +137,9 @@ MAKE.q = $(findstring q,$(firstword $(filter-out --%,$(MAKEFLAGS))))
|
|||||||
MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq)
|
MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq)
|
||||||
NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \
|
NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \
|
||||||
$(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \
|
$(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \
|
||||||
-d keepdepfile
|
|
||||||
ninja-cmd-goals = $(or $(MAKECMDGOALS), all)
|
ninja-cmd-goals = $(or $(MAKECMDGOALS), all)
|
||||||
ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g))
|
ninja-cmd-goals += $(foreach t, $(.tests), $(.test.deps.$t))
|
||||||
|
|
||||||
makefile-targets := build.ninja ctags TAGS cscope dist clean uninstall
|
makefile-targets := build.ninja ctags TAGS cscope dist clean uninstall
|
||||||
# "ninja -t targets" also lists all prerequisites. If build system
|
# "ninja -t targets" also lists all prerequisites. If build system
|
||||||
@ -162,12 +153,15 @@ $(ninja-targets): run-ninja
|
|||||||
# --output-sync line.
|
# --output-sync line.
|
||||||
run-ninja: config-host.mak
|
run-ninja: config-host.mak
|
||||||
ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),)
|
ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),)
|
||||||
+$(if $(MAKE.nq),@:,$(quiet-@)$(NINJA) $(NINJAFLAGS) \
|
+$(quiet-@)$(if $(MAKE.nq),@:, $(NINJA) -d keepdepfile \
|
||||||
$(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat)
|
$(NINJAFLAGS) $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Force configure to re-run if the API symbols are updated
|
||||||
ifeq ($(CONFIG_PLUGIN),y)
|
ifeq ($(CONFIG_PLUGIN),y)
|
||||||
|
config-host.mak: $(SRC_PATH)/plugins/qemu-plugins.symbols
|
||||||
|
|
||||||
.PHONY: plugins
|
.PHONY: plugins
|
||||||
plugins:
|
plugins:
|
||||||
$(call quiet-command,\
|
$(call quiet-command,\
|
||||||
@ -189,27 +183,30 @@ include $(SRC_PATH)/tests/Makefile.include
|
|||||||
|
|
||||||
all: recurse-all
|
all: recurse-all
|
||||||
|
|
||||||
ROMS_RULES=$(foreach t, all clean distclean, $(addsuffix /$(t), $(ROMS)))
|
ROM_DIRS = $(addprefix pc-bios/, $(ROMS))
|
||||||
.PHONY: $(ROMS_RULES)
|
ROM_DIRS_RULES=$(foreach t, all clean, $(addsuffix /$(t), $(ROM_DIRS)))
|
||||||
$(ROMS_RULES):
|
# Only keep -O and -g cflags
|
||||||
|
.PHONY: $(ROM_DIRS_RULES)
|
||||||
|
$(ROM_DIRS_RULES):
|
||||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),)
|
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" TARGET_DIR="$(dir $@)" $(notdir $@),)
|
||||||
|
|
||||||
.PHONY: recurse-all recurse-clean
|
.PHONY: recurse-all recurse-clean
|
||||||
recurse-all: $(addsuffix /all, $(ROMS))
|
recurse-all: $(addsuffix /all, $(ROM_DIRS))
|
||||||
recurse-clean: $(addsuffix /clean, $(ROMS))
|
recurse-clean: $(addsuffix /clean, $(ROM_DIRS))
|
||||||
recurse-distclean: $(addsuffix /distclean, $(ROMS))
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
clean: recurse-clean
|
clean: recurse-clean
|
||||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean || :
|
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean || :
|
||||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) clean-ctlist || :
|
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) clean-ctlist || :
|
||||||
find . \( -name '*.so' -o -name '*.dll' -o \
|
# avoid old build problems by removing potentially incorrect old files
|
||||||
-name '*.[oda]' -o -name '*.gcno' \) -type f \
|
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||||
|
find . \( -name '*.so' -o -name '*.dll' -o -name '*.[oda]' \) -type f \
|
||||||
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-aarch64.a \
|
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-aarch64.a \
|
||||||
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-arm.a \
|
! -path ./roms/edk2/ArmPkg/Library/GccLto/liblto-arm.a \
|
||||||
-exec rm {} +
|
-exec rm {} +
|
||||||
rm -f TAGS cscope.* *~ */*~
|
rm -f TAGS cscope.* *.pod *~ */*~
|
||||||
|
rm -f fsdev/*.pod scsi/*.pod
|
||||||
|
|
||||||
VERSION = $(shell cat $(SRC_PATH)/VERSION)
|
VERSION = $(shell cat $(SRC_PATH)/VERSION)
|
||||||
|
|
||||||
@ -218,12 +215,12 @@ dist: qemu-$(VERSION).tar.bz2
|
|||||||
qemu-%.tar.bz2:
|
qemu-%.tar.bz2:
|
||||||
$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
|
$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
|
||||||
|
|
||||||
distclean: clean recurse-distclean
|
distclean: clean
|
||||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || :
|
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || :
|
||||||
rm -f config-host.mak Makefile.prereqs qemu-bundle
|
rm -f config-host.mak config-host.h* config-poison.h
|
||||||
rm -f tests/tcg/*/config-target.mak tests/tcg/config-host.mak
|
rm -f tests/tcg/config-*.mak
|
||||||
rm -f config.status
|
rm -f config-all-disas.mak config.status
|
||||||
rm -f roms/seabios/config.mak
|
rm -f roms/seabios/config.mak roms/vgabios/config.mak
|
||||||
rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
|
rm -f qemu-plugins-ld.symbols qemu-plugins-ld64.symbols
|
||||||
rm -f *-config-target.h *-config-devices.mak *-config-devices.h
|
rm -f *-config-target.h *-config-devices.mak *-config-devices.h
|
||||||
rm -rf meson-private meson-logs meson-info compile_commands.json
|
rm -rf meson-private meson-logs meson-info compile_commands.json
|
||||||
@ -232,8 +229,7 @@ distclean: clean recurse-distclean
|
|||||||
rm -f linux-headers/asm
|
rm -f linux-headers/asm
|
||||||
rm -Rf .sdk
|
rm -Rf .sdk
|
||||||
|
|
||||||
find-src-path = find "$(SRC_PATH)" -path "$(SRC_PATH)/meson" -prune -o \
|
find-src-path = find "$(SRC_PATH)/" -path "$(SRC_PATH)/meson" -prune -o \( -name "*.[chsS]" -o -name "*.[ch].inc" \)
|
||||||
-type l -prune -o \( -name "*.[chsS]" -o -name "*.[ch].inc" \)
|
|
||||||
|
|
||||||
.PHONY: ctags
|
.PHONY: ctags
|
||||||
ctags:
|
ctags:
|
||||||
@ -254,7 +250,7 @@ gtags:
|
|||||||
"GTAGS", "Remove old $@ files")
|
"GTAGS", "Remove old $@ files")
|
||||||
$(call quiet-command, \
|
$(call quiet-command, \
|
||||||
(cd $(SRC_PATH) && \
|
(cd $(SRC_PATH) && \
|
||||||
$(find-src-path) -print | gtags -f -), \
|
$(find-src-path) | gtags -f -), \
|
||||||
"GTAGS", "Re-index $(SRC_PATH)")
|
"GTAGS", "Re-index $(SRC_PATH)")
|
||||||
|
|
||||||
.PHONY: TAGS
|
.PHONY: TAGS
|
||||||
@ -284,7 +280,6 @@ cscope:
|
|||||||
# Needed by "meson install"
|
# Needed by "meson install"
|
||||||
export DESTDIR
|
export DESTDIR
|
||||||
|
|
||||||
include $(SRC_PATH)/tests/lcitool/Makefile.include
|
|
||||||
include $(SRC_PATH)/tests/docker/Makefile.include
|
include $(SRC_PATH)/tests/docker/Makefile.include
|
||||||
include $(SRC_PATH)/tests/vm/Makefile.include
|
include $(SRC_PATH)/tests/vm/Makefile.include
|
||||||
|
|
||||||
@ -314,7 +309,6 @@ endif
|
|||||||
@echo 'Test targets:'
|
@echo 'Test targets:'
|
||||||
$(call print-help,check,Run all tests (check-help for details))
|
$(call print-help,check,Run all tests (check-help for details))
|
||||||
$(call print-help,bench,Run all benchmarks)
|
$(call print-help,bench,Run all benchmarks)
|
||||||
$(call print-help,lcitool-help,Help about targets for managing build environment manifests)
|
|
||||||
$(call print-help,docker-help,Help about targets running tests inside containers)
|
$(call print-help,docker-help,Help about targets running tests inside containers)
|
||||||
$(call print-help,vm-help,Help about targets running tests inside VM)
|
$(call print-help,vm-help,Help about targets running tests inside VM)
|
||||||
@echo ''
|
@echo ''
|
||||||
|
@ -39,7 +39,7 @@ Documentation can be found hosted online at
|
|||||||
current development version that is available at
|
current development version that is available at
|
||||||
`<https://www.qemu.org/docs/master/>`_ is generated from the ``docs/``
|
`<https://www.qemu.org/docs/master/>`_ is generated from the ``docs/``
|
||||||
folder in the source tree, and is built by `Sphinx
|
folder in the source tree, and is built by `Sphinx
|
||||||
<https://www.sphinx-doc.org/en/master/>`_.
|
<https://www.sphinx-doc.org/en/master/>_`.
|
||||||
|
|
||||||
|
|
||||||
Building
|
Building
|
||||||
@ -59,9 +59,9 @@ of other UNIX targets. The simple steps to build QEMU are:
|
|||||||
|
|
||||||
Additional information can also be found online via the QEMU website:
|
Additional information can also be found online via the QEMU website:
|
||||||
|
|
||||||
* `<https://wiki.qemu.org/Hosts/Linux>`_
|
* `<https://qemu.org/Hosts/Linux>`_
|
||||||
* `<https://wiki.qemu.org/Hosts/Mac>`_
|
* `<https://qemu.org/Hosts/Mac>`_
|
||||||
* `<https://wiki.qemu.org/Hosts/W32>`_
|
* `<https://qemu.org/Hosts/W32>`_
|
||||||
|
|
||||||
|
|
||||||
Submitting patches
|
Submitting patches
|
||||||
@ -78,14 +78,14 @@ format-patch' and/or 'git send-email' to format & send the mail to the
|
|||||||
qemu-devel@nongnu.org mailing list. All patches submitted must contain
|
qemu-devel@nongnu.org mailing list. All patches submitted must contain
|
||||||
a 'Signed-off-by' line from the author. Patches should follow the
|
a 'Signed-off-by' line from the author. Patches should follow the
|
||||||
guidelines set out in the `style section
|
guidelines set out in the `style section
|
||||||
<https://www.qemu.org/docs/master/devel/style.html>`_ of
|
<https://www.qemu.org/docs/master/devel/style.html>` of
|
||||||
the Developers Guide.
|
the Developers Guide.
|
||||||
|
|
||||||
Additional information on submitting patches can be found online via
|
Additional information on submitting patches can be found online via
|
||||||
the QEMU website
|
the QEMU website
|
||||||
|
|
||||||
* `<https://wiki.qemu.org/Contribute/SubmitAPatch>`_
|
* `<https://qemu.org/Contribute/SubmitAPatch>`_
|
||||||
* `<https://wiki.qemu.org/Contribute/TrivialPatches>`_
|
* `<https://qemu.org/Contribute/TrivialPatches>`_
|
||||||
|
|
||||||
The QEMU website is also maintained under source control.
|
The QEMU website is also maintained under source control.
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ reported via GitLab.
|
|||||||
|
|
||||||
For additional information on bug reporting consult:
|
For additional information on bug reporting consult:
|
||||||
|
|
||||||
* `<https://wiki.qemu.org/Contribute/ReportABug>`_
|
* `<https://qemu.org/Contribute/ReportABug>`_
|
||||||
|
|
||||||
|
|
||||||
ChangeLog
|
ChangeLog
|
||||||
@ -168,4 +168,4 @@ main methods being email and IRC
|
|||||||
Information on additional methods of contacting the community can be
|
Information on additional methods of contacting the community can be
|
||||||
found online via the QEMU website:
|
found online via the QEMU website:
|
||||||
|
|
||||||
* `<https://wiki.qemu.org/Contribute/StartHere>`_
|
* `<https://qemu.org/Contribute/StartHere>`_
|
@ -49,14 +49,6 @@ AccelClass *accel_find(const char *opt_name)
|
|||||||
return ac;
|
return ac;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the name of the current accelerator */
|
|
||||||
const char *current_accel_name(void)
|
|
||||||
{
|
|
||||||
AccelClass *ac = ACCEL_GET_CLASS(current_accel());
|
|
||||||
|
|
||||||
return ac->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque)
|
static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque)
|
||||||
{
|
{
|
||||||
CPUClass *cc = CPU_CLASS(klass);
|
CPUClass *cc = CPU_CLASS(klass);
|
||||||
@ -129,16 +121,6 @@ bool accel_cpu_realizefn(CPUState *cpu, Error **errp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int accel_supported_gdbstub_sstep_flags(void)
|
|
||||||
{
|
|
||||||
AccelState *accel = current_accel();
|
|
||||||
AccelClass *acc = ACCEL_GET_CLASS(accel);
|
|
||||||
if (acc->gdbstub_supported_sstep_flags) {
|
|
||||||
return acc->gdbstub_supported_sstep_flags();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const TypeInfo accel_cpu_type = {
|
static const TypeInfo accel_cpu_type = {
|
||||||
.name = TYPE_ACCEL_CPU,
|
.name = TYPE_ACCEL_CPU,
|
||||||
.parent = TYPE_OBJECT,
|
.parent = TYPE_OBJECT,
|
||||||
|
@ -66,7 +66,6 @@ void accel_init_ops_interfaces(AccelClass *ac)
|
|||||||
{
|
{
|
||||||
const char *ac_name;
|
const char *ac_name;
|
||||||
char *ops_name;
|
char *ops_name;
|
||||||
ObjectClass *oc;
|
|
||||||
AccelOpsClass *ops;
|
AccelOpsClass *ops;
|
||||||
|
|
||||||
ac_name = object_class_get_name(OBJECT_CLASS(ac));
|
ac_name = object_class_get_name(OBJECT_CLASS(ac));
|
||||||
@ -74,13 +73,8 @@ void accel_init_ops_interfaces(AccelClass *ac)
|
|||||||
|
|
||||||
ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
|
ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
|
||||||
ops = ACCEL_OPS_CLASS(module_object_class_by_name(ops_name));
|
ops = ACCEL_OPS_CLASS(module_object_class_by_name(ops_name));
|
||||||
oc = module_object_class_by_name(ops_name);
|
|
||||||
if (!oc) {
|
|
||||||
error_report("fatal: could not load module for type '%s'", ops_name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
g_free(ops_name);
|
g_free(ops_name);
|
||||||
ops = ACCEL_OPS_CLASS(oc);
|
|
||||||
/*
|
/*
|
||||||
* all accelerators need to define ops, providing at least a mandatory
|
* all accelerators need to define ops, providing at least a mandatory
|
||||||
* non-NULL create_vcpu_thread operation.
|
* non-NULL create_vcpu_thread operation.
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
static void *dummy_cpu_thread_fn(void *arg)
|
static void *dummy_cpu_thread_fn(void *arg)
|
||||||
{
|
{
|
||||||
CPUState *cpu = arg;
|
CPUState *cpu = arg;
|
||||||
|
sigset_t waitset;
|
||||||
|
int r;
|
||||||
|
|
||||||
rcu_register_thread();
|
rcu_register_thread();
|
||||||
|
|
||||||
@ -30,13 +32,8 @@ static void *dummy_cpu_thread_fn(void *arg)
|
|||||||
cpu->can_do_io = 1;
|
cpu->can_do_io = 1;
|
||||||
current_cpu = cpu;
|
current_cpu = cpu;
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
sigset_t waitset;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
sigemptyset(&waitset);
|
sigemptyset(&waitset);
|
||||||
sigaddset(&waitset, SIG_IPI);
|
sigaddset(&waitset, SIG_IPI);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* signal CPU creation */
|
/* signal CPU creation */
|
||||||
cpu_thread_signal_created(cpu);
|
cpu_thread_signal_created(cpu);
|
||||||
@ -44,7 +41,6 @@ static void *dummy_cpu_thread_fn(void *arg)
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
#ifndef _WIN32
|
|
||||||
do {
|
do {
|
||||||
int sig;
|
int sig;
|
||||||
r = sigwait(&waitset, &sig);
|
r = sigwait(&waitset, &sig);
|
||||||
@ -53,9 +49,6 @@ static void *dummy_cpu_thread_fn(void *arg)
|
|||||||
perror("sigwait");
|
perror("sigwait");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
qemu_sem_wait(&cpu->sem);
|
|
||||||
#endif
|
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
qemu_wait_io_event(cpu);
|
qemu_wait_io_event(cpu);
|
||||||
} while (!cpu->unplug);
|
} while (!cpu->unplug);
|
||||||
@ -76,7 +69,4 @@ void dummy_start_vcpu_thread(CPUState *cpu)
|
|||||||
cpu->cpu_index);
|
cpu->cpu_index);
|
||||||
qemu_thread_create(cpu->thread, thread_name, dummy_cpu_thread_fn, cpu,
|
qemu_thread_create(cpu->thread, thread_name, dummy_cpu_thread_fn, cpu,
|
||||||
QEMU_THREAD_JOINABLE);
|
QEMU_THREAD_JOINABLE);
|
||||||
#ifdef _WIN32
|
|
||||||
qemu_sem_init(&cpu->sem, 0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
@ -60,10 +60,6 @@
|
|||||||
|
|
||||||
HVFState *hvf_state;
|
HVFState *hvf_state;
|
||||||
|
|
||||||
#ifdef __aarch64__
|
|
||||||
#define HV_VM_DEFAULT NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Memory slots */
|
/* Memory slots */
|
||||||
|
|
||||||
hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
|
hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
|
||||||
@ -120,12 +116,11 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
|||||||
{
|
{
|
||||||
hvf_slot *mem;
|
hvf_slot *mem;
|
||||||
MemoryRegion *area = section->mr;
|
MemoryRegion *area = section->mr;
|
||||||
bool writable = !area->readonly && !area->rom_device;
|
bool writeable = !area->readonly && !area->rom_device;
|
||||||
hv_memory_flags_t flags;
|
hv_memory_flags_t flags;
|
||||||
uint64_t page_size = qemu_real_host_page_size();
|
|
||||||
|
|
||||||
if (!memory_region_is_ram(area)) {
|
if (!memory_region_is_ram(area)) {
|
||||||
if (writable) {
|
if (writeable) {
|
||||||
return;
|
return;
|
||||||
} else if (!memory_region_is_romd(area)) {
|
} else if (!memory_region_is_romd(area)) {
|
||||||
/*
|
/*
|
||||||
@ -136,12 +131,6 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
|
|
||||||
!QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
|
|
||||||
/* Not page aligned, so we can not map as RAM */
|
|
||||||
add = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem = hvf_find_overlap_slot(
|
mem = hvf_find_overlap_slot(
|
||||||
section->offset_within_address_space,
|
section->offset_within_address_space,
|
||||||
int128_get64(section->size));
|
int128_get64(section->size));
|
||||||
@ -250,12 +239,12 @@ static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
|
|||||||
if (on) {
|
if (on) {
|
||||||
slot->flags |= HVF_SLOT_LOG;
|
slot->flags |= HVF_SLOT_LOG;
|
||||||
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
||||||
HV_MEMORY_READ | HV_MEMORY_EXEC);
|
HV_MEMORY_READ);
|
||||||
/* stop tracking region*/
|
/* stop tracking region*/
|
||||||
} else {
|
} else {
|
||||||
slot->flags &= ~HVF_SLOT_LOG;
|
slot->flags &= ~HVF_SLOT_LOG;
|
||||||
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
||||||
HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
|
HV_MEMORY_READ | HV_MEMORY_WRITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +291,6 @@ static void hvf_region_del(MemoryListener *listener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static MemoryListener hvf_memory_listener = {
|
static MemoryListener hvf_memory_listener = {
|
||||||
.name = "hvf",
|
|
||||||
.priority = 10,
|
.priority = 10,
|
||||||
.region_add = hvf_region_add,
|
.region_add = hvf_region_add,
|
||||||
.region_del = hvf_region_del,
|
.region_del = hvf_region_del,
|
||||||
@ -328,7 +316,7 @@ static int hvf_accel_init(MachineState *ms)
|
|||||||
|
|
||||||
s = g_new0(HVFState, 1);
|
s = g_new0(HVFState, 1);
|
||||||
|
|
||||||
s->num_slots = ARRAY_SIZE(s->slots);
|
s->num_slots = 32;
|
||||||
for (x = 0; x < s->num_slots; ++x) {
|
for (x = 0; x < s->num_slots; ++x) {
|
||||||
s->slots[x].size = 0;
|
s->slots[x].size = 0;
|
||||||
s->slots[x].slot_id = x;
|
s->slots[x].slot_id = x;
|
||||||
@ -336,8 +324,7 @@ static int hvf_accel_init(MachineState *ms)
|
|||||||
|
|
||||||
hvf_state = s;
|
hvf_state = s;
|
||||||
memory_listener_register(&hvf_memory_listener, &address_space_memory);
|
memory_listener_register(&hvf_memory_listener, &address_space_memory);
|
||||||
|
return 0;
|
||||||
return hvf_arch_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hvf_accel_class_init(ObjectClass *oc, void *data)
|
static void hvf_accel_class_init(ObjectClass *oc, void *data)
|
||||||
@ -378,20 +365,17 @@ static int hvf_init_vcpu(CPUState *cpu)
|
|||||||
cpu->hvf = g_malloc0(sizeof(*cpu->hvf));
|
cpu->hvf = g_malloc0(sizeof(*cpu->hvf));
|
||||||
|
|
||||||
/* init cpu signals */
|
/* init cpu signals */
|
||||||
|
sigset_t set;
|
||||||
struct sigaction sigact;
|
struct sigaction sigact;
|
||||||
|
|
||||||
memset(&sigact, 0, sizeof(sigact));
|
memset(&sigact, 0, sizeof(sigact));
|
||||||
sigact.sa_handler = dummy_signal;
|
sigact.sa_handler = dummy_signal;
|
||||||
sigaction(SIG_IPI, &sigact, NULL);
|
sigaction(SIG_IPI, &sigact, NULL);
|
||||||
|
|
||||||
pthread_sigmask(SIG_BLOCK, NULL, &cpu->hvf->unblock_ipi_mask);
|
pthread_sigmask(SIG_BLOCK, NULL, &set);
|
||||||
sigdelset(&cpu->hvf->unblock_ipi_mask, SIG_IPI);
|
sigdelset(&set, SIG_IPI);
|
||||||
|
|
||||||
#ifdef __aarch64__
|
|
||||||
r = hv_vcpu_create(&cpu->hvf->fd, (hv_vcpu_exit_t **)&cpu->hvf->exit, NULL);
|
|
||||||
#else
|
|
||||||
r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT);
|
r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT);
|
||||||
#endif
|
|
||||||
cpu->vcpu_dirty = 1;
|
cpu->vcpu_dirty = 1;
|
||||||
assert_hvf_ok(r);
|
assert_hvf_ok(r);
|
||||||
|
|
||||||
@ -467,7 +451,6 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
|
|||||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||||
|
|
||||||
ops->create_vcpu_thread = hvf_start_vcpu_thread;
|
ops->create_vcpu_thread = hvf_start_vcpu_thread;
|
||||||
ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
|
|
||||||
|
|
||||||
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
|
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
|
||||||
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
|
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "sysemu/hvf.h"
|
#include "sysemu/hvf.h"
|
||||||
#include "sysemu/hvf_int.h"
|
#include "sysemu/hvf_int.h"
|
||||||
|
@ -16,14 +16,12 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "sysemu/kvm.h"
|
|
||||||
#include "sysemu/kvm_int.h"
|
#include "sysemu/kvm_int.h"
|
||||||
#include "sysemu/runstate.h"
|
#include "sysemu/runstate.h"
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
|
||||||
#include <linux/kvm.h>
|
|
||||||
#include "kvm-cpus.h"
|
#include "kvm-cpus.h"
|
||||||
|
|
||||||
static void *kvm_vcpu_thread_fn(void *arg)
|
static void *kvm_vcpu_thread_fn(void *arg)
|
||||||
@ -76,34 +74,15 @@ static void kvm_start_vcpu_thread(CPUState *cpu)
|
|||||||
cpu, QEMU_THREAD_JOINABLE);
|
cpu, QEMU_THREAD_JOINABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool kvm_vcpu_thread_is_idle(CPUState *cpu)
|
|
||||||
{
|
|
||||||
return !kvm_halt_in_kernel();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool kvm_cpus_are_resettable(void)
|
|
||||||
{
|
|
||||||
return !kvm_enabled() || kvm_cpu_check_are_resettable();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
ops->create_vcpu_thread = kvm_start_vcpu_thread;
|
ops->create_vcpu_thread = kvm_start_vcpu_thread;
|
||||||
ops->cpu_thread_is_idle = kvm_vcpu_thread_is_idle;
|
|
||||||
ops->cpus_are_resettable = kvm_cpus_are_resettable;
|
|
||||||
ops->synchronize_post_reset = kvm_cpu_synchronize_post_reset;
|
ops->synchronize_post_reset = kvm_cpu_synchronize_post_reset;
|
||||||
ops->synchronize_post_init = kvm_cpu_synchronize_post_init;
|
ops->synchronize_post_init = kvm_cpu_synchronize_post_init;
|
||||||
ops->synchronize_state = kvm_cpu_synchronize_state;
|
ops->synchronize_state = kvm_cpu_synchronize_state;
|
||||||
ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
|
ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
|
||||||
|
|
||||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
|
||||||
ops->supports_guest_debug = kvm_supports_guest_debug;
|
|
||||||
ops->insert_breakpoint = kvm_insert_breakpoint;
|
|
||||||
ops->remove_breakpoint = kvm_remove_breakpoint;
|
|
||||||
ops->remove_all_breakpoints = kvm_remove_all_breakpoints;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo kvm_accel_ops_type = {
|
static const TypeInfo kvm_accel_ops_type = {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,9 +18,5 @@ void kvm_destroy_vcpu(CPUState *cpu);
|
|||||||
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
|
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
|
||||||
void kvm_cpu_synchronize_post_init(CPUState *cpu);
|
void kvm_cpu_synchronize_post_init(CPUState *cpu);
|
||||||
void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu);
|
void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu);
|
||||||
bool kvm_supports_guest_debug(void);
|
|
||||||
int kvm_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len);
|
|
||||||
int kvm_remove_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len);
|
|
||||||
void kvm_remove_all_breakpoints(CPUState *cpu);
|
|
||||||
|
|
||||||
#endif /* KVM_CPUS_H */
|
#endif /* KVM_CPUS_H */
|
||||||
|
@ -3,5 +3,6 @@ kvm_ss.add(files(
|
|||||||
'kvm-all.c',
|
'kvm-all.c',
|
||||||
'kvm-accel-ops.c',
|
'kvm-accel-ops.c',
|
||||||
))
|
))
|
||||||
|
kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c'))
|
||||||
|
|
||||||
specific_ss.add_all(when: 'CONFIG_KVM', if_true: kvm_ss)
|
specific_ss.add_all(when: 'CONFIG_KVM', if_true: kvm_ss)
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sev.h"
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/sev.h"
|
||||||
|
|
||||||
int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
|
int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
|
||||||
{
|
{
|
@ -2,19 +2,17 @@ specific_ss.add(files('accel-common.c'))
|
|||||||
softmmu_ss.add(files('accel-softmmu.c'))
|
softmmu_ss.add(files('accel-softmmu.c'))
|
||||||
user_ss.add(files('accel-user.c'))
|
user_ss.add(files('accel-user.c'))
|
||||||
|
|
||||||
|
subdir('hvf')
|
||||||
|
subdir('qtest')
|
||||||
|
subdir('kvm')
|
||||||
subdir('tcg')
|
subdir('tcg')
|
||||||
if have_system
|
subdir('xen')
|
||||||
subdir('hvf')
|
subdir('stubs')
|
||||||
subdir('qtest')
|
|
||||||
subdir('kvm')
|
|
||||||
subdir('xen')
|
|
||||||
subdir('stubs')
|
|
||||||
endif
|
|
||||||
|
|
||||||
dummy_ss = ss.source_set()
|
dummy_ss = ss.source_set()
|
||||||
dummy_ss.add(files(
|
dummy_ss.add(files(
|
||||||
'dummy-cpus.c',
|
'dummy-cpus.c',
|
||||||
))
|
))
|
||||||
|
|
||||||
specific_ss.add_all(when: ['CONFIG_SOFTMMU'], if_true: dummy_ss)
|
specific_ss.add_all(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'], if_true: dummy_ss)
|
||||||
specific_ss.add_all(when: ['CONFIG_XEN'], if_true: dummy_ss)
|
specific_ss.add_all(when: ['CONFIG_XEN'], if_true: dummy_ss)
|
||||||
|
@ -1 +1,2 @@
|
|||||||
qtest_module_ss.add(when: ['CONFIG_SOFTMMU'], if_true: files('qtest.c'))
|
qtest_module_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'],
|
||||||
|
if_true: files('qtest.c'))
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "qemu/accel.h"
|
#include "qemu/accel.h"
|
||||||
#include "sysemu/qtest.h"
|
#include "sysemu/qtest.h"
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
|
#include "sysemu/cpu-timers.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sysemu/hax.h"
|
#include "sysemu/hax.h"
|
||||||
|
|
||||||
bool hax_allowed;
|
|
||||||
|
|
||||||
int hax_sync_vcpus(void)
|
int hax_sync_vcpus(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
#include "hw/pci/msi.h"
|
#include "hw/pci/msi.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
KVMState *kvm_state;
|
KVMState *kvm_state;
|
||||||
bool kvm_kernel_irqchip;
|
bool kvm_kernel_irqchip;
|
||||||
@ -46,6 +49,27 @@ int kvm_has_many_ioeventfds(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
|
||||||
|
target_ulong len, int type)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
|
||||||
|
target_ulong len, int type)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kvm_remove_all_breakpoints(CPUState *cpu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
|
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
@ -56,7 +80,8 @@ int kvm_on_sigbus(int code, void *addr)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
@ -122,13 +147,4 @@ bool kvm_arm_supports_user_irq(void)
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
bool kvm_dirty_ring_enabled(void)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t kvm_dirty_ring_size(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
sysemu_stubs_ss = ss.source_set()
|
specific_ss.add(when: 'CONFIG_HAX', if_false: files('hax-stub.c'))
|
||||||
sysemu_stubs_ss.add(when: 'CONFIG_HAX', if_false: files('hax-stub.c'))
|
specific_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c'))
|
||||||
sysemu_stubs_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c'))
|
specific_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
|
||||||
sysemu_stubs_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
|
specific_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c'))
|
||||||
sysemu_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c'))
|
|
||||||
|
|
||||||
specific_ss.add_all(when: ['CONFIG_SOFTMMU'], if_true: sysemu_stubs_ss)
|
|
||||||
|
@ -21,17 +21,6 @@ void tlb_set_dirty(CPUState *cpu, target_ulong vaddr)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcg_flush_jmp_cache(CPUState *cpu)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int probe_access_flags(CPUArchState *env, target_ulong addr,
|
|
||||||
MMUAccessType access_type, int mmu_idx,
|
|
||||||
bool nonfault, void **phost, uintptr_t retaddr)
|
|
||||||
{
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
||||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
@ -39,12 +28,12 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
|||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
G_NORETURN void cpu_loop_exit(CPUState *cpu)
|
void QEMU_NORETURN cpu_loop_exit(CPUState *cpu)
|
||||||
{
|
{
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc)
|
void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc)
|
||||||
{
|
{
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
@ -13,23 +13,56 @@
|
|||||||
* See the COPYING file in the top-level directory.
|
* See the COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr,
|
static uint16_t atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr,
|
||||||
MemOpIdx oi)
|
TCGMemOpIdx oi)
|
||||||
{
|
{
|
||||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_RW);
|
CPUState *cpu = env_cpu(env);
|
||||||
|
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false);
|
||||||
|
|
||||||
|
trace_guest_mem_before_exec(cpu, addr, info);
|
||||||
|
trace_guest_mem_before_exec(cpu, addr, info | TRACE_MEM_ST);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr,
|
||||||
|
uint16_t info)
|
||||||
|
{
|
||||||
|
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||||
|
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info | TRACE_MEM_ST);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_ATOMIC128
|
#if HAVE_ATOMIC128
|
||||||
static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr,
|
static uint16_t atomic_trace_ld_pre(CPUArchState *env, target_ulong addr,
|
||||||
MemOpIdx oi)
|
TCGMemOpIdx oi)
|
||||||
{
|
{
|
||||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
|
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false);
|
||||||
|
|
||||||
|
trace_guest_mem_before_exec(env_cpu(env), addr, info);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr,
|
||||||
|
uint16_t info)
|
||||||
|
{
|
||||||
|
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t atomic_trace_st_pre(CPUArchState *env, target_ulong addr,
|
||||||
|
TCGMemOpIdx oi)
|
||||||
|
{
|
||||||
|
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), true);
|
||||||
|
|
||||||
|
trace_guest_mem_before_exec(env_cpu(env), addr, info);
|
||||||
|
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atomic_trace_st_post(CPUArchState *env, target_ulong addr,
|
static void atomic_trace_st_post(CPUArchState *env, target_ulong addr,
|
||||||
MemOpIdx oi)
|
uint16_t info)
|
||||||
{
|
{
|
||||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
|
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/plugin.h"
|
#include "qemu/plugin.h"
|
||||||
|
#include "trace/mem.h"
|
||||||
|
|
||||||
#if DATA_SIZE == 16
|
#if DATA_SIZE == 16
|
||||||
# define SUFFIX o
|
# define SUFFIX o
|
||||||
@ -63,7 +64,7 @@
|
|||||||
the ATOMIC_NAME macro, and redefined below. */
|
the ATOMIC_NAME macro, and redefined below. */
|
||||||
#if DATA_SIZE == 1
|
#if DATA_SIZE == 1
|
||||||
# define END
|
# define END
|
||||||
#elif HOST_BIG_ENDIAN
|
#elif defined(HOST_WORDS_BIGENDIAN)
|
||||||
# define END _be
|
# define END _be
|
||||||
#else
|
#else
|
||||||
# define END _le
|
# define END _le
|
||||||
@ -71,11 +72,12 @@
|
|||||||
|
|
||||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||||
ABI_TYPE cmpv, ABI_TYPE newv,
|
ABI_TYPE cmpv, ABI_TYPE newv,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||||
PAGE_READ | PAGE_WRITE, retaddr);
|
PAGE_READ | PAGE_WRITE, retaddr);
|
||||||
DATA_TYPE ret;
|
DATA_TYPE ret;
|
||||||
|
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
|
||||||
|
|
||||||
#if DATA_SIZE == 16
|
#if DATA_SIZE == 16
|
||||||
ret = atomic16_cmpxchg(haddr, cmpv, newv);
|
ret = atomic16_cmpxchg(haddr, cmpv, newv);
|
||||||
@ -83,60 +85,64 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
|||||||
ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
|
ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
|
||||||
#endif
|
#endif
|
||||||
ATOMIC_MMU_CLEANUP;
|
ATOMIC_MMU_CLEANUP;
|
||||||
atomic_trace_rmw_post(env, addr, oi);
|
atomic_trace_rmw_post(env, addr, info);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DATA_SIZE >= 16
|
#if DATA_SIZE >= 16
|
||||||
#if HAVE_ATOMIC128
|
#if HAVE_ATOMIC128
|
||||||
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||||
PAGE_READ, retaddr);
|
PAGE_READ, retaddr);
|
||||||
DATA_TYPE val;
|
DATA_TYPE val;
|
||||||
|
uint16_t info = atomic_trace_ld_pre(env, addr, oi);
|
||||||
|
|
||||||
val = atomic16_read(haddr);
|
val = atomic16_read(haddr);
|
||||||
ATOMIC_MMU_CLEANUP;
|
ATOMIC_MMU_CLEANUP;
|
||||||
atomic_trace_ld_post(env, addr, oi);
|
atomic_trace_ld_post(env, addr, info);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||||
PAGE_WRITE, retaddr);
|
PAGE_WRITE, retaddr);
|
||||||
|
uint16_t info = atomic_trace_st_pre(env, addr, oi);
|
||||||
|
|
||||||
atomic16_set(haddr, val);
|
atomic16_set(haddr, val);
|
||||||
ATOMIC_MMU_CLEANUP;
|
ATOMIC_MMU_CLEANUP;
|
||||||
atomic_trace_st_post(env, addr, oi);
|
atomic_trace_st_post(env, addr, info);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||||
PAGE_READ | PAGE_WRITE, retaddr);
|
PAGE_READ | PAGE_WRITE, retaddr);
|
||||||
DATA_TYPE ret;
|
DATA_TYPE ret;
|
||||||
|
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
|
||||||
|
|
||||||
ret = qatomic_xchg__nocheck(haddr, val);
|
ret = qatomic_xchg__nocheck(haddr, val);
|
||||||
ATOMIC_MMU_CLEANUP;
|
ATOMIC_MMU_CLEANUP;
|
||||||
atomic_trace_rmw_post(env, addr, oi);
|
atomic_trace_rmw_post(env, addr, info);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GEN_ATOMIC_HELPER(X) \
|
#define GEN_ATOMIC_HELPER(X) \
|
||||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||||
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
|
ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
|
||||||
{ \
|
{ \
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||||
DATA_TYPE ret; \
|
DATA_TYPE ret; \
|
||||||
|
uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
|
||||||
ret = qatomic_##X(haddr, val); \
|
ret = qatomic_##X(haddr, val); \
|
||||||
ATOMIC_MMU_CLEANUP; \
|
ATOMIC_MMU_CLEANUP; \
|
||||||
atomic_trace_rmw_post(env, addr, oi); \
|
atomic_trace_rmw_post(env, addr, info); \
|
||||||
return ret; \
|
return ret; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,11 +167,12 @@ GEN_ATOMIC_HELPER(xor_fetch)
|
|||||||
*/
|
*/
|
||||||
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
|
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
|
||||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||||
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
|
ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
|
||||||
{ \
|
{ \
|
||||||
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||||
XDATA_TYPE cmp, old, new, val = xval; \
|
XDATA_TYPE cmp, old, new, val = xval; \
|
||||||
|
uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
|
||||||
smp_mb(); \
|
smp_mb(); \
|
||||||
cmp = qatomic_read__nocheck(haddr); \
|
cmp = qatomic_read__nocheck(haddr); \
|
||||||
do { \
|
do { \
|
||||||
@ -173,7 +180,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
|||||||
cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \
|
cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \
|
||||||
} while (cmp != old); \
|
} while (cmp != old); \
|
||||||
ATOMIC_MMU_CLEANUP; \
|
ATOMIC_MMU_CLEANUP; \
|
||||||
atomic_trace_rmw_post(env, addr, oi); \
|
atomic_trace_rmw_post(env, addr, info); \
|
||||||
return RET; \
|
return RET; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +203,7 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
|
|||||||
|
|
||||||
/* Define reverse-host-endian atomic operations. Note that END is used
|
/* Define reverse-host-endian atomic operations. Note that END is used
|
||||||
within the ATOMIC_NAME macro. */
|
within the ATOMIC_NAME macro. */
|
||||||
#if HOST_BIG_ENDIAN
|
#ifdef HOST_WORDS_BIGENDIAN
|
||||||
# define END _le
|
# define END _le
|
||||||
#else
|
#else
|
||||||
# define END _be
|
# define END _be
|
||||||
@ -204,11 +211,12 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
|
|||||||
|
|
||||||
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
||||||
ABI_TYPE cmpv, ABI_TYPE newv,
|
ABI_TYPE cmpv, ABI_TYPE newv,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||||
PAGE_READ | PAGE_WRITE, retaddr);
|
PAGE_READ | PAGE_WRITE, retaddr);
|
||||||
DATA_TYPE ret;
|
DATA_TYPE ret;
|
||||||
|
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
|
||||||
|
|
||||||
#if DATA_SIZE == 16
|
#if DATA_SIZE == 16
|
||||||
ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
|
ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||||
@ -216,61 +224,65 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
|||||||
ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
|
ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||||
#endif
|
#endif
|
||||||
ATOMIC_MMU_CLEANUP;
|
ATOMIC_MMU_CLEANUP;
|
||||||
atomic_trace_rmw_post(env, addr, oi);
|
atomic_trace_rmw_post(env, addr, info);
|
||||||
return BSWAP(ret);
|
return BSWAP(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DATA_SIZE >= 16
|
#if DATA_SIZE >= 16
|
||||||
#if HAVE_ATOMIC128
|
#if HAVE_ATOMIC128
|
||||||
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||||
PAGE_READ, retaddr);
|
PAGE_READ, retaddr);
|
||||||
DATA_TYPE val;
|
DATA_TYPE val;
|
||||||
|
uint16_t info = atomic_trace_ld_pre(env, addr, oi);
|
||||||
|
|
||||||
val = atomic16_read(haddr);
|
val = atomic16_read(haddr);
|
||||||
ATOMIC_MMU_CLEANUP;
|
ATOMIC_MMU_CLEANUP;
|
||||||
atomic_trace_ld_post(env, addr, oi);
|
atomic_trace_ld_post(env, addr, info);
|
||||||
return BSWAP(val);
|
return BSWAP(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||||
PAGE_WRITE, retaddr);
|
PAGE_WRITE, retaddr);
|
||||||
|
uint16_t info = atomic_trace_st_pre(env, addr, oi);
|
||||||
|
|
||||||
val = BSWAP(val);
|
val = BSWAP(val);
|
||||||
atomic16_set(haddr, val);
|
atomic16_set(haddr, val);
|
||||||
ATOMIC_MMU_CLEANUP;
|
ATOMIC_MMU_CLEANUP;
|
||||||
atomic_trace_st_post(env, addr, oi);
|
atomic_trace_st_post(env, addr, info);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
|
||||||
PAGE_READ | PAGE_WRITE, retaddr);
|
PAGE_READ | PAGE_WRITE, retaddr);
|
||||||
ABI_TYPE ret;
|
ABI_TYPE ret;
|
||||||
|
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
|
||||||
|
|
||||||
ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
|
ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
|
||||||
ATOMIC_MMU_CLEANUP;
|
ATOMIC_MMU_CLEANUP;
|
||||||
atomic_trace_rmw_post(env, addr, oi);
|
atomic_trace_rmw_post(env, addr, info);
|
||||||
return BSWAP(ret);
|
return BSWAP(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GEN_ATOMIC_HELPER(X) \
|
#define GEN_ATOMIC_HELPER(X) \
|
||||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||||
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
|
ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
|
||||||
{ \
|
{ \
|
||||||
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||||
DATA_TYPE ret; \
|
DATA_TYPE ret; \
|
||||||
|
uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
|
||||||
ret = qatomic_##X(haddr, BSWAP(val)); \
|
ret = qatomic_##X(haddr, BSWAP(val)); \
|
||||||
ATOMIC_MMU_CLEANUP; \
|
ATOMIC_MMU_CLEANUP; \
|
||||||
atomic_trace_rmw_post(env, addr, oi); \
|
atomic_trace_rmw_post(env, addr, info); \
|
||||||
return BSWAP(ret); \
|
return BSWAP(ret); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,11 +304,12 @@ GEN_ATOMIC_HELPER(xor_fetch)
|
|||||||
*/
|
*/
|
||||||
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
|
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
|
||||||
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
||||||
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
|
ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
|
||||||
{ \
|
{ \
|
||||||
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
|
||||||
PAGE_READ | PAGE_WRITE, retaddr); \
|
PAGE_READ | PAGE_WRITE, retaddr); \
|
||||||
XDATA_TYPE ldo, ldn, old, new, val = xval; \
|
XDATA_TYPE ldo, ldn, old, new, val = xval; \
|
||||||
|
uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
|
||||||
smp_mb(); \
|
smp_mb(); \
|
||||||
ldn = qatomic_read__nocheck(haddr); \
|
ldn = qatomic_read__nocheck(haddr); \
|
||||||
do { \
|
do { \
|
||||||
@ -304,7 +317,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
|||||||
ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
|
ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
|
||||||
} while (ldo != ldn); \
|
} while (ldo != ldn); \
|
||||||
ATOMIC_MMU_CLEANUP; \
|
ATOMIC_MMU_CLEANUP; \
|
||||||
atomic_trace_rmw_post(env, addr, oi); \
|
atomic_trace_rmw_post(env, addr, info); \
|
||||||
return RET; \
|
return RET; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ void cpu_loop_exit(CPUState *cpu)
|
|||||||
void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc)
|
void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc)
|
||||||
{
|
{
|
||||||
if (pc) {
|
if (pc) {
|
||||||
cpu_restore_state(cpu, pc);
|
cpu_restore_state(cpu, pc, true);
|
||||||
}
|
}
|
||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "qemu/qemu-print.h"
|
#include "qemu/qemu-print.h"
|
||||||
#include "qapi/error.h"
|
|
||||||
#include "qapi/qapi-commands-machine.h"
|
|
||||||
#include "qapi/type-helpers.h"
|
|
||||||
#include "hw/core/tcg-cpu-ops.h"
|
#include "hw/core/tcg-cpu-ops.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "disas/disas.h"
|
#include "disas/disas.h"
|
||||||
@ -40,9 +38,7 @@
|
|||||||
#include "exec/cpu-all.h"
|
#include "exec/cpu-all.h"
|
||||||
#include "sysemu/cpu-timers.h"
|
#include "sysemu/cpu-timers.h"
|
||||||
#include "sysemu/replay.h"
|
#include "sysemu/replay.h"
|
||||||
#include "sysemu/tcg.h"
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "tb-jmp-cache.h"
|
|
||||||
#include "tb-hash.h"
|
#include "tb-hash.h"
|
||||||
#include "tb-context.h"
|
#include "tb-context.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@ -171,96 +167,22 @@ uint32_t curr_cflags(CPUState *cpu)
|
|||||||
return cflags;
|
return cflags;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tb_desc {
|
|
||||||
target_ulong pc;
|
|
||||||
target_ulong cs_base;
|
|
||||||
CPUArchState *env;
|
|
||||||
tb_page_addr_t page_addr0;
|
|
||||||
uint32_t flags;
|
|
||||||
uint32_t cflags;
|
|
||||||
uint32_t trace_vcpu_dstate;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool tb_lookup_cmp(const void *p, const void *d)
|
|
||||||
{
|
|
||||||
const TranslationBlock *tb = p;
|
|
||||||
const struct tb_desc *desc = d;
|
|
||||||
|
|
||||||
if ((TARGET_TB_PCREL || tb_pc(tb) == desc->pc) &&
|
|
||||||
tb_page_addr0(tb) == desc->page_addr0 &&
|
|
||||||
tb->cs_base == desc->cs_base &&
|
|
||||||
tb->flags == desc->flags &&
|
|
||||||
tb->trace_vcpu_dstate == desc->trace_vcpu_dstate &&
|
|
||||||
tb_cflags(tb) == desc->cflags) {
|
|
||||||
/* check next page if needed */
|
|
||||||
tb_page_addr_t tb_phys_page1 = tb_page_addr1(tb);
|
|
||||||
if (tb_phys_page1 == -1) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
tb_page_addr_t phys_page1;
|
|
||||||
target_ulong virt_page1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We know that the first page matched, and an otherwise valid TB
|
|
||||||
* encountered an incomplete instruction at the end of that page,
|
|
||||||
* therefore we know that generating a new TB from the current PC
|
|
||||||
* must also require reading from the next page -- even if the
|
|
||||||
* second pages do not match, and therefore the resulting insn
|
|
||||||
* is different for the new TB. Therefore any exception raised
|
|
||||||
* here by the faulting lookup is not premature.
|
|
||||||
*/
|
|
||||||
virt_page1 = TARGET_PAGE_ALIGN(desc->pc);
|
|
||||||
phys_page1 = get_page_addr_code(desc->env, virt_page1);
|
|
||||||
if (tb_phys_page1 == phys_page1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
|
|
||||||
target_ulong cs_base, uint32_t flags,
|
|
||||||
uint32_t cflags)
|
|
||||||
{
|
|
||||||
tb_page_addr_t phys_pc;
|
|
||||||
struct tb_desc desc;
|
|
||||||
uint32_t h;
|
|
||||||
|
|
||||||
desc.env = cpu->env_ptr;
|
|
||||||
desc.cs_base = cs_base;
|
|
||||||
desc.flags = flags;
|
|
||||||
desc.cflags = cflags;
|
|
||||||
desc.trace_vcpu_dstate = *cpu->trace_dstate;
|
|
||||||
desc.pc = pc;
|
|
||||||
phys_pc = get_page_addr_code(desc.env, pc);
|
|
||||||
if (phys_pc == -1) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
desc.page_addr0 = phys_pc;
|
|
||||||
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : pc),
|
|
||||||
flags, cflags, *cpu->trace_dstate);
|
|
||||||
return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Might cause an exception, so have a longjmp destination ready */
|
/* Might cause an exception, so have a longjmp destination ready */
|
||||||
static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
|
static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
|
||||||
target_ulong cs_base,
|
target_ulong cs_base,
|
||||||
uint32_t flags, uint32_t cflags)
|
uint32_t flags, uint32_t cflags)
|
||||||
{
|
{
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
CPUJumpCache *jc;
|
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
|
||||||
/* we should never be trying to look up an INVALID tb */
|
/* we should never be trying to look up an INVALID tb */
|
||||||
tcg_debug_assert(!(cflags & CF_INVALID));
|
tcg_debug_assert(!(cflags & CF_INVALID));
|
||||||
|
|
||||||
hash = tb_jmp_cache_hash_func(pc);
|
hash = tb_jmp_cache_hash_func(pc);
|
||||||
jc = cpu->tb_jmp_cache;
|
tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash]);
|
||||||
tb = tb_jmp_cache_get_tb(jc, hash);
|
|
||||||
|
|
||||||
if (likely(tb &&
|
if (likely(tb &&
|
||||||
tb_jmp_cache_get_pc(jc, hash, tb) == pc &&
|
tb->pc == pc &&
|
||||||
tb->cs_base == cs_base &&
|
tb->cs_base == cs_base &&
|
||||||
tb->flags == flags &&
|
tb->flags == flags &&
|
||||||
tb->trace_vcpu_dstate == *cpu->trace_dstate &&
|
tb->trace_vcpu_dstate == *cpu->trace_dstate &&
|
||||||
@ -271,14 +193,16 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc,
|
|||||||
if (tb == NULL) {
|
if (tb == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
tb_jmp_cache_set(jc, hash, tb, pc);
|
qatomic_set(&cpu->tb_jmp_cache[hash], tb);
|
||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_cpu_exec(target_ulong pc, CPUState *cpu,
|
static inline void log_cpu_exec(target_ulong pc, CPUState *cpu,
|
||||||
const TranslationBlock *tb)
|
const TranslationBlock *tb)
|
||||||
{
|
{
|
||||||
if (qemu_log_in_addr_range(pc)) {
|
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC))
|
||||||
|
&& qemu_log_in_addr_range(pc)) {
|
||||||
|
|
||||||
qemu_log_mask(CPU_LOG_EXEC,
|
qemu_log_mask(CPU_LOG_EXEC,
|
||||||
"Trace %d: %p [" TARGET_FMT_lx
|
"Trace %d: %p [" TARGET_FMT_lx
|
||||||
"/" TARGET_FMT_lx "/%08x/%08x] %s\n",
|
"/" TARGET_FMT_lx "/%08x/%08x] %s\n",
|
||||||
@ -287,30 +211,32 @@ static void log_cpu_exec(target_ulong pc, CPUState *cpu,
|
|||||||
|
|
||||||
#if defined(DEBUG_DISAS)
|
#if defined(DEBUG_DISAS)
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
|
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
|
||||||
FILE *logfile = qemu_log_trylock();
|
FILE *logfile = qemu_log_lock();
|
||||||
if (logfile) {
|
int flags = 0;
|
||||||
int flags = 0;
|
|
||||||
|
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
|
if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) {
|
||||||
flags |= CPU_DUMP_FPU;
|
flags |= CPU_DUMP_FPU;
|
||||||
}
|
|
||||||
#if defined(TARGET_I386)
|
|
||||||
flags |= CPU_DUMP_CCOP;
|
|
||||||
#endif
|
|
||||||
cpu_dump_state(cpu, logfile, flags);
|
|
||||||
qemu_log_unlock(logfile);
|
|
||||||
}
|
}
|
||||||
|
#if defined(TARGET_I386)
|
||||||
|
flags |= CPU_DUMP_CCOP;
|
||||||
|
#endif
|
||||||
|
log_cpu_state(cpu, flags);
|
||||||
|
qemu_log_unlock(logfile);
|
||||||
}
|
}
|
||||||
#endif /* DEBUG_DISAS */
|
#endif /* DEBUG_DISAS */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_for_breakpoints_slow(CPUState *cpu, target_ulong pc,
|
static bool check_for_breakpoints(CPUState *cpu, target_ulong pc,
|
||||||
uint32_t *cflags)
|
uint32_t *cflags)
|
||||||
{
|
{
|
||||||
CPUBreakpoint *bp;
|
CPUBreakpoint *bp;
|
||||||
bool match_page = false;
|
bool match_page = false;
|
||||||
|
|
||||||
|
if (likely(QTAILQ_EMPTY(&cpu->breakpoints))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Singlestep overrides breakpoints.
|
* Singlestep overrides breakpoints.
|
||||||
* This requirement is visible in the record-replay tests, where
|
* This requirement is visible in the record-replay tests, where
|
||||||
@ -371,13 +297,6 @@ static bool check_for_breakpoints_slow(CPUState *cpu, target_ulong pc,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool check_for_breakpoints(CPUState *cpu, target_ulong pc,
|
|
||||||
uint32_t *cflags)
|
|
||||||
{
|
|
||||||
return unlikely(!QTAILQ_EMPTY(&cpu->breakpoints)) &&
|
|
||||||
check_for_breakpoints_slow(cpu, pc, cflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* helper_lookup_tb_ptr: quick check for next tb
|
* helper_lookup_tb_ptr: quick check for next tb
|
||||||
* @env: current cpu state
|
* @env: current cpu state
|
||||||
@ -405,9 +324,7 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
|||||||
return tcg_code_gen_epilogue;
|
return tcg_code_gen_epilogue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC)) {
|
log_cpu_exec(pc, cpu, tb);
|
||||||
log_cpu_exec(pc, cpu, tb);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tb->tc.ptr;
|
return tb->tc.ptr;
|
||||||
}
|
}
|
||||||
@ -430,9 +347,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
|||||||
TranslationBlock *last_tb;
|
TranslationBlock *last_tb;
|
||||||
const void *tb_ptr = itb->tc.ptr;
|
const void *tb_ptr = itb->tc.ptr;
|
||||||
|
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC)) {
|
log_cpu_exec(itb->pc, cpu, itb);
|
||||||
log_cpu_exec(log_pc(cpu, itb), cpu, itb);
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_thread_jit_execute();
|
qemu_thread_jit_execute();
|
||||||
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
||||||
@ -456,34 +371,18 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
|||||||
* of the start of the TB.
|
* of the start of the TB.
|
||||||
*/
|
*/
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
|
qemu_log_mask_and_addr(CPU_LOG_EXEC, last_tb->pc,
|
||||||
|
"Stopped execution of TB chain before %p ["
|
||||||
|
TARGET_FMT_lx "] %s\n",
|
||||||
|
last_tb->tc.ptr, last_tb->pc,
|
||||||
|
lookup_symbol(last_tb->pc));
|
||||||
if (cc->tcg_ops->synchronize_from_tb) {
|
if (cc->tcg_ops->synchronize_from_tb) {
|
||||||
cc->tcg_ops->synchronize_from_tb(cpu, last_tb);
|
cc->tcg_ops->synchronize_from_tb(cpu, last_tb);
|
||||||
} else {
|
} else {
|
||||||
assert(!TARGET_TB_PCREL);
|
|
||||||
assert(cc->set_pc);
|
assert(cc->set_pc);
|
||||||
cc->set_pc(cpu, tb_pc(last_tb));
|
cc->set_pc(cpu, last_tb->pc);
|
||||||
}
|
|
||||||
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
|
|
||||||
target_ulong pc = log_pc(cpu, last_tb);
|
|
||||||
if (qemu_log_in_addr_range(pc)) {
|
|
||||||
qemu_log("Stopped execution of TB chain before %p ["
|
|
||||||
TARGET_FMT_lx "] %s\n",
|
|
||||||
last_tb->tc.ptr, pc, lookup_symbol(pc));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If gdb single-step, and we haven't raised another exception,
|
|
||||||
* raise a debug exception. Single-step with another exception
|
|
||||||
* is handled in cpu_handle_exception.
|
|
||||||
*/
|
|
||||||
if (unlikely(cpu->singlestep_enabled) && cpu->exception_index == -1) {
|
|
||||||
cpu->exception_index = EXCP_DEBUG;
|
|
||||||
cpu_loop_exit(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
return last_tb;
|
return last_tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,7 +407,7 @@ static void cpu_exec_exit(CPUState *cpu)
|
|||||||
|
|
||||||
void cpu_exec_step_atomic(CPUState *cpu)
|
void cpu_exec_step_atomic(CPUState *cpu)
|
||||||
{
|
{
|
||||||
CPUArchState *env = cpu->env_ptr;
|
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
target_ulong cs_base, pc;
|
target_ulong cs_base, pc;
|
||||||
uint32_t flags, cflags;
|
uint32_t flags, cflags;
|
||||||
@ -547,11 +446,12 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||||||
cpu_tb_exec(cpu, tb, &tb_exit);
|
cpu_tb_exec(cpu, tb, &tb_exit);
|
||||||
cpu_exec_exit(cpu);
|
cpu_exec_exit(cpu);
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
* The mmap_lock is dropped by tb_gen_code if it runs out of
|
||||||
|
* memory.
|
||||||
|
*/
|
||||||
#ifndef CONFIG_SOFTMMU
|
#ifndef CONFIG_SOFTMMU
|
||||||
clear_helper_retaddr();
|
tcg_debug_assert(!have_mmap_lock());
|
||||||
if (have_mmap_lock()) {
|
|
||||||
mmap_unlock();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (qemu_mutex_iothread_locked()) {
|
if (qemu_mutex_iothread_locked()) {
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
@ -560,6 +460,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||||||
qemu_plugin_disable_mem_helpers(cpu);
|
qemu_plugin_disable_mem_helpers(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As we start the exclusive region before codegen we must still
|
* As we start the exclusive region before codegen we must still
|
||||||
* be in the region if we longjump out of either the codegen or
|
* be in the region if we longjump out of either the codegen or
|
||||||
@ -570,6 +471,67 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||||||
end_exclusive();
|
end_exclusive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tb_desc {
|
||||||
|
target_ulong pc;
|
||||||
|
target_ulong cs_base;
|
||||||
|
CPUArchState *env;
|
||||||
|
tb_page_addr_t phys_page1;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t cflags;
|
||||||
|
uint32_t trace_vcpu_dstate;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool tb_lookup_cmp(const void *p, const void *d)
|
||||||
|
{
|
||||||
|
const TranslationBlock *tb = p;
|
||||||
|
const struct tb_desc *desc = d;
|
||||||
|
|
||||||
|
if (tb->pc == desc->pc &&
|
||||||
|
tb->page_addr[0] == desc->phys_page1 &&
|
||||||
|
tb->cs_base == desc->cs_base &&
|
||||||
|
tb->flags == desc->flags &&
|
||||||
|
tb->trace_vcpu_dstate == desc->trace_vcpu_dstate &&
|
||||||
|
tb_cflags(tb) == desc->cflags) {
|
||||||
|
/* check next page if needed */
|
||||||
|
if (tb->page_addr[1] == -1) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
tb_page_addr_t phys_page2;
|
||||||
|
target_ulong virt_page2;
|
||||||
|
|
||||||
|
virt_page2 = (desc->pc & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||||
|
phys_page2 = get_page_addr_code(desc->env, virt_page2);
|
||||||
|
if (tb->page_addr[1] == phys_page2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
|
||||||
|
target_ulong cs_base, uint32_t flags,
|
||||||
|
uint32_t cflags)
|
||||||
|
{
|
||||||
|
tb_page_addr_t phys_pc;
|
||||||
|
struct tb_desc desc;
|
||||||
|
uint32_t h;
|
||||||
|
|
||||||
|
desc.env = (CPUArchState *)cpu->env_ptr;
|
||||||
|
desc.cs_base = cs_base;
|
||||||
|
desc.flags = flags;
|
||||||
|
desc.cflags = cflags;
|
||||||
|
desc.trace_vcpu_dstate = *cpu->trace_dstate;
|
||||||
|
desc.pc = pc;
|
||||||
|
phys_pc = get_page_addr_code(desc.env, pc);
|
||||||
|
if (phys_pc == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
desc.phys_page1 = phys_pc & TARGET_PAGE_MASK;
|
||||||
|
h = tb_hash_func(phys_pc, pc, flags, cflags, *cpu->trace_dstate);
|
||||||
|
return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
|
||||||
|
}
|
||||||
|
|
||||||
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
|
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
|
||||||
{
|
{
|
||||||
if (TCG_TARGET_HAS_direct_jump) {
|
if (TCG_TARGET_HAS_direct_jump) {
|
||||||
@ -612,8 +574,11 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
|||||||
|
|
||||||
qemu_spin_unlock(&tb_next->jmp_lock);
|
qemu_spin_unlock(&tb_next->jmp_lock);
|
||||||
|
|
||||||
qemu_log_mask(CPU_LOG_EXEC, "Linking TBs %p index %d -> %p\n",
|
qemu_log_mask_and_addr(CPU_LOG_EXEC, tb->pc,
|
||||||
tb->tc.ptr, n, tb_next->tc.ptr);
|
"Linking TBs %p [" TARGET_FMT_lx
|
||||||
|
"] index %d -> %p [" TARGET_FMT_lx "]\n",
|
||||||
|
tb->tc.ptr, tb->pc, n,
|
||||||
|
tb_next->tc.ptr, tb_next->pc);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
out_unlock_next:
|
out_unlock_next:
|
||||||
@ -623,9 +588,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
|||||||
|
|
||||||
static inline bool cpu_handle_halt(CPUState *cpu)
|
static inline bool cpu_handle_halt(CPUState *cpu)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
if (cpu->halted) {
|
if (cpu->halted) {
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||||
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
|
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
|
||||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
@ -633,14 +597,13 @@ static inline bool cpu_handle_halt(CPUState *cpu)
|
|||||||
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
|
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
}
|
}
|
||||||
#endif /* TARGET_I386 */
|
#endif
|
||||||
if (!cpu_has_work(cpu)) {
|
if (!cpu_has_work(cpu)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->halted = 0;
|
cpu->halted = 0;
|
||||||
}
|
}
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -661,12 +624,6 @@ static inline void cpu_handle_debug_exception(CPUState *cpu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
|
||||||
|
|
||||||
void libafl_sync_breakpoint_cpu(void);
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
|
||||||
|
|
||||||
static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||||
{
|
{
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
@ -676,8 +633,6 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||||||
if (cpu->exception_index == EXCP_LIBAFL_BP) {
|
if (cpu->exception_index == EXCP_LIBAFL_BP) {
|
||||||
*ret = cpu->exception_index;
|
*ret = cpu->exception_index;
|
||||||
cpu->exception_index = -1;
|
cpu->exception_index = -1;
|
||||||
|
|
||||||
libafl_sync_breakpoint_cpu();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -688,8 +643,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||||||
if (replay_has_exception()
|
if (replay_has_exception()
|
||||||
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) {
|
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) {
|
||||||
/* Execute just one insn to trigger exception pending in the log */
|
/* Execute just one insn to trigger exception pending in the log */
|
||||||
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT)
|
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT) | 1;
|
||||||
| CF_NOIRQ | 1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
@ -709,8 +663,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||||||
loop */
|
loop */
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
cc->tcg_ops->fake_user_interrupt(cpu);
|
cc->tcg_ops->do_interrupt(cpu);
|
||||||
#endif /* TARGET_I386 */
|
#endif
|
||||||
*ret = cpu->exception_index;
|
*ret = cpu->exception_index;
|
||||||
cpu->exception_index = -1;
|
cpu->exception_index = -1;
|
||||||
return true;
|
return true;
|
||||||
@ -743,7 +697,6 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
/*
|
/*
|
||||||
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
|
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
|
||||||
* "real" interrupt event later. It does not need to be recorded for
|
* "real" interrupt event later. It does not need to be recorded for
|
||||||
@ -757,19 +710,11 @@ static inline bool need_replay_interrupt(int interrupt_request)
|
|||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
|
||||||
|
|
||||||
static inline bool cpu_handle_interrupt(CPUState *cpu,
|
static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||||
TranslationBlock **last_tb)
|
TranslationBlock **last_tb)
|
||||||
{
|
{
|
||||||
/*
|
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||||
* If we have requested custom cflags with CF_NOIRQ we should
|
|
||||||
* skip checking here. Any pending interrupts will get picked up
|
|
||||||
* by the next TB we execute under normal cflags.
|
|
||||||
*/
|
|
||||||
if (cpu->cflags_next_tb != -1 && cpu->cflags_next_tb & CF_NOIRQ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the interrupt flag now since we're processing
|
/* Clear the interrupt flag now since we're processing
|
||||||
* cpu->interrupt_request and cpu->exit_request.
|
* cpu->interrupt_request and cpu->exit_request.
|
||||||
@ -792,7 +737,6 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) {
|
if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) {
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
|
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
|
||||||
@ -821,14 +765,12 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif /* !TARGET_I386 */
|
#endif
|
||||||
/* The target hook has 3 exit conditions:
|
/* The target hook has 3 exit conditions:
|
||||||
False when the interrupt isn't processed,
|
False when the interrupt isn't processed,
|
||||||
True when it is, and we should restart on a new TB,
|
True when it is, and we should restart on a new TB,
|
||||||
and via longjmp via cpu_loop_exit. */
|
and via longjmp via cpu_loop_exit. */
|
||||||
else {
|
else {
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
|
||||||
|
|
||||||
if (cc->tcg_ops->cpu_exec_interrupt &&
|
if (cc->tcg_ops->cpu_exec_interrupt &&
|
||||||
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
|
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||||
if (need_replay_interrupt(interrupt_request)) {
|
if (need_replay_interrupt(interrupt_request)) {
|
||||||
@ -839,19 +781,14 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||||||
* raised when single-stepping so that GDB doesn't miss the
|
* raised when single-stepping so that GDB doesn't miss the
|
||||||
* next instruction.
|
* next instruction.
|
||||||
*/
|
*/
|
||||||
if (unlikely(cpu->singlestep_enabled)) {
|
cpu->exception_index =
|
||||||
cpu->exception_index = EXCP_DEBUG;
|
(cpu->singlestep_enabled ? EXCP_DEBUG : -1);
|
||||||
qemu_mutex_unlock_iothread();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
cpu->exception_index = -1;
|
|
||||||
*last_tb = NULL;
|
*last_tb = NULL;
|
||||||
}
|
}
|
||||||
/* The target hook may have updated the 'cpu->interrupt_request';
|
/* The target hook may have updated the 'cpu->interrupt_request';
|
||||||
* reload the 'interrupt_request' value */
|
* reload the 'interrupt_request' value */
|
||||||
interrupt_request = cpu->interrupt_request;
|
interrupt_request = cpu->interrupt_request;
|
||||||
}
|
}
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
|
||||||
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
|
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||||
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
||||||
/* ensure that no TB jump will be modified as
|
/* ensure that no TB jump will be modified as
|
||||||
@ -879,12 +816,11 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||||
target_ulong pc,
|
|
||||||
TranslationBlock **last_tb, int *tb_exit)
|
TranslationBlock **last_tb, int *tb_exit)
|
||||||
{
|
{
|
||||||
int32_t insns_left;
|
int32_t insns_left;
|
||||||
|
|
||||||
trace_exec_tb(tb, pc);
|
trace_exec_tb(tb, tb->pc);
|
||||||
tb = cpu_tb_exec(cpu, tb, tb_exit);
|
tb = cpu_tb_exec(cpu, tb, tb_exit);
|
||||||
if (*tb_exit != TB_EXIT_REQUESTED) {
|
if (*tb_exit != TB_EXIT_REQUESTED) {
|
||||||
*last_tb = tb;
|
*last_tb = tb;
|
||||||
@ -930,10 +866,9 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
|||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
|
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
|
||||||
target_ulong dst_block, int exit_n, target_ulong cs_base,
|
target_ulong dst_block, target_ulong cs_base,
|
||||||
uint32_t flags, int cflags);
|
uint32_t flags, int cflags);
|
||||||
|
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block);
|
||||||
extern __thread int libafl_valid_current_cpu;
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
@ -947,12 +882,6 @@ int cpu_exec(CPUState *cpu)
|
|||||||
/* replay_interrupt may need current_cpu */
|
/* replay_interrupt may need current_cpu */
|
||||||
current_cpu = cpu;
|
current_cpu = cpu;
|
||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
|
||||||
|
|
||||||
libafl_valid_current_cpu = 1;
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
|
||||||
|
|
||||||
if (cpu_handle_halt(cpu)) {
|
if (cpu_handle_halt(cpu)) {
|
||||||
return EXCP_HALTED;
|
return EXCP_HALTED;
|
||||||
}
|
}
|
||||||
@ -991,10 +920,7 @@ int cpu_exec(CPUState *cpu)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_SOFTMMU
|
#ifndef CONFIG_SOFTMMU
|
||||||
clear_helper_retaddr();
|
tcg_debug_assert(!have_mmap_lock());
|
||||||
if (have_mmap_lock()) {
|
|
||||||
mmap_unlock();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (qemu_mutex_iothread_locked()) {
|
if (qemu_mutex_iothread_locked()) {
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
@ -1036,8 +962,6 @@ int cpu_exec(CPUState *cpu)
|
|||||||
|
|
||||||
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
||||||
if (tb == NULL) {
|
if (tb == NULL) {
|
||||||
uint32_t h;
|
|
||||||
|
|
||||||
mmap_lock();
|
mmap_lock();
|
||||||
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
@ -1045,9 +969,14 @@ int cpu_exec(CPUState *cpu)
|
|||||||
* We add the TB in the virtual pc hash table
|
* We add the TB in the virtual pc hash table
|
||||||
* for the fast lookup
|
* for the fast lookup
|
||||||
*/
|
*/
|
||||||
h = tb_jmp_cache_hash_func(pc);
|
qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
|
||||||
tb_jmp_cache_set(cpu->tb_jmp_cache, h, tb, pc);
|
|
||||||
}
|
}
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
// This will save an edge (0,pc) after interrupts
|
||||||
|
// if (!last_tb) {
|
||||||
|
// libafl_exec_edge_one_off(0, tb->pc);
|
||||||
|
// }
|
||||||
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
/*
|
/*
|
||||||
@ -1056,7 +985,7 @@ int cpu_exec(CPUState *cpu)
|
|||||||
* direct jump to a TB spanning two pages because the mapping
|
* direct jump to a TB spanning two pages because the mapping
|
||||||
* for the second page can change.
|
* for the second page can change.
|
||||||
*/
|
*/
|
||||||
if (tb_page_addr1(tb) != -1) {
|
if (tb->page_addr[1] != -1) {
|
||||||
last_tb = NULL;
|
last_tb = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1066,11 +995,10 @@ int cpu_exec(CPUState *cpu)
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
#if !TARGET_TB_PCREL
|
|
||||||
if (last_tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
|
if (last_tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
|
||||||
mmap_lock();
|
mmap_lock();
|
||||||
TranslationBlock *edge = libafl_gen_edge(cpu, tb_pc(last_tb), tb_pc(tb),
|
TranslationBlock *edge = libafl_gen_edge(cpu, last_tb->pc, tb->pc,
|
||||||
tb_exit, cs_base, flags, cflags);
|
cs_base, flags, cflags);
|
||||||
mmap_unlock();
|
mmap_unlock();
|
||||||
|
|
||||||
if (edge) {
|
if (edge) {
|
||||||
@ -1082,15 +1010,11 @@ int cpu_exec(CPUState *cpu)
|
|||||||
} else {
|
} else {
|
||||||
tb_add_jump(last_tb, tb_exit, tb);
|
tb_add_jump(last_tb, tb_exit, tb);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
// No party if TARGET_TB_PCREL is 1
|
|
||||||
tb_add_jump(last_tb, tb_exit, tb);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_loop_exec_tb(cpu, tb, pc, &last_tb, &tb_exit);
|
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit);
|
||||||
|
|
||||||
/* 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 */
|
||||||
@ -1113,106 +1037,44 @@ void tcg_exec_realizefn(CPUState *cpu, Error **errp)
|
|||||||
cc->tcg_ops->initialize();
|
cc->tcg_ops->initialize();
|
||||||
tcg_target_initialized = true;
|
tcg_target_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->tb_jmp_cache = g_new0(CPUJumpCache, 1);
|
|
||||||
tlb_init(cpu);
|
tlb_init(cpu);
|
||||||
|
qemu_plugin_vcpu_init_hook(cpu);
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
tcg_iommu_init_notifier_list(cpu);
|
tcg_iommu_init_notifier_list(cpu);
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
/* qemu_plugin_vcpu_init_hook delayed until cpu_index assigned. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* undo the initializations in reverse order */
|
/* undo the initializations in reverse order */
|
||||||
void tcg_exec_unrealizefn(CPUState *cpu)
|
void tcg_exec_unrealizefn(CPUState *cpu)
|
||||||
{
|
{
|
||||||
qemu_plugin_vcpu_exit_hook(cpu);
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
tcg_iommu_free_notifier_list(cpu);
|
tcg_iommu_free_notifier_list(cpu);
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
|
|
||||||
|
qemu_plugin_vcpu_exit_hook(cpu);
|
||||||
tlb_destroy(cpu);
|
tlb_destroy(cpu);
|
||||||
g_free(cpu->tb_jmp_cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
|
||||||
static void dump_drift_info(GString *buf)
|
void dump_drift_info(void)
|
||||||
{
|
{
|
||||||
if (!icount_enabled()) {
|
if (!icount_enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_string_append_printf(buf, "Host - Guest clock %"PRIi64" ms\n",
|
qemu_printf("Host - Guest clock %"PRIi64" ms\n",
|
||||||
(cpu_get_clock() - icount_get()) / SCALE_MS);
|
(cpu_get_clock() - icount_get()) / SCALE_MS);
|
||||||
if (icount_align_option) {
|
if (icount_align_option) {
|
||||||
g_string_append_printf(buf, "Max guest delay %"PRIi64" ms\n",
|
qemu_printf("Max guest delay %"PRIi64" ms\n",
|
||||||
-max_delay / SCALE_MS);
|
-max_delay / SCALE_MS);
|
||||||
g_string_append_printf(buf, "Max guest advance %"PRIi64" ms\n",
|
qemu_printf("Max guest advance %"PRIi64" ms\n",
|
||||||
max_advance / SCALE_MS);
|
max_advance / SCALE_MS);
|
||||||
} else {
|
} else {
|
||||||
g_string_append_printf(buf, "Max guest delay NA\n");
|
qemu_printf("Max guest delay NA\n");
|
||||||
g_string_append_printf(buf, "Max guest advance NA\n");
|
qemu_printf("Max guest advance NA\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HumanReadableText *qmp_x_query_jit(Error **errp)
|
|
||||||
{
|
|
||||||
g_autoptr(GString) buf = g_string_new("");
|
|
||||||
|
|
||||||
if (!tcg_enabled()) {
|
|
||||||
error_setg(errp, "JIT information is only available with accel=tcg");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dump_exec_info(buf);
|
|
||||||
dump_drift_info(buf);
|
|
||||||
|
|
||||||
return human_readable_text_from_str(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
HumanReadableText *qmp_x_query_opcount(Error **errp)
|
|
||||||
{
|
|
||||||
g_autoptr(GString) buf = g_string_new("");
|
|
||||||
|
|
||||||
if (!tcg_enabled()) {
|
|
||||||
error_setg(errp, "Opcode count information is only available with accel=tcg");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
tcg_dump_op_count(buf);
|
|
||||||
|
|
||||||
return human_readable_text_from_str(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_PROFILER
|
|
||||||
|
|
||||||
int64_t dev_time;
|
|
||||||
|
|
||||||
HumanReadableText *qmp_x_query_profile(Error **errp)
|
|
||||||
{
|
|
||||||
g_autoptr(GString) buf = g_string_new("");
|
|
||||||
static int64_t last_cpu_exec_time;
|
|
||||||
int64_t cpu_exec_time;
|
|
||||||
int64_t delta;
|
|
||||||
|
|
||||||
cpu_exec_time = tcg_cpu_exec_time();
|
|
||||||
delta = cpu_exec_time - last_cpu_exec_time;
|
|
||||||
|
|
||||||
g_string_append_printf(buf, "async time %" PRId64 " (%0.3f)\n",
|
|
||||||
dev_time, dev_time / (double)NANOSECONDS_PER_SECOND);
|
|
||||||
g_string_append_printf(buf, "qemu time %" PRId64 " (%0.3f)\n",
|
|
||||||
delta, delta / (double)NANOSECONDS_PER_SECOND);
|
|
||||||
last_cpu_exec_time = cpu_exec_time;
|
|
||||||
dev_time = 0;
|
|
||||||
|
|
||||||
return human_readable_text_from_str(buf);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
HumanReadableText *qmp_x_query_profile(Error **errp)
|
|
||||||
{
|
|
||||||
error_setg(errp, "Internal profiler not compiled");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !CONFIG_USER_ONLY */
|
#endif /* !CONFIG_USER_ONLY */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,29 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qapi/error.h"
|
|
||||||
#include "qapi/qapi-commands-machine.h"
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "monitor/monitor.h"
|
#include "monitor/monitor.h"
|
||||||
|
#include "sysemu/tcg.h"
|
||||||
|
|
||||||
|
static void hmp_info_jit(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
if (!tcg_enabled()) {
|
||||||
|
error_report("JIT information is only available with accel=tcg");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_exec_info();
|
||||||
|
dump_drift_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hmp_info_opcount(Monitor *mon, const QDict *qdict)
|
||||||
|
{
|
||||||
|
dump_opcount_info();
|
||||||
|
}
|
||||||
|
|
||||||
static void hmp_tcg_register(void)
|
static void hmp_tcg_register(void)
|
||||||
{
|
{
|
||||||
monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
|
monitor_register_hmp("jit", true, hmp_info_jit);
|
||||||
monitor_register_hmp_info_hrt("opcount", qmp_x_query_opcount);
|
monitor_register_hmp("opcount", true, hmp_info_opcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(hmp_tcg_register);
|
type_init(hmp_tcg_register);
|
||||||
|
@ -11,112 +11,12 @@
|
|||||||
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Access to the various translations structures need to be serialised
|
|
||||||
* via locks for consistency. In user-mode emulation access to the
|
|
||||||
* memory related structures are protected with mmap_lock.
|
|
||||||
* In !user-mode we use per-page locks.
|
|
||||||
*/
|
|
||||||
#ifdef CONFIG_SOFTMMU
|
|
||||||
#define assert_memory_lock()
|
|
||||||
#else
|
|
||||||
#define assert_memory_lock() tcg_debug_assert(have_mmap_lock())
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct PageDesc {
|
|
||||||
/* list of TBs intersecting this ram page */
|
|
||||||
uintptr_t first_tb;
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
unsigned long flags;
|
|
||||||
void *target_data;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_SOFTMMU
|
|
||||||
QemuSpin lock;
|
|
||||||
#endif
|
|
||||||
} PageDesc;
|
|
||||||
|
|
||||||
/* Size of the L2 (and L3, etc) page tables. */
|
|
||||||
#define V_L2_BITS 10
|
|
||||||
#define V_L2_SIZE (1 << V_L2_BITS)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* L1 Mapping properties
|
|
||||||
*/
|
|
||||||
extern int v_l1_size;
|
|
||||||
extern int v_l1_shift;
|
|
||||||
extern int v_l2_levels;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The bottom level has pointers to PageDesc, and is indexed by
|
|
||||||
* anything from 4 to (V_L2_BITS + 3) bits, depending on target page size.
|
|
||||||
*/
|
|
||||||
#define V_L1_MIN_BITS 4
|
|
||||||
#define V_L1_MAX_BITS (V_L2_BITS + 3)
|
|
||||||
#define V_L1_MAX_SIZE (1 << V_L1_MAX_BITS)
|
|
||||||
|
|
||||||
extern void *l1_map[V_L1_MAX_SIZE];
|
|
||||||
|
|
||||||
PageDesc *page_find_alloc(tb_page_addr_t index, bool alloc);
|
|
||||||
|
|
||||||
static inline PageDesc *page_find(tb_page_addr_t index)
|
|
||||||
{
|
|
||||||
return page_find_alloc(index, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* list iterators for lists of tagged pointers in TranslationBlock */
|
|
||||||
#define TB_FOR_EACH_TAGGED(head, tb, n, field) \
|
|
||||||
for (n = (head) & 1, tb = (TranslationBlock *)((head) & ~1); \
|
|
||||||
tb; tb = (TranslationBlock *)tb->field[n], n = (uintptr_t)tb & 1, \
|
|
||||||
tb = (TranslationBlock *)((uintptr_t)tb & ~1))
|
|
||||||
|
|
||||||
#define PAGE_FOR_EACH_TB(pagedesc, tb, n) \
|
|
||||||
TB_FOR_EACH_TAGGED((pagedesc)->first_tb, tb, n, page_next)
|
|
||||||
|
|
||||||
#define TB_FOR_EACH_JMP(head_tb, tb, n) \
|
|
||||||
TB_FOR_EACH_TAGGED((head_tb)->jmp_list_head, tb, n, jmp_list_next)
|
|
||||||
|
|
||||||
/* In user-mode page locks aren't used; mmap_lock is enough */
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
#define assert_page_locked(pd) tcg_debug_assert(have_mmap_lock())
|
|
||||||
static inline void page_lock(PageDesc *pd) { }
|
|
||||||
static inline void page_unlock(PageDesc *pd) { }
|
|
||||||
#else
|
|
||||||
#ifdef CONFIG_DEBUG_TCG
|
|
||||||
void do_assert_page_locked(const PageDesc *pd, const char *file, int line);
|
|
||||||
#define assert_page_locked(pd) do_assert_page_locked(pd, __FILE__, __LINE__)
|
|
||||||
#else
|
|
||||||
#define assert_page_locked(pd)
|
|
||||||
#endif
|
|
||||||
void page_lock(PageDesc *pd);
|
|
||||||
void page_unlock(PageDesc *pd);
|
|
||||||
#endif
|
|
||||||
#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_DEBUG_TCG)
|
|
||||||
void assert_no_pages_locked(void);
|
|
||||||
#else
|
|
||||||
static inline void assert_no_pages_locked(void) { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc,
|
TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc,
|
||||||
target_ulong cs_base, uint32_t flags,
|
target_ulong cs_base, uint32_t flags,
|
||||||
int cflags);
|
int cflags);
|
||||||
G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr);
|
|
||||||
|
void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr);
|
||||||
void page_init(void);
|
void page_init(void);
|
||||||
void tb_htable_init(void);
|
void tb_htable_init(void);
|
||||||
void tb_reset_jump(TranslationBlock *tb, int n);
|
|
||||||
TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
|
||||||
tb_page_addr_t phys_page2);
|
|
||||||
bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc);
|
|
||||||
void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
|
||||||
uintptr_t host_pc);
|
|
||||||
|
|
||||||
/* Return the current PC from CPU, which may be cached in TB. */
|
|
||||||
static inline target_ulong log_pc(CPUState *cpu, const TranslationBlock *tb)
|
|
||||||
{
|
|
||||||
#if TARGET_TB_PCREL
|
|
||||||
return cpu->cc->get_pc(cpu);
|
|
||||||
#else
|
|
||||||
return tb_pc(tb);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* ACCEL_TCG_INTERNAL_H */
|
#endif /* ACCEL_TCG_INTERNAL_H */
|
||||||
|
@ -1,307 +0,0 @@
|
|||||||
/*
|
|
||||||
* Routines common to user and system emulation of load/store.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*
|
|
||||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
||||||
* See the COPYING file in the top-level directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
|
|
||||||
return cpu_ldb_mmu(env, addr, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return (int8_t)cpu_ldub_mmuidx_ra(env, addr, mmu_idx, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
|
|
||||||
return cpu_ldw_be_mmu(env, addr, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return (int16_t)cpu_lduw_be_mmuidx_ra(env, addr, mmu_idx, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
|
|
||||||
return cpu_ldl_be_mmu(env, addr, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
|
|
||||||
return cpu_ldq_be_mmu(env, addr, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
|
|
||||||
return cpu_ldw_le_mmu(env, addr, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return (int16_t)cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
|
|
||||||
return cpu_ldl_le_mmu(env, addr, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
|
|
||||||
return cpu_ldq_le_mmu(env, addr, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
|
|
||||||
cpu_stb_mmu(env, addr, val, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
|
|
||||||
cpu_stw_be_mmu(env, addr, val, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
|
|
||||||
cpu_stl_be_mmu(env, addr, val, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx);
|
|
||||||
cpu_stq_be_mmu(env, addr, val, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
|
|
||||||
cpu_stw_le_mmu(env, addr, val, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
|
|
||||||
cpu_stl_le_mmu(env, addr, val, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
|
|
||||||
int mmu_idx, uintptr_t ra)
|
|
||||||
{
|
|
||||||
MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx);
|
|
||||||
cpu_stq_le_mmu(env, addr, val, oi, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------*/
|
|
||||||
|
|
||||||
uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return cpu_ldub_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return (int8_t)cpu_ldub_data_ra(env, addr, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return cpu_lduw_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return (int16_t)cpu_lduw_be_data_ra(env, addr, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return cpu_ldl_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return cpu_ldq_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return cpu_lduw_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return (int16_t)cpu_lduw_le_data_ra(env, addr, ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return cpu_ldl_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
|
|
||||||
{
|
|
||||||
return cpu_ldq_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stb_data_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
uint32_t val, uintptr_t ra)
|
|
||||||
{
|
|
||||||
cpu_stb_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
uint32_t val, uintptr_t ra)
|
|
||||||
{
|
|
||||||
cpu_stw_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
uint32_t val, uintptr_t ra)
|
|
||||||
{
|
|
||||||
cpu_stl_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
uint64_t val, uintptr_t ra)
|
|
||||||
{
|
|
||||||
cpu_stq_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
uint32_t val, uintptr_t ra)
|
|
||||||
{
|
|
||||||
cpu_stw_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
uint32_t val, uintptr_t ra)
|
|
||||||
{
|
|
||||||
cpu_stl_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr addr,
|
|
||||||
uint64_t val, uintptr_t ra)
|
|
||||||
{
|
|
||||||
cpu_stq_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------*/
|
|
||||||
|
|
||||||
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return cpu_ldub_data_ra(env, addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsb_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return (int8_t)cpu_ldub_data(env, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return cpu_lduw_be_data_ra(env, addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsw_be_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return (int16_t)cpu_lduw_be_data(env, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return cpu_ldl_be_data_ra(env, addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return cpu_ldq_be_data_ra(env, addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return cpu_lduw_le_data_ra(env, addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_ldsw_le_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return (int16_t)cpu_lduw_le_data(env, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return cpu_ldl_le_data_ra(env, addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr addr)
|
|
||||||
{
|
|
||||||
return cpu_ldq_le_data_ra(env, addr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stb_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
|
||||||
{
|
|
||||||
cpu_stb_data_ra(env, addr, val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stw_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
|
||||||
{
|
|
||||||
cpu_stw_be_data_ra(env, addr, val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stl_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
|
||||||
{
|
|
||||||
cpu_stl_be_data_ra(env, addr, val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stq_be_data(CPUArchState *env, abi_ptr addr, uint64_t val)
|
|
||||||
{
|
|
||||||
cpu_stq_be_data_ra(env, addr, val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stw_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
|
||||||
{
|
|
||||||
cpu_stw_le_data_ra(env, addr, val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stl_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
|
|
||||||
{
|
|
||||||
cpu_stl_le_data_ra(env, addr, val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_stq_le_data(CPUArchState *env, abi_ptr addr, uint64_t val)
|
|
||||||
{
|
|
||||||
cpu_stq_le_data_ra(env, addr, val, 0);
|
|
||||||
}
|
|
@ -3,7 +3,6 @@ tcg_ss.add(files(
|
|||||||
'tcg-all.c',
|
'tcg-all.c',
|
||||||
'cpu-exec-common.c',
|
'cpu-exec-common.c',
|
||||||
'cpu-exec.c',
|
'cpu-exec.c',
|
||||||
'tb-maint.c',
|
|
||||||
'tcg-runtime-gvec.c',
|
'tcg-runtime-gvec.c',
|
||||||
'tcg-runtime.c',
|
'tcg-runtime.c',
|
||||||
'translate-all.c',
|
'translate-all.c',
|
||||||
@ -11,7 +10,7 @@ tcg_ss.add(files(
|
|||||||
))
|
))
|
||||||
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
|
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
|
||||||
tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c'))
|
tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c'))
|
||||||
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c')])
|
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c'), libdl])
|
||||||
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
||||||
|
|
||||||
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
|
#include "trace/mem.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/plugin-gen.h"
|
#include "exec/plugin-gen.h"
|
||||||
#include "exec/translator.h"
|
#include "exec/translator.h"
|
||||||
@ -162,7 +163,11 @@ static void gen_empty_mem_helper(void)
|
|||||||
static void gen_plugin_cb_start(enum plugin_gen_from from,
|
static void gen_plugin_cb_start(enum plugin_gen_from from,
|
||||||
enum plugin_gen_cb type, unsigned wr)
|
enum plugin_gen_cb type, unsigned wr)
|
||||||
{
|
{
|
||||||
|
TCGOp *op;
|
||||||
|
|
||||||
tcg_gen_plugin_cb_start(from, type, wr);
|
tcg_gen_plugin_cb_start(from, type, wr);
|
||||||
|
op = tcg_last_op();
|
||||||
|
QSIMPLEQ_INSERT_TAIL(&tcg_ctx->plugin_ops, op, plugin_link);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_wrapped(enum plugin_gen_from from,
|
static void gen_wrapped(enum plugin_gen_from from,
|
||||||
@ -206,9 +211,9 @@ static void gen_mem_wrapped(enum plugin_gen_cb type,
|
|||||||
const union mem_gen_fn *f, TCGv addr,
|
const union mem_gen_fn *f, TCGv addr,
|
||||||
uint32_t info, bool is_mem)
|
uint32_t info, bool is_mem)
|
||||||
{
|
{
|
||||||
enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
|
int wr = !!(info & TRACE_MEM_ST);
|
||||||
|
|
||||||
gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, rw);
|
gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, wr);
|
||||||
if (is_mem) {
|
if (is_mem) {
|
||||||
f->mem_fn(addr, info);
|
f->mem_fn(addr, info);
|
||||||
} else {
|
} else {
|
||||||
@ -702,6 +707,62 @@ static void plugin_gen_disable_mem_helper(const struct qemu_plugin_tb *ptb,
|
|||||||
inject_mem_disable_helper(insn, begin_op);
|
inject_mem_disable_helper(insn, begin_op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void plugin_inject_cb(const struct qemu_plugin_tb *ptb, TCGOp *begin_op,
|
||||||
|
int insn_idx)
|
||||||
|
{
|
||||||
|
enum plugin_gen_from from = begin_op->args[0];
|
||||||
|
enum plugin_gen_cb type = begin_op->args[1];
|
||||||
|
|
||||||
|
switch (from) {
|
||||||
|
case PLUGIN_GEN_FROM_TB:
|
||||||
|
switch (type) {
|
||||||
|
case PLUGIN_GEN_CB_UDATA:
|
||||||
|
plugin_gen_tb_udata(ptb, begin_op);
|
||||||
|
return;
|
||||||
|
case PLUGIN_GEN_CB_INLINE:
|
||||||
|
plugin_gen_tb_inline(ptb, begin_op);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
case PLUGIN_GEN_FROM_INSN:
|
||||||
|
switch (type) {
|
||||||
|
case PLUGIN_GEN_CB_UDATA:
|
||||||
|
plugin_gen_insn_udata(ptb, begin_op, insn_idx);
|
||||||
|
return;
|
||||||
|
case PLUGIN_GEN_CB_INLINE:
|
||||||
|
plugin_gen_insn_inline(ptb, begin_op, insn_idx);
|
||||||
|
return;
|
||||||
|
case PLUGIN_GEN_ENABLE_MEM_HELPER:
|
||||||
|
plugin_gen_enable_mem_helper(ptb, begin_op, insn_idx);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
case PLUGIN_GEN_FROM_MEM:
|
||||||
|
switch (type) {
|
||||||
|
case PLUGIN_GEN_CB_MEM:
|
||||||
|
plugin_gen_mem_regular(ptb, begin_op, insn_idx);
|
||||||
|
return;
|
||||||
|
case PLUGIN_GEN_CB_INLINE:
|
||||||
|
plugin_gen_mem_inline(ptb, begin_op, insn_idx);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
case PLUGIN_GEN_AFTER_INSN:
|
||||||
|
switch (type) {
|
||||||
|
case PLUGIN_GEN_DISABLE_MEM_HELPER:
|
||||||
|
plugin_gen_disable_mem_helper(ptb, begin_op, insn_idx);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* #define DEBUG_PLUGIN_GEN_OPS */
|
/* #define DEBUG_PLUGIN_GEN_OPS */
|
||||||
static void pr_ops(void)
|
static void pr_ops(void)
|
||||||
{
|
{
|
||||||
@ -759,129 +820,42 @@ static void pr_ops(void)
|
|||||||
static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
|
static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
|
||||||
{
|
{
|
||||||
TCGOp *op;
|
TCGOp *op;
|
||||||
int insn_idx = -1;
|
int insn_idx;
|
||||||
|
|
||||||
pr_ops();
|
pr_ops();
|
||||||
|
insn_idx = -1;
|
||||||
|
QSIMPLEQ_FOREACH(op, &tcg_ctx->plugin_ops, plugin_link) {
|
||||||
|
enum plugin_gen_from from = op->args[0];
|
||||||
|
enum plugin_gen_cb type = op->args[1];
|
||||||
|
|
||||||
QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
|
tcg_debug_assert(op->opc == INDEX_op_plugin_cb_start);
|
||||||
switch (op->opc) {
|
/* ENABLE_MEM_HELPER is the first callback of an instruction */
|
||||||
case INDEX_op_insn_start:
|
if (from == PLUGIN_GEN_FROM_INSN &&
|
||||||
|
type == PLUGIN_GEN_ENABLE_MEM_HELPER) {
|
||||||
insn_idx++;
|
insn_idx++;
|
||||||
break;
|
|
||||||
case INDEX_op_plugin_cb_start:
|
|
||||||
{
|
|
||||||
enum plugin_gen_from from = op->args[0];
|
|
||||||
enum plugin_gen_cb type = op->args[1];
|
|
||||||
|
|
||||||
switch (from) {
|
|
||||||
case PLUGIN_GEN_FROM_TB:
|
|
||||||
{
|
|
||||||
g_assert(insn_idx == -1);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case PLUGIN_GEN_CB_UDATA:
|
|
||||||
plugin_gen_tb_udata(plugin_tb, op);
|
|
||||||
break;
|
|
||||||
case PLUGIN_GEN_CB_INLINE:
|
|
||||||
plugin_gen_tb_inline(plugin_tb, op);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLUGIN_GEN_FROM_INSN:
|
|
||||||
{
|
|
||||||
g_assert(insn_idx >= 0);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case PLUGIN_GEN_CB_UDATA:
|
|
||||||
plugin_gen_insn_udata(plugin_tb, op, insn_idx);
|
|
||||||
break;
|
|
||||||
case PLUGIN_GEN_CB_INLINE:
|
|
||||||
plugin_gen_insn_inline(plugin_tb, op, insn_idx);
|
|
||||||
break;
|
|
||||||
case PLUGIN_GEN_ENABLE_MEM_HELPER:
|
|
||||||
plugin_gen_enable_mem_helper(plugin_tb, op, insn_idx);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLUGIN_GEN_FROM_MEM:
|
|
||||||
{
|
|
||||||
g_assert(insn_idx >= 0);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case PLUGIN_GEN_CB_MEM:
|
|
||||||
plugin_gen_mem_regular(plugin_tb, op, insn_idx);
|
|
||||||
break;
|
|
||||||
case PLUGIN_GEN_CB_INLINE:
|
|
||||||
plugin_gen_mem_inline(plugin_tb, op, insn_idx);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLUGIN_GEN_AFTER_INSN:
|
|
||||||
{
|
|
||||||
g_assert(insn_idx >= 0);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case PLUGIN_GEN_DISABLE_MEM_HELPER:
|
|
||||||
plugin_gen_disable_mem_helper(plugin_tb, op, insn_idx);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
/* plugins don't care about any other ops */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
plugin_inject_cb(plugin_tb, op, insn_idx);
|
||||||
}
|
}
|
||||||
pr_ops();
|
pr_ops();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
|
bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_only)
|
||||||
bool mem_only)
|
|
||||||
{
|
{
|
||||||
|
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) {
|
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) {
|
||||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* reset callbacks */
|
|
||||||
for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
|
|
||||||
if (ptb->cbs[i]) {
|
|
||||||
g_array_set_size(ptb->cbs[i], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ptb->n = 0;
|
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
ptb->vaddr = db->pc_first;
|
QSIMPLEQ_INIT(&tcg_ctx->plugin_ops);
|
||||||
|
ptb->vaddr = tb->pc;
|
||||||
ptb->vaddr2 = -1;
|
ptb->vaddr2 = -1;
|
||||||
ptb->haddr1 = db->host_addr[0];
|
get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1);
|
||||||
ptb->haddr2 = NULL;
|
ptb->haddr2 = NULL;
|
||||||
ptb->mem_only = mem_only;
|
ptb->mem_only = mem_only;
|
||||||
|
|
||||||
plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB);
|
plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB);
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_ctx->plugin_insn = NULL;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -890,8 +864,9 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
|
|||||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||||
struct qemu_plugin_insn *pinsn;
|
struct qemu_plugin_insn *pinsn;
|
||||||
|
|
||||||
pinsn = qemu_plugin_tb_insn_get(ptb, db->pc_next);
|
pinsn = qemu_plugin_tb_insn_get(ptb);
|
||||||
tcg_ctx->plugin_insn = pinsn;
|
tcg_ctx->plugin_insn = pinsn;
|
||||||
|
pinsn->vaddr = db->pc_next;
|
||||||
plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
|
plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -899,15 +874,16 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
|
|||||||
* Note that we skip this when haddr1 == NULL, e.g. when we're
|
* Note that we skip this when haddr1 == NULL, e.g. when we're
|
||||||
* fetching instructions from a region not backed by RAM.
|
* fetching instructions from a region not backed by RAM.
|
||||||
*/
|
*/
|
||||||
if (ptb->haddr1 == NULL) {
|
if (likely(ptb->haddr1 != NULL && ptb->vaddr2 == -1) &&
|
||||||
pinsn->haddr = NULL;
|
unlikely((db->pc_next & TARGET_PAGE_MASK) !=
|
||||||
} else if (is_same_page(db, db->pc_next)) {
|
(db->pc_first & TARGET_PAGE_MASK))) {
|
||||||
|
get_page_addr_code_hostp(cpu->env_ptr, db->pc_next,
|
||||||
|
&ptb->haddr2);
|
||||||
|
ptb->vaddr2 = db->pc_next;
|
||||||
|
}
|
||||||
|
if (likely(ptb->vaddr2 == -1)) {
|
||||||
pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr;
|
pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr;
|
||||||
} else {
|
} else {
|
||||||
if (ptb->vaddr2 == -1) {
|
|
||||||
ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first);
|
|
||||||
get_page_addr_code_hostp(cpu->env_ptr, ptb->vaddr2, &ptb->haddr2);
|
|
||||||
}
|
|
||||||
pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
|
pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -917,19 +893,23 @@ void plugin_gen_insn_end(void)
|
|||||||
plugin_gen_empty_callback(PLUGIN_GEN_AFTER_INSN);
|
plugin_gen_empty_callback(PLUGIN_GEN_AFTER_INSN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* There are cases where we never get to finalise a translation - for
|
|
||||||
* example a page fault during translation. As a result we shouldn't
|
|
||||||
* do any clean-up here and make sure things are reset in
|
|
||||||
* plugin_gen_tb_start.
|
|
||||||
*/
|
|
||||||
void plugin_gen_tb_end(CPUState *cpu)
|
void plugin_gen_tb_end(CPUState *cpu)
|
||||||
{
|
{
|
||||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* collect instrumentation requests */
|
/* collect instrumentation requests */
|
||||||
qemu_plugin_tb_trans_cb(cpu, ptb);
|
qemu_plugin_tb_trans_cb(cpu, ptb);
|
||||||
|
|
||||||
/* inject the instrumentation at the appropriate places */
|
/* inject the instrumentation at the appropriate places */
|
||||||
plugin_gen_inject(ptb);
|
plugin_gen_inject(ptb);
|
||||||
|
|
||||||
|
/* clean up */
|
||||||
|
for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
|
||||||
|
if (ptb->cbs[i]) {
|
||||||
|
g_array_set_size(ptb->cbs[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptb->n = 0;
|
||||||
|
tcg_ctx->plugin_insn = NULL;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "exec/cpu-defs.h"
|
#include "exec/cpu-defs.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "qemu/xxhash.h"
|
#include "qemu/xxhash.h"
|
||||||
#include "tb-jmp-cache.h"
|
|
||||||
|
|
||||||
#ifdef CONFIG_SOFTMMU
|
#ifdef CONFIG_SOFTMMU
|
||||||
|
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* The per-CPU TranslationBlock jump cache.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ACCEL_TCG_TB_JMP_CACHE_H
|
|
||||||
#define ACCEL_TCG_TB_JMP_CACHE_H
|
|
||||||
|
|
||||||
#define TB_JMP_CACHE_BITS 12
|
|
||||||
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Accessed in parallel; all accesses to 'tb' must be atomic.
|
|
||||||
* For TARGET_TB_PCREL, accesses to 'pc' must be protected by
|
|
||||||
* a load_acquire/store_release to 'tb'.
|
|
||||||
*/
|
|
||||||
struct CPUJumpCache {
|
|
||||||
struct {
|
|
||||||
TranslationBlock *tb;
|
|
||||||
#if TARGET_TB_PCREL
|
|
||||||
target_ulong pc;
|
|
||||||
#endif
|
|
||||||
} array[TB_JMP_CACHE_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline TranslationBlock *
|
|
||||||
tb_jmp_cache_get_tb(CPUJumpCache *jc, uint32_t hash)
|
|
||||||
{
|
|
||||||
#if TARGET_TB_PCREL
|
|
||||||
/* Use acquire to ensure current load of pc from jc. */
|
|
||||||
return qatomic_load_acquire(&jc->array[hash].tb);
|
|
||||||
#else
|
|
||||||
/* Use rcu_read to ensure current load of pc from *tb. */
|
|
||||||
return qatomic_rcu_read(&jc->array[hash].tb);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline target_ulong
|
|
||||||
tb_jmp_cache_get_pc(CPUJumpCache *jc, uint32_t hash, TranslationBlock *tb)
|
|
||||||
{
|
|
||||||
#if TARGET_TB_PCREL
|
|
||||||
return jc->array[hash].pc;
|
|
||||||
#else
|
|
||||||
return tb_pc(tb);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
tb_jmp_cache_set(CPUJumpCache *jc, uint32_t hash,
|
|
||||||
TranslationBlock *tb, target_ulong pc)
|
|
||||||
{
|
|
||||||
#if TARGET_TB_PCREL
|
|
||||||
jc->array[hash].pc = pc;
|
|
||||||
/* Use store_release on tb to ensure pc is written first. */
|
|
||||||
qatomic_store_release(&jc->array[hash].tb, tb);
|
|
||||||
#else
|
|
||||||
/* Use the pc value already stored in tb->pc. */
|
|
||||||
qatomic_set(&jc->array[hash].tb, tb);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* ACCEL_TCG_TB_JMP_CACHE_H */
|
|
@ -1,704 +0,0 @@
|
|||||||
/*
|
|
||||||
* Translation Block Maintaince
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include "exec/cputlb.h"
|
|
||||||
#include "exec/log.h"
|
|
||||||
#include "exec/exec-all.h"
|
|
||||||
#include "exec/translate-all.h"
|
|
||||||
#include "sysemu/tcg.h"
|
|
||||||
#include "tcg/tcg.h"
|
|
||||||
#include "tb-hash.h"
|
|
||||||
#include "tb-context.h"
|
|
||||||
#include "internal.h"
|
|
||||||
|
|
||||||
|
|
||||||
static bool tb_cmp(const void *ap, const void *bp)
|
|
||||||
{
|
|
||||||
const TranslationBlock *a = ap;
|
|
||||||
const TranslationBlock *b = bp;
|
|
||||||
|
|
||||||
return ((TARGET_TB_PCREL || tb_pc(a) == tb_pc(b)) &&
|
|
||||||
a->cs_base == b->cs_base &&
|
|
||||||
a->flags == b->flags &&
|
|
||||||
(tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) &&
|
|
||||||
a->trace_vcpu_dstate == b->trace_vcpu_dstate &&
|
|
||||||
tb_page_addr0(a) == tb_page_addr0(b) &&
|
|
||||||
tb_page_addr1(a) == tb_page_addr1(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
void tb_htable_init(void)
|
|
||||||
{
|
|
||||||
unsigned int mode = QHT_MODE_AUTO_RESIZE;
|
|
||||||
|
|
||||||
qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set to NULL all the 'first_tb' fields in all PageDescs. */
|
|
||||||
static void page_flush_tb_1(int level, void **lp)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (*lp == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (level == 0) {
|
|
||||||
PageDesc *pd = *lp;
|
|
||||||
|
|
||||||
for (i = 0; i < V_L2_SIZE; ++i) {
|
|
||||||
page_lock(&pd[i]);
|
|
||||||
pd[i].first_tb = (uintptr_t)NULL;
|
|
||||||
page_unlock(&pd[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
void **pp = *lp;
|
|
||||||
|
|
||||||
for (i = 0; i < V_L2_SIZE; ++i) {
|
|
||||||
page_flush_tb_1(level - 1, pp + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void page_flush_tb(void)
|
|
||||||
{
|
|
||||||
int i, l1_sz = v_l1_size;
|
|
||||||
|
|
||||||
for (i = 0; i < l1_sz; i++) {
|
|
||||||
page_flush_tb_1(v_l2_levels, l1_map + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flush all the translation blocks */
|
|
||||||
static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
|
|
||||||
{
|
|
||||||
bool did_flush = false;
|
|
||||||
|
|
||||||
mmap_lock();
|
|
||||||
/* If it is already been done on request of another CPU, just retry. */
|
|
||||||
if (tb_ctx.tb_flush_count != tb_flush_count.host_int) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
did_flush = true;
|
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
tcg_flush_jmp_cache(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
qht_reset_size(&tb_ctx.htable, CODE_GEN_HTABLE_SIZE);
|
|
||||||
page_flush_tb();
|
|
||||||
|
|
||||||
tcg_region_reset_all();
|
|
||||||
/* XXX: flush processor icache at this point if cache flush is expensive */
|
|
||||||
qatomic_mb_set(&tb_ctx.tb_flush_count, tb_ctx.tb_flush_count + 1);
|
|
||||||
|
|
||||||
done:
|
|
||||||
mmap_unlock();
|
|
||||||
if (did_flush) {
|
|
||||||
qemu_plugin_flush_cb();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tb_flush(CPUState *cpu)
|
|
||||||
{
|
|
||||||
if (tcg_enabled()) {
|
|
||||||
unsigned tb_flush_count = qatomic_mb_read(&tb_ctx.tb_flush_count);
|
|
||||||
|
|
||||||
if (cpu_in_exclusive_context(cpu)) {
|
|
||||||
do_tb_flush(cpu, RUN_ON_CPU_HOST_INT(tb_flush_count));
|
|
||||||
} else {
|
|
||||||
async_safe_run_on_cpu(cpu, do_tb_flush,
|
|
||||||
RUN_ON_CPU_HOST_INT(tb_flush_count));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* user-mode: call with mmap_lock held
|
|
||||||
* !user-mode: call with @pd->lock held
|
|
||||||
*/
|
|
||||||
static inline void tb_page_remove(PageDesc *pd, TranslationBlock *tb)
|
|
||||||
{
|
|
||||||
TranslationBlock *tb1;
|
|
||||||
uintptr_t *pprev;
|
|
||||||
unsigned int n1;
|
|
||||||
|
|
||||||
assert_page_locked(pd);
|
|
||||||
pprev = &pd->first_tb;
|
|
||||||
PAGE_FOR_EACH_TB(pd, tb1, n1) {
|
|
||||||
if (tb1 == tb) {
|
|
||||||
*pprev = tb1->page_next[n1];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pprev = &tb1->page_next[n1];
|
|
||||||
}
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove @orig from its @n_orig-th jump list */
|
|
||||||
static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig)
|
|
||||||
{
|
|
||||||
uintptr_t ptr, ptr_locked;
|
|
||||||
TranslationBlock *dest;
|
|
||||||
TranslationBlock *tb;
|
|
||||||
uintptr_t *pprev;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
/* mark the LSB of jmp_dest[] so that no further jumps can be inserted */
|
|
||||||
ptr = qatomic_or_fetch(&orig->jmp_dest[n_orig], 1);
|
|
||||||
dest = (TranslationBlock *)(ptr & ~1);
|
|
||||||
if (dest == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_spin_lock(&dest->jmp_lock);
|
|
||||||
/*
|
|
||||||
* While acquiring the lock, the jump might have been removed if the
|
|
||||||
* destination TB was invalidated; check again.
|
|
||||||
*/
|
|
||||||
ptr_locked = qatomic_read(&orig->jmp_dest[n_orig]);
|
|
||||||
if (ptr_locked != ptr) {
|
|
||||||
qemu_spin_unlock(&dest->jmp_lock);
|
|
||||||
/*
|
|
||||||
* The only possibility is that the jump was unlinked via
|
|
||||||
* tb_jump_unlink(dest). Seeing here another destination would be a bug,
|
|
||||||
* because we set the LSB above.
|
|
||||||
*/
|
|
||||||
g_assert(ptr_locked == 1 && dest->cflags & CF_INVALID);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* We first acquired the lock, and since the destination pointer matches,
|
|
||||||
* we know for sure that @orig is in the jmp list.
|
|
||||||
*/
|
|
||||||
pprev = &dest->jmp_list_head;
|
|
||||||
TB_FOR_EACH_JMP(dest, tb, n) {
|
|
||||||
if (tb == orig && n == n_orig) {
|
|
||||||
*pprev = tb->jmp_list_next[n];
|
|
||||||
/* no need to set orig->jmp_dest[n]; setting the LSB was enough */
|
|
||||||
qemu_spin_unlock(&dest->jmp_lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pprev = &tb->jmp_list_next[n];
|
|
||||||
}
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reset the jump entry 'n' of a TB so that it is not chained to another TB.
|
|
||||||
*/
|
|
||||||
void tb_reset_jump(TranslationBlock *tb, int n)
|
|
||||||
{
|
|
||||||
uintptr_t addr = (uintptr_t)(tb->tc.ptr + tb->jmp_reset_offset[n]);
|
|
||||||
tb_set_jmp_target(tb, n, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove any jumps to the TB */
|
|
||||||
static inline void tb_jmp_unlink(TranslationBlock *dest)
|
|
||||||
{
|
|
||||||
TranslationBlock *tb;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
qemu_spin_lock(&dest->jmp_lock);
|
|
||||||
|
|
||||||
TB_FOR_EACH_JMP(dest, tb, n) {
|
|
||||||
tb_reset_jump(tb, n);
|
|
||||||
qatomic_and(&tb->jmp_dest[n], (uintptr_t)NULL | 1);
|
|
||||||
/* No need to clear the list entry; setting the dest ptr is enough */
|
|
||||||
}
|
|
||||||
dest->jmp_list_head = (uintptr_t)NULL;
|
|
||||||
|
|
||||||
qemu_spin_unlock(&dest->jmp_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tb_jmp_cache_inval_tb(TranslationBlock *tb)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
|
|
||||||
if (TARGET_TB_PCREL) {
|
|
||||||
/* A TB may be at any virtual address */
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
tcg_flush_jmp_cache(cpu);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uint32_t h = tb_jmp_cache_hash_func(tb_pc(tb));
|
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
CPUJumpCache *jc = cpu->tb_jmp_cache;
|
|
||||||
|
|
||||||
if (qatomic_read(&jc->array[h].tb) == tb) {
|
|
||||||
qatomic_set(&jc->array[h].tb, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In user-mode, call with mmap_lock held.
|
|
||||||
* In !user-mode, if @rm_from_page_list is set, call with the TB's pages'
|
|
||||||
* locks held.
|
|
||||||
*/
|
|
||||||
static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
|
|
||||||
{
|
|
||||||
PageDesc *p;
|
|
||||||
uint32_t h;
|
|
||||||
tb_page_addr_t phys_pc;
|
|
||||||
uint32_t orig_cflags = tb_cflags(tb);
|
|
||||||
|
|
||||||
assert_memory_lock();
|
|
||||||
|
|
||||||
/* make sure no further incoming jumps will be chained to this TB */
|
|
||||||
qemu_spin_lock(&tb->jmp_lock);
|
|
||||||
qatomic_set(&tb->cflags, tb->cflags | CF_INVALID);
|
|
||||||
qemu_spin_unlock(&tb->jmp_lock);
|
|
||||||
|
|
||||||
/* remove the TB from the hash list */
|
|
||||||
phys_pc = tb_page_addr0(tb);
|
|
||||||
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : tb_pc(tb)),
|
|
||||||
tb->flags, orig_cflags, tb->trace_vcpu_dstate);
|
|
||||||
if (!qht_remove(&tb_ctx.htable, tb, h)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove the TB from the page list */
|
|
||||||
if (rm_from_page_list) {
|
|
||||||
p = page_find(phys_pc >> TARGET_PAGE_BITS);
|
|
||||||
tb_page_remove(p, tb);
|
|
||||||
phys_pc = tb_page_addr1(tb);
|
|
||||||
if (phys_pc != -1) {
|
|
||||||
p = page_find(phys_pc >> TARGET_PAGE_BITS);
|
|
||||||
tb_page_remove(p, tb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove the TB from the hash list */
|
|
||||||
tb_jmp_cache_inval_tb(tb);
|
|
||||||
|
|
||||||
/* suppress this TB from the two jump lists */
|
|
||||||
tb_remove_from_jmp_list(tb, 0);
|
|
||||||
tb_remove_from_jmp_list(tb, 1);
|
|
||||||
|
|
||||||
/* suppress any remaining jumps to this TB */
|
|
||||||
tb_jmp_unlink(tb);
|
|
||||||
|
|
||||||
qatomic_set(&tb_ctx.tb_phys_invalidate_count,
|
|
||||||
tb_ctx.tb_phys_invalidate_count + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tb_phys_invalidate__locked(TranslationBlock *tb)
|
|
||||||
{
|
|
||||||
qemu_thread_jit_write();
|
|
||||||
do_tb_phys_invalidate(tb, true);
|
|
||||||
qemu_thread_jit_execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
|
|
||||||
PageDesc **ret_p2, tb_page_addr_t phys2, bool alloc)
|
|
||||||
{
|
|
||||||
PageDesc *p1, *p2;
|
|
||||||
tb_page_addr_t page1;
|
|
||||||
tb_page_addr_t page2;
|
|
||||||
|
|
||||||
assert_memory_lock();
|
|
||||||
g_assert(phys1 != -1);
|
|
||||||
|
|
||||||
page1 = phys1 >> TARGET_PAGE_BITS;
|
|
||||||
page2 = phys2 >> TARGET_PAGE_BITS;
|
|
||||||
|
|
||||||
p1 = page_find_alloc(page1, alloc);
|
|
||||||
if (ret_p1) {
|
|
||||||
*ret_p1 = p1;
|
|
||||||
}
|
|
||||||
if (likely(phys2 == -1)) {
|
|
||||||
page_lock(p1);
|
|
||||||
return;
|
|
||||||
} else if (page1 == page2) {
|
|
||||||
page_lock(p1);
|
|
||||||
if (ret_p2) {
|
|
||||||
*ret_p2 = p1;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p2 = page_find_alloc(page2, alloc);
|
|
||||||
if (ret_p2) {
|
|
||||||
*ret_p2 = p2;
|
|
||||||
}
|
|
||||||
if (page1 < page2) {
|
|
||||||
page_lock(p1);
|
|
||||||
page_lock(p2);
|
|
||||||
} else {
|
|
||||||
page_lock(p2);
|
|
||||||
page_lock(p1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
static inline void page_lock_tb(const TranslationBlock *tb) { }
|
|
||||||
static inline void page_unlock_tb(const TranslationBlock *tb) { }
|
|
||||||
#else
|
|
||||||
/* lock the page(s) of a TB in the correct acquisition order */
|
|
||||||
static void page_lock_tb(const TranslationBlock *tb)
|
|
||||||
{
|
|
||||||
page_lock_pair(NULL, tb_page_addr0(tb), NULL, tb_page_addr1(tb), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void page_unlock_tb(const TranslationBlock *tb)
|
|
||||||
{
|
|
||||||
PageDesc *p1 = page_find(tb_page_addr0(tb) >> TARGET_PAGE_BITS);
|
|
||||||
|
|
||||||
page_unlock(p1);
|
|
||||||
if (unlikely(tb_page_addr1(tb) != -1)) {
|
|
||||||
PageDesc *p2 = page_find(tb_page_addr1(tb) >> TARGET_PAGE_BITS);
|
|
||||||
|
|
||||||
if (p2 != p1) {
|
|
||||||
page_unlock(p2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Invalidate one TB.
|
|
||||||
* Called with mmap_lock held in user-mode.
|
|
||||||
*/
|
|
||||||
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
|
|
||||||
{
|
|
||||||
if (page_addr == -1 && tb_page_addr0(tb) != -1) {
|
|
||||||
page_lock_tb(tb);
|
|
||||||
do_tb_phys_invalidate(tb, true);
|
|
||||||
page_unlock_tb(tb);
|
|
||||||
} else {
|
|
||||||
do_tb_phys_invalidate(tb, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add the tb in the target page and protect it if necessary.
|
|
||||||
* Called with mmap_lock held for user-mode emulation.
|
|
||||||
* Called with @p->lock held in !user-mode.
|
|
||||||
*/
|
|
||||||
static inline void tb_page_add(PageDesc *p, TranslationBlock *tb,
|
|
||||||
unsigned int n, tb_page_addr_t page_addr)
|
|
||||||
{
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
bool page_already_protected;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert_page_locked(p);
|
|
||||||
|
|
||||||
tb->page_next[n] = p->first_tb;
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
page_already_protected = p->first_tb != (uintptr_t)NULL;
|
|
||||||
#endif
|
|
||||||
p->first_tb = (uintptr_t)tb | n;
|
|
||||||
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
|
||||||
/* translator_loop() must have made all TB pages non-writable */
|
|
||||||
assert(!(p->flags & PAGE_WRITE));
|
|
||||||
#else
|
|
||||||
/*
|
|
||||||
* If some code is already present, then the pages are already
|
|
||||||
* protected. So we handle the case where only the first TB is
|
|
||||||
* allocated in a physical page.
|
|
||||||
*/
|
|
||||||
if (!page_already_protected) {
|
|
||||||
tlb_protect_code(page_addr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add a new TB and link it to the physical page tables. phys_page2 is
|
|
||||||
* (-1) to indicate that only one page contains the TB.
|
|
||||||
*
|
|
||||||
* Called with mmap_lock held for user-mode emulation.
|
|
||||||
*
|
|
||||||
* Returns a pointer @tb, or a pointer to an existing TB that matches @tb.
|
|
||||||
* Note that in !user-mode, another thread might have already added a TB
|
|
||||||
* for the same block of guest code that @tb corresponds to. In that case,
|
|
||||||
* the caller should discard the original @tb, and use instead the returned TB.
|
|
||||||
*/
|
|
||||||
TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
|
||||||
tb_page_addr_t phys_page2)
|
|
||||||
{
|
|
||||||
PageDesc *p;
|
|
||||||
PageDesc *p2 = NULL;
|
|
||||||
void *existing_tb = NULL;
|
|
||||||
uint32_t h;
|
|
||||||
|
|
||||||
assert_memory_lock();
|
|
||||||
tcg_debug_assert(!(tb->cflags & CF_INVALID));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add the TB to the page list, acquiring first the pages's locks.
|
|
||||||
* We keep the locks held until after inserting the TB in the hash table,
|
|
||||||
* so that if the insertion fails we know for sure that the TBs are still
|
|
||||||
* in the page descriptors.
|
|
||||||
* Note that inserting into the hash table first isn't an option, since
|
|
||||||
* we can only insert TBs that are fully initialized.
|
|
||||||
*/
|
|
||||||
page_lock_pair(&p, phys_pc, &p2, phys_page2, true);
|
|
||||||
tb_page_add(p, tb, 0, phys_pc);
|
|
||||||
if (p2) {
|
|
||||||
tb_page_add(p2, tb, 1, phys_page2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add in the hash table */
|
|
||||||
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : tb_pc(tb)),
|
|
||||||
tb->flags, tb->cflags, tb->trace_vcpu_dstate);
|
|
||||||
qht_insert(&tb_ctx.htable, tb, h, &existing_tb);
|
|
||||||
|
|
||||||
/* remove TB from the page(s) if we couldn't insert it */
|
|
||||||
if (unlikely(existing_tb)) {
|
|
||||||
tb_page_remove(p, tb);
|
|
||||||
if (p2) {
|
|
||||||
tb_page_remove(p2, tb);
|
|
||||||
}
|
|
||||||
tb = existing_tb;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p2 && p2 != p) {
|
|
||||||
page_unlock(p2);
|
|
||||||
}
|
|
||||||
page_unlock(p);
|
|
||||||
return tb;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @p must be non-NULL.
|
|
||||||
* user-mode: call with mmap_lock held.
|
|
||||||
* !user-mode: call with all @pages locked.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
|
||||||
PageDesc *p, tb_page_addr_t start,
|
|
||||||
tb_page_addr_t end,
|
|
||||||
uintptr_t retaddr)
|
|
||||||
{
|
|
||||||
TranslationBlock *tb;
|
|
||||||
tb_page_addr_t tb_start, tb_end;
|
|
||||||
int n;
|
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
|
||||||
CPUState *cpu = current_cpu;
|
|
||||||
bool current_tb_not_found = retaddr != 0;
|
|
||||||
bool current_tb_modified = false;
|
|
||||||
TranslationBlock *current_tb = NULL;
|
|
||||||
#endif /* TARGET_HAS_PRECISE_SMC */
|
|
||||||
|
|
||||||
assert_page_locked(p);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We remove all the TBs in the range [start, end[.
|
|
||||||
* XXX: see if in some cases it could be faster to invalidate all the code
|
|
||||||
*/
|
|
||||||
PAGE_FOR_EACH_TB(p, tb, n) {
|
|
||||||
assert_page_locked(p);
|
|
||||||
/* NOTE: this is subtle as a TB may span two physical pages */
|
|
||||||
if (n == 0) {
|
|
||||||
/* NOTE: tb_end may be after the end of the page, but
|
|
||||||
it is not a problem */
|
|
||||||
tb_start = tb_page_addr0(tb);
|
|
||||||
tb_end = tb_start + tb->size;
|
|
||||||
} else {
|
|
||||||
tb_start = tb_page_addr1(tb);
|
|
||||||
tb_end = tb_start + ((tb_page_addr0(tb) + tb->size)
|
|
||||||
& ~TARGET_PAGE_MASK);
|
|
||||||
}
|
|
||||||
if (!(tb_end <= start || tb_start >= end)) {
|
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
|
||||||
if (current_tb_not_found) {
|
|
||||||
current_tb_not_found = false;
|
|
||||||
/* now we have a real cpu fault */
|
|
||||||
current_tb = tcg_tb_lookup(retaddr);
|
|
||||||
}
|
|
||||||
if (current_tb == tb &&
|
|
||||||
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
|
|
||||||
/*
|
|
||||||
* If we are modifying the current TB, we must stop
|
|
||||||
* its execution. We could be more precise by checking
|
|
||||||
* that the modification is after the current PC, but it
|
|
||||||
* would require a specialized function to partially
|
|
||||||
* restore the CPU state.
|
|
||||||
*/
|
|
||||||
current_tb_modified = true;
|
|
||||||
cpu_restore_state_from_tb(cpu, current_tb, retaddr);
|
|
||||||
}
|
|
||||||
#endif /* TARGET_HAS_PRECISE_SMC */
|
|
||||||
tb_phys_invalidate__locked(tb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
/* if no code remaining, no need to continue to use slow writes */
|
|
||||||
if (!p->first_tb) {
|
|
||||||
tlb_unprotect_code(start);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
|
||||||
if (current_tb_modified) {
|
|
||||||
page_collection_unlock(pages);
|
|
||||||
/* Force execution of one insn next time. */
|
|
||||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
|
|
||||||
mmap_unlock();
|
|
||||||
cpu_loop_exit_noexc(cpu);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Invalidate all TBs which intersect with the target physical
|
|
||||||
* address page @addr.
|
|
||||||
*
|
|
||||||
* Called with mmap_lock held for user-mode emulation
|
|
||||||
*/
|
|
||||||
void tb_invalidate_phys_page(tb_page_addr_t addr)
|
|
||||||
{
|
|
||||||
struct page_collection *pages;
|
|
||||||
tb_page_addr_t start, end;
|
|
||||||
PageDesc *p;
|
|
||||||
|
|
||||||
assert_memory_lock();
|
|
||||||
|
|
||||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
|
||||||
if (p == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = addr & TARGET_PAGE_MASK;
|
|
||||||
end = start + TARGET_PAGE_SIZE;
|
|
||||||
pages = page_collection_lock(start, end);
|
|
||||||
tb_invalidate_phys_page_range__locked(pages, p, start, end, 0);
|
|
||||||
page_collection_unlock(pages);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Invalidate all TBs which intersect with the target physical address range
|
|
||||||
* [start;end[. NOTE: start and end may refer to *different* physical pages.
|
|
||||||
* 'is_cpu_write_access' should be true if called from a real cpu write
|
|
||||||
* access: the virtual CPU will exit the current TB if code is modified inside
|
|
||||||
* this TB.
|
|
||||||
*
|
|
||||||
* Called with mmap_lock held for user-mode emulation.
|
|
||||||
*/
|
|
||||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end)
|
|
||||||
{
|
|
||||||
struct page_collection *pages;
|
|
||||||
tb_page_addr_t next;
|
|
||||||
|
|
||||||
assert_memory_lock();
|
|
||||||
|
|
||||||
pages = page_collection_lock(start, end);
|
|
||||||
for (next = (start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
|
||||||
start < end;
|
|
||||||
start = next, next += TARGET_PAGE_SIZE) {
|
|
||||||
PageDesc *pd = page_find(start >> TARGET_PAGE_BITS);
|
|
||||||
tb_page_addr_t bound = MIN(next, end);
|
|
||||||
|
|
||||||
if (pd == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tb_invalidate_phys_page_range__locked(pages, pd, start, bound, 0);
|
|
||||||
}
|
|
||||||
page_collection_unlock(pages);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_SOFTMMU
|
|
||||||
/*
|
|
||||||
* len must be <= 8 and start must be a multiple of len.
|
|
||||||
* Called via softmmu_template.h when code areas are written to with
|
|
||||||
* iothread mutex not held.
|
|
||||||
*
|
|
||||||
* Call with all @pages in the range [@start, @start + len[ locked.
|
|
||||||
*/
|
|
||||||
void tb_invalidate_phys_page_fast(struct page_collection *pages,
|
|
||||||
tb_page_addr_t start, int len,
|
|
||||||
uintptr_t retaddr)
|
|
||||||
{
|
|
||||||
PageDesc *p;
|
|
||||||
|
|
||||||
assert_memory_lock();
|
|
||||||
|
|
||||||
p = page_find(start >> TARGET_PAGE_BITS);
|
|
||||||
if (!p) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_page_locked(p);
|
|
||||||
tb_invalidate_phys_page_range__locked(pages, p, start, start + len,
|
|
||||||
retaddr);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/*
|
|
||||||
* Called with mmap_lock held. If pc is not 0 then it indicates the
|
|
||||||
* host PC of the faulting store instruction that caused this invalidate.
|
|
||||||
* Returns true if the caller needs to abort execution of the current
|
|
||||||
* TB (because it was modified by this store and the guest CPU has
|
|
||||||
* precise-SMC semantics).
|
|
||||||
*/
|
|
||||||
bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
|
|
||||||
{
|
|
||||||
TranslationBlock *tb;
|
|
||||||
PageDesc *p;
|
|
||||||
int n;
|
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
|
||||||
TranslationBlock *current_tb = NULL;
|
|
||||||
CPUState *cpu = current_cpu;
|
|
||||||
bool current_tb_modified = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
assert_memory_lock();
|
|
||||||
|
|
||||||
addr &= TARGET_PAGE_MASK;
|
|
||||||
p = page_find(addr >> TARGET_PAGE_BITS);
|
|
||||||
if (!p) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
|
||||||
if (p->first_tb && pc != 0) {
|
|
||||||
current_tb = tcg_tb_lookup(pc);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
assert_page_locked(p);
|
|
||||||
PAGE_FOR_EACH_TB(p, tb, n) {
|
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
|
||||||
if (current_tb == tb &&
|
|
||||||
(tb_cflags(current_tb) & CF_COUNT_MASK) != 1) {
|
|
||||||
/*
|
|
||||||
* If we are modifying the current TB, we must stop its execution.
|
|
||||||
* We could be more precise by checking that the modification is
|
|
||||||
* after the current PC, but it would require a specialized
|
|
||||||
* function to partially restore the CPU state.
|
|
||||||
*/
|
|
||||||
current_tb_modified = true;
|
|
||||||
cpu_restore_state_from_tb(cpu, current_tb, pc);
|
|
||||||
}
|
|
||||||
#endif /* TARGET_HAS_PRECISE_SMC */
|
|
||||||
tb_phys_invalidate(tb, addr);
|
|
||||||
}
|
|
||||||
p->first_tb = (uintptr_t)NULL;
|
|
||||||
#ifdef TARGET_HAS_PRECISE_SMC
|
|
||||||
if (current_tb_modified) {
|
|
||||||
/* Force execution of one insn next time. */
|
|
||||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -24,8 +24,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "sysemu/tcg.h"
|
||||||
#include "sysemu/replay.h"
|
#include "sysemu/replay.h"
|
||||||
#include "sysemu/cpu-timers.h"
|
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
@ -84,7 +85,8 @@ void icount_handle_deadline(void)
|
|||||||
* Don't interrupt cpu thread, when these events are waiting
|
* Don't interrupt cpu thread, when these events are waiting
|
||||||
* (i.e., there is no checkpoint)
|
* (i.e., there is no checkpoint)
|
||||||
*/
|
*/
|
||||||
if (deadline == 0) {
|
if (deadline == 0
|
||||||
|
&& (replay_mode != REPLAY_MODE_PLAY || replay_has_checkpoint())) {
|
||||||
icount_notify_aio_contexts();
|
icount_notify_aio_contexts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,14 +110,8 @@ void icount_prepare_for_run(CPUState *cpu)
|
|||||||
|
|
||||||
replay_mutex_lock();
|
replay_mutex_lock();
|
||||||
|
|
||||||
if (cpu->icount_budget == 0) {
|
if (cpu->icount_budget == 0 && replay_has_checkpoint()) {
|
||||||
/*
|
|
||||||
* We're called without the iothread lock, so must take it while
|
|
||||||
* we're calling timer handlers.
|
|
||||||
*/
|
|
||||||
qemu_mutex_lock_iothread();
|
|
||||||
icount_notify_aio_contexts();
|
icount_notify_aio_contexts();
|
||||||
qemu_mutex_unlock_iothread();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
* See the COPYING file in the top-level directory.
|
* See the COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TCG_ACCEL_OPS_ICOUNT_H
|
#ifndef TCG_CPUS_ICOUNT_H
|
||||||
#define TCG_ACCEL_OPS_ICOUNT_H
|
#define TCG_CPUS_ICOUNT_H
|
||||||
|
|
||||||
void icount_handle_deadline(void);
|
void icount_handle_deadline(void);
|
||||||
void icount_prepare_for_run(CPUState *cpu);
|
void icount_prepare_for_run(CPUState *cpu);
|
||||||
@ -16,4 +16,4 @@ void icount_process_data(CPUState *cpu);
|
|||||||
|
|
||||||
void icount_handle_interrupt(CPUState *cpu, int mask);
|
void icount_handle_interrupt(CPUState *cpu, int mask);
|
||||||
|
|
||||||
#endif /* TCG_ACCEL_OPS_ICOUNT_H */
|
#endif /* TCG_CPUS_ICOUNT_H */
|
||||||
|
@ -24,9 +24,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
#include "sysemu/replay.h"
|
#include "sysemu/replay.h"
|
||||||
#include "sysemu/cpu-timers.h"
|
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "qemu/notify.h"
|
#include "qemu/notify.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
@ -142,7 +142,7 @@ void mttcg_start_vcpu_thread(CPUState *cpu)
|
|||||||
g_assert(tcg_enabled());
|
g_assert(tcg_enabled());
|
||||||
tcg_cpu_init_cflags(cpu, current_machine->smp.max_cpus > 1);
|
tcg_cpu_init_cflags(cpu, current_machine->smp.max_cpus > 1);
|
||||||
|
|
||||||
cpu->thread = g_new0(QemuThread, 1);
|
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||||
qemu_cond_init(cpu->halt_cond);
|
qemu_cond_init(cpu->halt_cond);
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
* See the COPYING file in the top-level directory.
|
* See the COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TCG_ACCEL_OPS_MTTCG_H
|
#ifndef TCG_CPUS_MTTCG_H
|
||||||
#define TCG_ACCEL_OPS_MTTCG_H
|
#define TCG_CPUS_MTTCG_H
|
||||||
|
|
||||||
/* kick MTTCG vCPU thread */
|
/* kick MTTCG vCPU thread */
|
||||||
void mttcg_kick_vcpu_thread(CPUState *cpu);
|
void mttcg_kick_vcpu_thread(CPUState *cpu);
|
||||||
@ -16,4 +16,4 @@ void mttcg_kick_vcpu_thread(CPUState *cpu);
|
|||||||
/* start an mttcg vCPU thread */
|
/* start an mttcg vCPU thread */
|
||||||
void mttcg_start_vcpu_thread(CPUState *cpu);
|
void mttcg_start_vcpu_thread(CPUState *cpu);
|
||||||
|
|
||||||
#endif /* TCG_ACCEL_OPS_MTTCG_H */
|
#endif /* TCG_CPUS_MTTCG_H */
|
||||||
|
@ -24,9 +24,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
#include "sysemu/replay.h"
|
#include "sysemu/replay.h"
|
||||||
#include "sysemu/cpu-timers.h"
|
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "qemu/notify.h"
|
#include "qemu/notify.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
@ -51,7 +51,7 @@ void rr_kick_vcpu_thread(CPUState *unused)
|
|||||||
*
|
*
|
||||||
* The kick timer is responsible for moving single threaded vCPU
|
* The kick timer is responsible for moving single threaded vCPU
|
||||||
* emulation on to the next vCPU. If more than one vCPU is running a
|
* emulation on to the next vCPU. If more than one vCPU is running a
|
||||||
* timer event we force a cpu->exit so the next vCPU can get
|
* timer event with force a cpu->exit so the next vCPU can get
|
||||||
* scheduled.
|
* scheduled.
|
||||||
*
|
*
|
||||||
* The timer is removed if all vCPUs are idle and restarted again once
|
* The timer is removed if all vCPUs are idle and restarted again once
|
||||||
@ -61,6 +61,8 @@ void rr_kick_vcpu_thread(CPUState *unused)
|
|||||||
static QEMUTimer *rr_kick_vcpu_timer;
|
static QEMUTimer *rr_kick_vcpu_timer;
|
||||||
static CPUState *rr_current_cpu;
|
static CPUState *rr_current_cpu;
|
||||||
|
|
||||||
|
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
|
||||||
|
|
||||||
static inline int64_t rr_next_kick_time(void)
|
static inline int64_t rr_next_kick_time(void)
|
||||||
{
|
{
|
||||||
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
|
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
|
||||||
@ -279,8 +281,8 @@ void rr_start_vcpu_thread(CPUState *cpu)
|
|||||||
tcg_cpu_init_cflags(cpu, false);
|
tcg_cpu_init_cflags(cpu, false);
|
||||||
|
|
||||||
if (!single_tcg_cpu_thread) {
|
if (!single_tcg_cpu_thread) {
|
||||||
cpu->thread = g_new0(QemuThread, 1);
|
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||||
cpu->halt_cond = g_new0(QemuCond, 1);
|
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||||
qemu_cond_init(cpu->halt_cond);
|
qemu_cond_init(cpu->halt_cond);
|
||||||
|
|
||||||
/* share a single thread for all cpus with TCG */
|
/* share a single thread for all cpus with TCG */
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
* See the COPYING file in the top-level directory.
|
* See the COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TCG_ACCEL_OPS_RR_H
|
#ifndef TCG_CPUS_RR_H
|
||||||
#define TCG_ACCEL_OPS_RR_H
|
#define TCG_CPUS_RR_H
|
||||||
|
|
||||||
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
|
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
|
||||||
|
|
||||||
@ -18,4 +18,4 @@ void rr_kick_vcpu_thread(CPUState *unused);
|
|||||||
/* start the round robin vcpu thread */
|
/* start the round robin vcpu thread */
|
||||||
void rr_start_vcpu_thread(CPUState *cpu);
|
void rr_start_vcpu_thread(CPUState *cpu);
|
||||||
|
|
||||||
#endif /* TCG_ACCEL_OPS_RR_H */
|
#endif /* TCG_CPUS_RR_H */
|
||||||
|
@ -26,14 +26,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
#include "sysemu/replay.h"
|
#include "sysemu/replay.h"
|
||||||
#include "sysemu/cpu-timers.h"
|
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/hwaddr.h"
|
|
||||||
#include "exec/gdbstub.h"
|
|
||||||
|
|
||||||
#include "tcg-accel-ops.h"
|
#include "tcg-accel-ops.h"
|
||||||
#include "tcg-accel-ops-mttcg.h"
|
#include "tcg-accel-ops-mttcg.h"
|
||||||
@ -93,120 +91,23 @@ void tcg_handle_interrupt(CPUState *cpu, int mask)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tcg_supports_guest_debug(void)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */
|
|
||||||
static inline int xlat_gdb_type(CPUState *cpu, int gdbtype)
|
|
||||||
{
|
|
||||||
static const int xlat[] = {
|
|
||||||
[GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE,
|
|
||||||
[GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ,
|
|
||||||
[GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
|
|
||||||
};
|
|
||||||
|
|
||||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
|
||||||
int cputype = xlat[gdbtype];
|
|
||||||
|
|
||||||
if (cc->gdb_stop_before_watchpoint) {
|
|
||||||
cputype |= BP_STOP_BEFORE_ACCESS;
|
|
||||||
}
|
|
||||||
return cputype;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tcg_insert_breakpoint(CPUState *cs, int type, hwaddr addr, hwaddr len)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case GDB_BREAKPOINT_SW:
|
|
||||||
case GDB_BREAKPOINT_HW:
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
err = cpu_breakpoint_insert(cpu, addr, BP_GDB, NULL);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
case GDB_WATCHPOINT_WRITE:
|
|
||||||
case GDB_WATCHPOINT_READ:
|
|
||||||
case GDB_WATCHPOINT_ACCESS:
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
err = cpu_watchpoint_insert(cpu, addr, len,
|
|
||||||
xlat_gdb_type(cpu, type), NULL);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
default:
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tcg_remove_breakpoint(CPUState *cs, int type, hwaddr addr, hwaddr len)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case GDB_BREAKPOINT_SW:
|
|
||||||
case GDB_BREAKPOINT_HW:
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
err = cpu_breakpoint_remove(cpu, addr, BP_GDB);
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
case GDB_WATCHPOINT_WRITE:
|
|
||||||
case GDB_WATCHPOINT_READ:
|
|
||||||
case GDB_WATCHPOINT_ACCESS:
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
err = cpu_watchpoint_remove(cpu, addr, len,
|
|
||||||
xlat_gdb_type(cpu, type));
|
|
||||||
if (err) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
default:
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void tcg_remove_all_breakpoints(CPUState *cpu)
|
|
||||||
{
|
|
||||||
cpu_breakpoint_remove_all(cpu, BP_GDB);
|
|
||||||
cpu_watchpoint_remove_all(cpu, BP_GDB);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tcg_accel_ops_init(AccelOpsClass *ops)
|
static void tcg_accel_ops_init(AccelOpsClass *ops)
|
||||||
{
|
{
|
||||||
if (qemu_tcg_mttcg_enabled()) {
|
if (qemu_tcg_mttcg_enabled()) {
|
||||||
ops->create_vcpu_thread = mttcg_start_vcpu_thread;
|
ops->create_vcpu_thread = mttcg_start_vcpu_thread;
|
||||||
ops->kick_vcpu_thread = mttcg_kick_vcpu_thread;
|
ops->kick_vcpu_thread = mttcg_kick_vcpu_thread;
|
||||||
ops->handle_interrupt = tcg_handle_interrupt;
|
ops->handle_interrupt = tcg_handle_interrupt;
|
||||||
|
} else if (icount_enabled()) {
|
||||||
|
ops->create_vcpu_thread = rr_start_vcpu_thread;
|
||||||
|
ops->kick_vcpu_thread = rr_kick_vcpu_thread;
|
||||||
|
ops->handle_interrupt = icount_handle_interrupt;
|
||||||
|
ops->get_virtual_clock = icount_get;
|
||||||
|
ops->get_elapsed_ticks = icount_get;
|
||||||
} else {
|
} else {
|
||||||
ops->create_vcpu_thread = rr_start_vcpu_thread;
|
ops->create_vcpu_thread = rr_start_vcpu_thread;
|
||||||
ops->kick_vcpu_thread = rr_kick_vcpu_thread;
|
ops->kick_vcpu_thread = rr_kick_vcpu_thread;
|
||||||
|
ops->handle_interrupt = tcg_handle_interrupt;
|
||||||
if (icount_enabled()) {
|
|
||||||
ops->handle_interrupt = icount_handle_interrupt;
|
|
||||||
ops->get_virtual_clock = icount_get;
|
|
||||||
ops->get_elapsed_ticks = icount_get;
|
|
||||||
} else {
|
|
||||||
ops->handle_interrupt = tcg_handle_interrupt;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ops->supports_guest_debug = tcg_supports_guest_debug;
|
|
||||||
ops->insert_breakpoint = tcg_insert_breakpoint;
|
|
||||||
ops->remove_breakpoint = tcg_remove_breakpoint;
|
|
||||||
ops->remove_all_breakpoints = tcg_remove_all_breakpoints;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcg_accel_ops_class_init(ObjectClass *oc, void *data)
|
static void tcg_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
* See the COPYING file in the top-level directory.
|
* See the COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TCG_ACCEL_OPS_H
|
#ifndef TCG_CPUS_H
|
||||||
#define TCG_ACCEL_OPS_H
|
#define TCG_CPUS_H
|
||||||
|
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
|
|
||||||
@ -19,4 +19,4 @@ int tcg_cpus_exec(CPUState *cpu);
|
|||||||
void tcg_handle_interrupt(CPUState *cpu, int mask);
|
void tcg_handle_interrupt(CPUState *cpu, int mask);
|
||||||
void tcg_cpu_init_cflags(CPUState *cpu, bool parallel);
|
void tcg_cpu_init_cflags(CPUState *cpu, bool parallel);
|
||||||
|
|
||||||
#endif /* TCG_ACCEL_OPS_H */
|
#endif /* TCG_CPUS_H */
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
#include "sysemu/replay.h"
|
|
||||||
#include "sysemu/cpu-timers.h"
|
#include "sysemu/cpu-timers.h"
|
||||||
#include "tcg/tcg.h"
|
#include "tcg/tcg.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
@ -83,14 +83,6 @@ static bool check_tcg_memory_orders_compatible(void)
|
|||||||
|
|
||||||
static bool default_mttcg_enabled(void)
|
static bool default_mttcg_enabled(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
|
||||||
|
|
||||||
// Only the RR ops works with libafl_qemu, so avoid MTTCG by default
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
|
||||||
|
|
||||||
if (icount_enabled() || TCG_OVERSIZED_GUEST) {
|
if (icount_enabled() || TCG_OVERSIZED_GUEST) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@ -216,28 +208,12 @@ static void tcg_set_splitwx(Object *obj, bool value, Error **errp)
|
|||||||
s->splitwx_enabled = value;
|
s->splitwx_enabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcg_gdbstub_supported_sstep_flags(void)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* In replay mode all events will come from the log and can't be
|
|
||||||
* suppressed otherwise we would break determinism. However as those
|
|
||||||
* events are tied to the number of executed instructions we won't see
|
|
||||||
* them occurring every time we single step.
|
|
||||||
*/
|
|
||||||
if (replay_mode != REPLAY_MODE_NONE) {
|
|
||||||
return SSTEP_ENABLE;
|
|
||||||
} else {
|
|
||||||
return SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
AccelClass *ac = ACCEL_CLASS(oc);
|
AccelClass *ac = ACCEL_CLASS(oc);
|
||||||
ac->name = "tcg";
|
ac->name = "tcg";
|
||||||
ac->init_machine = tcg_init_machine;
|
ac->init_machine = tcg_init_machine;
|
||||||
ac->allowed = &tcg_allowed;
|
ac->allowed = &tcg_allowed;
|
||||||
ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags;
|
|
||||||
|
|
||||||
object_class_property_add_str(oc, "thread",
|
object_class_property_add_str(oc, "thread",
|
||||||
tcg_get_thread,
|
tcg_get_thread,
|
||||||
|
@ -33,145 +33,13 @@
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
|
|
||||||
#include "sysemu/runstate.h"
|
|
||||||
#include "migration/snapshot.h"
|
|
||||||
#include "qapi/error.h"
|
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "qemu/main-loop.h"
|
|
||||||
#include "hw/core/cpu.h"
|
|
||||||
#include "sysemu/hw_accel.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
void libafl_save_qemu_snapshot(char *name, bool sync);
|
|
||||||
void libafl_load_qemu_snapshot(char *name, bool sync);
|
|
||||||
|
|
||||||
static void save_snapshot_cb(void* opaque)
|
|
||||||
{
|
|
||||||
char* name = (char*)opaque;
|
|
||||||
Error *err = NULL;
|
|
||||||
if(!save_snapshot(name, true, NULL, false, NULL, &err)) {
|
|
||||||
error_report_err(err);
|
|
||||||
error_report("Could not save snapshot");
|
|
||||||
}
|
|
||||||
free(opaque);
|
|
||||||
}
|
|
||||||
|
|
||||||
void libafl_save_qemu_snapshot(char *name, bool sync)
|
|
||||||
{
|
|
||||||
// use snapshots synchronously, use if main loop is not running
|
|
||||||
if (sync) {
|
|
||||||
//TODO: eliminate this code duplication
|
|
||||||
//by passing a heap-allocated buffer from rust to c,
|
|
||||||
//which c needs to free
|
|
||||||
Error *err = NULL;
|
|
||||||
if(!save_snapshot(name, true, NULL, false, NULL, &err)) {
|
|
||||||
error_report_err(err);
|
|
||||||
error_report("Could not save snapshot");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char* name_buffer = malloc(strlen(name)+1);
|
|
||||||
strcpy(name_buffer, name);
|
|
||||||
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), save_snapshot_cb, (void*)name_buffer, "save_snapshot");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void load_snapshot_cb(void* opaque)
|
|
||||||
{
|
|
||||||
char* name = (char*)opaque;
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
int saved_vm_running = runstate_is_running();
|
|
||||||
vm_stop(RUN_STATE_RESTORE_VM);
|
|
||||||
|
|
||||||
bool loaded = load_snapshot(name, NULL, false, NULL, &err);
|
|
||||||
|
|
||||||
if(!loaded) {
|
|
||||||
error_report_err(err);
|
|
||||||
error_report("Could not load snapshot");
|
|
||||||
}
|
|
||||||
if (loaded && saved_vm_running) {
|
|
||||||
vm_start();
|
|
||||||
}
|
|
||||||
free(opaque);
|
|
||||||
}
|
|
||||||
|
|
||||||
void libafl_load_qemu_snapshot(char *name, bool sync)
|
|
||||||
{
|
|
||||||
// use snapshots synchronously, use if main loop is not running
|
|
||||||
if (sync) {
|
|
||||||
//TODO: see libafl_save_qemu_snapshot
|
|
||||||
Error *err = NULL;
|
|
||||||
|
|
||||||
int saved_vm_running = runstate_is_running();
|
|
||||||
vm_stop(RUN_STATE_RESTORE_VM);
|
|
||||||
|
|
||||||
bool loaded = load_snapshot(name, NULL, false, NULL, &err);
|
|
||||||
|
|
||||||
if(!loaded) {
|
|
||||||
error_report_err(err);
|
|
||||||
error_report("Could not load snapshot");
|
|
||||||
}
|
|
||||||
if (loaded && saved_vm_running) {
|
|
||||||
vm_start();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char* name_buffer = malloc(strlen(name)+1);
|
|
||||||
strcpy(name_buffer, name);
|
|
||||||
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), load_snapshot_cb, (void*)name_buffer, "load_snapshot");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EXCP_LIBAFL_BP 0xf4775747
|
#define EXCP_LIBAFL_BP 0xf4775747
|
||||||
|
|
||||||
int libafl_qemu_break_asap = 0;
|
void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env)
|
||||||
|
|
||||||
CPUState* libafl_breakpoint_cpu;
|
|
||||||
vaddr libafl_breakpoint_pc;
|
|
||||||
|
|
||||||
#ifdef TARGET_ARM
|
|
||||||
#define THUMB_MASK(value) (value | libafl_breakpoint_cpu->env_ptr->thumb)
|
|
||||||
#else
|
|
||||||
#define THUMB_MASK(value) value
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void libafl_qemu_trigger_breakpoint(CPUState* cpu);
|
|
||||||
|
|
||||||
void libafl_sync_breakpoint_cpu(void);
|
|
||||||
|
|
||||||
void libafl_sync_breakpoint_cpu(void)
|
|
||||||
{
|
|
||||||
if (libafl_breakpoint_pc) {
|
|
||||||
CPUClass* cc = CPU_GET_CLASS(libafl_breakpoint_cpu);
|
|
||||||
cc->set_pc(libafl_breakpoint_cpu, THUMB_MASK(libafl_breakpoint_pc));
|
|
||||||
}
|
|
||||||
libafl_breakpoint_pc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void libafl_qemu_trigger_breakpoint(CPUState* cpu)
|
|
||||||
{
|
|
||||||
libafl_breakpoint_cpu = cpu;
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
qemu_system_debug_request();
|
|
||||||
cpu->stopped = true;
|
|
||||||
#endif
|
|
||||||
if (cpu->running) {
|
|
||||||
cpu->exception_index = EXCP_LIBAFL_BP;
|
|
||||||
cpu_loop_exit(cpu);
|
|
||||||
} else {
|
|
||||||
libafl_qemu_break_asap = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env, target_ulong pc)
|
|
||||||
{
|
{
|
||||||
CPUState* cpu = env_cpu(env);
|
CPUState* cpu = env_cpu(env);
|
||||||
libafl_breakpoint_pc = pc;
|
cpu->exception_index = EXCP_LIBAFL_BP;
|
||||||
libafl_qemu_trigger_breakpoint(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
@ -288,7 +288,6 @@ DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_2(libafl_qemu_handle_breakpoint, TCG_CALL_NO_RWG,
|
DEF_HELPER_FLAGS_1(libafl_qemu_handle_breakpoint, TCG_CALL_NO_RWG, void, env)
|
||||||
void, env, tl)
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
#include "tcg/tcg-internal.h"
|
#include "tcg/tcg-internal.h"
|
||||||
|
|
||||||
extern target_ulong libafl_gen_cur_pc;
|
|
||||||
|
|
||||||
struct libafl_breakpoint {
|
struct libafl_breakpoint {
|
||||||
target_ulong addr;
|
target_ulong addr;
|
||||||
struct libafl_breakpoint* next;
|
struct libafl_breakpoint* next;
|
||||||
@ -34,24 +32,13 @@ extern struct libafl_breakpoint* libafl_qemu_breakpoints;
|
|||||||
struct libafl_hook {
|
struct libafl_hook {
|
||||||
target_ulong addr;
|
target_ulong addr;
|
||||||
void (*callback)(uint64_t);
|
void (*callback)(uint64_t);
|
||||||
uint64_t data;
|
uint64_t value;
|
||||||
TCGHelperInfo helper_info;
|
TCGHelperInfo helper_info;
|
||||||
struct libafl_hook* next;
|
struct libafl_hook* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct libafl_hook* libafl_qemu_hooks;
|
extern struct libafl_hook* libafl_qemu_hooks;
|
||||||
|
|
||||||
struct libafl_hook* libafl_search_hook(target_ulong addr);
|
|
||||||
|
|
||||||
struct libafl_backdoor_hook {
|
|
||||||
void (*exec)(target_ulong pc, uint64_t data);
|
|
||||||
uint64_t data;
|
|
||||||
TCGHelperInfo helper_info;
|
|
||||||
struct libafl_backdoor_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct libafl_backdoor_hook* libafl_backdoor_hooks;
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
/* Pairs with tcg_clear_temp_count.
|
/* Pairs with tcg_clear_temp_count.
|
||||||
@ -78,27 +65,20 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
|
|||||||
return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
|
return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns,
|
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||||
target_ulong pc, void *host_pc,
|
CPUState *cpu, TranslationBlock *tb, int max_insns)
|
||||||
const TranslatorOps *ops, DisasContextBase *db)
|
|
||||||
{
|
{
|
||||||
uint32_t cflags = tb_cflags(tb);
|
uint32_t cflags = tb_cflags(tb);
|
||||||
bool plugin_enabled;
|
bool plugin_enabled;
|
||||||
|
|
||||||
/* Initialize DisasContext */
|
/* Initialize DisasContext */
|
||||||
db->tb = tb;
|
db->tb = tb;
|
||||||
db->pc_first = pc;
|
db->pc_first = tb->pc;
|
||||||
db->pc_next = pc;
|
db->pc_next = db->pc_first;
|
||||||
db->is_jmp = DISAS_NEXT;
|
db->is_jmp = DISAS_NEXT;
|
||||||
db->num_insns = 0;
|
db->num_insns = 0;
|
||||||
db->max_insns = max_insns;
|
db->max_insns = max_insns;
|
||||||
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
|
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
|
||||||
db->host_addr[0] = host_pc;
|
|
||||||
db->host_addr[1] = NULL;
|
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
page_protect(pc);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ops->init_disas_context(db, cpu);
|
ops->init_disas_context(db, cpu);
|
||||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||||
@ -111,7 +91,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns,
|
|||||||
ops->tb_start(db, cpu);
|
ops->tb_start(db, cpu);
|
||||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||||
|
|
||||||
plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY);
|
plugin_enabled = plugin_gen_tb_start(cpu, tb, cflags & CF_MEMI_ONLY);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
db->num_insns++;
|
db->num_insns++;
|
||||||
@ -124,75 +104,25 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns,
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
struct libafl_hook* hk = libafl_search_hook(db->pc_next);
|
struct libafl_hook* hk = libafl_qemu_hooks;
|
||||||
if (hk) {
|
while (hk) {
|
||||||
TCGv tmp0 = tcg_const_tl(db->pc_next);
|
if (hk->addr == db->pc_next) {
|
||||||
TCGv_i64 tmp1 = tcg_const_i64(hk->data);
|
TCGv_i64 tmp0 = tcg_const_i64(hk->value);
|
||||||
#if TARGET_LONG_BITS == 32
|
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
|
||||||
TCGTemp *tmp2[2] = { tcgv_i32_temp(tmp0), tcgv_i64_temp(tmp1) };
|
tcg_gen_callN(hk->callback, NULL, 1, tmp1);
|
||||||
#else
|
tcg_temp_free_i64(tmp0);
|
||||||
TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1) };
|
}
|
||||||
#endif
|
hk = hk->next;
|
||||||
tcg_gen_callN(hk->callback, NULL, 2, tmp2);
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
tcg_temp_free_i32(tmp0);
|
|
||||||
#else
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
#endif
|
|
||||||
tcg_temp_free_i64(tmp1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct libafl_breakpoint* bp = libafl_qemu_breakpoints;
|
struct libafl_breakpoint* bp = libafl_qemu_breakpoints;
|
||||||
while (bp) {
|
while (bp) {
|
||||||
if (bp->addr == db->pc_next) {
|
if (bp->addr == db->pc_next) {
|
||||||
TCGv tmp0 = tcg_const_tl(db->pc_next);
|
gen_helper_libafl_qemu_handle_breakpoint(cpu_env);
|
||||||
gen_helper_libafl_qemu_handle_breakpoint(cpu_env, tmp0);
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
tcg_temp_free_i32(tmp0);
|
|
||||||
#else
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
bp = bp->next;
|
bp = bp->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
libafl_gen_cur_pc = db->pc_next;
|
|
||||||
|
|
||||||
// 0x0f, 0x3a, 0xf2, 0x44
|
|
||||||
uint8_t backdoor = translator_ldub(cpu->env_ptr, db, db->pc_next);
|
|
||||||
if (backdoor == 0x0f) {
|
|
||||||
backdoor = translator_ldub(cpu->env_ptr, db, db->pc_next +1);
|
|
||||||
if (backdoor == 0x3a) {
|
|
||||||
backdoor = translator_ldub(cpu->env_ptr, db, db->pc_next +2);
|
|
||||||
if (backdoor == 0xf2) {
|
|
||||||
backdoor = translator_ldub(cpu->env_ptr, db, db->pc_next +3);
|
|
||||||
if (backdoor == 0x44) {
|
|
||||||
struct libafl_backdoor_hook* hk = libafl_backdoor_hooks;
|
|
||||||
while (hk) {
|
|
||||||
TCGv tmp0 = tcg_const_tl(db->pc_next);
|
|
||||||
TCGv_i64 tmp1 = tcg_const_i64(hk->data);
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
TCGTemp *tmp2[2] = { tcgv_i32_temp(tmp0), tcgv_i64_temp(tmp1) };
|
|
||||||
#else
|
|
||||||
TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1) };
|
|
||||||
#endif
|
|
||||||
tcg_gen_callN(hk->exec, NULL, 2, tmp2);
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
tcg_temp_free_i32(tmp0);
|
|
||||||
#else
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
#endif
|
|
||||||
tcg_temp_free_i64(tmp1);
|
|
||||||
hk = hk->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
db->pc_next += 4;
|
|
||||||
goto post_translate_insn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
/* Disassemble one instruction. The translate_insn hook should
|
/* Disassemble one instruction. The translate_insn hook should
|
||||||
@ -209,8 +139,6 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns,
|
|||||||
ops->translate_insn(db, cpu);
|
ops->translate_insn(db, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
post_translate_insn:
|
|
||||||
|
|
||||||
/* Stop translation if translate_insn so indicated. */
|
/* Stop translation if translate_insn so indicated. */
|
||||||
if (db->is_jmp != DISAS_NEXT) {
|
if (db->is_jmp != DISAS_NEXT) {
|
||||||
break;
|
break;
|
||||||
@ -247,115 +175,11 @@ post_translate_insn:
|
|||||||
#ifdef DEBUG_DISAS
|
#ifdef DEBUG_DISAS
|
||||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
||||||
&& qemu_log_in_addr_range(db->pc_first)) {
|
&& qemu_log_in_addr_range(db->pc_first)) {
|
||||||
FILE *logfile = qemu_log_trylock();
|
FILE *logfile = qemu_log_lock();
|
||||||
if (logfile) {
|
qemu_log("----------------\n");
|
||||||
fprintf(logfile, "----------------\n");
|
ops->disas_log(db, cpu);
|
||||||
ops->disas_log(db, cpu, logfile);
|
qemu_log("\n");
|
||||||
fprintf(logfile, "\n");
|
qemu_log_unlock(logfile);
|
||||||
qemu_log_unlock(logfile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *translator_access(CPUArchState *env, DisasContextBase *db,
|
|
||||||
target_ulong pc, size_t len)
|
|
||||||
{
|
|
||||||
void *host;
|
|
||||||
target_ulong base, end;
|
|
||||||
TranslationBlock *tb;
|
|
||||||
|
|
||||||
tb = db->tb;
|
|
||||||
|
|
||||||
/* Use slow path if first page is MMIO. */
|
|
||||||
if (unlikely(tb_page_addr0(tb) == -1)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
end = pc + len - 1;
|
|
||||||
if (likely(is_same_page(db, end))) {
|
|
||||||
host = db->host_addr[0];
|
|
||||||
base = db->pc_first;
|
|
||||||
} else {
|
|
||||||
host = db->host_addr[1];
|
|
||||||
base = TARGET_PAGE_ALIGN(db->pc_first);
|
|
||||||
if (host == NULL) {
|
|
||||||
tb_page_addr_t phys_page =
|
|
||||||
get_page_addr_code_hostp(env, base, &db->host_addr[1]);
|
|
||||||
/* We cannot handle MMIO as second page. */
|
|
||||||
assert(phys_page != -1);
|
|
||||||
tb_set_page_addr1(tb, phys_page);
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
page_protect(end);
|
|
||||||
#endif
|
|
||||||
host = db->host_addr[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use slow path when crossing pages. */
|
|
||||||
if (is_same_page(db, pc)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tcg_debug_assert(pc >= base);
|
|
||||||
return host + (pc - base);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
|
||||||
{
|
|
||||||
uint8_t ret;
|
|
||||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
plugin_insn_append(pc, p, sizeof(ret));
|
|
||||||
return ldub_p(p);
|
|
||||||
}
|
|
||||||
ret = cpu_ldub_code(env, pc);
|
|
||||||
plugin_insn_append(pc, &ret, sizeof(ret));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
|
||||||
{
|
|
||||||
uint16_t ret, plug;
|
|
||||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
plugin_insn_append(pc, p, sizeof(ret));
|
|
||||||
return lduw_p(p);
|
|
||||||
}
|
|
||||||
ret = cpu_lduw_code(env, pc);
|
|
||||||
plug = tswap16(ret);
|
|
||||||
plugin_insn_append(pc, &plug, sizeof(ret));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
|
||||||
{
|
|
||||||
uint32_t ret, plug;
|
|
||||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
plugin_insn_append(pc, p, sizeof(ret));
|
|
||||||
return ldl_p(p);
|
|
||||||
}
|
|
||||||
ret = cpu_ldl_code(env, pc);
|
|
||||||
plug = tswap32(ret);
|
|
||||||
plugin_insn_append(pc, &plug, sizeof(ret));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
|
|
||||||
{
|
|
||||||
uint64_t ret, plug;
|
|
||||||
void *p = translator_access(env, db, pc, sizeof(ret));
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
plugin_insn_append(pc, p, sizeof(ret));
|
|
||||||
return ldq_p(p);
|
|
||||||
}
|
|
||||||
ret = cpu_ldq_code(env, pc);
|
|
||||||
plug = tswap64(ret);
|
|
||||||
plugin_insn_append(pc, &plug, sizeof(ret));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -72,7 +72,7 @@ struct alsa_params_obt {
|
|||||||
snd_pcm_uframes_t samples;
|
snd_pcm_uframes_t samples;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void G_GNUC_PRINTF (2, 3) alsa_logerr (int err, const char *fmt, ...)
|
static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ static void G_GNUC_PRINTF (2, 3) alsa_logerr (int err, const char *fmt, ...)
|
|||||||
AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
|
AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void G_GNUC_PRINTF (3, 4) alsa_logerr2 (
|
static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
|
||||||
int err,
|
int err,
|
||||||
const char *typ,
|
const char *typ,
|
||||||
const char *fmt,
|
const char *fmt,
|
||||||
@ -602,42 +602,6 @@ static int alsa_open(bool in, struct alsa_params_req *req,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t alsa_buffer_get_free(HWVoiceOut *hw)
|
|
||||||
{
|
|
||||||
ALSAVoiceOut *alsa = (ALSAVoiceOut *)hw;
|
|
||||||
snd_pcm_sframes_t avail;
|
|
||||||
size_t alsa_free, generic_free, generic_in_use;
|
|
||||||
|
|
||||||
avail = snd_pcm_avail_update(alsa->handle);
|
|
||||||
if (avail < 0) {
|
|
||||||
if (avail == -EPIPE) {
|
|
||||||
if (!alsa_recover(alsa->handle)) {
|
|
||||||
avail = snd_pcm_avail_update(alsa->handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (avail < 0) {
|
|
||||||
alsa_logerr(avail,
|
|
||||||
"Could not obtain number of available frames\n");
|
|
||||||
avail = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
alsa_free = avail * hw->info.bytes_per_frame;
|
|
||||||
generic_free = audio_generic_buffer_get_free(hw);
|
|
||||||
generic_in_use = hw->samples * hw->info.bytes_per_frame - generic_free;
|
|
||||||
if (generic_in_use) {
|
|
||||||
/*
|
|
||||||
* This code can only be reached in the unlikely case that
|
|
||||||
* snd_pcm_avail_update() returned a larger number of frames
|
|
||||||
* than snd_pcm_writei() could write. Make sure that all
|
|
||||||
* remaining bytes in the generic buffer can be written.
|
|
||||||
*/
|
|
||||||
alsa_free = alsa_free > generic_in_use ? alsa_free - generic_in_use : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return alsa_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
|
static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
|
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
|
||||||
@ -952,7 +916,6 @@ static struct audio_pcm_ops alsa_pcm_ops = {
|
|||||||
.init_out = alsa_init_out,
|
.init_out = alsa_init_out,
|
||||||
.fini_out = alsa_fini_out,
|
.fini_out = alsa_fini_out,
|
||||||
.write = alsa_write,
|
.write = alsa_write,
|
||||||
.buffer_get_free = alsa_buffer_get_free,
|
|
||||||
.run_buffer_out = audio_generic_run_buffer_out,
|
.run_buffer_out = audio_generic_run_buffer_out,
|
||||||
.enable_out = alsa_enable_out,
|
.enable_out = alsa_enable_out,
|
||||||
|
|
||||||
|
355
audio/audio.c
355
audio/audio.c
@ -32,8 +32,7 @@
|
|||||||
#include "qapi/qapi-visit-audio.h"
|
#include "qapi/qapi-visit-audio.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qemu/help_option.h"
|
#include "qemu-common.h"
|
||||||
#include "sysemu/sysemu.h"
|
|
||||||
#include "sysemu/replay.h"
|
#include "sysemu/replay.h"
|
||||||
#include "sysemu/runstate.h"
|
#include "sysemu/runstate.h"
|
||||||
#include "ui/qemu-spice.h"
|
#include "ui/qemu-spice.h"
|
||||||
@ -73,24 +72,20 @@ void audio_driver_register(audio_driver *drv)
|
|||||||
audio_driver *audio_driver_lookup(const char *name)
|
audio_driver *audio_driver_lookup(const char *name)
|
||||||
{
|
{
|
||||||
struct audio_driver *d;
|
struct audio_driver *d;
|
||||||
Error *local_err = NULL;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
QLIST_FOREACH(d, &audio_drivers, next) {
|
QLIST_FOREACH(d, &audio_drivers, next) {
|
||||||
if (strcmp(name, d->name) == 0) {
|
if (strcmp(name, d->name) == 0) {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rv = audio_module_load(name, &local_err);
|
|
||||||
if (rv > 0) {
|
audio_module_load_one(name);
|
||||||
QLIST_FOREACH(d, &audio_drivers, next) {
|
QLIST_FOREACH(d, &audio_drivers, next) {
|
||||||
if (strcmp(name, d->name) == 0) {
|
if (strcmp(name, d->name) == 0) {
|
||||||
return d;
|
return d;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (rv < 0) {
|
|
||||||
error_report_err(local_err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +117,7 @@ int audio_bug (const char *funcname, int cond)
|
|||||||
AUD_log (NULL, "I am sorry\n");
|
AUD_log (NULL, "I am sorry\n");
|
||||||
}
|
}
|
||||||
AUD_log (NULL, "Context:\n");
|
AUD_log (NULL, "Context:\n");
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
return cond;
|
return cond;
|
||||||
@ -552,45 +548,65 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
|
|||||||
return live;
|
return live;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
|
static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
|
||||||
{
|
{
|
||||||
size_t conv = 0;
|
size_t clipped = 0;
|
||||||
STSampleBuffer *conv_buf = hw->conv_buf;
|
size_t pos = hw->mix_buf->pos;
|
||||||
|
|
||||||
while (samples) {
|
while (len) {
|
||||||
uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
|
st_sample *src = hw->mix_buf->samples + pos;
|
||||||
size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
|
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_to_clip = MIN(len, samples_till_end_of_buf);
|
||||||
|
|
||||||
hw->conv(conv_buf->samples + conv_buf->pos, src, proc);
|
hw->clip(dst, src, samples_to_clip);
|
||||||
conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
|
|
||||||
samples -= proc;
|
pos = (pos + samples_to_clip) % hw->mix_buf->size;
|
||||||
conv += proc;
|
len -= samples_to_clip;
|
||||||
|
clipped += samples_to_clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
return conv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Soft voice (capture)
|
* Soft voice (capture)
|
||||||
*/
|
*/
|
||||||
|
static size_t audio_pcm_sw_get_rpos_in(SWVoiceIn *sw)
|
||||||
|
{
|
||||||
|
HWVoiceIn *hw = sw->hw;
|
||||||
|
ssize_t live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
|
ssize_t rpos;
|
||||||
|
|
||||||
|
if (audio_bug(__func__, live < 0 || live > hw->conv_buf->size)) {
|
||||||
|
dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpos = hw->conv_buf->pos - live;
|
||||||
|
if (rpos >= 0) {
|
||||||
|
return rpos;
|
||||||
|
} else {
|
||||||
|
return hw->conv_buf->size + rpos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
|
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
HWVoiceIn *hw = sw->hw;
|
HWVoiceIn *hw = sw->hw;
|
||||||
size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
|
size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
|
||||||
struct st_sample *src, *dst = sw->buf;
|
struct st_sample *src, *dst = sw->buf;
|
||||||
|
|
||||||
|
rpos = audio_pcm_sw_get_rpos_in(sw) % hw->conv_buf->size;
|
||||||
|
|
||||||
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||||
if (!live) {
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size);
|
|
||||||
|
|
||||||
samples = size / sw->info.bytes_per_frame;
|
samples = size / sw->info.bytes_per_frame;
|
||||||
|
if (!live) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
swlim = (live * sw->ratio) >> 32;
|
swlim = (live * sw->ratio) >> 32;
|
||||||
swlim = MIN (swlim, samples);
|
swlim = MIN (swlim, samples);
|
||||||
@ -616,7 +632,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
|
|||||||
total += isamp;
|
total += isamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hw->pcm_ops->volume_in) {
|
if (hw->pcm_ops && !hw->pcm_ops->volume_in) {
|
||||||
mixeng_volume (sw->buf, ret, &sw->vol);
|
mixeng_volume (sw->buf, ret, &sw->vol);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,38 +683,12 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)
|
|
||||||
{
|
|
||||||
return (hw->pcm_ops->buffer_get_free ? hw->pcm_ops->buffer_get_free(hw) :
|
|
||||||
INT_MAX) / hw->info.bytes_per_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
|
|
||||||
{
|
|
||||||
size_t clipped = 0;
|
|
||||||
size_t pos = hw->mix_buf->pos;
|
|
||||||
|
|
||||||
while (len) {
|
|
||||||
st_sample *src = hw->mix_buf->samples + pos;
|
|
||||||
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_to_clip = MIN(len, samples_till_end_of_buf);
|
|
||||||
|
|
||||||
hw->clip(dst, src, samples_to_clip);
|
|
||||||
|
|
||||||
pos = (pos + samples_to_clip) % hw->mix_buf->size;
|
|
||||||
len -= samples_to_clip;
|
|
||||||
clipped += samples_to_clip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Soft voice (playback)
|
* Soft voice (playback)
|
||||||
*/
|
*/
|
||||||
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
|
size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
|
||||||
size_t hw_free;
|
|
||||||
size_t ret = 0, pos = 0, total = 0;
|
size_t ret = 0, pos = 0, total = 0;
|
||||||
|
|
||||||
if (!sw) {
|
if (!sw) {
|
||||||
@ -721,28 +711,27 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
|
wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
|
||||||
|
samples = size / sw->info.bytes_per_frame;
|
||||||
|
|
||||||
dead = hwsamples - live;
|
dead = hwsamples - live;
|
||||||
hw_free = audio_pcm_hw_get_free(sw->hw);
|
swlim = ((int64_t) dead << 32) / sw->ratio;
|
||||||
hw_free = hw_free > live ? hw_free - live : 0;
|
swlim = MIN (swlim, samples);
|
||||||
samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
|
if (swlim) {
|
||||||
samples = MIN(samples, size / sw->info.bytes_per_frame);
|
sw->conv (sw->buf, buf, swlim);
|
||||||
if (samples) {
|
|
||||||
sw->conv(sw->buf, buf, samples);
|
|
||||||
|
|
||||||
if (!sw->hw->pcm_ops->volume_out) {
|
if (sw->hw->pcm_ops && !sw->hw->pcm_ops->volume_out) {
|
||||||
mixeng_volume(sw->buf, samples, &sw->vol);
|
mixeng_volume (sw->buf, swlim, &sw->vol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (samples) {
|
while (swlim) {
|
||||||
dead = hwsamples - live;
|
dead = hwsamples - live;
|
||||||
left = hwsamples - wpos;
|
left = hwsamples - wpos;
|
||||||
blck = MIN (dead, left);
|
blck = MIN (dead, left);
|
||||||
if (!blck) {
|
if (!blck) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
isamp = samples;
|
isamp = swlim;
|
||||||
osamp = blck;
|
osamp = blck;
|
||||||
st_rate_flow_mix (
|
st_rate_flow_mix (
|
||||||
sw->rate,
|
sw->rate,
|
||||||
@ -752,7 +741,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
|||||||
&osamp
|
&osamp
|
||||||
);
|
);
|
||||||
ret += isamp;
|
ret += isamp;
|
||||||
samples -= isamp;
|
swlim -= isamp;
|
||||||
pos += isamp;
|
pos += isamp;
|
||||||
live += osamp;
|
live += osamp;
|
||||||
wpos = (wpos + osamp) % hwsamples;
|
wpos = (wpos + osamp) % hwsamples;
|
||||||
@ -990,18 +979,6 @@ 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;
|
||||||
@ -1018,24 +995,12 @@ static size_t audio_get_avail (SWVoiceIn *sw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ldebug (
|
ldebug (
|
||||||
"%s: get_avail live %zu frontend frames %zu\n",
|
"%s: get_avail live %zu ret %" PRId64 "\n",
|
||||||
SW_NAME (sw),
|
SW_NAME (sw),
|
||||||
live, audio_frontend_frames_in(sw, live)
|
live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame
|
||||||
);
|
);
|
||||||
|
|
||||||
return live;
|
return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
||||||
@ -1057,11 +1022,13 @@ static size_t audio_get_free(SWVoiceOut *sw)
|
|||||||
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 %zu\n",
|
dolog ("%s: get_free live %zu dead %zu ret %" PRId64 "\n",
|
||||||
SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
|
SW_NAME (sw),
|
||||||
|
live, dead, (((int64_t) dead << 32) / sw->ratio) *
|
||||||
|
sw->info.bytes_per_frame);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return dead;
|
return (((int64_t) dead << 32) / sw->ratio) * sw->info.bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
|
static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
|
||||||
@ -1144,12 +1111,8 @@ static void audio_run_out (AudioState *s)
|
|||||||
HWVoiceOut *hw = NULL;
|
HWVoiceOut *hw = NULL;
|
||||||
SWVoiceOut *sw;
|
SWVoiceOut *sw;
|
||||||
|
|
||||||
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
|
if (!audio_get_pdo_out(s->dev)->mixing_engine) {
|
||||||
size_t played, live, prev_rpos;
|
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
|
||||||
size_t hw_free = audio_pcm_hw_get_free(hw);
|
|
||||||
int nb_live;
|
|
||||||
|
|
||||||
if (!audio_get_pdo_out(s->dev)->mixing_engine) {
|
|
||||||
/* there is exactly 1 sw for each hw with no mixeng */
|
/* there is exactly 1 sw for each hw with no mixeng */
|
||||||
sw = hw->sw_head.lh_first;
|
sw = hw->sw_head.lh_first;
|
||||||
|
|
||||||
@ -1162,34 +1125,15 @@ static void audio_run_out (AudioState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sw->active) {
|
if (sw->active) {
|
||||||
sw->callback.fn(sw->callback.opaque,
|
sw->callback.fn(sw->callback.opaque, INT_MAX);
|
||||||
hw_free * sw->info.bytes_per_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hw->pcm_ops->run_buffer_out) {
|
|
||||||
hw->pcm_ops->run_buffer_out(hw);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
|
||||||
if (sw->active) {
|
|
||||||
size_t sw_free = audio_get_free(sw);
|
|
||||||
size_t free;
|
|
||||||
|
|
||||||
if (hw_free > sw->total_hw_samples_mixed) {
|
|
||||||
free = audio_frontend_frames_out(sw,
|
|
||||||
MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
|
|
||||||
} else {
|
|
||||||
free = 0;
|
|
||||||
}
|
|
||||||
if (free > 0) {
|
|
||||||
sw->callback.fn(sw->callback.opaque,
|
|
||||||
free * sw->info.bytes_per_frame);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
|
||||||
|
size_t played, live, prev_rpos, free;
|
||||||
|
int nb_live;
|
||||||
|
|
||||||
live = audio_pcm_hw_get_live_out (hw, &nb_live);
|
live = audio_pcm_hw_get_live_out (hw, &nb_live);
|
||||||
if (!nb_live) {
|
if (!nb_live) {
|
||||||
@ -1219,6 +1163,14 @@ static void audio_run_out (AudioState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!live) {
|
if (!live) {
|
||||||
|
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||||
|
if (sw->active) {
|
||||||
|
free = audio_get_free (sw);
|
||||||
|
if (free > 0) {
|
||||||
|
sw->callback.fn (sw->callback.opaque, free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (hw->pcm_ops->run_buffer_out) {
|
if (hw->pcm_ops->run_buffer_out) {
|
||||||
hw->pcm_ops->run_buffer_out(hw);
|
hw->pcm_ops->run_buffer_out(hw);
|
||||||
}
|
}
|
||||||
@ -1259,6 +1211,13 @@ static void audio_run_out (AudioState *s)
|
|||||||
if (!sw->total_hw_samples_mixed) {
|
if (!sw->total_hw_samples_mixed) {
|
||||||
sw->empty = 1;
|
sw->empty = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sw->active) {
|
||||||
|
free = audio_get_free (sw);
|
||||||
|
if (free > 0) {
|
||||||
|
sw->callback.fn (sw->callback.opaque, free);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1266,6 +1225,7 @@ static void audio_run_out (AudioState *s)
|
|||||||
static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
|
static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
|
||||||
{
|
{
|
||||||
size_t conv = 0;
|
size_t conv = 0;
|
||||||
|
STSampleBuffer *conv_buf = hw->conv_buf;
|
||||||
|
|
||||||
if (hw->pcm_ops->run_buffer_in) {
|
if (hw->pcm_ops->run_buffer_in) {
|
||||||
hw->pcm_ops->run_buffer_in(hw);
|
hw->pcm_ops->run_buffer_in(hw);
|
||||||
@ -1281,7 +1241,11 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
proc = audio_pcm_hw_conv_in(hw, buf, size / hw->info.bytes_per_frame);
|
proc = MIN(size / hw->info.bytes_per_frame,
|
||||||
|
conv_buf->size - conv_buf->pos);
|
||||||
|
|
||||||
|
hw->conv(conv_buf->samples + conv_buf->pos, buf, proc);
|
||||||
|
conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
|
||||||
|
|
||||||
samples -= proc;
|
samples -= proc;
|
||||||
conv += proc;
|
conv += proc;
|
||||||
@ -1325,13 +1289,11 @@ static void audio_run_in (AudioState *s)
|
|||||||
sw->total_hw_samples_acquired -= min;
|
sw->total_hw_samples_acquired -= min;
|
||||||
|
|
||||||
if (sw->active) {
|
if (sw->active) {
|
||||||
size_t sw_avail = audio_get_avail(sw);
|
|
||||||
size_t avail;
|
size_t avail;
|
||||||
|
|
||||||
avail = audio_frontend_frames_in(sw, sw_avail);
|
avail = audio_get_avail (sw);
|
||||||
if (avail > 0) {
|
if (avail > 0) {
|
||||||
sw->callback.fn(sw->callback.opaque,
|
sw->callback.fn (sw->callback.opaque, avail);
|
||||||
avail * sw->info.bytes_per_frame);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1432,10 +1394,12 @@ void audio_generic_run_buffer_in(HWVoiceIn *hw)
|
|||||||
|
|
||||||
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||||
{
|
{
|
||||||
size_t start;
|
ssize_t start = (ssize_t)hw->pos_emul - hw->pending_emul;
|
||||||
|
|
||||||
start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
|
if (start < 0) {
|
||||||
assert(start < hw->size_emul);
|
start += hw->size_emul;
|
||||||
|
}
|
||||||
|
assert(start >= 0 && start < hw->size_emul);
|
||||||
|
|
||||||
*size = MIN(*size, hw->pending_emul);
|
*size = MIN(*size, hw->pending_emul);
|
||||||
*size = MIN(*size, hw->size_emul - start);
|
*size = MIN(*size, hw->size_emul - start);
|
||||||
@ -1448,22 +1412,16 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
|
|||||||
hw->pending_emul -= size;
|
hw->pending_emul -= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t audio_generic_buffer_get_free(HWVoiceOut *hw)
|
|
||||||
{
|
|
||||||
if (hw->buf_emul) {
|
|
||||||
return hw->size_emul - hw->pending_emul;
|
|
||||||
} else {
|
|
||||||
return hw->samples * hw->info.bytes_per_frame;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void audio_generic_run_buffer_out(HWVoiceOut *hw)
|
void audio_generic_run_buffer_out(HWVoiceOut *hw)
|
||||||
{
|
{
|
||||||
while (hw->pending_emul) {
|
while (hw->pending_emul) {
|
||||||
size_t write_len, written, start;
|
size_t write_len, written;
|
||||||
|
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
|
||||||
|
|
||||||
start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
|
if (start < 0) {
|
||||||
assert(start < hw->size_emul);
|
start += hw->size_emul;
|
||||||
|
}
|
||||||
|
assert(start >= 0 && start < hw->size_emul);
|
||||||
|
|
||||||
write_len = MIN(hw->pending_emul, hw->size_emul - start);
|
write_len = MIN(hw->pending_emul, hw->size_emul - start);
|
||||||
|
|
||||||
@ -1504,12 +1462,6 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
|||||||
{
|
{
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
|
|
||||||
if (hw->pcm_ops->buffer_get_free) {
|
|
||||||
size_t free = hw->pcm_ops->buffer_get_free(hw);
|
|
||||||
|
|
||||||
size = MIN(size, free);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (total < size) {
|
while (total < size) {
|
||||||
size_t dst_size = size - total;
|
size_t dst_size = size - total;
|
||||||
size_t copy_size, proc;
|
size_t copy_size, proc;
|
||||||
@ -1531,6 +1483,10 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hw->pcm_ops->run_buffer_out) {
|
||||||
|
hw->pcm_ops->run_buffer_out(hw);
|
||||||
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1760,7 +1716,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
|
|||||||
audio_validate_opts(dev, &error_abort);
|
audio_validate_opts(dev, &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = g_new0(AudioState, 1);
|
s = g_malloc0(sizeof(AudioState));
|
||||||
s->dev = dev;
|
s->dev = dev;
|
||||||
|
|
||||||
QLIST_INIT (&s->hw_head_out);
|
QLIST_INIT (&s->hw_head_out);
|
||||||
@ -1770,19 +1726,20 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
|
|||||||
atexit(audio_cleanup);
|
atexit(audio_cleanup);
|
||||||
atexit_registered = true;
|
atexit_registered = true;
|
||||||
}
|
}
|
||||||
|
QTAILQ_INSERT_TAIL(&audio_states, s, list);
|
||||||
|
|
||||||
s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s);
|
s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s);
|
||||||
|
|
||||||
s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices;
|
s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices;
|
||||||
s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices;
|
s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices;
|
||||||
|
|
||||||
if (s->nb_hw_voices_out < 1) {
|
if (s->nb_hw_voices_out <= 0) {
|
||||||
dolog ("Bogus number of playback voices %d, setting to 1\n",
|
dolog ("Bogus number of playback voices %d, setting to 1\n",
|
||||||
s->nb_hw_voices_out);
|
s->nb_hw_voices_out);
|
||||||
s->nb_hw_voices_out = 1;
|
s->nb_hw_voices_out = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->nb_hw_voices_in < 0) {
|
if (s->nb_hw_voices_in <= 0) {
|
||||||
dolog ("Bogus number of capture voices %d, setting to 0\n",
|
dolog ("Bogus number of capture voices %d, setting to 0\n",
|
||||||
s->nb_hw_voices_in);
|
s->nb_hw_voices_in);
|
||||||
s->nb_hw_voices_in = 0;
|
s->nb_hw_voices_in = 0;
|
||||||
@ -1795,10 +1752,6 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
|
|||||||
} else {
|
} else {
|
||||||
dolog ("Unknown audio driver `%s'\n", drvname);
|
dolog ("Unknown audio driver `%s'\n", drvname);
|
||||||
}
|
}
|
||||||
if (!done) {
|
|
||||||
free_audio_state(s);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; audio_prio_list[i]; i++) {
|
for (i = 0; audio_prio_list[i]; i++) {
|
||||||
AudiodevListEntry *e = audiodev_find(&head, audio_prio_list[i]);
|
AudiodevListEntry *e = audiodev_find(&head, audio_prio_list[i]);
|
||||||
@ -1836,7 +1789,6 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
|
|||||||
"(Audio can continue looping even after stopping the VM)\n");
|
"(Audio can continue looping even after stopping the VM)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
QTAILQ_INSERT_TAIL(&audio_states, s, list);
|
|
||||||
QLIST_INIT (&s->card_head);
|
QLIST_INIT (&s->card_head);
|
||||||
vmstate_register (NULL, 0, &vmstate_audio, s);
|
vmstate_register (NULL, 0, &vmstate_audio, s);
|
||||||
return s;
|
return s;
|
||||||
@ -1869,7 +1821,6 @@ void AUD_remove_card (QEMUSoundCard *card)
|
|||||||
g_free (card->name);
|
g_free (card->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct audio_pcm_ops capture_pcm_ops;
|
|
||||||
|
|
||||||
CaptureVoiceOut *AUD_add_capture(
|
CaptureVoiceOut *AUD_add_capture(
|
||||||
AudioState *s,
|
AudioState *s,
|
||||||
@ -1915,7 +1866,6 @@ CaptureVoiceOut *AUD_add_capture(
|
|||||||
|
|
||||||
hw = &cap->hw;
|
hw = &cap->hw;
|
||||||
hw->s = s;
|
hw->s = s;
|
||||||
hw->pcm_ops = &capture_pcm_ops;
|
|
||||||
QLIST_INIT (&hw->sw_head);
|
QLIST_INIT (&hw->sw_head);
|
||||||
QLIST_INIT (&cap->cb_head);
|
QLIST_INIT (&cap->cb_head);
|
||||||
|
|
||||||
@ -2050,13 +2000,11 @@ void audio_create_pdos(Audiodev *dev)
|
|||||||
CASE(NONE, none, );
|
CASE(NONE, none, );
|
||||||
CASE(ALSA, alsa, Alsa);
|
CASE(ALSA, alsa, Alsa);
|
||||||
CASE(COREAUDIO, coreaudio, Coreaudio);
|
CASE(COREAUDIO, coreaudio, Coreaudio);
|
||||||
CASE(DBUS, dbus, );
|
|
||||||
CASE(DSOUND, dsound, );
|
CASE(DSOUND, dsound, );
|
||||||
CASE(JACK, jack, Jack);
|
CASE(JACK, jack, Jack);
|
||||||
CASE(OSS, oss, Oss);
|
CASE(OSS, oss, Oss);
|
||||||
CASE(PA, pa, Pa);
|
CASE(PA, pa, Pa);
|
||||||
CASE(SDL, sdl, Sdl);
|
CASE(SDL, sdl, Sdl);
|
||||||
CASE(SNDIO, sndio, );
|
|
||||||
CASE(SPICE, spice, );
|
CASE(SPICE, spice, );
|
||||||
CASE(WAV, wav, );
|
CASE(WAV, wav, );
|
||||||
|
|
||||||
@ -2129,57 +2077,29 @@ static void audio_validate_opts(Audiodev *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_help(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
printf("Available audio drivers:\n");
|
|
||||||
|
|
||||||
for (i = 0; i < AUDIODEV_DRIVER__MAX; i++) {
|
|
||||||
audio_driver *driver = audio_driver_lookup(AudiodevDriver_str(i));
|
|
||||||
if (driver) {
|
|
||||||
printf("%s\n", driver->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void audio_parse_option(const char *opt)
|
void audio_parse_option(const char *opt)
|
||||||
{
|
{
|
||||||
|
AudiodevListEntry *e;
|
||||||
Audiodev *dev = NULL;
|
Audiodev *dev = NULL;
|
||||||
|
|
||||||
if (is_help_option(opt)) {
|
|
||||||
audio_help();
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
Visitor *v = qobject_input_visitor_new_str(opt, "driver", &error_fatal);
|
Visitor *v = qobject_input_visitor_new_str(opt, "driver", &error_fatal);
|
||||||
visit_type_Audiodev(v, NULL, &dev, &error_fatal);
|
visit_type_Audiodev(v, NULL, &dev, &error_fatal);
|
||||||
visit_free(v);
|
visit_free(v);
|
||||||
|
|
||||||
audio_define(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void audio_define(Audiodev *dev)
|
|
||||||
{
|
|
||||||
AudiodevListEntry *e;
|
|
||||||
|
|
||||||
audio_validate_opts(dev, &error_fatal);
|
audio_validate_opts(dev, &error_fatal);
|
||||||
|
|
||||||
e = g_new0(AudiodevListEntry, 1);
|
e = g_malloc0(sizeof(AudiodevListEntry));
|
||||||
e->dev = dev;
|
e->dev = dev;
|
||||||
QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next);
|
QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio_init_audiodevs(void)
|
void audio_init_audiodevs(void)
|
||||||
{
|
{
|
||||||
AudiodevListEntry *e;
|
AudiodevListEntry *e;
|
||||||
|
|
||||||
QSIMPLEQ_FOREACH(e, &audiodevs, next) {
|
QSIMPLEQ_FOREACH(e, &audiodevs, next) {
|
||||||
if (!audio_init(e->dev, NULL)) {
|
audio_init(e->dev, NULL);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo)
|
audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo)
|
||||||
@ -2277,39 +2197,26 @@ void audio_rate_start(RateCtl *rate)
|
|||||||
rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info)
|
size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
|
||||||
|
size_t bytes_avail)
|
||||||
{
|
{
|
||||||
int64_t now;
|
int64_t now;
|
||||||
int64_t ticks;
|
int64_t ticks;
|
||||||
int64_t bytes;
|
int64_t bytes;
|
||||||
int64_t frames;
|
int64_t samples;
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
ticks = now - rate->start_ticks;
|
ticks = now - rate->start_ticks;
|
||||||
bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
|
bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
|
||||||
frames = (bytes - rate->bytes_sent) / info->bytes_per_frame;
|
samples = (bytes - rate->bytes_sent) / info->bytes_per_frame;
|
||||||
if (frames < 0 || frames > 65536) {
|
if (samples < 0 || samples > 65536) {
|
||||||
AUD_log(NULL, "Resetting rate control (%" PRId64 " frames)\n", frames);
|
AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples);
|
||||||
audio_rate_start(rate);
|
audio_rate_start(rate);
|
||||||
frames = 0;
|
samples = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return frames * info->bytes_per_frame;
|
ret = MIN(samples * info->bytes_per_frame, bytes_avail);
|
||||||
}
|
rate->bytes_sent += ret;
|
||||||
|
return ret;
|
||||||
void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used)
|
|
||||||
{
|
|
||||||
rate->bytes_sent += bytes_used;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info,
|
|
||||||
size_t bytes_avail)
|
|
||||||
{
|
|
||||||
size_t bytes;
|
|
||||||
|
|
||||||
bytes = audio_rate_peek_bytes(rate, info);
|
|
||||||
bytes = MIN(bytes, bytes_avail);
|
|
||||||
audio_rate_add_bytes(rate, bytes);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
typedef void (*audio_callback_fn) (void *opaque, int avail);
|
typedef void (*audio_callback_fn) (void *opaque, int avail);
|
||||||
|
|
||||||
#if HOST_BIG_ENDIAN
|
#ifdef HOST_WORDS_BIGENDIAN
|
||||||
#define AUDIO_HOST_ENDIANNESS 1
|
#define AUDIO_HOST_ENDIANNESS 1
|
||||||
#else
|
#else
|
||||||
#define AUDIO_HOST_ENDIANNESS 0
|
#define AUDIO_HOST_ENDIANNESS 0
|
||||||
@ -91,8 +91,8 @@ typedef struct QEMUAudioTimeStamp {
|
|||||||
uint64_t old_ts;
|
uint64_t old_ts;
|
||||||
} QEMUAudioTimeStamp;
|
} QEMUAudioTimeStamp;
|
||||||
|
|
||||||
void AUD_vlog (const char *cap, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0);
|
void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
|
||||||
void AUD_log (const char *cap, const char *fmt, ...) G_GNUC_PRINTF(2, 3);
|
void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
|
||||||
|
|
||||||
void AUD_register_card (const char *name, QEMUSoundCard *card);
|
void AUD_register_card (const char *name, QEMUSoundCard *card);
|
||||||
void AUD_remove_card (QEMUSoundCard *card);
|
void AUD_remove_card (QEMUSoundCard *card);
|
||||||
@ -168,10 +168,8 @@ void audio_sample_to_uint64(const void *samples, int pos,
|
|||||||
void audio_sample_from_uint64(void *samples, int pos,
|
void audio_sample_from_uint64(void *samples, int pos,
|
||||||
uint64_t left, uint64_t right);
|
uint64_t left, uint64_t right);
|
||||||
|
|
||||||
void audio_define(Audiodev *audio);
|
|
||||||
void audio_parse_option(const char *opt);
|
void audio_parse_option(const char *opt);
|
||||||
bool audio_init_audiodevs(void);
|
void audio_init_audiodevs(void);
|
||||||
void audio_help(void);
|
|
||||||
void audio_legacy_help(void);
|
void audio_legacy_help(void);
|
||||||
|
|
||||||
AudioState *audio_state_by_name(const char *name);
|
AudioState *audio_state_by_name(const char *name);
|
||||||
|
@ -31,10 +31,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "mixeng.h"
|
#include "mixeng.h"
|
||||||
|
|
||||||
#ifdef CONFIG_GIO
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct audio_pcm_ops;
|
struct audio_pcm_ops;
|
||||||
|
|
||||||
struct audio_callback {
|
struct audio_callback {
|
||||||
@ -144,9 +140,6 @@ struct audio_driver {
|
|||||||
const char *descr;
|
const char *descr;
|
||||||
void *(*init) (Audiodev *);
|
void *(*init) (Audiodev *);
|
||||||
void (*fini) (void *);
|
void (*fini) (void *);
|
||||||
#ifdef CONFIG_GIO
|
|
||||||
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager);
|
|
||||||
#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;
|
||||||
@ -161,14 +154,10 @@ struct audio_pcm_ops {
|
|||||||
void (*fini_out)(HWVoiceOut *hw);
|
void (*fini_out)(HWVoiceOut *hw);
|
||||||
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
|
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
|
||||||
void (*run_buffer_out)(HWVoiceOut *hw);
|
void (*run_buffer_out)(HWVoiceOut *hw);
|
||||||
/*
|
|
||||||
* Get the free output buffer size. This is an upper limit. The size
|
|
||||||
* returned by function get_buffer_out may be smaller.
|
|
||||||
*/
|
|
||||||
size_t (*buffer_get_free)(HWVoiceOut *hw);
|
|
||||||
/*
|
/*
|
||||||
* get a buffer that after later can be passed to put_buffer_out; optional
|
* get a buffer that after later can be passed to put_buffer_out; optional
|
||||||
* returns the buffer, and writes it's size to size (in bytes)
|
* returns the buffer, and writes it's size to size (in bytes)
|
||||||
|
* this is unrelated to the above buffer_size_out function
|
||||||
*/
|
*/
|
||||||
void *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);
|
void *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);
|
||||||
/*
|
/*
|
||||||
@ -194,7 +183,6 @@ void audio_generic_run_buffer_in(HWVoiceIn *hw);
|
|||||||
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
|
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
|
||||||
void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
|
void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
|
||||||
void audio_generic_run_buffer_out(HWVoiceOut *hw);
|
void audio_generic_run_buffer_out(HWVoiceOut *hw);
|
||||||
size_t audio_generic_buffer_get_free(HWVoiceOut *hw);
|
|
||||||
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
|
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
|
||||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
|
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
|
||||||
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
|
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
|
||||||
@ -263,9 +251,7 @@ typedef struct RateCtl {
|
|||||||
} RateCtl;
|
} RateCtl;
|
||||||
|
|
||||||
void audio_rate_start(RateCtl *rate);
|
void audio_rate_start(RateCtl *rate);
|
||||||
size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info);
|
size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
|
||||||
void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used);
|
|
||||||
size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info,
|
|
||||||
size_t bytes_avail);
|
size_t bytes_avail);
|
||||||
|
|
||||||
static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
|
static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
|
||||||
@ -273,19 +259,6 @@ static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
|
|||||||
return (dst >= src) ? (dst - src) : (len - src + dst);
|
return (dst >= src) ? (dst - src) : (len - src + dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* audio_ring_posb() - returns new position in ringbuffer in backward
|
|
||||||
* direction at given distance
|
|
||||||
*
|
|
||||||
* @pos: current position in ringbuffer
|
|
||||||
* @dist: distance in ringbuffer to walk in reverse direction
|
|
||||||
* @len: size of ringbuffer
|
|
||||||
*/
|
|
||||||
static inline size_t audio_ring_posb(size_t pos, size_t dist, size_t len)
|
|
||||||
{
|
|
||||||
return pos >= dist ? pos - dist : len - dist + pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define dolog(fmt, ...) AUD_log(AUDIO_CAP, fmt, ## __VA_ARGS__)
|
#define dolog(fmt, ...) AUD_log(AUDIO_CAP, fmt, ## __VA_ARGS__)
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -328,8 +328,8 @@ static void handle_per_direction(
|
|||||||
|
|
||||||
static AudiodevListEntry *legacy_opt(const char *drvname)
|
static AudiodevListEntry *legacy_opt(const char *drvname)
|
||||||
{
|
{
|
||||||
AudiodevListEntry *e = g_new0(AudiodevListEntry, 1);
|
AudiodevListEntry *e = g_malloc0(sizeof(AudiodevListEntry));
|
||||||
e->dev = g_new0(Audiodev, 1);
|
e->dev = g_malloc0(sizeof(Audiodev));
|
||||||
e->dev->id = g_strdup(drvname);
|
e->dev->id = g_strdup(drvname);
|
||||||
e->dev->driver = qapi_enum_parse(
|
e->dev->driver = qapi_enum_parse(
|
||||||
&AudiodevDriver_lookup, drvname, -1, &error_abort);
|
&AudiodevDriver_lookup, drvname, -1, &error_abort);
|
||||||
@ -508,7 +508,7 @@ static void lv_free(Visitor *v)
|
|||||||
|
|
||||||
static Visitor *legacy_visitor_new(void)
|
static Visitor *legacy_visitor_new(void)
|
||||||
{
|
{
|
||||||
LegacyPrintVisitor *lv = g_new0(LegacyPrintVisitor, 1);
|
LegacyPrintVisitor *lv = g_malloc0(sizeof(LegacyPrintVisitor));
|
||||||
|
|
||||||
lv->visitor.start_struct = lv_start_struct;
|
lv->visitor.start_struct = lv_start_struct;
|
||||||
lv->visitor.end_struct = lv_end_struct;
|
lv->visitor.end_struct = lv_end_struct;
|
||||||
|
@ -110,11 +110,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DAC
|
|
||||||
samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
|
samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
|
||||||
#else
|
|
||||||
samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
|
sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
|
||||||
if (!sw->buf) {
|
if (!sw->buf) {
|
||||||
@ -331,8 +327,6 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
|||||||
case AUDIODEV_DRIVER_COREAUDIO:
|
case AUDIODEV_DRIVER_COREAUDIO:
|
||||||
return qapi_AudiodevCoreaudioPerDirectionOptions_base(
|
return qapi_AudiodevCoreaudioPerDirectionOptions_base(
|
||||||
dev->u.coreaudio.TYPE);
|
dev->u.coreaudio.TYPE);
|
||||||
case AUDIODEV_DRIVER_DBUS:
|
|
||||||
return dev->u.dbus.TYPE;
|
|
||||||
case AUDIODEV_DRIVER_DSOUND:
|
case AUDIODEV_DRIVER_DSOUND:
|
||||||
return dev->u.dsound.TYPE;
|
return dev->u.dsound.TYPE;
|
||||||
case AUDIODEV_DRIVER_JACK:
|
case AUDIODEV_DRIVER_JACK:
|
||||||
@ -343,8 +337,6 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
|||||||
return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
|
return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
|
||||||
case AUDIODEV_DRIVER_SDL:
|
case AUDIODEV_DRIVER_SDL:
|
||||||
return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE);
|
return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE);
|
||||||
case AUDIODEV_DRIVER_SNDIO:
|
|
||||||
return dev->u.sndio.TYPE;
|
|
||||||
case AUDIODEV_DRIVER_SPICE:
|
case AUDIODEV_DRIVER_SPICE:
|
||||||
return dev->u.spice.TYPE;
|
return dev->u.spice.TYPE;
|
||||||
case AUDIODEV_DRIVER_WAV:
|
case AUDIODEV_DRIVER_WAV:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* public domain */
|
/* public domain */
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
|
||||||
#define AUDIO_CAP "win-int"
|
#define AUDIO_CAP "win-int"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -44,15 +44,10 @@ typedef struct coreaudioVoiceOut {
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
} coreaudioVoiceOut;
|
} coreaudioVoiceOut;
|
||||||
|
|
||||||
#if !defined(MAC_OS_VERSION_12_0) \
|
|
||||||
|| (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_12_0)
|
|
||||||
#define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const AudioObjectPropertyAddress voice_addr = {
|
static const AudioObjectPropertyAddress voice_addr = {
|
||||||
kAudioHardwarePropertyDefaultOutputDevice,
|
kAudioHardwarePropertyDefaultOutputDevice,
|
||||||
kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyScopeGlobal,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
static OSStatus coreaudio_get_voice(AudioDeviceID *id)
|
static OSStatus coreaudio_get_voice(AudioDeviceID *id)
|
||||||
@ -74,7 +69,7 @@ static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
|
|||||||
AudioObjectPropertyAddress addr = {
|
AudioObjectPropertyAddress addr = {
|
||||||
kAudioDevicePropertyBufferFrameSizeRange,
|
kAudioDevicePropertyBufferFrameSizeRange,
|
||||||
kAudioDevicePropertyScopeOutput,
|
kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
return AudioObjectGetPropertyData(id,
|
return AudioObjectGetPropertyData(id,
|
||||||
@ -91,7 +86,7 @@ static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
|
|||||||
AudioObjectPropertyAddress addr = {
|
AudioObjectPropertyAddress addr = {
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
kAudioDevicePropertyBufferFrameSize,
|
||||||
kAudioDevicePropertyScopeOutput,
|
kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
return AudioObjectGetPropertyData(id,
|
return AudioObjectGetPropertyData(id,
|
||||||
@ -108,7 +103,7 @@ static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
|
|||||||
AudioObjectPropertyAddress addr = {
|
AudioObjectPropertyAddress addr = {
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
kAudioDevicePropertyBufferFrameSize,
|
||||||
kAudioDevicePropertyScopeOutput,
|
kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
return AudioObjectSetPropertyData(id,
|
return AudioObjectSetPropertyData(id,
|
||||||
@ -126,7 +121,7 @@ static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
|
|||||||
AudioObjectPropertyAddress addr = {
|
AudioObjectPropertyAddress addr = {
|
||||||
kAudioDevicePropertyStreamFormat,
|
kAudioDevicePropertyStreamFormat,
|
||||||
kAudioDevicePropertyScopeOutput,
|
kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
return AudioObjectSetPropertyData(id,
|
return AudioObjectSetPropertyData(id,
|
||||||
@ -143,7 +138,7 @@ static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
|
|||||||
AudioObjectPropertyAddress addr = {
|
AudioObjectPropertyAddress addr = {
|
||||||
kAudioDevicePropertyDeviceIsRunning,
|
kAudioDevicePropertyDeviceIsRunning,
|
||||||
kAudioDevicePropertyScopeOutput,
|
kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
return AudioObjectGetPropertyData(id,
|
return AudioObjectGetPropertyData(id,
|
||||||
@ -211,7 +206,7 @@ static void coreaudio_logstatus (OSStatus status)
|
|||||||
AUD_log (AUDIO_CAP, "Reason: %s\n", str);
|
AUD_log (AUDIO_CAP, "Reason: %s\n", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void G_GNUC_PRINTF (2, 3) coreaudio_logerr (
|
static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
|
||||||
OSStatus status,
|
OSStatus status,
|
||||||
const char *fmt,
|
const char *fmt,
|
||||||
...
|
...
|
||||||
@ -226,7 +221,7 @@ static void G_GNUC_PRINTF (2, 3) coreaudio_logerr (
|
|||||||
coreaudio_logstatus (status);
|
coreaudio_logstatus (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void G_GNUC_PRINTF (3, 4) coreaudio_logerr2 (
|
static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
|
||||||
OSStatus status,
|
OSStatus status,
|
||||||
const char *typ,
|
const char *typ,
|
||||||
const char *fmt,
|
const char *fmt,
|
||||||
@ -288,7 +283,6 @@ static int coreaudio_buf_unlock (coreaudioVoiceOut *core, const char *fn_name)
|
|||||||
coreaudio_buf_unlock(core, "coreaudio_" #name); \
|
coreaudio_buf_unlock(core, "coreaudio_" #name); \
|
||||||
return ret; \
|
return ret; \
|
||||||
}
|
}
|
||||||
COREAUDIO_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
|
|
||||||
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||||
(hw, size))
|
(hw, size))
|
||||||
COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
|
COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
|
||||||
@ -339,10 +333,12 @@ static OSStatus audioDeviceIOProc(
|
|||||||
|
|
||||||
len = frameCount * hw->info.bytes_per_frame;
|
len = frameCount * hw->info.bytes_per_frame;
|
||||||
while (len) {
|
while (len) {
|
||||||
size_t write_len, start;
|
size_t write_len;
|
||||||
|
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
|
||||||
start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
|
if (start < 0) {
|
||||||
assert(start < hw->size_emul);
|
start += hw->size_emul;
|
||||||
|
}
|
||||||
|
assert(start >= 0 && start < hw->size_emul);
|
||||||
|
|
||||||
write_len = MIN(MIN(hw->pending_emul, len),
|
write_len = MIN(MIN(hw->pending_emul, len),
|
||||||
hw->size_emul - start);
|
hw->size_emul - start);
|
||||||
@ -545,6 +541,7 @@ static OSStatus handle_voice_change(
|
|||||||
const AudioObjectPropertyAddress *in_addresses,
|
const AudioObjectPropertyAddress *in_addresses,
|
||||||
void *in_client_data)
|
void *in_client_data)
|
||||||
{
|
{
|
||||||
|
OSStatus status;
|
||||||
coreaudioVoiceOut *core = in_client_data;
|
coreaudioVoiceOut *core = in_client_data;
|
||||||
|
|
||||||
qemu_mutex_lock_iothread();
|
qemu_mutex_lock_iothread();
|
||||||
@ -553,12 +550,13 @@ static OSStatus handle_voice_change(
|
|||||||
fini_out_device(core);
|
fini_out_device(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!init_out_device(core)) {
|
status = init_out_device(core);
|
||||||
|
if (!status) {
|
||||||
update_device_playback_state(core);
|
update_device_playback_state(core);
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
return 0;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||||
@ -606,8 +604,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
coreaudio_playback_logerr(status,
|
coreaudio_playback_logerr(status,
|
||||||
"Could not remove voice property change listener\n");
|
"Could not remove voice property change listener\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -658,8 +654,6 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
|
|||||||
.fini_out = coreaudio_fini_out,
|
.fini_out = coreaudio_fini_out,
|
||||||
/* wrapper for audio_generic_write */
|
/* wrapper for audio_generic_write */
|
||||||
.write = coreaudio_write,
|
.write = coreaudio_write,
|
||||||
/* wrapper for audio_generic_buffer_get_free */
|
|
||||||
.buffer_get_free = coreaudio_buffer_get_free,
|
|
||||||
/* wrapper for audio_generic_get_buffer_out */
|
/* wrapper for audio_generic_get_buffer_out */
|
||||||
.get_buffer_out = coreaudio_get_buffer_out,
|
.get_buffer_out = coreaudio_get_buffer_out,
|
||||||
/* wrapper for audio_generic_put_buffer_out */
|
/* wrapper for audio_generic_put_buffer_out */
|
@ -1,654 +0,0 @@
|
|||||||
/*
|
|
||||||
* QEMU DBus audio
|
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Red Hat, Inc.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include "qemu/error-report.h"
|
|
||||||
#include "qemu/host-utils.h"
|
|
||||||
#include "qemu/module.h"
|
|
||||||
#include "qemu/timer.h"
|
|
||||||
#include "qemu/dbus.h"
|
|
||||||
|
|
||||||
#include <gio/gunixfdlist.h>
|
|
||||||
#include "ui/dbus-display1.h"
|
|
||||||
|
|
||||||
#define AUDIO_CAP "dbus"
|
|
||||||
#include "audio.h"
|
|
||||||
#include "audio_int.h"
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
#define DBUS_DISPLAY1_AUDIO_PATH DBUS_DISPLAY1_ROOT "/Audio"
|
|
||||||
|
|
||||||
#define DBUS_AUDIO_NSAMPLES 1024 /* could be configured? */
|
|
||||||
|
|
||||||
typedef struct DBusAudio {
|
|
||||||
GDBusObjectManagerServer *server;
|
|
||||||
GDBusObjectSkeleton *audio;
|
|
||||||
QemuDBusDisplay1Audio *iface;
|
|
||||||
GHashTable *out_listeners;
|
|
||||||
GHashTable *in_listeners;
|
|
||||||
} DBusAudio;
|
|
||||||
|
|
||||||
typedef struct DBusVoiceOut {
|
|
||||||
HWVoiceOut hw;
|
|
||||||
bool enabled;
|
|
||||||
RateCtl rate;
|
|
||||||
|
|
||||||
void *buf;
|
|
||||||
size_t buf_pos;
|
|
||||||
size_t buf_size;
|
|
||||||
|
|
||||||
bool has_volume;
|
|
||||||
Volume volume;
|
|
||||||
} DBusVoiceOut;
|
|
||||||
|
|
||||||
typedef struct DBusVoiceIn {
|
|
||||||
HWVoiceIn hw;
|
|
||||||
bool enabled;
|
|
||||||
RateCtl rate;
|
|
||||||
|
|
||||||
bool has_volume;
|
|
||||||
Volume volume;
|
|
||||||
} DBusVoiceIn;
|
|
||||||
|
|
||||||
static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
|
||||||
{
|
|
||||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
|
||||||
|
|
||||||
if (!vo->buf) {
|
|
||||||
vo->buf_size = hw->samples * hw->info.bytes_per_frame;
|
|
||||||
vo->buf = g_malloc(vo->buf_size);
|
|
||||||
vo->buf_pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*size = MIN(vo->buf_size - vo->buf_pos, *size);
|
|
||||||
*size = audio_rate_get_bytes(&vo->rate, &hw->info, *size);
|
|
||||||
|
|
||||||
return vo->buf + vo->buf_pos;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t dbus_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
|
||||||
g_autoptr(GBytes) bytes = NULL;
|
|
||||||
g_autoptr(GVariant) v_data = NULL;
|
|
||||||
|
|
||||||
assert(buf == vo->buf + vo->buf_pos && vo->buf_pos + size <= vo->buf_size);
|
|
||||||
vo->buf_pos += size;
|
|
||||||
|
|
||||||
trace_dbus_audio_put_buffer_out(size);
|
|
||||||
|
|
||||||
if (vo->buf_pos < vo->buf_size) {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = g_bytes_new_take(g_steal_pointer(&vo->buf), vo->buf_size);
|
|
||||||
v_data = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
|
||||||
g_variant_ref_sink(v_data);
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
qemu_dbus_display1_audio_out_listener_call_write(
|
|
||||||
listener,
|
|
||||||
(uintptr_t)hw,
|
|
||||||
v_data,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if HOST_BIG_ENDIAN
|
|
||||||
#define AUDIO_HOST_BE TRUE
|
|
||||||
#else
|
|
||||||
#define AUDIO_HOST_BE FALSE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_init_out_listener(QemuDBusDisplay1AudioOutListener *listener,
|
|
||||||
HWVoiceOut *hw)
|
|
||||||
{
|
|
||||||
qemu_dbus_display1_audio_out_listener_call_init(
|
|
||||||
listener,
|
|
||||||
(uintptr_t)hw,
|
|
||||||
hw->info.bits,
|
|
||||||
hw->info.is_signed,
|
|
||||||
hw->info.is_float,
|
|
||||||
hw->info.freq,
|
|
||||||
hw->info.nchannels,
|
|
||||||
hw->info.bytes_per_frame,
|
|
||||||
hw->info.bytes_per_second,
|
|
||||||
hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
dbus_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
|
||||||
|
|
||||||
audio_pcm_init_info(&hw->info, as);
|
|
||||||
hw->samples = DBUS_AUDIO_NSAMPLES;
|
|
||||||
audio_rate_start(&vo->rate);
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
dbus_init_out_listener(listener, hw);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_fini_out(HWVoiceOut *hw)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
qemu_dbus_display1_audio_out_listener_call_fini(
|
|
||||||
listener,
|
|
||||||
(uintptr_t)hw,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_clear_pointer(&vo->buf, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_enable_out(HWVoiceOut *hw, bool enable)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
|
||||||
|
|
||||||
vo->enabled = enable;
|
|
||||||
if (enable) {
|
|
||||||
audio_rate_start(&vo->rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
qemu_dbus_display1_audio_out_listener_call_set_enabled(
|
|
||||||
listener, (uintptr_t)hw, enable,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_volume_out_listener(HWVoiceOut *hw,
|
|
||||||
QemuDBusDisplay1AudioOutListener *listener)
|
|
||||||
{
|
|
||||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
|
||||||
Volume *vol = &vo->volume;
|
|
||||||
g_autoptr(GBytes) bytes = NULL;
|
|
||||||
GVariant *v_vol = NULL;
|
|
||||||
|
|
||||||
if (!vo->has_volume) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(vol->channels < sizeof(vol->vol));
|
|
||||||
bytes = g_bytes_new(vol->vol, vol->channels);
|
|
||||||
v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
|
||||||
qemu_dbus_display1_audio_out_listener_call_set_volume(
|
|
||||||
listener, (uintptr_t)hw, vol->mute, v_vol,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_volume_out(HWVoiceOut *hw, Volume *vol)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioOutListener *listener = NULL;
|
|
||||||
|
|
||||||
vo->has_volume = true;
|
|
||||||
vo->volume = *vol;
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->out_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
dbus_volume_out_listener(hw, listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_init_in_listener(QemuDBusDisplay1AudioInListener *listener, HWVoiceIn *hw)
|
|
||||||
{
|
|
||||||
qemu_dbus_display1_audio_in_listener_call_init(
|
|
||||||
listener,
|
|
||||||
(uintptr_t)hw,
|
|
||||||
hw->info.bits,
|
|
||||||
hw->info.is_signed,
|
|
||||||
hw->info.is_float,
|
|
||||||
hw->info.freq,
|
|
||||||
hw->info.nchannels,
|
|
||||||
hw->info.bytes_per_frame,
|
|
||||||
hw->info.bytes_per_second,
|
|
||||||
hw->info.swap_endianness ? !AUDIO_HOST_BE : AUDIO_HOST_BE,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
dbus_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
|
||||||
|
|
||||||
audio_pcm_init_info(&hw->info, as);
|
|
||||||
hw->samples = DBUS_AUDIO_NSAMPLES;
|
|
||||||
audio_rate_start(&vo->rate);
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
dbus_init_in_listener(listener, hw);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_fini_in(HWVoiceIn *hw)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
qemu_dbus_display1_audio_in_listener_call_fini(
|
|
||||||
listener,
|
|
||||||
(uintptr_t)hw,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_volume_in_listener(HWVoiceIn *hw,
|
|
||||||
QemuDBusDisplay1AudioInListener *listener)
|
|
||||||
{
|
|
||||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
|
||||||
Volume *vol = &vo->volume;
|
|
||||||
g_autoptr(GBytes) bytes = NULL;
|
|
||||||
GVariant *v_vol = NULL;
|
|
||||||
|
|
||||||
if (!vo->has_volume) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(vol->channels < sizeof(vol->vol));
|
|
||||||
bytes = g_bytes_new(vol->vol, vol->channels);
|
|
||||||
v_vol = g_variant_new_from_bytes(G_VARIANT_TYPE("ay"), bytes, TRUE);
|
|
||||||
qemu_dbus_display1_audio_in_listener_call_set_volume(
|
|
||||||
listener, (uintptr_t)hw, vol->mute, v_vol,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_volume_in(HWVoiceIn *hw, Volume *vol)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
|
||||||
|
|
||||||
vo->has_volume = true;
|
|
||||||
vo->volume = *vol;
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
dbus_volume_in_listener(hw, listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
dbus_read(HWVoiceIn *hw, void *buf, size_t size)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
/* DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw); */
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
|
||||||
|
|
||||||
trace_dbus_audio_read(size);
|
|
||||||
|
|
||||||
/* size = audio_rate_get_bytes(&vo->rate, &hw->info, size); */
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
g_autoptr(GVariant) v_data = NULL;
|
|
||||||
const char *data;
|
|
||||||
gsize n = 0;
|
|
||||||
|
|
||||||
if (qemu_dbus_display1_audio_in_listener_call_read_sync(
|
|
||||||
listener,
|
|
||||||
(uintptr_t)hw,
|
|
||||||
size,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1,
|
|
||||||
&v_data, NULL, NULL)) {
|
|
||||||
data = g_variant_get_fixed_array(v_data, &n, 1);
|
|
||||||
g_warn_if_fail(n <= size);
|
|
||||||
size = MIN(n, size);
|
|
||||||
memcpy(buf, data, size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_enable_in(HWVoiceIn *hw, bool enable)
|
|
||||||
{
|
|
||||||
DBusAudio *da = (DBusAudio *)hw->s->drv_opaque;
|
|
||||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
|
||||||
GHashTableIter iter;
|
|
||||||
QemuDBusDisplay1AudioInListener *listener = NULL;
|
|
||||||
|
|
||||||
vo->enabled = enable;
|
|
||||||
if (enable) {
|
|
||||||
audio_rate_start(&vo->rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_iter_init(&iter, da->in_listeners);
|
|
||||||
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {
|
|
||||||
qemu_dbus_display1_audio_in_listener_call_set_enabled(
|
|
||||||
listener, (uintptr_t)hw, enable,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
dbus_audio_init(Audiodev *dev)
|
|
||||||
{
|
|
||||||
DBusAudio *da = g_new0(DBusAudio, 1);
|
|
||||||
|
|
||||||
da->out_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
|
|
||||||
g_free, g_object_unref);
|
|
||||||
da->in_listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
|
|
||||||
g_free, g_object_unref);
|
|
||||||
return da;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_audio_fini(void *opaque)
|
|
||||||
{
|
|
||||||
DBusAudio *da = opaque;
|
|
||||||
|
|
||||||
if (da->server) {
|
|
||||||
g_dbus_object_manager_server_unexport(da->server,
|
|
||||||
DBUS_DISPLAY1_AUDIO_PATH);
|
|
||||||
}
|
|
||||||
g_clear_object(&da->audio);
|
|
||||||
g_clear_object(&da->iface);
|
|
||||||
g_clear_pointer(&da->in_listeners, g_hash_table_unref);
|
|
||||||
g_clear_pointer(&da->out_listeners, g_hash_table_unref);
|
|
||||||
g_clear_object(&da->server);
|
|
||||||
g_free(da);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
listener_out_vanished_cb(GDBusConnection *connection,
|
|
||||||
gboolean remote_peer_vanished,
|
|
||||||
GError *error,
|
|
||||||
DBusAudio *da)
|
|
||||||
{
|
|
||||||
char *name = g_object_get_data(G_OBJECT(connection), "name");
|
|
||||||
|
|
||||||
g_hash_table_remove(da->out_listeners, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
listener_in_vanished_cb(GDBusConnection *connection,
|
|
||||||
gboolean remote_peer_vanished,
|
|
||||||
GError *error,
|
|
||||||
DBusAudio *da)
|
|
||||||
{
|
|
||||||
char *name = g_object_get_data(G_OBJECT(connection), "name");
|
|
||||||
|
|
||||||
g_hash_table_remove(da->in_listeners, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
dbus_audio_register_listener(AudioState *s,
|
|
||||||
GDBusMethodInvocation *invocation,
|
|
||||||
GUnixFDList *fd_list,
|
|
||||||
GVariant *arg_listener,
|
|
||||||
bool out)
|
|
||||||
{
|
|
||||||
DBusAudio *da = s->drv_opaque;
|
|
||||||
const char *sender = g_dbus_method_invocation_get_sender(invocation);
|
|
||||||
g_autoptr(GDBusConnection) listener_conn = NULL;
|
|
||||||
g_autoptr(GError) err = NULL;
|
|
||||||
g_autoptr(GSocket) socket = NULL;
|
|
||||||
g_autoptr(GSocketConnection) socket_conn = NULL;
|
|
||||||
g_autofree char *guid = g_dbus_generate_guid();
|
|
||||||
GHashTable *listeners = out ? da->out_listeners : da->in_listeners;
|
|
||||||
GObject *listener;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
trace_dbus_audio_register(sender, out ? "out" : "in");
|
|
||||||
|
|
||||||
if (g_hash_table_contains(listeners, sender)) {
|
|
||||||
g_dbus_method_invocation_return_error(invocation,
|
|
||||||
DBUS_DISPLAY_ERROR,
|
|
||||||
DBUS_DISPLAY_ERROR_INVALID,
|
|
||||||
"`%s` is already registered!",
|
|
||||||
sender);
|
|
||||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
|
|
||||||
if (err) {
|
|
||||||
g_dbus_method_invocation_return_error(invocation,
|
|
||||||
DBUS_DISPLAY_ERROR,
|
|
||||||
DBUS_DISPLAY_ERROR_FAILED,
|
|
||||||
"Couldn't get peer fd: %s",
|
|
||||||
err->message);
|
|
||||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
socket = g_socket_new_from_fd(fd, &err);
|
|
||||||
if (err) {
|
|
||||||
g_dbus_method_invocation_return_error(invocation,
|
|
||||||
DBUS_DISPLAY_ERROR,
|
|
||||||
DBUS_DISPLAY_ERROR_FAILED,
|
|
||||||
"Couldn't make a socket: %s",
|
|
||||||
err->message);
|
|
||||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
|
||||||
}
|
|
||||||
socket_conn = g_socket_connection_factory_create_connection(socket);
|
|
||||||
if (out) {
|
|
||||||
qemu_dbus_display1_audio_complete_register_out_listener(
|
|
||||||
da->iface, invocation, NULL);
|
|
||||||
} else {
|
|
||||||
qemu_dbus_display1_audio_complete_register_in_listener(
|
|
||||||
da->iface, invocation, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
listener_conn =
|
|
||||||
g_dbus_connection_new_sync(
|
|
||||||
G_IO_STREAM(socket_conn),
|
|
||||||
guid,
|
|
||||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
|
|
||||||
NULL, NULL, &err);
|
|
||||||
if (err) {
|
|
||||||
error_report("Failed to setup peer connection: %s", err->message);
|
|
||||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
listener = out ?
|
|
||||||
G_OBJECT(qemu_dbus_display1_audio_out_listener_proxy_new_sync(
|
|
||||||
listener_conn,
|
|
||||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
|
||||||
NULL,
|
|
||||||
"/org/qemu/Display1/AudioOutListener",
|
|
||||||
NULL,
|
|
||||||
&err)) :
|
|
||||||
G_OBJECT(qemu_dbus_display1_audio_in_listener_proxy_new_sync(
|
|
||||||
listener_conn,
|
|
||||||
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
|
||||||
NULL,
|
|
||||||
"/org/qemu/Display1/AudioInListener",
|
|
||||||
NULL,
|
|
||||||
&err));
|
|
||||||
if (!listener) {
|
|
||||||
error_report("Failed to setup proxy: %s", err->message);
|
|
||||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out) {
|
|
||||||
HWVoiceOut *hw;
|
|
||||||
|
|
||||||
QLIST_FOREACH(hw, &s->hw_head_out, entries) {
|
|
||||||
DBusVoiceOut *vo = container_of(hw, DBusVoiceOut, hw);
|
|
||||||
QemuDBusDisplay1AudioOutListener *l =
|
|
||||||
QEMU_DBUS_DISPLAY1_AUDIO_OUT_LISTENER(listener);
|
|
||||||
|
|
||||||
dbus_init_out_listener(l, hw);
|
|
||||||
qemu_dbus_display1_audio_out_listener_call_set_enabled(
|
|
||||||
l, (uintptr_t)hw, vo->enabled,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
HWVoiceIn *hw;
|
|
||||||
|
|
||||||
QLIST_FOREACH(hw, &s->hw_head_in, entries) {
|
|
||||||
DBusVoiceIn *vo = container_of(hw, DBusVoiceIn, hw);
|
|
||||||
QemuDBusDisplay1AudioInListener *l =
|
|
||||||
QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener);
|
|
||||||
|
|
||||||
dbus_init_in_listener(
|
|
||||||
QEMU_DBUS_DISPLAY1_AUDIO_IN_LISTENER(listener), hw);
|
|
||||||
qemu_dbus_display1_audio_in_listener_call_set_enabled(
|
|
||||||
l, (uintptr_t)hw, vo->enabled,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_set_data_full(G_OBJECT(listener_conn), "name",
|
|
||||||
g_strdup(sender), g_free);
|
|
||||||
g_hash_table_insert(listeners, g_strdup(sender), listener);
|
|
||||||
g_object_connect(listener_conn,
|
|
||||||
"signal::closed",
|
|
||||||
out ? listener_out_vanished_cb : listener_in_vanished_cb,
|
|
||||||
da,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
return DBUS_METHOD_INVOCATION_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
dbus_audio_register_out_listener(AudioState *s,
|
|
||||||
GDBusMethodInvocation *invocation,
|
|
||||||
GUnixFDList *fd_list,
|
|
||||||
GVariant *arg_listener)
|
|
||||||
{
|
|
||||||
return dbus_audio_register_listener(s, invocation,
|
|
||||||
fd_list, arg_listener, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
dbus_audio_register_in_listener(AudioState *s,
|
|
||||||
GDBusMethodInvocation *invocation,
|
|
||||||
GUnixFDList *fd_list,
|
|
||||||
GVariant *arg_listener)
|
|
||||||
{
|
|
||||||
return dbus_audio_register_listener(s, invocation,
|
|
||||||
fd_list, arg_listener, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server)
|
|
||||||
{
|
|
||||||
DBusAudio *da = s->drv_opaque;
|
|
||||||
|
|
||||||
g_assert(da);
|
|
||||||
g_assert(!da->server);
|
|
||||||
|
|
||||||
da->server = g_object_ref(server);
|
|
||||||
|
|
||||||
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
|
|
||||||
da->iface = qemu_dbus_display1_audio_skeleton_new();
|
|
||||||
g_object_connect(da->iface,
|
|
||||||
"swapped-signal::handle-register-in-listener",
|
|
||||||
dbus_audio_register_in_listener, s,
|
|
||||||
"swapped-signal::handle-register-out-listener",
|
|
||||||
dbus_audio_register_out_listener, s,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
|
|
||||||
G_DBUS_INTERFACE_SKELETON(da->iface));
|
|
||||||
g_dbus_object_manager_server_export(da->server, da->audio);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct audio_pcm_ops dbus_pcm_ops = {
|
|
||||||
.init_out = dbus_init_out,
|
|
||||||
.fini_out = dbus_fini_out,
|
|
||||||
.write = audio_generic_write,
|
|
||||||
.get_buffer_out = dbus_get_buffer_out,
|
|
||||||
.put_buffer_out = dbus_put_buffer_out,
|
|
||||||
.enable_out = dbus_enable_out,
|
|
||||||
.volume_out = dbus_volume_out,
|
|
||||||
|
|
||||||
.init_in = dbus_init_in,
|
|
||||||
.fini_in = dbus_fini_in,
|
|
||||||
.read = dbus_read,
|
|
||||||
.run_buffer_in = audio_generic_run_buffer_in,
|
|
||||||
.enable_in = dbus_enable_in,
|
|
||||||
.volume_in = dbus_volume_in,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct audio_driver dbus_audio_driver = {
|
|
||||||
.name = "dbus",
|
|
||||||
.descr = "Timer based audio exposed with DBus interface",
|
|
||||||
.init = dbus_audio_init,
|
|
||||||
.fini = dbus_audio_fini,
|
|
||||||
.set_dbus_server = dbus_audio_set_server,
|
|
||||||
.pcm_ops = &dbus_pcm_ops,
|
|
||||||
.can_be_default = 1,
|
|
||||||
.max_voices_out = INT_MAX,
|
|
||||||
.max_voices_in = INT_MAX,
|
|
||||||
.voice_size_out = sizeof(DBusVoiceOut),
|
|
||||||
.voice_size_in = sizeof(DBusVoiceIn)
|
|
||||||
};
|
|
||||||
|
|
||||||
static void register_audio_dbus(void)
|
|
||||||
{
|
|
||||||
audio_driver_register(&dbus_audio_driver);
|
|
||||||
}
|
|
||||||
type_init(register_audio_dbus);
|
|
||||||
|
|
||||||
module_dep("ui-dbus")
|
|
@ -222,7 +222,7 @@ static void dsound_log_hresult (HRESULT hr)
|
|||||||
AUD_log (AUDIO_CAP, "Reason: %s\n", str);
|
AUD_log (AUDIO_CAP, "Reason: %s\n", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void G_GNUC_PRINTF (2, 3) dsound_logerr (
|
static void GCC_FMT_ATTR (2, 3) dsound_logerr (
|
||||||
HRESULT hr,
|
HRESULT hr,
|
||||||
const char *fmt,
|
const char *fmt,
|
||||||
...
|
...
|
||||||
@ -237,7 +237,7 @@ static void G_GNUC_PRINTF (2, 3) dsound_logerr (
|
|||||||
dsound_log_hresult (hr);
|
dsound_log_hresult (hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void G_GNUC_PRINTF (3, 4) dsound_logerr2 (
|
static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
|
||||||
HRESULT hr,
|
HRESULT hr,
|
||||||
const char *typ,
|
const char *typ,
|
||||||
const char *fmt,
|
const char *fmt,
|
||||||
@ -427,18 +427,22 @@ static void dsound_enable_out(HWVoiceOut *hw, bool enable)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t dsound_buffer_get_free(HWVoiceOut *hw)
|
static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||||
{
|
{
|
||||||
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
||||||
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
DWORD ppos, wpos;
|
DWORD ppos, wpos, act_size;
|
||||||
|
size_t req_size;
|
||||||
|
int err;
|
||||||
|
void *ret;
|
||||||
|
|
||||||
hr = IDirectSoundBuffer_GetCurrentPosition(
|
hr = IDirectSoundBuffer_GetCurrentPosition(
|
||||||
dsb, &ppos, ds->first_time ? &wpos : NULL);
|
dsb, &ppos, ds->first_time ? &wpos : NULL);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dsound_logerr(hr, "Could not get playback buffer position\n");
|
dsound_logerr(hr, "Could not get playback buffer position\n");
|
||||||
return 0;
|
*size = 0;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ds->first_time) {
|
if (ds->first_time) {
|
||||||
@ -446,20 +450,13 @@ static size_t dsound_buffer_get_free(HWVoiceOut *hw)
|
|||||||
ds->first_time = false;
|
ds->first_time = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
|
req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
|
||||||
}
|
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
||||||
|
|
||||||
static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
if (req_size == 0) {
|
||||||
{
|
*size = 0;
|
||||||
DSoundVoiceOut *ds = (DSoundVoiceOut *)hw;
|
return NULL;
|
||||||
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
}
|
||||||
DWORD act_size;
|
|
||||||
size_t req_size;
|
|
||||||
int err;
|
|
||||||
void *ret;
|
|
||||||
|
|
||||||
req_size = MIN(*size, hw->size_emul - hw->pos_emul);
|
|
||||||
assert(req_size > 0);
|
|
||||||
|
|
||||||
err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
|
err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
|
||||||
&act_size, NULL, false, ds->s);
|
&act_size, NULL, false, ds->s);
|
||||||
@ -539,12 +536,13 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
|||||||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||||
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
DWORD rpos, act_size;
|
DWORD cpos, rpos, act_size;
|
||||||
size_t req_size;
|
size_t req_size;
|
||||||
int err;
|
int err;
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, NULL, &rpos);
|
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
|
||||||
|
dscb, &cpos, ds->first_time ? &rpos : NULL);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dsound_logerr(hr, "Could not get capture buffer position\n");
|
dsound_logerr(hr, "Could not get capture buffer position\n");
|
||||||
*size = 0;
|
*size = 0;
|
||||||
@ -556,7 +554,7 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
|||||||
ds->first_time = false;
|
ds->first_time = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
req_size = audio_ring_dist(rpos, hw->pos_emul, hw->size_emul);
|
req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
|
||||||
req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul));
|
req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul));
|
||||||
|
|
||||||
if (req_size == 0) {
|
if (req_size == 0) {
|
||||||
@ -623,7 +621,7 @@ static void *dsound_audio_init(Audiodev *dev)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
dsound *s = g_new0(dsound, 1);
|
dsound *s = g_malloc0(sizeof(dsound));
|
||||||
AudiodevDsoundOptions *dso;
|
AudiodevDsoundOptions *dso;
|
||||||
|
|
||||||
assert(dev->driver == AUDIODEV_DRIVER_DSOUND);
|
assert(dev->driver == AUDIODEV_DRIVER_DSOUND);
|
||||||
@ -702,7 +700,6 @@ static struct audio_pcm_ops dsound_pcm_ops = {
|
|||||||
.init_out = dsound_init_out,
|
.init_out = dsound_init_out,
|
||||||
.fini_out = dsound_fini_out,
|
.fini_out = dsound_fini_out,
|
||||||
.write = audio_generic_write,
|
.write = audio_generic_write,
|
||||||
.buffer_get_free = dsound_buffer_get_free,
|
|
||||||
.get_buffer_out = dsound_get_buffer_out,
|
.get_buffer_out = dsound_get_buffer_out,
|
||||||
.put_buffer_out = dsound_put_buffer_out,
|
.put_buffer_out = dsound_put_buffer_out,
|
||||||
.enable_out = dsound_enable_out,
|
.enable_out = dsound_enable_out,
|
||||||
|
@ -97,9 +97,9 @@ static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames)
|
|||||||
buffer->used = 0;
|
buffer->used = 0;
|
||||||
buffer->rptr = 0;
|
buffer->rptr = 0;
|
||||||
buffer->wptr = 0;
|
buffer->wptr = 0;
|
||||||
buffer->data = g_new(float *, channels);
|
buffer->data = g_malloc(channels * sizeof(float *));
|
||||||
for (int i = 0; i < channels; ++i) {
|
for (int i = 0; i < channels; ++i) {
|
||||||
buffer->data[i] = g_new(float, frames);
|
buffer->data[i] = g_malloc(frames * sizeof(float));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +453,7 @@ static int qjack_client_init(QJackClient *c)
|
|||||||
jack_on_shutdown(c->client, qjack_shutdown, c);
|
jack_on_shutdown(c->client, qjack_shutdown, c);
|
||||||
|
|
||||||
/* allocate and register the ports */
|
/* allocate and register the ports */
|
||||||
c->port = g_new(jack_port_t *, c->nchannels);
|
c->port = g_malloc(sizeof(jack_port_t *) * c->nchannels);
|
||||||
for (int i = 0; i < c->nchannels; ++i) {
|
for (int i = 0; i < c->nchannels; ++i) {
|
||||||
|
|
||||||
char port_name[16];
|
char port_name[16];
|
||||||
@ -483,8 +483,8 @@ static int qjack_client_init(QJackClient *c)
|
|||||||
c->buffersize = 512;
|
c->buffersize = 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a 3 period buffer */
|
/* create a 2 period buffer */
|
||||||
qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 3);
|
qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2);
|
||||||
|
|
||||||
qjack_client_connect_ports(c);
|
qjack_client_connect_ports(c);
|
||||||
c->state = QJACK_STATE_RUNNING;
|
c->state = QJACK_STATE_RUNNING;
|
||||||
@ -622,7 +622,6 @@ static void qjack_enable_in(HWVoiceIn *hw, bool enable)
|
|||||||
ji->c.enabled = enable;
|
ji->c.enabled = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(WIN32) && defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
|
|
||||||
static int qjack_thread_creator(jack_native_thread_t *thread,
|
static int qjack_thread_creator(jack_native_thread_t *thread,
|
||||||
const pthread_attr_t *attr, void *(*function)(void *), void *arg)
|
const pthread_attr_t *attr, void *(*function)(void *), void *arg)
|
||||||
{
|
{
|
||||||
@ -636,7 +635,6 @@ static int qjack_thread_creator(jack_native_thread_t *thread,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void *qjack_init(Audiodev *dev)
|
static void *qjack_init(Audiodev *dev)
|
||||||
{
|
{
|
||||||
@ -652,7 +650,6 @@ static struct audio_pcm_ops jack_pcm_ops = {
|
|||||||
.init_out = qjack_init_out,
|
.init_out = qjack_init_out,
|
||||||
.fini_out = qjack_fini_out,
|
.fini_out = qjack_fini_out,
|
||||||
.write = qjack_write,
|
.write = qjack_write,
|
||||||
.buffer_get_free = audio_generic_buffer_get_free,
|
|
||||||
.run_buffer_out = audio_generic_run_buffer_out,
|
.run_buffer_out = audio_generic_run_buffer_out,
|
||||||
.enable_out = qjack_enable_out,
|
.enable_out = qjack_enable_out,
|
||||||
|
|
||||||
@ -690,9 +687,7 @@ static void register_audio_jack(void)
|
|||||||
{
|
{
|
||||||
qemu_mutex_init(&qjack_shutdown_lock);
|
qemu_mutex_init(&qjack_shutdown_lock);
|
||||||
audio_driver_register(&jack_driver);
|
audio_driver_register(&jack_driver);
|
||||||
#if !defined(WIN32) && defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
|
|
||||||
jack_set_thread_creator(qjack_thread_creator);
|
jack_set_thread_creator(qjack_thread_creator);
|
||||||
#endif
|
|
||||||
jack_set_error_function(qjack_error);
|
jack_set_error_function(qjack_error);
|
||||||
jack_set_info_function(qjack_info);
|
jack_set_info_function(qjack_info);
|
||||||
}
|
}
|
||||||
|
@ -7,30 +7,24 @@ softmmu_ss.add(files(
|
|||||||
'wavcapture.c',
|
'wavcapture.c',
|
||||||
))
|
))
|
||||||
|
|
||||||
softmmu_ss.add(when: coreaudio, if_true: files('coreaudio.m'))
|
softmmu_ss.add(when: [coreaudio, 'CONFIG_AUDIO_COREAUDIO'], if_true: files('coreaudio.c'))
|
||||||
softmmu_ss.add(when: dsound, if_true: files('dsoundaudio.c', 'audio_win_int.c'))
|
softmmu_ss.add(when: [dsound, 'CONFIG_AUDIO_DSOUND'], if_true: files('dsoundaudio.c'))
|
||||||
|
softmmu_ss.add(when: ['CONFIG_AUDIO_WIN_INT'], if_true: files('audio_win_int.c'))
|
||||||
|
|
||||||
audio_modules = {}
|
audio_modules = {}
|
||||||
foreach m : [
|
foreach m : [
|
||||||
['alsa', alsa, files('alsaaudio.c')],
|
['CONFIG_AUDIO_ALSA', 'alsa', alsa, 'alsaaudio.c'],
|
||||||
['oss', oss, files('ossaudio.c')],
|
['CONFIG_AUDIO_OSS', 'oss', oss, 'ossaudio.c'],
|
||||||
['pa', pulse, files('paaudio.c')],
|
['CONFIG_AUDIO_PA', 'pa', pulse, 'paaudio.c'],
|
||||||
['sdl', sdl, files('sdlaudio.c')],
|
['CONFIG_AUDIO_SDL', 'sdl', sdl, 'sdlaudio.c'],
|
||||||
['jack', jack, files('jackaudio.c')],
|
['CONFIG_AUDIO_JACK', 'jack', jack, 'jackaudio.c'],
|
||||||
['sndio', sndio, files('sndioaudio.c')],
|
['CONFIG_SPICE', 'spice', spice, 'spiceaudio.c']
|
||||||
['spice', spice, files('spiceaudio.c')]
|
|
||||||
]
|
]
|
||||||
if m[1].found()
|
if config_host.has_key(m[0])
|
||||||
module_ss = ss.source_set()
|
module_ss = ss.source_set()
|
||||||
module_ss.add(m[1], m[2])
|
module_ss.add(when: m[2], if_true: files(m[3]))
|
||||||
audio_modules += {m[0] : module_ss}
|
audio_modules += {m[1] : module_ss}
|
||||||
endif
|
endif
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
if dbus_display
|
|
||||||
module_ss = ss.source_set()
|
|
||||||
module_ss.add(when: gio, if_true: files('dbusaudio.c'))
|
|
||||||
audio_modules += {'dbus': module_ss}
|
|
||||||
endif
|
|
||||||
|
|
||||||
modules += {'audio': audio_modules}
|
modules += {'audio': audio_modules}
|
||||||
|
@ -342,13 +342,13 @@ f_sample *mixeng_clip_float[2] = {
|
|||||||
void audio_sample_to_uint64(const void *samples, int pos,
|
void audio_sample_to_uint64(const void *samples, int pos,
|
||||||
uint64_t *left, uint64_t *right)
|
uint64_t *left, uint64_t *right)
|
||||||
{
|
{
|
||||||
|
const struct st_sample *sample = samples;
|
||||||
|
sample += pos;
|
||||||
#ifdef FLOAT_MIXENG
|
#ifdef FLOAT_MIXENG
|
||||||
error_report(
|
error_report(
|
||||||
"Coreaudio and floating point samples are not supported by replay yet");
|
"Coreaudio and floating point samples are not supported by replay yet");
|
||||||
abort();
|
abort();
|
||||||
#else
|
#else
|
||||||
const struct st_sample *sample = samples;
|
|
||||||
sample += pos;
|
|
||||||
*left = sample->l;
|
*left = sample->l;
|
||||||
*right = sample->r;
|
*right = sample->r;
|
||||||
#endif
|
#endif
|
||||||
@ -357,13 +357,13 @@ void audio_sample_to_uint64(const void *samples, int pos,
|
|||||||
void audio_sample_from_uint64(void *samples, int pos,
|
void audio_sample_from_uint64(void *samples, int pos,
|
||||||
uint64_t left, uint64_t right)
|
uint64_t left, uint64_t right)
|
||||||
{
|
{
|
||||||
|
struct st_sample *sample = samples;
|
||||||
|
sample += pos;
|
||||||
#ifdef FLOAT_MIXENG
|
#ifdef FLOAT_MIXENG
|
||||||
error_report(
|
error_report(
|
||||||
"Coreaudio and floating point samples are not supported by replay yet");
|
"Coreaudio and floating point samples are not supported by replay yet");
|
||||||
abort();
|
abort();
|
||||||
#else
|
#else
|
||||||
struct st_sample *sample = samples;
|
|
||||||
sample += pos;
|
|
||||||
sample->l = left;
|
sample->l = left;
|
||||||
sample->r = right;
|
sample->r = right;
|
||||||
#endif
|
#endif
|
||||||
|
@ -44,7 +44,7 @@ typedef struct NoVoiceIn {
|
|||||||
static size_t no_write(HWVoiceOut *hw, void *buf, size_t len)
|
static size_t no_write(HWVoiceOut *hw, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
NoVoiceOut *no = (NoVoiceOut *) hw;
|
NoVoiceOut *no = (NoVoiceOut *) hw;
|
||||||
return audio_rate_get_bytes(&no->rate, &hw->info, len);
|
return audio_rate_get_bytes(&hw->info, &no->rate, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
||||||
@ -89,7 +89,7 @@ static void no_fini_in (HWVoiceIn *hw)
|
|||||||
static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
|
static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
NoVoiceIn *no = (NoVoiceIn *) hw;
|
NoVoiceIn *no = (NoVoiceIn *) hw;
|
||||||
int64_t bytes = audio_rate_get_bytes(&no->rate, &hw->info, size);
|
int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size);
|
||||||
|
|
||||||
audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame);
|
audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame);
|
||||||
return bytes;
|
return bytes;
|
||||||
@ -118,7 +118,6 @@ static struct audio_pcm_ops no_pcm_ops = {
|
|||||||
.init_out = no_init_out,
|
.init_out = no_init_out,
|
||||||
.fini_out = no_fini_out,
|
.fini_out = no_fini_out,
|
||||||
.write = no_write,
|
.write = no_write,
|
||||||
.buffer_get_free = audio_generic_buffer_get_free,
|
|
||||||
.run_buffer_out = audio_generic_run_buffer_out,
|
.run_buffer_out = audio_generic_run_buffer_out,
|
||||||
.enable_out = no_enable_out,
|
.enable_out = no_enable_out,
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ struct oss_params {
|
|||||||
int fragsize;
|
int fragsize;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void G_GNUC_PRINTF (2, 3) oss_logerr (int err, const char *fmt, ...)
|
static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ static void G_GNUC_PRINTF (2, 3) oss_logerr (int err, const char *fmt, ...)
|
|||||||
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
|
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void G_GNUC_PRINTF (3, 4) oss_logerr2 (
|
static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
|
||||||
int err,
|
int err,
|
||||||
const char *typ,
|
const char *typ,
|
||||||
const char *fmt,
|
const char *fmt,
|
||||||
@ -389,23 +389,11 @@ static void oss_run_buffer_out(HWVoiceOut *hw)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t oss_buffer_get_free(HWVoiceOut *hw)
|
|
||||||
{
|
|
||||||
OSSVoiceOut *oss = (OSSVoiceOut *)hw;
|
|
||||||
|
|
||||||
if (oss->mmapped) {
|
|
||||||
return oss_get_available_bytes(oss);
|
|
||||||
} else {
|
|
||||||
return audio_generic_buffer_get_free(hw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||||
{
|
{
|
||||||
OSSVoiceOut *oss = (OSSVoiceOut *)hw;
|
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
||||||
|
|
||||||
if (oss->mmapped) {
|
if (oss->mmapped) {
|
||||||
*size = hw->size_emul - hw->pos_emul;
|
*size = MIN(oss_get_available_bytes(oss), hw->size_emul - hw->pos_emul);
|
||||||
return hw->buf_emul + hw->pos_emul;
|
return hw->buf_emul + hw->pos_emul;
|
||||||
} else {
|
} else {
|
||||||
return audio_generic_get_buffer_out(hw, size);
|
return audio_generic_get_buffer_out(hw, size);
|
||||||
@ -762,7 +750,6 @@ static struct audio_pcm_ops oss_pcm_ops = {
|
|||||||
.init_out = oss_init_out,
|
.init_out = oss_init_out,
|
||||||
.fini_out = oss_fini_out,
|
.fini_out = oss_fini_out,
|
||||||
.write = oss_write,
|
.write = oss_write,
|
||||||
.buffer_get_free = oss_buffer_get_free,
|
|
||||||
.run_buffer_out = oss_run_buffer_out,
|
.run_buffer_out = oss_run_buffer_out,
|
||||||
.get_buffer_out = oss_get_buffer_out,
|
.get_buffer_out = oss_get_buffer_out,
|
||||||
.put_buffer_out = oss_put_buffer_out,
|
.put_buffer_out = oss_put_buffer_out,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user