mirror of https://github.com/xemu-project/xemu.git
v6.0.0-rc3 release
-----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmB3WUoZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3jEMD/46lT/PC77XxfNfzjpFhjBH XIGxr+zIAN2FvxH8ILaoPZn+1jhiS4FVqpq5aKyoaK61f3ZRsulO02Qb9QRHoy+P GOmunAAKN0lIbbvsLHQc9N1ndiSZ3uIhf1WlDvXVomBqDxhKDJY60pHrtGBnTyEe BdS7H41WIWWorrMdK/sHxudCsZkaQEwJu5pfIvqbNg4tH5AIaQabGak5tOWuKJ7m AFFCTp0g+g5ibWl9mx1sbNbE5WRzjSN6MepCz/OLZYGxYQ9Q/1xxrq/e3rpHblkh TWR5iWxrsEU9iIhr5AOQl5ISuMLO1lVJjDudej0zAaf3D9ekJ7a6TD5tAfSTYm4z lpcVk5PGJntHdnZ3rHfnlLpTKUfTifzCkfm8sxgqP/5Jyty/8b0s8FU0RVspJdPF Fa+axpcQnRP7D+MAB1d5sPXWsrf1KO5FBohsbBWAgZIw28qg7Q59iuSXntpTbr09 QgeohMKqITJ41ADzAq0K8JEBCzwH9JkbfFYsISd6OoEvB77PdM4XB7npRUNG9LP9 9lZLFqY0VPAdDkDwzJEZS45vUjKIeHLK9XR5Slz6feKG29P69L4L6Owd250m5NRP FwslKSjJwLY4PcHgcMytk7V8Yur536I43m4VFwTtHFQz1SBjkAAsUDP+Q+MHsYr0 eVVycmRz7bOdgWDZadJpqQ== =zM6v -----END PGP SIGNATURE----- Merge tag 'v6.0.0-rc3' into merge/qemu-v6.0.0 Merge v6.0.0-rc3 release
This commit is contained in:
commit
d1d32026f8
153
.cirrus.yml
153
.cirrus.yml
|
@ -3,40 +3,163 @@ env:
|
|||
|
||||
freebsd_12_task:
|
||||
freebsd_instance:
|
||||
image_family: freebsd-12-1
|
||||
image_family: freebsd-12-2
|
||||
cpu: 8
|
||||
memory: 8G
|
||||
install_script: ASSUME_ALWAYS_YES=yes pkg bootstrap -f ; pkg install -y
|
||||
bash curl cyrus-sasl git glib gmake gnutls gsed
|
||||
nettle perl5 pixman pkgconf png usbredir
|
||||
install_script:
|
||||
- ASSUME_ALWAYS_YES=yes pkg bootstrap -f ;
|
||||
- pkg install -y bash curl cyrus-sasl git glib gmake gnutls gsed
|
||||
nettle perl5 pixman pkgconf png usbredir ninja
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure || { cat config.log; exit 1; }
|
||||
- gmake -j8
|
||||
- gmake V=1 check
|
||||
# TODO: Enable gnutls again once FreeBSD's libtasn1 got fixed
|
||||
# See: https://gitlab.com/gnutls/libtasn1/-/merge_requests/71
|
||||
- ../configure --enable-werror --disable-gnutls
|
||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake -j$(sysctl -n hw.ncpu) check V=1
|
||||
|
||||
macos_task:
|
||||
osx_instance:
|
||||
image: mojave-base
|
||||
image: catalina-base
|
||||
install_script:
|
||||
- brew install pkg-config python gnu-sed glib pixman make sdl2 bash
|
||||
- brew install pkg-config python gnu-sed glib pixman make sdl2 bash ninja
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; }
|
||||
- ../configure --python=/usr/local/bin/python3 --enable-werror
|
||||
--extra-cflags='-Wno-error=deprecated-declarations'
|
||||
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake check
|
||||
- gmake check-unit V=1
|
||||
- gmake check-block V=1
|
||||
- gmake check-qapi-schema V=1
|
||||
- gmake check-softfloat V=1
|
||||
- gmake check-qtest-x86_64 V=1
|
||||
|
||||
macos_xcode_task:
|
||||
osx_instance:
|
||||
# this is an alias for the latest Xcode
|
||||
image: mojave-xcode
|
||||
image: catalina-xcode
|
||||
install_script:
|
||||
- brew install pkg-config gnu-sed glib pixman make sdl2 bash
|
||||
- brew install pkg-config gnu-sed glib pixman make sdl2 bash ninja
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --cc=clang || { cat config.log; exit 1; }
|
||||
- ../configure --extra-cflags='-Wno-error=deprecated-declarations' --enable-modules
|
||||
--enable-werror --cc=clang || { cat config.log meson-logs/meson-log.txt; exit 1; }
|
||||
- gmake -j$(sysctl -n hw.ncpu)
|
||||
- gmake check
|
||||
- gmake check-unit V=1
|
||||
- gmake check-block V=1
|
||||
- gmake check-qapi-schema V=1
|
||||
- gmake check-softfloat V=1
|
||||
- gmake check-qtest-x86_64 V=1
|
||||
|
||||
windows_msys2_task:
|
||||
timeout_in: 90m
|
||||
windows_container:
|
||||
image: cirrusci/windowsservercore:2019
|
||||
os_version: 2019
|
||||
cpu: 8
|
||||
memory: 8G
|
||||
env:
|
||||
CIRRUS_SHELL: powershell
|
||||
MSYS: winsymlinks:nativestrict
|
||||
MSYSTEM: MINGW64
|
||||
MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-01-05/msys2-base-x86_64-20210105.sfx.exe
|
||||
MSYS2_FINGERPRINT: 0
|
||||
MSYS2_PACKAGES: "
|
||||
diffutils git grep make pkg-config sed
|
||||
mingw-w64-x86_64-python
|
||||
mingw-w64-x86_64-python-sphinx
|
||||
mingw-w64-x86_64-toolchain
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-SDL2_image
|
||||
mingw-w64-x86_64-gtk3
|
||||
mingw-w64-x86_64-glib2
|
||||
mingw-w64-x86_64-ninja
|
||||
mingw-w64-x86_64-jemalloc
|
||||
mingw-w64-x86_64-lzo2
|
||||
mingw-w64-x86_64-zstd
|
||||
mingw-w64-x86_64-libjpeg-turbo
|
||||
mingw-w64-x86_64-pixman
|
||||
mingw-w64-x86_64-libgcrypt
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-libssh
|
||||
mingw-w64-x86_64-libxml2
|
||||
mingw-w64-x86_64-snappy
|
||||
mingw-w64-x86_64-libusb
|
||||
mingw-w64-x86_64-usbredir
|
||||
mingw-w64-x86_64-libtasn1
|
||||
mingw-w64-x86_64-nettle
|
||||
mingw-w64-x86_64-cyrus-sasl
|
||||
mingw-w64-x86_64-curl
|
||||
mingw-w64-x86_64-gnutls
|
||||
mingw-w64-x86_64-libnfs
|
||||
"
|
||||
CHERE_INVOKING: 1
|
||||
msys2_cache:
|
||||
folder: C:\tools\archive
|
||||
reupload_on_changes: false
|
||||
# These env variables are used to generate fingerprint to trigger the cache procedure
|
||||
# If wanna to force re-populate msys2, increase MSYS2_FINGERPRINT
|
||||
fingerprint_script:
|
||||
- |
|
||||
echo $env:CIRRUS_TASK_NAME
|
||||
echo $env:MSYS2_URL
|
||||
echo $env:MSYS2_FINGERPRINT
|
||||
echo $env:MSYS2_PACKAGES
|
||||
populate_script:
|
||||
- |
|
||||
md -Force C:\tools\archive\pkg
|
||||
$start_time = Get-Date
|
||||
bitsadmin /transfer msys_download /dynamic /download /priority FOREGROUND $env:MSYS2_URL C:\tools\archive\base.exe
|
||||
Write-Output "Download time taken: $((Get-Date).Subtract($start_time))"
|
||||
cd C:\tools
|
||||
C:\tools\archive\base.exe -y
|
||||
del -Force C:\tools\archive\base.exe
|
||||
Write-Output "Base install time taken: $((Get-Date).Subtract($start_time))"
|
||||
$start_time = Get-Date
|
||||
|
||||
((Get-Content -path C:\tools\msys64\etc\\post-install\\07-pacman-key.post -Raw) -replace '--refresh-keys', '--version') | Set-Content -Path C:\tools\msys64\etc\\post-install\\07-pacman-key.post
|
||||
C:\tools\msys64\usr\bin\bash.exe -lc "sed -i 's/^CheckSpace/#CheckSpace/g' /etc/pacman.conf"
|
||||
C:\tools\msys64\usr\bin\bash.exe -lc "export"
|
||||
C:\tools\msys64\usr\bin\pacman.exe --noconfirm -Sy
|
||||
echo Y | C:\tools\msys64\usr\bin\pacman.exe --noconfirm -Suu --overwrite=*
|
||||
taskkill /F /FI "MODULES eq msys-2.0.dll"
|
||||
tasklist
|
||||
C:\tools\msys64\usr\bin\bash.exe -lc "mv -f /etc/pacman.conf.pacnew /etc/pacman.conf || true"
|
||||
C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Suu --overwrite=*"
|
||||
Write-Output "Core install time taken: $((Get-Date).Subtract($start_time))"
|
||||
$start_time = Get-Date
|
||||
|
||||
C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -S --needed $env:MSYS2_PACKAGES"
|
||||
Write-Output "Package install time taken: $((Get-Date).Subtract($start_time))"
|
||||
$start_time = Get-Date
|
||||
|
||||
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\etc\mtab
|
||||
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\dev\fd
|
||||
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\dev\stderr
|
||||
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\dev\stdin
|
||||
del -Force -ErrorAction SilentlyContinue C:\tools\msys64\dev\stdout
|
||||
del -Force -Recurse -ErrorAction SilentlyContinue C:\tools\msys64\var\cache\pacman\pkg
|
||||
tar cf C:\tools\archive\msys64.tar -C C:\tools\ msys64
|
||||
|
||||
Write-Output "Package archive time taken: $((Get-Date).Subtract($start_time))"
|
||||
del -Force -Recurse -ErrorAction SilentlyContinue c:\tools\msys64
|
||||
install_script:
|
||||
- |
|
||||
$start_time = Get-Date
|
||||
cd C:\tools
|
||||
ls C:\tools\archive\msys64.tar
|
||||
tar xf C:\tools\archive\msys64.tar
|
||||
Write-Output "Extract msys2 time taken: $((Get-Date).Subtract($start_time))"
|
||||
script:
|
||||
- C:\tools\msys64\usr\bin\bash.exe -lc "mkdir build"
|
||||
- C:\tools\msys64\usr\bin\bash.exe -lc "cd build && ../configure --python=python3"
|
||||
- C:\tools\msys64\usr\bin\bash.exe -lc "cd build && make -j8"
|
||||
- exit $LastExitCode
|
||||
test_script:
|
||||
- C:\tools\msys64\usr\bin\bash.exe -lc "cd build && make V=1 check"
|
||||
- exit $LastExitCode
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
# plugin.
|
||||
#
|
||||
# Check https://editorconfig.org for details.
|
||||
#
|
||||
# Emacs: you need https://github.com/10sr/editorconfig-custom-majormode-el
|
||||
# to automatically enable the appropriate major-mode for your files
|
||||
# that aren't already caught by your existing config.
|
||||
#
|
||||
|
||||
root = true
|
||||
|
||||
|
@ -15,16 +20,17 @@ charset = utf-8
|
|||
[*.mak]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
file_type_emacs = makefile
|
||||
emacs_mode = makefile
|
||||
|
||||
[Makefile*]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
file_type_emacs = makefile
|
||||
emacs_mode = makefile
|
||||
|
||||
[*.{c,h}]
|
||||
[*.{c,h,c.inc,h.inc}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
emacs_mode = c
|
||||
|
||||
[*.sh]
|
||||
indent_style = space
|
||||
|
@ -33,11 +39,11 @@ indent_size = 4
|
|||
[*.{s,S}]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
file_type_emacs = asm
|
||||
emacs_mode = asm
|
||||
|
||||
[*.{vert,frag}]
|
||||
file_type_emacs = glsl
|
||||
emacs_mode = glsl
|
||||
|
||||
[*.json]
|
||||
indent_style = space
|
||||
file_type_emacs = python
|
||||
emacs_mode = python
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
*.c.inc diff=c
|
||||
*.h.inc diff=c
|
||||
*.py diff=python
|
|
@ -10,8 +10,8 @@ issues:
|
|||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's master
|
||||
repostories hosted on https://git.qemu.org/git/qemu.git.
|
||||
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 Launchpad:
|
||||
|
@ -24,8 +24,8 @@ pulls:
|
|||
comment: |
|
||||
Thank you for your interest in the QEMU project.
|
||||
|
||||
This repository is a read-only mirror of the project's master
|
||||
repostories hosted on https://git.qemu.org/git/qemu.git.
|
||||
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
|
||||
|
|
|
@ -1,168 +1,18 @@
|
|||
/.doctrees
|
||||
/config-devices.*
|
||||
/config-all-devices.*
|
||||
/config-all-disas.*
|
||||
/config-host.*
|
||||
/config-target.*
|
||||
/config.status
|
||||
/config-temp
|
||||
/tools/virtiofsd/50-qemu-virtiofsd.json
|
||||
/elf2dmp
|
||||
/trace-events-all
|
||||
/trace/generated-events.h
|
||||
/trace/generated-events.c
|
||||
/trace/generated-helpers-wrappers.h
|
||||
/trace/generated-helpers.h
|
||||
/trace/generated-helpers.c
|
||||
/trace/generated-tcg-tracers.h
|
||||
/ui/shader/texture-blit-frag.h
|
||||
/ui/shader/texture-blit-vert.h
|
||||
/ui/shader/texture-blit-flip-vert.h
|
||||
/ui/input-keymap-*.c
|
||||
*-timestamp
|
||||
/*-softmmu
|
||||
/*-darwin-user
|
||||
/*-linux-user
|
||||
/*-bsd-user
|
||||
/ivshmem-client
|
||||
/ivshmem-server
|
||||
/libdis*
|
||||
/libuser
|
||||
/linux-headers/asm
|
||||
/qga/qapi-generated
|
||||
/qapi-gen-timestamp
|
||||
/qapi/qapi-builtin-types.[ch]
|
||||
/qapi/qapi-builtin-visit.[ch]
|
||||
/qapi/qapi-commands-*.[ch]
|
||||
**/qapi/qapi-commands.[ch]
|
||||
**/qapi/qapi-emit-events.[ch]
|
||||
/qapi/qapi-events-*.[ch]
|
||||
**/qapi/qapi-events.[ch]
|
||||
**/qapi/qapi-init-commands.[ch]
|
||||
**/qapi/qapi-introspect.[ch]
|
||||
/qapi/qapi-types-*.[ch]
|
||||
**/qapi/qapi-types.[ch]
|
||||
/qapi/qapi-visit-*.[ch]
|
||||
!/qapi/qapi-visit-core.c
|
||||
**/qapi/qapi-visit.[ch]
|
||||
**/qapi/qapi-doc.texi
|
||||
/qemu-edid
|
||||
/qemu-img
|
||||
/qemu-nbd
|
||||
/qemu-options.def
|
||||
/qemu-options.texi
|
||||
/qemu-img-cmds.texi
|
||||
/qemu-img-cmds.h
|
||||
/qemu-io
|
||||
/qemu-ga
|
||||
/qemu-bridge-helper
|
||||
/qemu-keymap
|
||||
/qemu-monitor.texi
|
||||
/qemu-monitor-info.texi
|
||||
/qemu-storage-daemon
|
||||
/qemu-version.h
|
||||
/qemu-version.h.tmp
|
||||
/module_block.h
|
||||
/scsi/qemu-pr-helper
|
||||
/vhost-user-scsi
|
||||
/vhost-user-blk
|
||||
/vhost-user-gpu
|
||||
/vhost-user-input
|
||||
/fsdev/virtfs-proxy-helper
|
||||
*.tmp
|
||||
*.[1-9]
|
||||
*.a
|
||||
*.aux
|
||||
*.cp
|
||||
*.exe
|
||||
*.msi
|
||||
*.dll
|
||||
*.so
|
||||
*.mo
|
||||
*.fn
|
||||
*.ky
|
||||
*.log
|
||||
*.pdf
|
||||
*.pod
|
||||
*.cps
|
||||
*.fns
|
||||
*.kys
|
||||
*.pg
|
||||
/GNUmakefile
|
||||
/build/
|
||||
*.pyc
|
||||
*.toc
|
||||
*.tp
|
||||
*.vr
|
||||
*.d
|
||||
!/.gitlab-ci.d
|
||||
!/scripts/qemu-guest-agent/fsfreeze-hook.d
|
||||
*.o
|
||||
.sdk
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
/pc-bios/bios-pq/status
|
||||
/pc-bios/edk2-*.fd
|
||||
/pc-bios/vgabios-pq/status
|
||||
/pc-bios/optionrom/linuxboot.asm
|
||||
/pc-bios/optionrom/linuxboot.bin
|
||||
/pc-bios/optionrom/linuxboot.raw
|
||||
/pc-bios/optionrom/linuxboot.img
|
||||
/pc-bios/optionrom/linuxboot_dma.asm
|
||||
/pc-bios/optionrom/linuxboot_dma.bin
|
||||
/pc-bios/optionrom/linuxboot_dma.raw
|
||||
/pc-bios/optionrom/linuxboot_dma.img
|
||||
/pc-bios/optionrom/pvh.asm
|
||||
/pc-bios/optionrom/pvh.bin
|
||||
/pc-bios/optionrom/pvh.raw
|
||||
/pc-bios/optionrom/pvh.img
|
||||
/pc-bios/optionrom/multiboot.asm
|
||||
/pc-bios/optionrom/multiboot.bin
|
||||
/pc-bios/optionrom/multiboot.raw
|
||||
/pc-bios/optionrom/multiboot.img
|
||||
/pc-bios/optionrom/kvmvapic.asm
|
||||
/pc-bios/optionrom/kvmvapic.bin
|
||||
/pc-bios/optionrom/kvmvapic.raw
|
||||
/pc-bios/optionrom/kvmvapic.img
|
||||
/pc-bios/s390-ccw/s390-ccw.elf
|
||||
/pc-bios/s390-ccw/s390-ccw.img
|
||||
/docs/built
|
||||
/docs/interop/qemu-ga-qapi.texi
|
||||
/docs/interop/qemu-ga-ref.html
|
||||
/docs/interop/qemu-ga-ref.info*
|
||||
/docs/interop/qemu-ga-ref.txt
|
||||
/docs/interop/qemu-qmp-qapi.texi
|
||||
/docs/interop/qemu-qmp-ref.html
|
||||
/docs/interop/qemu-qmp-ref.info*
|
||||
/docs/interop/qemu-qmp-ref.txt
|
||||
/docs/version.texi
|
||||
/contrib/vhost-user-gpu/50-qemu-gpu.json
|
||||
*.tps
|
||||
.stgit-*
|
||||
.git-submodule-status
|
||||
cscope.*
|
||||
tags
|
||||
TAGS
|
||||
docker-src.*
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
*~
|
||||
*.ast_raw
|
||||
*.depend_raw
|
||||
trace.h
|
||||
trace.c
|
||||
trace-ust.h
|
||||
trace-ust.h
|
||||
trace-dtrace.h
|
||||
trace-dtrace.dtrace
|
||||
trace-root.h
|
||||
trace-root.c
|
||||
trace-ust-root.h
|
||||
trace-ust-root.h
|
||||
trace-ust-all.h
|
||||
trace-ust-all.c
|
||||
trace-dtrace-root.h
|
||||
trace-dtrace-root.dtrace
|
||||
trace-ust-all.h
|
||||
trace-ust-all.c
|
||||
/target/arm/decode-sve.inc.c
|
||||
|
||||
/dist
|
||||
/xemu-version.c
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# check-dco.py: validate all commits are signed off
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
namespace = "qemu-project"
|
||||
if len(sys.argv) >= 2:
|
||||
namespace = sys.argv[1]
|
||||
|
||||
cwd = os.getcwd()
|
||||
reponame = os.path.basename(cwd)
|
||||
repourl = "https://gitlab.com/%s/%s.git" % (namespace, reponame)
|
||||
|
||||
subprocess.check_call(["git", "remote", "add", "check-dco", repourl])
|
||||
subprocess.check_call(["git", "fetch", "check-dco", "master"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
ancestor = subprocess.check_output(["git", "merge-base",
|
||||
"check-dco/master", "HEAD"],
|
||||
universal_newlines=True)
|
||||
|
||||
ancestor = ancestor.strip()
|
||||
|
||||
subprocess.check_call(["git", "remote", "rm", "check-dco"])
|
||||
|
||||
errors = False
|
||||
|
||||
print("\nChecking for 'Signed-off-by: NAME <EMAIL>' " +
|
||||
"on all commits since %s...\n" % ancestor)
|
||||
|
||||
log = subprocess.check_output(["git", "log", "--format=%H %s",
|
||||
ancestor + "..."],
|
||||
universal_newlines=True)
|
||||
|
||||
if log == "":
|
||||
commits = []
|
||||
else:
|
||||
commits = [[c[0:40], c[41:]] for c in log.strip().split("\n")]
|
||||
|
||||
for sha, subject in commits:
|
||||
|
||||
msg = subprocess.check_output(["git", "show", "-s", sha],
|
||||
universal_newlines=True)
|
||||
lines = msg.strip().split("\n")
|
||||
|
||||
print("🔍 %s %s" % (sha, subject))
|
||||
sob = False
|
||||
for line in lines:
|
||||
if "Signed-off-by:" in line:
|
||||
sob = True
|
||||
if "localhost" in line:
|
||||
print(" ❌ FAIL: bad email in %s" % line)
|
||||
errors = True
|
||||
|
||||
if not sob:
|
||||
print(" ❌ FAIL missing Signed-off-by tag")
|
||||
errors = True
|
||||
|
||||
if errors:
|
||||
print("""
|
||||
|
||||
❌ ERROR: One or more commits are missing a valid Signed-off-By tag.
|
||||
|
||||
|
||||
This project requires all contributors to assert that their contributions
|
||||
are provided in compliance with the terms of the Developer's Certificate
|
||||
of Origin 1.1 (DCO):
|
||||
|
||||
https://developercertificate.org/
|
||||
|
||||
To indicate acceptance of the DCO every commit must have a tag
|
||||
|
||||
Signed-off-by: REAL NAME <EMAIL>
|
||||
|
||||
This can be achieved by passing the "-s" flag to the "git commit" command.
|
||||
|
||||
To bulk update all commits on current branch "git rebase" can be used:
|
||||
|
||||
git rebase -i master -x 'git commit --amend --no-edit -s'
|
||||
|
||||
""")
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
sys.exit(0)
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# check-patch.py: run checkpatch.pl across all commits in a branch
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
namespace = "qemu-project"
|
||||
if len(sys.argv) >= 2:
|
||||
namespace = sys.argv[1]
|
||||
|
||||
cwd = os.getcwd()
|
||||
reponame = os.path.basename(cwd)
|
||||
repourl = "https://gitlab.com/%s/%s.git" % (namespace, reponame)
|
||||
|
||||
# GitLab CI environment does not give us any direct info about the
|
||||
# base for the user's branch. We thus need to figure out a common
|
||||
# ancestor between the user's branch and current git master.
|
||||
subprocess.check_call(["git", "remote", "add", "check-patch", repourl])
|
||||
subprocess.check_call(["git", "fetch", "check-patch", "master"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
ancestor = subprocess.check_output(["git", "merge-base",
|
||||
"check-patch/master", "HEAD"],
|
||||
universal_newlines=True)
|
||||
|
||||
ancestor = ancestor.strip()
|
||||
|
||||
log = subprocess.check_output(["git", "log", "--format=%H %s",
|
||||
ancestor + "..."],
|
||||
universal_newlines=True)
|
||||
|
||||
subprocess.check_call(["git", "remote", "rm", "check-patch"])
|
||||
|
||||
if log == "":
|
||||
print("\nNo commits since %s, skipping checks\n" % ancestor)
|
||||
sys.exit(0)
|
||||
|
||||
errors = False
|
||||
|
||||
print("\nChecking all commits since %s...\n" % ancestor, flush=True)
|
||||
|
||||
ret = subprocess.run(["scripts/checkpatch.pl", "--terse", ancestor + "..."])
|
||||
|
||||
if ret.returncode != 0:
|
||||
print(" ❌ FAIL one or more commits failed scripts/checkpatch.pl")
|
||||
sys.exit(1)
|
||||
|
||||
sys.exit(0)
|
|
@ -8,7 +8,7 @@
|
|||
- export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/$NAME:latest"
|
||||
- apk add python3
|
||||
- docker info
|
||||
- docker login registry.gitlab.com -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
|
||||
- docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
|
||||
script:
|
||||
- echo "TAG:$TAG"
|
||||
- echo "COMMON_TAG:$COMMON_TAG"
|
||||
|
@ -20,13 +20,11 @@
|
|||
- docker push "$TAG"
|
||||
after_script:
|
||||
- docker logout
|
||||
rules:
|
||||
- changes:
|
||||
- .gitlab-ci.d/containers.yml
|
||||
- tests/docker/*
|
||||
- tests/docker/dockerfiles/*
|
||||
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||
- if: '$CI_COMMIT_REF_NAME == "testing/next"'
|
||||
|
||||
amd64-alpine-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: alpine
|
||||
|
||||
amd64-centos7-container:
|
||||
<<: *container_job_definition
|
||||
|
@ -48,18 +46,6 @@ amd64-debian11-container:
|
|||
variables:
|
||||
NAME: debian11
|
||||
|
||||
amd64-debian9-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: debian9
|
||||
|
||||
amd64-debian9-mxe-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian9-container']
|
||||
variables:
|
||||
NAME: debian9-mxe
|
||||
|
||||
alpha-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
|
@ -210,24 +196,10 @@ sparc64-debian-cross-container:
|
|||
tricore-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer2
|
||||
needs: ['amd64-debian9-container']
|
||||
needs: ['amd64-debian10-container']
|
||||
variables:
|
||||
NAME: debian-tricore-cross
|
||||
|
||||
win32-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer3
|
||||
needs: ['amd64-debian9-mxe-container']
|
||||
variables:
|
||||
NAME: debian-win32-cross
|
||||
|
||||
win64-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
stage: containers-layer3
|
||||
needs: ['amd64-debian9-mxe-container']
|
||||
variables:
|
||||
NAME: debian-win64-cross
|
||||
|
||||
xtensa-debian-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
|
@ -248,6 +220,16 @@ i386-fedora-cross-container:
|
|||
variables:
|
||||
NAME: fedora-i386-cross
|
||||
|
||||
win32-fedora-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora-win32-cross
|
||||
|
||||
win64-fedora-cross-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: fedora-win64-cross
|
||||
|
||||
amd64-ubuntu1804-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
|
@ -262,3 +244,8 @@ amd64-ubuntu-container:
|
|||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: ubuntu
|
||||
|
||||
amd64-opensuse-leap-container:
|
||||
<<: *container_job_definition
|
||||
variables:
|
||||
NAME: opensuse-leap
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
.cross_system_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
timeout: 80m
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-user --target-list-exclude="arm-softmmu cris-softmmu
|
||||
i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu
|
||||
mips64-softmmu ppc-softmmu sh4-softmmu xtensa-softmmu"
|
||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||
|
||||
# Job to cross-build specific accelerators.
|
||||
#
|
||||
# Set the $ACCEL variable to select the specific accelerator (default to
|
||||
# KVM), and set extra options (such disabling other accelerators) via the
|
||||
# $ACCEL_CONFIGURE_OPTS variable.
|
||||
.cross_accel_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
timeout: 30m
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-tools --enable-${ACCEL:-kvm} $ACCEL_CONFIGURE_OPTS
|
||||
- make -j$(expr $(nproc) + 1) all check-build
|
||||
|
||||
.cross_user_build_job:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
||||
../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
|
||||
--disable-system
|
||||
- make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
|
||||
|
||||
cross-armel-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: armel-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-armel-cross
|
||||
|
||||
cross-armel-user:
|
||||
extends: .cross_user_build_job
|
||||
needs:
|
||||
job: armel-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-armel-cross
|
||||
|
||||
cross-armhf-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: armhf-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-armhf-cross
|
||||
|
||||
cross-armhf-user:
|
||||
extends: .cross_user_build_job
|
||||
needs:
|
||||
job: armhf-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-armhf-cross
|
||||
|
||||
cross-arm64-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: arm64-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-arm64-cross
|
||||
|
||||
cross-arm64-user:
|
||||
extends: .cross_user_build_job
|
||||
needs:
|
||||
job: arm64-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-arm64-cross
|
||||
|
||||
cross-i386-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: i386-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: fedora-i386-cross
|
||||
MAKE_CHECK_ARGS: check-qtest
|
||||
|
||||
cross-i386-user:
|
||||
extends: .cross_user_build_job
|
||||
needs:
|
||||
job: i386-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: fedora-i386-cross
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
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:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: mipsel-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-mipsel-cross
|
||||
|
||||
cross-mipsel-user:
|
||||
extends: .cross_user_build_job
|
||||
needs:
|
||||
job: mipsel-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-mipsel-cross
|
||||
|
||||
cross-mips64el-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: mips64el-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-mips64el-cross
|
||||
|
||||
cross-mips64el-user:
|
||||
extends: .cross_user_build_job
|
||||
needs:
|
||||
job: mips64el-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-mips64el-cross
|
||||
|
||||
cross-ppc64el-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: ppc64el-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-ppc64el-cross
|
||||
|
||||
cross-ppc64el-user:
|
||||
extends: .cross_user_build_job
|
||||
needs:
|
||||
job: ppc64el-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-ppc64el-cross
|
||||
|
||||
cross-s390x-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: s390x-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-s390x-cross
|
||||
|
||||
cross-s390x-user:
|
||||
extends: .cross_user_build_job
|
||||
needs:
|
||||
job: s390x-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-s390x-cross
|
||||
|
||||
cross-s390x-kvm-only:
|
||||
extends: .cross_accel_build_job
|
||||
needs:
|
||||
job: s390x-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-s390x-cross
|
||||
ACCEL_CONFIGURE_OPTS: --disable-tcg
|
||||
|
||||
cross-win32-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: win32-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: fedora-win32-cross
|
||||
|
||||
cross-win64-system:
|
||||
extends: .cross_system_build_job
|
||||
needs:
|
||||
job: win64-fedora-cross-container
|
||||
variables:
|
||||
IMAGE: fedora-win64-cross
|
||||
|
||||
cross-amd64-xen-only:
|
||||
extends: .cross_accel_build_job
|
||||
needs:
|
||||
job: amd64-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-amd64-cross
|
||||
ACCEL: xen
|
||||
ACCEL_CONFIGURE_OPTS: --disable-tcg --disable-kvm
|
||||
|
||||
cross-arm64-xen-only:
|
||||
extends: .cross_accel_build_job
|
||||
needs:
|
||||
job: arm64-debian-cross-container
|
||||
variables:
|
||||
IMAGE: debian-arm64-cross
|
||||
ACCEL: xen
|
||||
ACCEL_CONFIGURE_OPTS: --disable-tcg --disable-kvm
|
|
@ -25,6 +25,7 @@ docker-edk2:
|
|||
|
||||
build-edk2:
|
||||
stage: build
|
||||
needs: ['docker-edk2']
|
||||
rules: # Only run this job when ...
|
||||
- changes: # ... roms/edk2/ is modified (submodule updated)
|
||||
- roms/edk2/*
|
||||
|
|
|
@ -25,6 +25,7 @@ docker-opensbi:
|
|||
|
||||
build-opensbi:
|
||||
stage: build
|
||||
needs: ['docker-opensbi']
|
||||
rules: # Only run this job when ...
|
||||
- changes: # ... roms/opensbi/ is modified (submodule updated)
|
||||
- roms/opensbi/*
|
||||
|
@ -35,18 +36,14 @@ build-opensbi:
|
|||
when: always
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/opensbi-riscv32-sifive_u-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv32-virt-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
|
||||
- pc-bios/opensbi-riscv64-virt-fw_jump.bin
|
||||
- opensbi32-virt-stdout.log
|
||||
- opensbi32-virt-stderr.log
|
||||
- opensbi64-virt-stdout.log
|
||||
- opensbi64-virt-stderr.log
|
||||
- opensbi32-sifive_u-stdout.log
|
||||
- opensbi32-sifive_u-stderr.log
|
||||
- opensbi64-sifive_u-stdout.log
|
||||
- opensbi64-sifive_u-stderr.log
|
||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.elf
|
||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.elf
|
||||
- opensbi32-generic-stdout.log
|
||||
- opensbi32-generic-stderr.log
|
||||
- opensbi64-generic-stdout.log
|
||||
- opensbi64-generic-stderr.log
|
||||
image: $CI_REGISTRY_IMAGE:opensbi-cross-build
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
|
@ -55,10 +52,6 @@ build-opensbi:
|
|||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi32-virt 2>&1 1>opensbi32-virt-stdout.log | tee -a opensbi32-virt-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-virt 2>&1 1>opensbi64-virt-stdout.log | tee -a opensbi64-virt-stderr.log >&2
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi32-sifive_u 2>&1 1>opensbi32-sifive_u-stdout.log | tee -a opensbi32-sifive_u-stderr.log >&2
|
||||
- make -j${JOBS} -C roms/opensbi clean
|
||||
- make -j${JOBS} -C roms opensbi64-sifive_u 2>&1 1>opensbi64-sifive_u-stdout.log | tee -a opensbi64-sifive_u-stderr.log >&2
|
||||
- make -j${JOBS} -C roms opensbi64-generic 2>&1 1>opensbi64-generic-stdout.log | tee -a opensbi64-generic-stderr.log >&2
|
||||
|
|
630
.gitlab-ci.yml
630
.gitlab-ci.yml
|
@ -4,20 +4,14 @@
|
|||
stages:
|
||||
- containers
|
||||
- containers-layer2
|
||||
- containers-layer3
|
||||
- build
|
||||
- test
|
||||
|
||||
# We assume GitLab has it's own caching set up for RPM/APT repositories so we
|
||||
# just take care of avocado assets here.
|
||||
cache:
|
||||
paths:
|
||||
- $HOME/avocado/data/cache
|
||||
|
||||
include:
|
||||
- local: '/.gitlab-ci.d/edk2.yml'
|
||||
- local: '/.gitlab-ci.d/opensbi.yml'
|
||||
- local: '/.gitlab-ci.d/containers.yml'
|
||||
- local: '/.gitlab-ci.d/crossbuilds.yml'
|
||||
|
||||
.native_build_job_template: &native_build_job_definition
|
||||
stage: build
|
||||
|
@ -29,10 +23,14 @@ include:
|
|||
- cd build
|
||||
- if test -n "$TARGETS";
|
||||
then
|
||||
../configure --enable-werror $CONFIGURE_ARGS --target-list="$TARGETS" ;
|
||||
../configure --enable-werror --disable-docs $CONFIGURE_ARGS --target-list="$TARGETS" ;
|
||||
else
|
||||
../configure --enable-werror $CONFIGURE_ARGS ;
|
||||
fi
|
||||
../configure --enable-werror --disable-docs $CONFIGURE_ARGS ;
|
||||
fi || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- if test -n "$LD_JOBS";
|
||||
then
|
||||
meson configure . -Dbackend_max_links="$LD_JOBS" ;
|
||||
fi || exit 1;
|
||||
- make -j"$JOBS"
|
||||
- if test -n "$MAKE_CHECK_ARGS";
|
||||
then
|
||||
|
@ -43,9 +41,12 @@ include:
|
|||
stage: test
|
||||
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
|
||||
script:
|
||||
- scripts/git-submodule.sh update
|
||||
$(sed -n '/GIT_SUBMODULES=/ s/.*=// p' build/config-host.mak)
|
||||
- cd build
|
||||
- find . -type f -exec touch {} +
|
||||
- make $MAKE_CHECK_ARGS
|
||||
# Avoid recompiling by hiding ninja with NINJA=":"
|
||||
- make NINJA=":" $MAKE_CHECK_ARGS
|
||||
|
||||
.acceptance_template: &acceptance_definition
|
||||
cache:
|
||||
|
@ -53,27 +54,77 @@ include:
|
|||
paths:
|
||||
- ${CI_PROJECT_DIR}/avocado-cache
|
||||
policy: pull-push
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
when: always
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build/tests/results/latest/results.xml
|
||||
- build/tests/results/latest/test-results
|
||||
reports:
|
||||
junit: build/tests/results/latest/results.xml
|
||||
before_script:
|
||||
- mkdir -p ~/.config/avocado
|
||||
- echo "[datadir.paths]" > ~/.config/avocado/avocado.conf
|
||||
- echo "cache_dirs = ['${CI_PROJECT_DIR}/avocado-cache']"
|
||||
>> ~/.config/avocado/avocado.conf
|
||||
- echo -e '[job.output.testlogs]\nstatuses = ["FAIL", "INTERRUPT"]'
|
||||
>> ~/.config/avocado/avocado.conf
|
||||
- if [ -d ${CI_PROJECT_DIR}/avocado-cache ]; then
|
||||
du -chs ${CI_PROJECT_DIR}/avocado-cache ;
|
||||
fi
|
||||
- export AVOCADO_ALLOW_UNTRUSTED_CODE=1
|
||||
after_script:
|
||||
- cd build
|
||||
- python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat
|
||||
- du -chs ${CI_PROJECT_DIR}/avocado-cache
|
||||
|
||||
build-system-alpine:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-alpine-container
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
moxie-softmmu microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
CONFIGURE_ARGS: --enable-docs --enable-trace-backends=log,simple,syslog
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- .git-submodule-status
|
||||
- build
|
||||
|
||||
check-system-alpine:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-alpine
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-alpine:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-alpine
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: alpine
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-ubuntu:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system
|
||||
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
|
||||
moxie-softmmu microblazeel-softmmu mips64el-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
|
@ -98,12 +149,16 @@ acceptance-system-ubuntu:
|
|||
|
||||
build-system-debian:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
CONFIGURE_ARGS: --enable-fdt=system
|
||||
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
|
||||
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
|
@ -128,12 +183,17 @@ acceptance-system-debian:
|
|||
|
||||
build-system-fedora:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
TARGETS: tricore-softmmu unicore32-softmmu microblaze-softmmu mips-softmmu
|
||||
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs
|
||||
--enable-fdt=system --enable-slirp=system --enable-capstone=system
|
||||
TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu
|
||||
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
|
@ -158,12 +218,17 @@ acceptance-system-fedora:
|
|||
|
||||
build-system-centos:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
TARGETS: ppc64-softmmu lm32-softmmu or1k-softmmu s390x-softmmu
|
||||
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt --enable-fdt=system
|
||||
--enable-modules --enable-trace-backends=dtrace
|
||||
TARGETS: ppc64-softmmu or1k-softmmu s390x-softmmu
|
||||
x86_64-softmmu rx-softmmu sh4-softmmu nios2-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
|
@ -186,27 +251,138 @@ acceptance-system-centos:
|
|||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-system-opensuse:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-opensuse-leap-container
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
CONFIGURE_ARGS: --enable-fdt=system
|
||||
TARGETS: s390x-softmmu x86_64-softmmu aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-system-opensuse:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-opensuse
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-system-opensuse:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-system-opensuse
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: opensuse-leap
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
|
||||
build-disabled:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --disable-rdma --disable-slirp --disable-curl
|
||||
--disable-capstone --disable-live-block-migration --disable-glusterfs
|
||||
--disable-replication --disable-coroutine-pool --disable-smartcard
|
||||
--disable-guest-agent --disable-curses --disable-libxml2 --disable-tpm
|
||||
--disable-qom-cast-debug --disable-spice --disable-vhost-vsock
|
||||
--disable-vhost-net --disable-vhost-crypto --disable-vhost-user
|
||||
TARGETS: i386-softmmu ppc64-softmmu mips64-softmmu i386-linux-user
|
||||
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-sheepdog
|
||||
--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
|
||||
# the configure script. The container doesn't contain Xen headers so
|
||||
# Xen accelerator is not detected / selected. As result it build the
|
||||
# i386-softmmu and x86_64-softmmu with KVM being the single accelerator
|
||||
# available.
|
||||
# Also use a different coroutine implementation (which is only really of
|
||||
# interest to KVM users, i.e. with TCG disabled)
|
||||
build-tcg-disabled:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-tcg --audio-drv-list=""
|
||||
- ../configure --disable-tcg --audio-drv-list="" --with-coroutine=ucontext
|
||||
|| { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make -j"$JOBS"
|
||||
- make check-unit
|
||||
- make check-qapi-schema
|
||||
|
@ -214,60 +390,448 @@ build-tcg-disabled:
|
|||
- ./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
|
||||
170 171 183 184 192 194 197 208 215 221 222 226 227 236 253 277
|
||||
- ./check -qcow2 028 051 056 057 058 065 067 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 197 200 202
|
||||
208 209 215 216 218 222 227 234 246 247 248 250 254 255 257 258
|
||||
260 261 262 263 264 270 272 273 277 279
|
||||
|
||||
build-user:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
build-clang:
|
||||
build-user-static:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system --static
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
# Only build the softmmu targets we have check-tcg tests for
|
||||
build-some-softmmu:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --enable-debug
|
||||
TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
# Run check-tcg against linux-user (with plugins)
|
||||
# we skip sparc64-linux-user until it has been fixed somewhat
|
||||
# we skip cris-linux-user as it doesn't use the common run loop
|
||||
build-user-plugins:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
timeout: 1h 30m
|
||||
|
||||
build-user-centos7:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos7-container
|
||||
variables:
|
||||
IMAGE: centos7
|
||||
CONFIGURE_ARGS: --disable-system --disable-tools --disable-docs
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
build-some-softmmu-plugins:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --disable-tools --disable-user --enable-plugins --enable-debug-tcg
|
||||
TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu
|
||||
MAKE_CHECK_ARGS: check-tcg
|
||||
|
||||
clang-system:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++
|
||||
--extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined
|
||||
TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu
|
||||
ppc-softmmu s390x-softmmu arm-linux-user
|
||||
ppc-softmmu s390x-softmmu
|
||||
MAKE_CHECK_ARGS: check-qtest check-tcg
|
||||
|
||||
clang-user:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: debian-all-test-cross
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system
|
||||
--target-list-exclude=microblazeel-linux-user,aarch64_be-linux-user,i386-linux-user,m68k-linux-user,mipsn32el-linux-user,xtensaeb-linux-user
|
||||
--extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined
|
||||
MAKE_CHECK_ARGS: check-unit check-tcg
|
||||
|
||||
# Set LD_JOBS=1 because this requires LTO and ld consumes a large amount of memory.
|
||||
# On gitlab runners, default value sometimes end up calling 2 lds concurrently and
|
||||
# triggers an Out-Of-Memory error
|
||||
#
|
||||
# Since slirp callbacks are used in QEMU Timers, slirp needs to be compiled together
|
||||
# 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/acceptance to limit the execution time of each
|
||||
# job
|
||||
build-cfi-aarch64:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-aarch64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-aarch64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-cfi-ppc64-s390x:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: ppc64-softmmu s390x-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-ppc64-s390x:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-ppc64-s390x:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-cfi-x86_64:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: x86_64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
timeout: 70m
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-x86_64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-x86_64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
tsan-build:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-tsan --cc=clang-10 --cxx=clang++-10
|
||||
--enable-trace-backends=ust --enable-fdt=system --enable-slirp=system
|
||||
TARGETS: x86_64-softmmu ppc64-softmmu riscv64-softmmu x86_64-linux-user
|
||||
MAKE_CHECK_ARGS: bench V=1
|
||||
|
||||
# These targets are on the way out
|
||||
build-deprecated:
|
||||
<<: *native_build_job_definition
|
||||
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 lm32-softmmu unicore32-softmmu
|
||||
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:
|
||||
<<: *native_test_job_definition
|
||||
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:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --enable-gprof --enable-gcov
|
||||
MAKE_CHECK_ARGS: check
|
||||
TARGETS: aarch64-softmmu ppc64-softmmu s390x-softmmu x86_64-softmmu
|
||||
timeout: 70m
|
||||
after_script:
|
||||
- ${CI_PROJECT_DIR}/scripts/ci/coverage-summary.sh
|
||||
|
||||
build-oss-fuzz:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
script:
|
||||
- mkdir build-oss-fuzz
|
||||
- CC="clang" CXX="clang++" CFLAGS="-fsanitize=address"
|
||||
./scripts/oss-fuzz/build.sh
|
||||
- export ASAN_OPTIONS="fast_unwind_on_malloc=0"
|
||||
- for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f
|
||||
| grep -v slirp); do
|
||||
grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ;
|
||||
echo Testing ${fuzzer} ... ;
|
||||
ASAN_OPTIONS="fast_unwind_on_malloc=0"
|
||||
"${fuzzer}" -runs=1000 -seed=1 || exit 1 ;
|
||||
"${fuzzer}" -runs=1 -seed=1 || exit 1 ;
|
||||
done
|
||||
# Unrelated to fuzzer: run some tests with -fsanitize=address
|
||||
- cd build-oss-fuzz && make check-qtest-i386 check-unit
|
||||
|
||||
build-tci:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-user-cross-container
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
IMAGE: debian-all-test-cross
|
||||
script:
|
||||
- TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --enable-tcg-interpreter
|
||||
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)"
|
||||
--target-list="$(for tg in $TARGETS; do echo -n ${tg}'-softmmu '; done)" || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make -j"$JOBS"
|
||||
- make run-tcg-tests-x86_64-softmmu
|
||||
- make tests/qtest/boot-serial-test tests/qtest/cdrom-test tests/qtest/pxe-test
|
||||
- for tg in $TARGETS ; do
|
||||
export QTEST_QEMU_BINARY="${tg}-softmmu/qemu-system-${tg}" ;
|
||||
export QTEST_QEMU_BINARY="./qemu-system-${tg}" ;
|
||||
./tests/qtest/boot-serial-test || exit 1 ;
|
||||
./tests/qtest/cdrom-test || exit 1 ;
|
||||
done
|
||||
- QTEST_QEMU_BINARY="x86_64-softmmu/qemu-system-x86_64" ./tests/qtest/pxe-test
|
||||
- QTEST_QEMU_BINARY="s390x-softmmu/qemu-system-s390x" ./tests/qtest/pxe-test -m slow
|
||||
- QTEST_QEMU_BINARY="./qemu-system-x86_64" ./tests/qtest/pxe-test
|
||||
- QTEST_QEMU_BINARY="./qemu-system-s390x" ./tests/qtest/pxe-test -m slow
|
||||
- make check-tcg
|
||||
|
||||
# Alternate coroutines implementations are only really of interest to KVM users
|
||||
# However we can't test against KVM on Gitlab-CI so we can only run unit tests
|
||||
build-coroutine-sigaltstack:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-ubuntu2004-container
|
||||
variables:
|
||||
IMAGE: ubuntu2004
|
||||
CONFIGURE_ARGS: --with-coroutine=sigaltstack --disable-tcg
|
||||
--enable-trace-backends=ftrace
|
||||
MAKE_CHECK_ARGS: check-unit
|
||||
|
||||
# Most jobs test latest gcrypt or nettle builds
|
||||
#
|
||||
# These jobs test old gcrypt and nettle from RHEL7
|
||||
# which had some API differences.
|
||||
crypto-old-nettle:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos7-container
|
||||
variables:
|
||||
IMAGE: centos7
|
||||
TARGETS: x86_64-softmmu x86_64-linux-user
|
||||
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
crypto-old-gcrypt:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos7-container
|
||||
variables:
|
||||
IMAGE: centos7
|
||||
TARGETS: x86_64-softmmu x86_64-linux-user
|
||||
CONFIGURE_ARGS: --disable-nettle --enable-gcrypt
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
crypto-only-gnutls:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos7-container
|
||||
variables:
|
||||
IMAGE: centos7
|
||||
TARGETS: x86_64-softmmu x86_64-linux-user
|
||||
CONFIGURE_ARGS: --disable-nettle --disable-gcrypt --enable-gnutls
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
|
||||
# Check our reduced build configurations
|
||||
build-without-default-devices:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
variables:
|
||||
IMAGE: centos8
|
||||
CONFIGURE_ARGS: --without-default-devices --disable-user
|
||||
|
||||
build-without-default-features:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
CONFIGURE_ARGS: --without-default-features --disable-user
|
||||
--target-list-exclude=arm-softmmu,i386-softmmu,mipsel-softmmu,mips64-softmmu,ppc-softmmu
|
||||
MAKE_CHECK_ARGS: check-unit
|
||||
|
||||
check-patch:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/centos8:latest
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
script: .gitlab-ci.d/check-patch.py
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_NAMESPACE == 'qemu-project' && $CI_COMMIT_BRANCH == 'master'
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
allow_failure: true
|
||||
|
||||
check-dco:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/centos8:latest
|
||||
needs:
|
||||
job: amd64-centos8-container
|
||||
script: .gitlab-ci.d/check-dco.py
|
||||
except:
|
||||
variables:
|
||||
- $CI_PROJECT_NAMESPACE == 'qemu-project' && $CI_COMMIT_BRANCH == 'master'
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
|
||||
build-libvhost-user:
|
||||
stage: build
|
||||
image: $CI_REGISTRY_IMAGE/qemu/fedora:latest
|
||||
needs:
|
||||
job: amd64-fedora-container
|
||||
before_script:
|
||||
- dnf install -y meson ninja-build
|
||||
script:
|
||||
- mkdir subprojects/libvhost-user/build
|
||||
- cd subprojects/libvhost-user/build
|
||||
- meson
|
||||
- ninja
|
||||
|
||||
# No targets are built here, just tools, docs, and unit tests. This
|
||||
# also feeds into the eventual documentation deployment steps later
|
||||
build-tools-and-docs-debian:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
job: amd64-debian-container
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-unit check-softfloat ctags TAGS cscope
|
||||
CONFIGURE_ARGS: --disable-system --disable-user --enable-docs --enable-tools
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
# Prepare for GitLab pages deployment. Anything copied into the
|
||||
# "public" directory will be deployed to $USER.gitlab.io/$PROJECT
|
||||
pages:
|
||||
image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest
|
||||
stage: test
|
||||
needs:
|
||||
- job: build-tools-and-docs-debian
|
||||
script:
|
||||
- mkdir -p public
|
||||
# HTML-ised source tree
|
||||
- make gtags
|
||||
- htags -anT --tree-view=filetree -m qemu_init
|
||||
-t "Welcome to the QEMU sourcecode"
|
||||
- mv HTML public/src
|
||||
# Project documentation
|
||||
- make -C build install DESTDIR=$(pwd)/temp-install
|
||||
- mv temp-install/usr/local/share/doc/qemu/* public/
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
|
|
|
@ -1,63 +1,69 @@
|
|||
[submodule "roms/seabios"]
|
||||
path = roms/seabios
|
||||
url = https://git.qemu.org/git/seabios.git/
|
||||
url = https://gitlab.com/qemu-project/seabios.git/
|
||||
[submodule "roms/SLOF"]
|
||||
path = roms/SLOF
|
||||
url = https://git.qemu.org/git/SLOF.git
|
||||
url = https://gitlab.com/qemu-project/SLOF.git
|
||||
[submodule "roms/ipxe"]
|
||||
path = roms/ipxe
|
||||
url = https://git.qemu.org/git/ipxe.git
|
||||
url = https://gitlab.com/qemu-project/ipxe.git
|
||||
[submodule "roms/openbios"]
|
||||
path = roms/openbios
|
||||
url = https://git.qemu.org/git/openbios.git
|
||||
url = https://gitlab.com/qemu-project/openbios.git
|
||||
[submodule "roms/qemu-palcode"]
|
||||
path = roms/qemu-palcode
|
||||
url = https://git.qemu.org/git/qemu-palcode.git
|
||||
url = https://gitlab.com/qemu-project/qemu-palcode.git
|
||||
[submodule "roms/sgabios"]
|
||||
path = roms/sgabios
|
||||
url = https://git.qemu.org/git/sgabios.git
|
||||
url = https://gitlab.com/qemu-project/sgabios.git
|
||||
[submodule "dtc"]
|
||||
path = dtc
|
||||
url = https://git.qemu.org/git/dtc.git
|
||||
url = https://gitlab.com/qemu-project/dtc.git
|
||||
[submodule "roms/u-boot"]
|
||||
path = roms/u-boot
|
||||
url = https://git.qemu.org/git/u-boot.git
|
||||
url = https://gitlab.com/qemu-project/u-boot.git
|
||||
[submodule "roms/skiboot"]
|
||||
path = roms/skiboot
|
||||
url = https://git.qemu.org/git/skiboot.git
|
||||
url = https://gitlab.com/qemu-project/skiboot.git
|
||||
[submodule "roms/QemuMacDrivers"]
|
||||
path = roms/QemuMacDrivers
|
||||
url = https://git.qemu.org/git/QemuMacDrivers.git
|
||||
url = https://gitlab.com/qemu-project/QemuMacDrivers.git
|
||||
[submodule "ui/keycodemapdb"]
|
||||
path = ui/keycodemapdb
|
||||
url = https://git.qemu.org/git/keycodemapdb.git
|
||||
url = https://gitlab.com/qemu-project/keycodemapdb.git
|
||||
[submodule "capstone"]
|
||||
path = capstone
|
||||
url = https://git.qemu.org/git/capstone.git
|
||||
url = https://gitlab.com/qemu-project/capstone.git
|
||||
[submodule "roms/seabios-hppa"]
|
||||
path = roms/seabios-hppa
|
||||
url = https://git.qemu.org/git/seabios-hppa.git
|
||||
url = https://gitlab.com/qemu-project/seabios-hppa.git
|
||||
[submodule "roms/u-boot-sam460ex"]
|
||||
path = roms/u-boot-sam460ex
|
||||
url = https://git.qemu.org/git/u-boot-sam460ex.git
|
||||
url = https://gitlab.com/qemu-project/u-boot-sam460ex.git
|
||||
[submodule "tests/fp/berkeley-testfloat-3"]
|
||||
path = tests/fp/berkeley-testfloat-3
|
||||
url = https://git.qemu.org/git/berkeley-testfloat-3.git
|
||||
url = https://gitlab.com/qemu-project/berkeley-testfloat-3.git
|
||||
[submodule "tests/fp/berkeley-softfloat-3"]
|
||||
path = tests/fp/berkeley-softfloat-3
|
||||
url = https://git.qemu.org/git/berkeley-softfloat-3.git
|
||||
url = https://gitlab.com/qemu-project/berkeley-softfloat-3.git
|
||||
[submodule "roms/edk2"]
|
||||
path = roms/edk2
|
||||
url = https://git.qemu.org/git/edk2.git
|
||||
url = https://gitlab.com/qemu-project/edk2.git
|
||||
[submodule "slirp"]
|
||||
path = slirp
|
||||
url = https://git.qemu.org/git/libslirp.git
|
||||
url = https://gitlab.com/qemu-project/libslirp.git
|
||||
[submodule "roms/opensbi"]
|
||||
path = roms/opensbi
|
||||
url = https://git.qemu.org/git/opensbi.git
|
||||
url = https://gitlab.com/qemu-project/opensbi.git
|
||||
[submodule "roms/qboot"]
|
||||
path = roms/qboot
|
||||
url = https://github.com/bonzini/qboot
|
||||
url = https://gitlab.com/qemu-project/qboot.git
|
||||
[submodule "meson"]
|
||||
path = meson
|
||||
url = https://gitlab.com/qemu-project/meson.git
|
||||
[submodule "roms/vbootrom"]
|
||||
path = roms/vbootrom
|
||||
url = https://gitlab.com/qemu-project/vbootrom.git
|
||||
[submodule "ui/imgui"]
|
||||
path = ui/imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
|
|
13
.mailmap
13
.mailmap
|
@ -48,13 +48,16 @@ Alexander Graf <agraf@csgraf.de> <agraf@suse.de>
|
|||
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
|
||||
Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
|
||||
Frederic Konrad <konrad@adacore.com> <fred.konrad@greensocs.com>
|
||||
Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
||||
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
|
||||
Leif Lindholm <leif@nuviainc.com> <leif.lindholm@linaro.org>
|
||||
Radoslaw Biernacki <rad@semihalf.com> <radoslaw.biernacki@linaro.org>
|
||||
Paul Burton <pburton@wavecomp.com> <paul.burton@mips.com>
|
||||
Paul Burton <pburton@wavecomp.com> <paul.burton@imgtec.com>
|
||||
Paul Burton <pburton@wavecomp.com> <paul@archlinuxmips.org>
|
||||
Philippe Mathieu-Daudé <philmd@redhat.com> <f4bug@amsat.org>
|
||||
Paul Burton <paulburton@kernel.org> <paul.burton@mips.com>
|
||||
Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com>
|
||||
Paul Burton <paulburton@kernel.org> <paul@archlinuxmips.org>
|
||||
Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com>
|
||||
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
|
||||
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
||||
|
||||
|
@ -84,6 +87,7 @@ Christophe Lyon <christophe.lyon@st.com>
|
|||
Collin L. Walling <walling@linux.ibm.com>
|
||||
Daniel P. Berrangé <berrange@redhat.com>
|
||||
Eduardo Otubo <otubo@redhat.com>
|
||||
Erik Smit <erik.lucas.smit@gmail.com>
|
||||
Fabrice Desclaux <fabrice.desclaux@cea.fr>
|
||||
Fernando Luis Vázquez Cao <fernando_b1@lab.ntt.co.jp>
|
||||
Fernando Luis Vázquez Cao <fernando@oss.ntt.co.jp>
|
||||
|
@ -141,6 +145,7 @@ Roger Pau Monné <roger.pau@citrix.com>
|
|||
Shin'ichiro Kawasaki <kawasaki@juno.dti.ne.jp>
|
||||
Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
|
||||
Sochin Jiang <sochin.jiang@huawei.com>
|
||||
Stefan Berger <stefanb@linux.vnet.ibm.com> <stefanb@linux.ibm.com>
|
||||
Takashi Yoshii <takasi-y@ops.dti.ne.jp>
|
||||
Thomas Huth <thuth@redhat.com>
|
||||
Thomas Knych <thomaswk@google.com>
|
||||
|
|
|
@ -17,4 +17,4 @@ formats: all
|
|||
# we require for other Python in our codebase (our conf.py
|
||||
# enforces this, and some code needs it.)
|
||||
python:
|
||||
version: 3.5
|
||||
version: 3.6
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
language: c
|
||||
git:
|
||||
submodules: false
|
||||
env:
|
||||
global:
|
||||
- LC_ALL=C
|
||||
matrix:
|
||||
- IMAGE=debian-amd64
|
||||
TARGET_LIST=x86_64-softmmu,x86_64-linux-user
|
||||
- IMAGE=debian-win32-cross
|
||||
TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu
|
||||
- IMAGE=debian-win64-cross
|
||||
TARGET_LIST=aarch64-softmmu,sparc64-softmmu,x86_64-softmmu
|
||||
- IMAGE=debian-armel-cross
|
||||
TARGET_LIST=arm-softmmu,arm-linux-user,armeb-linux-user
|
||||
- IMAGE=debian-armhf-cross
|
||||
TARGET_LIST=arm-softmmu,arm-linux-user,armeb-linux-user
|
||||
- IMAGE=debian-arm64-cross
|
||||
TARGET_LIST=aarch64-softmmu,aarch64-linux-user
|
||||
- IMAGE=debian-s390x-cross
|
||||
TARGET_LIST=s390x-softmmu,s390x-linux-user
|
||||
- IMAGE=debian-mips-cross
|
||||
TARGET_LIST=mips-softmmu,mipsel-linux-user
|
||||
- IMAGE=debian-mips64el-cross
|
||||
TARGET_LIST=mips64el-softmmu,mips64el-linux-user
|
||||
- IMAGE=debian-ppc64el-cross
|
||||
TARGET_LIST=ppc64-softmmu,ppc64-linux-user,ppc64abi32-linux-user
|
||||
build:
|
||||
pre_ci_boot:
|
||||
image_name: registry.gitlab.com/qemu-project/qemu/qemu/${IMAGE}
|
||||
image_tag: latest
|
||||
pull: true
|
||||
options: "-e HOME=/root"
|
||||
ci:
|
||||
- unset CC
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ../configure --disable-docs ${QEMU_CONFIGURE_OPTS} --target-list=${TARGET_LIST}
|
||||
- make -j$(($(getconf _NPROCESSORS_ONLN) + 1))
|
285
.travis.yml
285
.travis.yml
|
@ -2,7 +2,7 @@
|
|||
# Additional builds with specific requirements for a full VM need to
|
||||
# be added as additional matrix: entries later on
|
||||
os: linux
|
||||
dist: xenial
|
||||
dist: focal
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
|
@ -10,7 +10,7 @@ cache:
|
|||
# There is one cache per branch and compiler version.
|
||||
# characteristics of each job are used to identify the cache:
|
||||
# - OS name (currently only linux)
|
||||
# - OS distribution (for Linux, xenial, trusty, or precise)
|
||||
# - OS distribution (for Linux, bionic or focal)
|
||||
# - Names and values of visible environment variables set in .travis.yml or Settings panel
|
||||
timeout: 1200
|
||||
ccache: true
|
||||
|
@ -27,7 +27,7 @@ addons:
|
|||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgcc-4.8-dev
|
||||
- libgcc-7-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
|
@ -49,9 +49,9 @@ addons:
|
|||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
- libzstd-dev
|
||||
- ninja-build
|
||||
- sparse
|
||||
- uuid-dev
|
||||
- gcovr
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
|
||||
|
@ -86,15 +86,17 @@ git:
|
|||
submodules: false
|
||||
|
||||
# Common first phase for all steps
|
||||
# We no longer use nproc to calculate jobs:
|
||||
# https://travis-ci.community/t/nproc-reports-32-cores-on-arm64/5851
|
||||
before_install:
|
||||
- if command -v ccache ; then ccache --zero-stats ; fi
|
||||
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
|
||||
- export JOBS=3
|
||||
- echo "=== Using ${JOBS} simultaneous jobs ==="
|
||||
|
||||
# Configure step - may be overridden
|
||||
before_script:
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
|
||||
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
|
||||
# Main build & test - rarely overridden - controlled by TEST_CMD
|
||||
script:
|
||||
|
@ -118,267 +120,10 @@ after_script:
|
|||
|
||||
jobs:
|
||||
include:
|
||||
- name: "GCC static (user)"
|
||||
env:
|
||||
- CONFIG="--disable-system --static"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# we split the system builds as it takes a while to build them all
|
||||
- name: "GCC (main-softmmu)"
|
||||
env:
|
||||
- CONFIG="--disable-user --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
- name: "GCC (other-softmmu)"
|
||||
env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# Just build tools and run minimal unit and softfloat checks
|
||||
- name: "GCC check-softfloat (user)"
|
||||
env:
|
||||
- BASE_CONFIG="--enable-tools"
|
||||
- CONFIG="--disable-user --disable-system"
|
||||
- TEST_CMD="make check-unit check-softfloat -j${JOBS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# --enable-debug implies --enable-debug-tcg, also runs quite a bit slower
|
||||
- name: "GCC debug (main-softmmu)"
|
||||
env:
|
||||
- CONFIG="--enable-debug --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug"
|
||||
|
||||
|
||||
# TCG debug can be run just on its own and is mostly agnostic to user/softmmu distinctions
|
||||
- name: "GCC debug (user)"
|
||||
env:
|
||||
- CONFIG="--enable-debug-tcg --disable-system"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
- name: "GCC some libs disabled (main-softmmu)"
|
||||
env:
|
||||
- CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-libusb --disable-replication --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
|
||||
|
||||
# Module builds are mostly of interest to major distros
|
||||
- name: "GCC modules (main-softmmu)"
|
||||
env:
|
||||
- CONFIG="--enable-modules --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
|
||||
|
||||
# Alternate coroutines implementations are only really of interest to KVM users
|
||||
# However we can't test against KVM on Travis so we can only run unit tests
|
||||
- name: "check-unit coroutine=ucontext"
|
||||
env:
|
||||
- CONFIG="--with-coroutine=ucontext --disable-tcg"
|
||||
- TEST_CMD="make check-unit -j${JOBS} V=1"
|
||||
|
||||
|
||||
- name: "check-unit coroutine=sigaltstack"
|
||||
env:
|
||||
- CONFIG="--with-coroutine=sigaltstack --disable-tcg"
|
||||
- TEST_CMD="make check-unit -j${JOBS} V=1"
|
||||
|
||||
|
||||
# Check we can build docs and tools (out of tree)
|
||||
- name: "tools and docs (bionic)"
|
||||
dist: bionic
|
||||
env:
|
||||
- BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
|
||||
- BASE_CONFIG="--enable-tools --enable-docs"
|
||||
- CONFIG="--target-list=x86_64-softmmu,aarch64-linux-user"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3-sphinx
|
||||
- texinfo
|
||||
- perl
|
||||
|
||||
|
||||
# Test with Clang for compile portability (Travis uses clang-5.0)
|
||||
- name: "Clang (user)"
|
||||
env:
|
||||
- CONFIG="--disable-system --host-cc=clang --cxx=clang++"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
|
||||
compiler: clang
|
||||
|
||||
|
||||
- name: "Clang (main-softmmu)"
|
||||
env:
|
||||
- CONFIG="--target-list=${MAIN_SOFTMMU_TARGETS}
|
||||
--host-cc=clang --cxx=clang++"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-sanitize"
|
||||
compiler: clang
|
||||
before_script:
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${CONFIG} --extra-cflags="-fsanitize=undefined -Werror" || { cat config.log && exit 1; }
|
||||
|
||||
|
||||
- name: "Clang (other-softmmu)"
|
||||
env:
|
||||
- CONFIG="--disable-user --target-list-exclude=${MAIN_SOFTMMU_TARGETS}
|
||||
--host-cc=clang --cxx=clang++"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-clang-default"
|
||||
compiler: clang
|
||||
|
||||
|
||||
# gprof/gcov are GCC features
|
||||
- name: "GCC gprof/gcov"
|
||||
env:
|
||||
- CONFIG="--enable-gprof --enable-gcov --disable-pie --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
after_success:
|
||||
- ${SRC_DIR}/scripts/travis/coverage-summary.sh
|
||||
|
||||
|
||||
# We manually include builds which we disable "make check" for
|
||||
- name: "GCC without-default-devices (softmmu)"
|
||||
env:
|
||||
- CONFIG="--without-default-devices --disable-user"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
# Check the TCG interpreter (TCI)
|
||||
- name: "GCC TCI"
|
||||
env:
|
||||
- CONFIG="--enable-debug-tcg --enable-tcg-interpreter --disable-kvm --disable-containers
|
||||
--target-list=alpha-softmmu,arm-softmmu,hppa-softmmu,m68k-softmmu,microblaze-softmmu,moxie-softmmu,ppc-softmmu,s390x-softmmu,x86_64-softmmu"
|
||||
- TEST_CMD="make check-qtest check-tcg V=1"
|
||||
|
||||
|
||||
# We don't need to exercise every backend with every front-end
|
||||
- name: "GCC trace log,simple,syslog (user)"
|
||||
env:
|
||||
- CONFIG="--enable-trace-backends=log,simple,syslog --disable-system"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
- name: "GCC trace ftrace (x86_64-softmmu)"
|
||||
env:
|
||||
- CONFIG="--enable-trace-backends=ftrace --target-list=x86_64-softmmu"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
- name: "GCC trace ust (x86_64-softmmu)"
|
||||
env:
|
||||
- CONFIG="--enable-trace-backends=ust --target-list=x86_64-softmmu"
|
||||
- TEST_CMD=""
|
||||
|
||||
|
||||
# Python builds
|
||||
- name: "GCC Python 3.5 (x86_64-softmmu)"
|
||||
env:
|
||||
- CONFIG="--target-list=x86_64-softmmu"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
language: python
|
||||
python: 3.5
|
||||
|
||||
|
||||
- name: "GCC Python 3.6 (x86_64-softmmu)"
|
||||
env:
|
||||
- CONFIG="--target-list=x86_64-softmmu"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
|
||||
language: python
|
||||
python: 3.6
|
||||
|
||||
|
||||
# Using newer GCC with sanitizers
|
||||
- name: "GCC9 with sanitizers (softmmu)"
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
# PPAs for newer toolchains
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
# Extra toolchains
|
||||
- gcc-9
|
||||
- g++-9
|
||||
# Build dependencies
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgnutls-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libnfs-dev
|
||||
- libncurses5-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng12-dev
|
||||
- librados-dev
|
||||
- libsdl2-dev
|
||||
- libsdl2-image-dev
|
||||
- libseccomp-dev
|
||||
- libspice-protocol-dev
|
||||
- libspice-server-dev
|
||||
- libssh-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvte-2.91-dev
|
||||
- sparse
|
||||
- uuid-dev
|
||||
language: generic
|
||||
compiler: none
|
||||
env:
|
||||
- COMPILER_NAME=gcc CXX=g++-9 CC=gcc-9
|
||||
- CONFIG="--cc=gcc-9 --cxx=g++-9 --disable-pie --disable-linux-user"
|
||||
- TEST_CMD=""
|
||||
before_script:
|
||||
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
|
||||
- ${SRC_DIR}/configure ${CONFIG} --extra-cflags="-g3 -O0 -Wno-error=stringop-truncation -fsanitize=thread" --extra-ldflags="-fuse-ld=gold" || { cat config.log && exit 1; }
|
||||
|
||||
|
||||
# Run check-tcg against linux-user
|
||||
- name: "GCC check-tcg (user)"
|
||||
env:
|
||||
- CONFIG="--disable-system --enable-debug-tcg"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against linux-user (with plugins)
|
||||
# we skip sparc64-linux-user until it has been fixed somewhat
|
||||
# we skip cris-linux-user as it doesn't use the common run loop
|
||||
# we skip ppc64abi32-linux-user as it seems to have a broken libc
|
||||
- name: "GCC plugins check-tcg (user)"
|
||||
env:
|
||||
- CONFIG="--disable-system --enable-plugins --enable-debug-tcg --target-list-exclude=sparc64-linux-user,cris-linux-user,ppc64abi32-linux-user"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against softmmu targets
|
||||
- name: "GCC check-tcg (some-softmmu)"
|
||||
env:
|
||||
- CONFIG="--enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
|
||||
# Run check-tcg against softmmu targets (with plugins)
|
||||
- name: "GCC plugins check-tcg (some-softmmu)"
|
||||
env:
|
||||
- CONFIG="--enable-plugins --enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_BUILD_CMD="make build-tcg"
|
||||
- TEST_CMD="make check-tcg"
|
||||
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
|
||||
|
||||
- name: "[aarch64] GCC check-tcg"
|
||||
arch: arm64
|
||||
dist: xenial
|
||||
dist: focal
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
|
@ -402,16 +147,17 @@ jobs:
|
|||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
- ninja-build
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
- TEST_CMD="make check check-tcg V=1"
|
||||
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS}"
|
||||
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS} --cxx=/bin/false"
|
||||
- UNRELIABLE=true
|
||||
|
||||
- name: "[ppc64] GCC check-tcg"
|
||||
arch: ppc64le
|
||||
dist: xenial
|
||||
dist: focal
|
||||
addons:
|
||||
apt_packages:
|
||||
- libaio-dev
|
||||
|
@ -435,6 +181,7 @@ jobs:
|
|||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
- ninja-build
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
|
@ -467,6 +214,7 @@ jobs:
|
|||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
- ninja-build
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
|
@ -506,6 +254,7 @@ jobs:
|
|||
- libzstd-dev
|
||||
- nettle-dev
|
||||
- xfslibs-dev
|
||||
- ninja-build
|
||||
# Tests dependencies
|
||||
- genisoimage
|
||||
env:
|
||||
|
@ -519,6 +268,7 @@ jobs:
|
|||
apt_packages:
|
||||
- libgcrypt20-dev
|
||||
- libgnutls28-dev
|
||||
- ninja-build
|
||||
env:
|
||||
- CONFIG="--disable-containers --disable-system"
|
||||
|
||||
|
@ -549,6 +299,7 @@ jobs:
|
|||
- libusb-1.0-0-dev
|
||||
- libvdeplug-dev
|
||||
- libvte-2.91-dev
|
||||
- ninja-build
|
||||
env:
|
||||
- TEST_CMD="make check-unit"
|
||||
- CONFIG="--disable-containers --disable-tcg --enable-kvm
|
||||
|
@ -573,7 +324,7 @@ jobs:
|
|||
- 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 && exit 1; }
|
||||
- ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- make install
|
||||
allow_failures:
|
||||
- env: UNRELIABLE=true
|
||||
|
|
580
Changelog
580
Changelog
|
@ -1,580 +0,0 @@
|
|||
This file documents changes for QEMU releases 0.12 and earlier.
|
||||
For changelog information for later releases, see
|
||||
https://wiki.qemu.org/ChangeLog or look at the git history for
|
||||
more detailed information.
|
||||
|
||||
|
||||
version 0.12.0:
|
||||
|
||||
- Update to SeaBIOS 0.5.0
|
||||
- e1000: fix device link status in Linux (Anthony Liguori)
|
||||
- monitor: fix QMP for balloon command (Luiz Capitulino)
|
||||
- QMP: Return an empty dict by default (Luiz Capitulino)
|
||||
- QMP: Only handle converted commands (Luiz Capitulino)
|
||||
- pci: support PCI based option rom loading (Gerd Hoffman/Anthony Liguori)
|
||||
- Fix backcompat for hotplug of SCSI controllers (Daniel P. Berrange)
|
||||
- fdc: fix migration from 0.11 (Juan Quintela)
|
||||
- vmware-vga: fix segv on cursor resize. (Dave Airlie)
|
||||
- vmware-vga: various fixes (Dave Airlie/Anthony Liguori)
|
||||
- qdev: improve property error reporting. (Gerd Hoffmann)
|
||||
- fix vga names in default_list (Gerd Hoffmann)
|
||||
- usb-host: check mon before using it. (Gerd Hoffmann)
|
||||
- usb-net: use qdev for -usbdevice (Gerd Hoffmann)
|
||||
- monitor: Catch printing to non-existent monitor (Luiz Capitulino)
|
||||
- Avoid permanently disabled QEMU monitor when UNIX migration fails (Daniel P. Berrange)
|
||||
- Fix loading of ELF multiboot kernels (Kevin Wolf)
|
||||
- qemu-io: Fix memory leak (Kevin Wolf)
|
||||
- Fix thinko in linuxboot.S (Paolo Bonzini)
|
||||
- target-i386: Fix evaluation of DR7 register (Jan Kiszka)
|
||||
- vnc: hextile: do not generate ForegroundSpecified and SubrectsColoured tiles (Anthony Liguori)
|
||||
- S390: Bail out without KVM (Alexander Graf)
|
||||
- S390: Don't tell guest we're updating config space (Alexander Graf)
|
||||
- target-s390: Fail on unknown instructions (Alexander Graf)
|
||||
- osdep: Fix runtime failure on older Linux kernels (Andre Przywara)
|
||||
- Fix a make -j race (Juergen Lock)
|
||||
- target-alpha: Fix generic ctz64. (Richard Henderson)
|
||||
- s390: Fix buggy assignment (Stefan Weil)
|
||||
- target-mips: fix user-mode emulation startup (Nathan Froyd)
|
||||
- target-i386: Update CPUID feature set for TCG (Andre Przywara)
|
||||
- s390: fix build on 32 bit host (Michael S. Tsirkin)
|
||||
|
||||
version 0.12.0-rc2:
|
||||
|
||||
- v2: properly save kvm system time msr registers (Glauber Costa)
|
||||
- convert more monitor commands to qmp (Luiz Capitulino)
|
||||
- vnc: fix capslock tracking logic. (Gerd Hoffmann)
|
||||
- QemuOpts: allow larger option values. (Gerd Hoffmann)
|
||||
- scsi: fix drive hotplug. (Gerd Hoffmann)
|
||||
- pci: don't hw_error() when no slot is available. (Gerd Hoffmann)
|
||||
- pci: don't abort() when trying to hotplug with acpi off. (Gerd Hoffmann)
|
||||
- allow default devices to be implemented in config file (Gerd Hoffman)
|
||||
- vc: colorize chardev title line with blue background. (Gerd Hoffmann)
|
||||
- chardev: make chardevs specified in config file work. (Gerd Hoffmann)
|
||||
- qdev: also match bus name for global properties (Gerd Hoffmann)
|
||||
- qdev: add command line option to set global defaults for properties. (Gerd Hoffmann)
|
||||
- kvm: x86: Save/restore exception_index (Jan Kiszka)
|
||||
- qdev: Replace device names containing whitespace (Markus Armbruster)
|
||||
- fix rtc-td-hack on host without high-res timers (Gleb Natapov)
|
||||
- virtio: verify features on load (Michael S. Tsirkin)
|
||||
- vmware_vga: add rom file so that it boots. (Dave Airlie)
|
||||
- Do not abort on qemu_malloc(0) in production builds (Anthony Liguori)
|
||||
- Fix ARM userspace strex implementation. (Paul Brook)
|
||||
- qemu: delete rule target on error (Michael S. Tsirkin)
|
||||
- QMP: add human-readable description to error response (Markus Armbruster)
|
||||
- convert more monitor commands to QError (Markus Armbruster)
|
||||
- monitor: Fix double-prompt after "change vnc passwd BLA" (Markus Armbruster)
|
||||
- monitor: do_cont(): Don't ask for passwords (Luiz Capitulino)
|
||||
- monitor: Introduce 'block_passwd' command (Luiz Capitulino)
|
||||
- pci: interrupt disable bit support (Michael S. Tsirkin)
|
||||
- pci: interrupt status bit implementation (Michael S. Tsirkin)
|
||||
- pci: prepare irq code for interrupt state (Michael S. Tsirkin)
|
||||
- msix: function mask support (Michael S. Tsirkin)
|
||||
- msix: macro rename for function mask support (Michael S. Tsirkin)
|
||||
- cpuid: Fix multicore setup on Intel (Andre Przywara)
|
||||
- kvm: x86: Fix initial kvm_has_msr_star (Jan Kiszka)
|
||||
- Update OpenBIOS images to r640 (Aurelien Jarno)
|
||||
|
||||
version 0.10.2:
|
||||
|
||||
- fix savevm/loadvm (Anthony Liguori)
|
||||
- live migration: fix dirty tracking windows (Glauber Costa)
|
||||
- live migration: improve error propagation (Glauber Costa)
|
||||
- qcow2: fix image creation for > ~2TB images (Chris Wright)
|
||||
- hotplug: fix error handling for if= parameter (Eduardo Habkost)
|
||||
- qcow2: fix data corruption (Nolan Leake)
|
||||
- virtio: fix guest oops with 2.6.25 kernels (Rusty Russell)
|
||||
- SH4: add support for -kernel (Takashi Yoshii, Aurelien Jarno)
|
||||
- hotplug: fix closing of char devices (Jan Kiszka)
|
||||
- hotplug: remove incorrect check for device name (Eduardo Habkost)
|
||||
- enable -k on win32 (Herve Poussineau)
|
||||
- configure: use LANG=C for grep (Andreas Faerber)
|
||||
- fix VGA regression (malc)
|
||||
|
||||
version 0.10.1:
|
||||
|
||||
- virtio-net: check right return size on sg list (Alex Williamson)
|
||||
- Make qemu_announce_self handle holes (live migration after hotplug)
|
||||
(Marcelo Tosatti)
|
||||
- Revert r6804-r6808 (qcow2 allocation info). This series of changes added
|
||||
a high cost to startup for large qcow2 images (Anthony Liguori)
|
||||
- qemu-img: fix help message (Aurelien Jarno)
|
||||
- Fix build for non-default installs of SDL (Anthony Liguori)
|
||||
- Fix race condition in env->interrupt_request. When using TCG and a dynticks
|
||||
host timer, this condition could cause TCG to get stuck in an infinite
|
||||
loop (Aurelien Jarno)
|
||||
- Fix reading encrypted hard disk passwords during early startup (Jan Kiszka)
|
||||
- Fix encrypted disk reporting in 'info block' (Jan Kiszka)
|
||||
- Fix console size with tiny displays (MusicPal) (Jan Kiszka)
|
||||
- Improve error handling in bdrv_open2 (Jan Kiszka)
|
||||
- Avoid leaking data in mux'ed character devices (Jan Kiszka)
|
||||
- Fix initial character device reset (no banner in monitor) (Jan Kiszka)
|
||||
- Fix cpuid KVM crash on i386 host (Lubomir Rintel)
|
||||
- Fix SLES10sp2 installation by adding ISTAT1 register to LSI SCSI emulation
|
||||
(Ryan Harper)
|
||||
|
||||
version 0.10.0:
|
||||
|
||||
- TCG support (No longer requires GCC 3.x)
|
||||
- Kernel Virtual Machine acceleration support
|
||||
- BSD userspace emulation
|
||||
- Bluetooth emulation and host passthrough support
|
||||
- GDB XML register description support
|
||||
- Intel e1000 emulation
|
||||
- HPET emulation
|
||||
- VirtIO paravirtual device support
|
||||
- Marvell 88w8618 / MusicPal emulation
|
||||
- Nokia N-series tablet emulation / OMAP2 processor emulation
|
||||
- PCI hotplug support
|
||||
- Live migration and new save/restore formats
|
||||
- Curses display support
|
||||
- qemu-nbd utility to mount supported block formats
|
||||
- Altivec support in PPC emulation and new firmware (OpenBIOS)
|
||||
- Multiple VNC clients are now supported
|
||||
- TLS encryption is now supported in VNC
|
||||
- MIPS Magnum R4000 machine (Hervé Poussineau)
|
||||
- Braille support (Samuel Thibault)
|
||||
- Freecom MusicPal system emulation (Jan Kiszka)
|
||||
- OMAP242x and Nokia N800, N810 machines (Andrzej Zaborowski)
|
||||
- EsounD audio driver (Frederick Reeve)
|
||||
- Gravis Ultrasound GF1 sound card (Tibor "TS" Schütz)
|
||||
- Many, many, bug fixes and new features
|
||||
|
||||
version 0.9.1:
|
||||
|
||||
- TFTP booting from host directory (Anthony Liguori, Erwan Velu)
|
||||
- Tap device emulation for Solaris (Sittichai Palanisong)
|
||||
- Monitor multiplexing to several I/O channels (Jason Wessel)
|
||||
- ds1225y nvram support (Herve Poussineau)
|
||||
- CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
|
||||
- Several Sparc fixes (Aurelien Jarno, Blue Swirl, Robert Reif)
|
||||
- MIPS 64-bit FPU support (Thiemo Seufer)
|
||||
- Xscale PDA emulation (Andrzej Zaborowski)
|
||||
- ColdFire system emulation (Paul Brook)
|
||||
- Improved SH4 support (Magnus Damm)
|
||||
- MIPS64 support (Aurelien Jarno, Thiemo Seufer)
|
||||
- Preliminary Alpha guest support (J. Mayer)
|
||||
- Read-only support for Parallels disk images (Alex Beregszaszi)
|
||||
- SVM (x86 virtualization) support (Alexander Graf)
|
||||
- CRIS emulation (Edgar E. Iglesias)
|
||||
- SPARC32PLUS execution support (Blue Swirl)
|
||||
- MIPS mipssim pseudo machine (Thiemo Seufer)
|
||||
- Strace for Linux userland emulation (Stuart Anderson, Thayne Harbaugh)
|
||||
- OMAP310 MPU emulation plus Palm T|E machine (Andrzej Zaborowski)
|
||||
- ARM v6, v7, NEON SIMD and SMP emulation (Paul Brook/CodeSourcery)
|
||||
- Gumstix boards: connex and verdex emulation (Thorsten Zitterell)
|
||||
- Intel mainstone II board emulation (Armin Kuster)
|
||||
- VMware SVGA II graphics card support (Andrzej Zaborowski)
|
||||
|
||||
version 0.9.0:
|
||||
|
||||
- Support for relative paths in backing files for disk images
|
||||
- Async file I/O API
|
||||
- New qcow2 disk image format
|
||||
- Support of multiple VM snapshots
|
||||
- Linux: specific host CDROM and floppy support
|
||||
- SMM support
|
||||
- Moved PCI init, MP table init and ACPI table init to Bochs BIOS
|
||||
- Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
|
||||
- MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
|
||||
- Darwin userspace emulation (Pierre d'Herbemont)
|
||||
- m68k user support (Paul Brook)
|
||||
- several x86 and x86_64 emulation fixes
|
||||
- Mouse relative offset VNC extension (Anthony Liguori)
|
||||
- PXE boot support (Anthony Liguori)
|
||||
- '-daemonize' option (Anthony Liguori)
|
||||
|
||||
version 0.8.2:
|
||||
|
||||
- ACPI support
|
||||
- PC VGA BIOS fixes
|
||||
- switch to OpenBios for SPARC targets (Blue Swirl)
|
||||
- VNC server fixes
|
||||
- MIPS FPU support (Marius Groeger)
|
||||
- Solaris/SPARC host support (Juergen Keil)
|
||||
- PPC breakpoints and single stepping (Jason Wessel)
|
||||
- USB updates (Paul Brook)
|
||||
- UDP/TCP/telnet character devices (Jason Wessel)
|
||||
- Windows sparse file support (Frediano Ziglio)
|
||||
- RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
|
||||
- PCNET NIC support (Antony T Curtis)
|
||||
- Support for variable frequency host CPUs
|
||||
- Workaround for win32 SMP hosts
|
||||
- Support for AMD Flash memories (Jocelyn Mayer)
|
||||
- Audio capture to WAV files support (malc)
|
||||
|
||||
version 0.8.1:
|
||||
|
||||
- USB tablet support (Brad Campbell, Anthony Liguori)
|
||||
- win32 host serial support (Kazu)
|
||||
- PC speaker support (Joachim Henke)
|
||||
- IDE LBA48 support (Jens Axboe)
|
||||
- SSE3 support
|
||||
- Solaris port (Juergen Keil)
|
||||
- Preliminary SH4 target (Samuel Tardieu)
|
||||
- VNC server (Anthony Liguori)
|
||||
- slirp fixes (Ed Swierk et al.)
|
||||
- USB fixes
|
||||
- ARM Versatile Platform Baseboard emulation (Paul Brook)
|
||||
|
||||
version 0.8.0:
|
||||
|
||||
- ARM system emulation: Arm Integrator/CP board with an arm1026ej-s
|
||||
cpu (Paul Brook)
|
||||
- SMP support
|
||||
- Mac OS X cocoa improvements (Mike Kronenberg)
|
||||
- Mac OS X CoreAudio driver (Mike Kronenberg)
|
||||
- DirectSound driver (malc)
|
||||
- ALSA audio driver (malc)
|
||||
- new audio options: '-soundhw' and '-audio-help' (malc)
|
||||
- ES1370 PCI audio device (malc)
|
||||
- Initial USB support
|
||||
- Linux host serial port access
|
||||
- Linux host low level parallel port access
|
||||
- New network emulation code supporting VLANs.
|
||||
- MIPS and MIPSel User Linux emulation
|
||||
- MIPS fixes to boot Linux (Daniel Jacobowitz)
|
||||
- NX bit support
|
||||
- Initial SPARC SMP support (Blue Swirl)
|
||||
- Major overhaul of the virtual FAT driver for read/write support
|
||||
(Johannes Schindelin)
|
||||
|
||||
version 0.7.2:
|
||||
|
||||
- x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
|
||||
- merge self modifying code handling in dirty ram page mecanism.
|
||||
- MIPS fixes (Ralf Baechle)
|
||||
- better user net performances
|
||||
|
||||
version 0.7.1:
|
||||
|
||||
- read-only Virtual FAT support (Johannes Schindelin)
|
||||
- Windows 2000 install disk full hack (original idea from Vladimir
|
||||
N. Oleynik)
|
||||
- VMDK disk image creation (Filip Navara)
|
||||
- SPARC64 progress (Blue Swirl)
|
||||
- initial MIPS support (Jocelyn mayer)
|
||||
- MIPS improvements (Ralf Baechle)
|
||||
- 64 bit fixes in user networking (initial patch by Gwenole Beauchesne)
|
||||
- IOAPIC support (Filip Navara)
|
||||
|
||||
version 0.7.0:
|
||||
|
||||
- better BIOS translation and HDD geometry auto-detection
|
||||
- user mode networking bug fix
|
||||
- undocumented FPU ops support
|
||||
- Cirrus VGA: support for 1280x1024x[8,15,16] modes
|
||||
- 'pidfile' option
|
||||
- .dmg disk image format support (Johannes Schindelin)
|
||||
- keymaps support (initial patch by Johannes Schindelin)
|
||||
- big endian ARM support (Lennert Buytenhek)
|
||||
- added generic 64 bit target support
|
||||
- x86_64 target support
|
||||
- initial APIC support
|
||||
- MMX/SSE/SSE2/PNI support
|
||||
- PC parallel port support (Mark Jonckheere)
|
||||
- initial SPARC64 support (Blue Swirl)
|
||||
- SPARC target boots Linux (Blue Swirl)
|
||||
- armv5te user mode support (Paul Brook)
|
||||
- ARM VFP support (Paul Brook)
|
||||
- ARM "Angel" semihosting syscalls (Paul Brook)
|
||||
- user mode gdb stub support (Paul Brook)
|
||||
- Samba 3 support
|
||||
- initial Cocoa support (Pierre d'Herbemont)
|
||||
- generic FPU emulation code
|
||||
- Virtual PC read-only disk image support (Alex Beregszaszi)
|
||||
|
||||
version 0.6.1:
|
||||
|
||||
- Mac OS X port (Pierre d'Herbemont)
|
||||
- Virtual console support
|
||||
- Better monitor line edition
|
||||
- New block device layer
|
||||
- New 'qcow' growable disk image support with AES encryption and
|
||||
transparent decompression
|
||||
- VMware 3 and 4 read-only disk image support (untested)
|
||||
- Support for up to 4 serial ports
|
||||
- TFTP server support (Magnus Damm)
|
||||
- Port redirection support in user mode networking
|
||||
- Support for not executable data sections
|
||||
- Compressed loop disk image support (Johannes Schindelin)
|
||||
- Level triggered IRQ fix (aka NE2000 PCI performance fix) (Steve
|
||||
Wormley)
|
||||
- Fixed Fedora Core 2 problems (now you can run qemu without any
|
||||
LD_ASSUME_KERNEL tricks on FC2)
|
||||
- DHCP fix for Windows (accept DHCPREQUEST alone)
|
||||
- SPARC system emulation (Blue Swirl)
|
||||
- Automatic Samba configuration for host file access from Windows.
|
||||
- '-loadvm' and '-full-screen' options
|
||||
- ne2000 savevm support (Johannes Schindelin)
|
||||
- Ctrl-Alt is now the default grab key. Ctrl-Alt-[0-9] switches to
|
||||
the virtual consoles.
|
||||
- BIOS floppy fix for NT4 (Mike Nordell, Derek Fawcus, Volker Ruppert)
|
||||
- Floppy fixes for NT4 and NT5 (Mike Nordell)
|
||||
- NT4 IDE fixes (Ben Pfaf, Mike Nordell)
|
||||
- SDL Audio support and SB16 fixes (malc)
|
||||
- ENTER instruction bug fix (initial patch by Stefan Kisdaroczi)
|
||||
- VGA font change fix
|
||||
- VGA read-only CRTC register fix
|
||||
|
||||
version 0.6.0:
|
||||
|
||||
- minimalist FPU exception support (NetBSD FPU probe fix)
|
||||
- cr0.ET fix (Win95 boot)
|
||||
- *BSD port (Markus Niemisto)
|
||||
- I/O access fix (signaled by Mark Jonckheere)
|
||||
- IDE drives serial number fix (Mike Nordell)
|
||||
- int13 CDROM BIOS fix (aka Solaris x86 install CD fix)
|
||||
- int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix)
|
||||
- BSR/BSF "undefined behaviour" fix
|
||||
- vmdk2raw: convert VMware disk images to raw images
|
||||
- PCI support
|
||||
- NE2K PCI support
|
||||
- dummy VGA PCI support
|
||||
- VGA font selection fix (Daniel Serpell)
|
||||
- PIC reset fix (Hidemi KAWAI)
|
||||
- PIC spurious irq support (aka Solaris install bug)
|
||||
- added '-localtime' option
|
||||
- Cirrus CL-GD54xx VGA support (initial patch by Makoto Suzuki (suzu))
|
||||
- APM and system shutdown support
|
||||
- Fixed system reset
|
||||
- Support for other PC BIOSes
|
||||
- Initial PowerMac hardware emulation
|
||||
- PowerMac/PREP OpenFirmware compatible BIOS (Jocelyn Mayer)
|
||||
- initial IDE BMDMA support (needed for Darwin x86)
|
||||
- Set the default memory size for PC emulation to 128 MB
|
||||
|
||||
version 0.5.5:
|
||||
|
||||
- SDL full screen support (initial patch by malc)
|
||||
- VGA support on PowerPC PREP
|
||||
- VBE fixes (Matthew Mastracci)
|
||||
- PIT fixes (aka Win98 hardware probe and "VGA slowness" bug)
|
||||
- IDE master only fixes (aka Win98 CD-ROM probe bug)
|
||||
- ARM load/store half word fix (Ulrich Hecht)
|
||||
- FDC fixes for Win98
|
||||
|
||||
version 0.5.4:
|
||||
|
||||
- qemu-fast fixes
|
||||
- BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
|
||||
- keyboard/mouse fix (Mike Nordell)
|
||||
- IDE fixes (Linux did not recognized slave drivers)
|
||||
- VM86 EIP masking fix (aka NT5 install fix) (Mike Nordell)
|
||||
- QEMU can now boot a PowerPC Linux kernel (Jocelyn Mayer)
|
||||
- User mode network stack
|
||||
- imul imm8 fix + 0x82 opcode support (Hidemi KAWAI)
|
||||
- precise self modifying code (aka BeOS install bug)
|
||||
|
||||
version 0.5.3:
|
||||
|
||||
- added Bochs VESA VBE support
|
||||
- VGA memory map mode 3 access fix (OS/2 install fix)
|
||||
- IDE fixes (Jens Axboe)
|
||||
- CPU interrupt fixes
|
||||
- fixed various TLB invalidation cases (NT install)
|
||||
- fixed cr0.WP semantics (XP install)
|
||||
- direct chaining support for SPARC and PowerPC (faster)
|
||||
- ARM NWFPE support (initial patch by Ulrich Hecht)
|
||||
- added specific x86 to x86 translator (close to native performance
|
||||
in qemu-i386 and qemu-fast)
|
||||
- shm syscalls support (Paul McKerras)
|
||||
- added accurate CR0.MP/ME/TS emulation
|
||||
- fixed DMA memory write access (Win95 boot floppy fix)
|
||||
- graphical x86 linux loader
|
||||
- command line monitor
|
||||
- generic removable device support
|
||||
- support of CD-ROM change
|
||||
- multiple network interface support
|
||||
- initial x86-64 host support (Gwenole Beauchesne)
|
||||
- lret to outer privilege fix (OS/2 install fix)
|
||||
- task switch fixes (SkyOS boot)
|
||||
- VM save/restore commands
|
||||
- new timer API
|
||||
- more precise RTC emulation (periodic timers + time updates)
|
||||
- Win32 port (initial patch by Kazu)
|
||||
|
||||
version 0.5.2:
|
||||
|
||||
- improved soft MMU speed (assembly functions and specializing)
|
||||
- improved multitasking speed by avoiding flushing TBs when
|
||||
switching tasks
|
||||
- improved qemu-fast speed
|
||||
- improved self modifying code handling (big performance gain in
|
||||
softmmu mode).
|
||||
- fixed IO checking
|
||||
- fixed CD-ROM detection (win98 install CD)
|
||||
- fixed addseg real mode bug (GRUB boot fix)
|
||||
- added ROM memory support (win98 boot)
|
||||
- fixed 'call Ev' in case of paging exception
|
||||
- updated the script 'qemu-binfmt-conf.sh' to use QEMU automagically
|
||||
when launching executables for the supported target CPUs.
|
||||
- PowerPC system emulation update (Jocelyn Mayer)
|
||||
- PC floppy emulation and DMA fixes (Jocelyn Mayer)
|
||||
- polled mode for PIC (Jocelyn Mayer)
|
||||
- fixed PTE dirty bit handling
|
||||
- fixed xadd same reg bug
|
||||
- fixed cmpxchg exception safeness
|
||||
- access to virtual memory in gdb stub
|
||||
- task gate and NT flag fixes
|
||||
- eflags optimisation fix for string operations
|
||||
|
||||
version 0.5.1:
|
||||
|
||||
- float access fixes when using soft mmu
|
||||
- PC emulation support on PowerPC
|
||||
- A20 support
|
||||
- IDE CD-ROM emulation
|
||||
- ARM fixes (Ulrich Hecht)
|
||||
- SB16 emulation (malc)
|
||||
- IRET and INT fixes in VM86 mode with IOPL=3
|
||||
- Port I/Os use TSS io map
|
||||
- Full task switching/task gate support
|
||||
- added verr, verw, arpl, fcmovxx
|
||||
- PowerPC target support (Jocelyn Mayer)
|
||||
- Major SPARC target fixes (dynamically linked programs begin to work)
|
||||
|
||||
version 0.5.0:
|
||||
|
||||
- full hardware level VGA emulation
|
||||
- graphical display with SDL
|
||||
- added PS/2 mouse and keyboard emulation
|
||||
- popw (%esp) fix
|
||||
- mov to/from segment data width fix
|
||||
- added real mode support
|
||||
- added Bochs BIOS and LGPL'ed VGA BIOS loader in qemu
|
||||
- m68k host port (Richard Zidlicky)
|
||||
- partial soft MMU support for memory mapped I/Os
|
||||
- multi-target build
|
||||
- fixed: no error code in hardware interrupts
|
||||
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
|
||||
- correct single stepping through string operations
|
||||
- preliminary SPARC target support (Thomas M. Ogrisegg)
|
||||
- tun-fd option (Rusty Russell)
|
||||
- automatic IDE geometry detection
|
||||
- renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}.
|
||||
- added man page
|
||||
- added full soft mmu mode to launch unpatched OSes.
|
||||
|
||||
version 0.4.3:
|
||||
|
||||
- x86 exception fix in case of nop instruction.
|
||||
- gcc 3.2.2 bug workaround (RedHat 9 fix)
|
||||
- sparc and Alpha host fixes
|
||||
- many ARM target fixes: 'ls' and 'bash' can be launched.
|
||||
|
||||
version 0.4.2:
|
||||
|
||||
- many exception handling fixes (can compile a Linux kernel inside vl)
|
||||
- IDE emulation support
|
||||
- initial GDB stub support
|
||||
- deferred update support for disk images (Rusty Russell)
|
||||
- accept User Mode Linux Copy On Write disk images
|
||||
- SMP kernels can at least be booted
|
||||
|
||||
version 0.4.1:
|
||||
|
||||
- more accurate timer support in vl.
|
||||
- more reliable NE2000 probe in vl.
|
||||
- added 2.5.66 kernel in vl-test.
|
||||
- added VLTMPDIR environment variable in vl.
|
||||
|
||||
version 0.4:
|
||||
|
||||
- initial support for ring 0 x86 processor emulation
|
||||
- fixed signal handling for correct dosemu DPMI emulation
|
||||
- fast x86 MMU emulation with mmap()
|
||||
- fixed popl (%esp) case
|
||||
- Linux kernel can be executed by QEMU with the 'vl' command.
|
||||
|
||||
version 0.3:
|
||||
|
||||
- initial support for ARM emulation
|
||||
- added fnsave, frstor, fnstenv, fldenv FPU instructions
|
||||
- added FPU register save in signal emulation
|
||||
- initial ARM port
|
||||
- Sparc and Alpha ports work on the regression test
|
||||
- generic ioctl number conversion
|
||||
- fixed ioctl type conversion
|
||||
|
||||
version 0.2:
|
||||
|
||||
- PowerPC disassembly and ELF symbols output (Rusty Russell)
|
||||
- flock support (Rusty Russell)
|
||||
- ugetrlimit support (Rusty Russell)
|
||||
- fstat64 fix (Rusty Russell)
|
||||
- initial Alpha port (Falk Hueffner)
|
||||
- initial IA64 port (Matt Wilson)
|
||||
- initial Sparc and Sparc64 port (David S. Miller)
|
||||
- added HLT instruction
|
||||
- LRET instruction fix.
|
||||
- added GPF generation for I/Os.
|
||||
- added INT3 and TF flag support.
|
||||
- SHL instruction C flag fix.
|
||||
- mmap emulation for host page size > 4KB
|
||||
- self-modifying code support
|
||||
- better VM86 support (dosemu works on non trivial programs)
|
||||
- precise exception support (EIP is computed correctly in most cases)
|
||||
- more precise LDT/GDT/IDT emulation
|
||||
- faster segment load in vm86 mode
|
||||
- direct chaining of basic blocks (faster emulation)
|
||||
|
||||
version 0.1.6:
|
||||
|
||||
- automatic library search system. QEMU can now work with unpatched
|
||||
ELF dynamic loader and libc (Rusty Russell).
|
||||
- ISO C warning fixes (Alistair Strachan)
|
||||
- first self-virtualizable version (works only as long as the
|
||||
translation cache is not flushed)
|
||||
- RH9 fixes
|
||||
|
||||
version 0.1.5:
|
||||
|
||||
- ppc64 support + personality() patch (Rusty Russell)
|
||||
- first Alpha CPU patches (Falk Hueffner)
|
||||
- removed bfd.h dependency
|
||||
- fixed shrd, shld, idivl and divl on PowerPC.
|
||||
- fixed buggy glibc PowerPC rint() function (test-i386 passes now on PowerPC).
|
||||
|
||||
version 0.1.4:
|
||||
|
||||
- more accurate VM86 emulation (can launch small DOS 16 bit
|
||||
executables in wine).
|
||||
- fixed push/pop fs/gs
|
||||
- added iret instruction.
|
||||
- added times() syscall and SIOCATMARK ioctl.
|
||||
|
||||
version 0.1.3:
|
||||
|
||||
- S390 support (Ulrich Weigand)
|
||||
- glibc 2.3.x compile fix (Ulrich Weigand)
|
||||
- socketcall endian fix (Ulrich Weigand)
|
||||
- struct sockaddr endian fix (Ulrich Weigand)
|
||||
- sendmsg/recvmsg endian fix (Ulrich Weigand)
|
||||
- execve endian fix (Ulrich Weigand)
|
||||
- fdset endian fix (Ulrich Weigand)
|
||||
- partial setsockopt syscall support (Ulrich Weigand)
|
||||
- more accurate pushf/popf emulation
|
||||
- first partial vm86() syscall support (can be used with runcom example).
|
||||
- added bound, cmpxchg8b, cpuid instructions
|
||||
- added 16 bit addressing support/override for string operations
|
||||
- poll() fix
|
||||
|
||||
version 0.1.2:
|
||||
|
||||
- compile fixes
|
||||
- xlat instruction
|
||||
- xchg instruction memory lock
|
||||
- added simple vm86 example (not working with QEMU yet). The 54 byte
|
||||
DOS executable 'pi_10.com' program was released by Bertram
|
||||
Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html).
|
||||
|
||||
version 0.1.1:
|
||||
|
||||
- glibc 2.2 compilation fixes
|
||||
- added -s and -L options
|
||||
- binary distribution of x86 glibc and wine
|
||||
- big endian fixes in ELF loader and getdents.
|
||||
|
||||
version 0.1:
|
||||
|
||||
- initial public release.
|
1
Kconfig
1
Kconfig
|
@ -2,3 +2,4 @@ source Kconfig.host
|
|||
source backends/Kconfig
|
||||
source accel/Kconfig
|
||||
source hw/Kconfig
|
||||
source semihosting/Kconfig
|
||||
|
|
12
Kconfig.host
12
Kconfig.host
|
@ -1,6 +1,6 @@
|
|||
# These are "proxy" symbols used to pass config-host.mak values
|
||||
# down to Kconfig. See also MINIKCONF_ARGS in the Makefile:
|
||||
# these two need to be kept in sync.
|
||||
# down to Kconfig. See also kconfig_external_symbols in
|
||||
# meson.build: these two need to be kept in sync.
|
||||
|
||||
config LINUX
|
||||
bool
|
||||
|
@ -24,6 +24,10 @@ config VHOST_USER
|
|||
bool
|
||||
select VHOST
|
||||
|
||||
config VHOST_VDPA
|
||||
bool
|
||||
select VHOST
|
||||
|
||||
config VHOST_KERNEL
|
||||
bool
|
||||
select VHOST
|
||||
|
@ -33,3 +37,7 @@ config VIRTFS
|
|||
|
||||
config PVRDMA
|
||||
bool
|
||||
|
||||
config MULTIPROCESS_ALLOWED
|
||||
bool
|
||||
imply MULTIPROCESS
|
||||
|
|
618
MAINTAINERS
618
MAINTAINERS
File diff suppressed because it is too large
Load Diff
217
Makefile.objs
217
Makefile.objs
|
@ -1,217 +0,0 @@
|
|||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
stub-obj-y = stubs/
|
||||
util-obj-y = crypto/ util/ qobject/ qapi/
|
||||
qom-obj-y = qom/
|
||||
|
||||
#######################################################################
|
||||
# code used by both qemu system emulation and qemu-img
|
||||
|
||||
ifeq ($(call lor,$(CONFIG_SOFTMMU),$(CONFIG_TOOLS)),y)
|
||||
|
||||
chardev-obj-y = chardev/
|
||||
|
||||
authz-obj-y = authz/
|
||||
|
||||
block-obj-y = block/ nbd/ scsi/
|
||||
block-obj-y += block.o blockjob.o job.o
|
||||
block-obj-y += qemu-io-cmds.o
|
||||
block-obj-$(CONFIG_REPLICATION) += replication.o
|
||||
|
||||
block-obj-m = block/
|
||||
|
||||
crypto-obj-y = crypto/
|
||||
|
||||
io-obj-y = io/
|
||||
|
||||
endif # CONFIG_SOFTMMU or CONFIG_TOOLS
|
||||
|
||||
#######################################################################
|
||||
# storage-daemon-obj-y is code used by qemu-storage-daemon (these objects are
|
||||
# used for system emulation, too, but specified separately there)
|
||||
|
||||
storage-daemon-obj-y = block/ monitor/ qapi/ qom/ storage-daemon/
|
||||
storage-daemon-obj-y += blockdev.o blockdev-nbd.o iothread.o job-qmp.o
|
||||
storage-daemon-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
storage-daemon-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
|
||||
######################################################################
|
||||
# Target independent part of system emulation. The long term path is to
|
||||
# suppress *all* target specific code in case of system emulation, i.e. a
|
||||
# single QEMU executable should support all CPUs and machines.
|
||||
|
||||
ifeq ($(CONFIG_SOFTMMU),y)
|
||||
common-obj-y = blockdev.o blockdev-nbd.o block/
|
||||
common-obj-y += bootdevice.o iothread.o
|
||||
common-obj-y += dump/
|
||||
common-obj-y += job-qmp.o
|
||||
common-obj-y += monitor/
|
||||
common-obj-y += net/
|
||||
common-obj-y += qdev-monitor.o
|
||||
common-obj-$(CONFIG_WIN32) += os-win32.o
|
||||
common-obj-$(CONFIG_POSIX) += os-posix.o
|
||||
|
||||
common-obj-$(CONFIG_LINUX) += fsdev/
|
||||
|
||||
common-obj-y += accel/
|
||||
common-obj-y += migration/
|
||||
|
||||
common-obj-y += audio/
|
||||
common-obj-m += audio/
|
||||
common-obj-y += hw/
|
||||
common-obj-m += hw/
|
||||
|
||||
common-obj-y += replay/
|
||||
|
||||
common-obj-y += ui/
|
||||
common-obj-m += ui/
|
||||
|
||||
common-obj-y += dma-helpers.o
|
||||
common-obj-$(CONFIG_TPM) += tpm.o
|
||||
|
||||
common-obj-y += backends/
|
||||
common-obj-y += chardev/
|
||||
common-obj-m += chardev/
|
||||
|
||||
common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
|
||||
qemu-seccomp.o-cflags := $(SECCOMP_CFLAGS)
|
||||
qemu-seccomp.o-libs := $(SECCOMP_LIBS)
|
||||
|
||||
common-obj-$(CONFIG_FDT) += device_tree.o
|
||||
|
||||
common-obj-y += qapi/
|
||||
|
||||
common-obj-y += xemu-version.o
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
|
||||
#######################################################################
|
||||
# Target-independent parts used in system and user emulation
|
||||
common-obj-y += cpus-common.o
|
||||
common-obj-y += hw/
|
||||
common-obj-y += qom/
|
||||
common-obj-y += disas/
|
||||
|
||||
######################################################################
|
||||
# Resource file for Windows executables
|
||||
version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o
|
||||
|
||||
######################################################################
|
||||
# tracing
|
||||
util-obj-y += trace/
|
||||
|
||||
######################################################################
|
||||
# guest agent
|
||||
|
||||
# FIXME: a few definitions from qapi/qapi-types.o and
|
||||
# qapi/qapi-visit.o are needed by libqemuutil.a. These should be
|
||||
# extracted into a QAPI schema module, or perhaps a separate schema.
|
||||
qga-obj-y = qga/
|
||||
qga-vss-dll-obj-y = qga/
|
||||
|
||||
######################################################################
|
||||
# contrib
|
||||
elf2dmp-obj-y = contrib/elf2dmp/
|
||||
ivshmem-client-obj-$(CONFIG_IVSHMEM) = contrib/ivshmem-client/
|
||||
ivshmem-server-obj-$(CONFIG_IVSHMEM) = contrib/ivshmem-server/
|
||||
libvhost-user-obj-y = contrib/libvhost-user/
|
||||
vhost-user-scsi.o-cflags := $(LIBISCSI_CFLAGS)
|
||||
vhost-user-scsi.o-libs := $(LIBISCSI_LIBS)
|
||||
vhost-user-scsi-obj-y = contrib/vhost-user-scsi/
|
||||
vhost-user-blk-obj-y = contrib/vhost-user-blk/
|
||||
rdmacm-mux-obj-y = contrib/rdmacm-mux/
|
||||
vhost-user-input-obj-y = contrib/vhost-user-input/
|
||||
vhost-user-gpu-obj-y = contrib/vhost-user-gpu/
|
||||
virtiofsd-obj-y = tools/virtiofsd/
|
||||
|
||||
######################################################################
|
||||
trace-events-subdirs =
|
||||
trace-events-subdirs += accel/kvm
|
||||
trace-events-subdirs += accel/tcg
|
||||
trace-events-subdirs += backends
|
||||
trace-events-subdirs += backends/tpm
|
||||
trace-events-subdirs += crypto
|
||||
trace-events-subdirs += monitor
|
||||
ifeq ($(CONFIG_USER_ONLY),y)
|
||||
trace-events-subdirs += linux-user
|
||||
endif
|
||||
ifeq ($(CONFIG_BLOCK),y)
|
||||
trace-events-subdirs += authz
|
||||
trace-events-subdirs += block
|
||||
trace-events-subdirs += io
|
||||
trace-events-subdirs += nbd
|
||||
trace-events-subdirs += scsi
|
||||
endif
|
||||
ifeq ($(CONFIG_SOFTMMU),y)
|
||||
trace-events-subdirs += audio
|
||||
trace-events-subdirs += chardev
|
||||
trace-events-subdirs += hw/9pfs
|
||||
trace-events-subdirs += hw/acpi
|
||||
trace-events-subdirs += hw/alpha
|
||||
trace-events-subdirs += hw/arm
|
||||
trace-events-subdirs += hw/audio
|
||||
trace-events-subdirs += hw/block
|
||||
trace-events-subdirs += hw/block/dataplane
|
||||
trace-events-subdirs += hw/char
|
||||
trace-events-subdirs += hw/dma
|
||||
trace-events-subdirs += hw/hppa
|
||||
trace-events-subdirs += hw/hyperv
|
||||
trace-events-subdirs += hw/i2c
|
||||
trace-events-subdirs += hw/i386
|
||||
trace-events-subdirs += hw/i386/xen
|
||||
trace-events-subdirs += hw/ide
|
||||
trace-events-subdirs += hw/input
|
||||
trace-events-subdirs += hw/intc
|
||||
trace-events-subdirs += hw/isa
|
||||
trace-events-subdirs += hw/mem
|
||||
trace-events-subdirs += hw/mips
|
||||
trace-events-subdirs += hw/misc
|
||||
trace-events-subdirs += hw/misc/macio
|
||||
trace-events-subdirs += hw/net
|
||||
trace-events-subdirs += hw/nvram
|
||||
trace-events-subdirs += hw/pci
|
||||
trace-events-subdirs += hw/pci-host
|
||||
trace-events-subdirs += hw/ppc
|
||||
trace-events-subdirs += hw/rdma
|
||||
trace-events-subdirs += hw/rdma/vmw
|
||||
trace-events-subdirs += hw/rtc
|
||||
trace-events-subdirs += hw/s390x
|
||||
trace-events-subdirs += hw/scsi
|
||||
trace-events-subdirs += hw/sd
|
||||
trace-events-subdirs += hw/sparc
|
||||
trace-events-subdirs += hw/sparc64
|
||||
trace-events-subdirs += hw/ssi
|
||||
trace-events-subdirs += hw/timer
|
||||
trace-events-subdirs += hw/tpm
|
||||
trace-events-subdirs += hw/usb
|
||||
trace-events-subdirs += hw/vfio
|
||||
trace-events-subdirs += hw/virtio
|
||||
trace-events-subdirs += hw/watchdog
|
||||
trace-events-subdirs += hw/xen
|
||||
trace-events-subdirs += hw/gpio
|
||||
trace-events-subdirs += hw/riscv
|
||||
trace-events-subdirs += migration
|
||||
trace-events-subdirs += net
|
||||
trace-events-subdirs += ui
|
||||
endif
|
||||
trace-events-subdirs += hw/core
|
||||
trace-events-subdirs += hw/display
|
||||
trace-events-subdirs += qapi
|
||||
trace-events-subdirs += qom
|
||||
trace-events-subdirs += target/arm
|
||||
trace-events-subdirs += target/hppa
|
||||
trace-events-subdirs += target/i386
|
||||
trace-events-subdirs += target/mips
|
||||
trace-events-subdirs += target/ppc
|
||||
trace-events-subdirs += target/riscv
|
||||
trace-events-subdirs += target/s390x
|
||||
trace-events-subdirs += target/sparc
|
||||
trace-events-subdirs += util
|
||||
|
||||
trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
|
||||
|
||||
trace-obj-y = trace-root.o
|
||||
trace-obj-y += $(trace-events-subdirs:%=%/trace.o)
|
||||
trace-obj-$(CONFIG_TRACE_UST) += trace-ust-all.o
|
||||
trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace-root.o
|
||||
trace-obj-$(CONFIG_TRACE_DTRACE) += $(trace-events-subdirs:%=%/trace-dtrace.o)
|
291
Makefile.target
291
Makefile.target
|
@ -1,291 +0,0 @@
|
|||
# -*- Mode: makefile -*-
|
||||
|
||||
BUILD_DIR?=$(CURDIR)/..
|
||||
|
||||
include ../config-host.mak
|
||||
include config-target.mak
|
||||
include $(SRC_PATH)/rules.mak
|
||||
|
||||
ifdef CONFIG_SOFTMMU
|
||||
include config-devices.mak
|
||||
endif
|
||||
|
||||
$(call set-vpath, $(SRC_PATH):$(BUILD_DIR))
|
||||
ifdef CONFIG_LINUX
|
||||
QEMU_CFLAGS += -isystem ../linux-headers
|
||||
endif
|
||||
QEMU_CFLAGS += -iquote .. -iquote $(SRC_PATH)/target/$(TARGET_BASE_ARCH) -DNEED_CPU_H
|
||||
|
||||
QEMU_CFLAGS+=-iquote $(SRC_PATH)/include
|
||||
|
||||
ifdef CONFIG_USER_ONLY
|
||||
# user emulator name
|
||||
QEMU_PROG=qemu-$(TARGET_NAME)
|
||||
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||
else
|
||||
# system emulator name
|
||||
QEMU_PROG=qemu-system-$(TARGET_NAME)$(EXESUF)
|
||||
ifneq (,$(findstring -mwindows,$(SDL_LIBS)))
|
||||
# Terminate program name with a 'w' because the linker builds a windows executable.
|
||||
QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF)
|
||||
$(QEMU_PROG): $(QEMU_PROGW)
|
||||
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG),"GEN","$(TARGET_DIR)$(QEMU_PROG)")
|
||||
QEMU_PROG_BUILD = $(QEMU_PROGW)
|
||||
else
|
||||
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||
endif
|
||||
endif
|
||||
|
||||
PROGS=$(QEMU_PROG) $(QEMU_PROGW)
|
||||
STPFILES=
|
||||
|
||||
config-target.h: config-target.h-timestamp
|
||||
config-target.h-timestamp: config-target.mak
|
||||
|
||||
config-devices.h: config-devices.h-timestamp
|
||||
config-devices.h-timestamp: config-devices.mak
|
||||
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp $(QEMU_PROG)-simpletrace.stp $(QEMU_PROG)-log.stp
|
||||
|
||||
ifdef CONFIG_USER_ONLY
|
||||
TARGET_TYPE=user
|
||||
else
|
||||
TARGET_TYPE=system
|
||||
endif
|
||||
|
||||
tracetool-y = $(SRC_PATH)/scripts/tracetool.py
|
||||
tracetool-y += $(shell find $(SRC_PATH)/scripts/tracetool -name "*.py")
|
||||
|
||||
$(QEMU_PROG).stp-installed: $(BUILD_DIR)/trace-events-all $(tracetool-y)
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--group=all \
|
||||
--format=stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--binary=$(bindir)/$(QEMU_PROG) \
|
||||
--target-name=$(TARGET_NAME) \
|
||||
--target-type=$(TARGET_TYPE) \
|
||||
$< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp-installed")
|
||||
|
||||
$(QEMU_PROG).stp: $(BUILD_DIR)/trace-events-all $(tracetool-y)
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--group=all \
|
||||
--format=stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--binary=$(realpath .)/$(QEMU_PROG) \
|
||||
--target-name=$(TARGET_NAME) \
|
||||
--target-type=$(TARGET_TYPE) \
|
||||
$< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG).stp")
|
||||
|
||||
$(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all $(tracetool-y)
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--group=all \
|
||||
--format=simpletrace-stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \
|
||||
$< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp")
|
||||
|
||||
$(QEMU_PROG)-log.stp: $(BUILD_DIR)/trace-events-all $(tracetool-y)
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--group=all \
|
||||
--format=log-stap \
|
||||
--backends=$(TRACE_BACKENDS) \
|
||||
--probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \
|
||||
$< > $@,"GEN","$(TARGET_DIR)$(QEMU_PROG)-log.stp")
|
||||
|
||||
else
|
||||
stap:
|
||||
endif
|
||||
.PHONY: stap
|
||||
|
||||
all: $(PROGS) stap
|
||||
|
||||
# Dummy command so that make thinks it has done something
|
||||
@true
|
||||
|
||||
obj-y += trace/
|
||||
|
||||
#########################################################
|
||||
# xemu
|
||||
obj-y += xemu-xbe.o
|
||||
|
||||
#########################################################
|
||||
# cpu emulator library
|
||||
obj-y += exec.o exec-vary.o
|
||||
obj-y += accel/
|
||||
obj-$(CONFIG_TCG) += tcg/tcg.o tcg/tcg-op.o tcg/tcg-op-vec.o tcg/tcg-op-gvec.o
|
||||
obj-$(CONFIG_TCG) += tcg/tcg-common.o tcg/optimize.o
|
||||
obj-$(CONFIG_TCG_INTERPRETER) += tcg/tci.o
|
||||
obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
|
||||
obj-$(CONFIG_TCG) += fpu/softfloat.o
|
||||
obj-y += target/$(TARGET_BASE_ARCH)/
|
||||
obj-y += disas.o
|
||||
obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o
|
||||
LIBS := $(libs_cpu) $(LIBS)
|
||||
|
||||
obj-$(CONFIG_PLUGIN) += plugins/
|
||||
|
||||
#########################################################
|
||||
# Linux user emulator target
|
||||
|
||||
ifdef CONFIG_LINUX_USER
|
||||
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
|
||||
-I$(SRC_PATH)/linux-user/host/$(ARCH) \
|
||||
-I$(SRC_PATH)/linux-user \
|
||||
-Ilinux-user/$(TARGET_ABI_DIR)
|
||||
|
||||
obj-y += linux-user/
|
||||
obj-y += gdbstub.o thunk.o
|
||||
|
||||
endif #CONFIG_LINUX_USER
|
||||
|
||||
#########################################################
|
||||
# BSD user emulator target
|
||||
|
||||
ifdef CONFIG_BSD_USER
|
||||
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ABI_DIR) \
|
||||
-I$(SRC_PATH)/bsd-user/$(HOST_VARIANT_DIR)
|
||||
|
||||
obj-y += bsd-user/
|
||||
obj-y += gdbstub.o
|
||||
|
||||
endif #CONFIG_BSD_USER
|
||||
|
||||
#########################################################
|
||||
# System emulator target
|
||||
ifdef CONFIG_SOFTMMU
|
||||
obj-y += softmmu/
|
||||
obj-y += gdbstub.o
|
||||
obj-y += dump/
|
||||
obj-y += hw/
|
||||
obj-y += monitor/
|
||||
obj-y += qapi/
|
||||
obj-y += migration/ram.o
|
||||
LIBS := $(libs_softmmu) $(LIBS)
|
||||
|
||||
# Hardware support
|
||||
ifeq ($(TARGET_NAME), sparc64)
|
||||
obj-y += hw/sparc64/
|
||||
else
|
||||
obj-y += hw/$(TARGET_BASE_ARCH)/
|
||||
endif
|
||||
|
||||
generated-files-y += hmp-commands.h hmp-commands-info.h
|
||||
generated-files-y += config-devices.h
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
|
||||
dummy := $(call unnest-vars,,obj-y)
|
||||
all-obj-y := $(obj-y)
|
||||
|
||||
#
|
||||
# common-obj-m has some crap here, probably as side effect from
|
||||
# unnest-vars recursing into target directories to fill obj-y and not
|
||||
# properly handling the -m case.
|
||||
#
|
||||
# Clear common-obj-m as workaround. Fixes suspious dependency errors
|
||||
# when building devices as modules. A bit hackish, but should be ok
|
||||
# as long as we do not have any target-specific modules.
|
||||
#
|
||||
# The meson-based build system currently in development doesn't need
|
||||
# unnest-vars and will obsolete this workaround.
|
||||
#
|
||||
common-obj-m :=
|
||||
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
dummy := $(call unnest-vars,.., \
|
||||
authz-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
chardev-obj-y \
|
||||
crypto-obj-y \
|
||||
qom-obj-y \
|
||||
io-obj-y \
|
||||
common-obj-y \
|
||||
common-obj-m)
|
||||
all-obj-y += $(common-obj-y)
|
||||
all-obj-y += $(qom-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(authz-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
|
||||
|
||||
ifdef CONFIG_SOFTMMU
|
||||
$(QEMU_PROG_BUILD): config-devices.mak
|
||||
endif
|
||||
|
||||
COMMON_LDADDS = ../libqemuutil.a
|
||||
|
||||
# build either PROG or PROGW
|
||||
$(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS) $(softmmu-main-y)
|
||||
$(call LINK, $(filter-out %.mak, $^))
|
||||
ifdef CONFIG_DARWIN
|
||||
$(call quiet-command,Rez -append $(SRC_PATH)/pc-bios/qemu.rsrc -o $@,"REZ","$(TARGET_DIR)$@")
|
||||
$(call quiet-command,SetFile -a C $@,"SETFILE","$(TARGET_DIR)$@")
|
||||
endif
|
||||
|
||||
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
|
||||
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"GEN","$(TARGET_DIR)$@")
|
||||
|
||||
hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@")
|
||||
|
||||
hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool
|
||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@")
|
||||
|
||||
clean: clean-target
|
||||
rm -f *.a *~ $(PROGS)
|
||||
rm -f $(shell find . -name '*.[od]')
|
||||
rm -f hmp-commands.h gdbstub-xml.c
|
||||
rm -f trace/generated-helpers.c trace/generated-helpers.c-timestamp
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
rm -f *.stp
|
||||
endif
|
||||
|
||||
ifdef CONFIG_FUZZ
|
||||
include $(SRC_PATH)/tests/qtest/fuzz/Makefile.include
|
||||
include $(SRC_PATH)/tests/qtest/Makefile.include
|
||||
|
||||
fuzz: fuzz-vars
|
||||
fuzz-vars: QEMU_CFLAGS := $(FUZZ_CFLAGS) $(QEMU_CFLAGS)
|
||||
fuzz-vars: QEMU_LDFLAGS := $(FUZZ_LDFLAGS) $(QEMU_LDFLAGS)
|
||||
fuzz-vars: $(QEMU_PROG_FUZZ)
|
||||
dummy := $(call unnest-vars,, fuzz-obj-y)
|
||||
|
||||
|
||||
$(QEMU_PROG_FUZZ): config-devices.mak $(all-obj-y) $(COMMON_LDADDS) $(fuzz-obj-y)
|
||||
$(call LINK, $(filter-out %.mak, $^))
|
||||
|
||||
endif
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
$(call install-prog,$(PROGS),$(DESTDIR)$(bindir))
|
||||
endif
|
||||
ifdef CONFIG_TRACE_SYSTEMTAP
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
|
||||
$(INSTALL_DATA) $(QEMU_PROG).stp-installed "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG).stp"
|
||||
$(INSTALL_DATA) $(QEMU_PROG)-simpletrace.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-simpletrace.stp"
|
||||
$(INSTALL_DATA) $(QEMU_PROG)-log.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-log.stp"
|
||||
endif
|
||||
|
||||
generated-files-y += config-target.h
|
||||
Makefile: $(generated-files-y)
|
||||
|
||||
# Reports/Analysis
|
||||
#
|
||||
# The target specific coverage report only cares about target specific
|
||||
# blobs and not the shared code.
|
||||
#
|
||||
|
||||
%/coverage-report.html:
|
||||
@mkdir -p $*
|
||||
$(call quiet-command,\
|
||||
gcovr -r $(SRC_PATH) --object-directory $(CURDIR) \
|
||||
-p --html --html-details -o $@, \
|
||||
"GEN", "coverage-report.html")
|
||||
|
||||
.PHONY: coverage-report
|
||||
coverage-report: $(CURDIR)/reports/coverage/coverage-report.html
|
27
README.rst
27
README.rst
|
@ -31,6 +31,17 @@ QEMU as a whole is released under the GNU General Public License,
|
|||
version 2. For full licensing details, consult the LICENSE file.
|
||||
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
Documentation can be found hosted online at
|
||||
`<https://www.qemu.org/documentation/>`_. The documentation for the
|
||||
current development version that is available at
|
||||
`<https://www.qemu.org/docs/master/>`_ is generated from the ``docs/``
|
||||
folder in the source tree, and is built by `Sphinx
|
||||
<https://www.sphinx-doc.org/en/master/>_`.
|
||||
|
||||
|
||||
Building
|
||||
========
|
||||
|
||||
|
@ -60,13 +71,15 @@ The QEMU source code is maintained under the GIT version control system.
|
|||
|
||||
.. code-block:: shell
|
||||
|
||||
git clone https://git.qemu.org/git/qemu.git
|
||||
git clone https://gitlab.com/qemu-project/qemu.git
|
||||
|
||||
When submitting patches, one common approach is to use 'git
|
||||
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
|
||||
a 'Signed-off-by' line from the author. Patches should follow the
|
||||
guidelines set out in the CODING_STYLE.rst file.
|
||||
guidelines set out in the `style section
|
||||
<https://www.qemu.org/docs/master/devel/style.html>` of
|
||||
the Developers Guide.
|
||||
|
||||
Additional information on submitting patches can be found online via
|
||||
the QEMU website
|
||||
|
@ -78,7 +91,7 @@ The QEMU website is also maintained under source control.
|
|||
|
||||
.. code-block:: shell
|
||||
|
||||
git clone https://git.qemu.org/git/qemu-web.git
|
||||
git clone https://gitlab.com/qemu-project/qemu-web.git
|
||||
|
||||
* `<https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/>`_
|
||||
|
||||
|
@ -134,6 +147,14 @@ For additional information on bug reporting consult:
|
|||
* `<https://qemu.org/Contribute/ReportABug>`_
|
||||
|
||||
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
For version history and release notes, please visit
|
||||
`<https://wiki.qemu.org/ChangeLog/>`_ or look at the git history for
|
||||
more detailed information.
|
||||
|
||||
|
||||
Contact
|
||||
=======
|
||||
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
config WHPX
|
||||
bool
|
||||
|
||||
config HAX
|
||||
bool
|
||||
|
||||
config HVF
|
||||
bool
|
||||
|
||||
config TCG
|
||||
bool
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
common-obj-$(CONFIG_SOFTMMU) += accel.o
|
||||
obj-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_POSIX)) += qtest.o
|
||||
obj-$(CONFIG_KVM) += kvm/
|
||||
obj-$(CONFIG_TCG) += tcg/
|
||||
obj-$(CONFIG_XEN) += xen/
|
||||
obj-y += stubs/
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* QEMU accel class, components common to system emulation and user mode
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2014 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/accel.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "hw/core/accel-cpu.h"
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#include "accel-softmmu.h"
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
static const TypeInfo accel_type = {
|
||||
.name = TYPE_ACCEL,
|
||||
.parent = TYPE_OBJECT,
|
||||
.class_size = sizeof(AccelClass),
|
||||
.instance_size = sizeof(AccelState),
|
||||
};
|
||||
|
||||
/* Lookup AccelClass from opt_name. Returns NULL if not found */
|
||||
AccelClass *accel_find(const char *opt_name)
|
||||
{
|
||||
char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
|
||||
AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name));
|
||||
g_free(class_name);
|
||||
return ac;
|
||||
}
|
||||
|
||||
static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque)
|
||||
{
|
||||
CPUClass *cc = CPU_CLASS(klass);
|
||||
AccelCPUClass *accel_cpu = opaque;
|
||||
|
||||
cc->accel_cpu = accel_cpu;
|
||||
if (accel_cpu->cpu_class_init) {
|
||||
accel_cpu->cpu_class_init(cc);
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize the arch-specific accel CpuClass interfaces */
|
||||
static void accel_init_cpu_interfaces(AccelClass *ac)
|
||||
{
|
||||
const char *ac_name; /* AccelClass name */
|
||||
char *acc_name; /* AccelCPUClass name */
|
||||
ObjectClass *acc; /* AccelCPUClass */
|
||||
|
||||
ac_name = object_class_get_name(OBJECT_CLASS(ac));
|
||||
g_assert(ac_name != NULL);
|
||||
|
||||
acc_name = g_strdup_printf("%s-%s", ac_name, CPU_RESOLVING_TYPE);
|
||||
acc = object_class_by_name(acc_name);
|
||||
g_free(acc_name);
|
||||
|
||||
if (acc) {
|
||||
object_class_foreach(accel_init_cpu_int_aux,
|
||||
CPU_RESOLVING_TYPE, false, acc);
|
||||
}
|
||||
}
|
||||
|
||||
void accel_init_interfaces(AccelClass *ac)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
accel_init_ops_interfaces(ac);
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
accel_init_cpu_interfaces(ac);
|
||||
}
|
||||
|
||||
static const TypeInfo accel_cpu_type = {
|
||||
.name = TYPE_ACCEL_CPU,
|
||||
.parent = TYPE_OBJECT,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(AccelCPUClass),
|
||||
};
|
||||
|
||||
static void register_accel_types(void)
|
||||
{
|
||||
type_register_static(&accel_type);
|
||||
type_register_static(&accel_cpu_type);
|
||||
}
|
||||
|
||||
type_init(register_accel_types);
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* QEMU System Emulator, accelerator interfaces
|
||||
* QEMU accel class, system emulation components
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2014 Red Hat Inc.
|
||||
|
@ -24,27 +24,11 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/accel.h"
|
||||
#include "qemu/accel.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qom/object.h"
|
||||
#include "sysemu/cpus.h"
|
||||
|
||||
static const TypeInfo accel_type = {
|
||||
.name = TYPE_ACCEL,
|
||||
.parent = TYPE_OBJECT,
|
||||
.class_size = sizeof(AccelClass),
|
||||
.instance_size = sizeof(AccelState),
|
||||
};
|
||||
|
||||
/* Lookup AccelClass from opt_name. Returns NULL if not found */
|
||||
AccelClass *accel_find(const char *opt_name)
|
||||
{
|
||||
char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
|
||||
AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name));
|
||||
g_free(class_name);
|
||||
return ac;
|
||||
}
|
||||
#include "accel-softmmu.h"
|
||||
|
||||
int accel_init_machine(AccelState *accel, MachineState *ms)
|
||||
{
|
||||
|
@ -77,9 +61,40 @@ void accel_setup_post(MachineState *ms)
|
|||
}
|
||||
}
|
||||
|
||||
static void register_accel_types(void)
|
||||
/* initialize the arch-independent accel operation interfaces */
|
||||
void accel_init_ops_interfaces(AccelClass *ac)
|
||||
{
|
||||
type_register_static(&accel_type);
|
||||
const char *ac_name;
|
||||
char *ops_name;
|
||||
AccelOpsClass *ops;
|
||||
|
||||
ac_name = object_class_get_name(OBJECT_CLASS(ac));
|
||||
g_assert(ac_name != NULL);
|
||||
|
||||
ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
|
||||
ops = ACCEL_OPS_CLASS(object_class_by_name(ops_name));
|
||||
g_free(ops_name);
|
||||
|
||||
/*
|
||||
* all accelerators need to define ops, providing at least a mandatory
|
||||
* non-NULL create_vcpu_thread operation.
|
||||
*/
|
||||
g_assert(ops != NULL);
|
||||
if (ops->ops_init) {
|
||||
ops->ops_init(ops);
|
||||
}
|
||||
cpus_register_accel(ops);
|
||||
}
|
||||
|
||||
type_init(register_accel_types);
|
||||
static const TypeInfo accel_ops_type_info = {
|
||||
.name = TYPE_ACCEL_OPS,
|
||||
.parent = TYPE_OBJECT,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(AccelOpsClass),
|
||||
};
|
||||
|
||||
static void accel_softmmu_register_types(void)
|
||||
{
|
||||
type_register_static(&accel_ops_type_info);
|
||||
}
|
||||
type_init(accel_softmmu_register_types);
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* QEMU System Emulation accel internal functions
|
||||
*
|
||||
* Copyright 2021 SUSE LLC
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef ACCEL_SOFTMMU_H
|
||||
#define ACCEL_SOFTMMU_H
|
||||
|
||||
void accel_init_ops_interfaces(AccelClass *ac);
|
||||
|
||||
#endif /* ACCEL_SOFTMMU_H */
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* QEMU accel class, user-mode components
|
||||
*
|
||||
* Copyright 2021 SUSE LLC
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/accel.h"
|
||||
|
||||
AccelState *current_accel(void)
|
||||
{
|
||||
static AccelState *accel;
|
||||
|
||||
if (!accel) {
|
||||
AccelClass *ac = accel_find("tcg");
|
||||
|
||||
g_assert(ac != NULL);
|
||||
accel = ACCEL(object_new_with_class(OBJECT_CLASS(ac)));
|
||||
}
|
||||
return accel;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Dummy cpu thread code
|
||||
*
|
||||
* Copyright IBM, Corp. 2011
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "hw/core/cpu.h"
|
||||
|
||||
static void *dummy_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
sigset_t waitset;
|
||||
int r;
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->can_do_io = 1;
|
||||
current_cpu = cpu;
|
||||
|
||||
sigemptyset(&waitset);
|
||||
sigaddset(&waitset, SIG_IPI);
|
||||
|
||||
/* signal CPU creation */
|
||||
cpu_thread_signal_created(cpu);
|
||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||
|
||||
do {
|
||||
qemu_mutex_unlock_iothread();
|
||||
do {
|
||||
int sig;
|
||||
r = sigwait(&waitset, &sig);
|
||||
} while (r == -1 && (errno == EAGAIN || errno == EINTR));
|
||||
if (r == -1) {
|
||||
perror("sigwait");
|
||||
exit(1);
|
||||
}
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_wait_io_event(cpu);
|
||||
} while (!cpu->unplug);
|
||||
|
||||
qemu_mutex_unlock_iothread();
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dummy_start_vcpu_thread(CPUState *cpu)
|
||||
{
|
||||
char thread_name[VCPU_THREAD_NAME_SIZE];
|
||||
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/DUMMY",
|
||||
cpu->cpu_index);
|
||||
qemu_thread_create(cpu->thread, thread_name, dummy_cpu_thread_fn, cpu,
|
||||
QEMU_THREAD_JOINABLE);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.hypervisor</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,2 +0,0 @@
|
|||
obj-y += kvm-all.o
|
||||
obj-$(call lnot,$(CONFIG_SEV)) += sev-stub.o
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* QEMU KVM support
|
||||
*
|
||||
* Copyright IBM, Corp. 2008
|
||||
* Red Hat, Inc. 2008
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
* Glauber Costa <gcosta@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "sysemu/kvm_int.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include "kvm-cpus.h"
|
||||
|
||||
static void *kvm_vcpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
int r;
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->can_do_io = 1;
|
||||
current_cpu = cpu;
|
||||
|
||||
r = kvm_init_vcpu(cpu, &error_fatal);
|
||||
kvm_init_cpu_signals(cpu);
|
||||
|
||||
/* signal CPU creation */
|
||||
cpu_thread_signal_created(cpu);
|
||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||
|
||||
do {
|
||||
if (cpu_can_run(cpu)) {
|
||||
r = kvm_cpu_exec(cpu);
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(cpu);
|
||||
}
|
||||
}
|
||||
qemu_wait_io_event(cpu);
|
||||
} while (!cpu->unplug || cpu_can_run(cpu));
|
||||
|
||||
kvm_destroy_vcpu(cpu);
|
||||
cpu_thread_signal_destroyed(cpu);
|
||||
qemu_mutex_unlock_iothread();
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void kvm_start_vcpu_thread(CPUState *cpu)
|
||||
{
|
||||
char thread_name[VCPU_THREAD_NAME_SIZE];
|
||||
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/KVM",
|
||||
cpu->cpu_index);
|
||||
qemu_thread_create(cpu->thread, thread_name, kvm_vcpu_thread_fn,
|
||||
cpu, QEMU_THREAD_JOINABLE);
|
||||
}
|
||||
|
||||
static void kvm_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||
|
||||
ops->create_vcpu_thread = kvm_start_vcpu_thread;
|
||||
ops->synchronize_post_reset = kvm_cpu_synchronize_post_reset;
|
||||
ops->synchronize_post_init = kvm_cpu_synchronize_post_init;
|
||||
ops->synchronize_state = kvm_cpu_synchronize_state;
|
||||
ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_accel_ops_type = {
|
||||
.name = ACCEL_OPS_NAME("kvm"),
|
||||
|
||||
.parent = TYPE_ACCEL_OPS,
|
||||
.class_init = kvm_accel_ops_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void kvm_accel_ops_register_types(void)
|
||||
{
|
||||
type_register_static(&kvm_accel_ops_type);
|
||||
}
|
||||
type_init(kvm_accel_ops_register_types);
|
|
@ -39,11 +39,13 @@
|
|||
#include "qemu/main-loop.h"
|
||||
#include "trace.h"
|
||||
#include "hw/irq.h"
|
||||
#include "sysemu/sev.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi/qapi-types-common.h"
|
||||
#include "qapi/qapi-visit-common.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "kvm-cpus.h"
|
||||
|
||||
#include "hw/boards.h"
|
||||
|
||||
|
@ -55,6 +57,9 @@
|
|||
/* KVM uses PAGE_SIZE in its definition of KVM_COALESCED_MMIO_MAX. We
|
||||
* need to use the real host PAGE_SIZE, as that's what KVM will use.
|
||||
*/
|
||||
#ifdef PAGE_SIZE
|
||||
#undef PAGE_SIZE
|
||||
#endif
|
||||
#define PAGE_SIZE qemu_real_host_page_size
|
||||
|
||||
//#define DEBUG_KVM
|
||||
|
@ -117,10 +122,6 @@ struct KVMState
|
|||
KVMMemoryListener memory_listener;
|
||||
QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus;
|
||||
|
||||
/* memory encryption */
|
||||
void *memcrypt_handle;
|
||||
int (*memcrypt_encrypt_data)(void *handle, uint8_t *ptr, uint64_t len);
|
||||
|
||||
/* For "info mtree -f" to tell if an MR is registered in KVM */
|
||||
int nr_as;
|
||||
struct KVMAs {
|
||||
|
@ -219,26 +220,6 @@ int kvm_get_max_memslots(void)
|
|||
return s->nr_slots;
|
||||
}
|
||||
|
||||
bool kvm_memcrypt_enabled(void)
|
||||
{
|
||||
if (kvm_state && kvm_state->memcrypt_handle) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
|
||||
{
|
||||
if (kvm_state->memcrypt_handle &&
|
||||
kvm_state->memcrypt_encrypt_data) {
|
||||
return kvm_state->memcrypt_encrypt_data(kvm_state->memcrypt_handle,
|
||||
ptr, len);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Called with KVMMemoryListener.slots_lock held */
|
||||
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
|
||||
{
|
||||
|
@ -378,7 +359,7 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int kvm_destroy_vcpu(CPUState *cpu)
|
||||
static int do_kvm_destroy_vcpu(CPUState *cpu)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
long mmap_size;
|
||||
|
@ -412,6 +393,14 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void kvm_destroy_vcpu(CPUState *cpu)
|
||||
{
|
||||
if (do_kvm_destroy_vcpu(cpu) < 0) {
|
||||
error_report("kvm_destroy_vcpu failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
|
||||
{
|
||||
struct KVMParkedVcpu *cpu;
|
||||
|
@ -430,17 +419,18 @@ static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
|
|||
return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
|
||||
}
|
||||
|
||||
int kvm_init_vcpu(CPUState *cpu)
|
||||
int kvm_init_vcpu(CPUState *cpu, Error **errp)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
long mmap_size;
|
||||
int ret;
|
||||
|
||||
DPRINTF("kvm_init_vcpu\n");
|
||||
trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
|
||||
|
||||
ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu));
|
||||
if (ret < 0) {
|
||||
DPRINTF("kvm_create_vcpu failed\n");
|
||||
error_setg_errno(errp, -ret, "kvm_init_vcpu: kvm_get_vcpu failed (%lu)",
|
||||
kvm_arch_vcpu_id(cpu));
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -451,7 +441,8 @@ int kvm_init_vcpu(CPUState *cpu)
|
|||
mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
|
||||
if (mmap_size < 0) {
|
||||
ret = mmap_size;
|
||||
DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n");
|
||||
error_setg_errno(errp, -mmap_size,
|
||||
"kvm_init_vcpu: KVM_GET_VCPU_MMAP_SIZE failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -459,7 +450,9 @@ int kvm_init_vcpu(CPUState *cpu)
|
|||
cpu->kvm_fd, 0);
|
||||
if (cpu->kvm_run == MAP_FAILED) {
|
||||
ret = -errno;
|
||||
DPRINTF("mmap'ing vcpu state failed\n");
|
||||
error_setg_errno(errp, ret,
|
||||
"kvm_init_vcpu: mmap'ing vcpu state failed (%lu)",
|
||||
kvm_arch_vcpu_id(cpu));
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -469,6 +462,11 @@ int kvm_init_vcpu(CPUState *cpu)
|
|||
}
|
||||
|
||||
ret = kvm_arch_init_vcpu(cpu);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret,
|
||||
"kvm_init_vcpu: kvm_arch_init_vcpu failed (%lu)",
|
||||
kvm_arch_vcpu_id(cpu));
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
@ -600,8 +598,12 @@ static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem)
|
|||
* too, in most cases).
|
||||
* So for now, let's align to 64 instead of HOST_LONG_BITS here, in
|
||||
* a hope that sizeof(long) won't become >8 any time soon.
|
||||
*
|
||||
* Note: the granule of kvm dirty log is qemu_real_host_page_size.
|
||||
* And mem->memory_size is aligned to it (otherwise this mem can't
|
||||
* be registered to KVM).
|
||||
*/
|
||||
hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
|
||||
hwaddr bitmap_size = ALIGN(mem->memory_size / qemu_real_host_page_size,
|
||||
/*HOST_LONG_BITS*/ 64) / 8;
|
||||
mem->dirty_bmap = g_malloc0(bitmap_size);
|
||||
}
|
||||
|
@ -645,16 +647,19 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml,
|
|||
|
||||
d.dirty_bitmap = mem->dirty_bmap;
|
||||
d.slot = mem->slot | (kml->as_id << 16);
|
||||
if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
|
||||
DPRINTF("ioctl failed %d\n", errno);
|
||||
ret = -1;
|
||||
ret = kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d);
|
||||
if (ret == -ENOENT) {
|
||||
/* kernel does not have dirty bitmap in this slot */
|
||||
ret = 0;
|
||||
} else if (ret < 0) {
|
||||
error_report("ioctl KVM_GET_DIRTY_LOG failed: %d", errno);
|
||||
goto out;
|
||||
} else {
|
||||
subsection.offset_within_region += slot_offset;
|
||||
subsection.size = int128_make64(slot_size);
|
||||
kvm_get_dirty_pages_log_range(&subsection, d.dirty_bitmap);
|
||||
}
|
||||
|
||||
subsection.offset_within_region += slot_offset;
|
||||
subsection.size = int128_make64(slot_size);
|
||||
kvm_get_dirty_pages_log_range(&subsection, d.dirty_bitmap);
|
||||
|
||||
slot_offset += slot_size;
|
||||
start_addr += slot_size;
|
||||
size -= slot_size;
|
||||
|
@ -725,7 +730,7 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
|
|||
assert(bmap_start % BITS_PER_LONG == 0);
|
||||
/* We should never do log_clear before log_sync */
|
||||
assert(mem->dirty_bmap);
|
||||
if (start_delta) {
|
||||
if (start_delta || bmap_npages - size / psize) {
|
||||
/* Slow path - we need to manipulate a temp bitmap */
|
||||
bmap_clear = bitmap_new(bmap_npages);
|
||||
bitmap_copy_with_src_offset(bmap_clear, mem->dirty_bmap,
|
||||
|
@ -738,7 +743,10 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
|
|||
bitmap_clear(bmap_clear, 0, start_delta);
|
||||
d.dirty_bitmap = bmap_clear;
|
||||
} else {
|
||||
/* Fast path - start address aligns well with BITS_PER_LONG */
|
||||
/*
|
||||
* Fast path - both start and size align well with BITS_PER_LONG
|
||||
* (or the end of memory slot)
|
||||
*/
|
||||
d.dirty_bitmap = mem->dirty_bmap + BIT_WORD(bmap_start);
|
||||
}
|
||||
|
||||
|
@ -748,8 +756,8 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
|
|||
d.num_pages = bmap_npages;
|
||||
d.slot = mem->slot | (as_id << 16);
|
||||
|
||||
if (kvm_vm_ioctl(s, KVM_CLEAR_DIRTY_LOG, &d) == -1) {
|
||||
ret = -errno;
|
||||
ret = kvm_vm_ioctl(s, KVM_CLEAR_DIRTY_LOG, &d);
|
||||
if (ret < 0 && ret != -ENOENT) {
|
||||
error_report("%s: KVM_CLEAR_DIRTY_LOG failed, slot=%d, "
|
||||
"start=0x%"PRIx64", size=0x%"PRIx32", errno=%d",
|
||||
__func__, d.slot, (uint64_t)d.first_page,
|
||||
|
@ -1993,7 +2001,6 @@ static int kvm_init(MachineState *ms)
|
|||
const KVMCapabilityInfo *missing_cap;
|
||||
int ret;
|
||||
int type = 0;
|
||||
const char *kvm_type;
|
||||
uint64_t dirty_log_manual_caps;
|
||||
|
||||
s = KVM_STATE(ms->accelerator);
|
||||
|
@ -2013,7 +2020,7 @@ static int kvm_init(MachineState *ms)
|
|||
#endif
|
||||
QLIST_INIT(&s->kvm_parked_vcpus);
|
||||
s->vmfd = -1;
|
||||
s->fd = qemu_open("/dev/kvm", O_RDWR);
|
||||
s->fd = qemu_open_old("/dev/kvm", O_RDWR);
|
||||
if (s->fd == -1) {
|
||||
fprintf(stderr, "Could not access KVM kernel module: %m\n");
|
||||
ret = -errno;
|
||||
|
@ -2049,13 +2056,13 @@ static int kvm_init(MachineState *ms)
|
|||
}
|
||||
s->as = g_new0(struct KVMAs, s->nr_as);
|
||||
|
||||
kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type");
|
||||
if (mc->kvm_type) {
|
||||
if (object_property_find(OBJECT(current_machine), "kvm-type")) {
|
||||
g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
|
||||
"kvm-type",
|
||||
&error_abort);
|
||||
type = mc->kvm_type(ms, kvm_type);
|
||||
} else if (kvm_type) {
|
||||
ret = -EINVAL;
|
||||
fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type);
|
||||
goto err;
|
||||
} else if (mc->kvm_type) {
|
||||
type = mc->kvm_type(ms, NULL);
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -2181,20 +2188,6 @@ static int kvm_init(MachineState *ms)
|
|||
|
||||
kvm_state = s;
|
||||
|
||||
/*
|
||||
* if memory encryption object is specified then initialize the memory
|
||||
* encryption context.
|
||||
*/
|
||||
if (ms->memory_encryption) {
|
||||
kvm_state->memcrypt_handle = sev_guest_init(ms->memory_encryption);
|
||||
if (!kvm_state->memcrypt_handle) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
|
||||
}
|
||||
|
||||
ret = kvm_arch_init(ms, s);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
|
@ -2219,8 +2212,10 @@ static int kvm_init(MachineState *ms)
|
|||
|
||||
kvm_memory_listener_register(s, &s->memory_listener,
|
||||
&address_space_memory, 0);
|
||||
memory_listener_register(&kvm_io_listener,
|
||||
&address_space_io);
|
||||
if (kvm_eventfds_allowed) {
|
||||
memory_listener_register(&kvm_io_listener,
|
||||
&address_space_io);
|
||||
}
|
||||
memory_listener_register(&kvm_coalesced_pio_listener,
|
||||
&address_space_io);
|
||||
|
||||
|
@ -2231,7 +2226,6 @@ static int kvm_init(MachineState *ms)
|
|||
ret = ram_block_discard_disable(true);
|
||||
assert(!ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -2324,6 +2318,11 @@ void kvm_flush_coalesced_mmio_buffer(void)
|
|||
s->coalesced_flush_in_progress = false;
|
||||
}
|
||||
|
||||
bool kvm_cpu_check_are_resettable(void)
|
||||
{
|
||||
return kvm_arch_cpu_check_are_resettable();
|
||||
}
|
||||
|
||||
static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
||||
{
|
||||
if (!cpu->vcpu_dirty) {
|
||||
|
@ -2379,7 +2378,7 @@ static __thread bool have_sigbus_pending;
|
|||
|
||||
static void kvm_cpu_kick(CPUState *cpu)
|
||||
{
|
||||
atomic_set(&cpu->kvm_run->immediate_exit, 1);
|
||||
qatomic_set(&cpu->kvm_run->immediate_exit, 1);
|
||||
}
|
||||
|
||||
static void kvm_cpu_kick_self(void)
|
||||
|
@ -2400,7 +2399,7 @@ static void kvm_eat_signals(CPUState *cpu)
|
|||
int r;
|
||||
|
||||
if (kvm_immediate_exit) {
|
||||
atomic_set(&cpu->kvm_run->immediate_exit, 0);
|
||||
qatomic_set(&cpu->kvm_run->immediate_exit, 0);
|
||||
/* Write kvm_run->immediate_exit before the cpu->exit_request
|
||||
* write in kvm_cpu_exec.
|
||||
*/
|
||||
|
@ -2434,7 +2433,7 @@ int kvm_cpu_exec(CPUState *cpu)
|
|||
DPRINTF("kvm_cpu_exec()\n");
|
||||
|
||||
if (kvm_arch_process_async_events(cpu)) {
|
||||
atomic_set(&cpu->exit_request, 0);
|
||||
qatomic_set(&cpu->exit_request, 0);
|
||||
return EXCP_HLT;
|
||||
}
|
||||
|
||||
|
@ -2450,7 +2449,7 @@ int kvm_cpu_exec(CPUState *cpu)
|
|||
}
|
||||
|
||||
kvm_arch_pre_run(cpu, run);
|
||||
if (atomic_read(&cpu->exit_request)) {
|
||||
if (qatomic_read(&cpu->exit_request)) {
|
||||
DPRINTF("interrupt exit requested\n");
|
||||
/*
|
||||
* KVM requires us to reenter the kernel after IO exits to complete
|
||||
|
@ -2577,7 +2576,7 @@ int kvm_cpu_exec(CPUState *cpu)
|
|||
vm_stop(RUN_STATE_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
atomic_set(&cpu->exit_request, 0);
|
||||
qatomic_set(&cpu->exit_request, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2994,7 +2993,7 @@ int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
|
|||
have_sigbus_pending = true;
|
||||
pending_sigbus_addr = addr;
|
||||
pending_sigbus_code = code;
|
||||
atomic_set(&cpu->exit_request, 1);
|
||||
qatomic_set(&cpu->exit_request, 1);
|
||||
return 0;
|
||||
#else
|
||||
return 1;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Accelerator CPUS Interface
|
||||
*
|
||||
* Copyright 2020 SUSE LLC
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef KVM_CPUS_H
|
||||
#define KVM_CPUS_H
|
||||
|
||||
#include "sysemu/cpus.h"
|
||||
|
||||
int kvm_init_vcpu(CPUState *cpu, Error **errp);
|
||||
int kvm_cpu_exec(CPUState *cpu);
|
||||
void kvm_destroy_vcpu(CPUState *cpu);
|
||||
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
|
||||
void kvm_cpu_synchronize_post_init(CPUState *cpu);
|
||||
void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu);
|
||||
|
||||
#endif /* KVM_CPUS_H */
|
|
@ -0,0 +1,8 @@
|
|||
kvm_ss = ss.source_set()
|
||||
kvm_ss.add(files(
|
||||
'kvm-all.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)
|
|
@ -15,12 +15,8 @@
|
|||
#include "qemu-common.h"
|
||||
#include "sysemu/sev.h"
|
||||
|
||||
int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
|
||||
int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
void *sev_guest_init(const char *id)
|
||||
{
|
||||
return NULL;
|
||||
/* If we get here, cgs must be some non-SEV thing */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d"
|
|||
kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p"
|
||||
kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s"
|
||||
kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s"
|
||||
kvm_init_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
|
||||
kvm_irqchip_commit_routes(void) ""
|
||||
kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d"
|
||||
kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include "trace/trace-accel_kvm.h"
|
|
@ -0,0 +1,17 @@
|
|||
specific_ss.add(files('accel-common.c'))
|
||||
softmmu_ss.add(files('accel-softmmu.c'))
|
||||
user_ss.add(files('accel-user.c'))
|
||||
|
||||
subdir('qtest')
|
||||
subdir('kvm')
|
||||
subdir('tcg')
|
||||
subdir('xen')
|
||||
subdir('stubs')
|
||||
|
||||
dummy_ss = ss.source_set()
|
||||
dummy_ss.add(files(
|
||||
'dummy-cpus.c',
|
||||
))
|
||||
|
||||
specific_ss.add_all(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'], if_true: dummy_ss)
|
||||
specific_ss.add_all(when: ['CONFIG_XEN'], if_true: dummy_ss)
|
|
@ -0,0 +1,6 @@
|
|||
qtest_ss = ss.source_set()
|
||||
qtest_ss.add(files(
|
||||
'qtest.c',
|
||||
))
|
||||
|
||||
specific_ss.add_all(when: ['CONFIG_SOFTMMU', 'CONFIG_POSIX'], if_true: qtest_ss)
|
|
@ -12,21 +12,21 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "sysemu/accel.h"
|
||||
#include "qemu/accel.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "hw/core/cpu.h"
|
||||
|
||||
static int qtest_init_accel(MachineState *ms)
|
||||
{
|
||||
QemuOpts *opts = qemu_opts_create(qemu_find_opts("icount"), NULL, 0,
|
||||
&error_abort);
|
||||
qemu_opt_set(opts, "shift", "0", &error_abort);
|
||||
configure_icount(opts, &error_abort);
|
||||
qemu_opts_del(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -46,9 +46,26 @@ static const TypeInfo qtest_accel_type = {
|
|||
.class_init = qtest_accel_class_init,
|
||||
};
|
||||
|
||||
static void qtest_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||
|
||||
ops->create_vcpu_thread = dummy_start_vcpu_thread;
|
||||
ops->get_virtual_clock = qtest_get_virtual_clock;
|
||||
};
|
||||
|
||||
static const TypeInfo qtest_accel_ops_type = {
|
||||
.name = ACCEL_OPS_NAME("qtest"),
|
||||
|
||||
.parent = TYPE_ACCEL_OPS,
|
||||
.class_init = qtest_accel_ops_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void qtest_type_init(void)
|
||||
{
|
||||
type_register_static(&qtest_accel_type);
|
||||
type_register_static(&qtest_accel_ops_type);
|
||||
}
|
||||
|
||||
type_init(qtest_type_init);
|
|
@ -1,6 +0,0 @@
|
|||
obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o
|
||||
obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o
|
||||
obj-$(call lnot,$(CONFIG_WHPX)) += whpx-stub.o
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||
obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
|
||||
obj-$(call lnot,$(CONFIG_XEN)) += xen-stub.o
|
|
@ -14,20 +14,9 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/hax.h"
|
||||
|
||||
int hax_sync_vcpus(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hax_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int hax_smp_cpu_exec(CPUState *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* QEMU HVF support
|
||||
*
|
||||
* Copyright 2017 Red Hat, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2 or later, as published by the Free Software Foundation,
|
||||
* and may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/hvf.h"
|
||||
|
||||
int hvf_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int hvf_vcpu_exec(CPUState *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
void hvf_vcpu_destroy(CPUState *cpu)
|
||||
{
|
||||
}
|
|
@ -32,16 +32,6 @@ bool kvm_readonly_mem_allowed;
|
|||
bool kvm_ioeventfd_any_length_allowed;
|
||||
bool kvm_msi_use_devid;
|
||||
|
||||
int kvm_destroy_vcpu(CPUState *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
void kvm_flush_coalesced_mmio_buffer(void)
|
||||
{
|
||||
}
|
||||
|
@ -50,19 +40,6 @@ void kvm_cpu_synchronize_state(CPUState *cpu)
|
|||
{
|
||||
}
|
||||
|
||||
void kvm_cpu_synchronize_post_reset(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void kvm_cpu_synchronize_post_init(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
int kvm_cpu_exec(CPUState *cpu)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
bool kvm_has_sync_mmu(void)
|
||||
{
|
||||
return false;
|
||||
|
@ -104,16 +81,6 @@ int kvm_on_sigbus(int code, void *addr)
|
|||
return 1;
|
||||
}
|
||||
|
||||
bool kvm_memcrypt_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
specific_ss.add(when: 'CONFIG_HAX', if_false: files('hax-stub.c'))
|
||||
specific_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c'))
|
||||
specific_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
|
||||
specific_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c'))
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
void tb_flush(CPUState *cpu)
|
||||
|
@ -29,3 +28,13 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
|||
/* Handled by hardware accelerator. */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
void QEMU_NORETURN cpu_loop_exit(CPUState *cpu)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* QEMU Windows Hypervisor Platform accelerator (WHPX) stub
|
||||
*
|
||||
* Copyright Microsoft Corp. 2017
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/whpx.h"
|
||||
|
||||
int whpx_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int whpx_vcpu_exec(CPUState *cpu)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void whpx_destroy_vcpu(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_vcpu_kick(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_cpu_synchronize_state(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_cpu_synchronize_post_reset(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_cpu_synchronize_post_init(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
|
||||
{
|
||||
}
|
|
@ -6,50 +6,11 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "sysemu/xen.h"
|
||||
#include "qapi/qapi-commands-migration.h"
|
||||
|
||||
bool xen_allowed;
|
||||
|
||||
void xenstore_store_pv_console_info(int i, Chardev *chr)
|
||||
{
|
||||
}
|
||||
|
||||
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void xen_piix3_set_irq(void *opaque, int irq_num, int level)
|
||||
{
|
||||
}
|
||||
|
||||
void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
}
|
||||
|
||||
void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
|
||||
{
|
||||
}
|
||||
|
||||
int xen_is_pirq_msi(uint32_t msi_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
qemu_irq *xen_interrupt_controller_init(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xen_register_framebuffer(MemoryRegion *mr)
|
||||
{
|
||||
}
|
||||
|
||||
void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
|
||||
{
|
||||
}
|
||||
|
||||
void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
obj-$(CONFIG_SOFTMMU) += tcg-all.o
|
||||
obj-$(CONFIG_SOFTMMU) += cputlb.o
|
||||
obj-y += tcg-runtime.o tcg-runtime-gvec.o
|
||||
obj-y += cpu-exec.o cpu-exec-common.o translate-all.o
|
||||
obj-y += translator.o
|
||||
|
||||
obj-$(CONFIG_USER_ONLY) += user-exec.o
|
||||
obj-$(call lnot,$(CONFIG_SOFTMMU)) += user-exec-stub.o
|
||||
obj-$(CONFIG_PLUGIN) += plugin-gen.o
|
|
@ -83,7 +83,7 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
|||
#if DATA_SIZE == 16
|
||||
ret = atomic16_cmpxchg(haddr, cmpv, newv);
|
||||
#else
|
||||
ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
|
||||
ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
|
||||
#endif
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
|
@ -131,7 +131,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
|||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
ret = atomic_xchg__nocheck(haddr, val);
|
||||
ret = qatomic_xchg__nocheck(haddr, val);
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return ret;
|
||||
|
@ -147,7 +147,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
|||
uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \
|
||||
ATOMIC_MMU_IDX); \
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
ret = atomic_##X(haddr, val); \
|
||||
ret = qatomic_##X(haddr, val); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return ret; \
|
||||
|
@ -182,10 +182,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
|||
ATOMIC_MMU_IDX); \
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
smp_mb(); \
|
||||
cmp = atomic_read__nocheck(haddr); \
|
||||
cmp = qatomic_read__nocheck(haddr); \
|
||||
do { \
|
||||
old = cmp; new = FN(old, val); \
|
||||
cmp = atomic_cmpxchg__nocheck(haddr, old, new); \
|
||||
cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \
|
||||
} while (cmp != old); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
|
@ -230,7 +230,7 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
|
|||
#if DATA_SIZE == 16
|
||||
ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||
#else
|
||||
ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||
ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
|
||||
#endif
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
|
@ -280,7 +280,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
|
|||
ATOMIC_MMU_IDX);
|
||||
|
||||
atomic_trace_rmw_pre(env, addr, info);
|
||||
ret = atomic_xchg__nocheck(haddr, BSWAP(val));
|
||||
ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
|
||||
ATOMIC_MMU_CLEANUP;
|
||||
atomic_trace_rmw_post(env, addr, info);
|
||||
return BSWAP(ret);
|
||||
|
@ -296,7 +296,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
|||
uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \
|
||||
false, ATOMIC_MMU_IDX); \
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
ret = atomic_##X(haddr, BSWAP(val)); \
|
||||
ret = qatomic_##X(haddr, BSWAP(val)); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
return BSWAP(ret); \
|
||||
|
@ -329,10 +329,10 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
|
|||
false, ATOMIC_MMU_IDX); \
|
||||
atomic_trace_rmw_pre(env, addr, info); \
|
||||
smp_mb(); \
|
||||
ldn = atomic_read__nocheck(haddr); \
|
||||
ldn = qatomic_read__nocheck(haddr); \
|
||||
do { \
|
||||
ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \
|
||||
ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
|
||||
ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
|
||||
} while (ldo != ldn); \
|
||||
ATOMIC_MMU_CLEANUP; \
|
||||
atomic_trace_rmw_post(env, addr, info); \
|
||||
|
|
|
@ -19,13 +19,15 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
#include "trace.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "qemu/compiler.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "exec/tb-hash.h"
|
||||
|
@ -36,7 +38,10 @@
|
|||
#include "hw/i386/apic.h"
|
||||
#endif
|
||||
#include "sysemu/cpus.h"
|
||||
#include "exec/cpu-all.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* -icount align implementation. */
|
||||
|
||||
|
@ -56,6 +61,9 @@ typedef struct SyncClocks {
|
|||
#define MAX_DELAY_PRINT_RATE 2000000000LL
|
||||
#define MAX_NB_PRINTS 100
|
||||
|
||||
static int64_t max_delay;
|
||||
static int64_t max_advance;
|
||||
|
||||
static void align_clocks(SyncClocks *sc, CPUState *cpu)
|
||||
{
|
||||
int64_t cpu_icount;
|
||||
|
@ -65,7 +73,7 @@ static void align_clocks(SyncClocks *sc, CPUState *cpu)
|
|||
}
|
||||
|
||||
cpu_icount = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low;
|
||||
sc->diff_clk += cpu_icount_to_ns(sc->last_cpu_icount - cpu_icount);
|
||||
sc->diff_clk += icount_to_ns(sc->last_cpu_icount - cpu_icount);
|
||||
sc->last_cpu_icount = cpu_icount;
|
||||
|
||||
if (sc->diff_clk > VM_CLOCK_ADVANCE) {
|
||||
|
@ -98,9 +106,9 @@ static void print_delay(const SyncClocks *sc)
|
|||
(-sc->diff_clk / (float)1000000000LL <
|
||||
(threshold_delay - THRESHOLD_REDUCE))) {
|
||||
threshold_delay = (-sc->diff_clk / 1000000000LL) + 1;
|
||||
printf("Warning: The guest is now late by %.1f to %.1f seconds\n",
|
||||
threshold_delay - 1,
|
||||
threshold_delay);
|
||||
qemu_printf("Warning: The guest is now late by %.1f to %.1f seconds\n",
|
||||
threshold_delay - 1,
|
||||
threshold_delay);
|
||||
nb_prints++;
|
||||
last_realtime_clock = sc->realtime_clock;
|
||||
}
|
||||
|
@ -138,13 +146,22 @@ static void init_delay_params(SyncClocks *sc, const CPUState *cpu)
|
|||
#endif /* CONFIG USER ONLY */
|
||||
|
||||
/* Execute a TB, and fix up the CPU state afterwards if necessary */
|
||||
static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
/*
|
||||
* Disable CFI checks.
|
||||
* TCG creates binary blobs at runtime, with the transformed code.
|
||||
* A TB is a blob of binary code, created at runtime and called with an
|
||||
* indirect function call. Since such function did not exist at compile time,
|
||||
* the CFI runtime has no way to verify its signature and would fail.
|
||||
* TCG is not considered a security-sensitive part of QEMU so this does not
|
||||
* affect the impact of CFI in environment with high security requirements
|
||||
*/
|
||||
static inline TranslationBlock * QEMU_DISABLE_CFI
|
||||
cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
uintptr_t ret;
|
||||
TranslationBlock *last_tb;
|
||||
int tb_exit;
|
||||
uint8_t *tb_ptr = itb->tc.ptr;
|
||||
const void *tb_ptr = itb->tc.ptr;
|
||||
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc,
|
||||
"Trace %d: %p ["
|
||||
|
@ -169,13 +186,23 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
|||
}
|
||||
#endif /* DEBUG_DISAS */
|
||||
|
||||
qemu_thread_jit_execute();
|
||||
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
||||
cpu->can_do_io = 1;
|
||||
last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
||||
tb_exit = ret & TB_EXIT_MASK;
|
||||
trace_exec_tb_exit(last_tb, tb_exit);
|
||||
/*
|
||||
* TODO: Delay swapping back to the read-write region of the TB
|
||||
* until we actually need to modify the TB. The read-only copy,
|
||||
* coming from the rx region, shares the same host TLB entry as
|
||||
* the code that executed the exit_tb opcode that arrived here.
|
||||
* If we insist on touching both the RX and the RW pages, we
|
||||
* double the host TLB pressure.
|
||||
*/
|
||||
last_tb = tcg_splitwx_to_rw((void *)(ret & ~TB_EXIT_MASK));
|
||||
*tb_exit = ret & TB_EXIT_MASK;
|
||||
|
||||
if (tb_exit > TB_EXIT_IDX1) {
|
||||
trace_exec_tb_exit(last_tb, *tb_exit);
|
||||
|
||||
if (*tb_exit > TB_EXIT_IDX1) {
|
||||
/* We didn't start executing this TB (eg because the instruction
|
||||
* counter hit zero); we must restore the guest PC to the address
|
||||
* of the start of the TB.
|
||||
|
@ -186,76 +213,64 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
|||
TARGET_FMT_lx "] %s\n",
|
||||
last_tb->tc.ptr, last_tb->pc,
|
||||
lookup_symbol(last_tb->pc));
|
||||
if (cc->synchronize_from_tb) {
|
||||
cc->synchronize_from_tb(cpu, last_tb);
|
||||
if (cc->tcg_ops->synchronize_from_tb) {
|
||||
cc->tcg_ops->synchronize_from_tb(cpu, last_tb);
|
||||
} else {
|
||||
assert(cc->set_pc);
|
||||
cc->set_pc(cpu, last_tb->pc);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return last_tb;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Execute the code without caching the generated code. An interpreter
|
||||
could be used if available. */
|
||||
static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
|
||||
TranslationBlock *orig_tb, bool ignore_icount)
|
||||
|
||||
static void cpu_exec_enter(CPUState *cpu)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
uint32_t cflags = curr_cflags() | CF_NOCACHE;
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (ignore_icount) {
|
||||
cflags &= ~CF_USE_ICOUNT;
|
||||
if (cc->tcg_ops->cpu_exec_enter) {
|
||||
cc->tcg_ops->cpu_exec_enter(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_exec_exit(CPUState *cpu)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (cc->tcg_ops->cpu_exec_exit) {
|
||||
cc->tcg_ops->cpu_exec_exit(cpu);
|
||||
}
|
||||
|
||||
/* Should never happen.
|
||||
We only end up here when an existing TB is too long. */
|
||||
cflags |= MIN(max_cycles, CF_COUNT_MASK);
|
||||
|
||||
mmap_lock();
|
||||
tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base,
|
||||
orig_tb->flags, cflags);
|
||||
tb->orig_tb = orig_tb;
|
||||
mmap_unlock();
|
||||
|
||||
/* execute the generated code */
|
||||
trace_exec_tb_nocache(tb, tb->pc);
|
||||
cpu_tb_exec(cpu, tb);
|
||||
|
||||
mmap_lock();
|
||||
tb_phys_invalidate(tb, -1);
|
||||
mmap_unlock();
|
||||
tcg_tb_remove(tb);
|
||||
}
|
||||
#endif
|
||||
|
||||
void cpu_exec_step_atomic(CPUState *cpu)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags;
|
||||
uint32_t cflags = 1;
|
||||
uint32_t cf_mask = cflags & CF_HASH_MASK;
|
||||
uint32_t cflags = (curr_cflags(cpu) & ~CF_PARALLEL) | 1;
|
||||
int tb_exit;
|
||||
|
||||
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
||||
start_exclusive();
|
||||
g_assert(cpu == current_cpu);
|
||||
g_assert(!cpu->running);
|
||||
cpu->running = true;
|
||||
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
|
||||
tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask);
|
||||
if (tb == NULL) {
|
||||
mmap_lock();
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
||||
mmap_unlock();
|
||||
}
|
||||
|
||||
/* Since we got here, we know that parallel_cpus must be true. */
|
||||
parallel_cpus = false;
|
||||
cc->cpu_exec_enter(cpu);
|
||||
cpu_exec_enter(cpu);
|
||||
/* execute the generated code */
|
||||
trace_exec_tb(tb, pc);
|
||||
cpu_tb_exec(cpu, tb);
|
||||
cc->cpu_exec_exit(cpu);
|
||||
cpu_tb_exec(cpu, tb, &tb_exit);
|
||||
cpu_exec_exit(cpu);
|
||||
} else {
|
||||
/*
|
||||
* The mmap_lock is dropped by tb_gen_code if it runs out of
|
||||
|
@ -278,7 +293,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
|||
* the execution.
|
||||
*/
|
||||
g_assert(cpu_in_exclusive_context(cpu));
|
||||
parallel_cpus = true;
|
||||
cpu->running = false;
|
||||
end_exclusive();
|
||||
}
|
||||
|
||||
|
@ -288,7 +303,7 @@ struct tb_desc {
|
|||
CPUArchState *env;
|
||||
tb_page_addr_t phys_page1;
|
||||
uint32_t flags;
|
||||
uint32_t cf_mask;
|
||||
uint32_t cflags;
|
||||
uint32_t trace_vcpu_dstate;
|
||||
};
|
||||
|
||||
|
@ -302,7 +317,7 @@ static bool tb_lookup_cmp(const void *p, const void *d)
|
|||
tb->cs_base == desc->cs_base &&
|
||||
tb->flags == desc->flags &&
|
||||
tb->trace_vcpu_dstate == desc->trace_vcpu_dstate &&
|
||||
(tb_cflags(tb) & (CF_HASH_MASK | CF_INVALID)) == desc->cf_mask) {
|
||||
tb_cflags(tb) == desc->cflags) {
|
||||
/* check next page if needed */
|
||||
if (tb->page_addr[1] == -1) {
|
||||
return true;
|
||||
|
@ -322,7 +337,7 @@ static bool tb_lookup_cmp(const void *p, const void *d)
|
|||
|
||||
TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
|
||||
target_ulong cs_base, uint32_t flags,
|
||||
uint32_t cf_mask)
|
||||
uint32_t cflags)
|
||||
{
|
||||
tb_page_addr_t phys_pc;
|
||||
struct tb_desc desc;
|
||||
|
@ -331,7 +346,7 @@ TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
|
|||
desc.env = (CPUArchState *)cpu->env_ptr;
|
||||
desc.cs_base = cs_base;
|
||||
desc.flags = flags;
|
||||
desc.cf_mask = cf_mask;
|
||||
desc.cflags = cflags;
|
||||
desc.trace_vcpu_dstate = *cpu->trace_dstate;
|
||||
desc.pc = pc;
|
||||
phys_pc = get_page_addr_code(desc.env, pc);
|
||||
|
@ -339,7 +354,7 @@ TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
|
|||
return NULL;
|
||||
}
|
||||
desc.phys_page1 = phys_pc & TARGET_PAGE_MASK;
|
||||
h = tb_hash_func(phys_pc, pc, flags, cf_mask, *cpu->trace_dstate);
|
||||
h = tb_hash_func(phys_pc, pc, flags, cflags, *cpu->trace_dstate);
|
||||
return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
|
||||
}
|
||||
|
||||
|
@ -348,7 +363,9 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr)
|
|||
if (TCG_TARGET_HAS_direct_jump) {
|
||||
uintptr_t offset = tb->jmp_target_arg[n];
|
||||
uintptr_t tc_ptr = (uintptr_t)tb->tc.ptr;
|
||||
tb_target_set_jmp_target(tc_ptr, tc_ptr + offset, addr);
|
||||
uintptr_t jmp_rx = tc_ptr + offset;
|
||||
uintptr_t jmp_rw = jmp_rx - tcg_splitwx_diff;
|
||||
tb_target_set_jmp_target(tc_ptr, jmp_rx, jmp_rw, addr);
|
||||
} else {
|
||||
tb->jmp_target_arg[n] = addr;
|
||||
}
|
||||
|
@ -359,6 +376,7 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
|||
{
|
||||
uintptr_t old;
|
||||
|
||||
qemu_thread_jit_write();
|
||||
assert(n < ARRAY_SIZE(tb->jmp_list_next));
|
||||
qemu_spin_lock(&tb_next->jmp_lock);
|
||||
|
||||
|
@ -367,7 +385,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
|||
goto out_unlock_next;
|
||||
}
|
||||
/* Atomically claim the jump destination slot only if it was NULL */
|
||||
old = atomic_cmpxchg(&tb->jmp_dest[n], (uintptr_t)NULL, (uintptr_t)tb_next);
|
||||
old = qatomic_cmpxchg(&tb->jmp_dest[n], (uintptr_t)NULL,
|
||||
(uintptr_t)tb_next);
|
||||
if (old) {
|
||||
goto out_unlock_next;
|
||||
}
|
||||
|
@ -395,19 +414,22 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
|||
|
||||
static inline TranslationBlock *tb_find(CPUState *cpu,
|
||||
TranslationBlock *last_tb,
|
||||
int tb_exit, uint32_t cf_mask)
|
||||
int tb_exit, uint32_t cflags)
|
||||
{
|
||||
CPUArchState *env = (CPUArchState *)cpu->env_ptr;
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags;
|
||||
|
||||
tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask);
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
|
||||
tb = tb_lookup(cpu, pc, cs_base, flags, cflags);
|
||||
if (tb == NULL) {
|
||||
mmap_lock();
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, cf_mask);
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, cflags);
|
||||
mmap_unlock();
|
||||
/* We add the TB in the virtual pc hash table for the fast lookup */
|
||||
atomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
|
||||
qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
|
||||
}
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* We don't take care of direct jumps when address mapping changes in
|
||||
|
@ -429,8 +451,7 @@ static inline bool cpu_handle_halt(CPUState *cpu)
|
|||
{
|
||||
if (cpu->halted) {
|
||||
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
|
||||
if ((cpu->interrupt_request & CPU_INTERRUPT_POLL)
|
||||
&& replay_interrupt()) {
|
||||
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
|
||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
apic_poll_irq(x86_cpu->apic_state);
|
||||
|
@ -459,7 +480,9 @@ static inline void cpu_handle_debug_exception(CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
cc->debug_excp_handler(cpu);
|
||||
if (cc->tcg_ops->debug_excp_handler) {
|
||||
cc->tcg_ops->debug_excp_handler(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
|
@ -468,15 +491,12 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||
#ifndef CONFIG_USER_ONLY
|
||||
if (replay_has_exception()
|
||||
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) {
|
||||
/* try to cause an exception pending in the log */
|
||||
cpu_exec_nocache(cpu, 1, tb_find(cpu, NULL, 0, curr_cflags()), true);
|
||||
/* Execute just one insn to trigger exception pending in the log */
|
||||
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT) | 1;
|
||||
}
|
||||
#endif
|
||||
if (cpu->exception_index < 0) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cpu->exception_index >= EXCP_INTERRUPT) {
|
||||
/* exit request from the cpu execution loop */
|
||||
*ret = cpu->exception_index;
|
||||
|
@ -492,7 +512,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||
loop */
|
||||
#if defined(TARGET_I386)
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
cc->do_interrupt(cpu);
|
||||
cc->tcg_ops->do_interrupt(cpu);
|
||||
#endif
|
||||
*ret = cpu->exception_index;
|
||||
cpu->exception_index = -1;
|
||||
|
@ -501,7 +521,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||
if (replay_exception()) {
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
cc->do_interrupt(cpu);
|
||||
cc->tcg_ops->do_interrupt(cpu);
|
||||
qemu_mutex_unlock_iothread();
|
||||
cpu->exception_index = -1;
|
||||
|
||||
|
@ -526,6 +546,20 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
|
||||
* "real" interrupt event later. It does not need to be recorded for
|
||||
* replay purposes.
|
||||
*/
|
||||
static inline bool need_replay_interrupt(int interrupt_request)
|
||||
{
|
||||
#if defined(TARGET_I386)
|
||||
return !(interrupt_request & CPU_INTERRUPT_POLL);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
TranslationBlock **last_tb)
|
||||
{
|
||||
|
@ -536,9 +570,9 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
* Ensure zeroing happens before reading cpu->exit_request or
|
||||
* cpu->interrupt_request (see also smp_wmb in cpu_exit())
|
||||
*/
|
||||
atomic_mb_set(&cpu_neg(cpu)->icount_decr.u16.high, 0);
|
||||
qatomic_mb_set(&cpu_neg(cpu)->icount_decr.u16.high, 0);
|
||||
|
||||
if (unlikely(atomic_read(&cpu->interrupt_request))) {
|
||||
if (unlikely(qatomic_read(&cpu->interrupt_request))) {
|
||||
int interrupt_request;
|
||||
qemu_mutex_lock_iothread();
|
||||
interrupt_request = cpu->interrupt_request;
|
||||
|
@ -586,8 +620,11 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
True when it is, and we should restart on a new TB,
|
||||
and via longjmp via cpu_loop_exit. */
|
||||
else {
|
||||
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
replay_interrupt();
|
||||
if (cc->tcg_ops->cpu_exec_interrupt &&
|
||||
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
if (need_replay_interrupt(interrupt_request)) {
|
||||
replay_interrupt();
|
||||
}
|
||||
/*
|
||||
* After processing the interrupt, ensure an EXCP_DEBUG is
|
||||
* raised when single-stepping so that GDB doesn't miss the
|
||||
|
@ -613,10 +650,11 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
}
|
||||
|
||||
/* Finally, check if we need to exit to the main loop. */
|
||||
if (unlikely(atomic_read(&cpu->exit_request))
|
||||
|| (use_icount
|
||||
if (unlikely(qatomic_read(&cpu->exit_request))
|
||||
|| (icount_enabled()
|
||||
&& (cpu->cflags_next_tb == -1 || cpu->cflags_next_tb & CF_USE_ICOUNT)
|
||||
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0)) {
|
||||
atomic_set(&cpu->exit_request, 0);
|
||||
qatomic_set(&cpu->exit_request, 0);
|
||||
if (cpu->exception_index == -1) {
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
}
|
||||
|
@ -629,20 +667,17 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
|
|||
static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
TranslationBlock **last_tb, int *tb_exit)
|
||||
{
|
||||
uintptr_t ret;
|
||||
int32_t insns_left;
|
||||
|
||||
trace_exec_tb(tb, tb->pc);
|
||||
ret = cpu_tb_exec(cpu, tb);
|
||||
tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
||||
*tb_exit = ret & TB_EXIT_MASK;
|
||||
tb = cpu_tb_exec(cpu, tb, tb_exit);
|
||||
if (*tb_exit != TB_EXIT_REQUESTED) {
|
||||
*last_tb = tb;
|
||||
return;
|
||||
}
|
||||
|
||||
*last_tb = NULL;
|
||||
insns_left = atomic_read(&cpu_neg(cpu)->icount_decr.u32);
|
||||
insns_left = qatomic_read(&cpu_neg(cpu)->icount_decr.u32);
|
||||
if (insns_left < 0) {
|
||||
/* Something asked us to stop executing chained TBs; just
|
||||
* continue round the main loop. Whatever requested the exit
|
||||
|
@ -655,21 +690,22 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
|||
}
|
||||
|
||||
/* Instruction counter expired. */
|
||||
assert(use_icount);
|
||||
assert(icount_enabled());
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Ensure global icount has gone forward */
|
||||
cpu_update_icount(cpu);
|
||||
icount_update(cpu);
|
||||
/* Refill decrementer and continue execution. */
|
||||
insns_left = MIN(0xffff, cpu->icount_budget);
|
||||
insns_left = MIN(CF_COUNT_MASK, cpu->icount_budget);
|
||||
cpu_neg(cpu)->icount_decr.u16.low = insns_left;
|
||||
cpu->icount_extra = cpu->icount_budget - insns_left;
|
||||
if (!cpu->icount_extra) {
|
||||
/* Execute any remaining instructions, then let the main loop
|
||||
* handle the next event.
|
||||
*/
|
||||
if (insns_left > 0) {
|
||||
cpu_exec_nocache(cpu, insns_left, tb, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the next tb has more instructions than we have left to
|
||||
* execute we need to ensure we find/generate a TB with exactly
|
||||
* insns_left instructions in it.
|
||||
*/
|
||||
if (!cpu->icount_extra && insns_left > 0 && insns_left < tb->icount) {
|
||||
cpu->cflags_next_tb = (tb->cflags & ~CF_COUNT_MASK) | insns_left;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -691,7 +727,7 @@ int cpu_exec(CPUState *cpu)
|
|||
|
||||
rcu_read_lock();
|
||||
|
||||
cc->cpu_exec_enter(cpu);
|
||||
cpu_exec_enter(cpu);
|
||||
|
||||
/* Calculate difference between guest clock and host clock.
|
||||
* This delay includes the delay of the last cycle, so
|
||||
|
@ -702,18 +738,31 @@ int cpu_exec(CPUState *cpu)
|
|||
|
||||
/* prepare setjmp context for exception handling */
|
||||
if (sigsetjmp(cpu->jmp_env, 0) != 0) {
|
||||
#if defined(__clang__) || !QEMU_GNUC_PREREQ(4, 6)
|
||||
/* Some compilers wrongly smash all local variables after
|
||||
* siglongjmp. There were bug reports for gcc 4.5.0 and clang.
|
||||
#if defined(__clang__)
|
||||
/*
|
||||
* Some compilers wrongly smash all local variables after
|
||||
* siglongjmp (the spec requires that only non-volatile locals
|
||||
* which are changed between the sigsetjmp and siglongjmp are
|
||||
* permitted to be trashed). There were bug reports for gcc
|
||||
* 4.5.0 and clang. The bug is fixed in all versions of gcc
|
||||
* that we support, but is still unfixed in clang:
|
||||
* https://bugs.llvm.org/show_bug.cgi?id=21183
|
||||
*
|
||||
* Reload essential local variables here for those compilers.
|
||||
* Newer versions of gcc would complain about this code (-Wclobbered). */
|
||||
* Newer versions of gcc would complain about this code (-Wclobbered),
|
||||
* so we only perform the workaround for clang.
|
||||
*/
|
||||
cpu = current_cpu;
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
#else /* buggy compiler */
|
||||
/* Assert that the compiler does not smash local variables. */
|
||||
#else
|
||||
/*
|
||||
* Non-buggy compilers preserve these locals; assert that
|
||||
* they have the correct value.
|
||||
*/
|
||||
g_assert(cpu == current_cpu);
|
||||
g_assert(cc == CPU_GET_CLASS(cpu));
|
||||
#endif /* buggy compiler */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
tcg_debug_assert(!have_mmap_lock());
|
||||
#endif
|
||||
|
@ -740,7 +789,7 @@ int cpu_exec(CPUState *cpu)
|
|||
have CF_INVALID set, -1 is a convenient invalid value that
|
||||
does not require tcg headers for cpu_common_reset. */
|
||||
if (cflags == -1) {
|
||||
cflags = curr_cflags();
|
||||
cflags = curr_cflags(cpu);
|
||||
} else {
|
||||
cpu->cflags_next_tb = -1;
|
||||
}
|
||||
|
@ -753,8 +802,59 @@ int cpu_exec(CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
cc->cpu_exec_exit(cpu);
|
||||
cpu_exec_exit(cpu);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tcg_exec_realizefn(CPUState *cpu, Error **errp)
|
||||
{
|
||||
static bool tcg_target_initialized;
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (!tcg_target_initialized) {
|
||||
cc->tcg_ops->initialize();
|
||||
tcg_target_initialized = true;
|
||||
}
|
||||
tlb_init(cpu);
|
||||
qemu_plugin_vcpu_init_hook(cpu);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_iommu_init_notifier_list(cpu);
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
}
|
||||
|
||||
/* undo the initializations in reverse order */
|
||||
void tcg_exec_unrealizefn(CPUState *cpu)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_iommu_free_notifier_list(cpu);
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
qemu_plugin_vcpu_exit_hook(cpu);
|
||||
tlb_destroy(cpu);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
void dump_drift_info(void)
|
||||
{
|
||||
if (!icount_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_printf("Host - Guest clock %"PRIi64" ms\n",
|
||||
(cpu_get_clock() - icount_get()) / SCALE_MS);
|
||||
if (icount_align_option) {
|
||||
qemu_printf("Max guest delay %"PRIi64" ms\n",
|
||||
-max_delay / SCALE_MS);
|
||||
qemu_printf("Max guest advance %"PRIi64" ms\n",
|
||||
max_advance / SCALE_MS);
|
||||
} else {
|
||||
qemu_printf("Max guest delay NA\n");
|
||||
qemu_printf("Max guest advance NA\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
|
|
@ -20,11 +20,13 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/cputlb.h"
|
||||
#include "exec/tb-hash.h"
|
||||
#include "exec/memory-internal.h"
|
||||
#include "exec/ram_addr.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
@ -33,9 +35,10 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/atomic128.h"
|
||||
#include "translate-all.h"
|
||||
#include "trace-root.h"
|
||||
#include "exec/translate-all.h"
|
||||
#include "trace/trace-root.h"
|
||||
#include "trace/mem.h"
|
||||
#include "internal.h"
|
||||
#ifdef CONFIG_PLUGIN
|
||||
#include "qemu/plugin-memory.h"
|
||||
#endif
|
||||
|
@ -97,6 +100,23 @@ static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns,
|
|||
desc->window_max_entries = max_entries;
|
||||
}
|
||||
|
||||
static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr)
|
||||
{
|
||||
unsigned int i, i0 = tb_jmp_cache_hash_page(page_addr);
|
||||
|
||||
for (i = 0; i < TB_JMP_PAGE_SIZE; i++) {
|
||||
qatomic_set(&cpu->tb_jmp_cache[i0 + i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr)
|
||||
{
|
||||
/* Discard jump cache entries for any tb which might potentially
|
||||
overlap the flushed page. */
|
||||
tb_jmp_cache_clear_page(cpu, addr - TARGET_PAGE_SIZE);
|
||||
tb_jmp_cache_clear_page(cpu, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* tlb_mmu_resize_locked() - perform TLB resize bookkeeping; resize if necessary
|
||||
* @desc: The CPUTLBDesc portion of the TLB
|
||||
|
@ -312,9 +332,9 @@ void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
|
|||
CPU_FOREACH(cpu) {
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
|
||||
full += atomic_read(&env_tlb(env)->c.full_flush_count);
|
||||
part += atomic_read(&env_tlb(env)->c.part_flush_count);
|
||||
elide += atomic_read(&env_tlb(env)->c.elide_flush_count);
|
||||
full += qatomic_read(&env_tlb(env)->c.full_flush_count);
|
||||
part += qatomic_read(&env_tlb(env)->c.part_flush_count);
|
||||
elide += qatomic_read(&env_tlb(env)->c.elide_flush_count);
|
||||
}
|
||||
*pfull = full;
|
||||
*ppart = part;
|
||||
|
@ -349,13 +369,13 @@ static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data)
|
|||
cpu_tb_jmp_cache_clear(cpu);
|
||||
|
||||
if (to_clean == ALL_MMUIDX_BITS) {
|
||||
atomic_set(&env_tlb(env)->c.full_flush_count,
|
||||
qatomic_set(&env_tlb(env)->c.full_flush_count,
|
||||
env_tlb(env)->c.full_flush_count + 1);
|
||||
} else {
|
||||
atomic_set(&env_tlb(env)->c.part_flush_count,
|
||||
qatomic_set(&env_tlb(env)->c.part_flush_count,
|
||||
env_tlb(env)->c.part_flush_count + ctpop16(to_clean));
|
||||
if (to_clean != asked) {
|
||||
atomic_set(&env_tlb(env)->c.elide_flush_count,
|
||||
qatomic_set(&env_tlb(env)->c.elide_flush_count,
|
||||
env_tlb(env)->c.elide_flush_count +
|
||||
ctpop16(asked & ~to_clean));
|
||||
}
|
||||
|
@ -409,12 +429,21 @@ void tlb_flush_all_cpus_synced(CPUState *src_cpu)
|
|||
tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, ALL_MMUIDX_BITS);
|
||||
}
|
||||
|
||||
static bool tlb_hit_page_mask_anyprot(CPUTLBEntry *tlb_entry,
|
||||
target_ulong page, target_ulong mask)
|
||||
{
|
||||
page &= mask;
|
||||
mask &= TARGET_PAGE_MASK | TLB_INVALID_MASK;
|
||||
|
||||
return (page == (tlb_entry->addr_read & mask) ||
|
||||
page == (tlb_addr_write(tlb_entry) & mask) ||
|
||||
page == (tlb_entry->addr_code & mask));
|
||||
}
|
||||
|
||||
static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry,
|
||||
target_ulong page)
|
||||
{
|
||||
return tlb_hit_page(tlb_entry->addr_read, page) ||
|
||||
tlb_hit_page(tlb_addr_write(tlb_entry), page) ||
|
||||
tlb_hit_page(tlb_entry->addr_code, page);
|
||||
return tlb_hit_page_mask_anyprot(tlb_entry, page, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -427,31 +456,45 @@ static inline bool tlb_entry_is_empty(const CPUTLBEntry *te)
|
|||
}
|
||||
|
||||
/* Called with tlb_c.lock held */
|
||||
static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry,
|
||||
target_ulong page)
|
||||
static bool tlb_flush_entry_mask_locked(CPUTLBEntry *tlb_entry,
|
||||
target_ulong page,
|
||||
target_ulong mask)
|
||||
{
|
||||
if (tlb_hit_page_anyprot(tlb_entry, page)) {
|
||||
if (tlb_hit_page_mask_anyprot(tlb_entry, page, mask)) {
|
||||
memset(tlb_entry, -1, sizeof(*tlb_entry));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry,
|
||||
target_ulong page)
|
||||
{
|
||||
return tlb_flush_entry_mask_locked(tlb_entry, page, -1);
|
||||
}
|
||||
|
||||
/* Called with tlb_c.lock held */
|
||||
static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx,
|
||||
target_ulong page)
|
||||
static void tlb_flush_vtlb_page_mask_locked(CPUArchState *env, int mmu_idx,
|
||||
target_ulong page,
|
||||
target_ulong mask)
|
||||
{
|
||||
CPUTLBDesc *d = &env_tlb(env)->d[mmu_idx];
|
||||
int k;
|
||||
|
||||
assert_cpu_is_self(env_cpu(env));
|
||||
for (k = 0; k < CPU_VTLB_SIZE; k++) {
|
||||
if (tlb_flush_entry_locked(&d->vtable[k], page)) {
|
||||
if (tlb_flush_entry_mask_locked(&d->vtable[k], page, mask)) {
|
||||
tlb_n_used_entries_dec(env, mmu_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx,
|
||||
target_ulong page)
|
||||
{
|
||||
tlb_flush_vtlb_page_mask_locked(env, mmu_idx, page, -1);
|
||||
}
|
||||
|
||||
static void tlb_flush_page_locked(CPUArchState *env, int midx,
|
||||
target_ulong page)
|
||||
{
|
||||
|
@ -666,6 +709,240 @@ void tlb_flush_page_all_cpus_synced(CPUState *src, target_ulong addr)
|
|||
tlb_flush_page_by_mmuidx_all_cpus_synced(src, addr, ALL_MMUIDX_BITS);
|
||||
}
|
||||
|
||||
static void tlb_flush_page_bits_locked(CPUArchState *env, int midx,
|
||||
target_ulong page, unsigned bits)
|
||||
{
|
||||
CPUTLBDesc *d = &env_tlb(env)->d[midx];
|
||||
CPUTLBDescFast *f = &env_tlb(env)->f[midx];
|
||||
target_ulong mask = MAKE_64BIT_MASK(0, bits);
|
||||
|
||||
/*
|
||||
* If @bits is smaller than the tlb size, there may be multiple entries
|
||||
* within the TLB; otherwise all addresses that match under @mask hit
|
||||
* the same TLB entry.
|
||||
*
|
||||
* TODO: Perhaps allow bits to be a few bits less than the size.
|
||||
* For now, just flush the entire TLB.
|
||||
*/
|
||||
if (mask < f->mask) {
|
||||
tlb_debug("forcing full flush midx %d ("
|
||||
TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
|
||||
midx, page, mask);
|
||||
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we need to flush due to large pages. */
|
||||
if ((page & d->large_page_mask) == d->large_page_addr) {
|
||||
tlb_debug("forcing full flush midx %d ("
|
||||
TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
|
||||
midx, d->large_page_addr, d->large_page_mask);
|
||||
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
|
||||
return;
|
||||
}
|
||||
|
||||
if (tlb_flush_entry_mask_locked(tlb_entry(env, midx, page), page, mask)) {
|
||||
tlb_n_used_entries_dec(env, midx);
|
||||
}
|
||||
tlb_flush_vtlb_page_mask_locked(env, midx, page, mask);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
target_ulong addr;
|
||||
uint16_t idxmap;
|
||||
uint16_t bits;
|
||||
} TLBFlushPageBitsByMMUIdxData;
|
||||
|
||||
static void
|
||||
tlb_flush_page_bits_by_mmuidx_async_0(CPUState *cpu,
|
||||
TLBFlushPageBitsByMMUIdxData d)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
int mmu_idx;
|
||||
|
||||
assert_cpu_is_self(cpu);
|
||||
|
||||
tlb_debug("page addr:" TARGET_FMT_lx "/%u mmu_map:0x%x\n",
|
||||
d.addr, d.bits, d.idxmap);
|
||||
|
||||
qemu_spin_lock(&env_tlb(env)->c.lock);
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
if ((d.idxmap >> mmu_idx) & 1) {
|
||||
tlb_flush_page_bits_locked(env, mmu_idx, d.addr, d.bits);
|
||||
}
|
||||
}
|
||||
qemu_spin_unlock(&env_tlb(env)->c.lock);
|
||||
|
||||
tb_flush_jmp_cache(cpu, d.addr);
|
||||
}
|
||||
|
||||
static bool encode_pbm_to_runon(run_on_cpu_data *out,
|
||||
TLBFlushPageBitsByMMUIdxData d)
|
||||
{
|
||||
/* We need 6 bits to hold to hold @bits up to 63. */
|
||||
if (d.idxmap <= MAKE_64BIT_MASK(0, TARGET_PAGE_BITS - 6)) {
|
||||
*out = RUN_ON_CPU_TARGET_PTR(d.addr | (d.idxmap << 6) | d.bits);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static TLBFlushPageBitsByMMUIdxData
|
||||
decode_runon_to_pbm(run_on_cpu_data data)
|
||||
{
|
||||
target_ulong addr_map_bits = (target_ulong) data.target_ptr;
|
||||
return (TLBFlushPageBitsByMMUIdxData){
|
||||
.addr = addr_map_bits & TARGET_PAGE_MASK,
|
||||
.idxmap = (addr_map_bits & ~TARGET_PAGE_MASK) >> 6,
|
||||
.bits = addr_map_bits & 0x3f
|
||||
};
|
||||
}
|
||||
|
||||
static void tlb_flush_page_bits_by_mmuidx_async_1(CPUState *cpu,
|
||||
run_on_cpu_data runon)
|
||||
{
|
||||
tlb_flush_page_bits_by_mmuidx_async_0(cpu, decode_runon_to_pbm(runon));
|
||||
}
|
||||
|
||||
static void tlb_flush_page_bits_by_mmuidx_async_2(CPUState *cpu,
|
||||
run_on_cpu_data data)
|
||||
{
|
||||
TLBFlushPageBitsByMMUIdxData *d = data.host_ptr;
|
||||
tlb_flush_page_bits_by_mmuidx_async_0(cpu, *d);
|
||||
g_free(d);
|
||||
}
|
||||
|
||||
void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, target_ulong addr,
|
||||
uint16_t idxmap, unsigned bits)
|
||||
{
|
||||
TLBFlushPageBitsByMMUIdxData d;
|
||||
run_on_cpu_data runon;
|
||||
|
||||
/* If all bits are significant, this devolves to tlb_flush_page. */
|
||||
if (bits >= TARGET_LONG_BITS) {
|
||||
tlb_flush_page_by_mmuidx(cpu, addr, idxmap);
|
||||
return;
|
||||
}
|
||||
/* If no page bits are significant, this devolves to tlb_flush. */
|
||||
if (bits < TARGET_PAGE_BITS) {
|
||||
tlb_flush_by_mmuidx(cpu, idxmap);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This should already be page aligned */
|
||||
d.addr = addr & TARGET_PAGE_MASK;
|
||||
d.idxmap = idxmap;
|
||||
d.bits = bits;
|
||||
|
||||
if (qemu_cpu_is_self(cpu)) {
|
||||
tlb_flush_page_bits_by_mmuidx_async_0(cpu, d);
|
||||
} else if (encode_pbm_to_runon(&runon, d)) {
|
||||
async_run_on_cpu(cpu, tlb_flush_page_bits_by_mmuidx_async_1, runon);
|
||||
} else {
|
||||
TLBFlushPageBitsByMMUIdxData *p
|
||||
= g_new(TLBFlushPageBitsByMMUIdxData, 1);
|
||||
|
||||
/* Otherwise allocate a structure, freed by the worker. */
|
||||
*p = d;
|
||||
async_run_on_cpu(cpu, tlb_flush_page_bits_by_mmuidx_async_2,
|
||||
RUN_ON_CPU_HOST_PTR(p));
|
||||
}
|
||||
}
|
||||
|
||||
void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *src_cpu,
|
||||
target_ulong addr,
|
||||
uint16_t idxmap,
|
||||
unsigned bits)
|
||||
{
|
||||
TLBFlushPageBitsByMMUIdxData d;
|
||||
run_on_cpu_data runon;
|
||||
|
||||
/* If all bits are significant, this devolves to tlb_flush_page. */
|
||||
if (bits >= TARGET_LONG_BITS) {
|
||||
tlb_flush_page_by_mmuidx_all_cpus(src_cpu, addr, idxmap);
|
||||
return;
|
||||
}
|
||||
/* If no page bits are significant, this devolves to tlb_flush. */
|
||||
if (bits < TARGET_PAGE_BITS) {
|
||||
tlb_flush_by_mmuidx_all_cpus(src_cpu, idxmap);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This should already be page aligned */
|
||||
d.addr = addr & TARGET_PAGE_MASK;
|
||||
d.idxmap = idxmap;
|
||||
d.bits = bits;
|
||||
|
||||
if (encode_pbm_to_runon(&runon, d)) {
|
||||
flush_all_helper(src_cpu, tlb_flush_page_bits_by_mmuidx_async_1, runon);
|
||||
} else {
|
||||
CPUState *dst_cpu;
|
||||
TLBFlushPageBitsByMMUIdxData *p;
|
||||
|
||||
/* Allocate a separate data block for each destination cpu. */
|
||||
CPU_FOREACH(dst_cpu) {
|
||||
if (dst_cpu != src_cpu) {
|
||||
p = g_new(TLBFlushPageBitsByMMUIdxData, 1);
|
||||
*p = d;
|
||||
async_run_on_cpu(dst_cpu,
|
||||
tlb_flush_page_bits_by_mmuidx_async_2,
|
||||
RUN_ON_CPU_HOST_PTR(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tlb_flush_page_bits_by_mmuidx_async_0(src_cpu, d);
|
||||
}
|
||||
|
||||
void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
|
||||
target_ulong addr,
|
||||
uint16_t idxmap,
|
||||
unsigned bits)
|
||||
{
|
||||
TLBFlushPageBitsByMMUIdxData d;
|
||||
run_on_cpu_data runon;
|
||||
|
||||
/* If all bits are significant, this devolves to tlb_flush_page. */
|
||||
if (bits >= TARGET_LONG_BITS) {
|
||||
tlb_flush_page_by_mmuidx_all_cpus_synced(src_cpu, addr, idxmap);
|
||||
return;
|
||||
}
|
||||
/* If no page bits are significant, this devolves to tlb_flush. */
|
||||
if (bits < TARGET_PAGE_BITS) {
|
||||
tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, idxmap);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This should already be page aligned */
|
||||
d.addr = addr & TARGET_PAGE_MASK;
|
||||
d.idxmap = idxmap;
|
||||
d.bits = bits;
|
||||
|
||||
if (encode_pbm_to_runon(&runon, d)) {
|
||||
flush_all_helper(src_cpu, tlb_flush_page_bits_by_mmuidx_async_1, runon);
|
||||
async_safe_run_on_cpu(src_cpu, tlb_flush_page_bits_by_mmuidx_async_1,
|
||||
runon);
|
||||
} else {
|
||||
CPUState *dst_cpu;
|
||||
TLBFlushPageBitsByMMUIdxData *p;
|
||||
|
||||
/* Allocate a separate data block for each destination cpu. */
|
||||
CPU_FOREACH(dst_cpu) {
|
||||
if (dst_cpu != src_cpu) {
|
||||
p = g_new(TLBFlushPageBitsByMMUIdxData, 1);
|
||||
*p = d;
|
||||
async_run_on_cpu(dst_cpu, tlb_flush_page_bits_by_mmuidx_async_2,
|
||||
RUN_ON_CPU_HOST_PTR(p));
|
||||
}
|
||||
}
|
||||
|
||||
p = g_new(TLBFlushPageBitsByMMUIdxData, 1);
|
||||
*p = d;
|
||||
async_safe_run_on_cpu(src_cpu, tlb_flush_page_bits_by_mmuidx_async_2,
|
||||
RUN_ON_CPU_HOST_PTR(p));
|
||||
}
|
||||
}
|
||||
|
||||
/* update the TLBs so that writes to code in the virtual page 'addr'
|
||||
can be detected */
|
||||
void tlb_protect_code(ram_addr_t ram_addr)
|
||||
|
@ -693,7 +970,7 @@ void tlb_unprotect_code(ram_addr_t ram_addr)
|
|||
* generated code.
|
||||
*
|
||||
* Other vCPUs might be reading their TLBs during guest execution, so we update
|
||||
* te->addr_write with atomic_set. We don't need to worry about this for
|
||||
* te->addr_write with qatomic_set. We don't need to worry about this for
|
||||
* oversized guests as MTTCG is disabled for them.
|
||||
*
|
||||
* Called with tlb_c.lock held.
|
||||
|
@ -711,7 +988,7 @@ static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry,
|
|||
#if TCG_OVERSIZED_GUEST
|
||||
tlb_entry->addr_write |= TLB_NOTDIRTY;
|
||||
#else
|
||||
atomic_set(&tlb_entry->addr_write,
|
||||
qatomic_set(&tlb_entry->addr_write,
|
||||
tlb_entry->addr_write | TLB_NOTDIRTY);
|
||||
#endif
|
||||
}
|
||||
|
@ -1034,10 +1311,37 @@ static void tlb_fill(CPUState *cpu, target_ulong addr, int size,
|
|||
* This is not a probe, so only valid return is success; failure
|
||||
* should result in exception + longjmp to the cpu loop.
|
||||
*/
|
||||
ok = cc->tlb_fill(cpu, addr, size, access_type, mmu_idx, false, retaddr);
|
||||
ok = cc->tcg_ops->tlb_fill(cpu, addr, size,
|
||||
access_type, mmu_idx, false, retaddr);
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
cc->tcg_ops->do_unaligned_access(cpu, addr, access_type, mmu_idx, retaddr);
|
||||
}
|
||||
|
||||
static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr,
|
||||
vaddr addr, unsigned size,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
MemTxResult response,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
if (!cpu->ignore_memory_transaction_failures &&
|
||||
cc->tcg_ops->do_transaction_failed) {
|
||||
cc->tcg_ops->do_transaction_failed(cpu, physaddr, addr, size,
|
||||
access_type, mmu_idx, attrs,
|
||||
response, retaddr);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
||||
int mmu_idx, target_ulong addr, uintptr_t retaddr,
|
||||
MMUAccessType access_type, MemOp op)
|
||||
|
@ -1058,7 +1362,7 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
|||
cpu_io_recompile(cpu, retaddr);
|
||||
}
|
||||
|
||||
if (mr->global_locking && !qemu_mutex_iothread_locked()) {
|
||||
if (!qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_lock_iothread();
|
||||
locked = true;
|
||||
}
|
||||
|
@ -1119,7 +1423,7 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
|
|||
*/
|
||||
save_iotlb_data(cpu, iotlbentry->addr, section, mr_offset);
|
||||
|
||||
if (mr->global_locking && !qemu_mutex_iothread_locked()) {
|
||||
if (!qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_lock_iothread();
|
||||
locked = true;
|
||||
}
|
||||
|
@ -1143,8 +1447,8 @@ static inline target_ulong tlb_read_ofs(CPUTLBEntry *entry, size_t ofs)
|
|||
#if TCG_OVERSIZED_GUEST
|
||||
return *(target_ulong *)((uintptr_t)entry + ofs);
|
||||
#else
|
||||
/* ofs might correspond to .addr_write, so use atomic_read */
|
||||
return atomic_read((target_ulong *)((uintptr_t)entry + ofs));
|
||||
/* ofs might correspond to .addr_write, so use qatomic_read */
|
||||
return qatomic_read((target_ulong *)((uintptr_t)entry + ofs));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1160,11 +1464,11 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index,
|
|||
CPUTLBEntry *vtlb = &env_tlb(env)->d[mmu_idx].vtable[vidx];
|
||||
target_ulong cmp;
|
||||
|
||||
/* elt_ofs might correspond to .addr_write, so use atomic_read */
|
||||
/* elt_ofs might correspond to .addr_write, so use qatomic_read */
|
||||
#if TCG_OVERSIZED_GUEST
|
||||
cmp = *(target_ulong *)((uintptr_t)vtlb + elt_ofs);
|
||||
#else
|
||||
cmp = atomic_read((target_ulong *)((uintptr_t)vtlb + elt_ofs));
|
||||
cmp = qatomic_read((target_ulong *)((uintptr_t)vtlb + elt_ofs));
|
||||
#endif
|
||||
|
||||
if (cmp == page) {
|
||||
|
@ -1305,8 +1609,8 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr,
|
|||
CPUState *cs = env_cpu(env);
|
||||
CPUClass *cc = CPU_GET_CLASS(cs);
|
||||
|
||||
if (!cc->tlb_fill(cs, addr, fault_size, access_type,
|
||||
mmu_idx, nonfault, retaddr)) {
|
||||
if (!cc->tcg_ops->tlb_fill(cs, addr, fault_size, access_type,
|
||||
mmu_idx, nonfault, retaddr)) {
|
||||
/* Non-faulting page table read failed. */
|
||||
*phost = NULL;
|
||||
return TLB_INVALID_MASK;
|
||||
|
@ -2023,6 +2327,97 @@ store_memop(void *haddr, uint64_t val, MemOp op)
|
|||
}
|
||||
}
|
||||
|
||||
static void __attribute__((noinline))
|
||||
store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
uintptr_t retaddr, size_t size, uintptr_t mmu_idx,
|
||||
bool big_endian)
|
||||
{
|
||||
const size_t tlb_off = offsetof(CPUTLBEntry, addr_write);
|
||||
uintptr_t index, index2;
|
||||
CPUTLBEntry *entry, *entry2;
|
||||
target_ulong page2, tlb_addr, tlb_addr2;
|
||||
TCGMemOpIdx oi;
|
||||
size_t size2;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Ensure the second page is in the TLB. Note that the first page
|
||||
* is already guaranteed to be filled, and that the second page
|
||||
* cannot evict the first.
|
||||
*/
|
||||
|
||||
// FIXME: Upstream patch for this
|
||||
if ((addr & ~TARGET_PAGE_MASK) + size - 1 >= TARGET_PAGE_SIZE) {
|
||||
|
||||
page2 = (addr + size) & TARGET_PAGE_MASK;
|
||||
size2 = (addr + size) & ~TARGET_PAGE_MASK;
|
||||
index2 = tlb_index(env, mmu_idx, page2);
|
||||
entry2 = tlb_entry(env, mmu_idx, page2);
|
||||
|
||||
tlb_addr2 = tlb_addr_write(entry2);
|
||||
if (!tlb_hit_page(tlb_addr2, page2)) {
|
||||
if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) {
|
||||
tlb_fill(env_cpu(env), page2, size2, MMU_DATA_STORE,
|
||||
mmu_idx, retaddr);
|
||||
index2 = tlb_index(env, mmu_idx, page2);
|
||||
entry2 = tlb_entry(env, mmu_idx, page2);
|
||||
}
|
||||
tlb_addr2 = tlb_addr_write(entry2);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* The access happens on a single page */
|
||||
size2 = 0;
|
||||
}
|
||||
|
||||
index = tlb_index(env, mmu_idx, addr);
|
||||
entry = tlb_entry(env, mmu_idx, addr);
|
||||
tlb_addr = tlb_addr_write(entry);
|
||||
|
||||
/*
|
||||
* Handle watchpoints. Since this may trap, all checks
|
||||
* must happen before any store.
|
||||
*/
|
||||
if (unlikely(tlb_addr & TLB_WATCHPOINT)) {
|
||||
#ifdef XBOX
|
||||
mem_check_access_callback_vaddr(env_cpu(env), addr, size - size2,
|
||||
BP_MEM_WRITE, &env_tlb(env)->d[mmu_idx].iotlb[index]);
|
||||
#endif
|
||||
cpu_check_watchpoint(env_cpu(env), addr, size - size2,
|
||||
env_tlb(env)->d[mmu_idx].iotlb[index].attrs,
|
||||
BP_MEM_WRITE, retaddr);
|
||||
}
|
||||
if (size2 > 0 && unlikely(tlb_addr2 & TLB_WATCHPOINT)) {
|
||||
#ifdef XBOX
|
||||
mem_check_access_callback_vaddr(env_cpu(env), page2, size2,
|
||||
BP_MEM_WRITE, &env_tlb(env)->d[mmu_idx].iotlb[index2]);
|
||||
#endif
|
||||
cpu_check_watchpoint(env_cpu(env), page2, size2,
|
||||
env_tlb(env)->d[mmu_idx].iotlb[index2].attrs,
|
||||
BP_MEM_WRITE, retaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: not efficient, but simple.
|
||||
* This loop must go in the forward direction to avoid issues
|
||||
* with self-modifying code in Windows 64-bit.
|
||||
*/
|
||||
oi = make_memop_idx(MO_UB, mmu_idx);
|
||||
if (big_endian) {
|
||||
for (i = 0; i < size; ++i) {
|
||||
/* Big-endian extract. */
|
||||
uint8_t val8 = val >> (((size - 1) * 8) - (i * 8));
|
||||
helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < size; ++i) {
|
||||
/* Little-endian extract. */
|
||||
uint8_t val8 = val >> (i * 8);
|
||||
helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void QEMU_ALWAYS_INLINE
|
||||
store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr, MemOp op)
|
||||
|
@ -2116,79 +2511,9 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
|||
if (size > 1
|
||||
&& unlikely((addr & ~TARGET_PAGE_MASK) + size - 1
|
||||
>= TARGET_PAGE_SIZE)) {
|
||||
int i;
|
||||
uintptr_t index2;
|
||||
CPUTLBEntry *entry2;
|
||||
target_ulong page2, tlb_addr2;
|
||||
size_t size2;
|
||||
|
||||
do_unaligned_access:
|
||||
/*
|
||||
* Ensure the second page is in the TLB. Note that the first page
|
||||
* is already guaranteed to be filled, and that the second page
|
||||
* cannot evict the first.
|
||||
*/
|
||||
|
||||
// FIXME: Upstream patch for this
|
||||
if ((addr & ~TARGET_PAGE_MASK) + size - 1 >= TARGET_PAGE_SIZE) {
|
||||
page2 = (addr + size) & TARGET_PAGE_MASK;
|
||||
size2 = (addr + size) & ~TARGET_PAGE_MASK;
|
||||
index2 = tlb_index(env, mmu_idx, page2);
|
||||
entry2 = tlb_entry(env, mmu_idx, page2);
|
||||
tlb_addr2 = tlb_addr_write(entry2);
|
||||
if (!tlb_hit_page(tlb_addr2, page2)) {
|
||||
if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) {
|
||||
tlb_fill(env_cpu(env), page2, size2, MMU_DATA_STORE,
|
||||
mmu_idx, retaddr);
|
||||
index2 = tlb_index(env, mmu_idx, page2);
|
||||
entry2 = tlb_entry(env, mmu_idx, page2);
|
||||
}
|
||||
tlb_addr2 = tlb_addr_write(entry2);
|
||||
}
|
||||
} else {
|
||||
/* The access happens on a single page */
|
||||
size2 = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle watchpoints. Since this may trap, all checks
|
||||
* must happen before any store.
|
||||
*/
|
||||
if (unlikely(tlb_addr & TLB_WATCHPOINT)) {
|
||||
#ifdef XBOX
|
||||
mem_check_access_callback_vaddr(env_cpu(env), addr, size - size2,
|
||||
BP_MEM_WRITE, &env_tlb(env)->d[mmu_idx].iotlb[index]);
|
||||
#endif
|
||||
cpu_check_watchpoint(env_cpu(env), addr, size - size2,
|
||||
env_tlb(env)->d[mmu_idx].iotlb[index].attrs,
|
||||
BP_MEM_WRITE, retaddr);
|
||||
}
|
||||
if (size2 > 0 && unlikely(tlb_addr2 & TLB_WATCHPOINT)) {
|
||||
#ifdef XBOX
|
||||
mem_check_access_callback_vaddr(env_cpu(env), page2, size2,
|
||||
BP_MEM_WRITE, &env_tlb(env)->d[mmu_idx].iotlb[index2]);
|
||||
#endif
|
||||
cpu_check_watchpoint(env_cpu(env), page2, size2,
|
||||
env_tlb(env)->d[mmu_idx].iotlb[index2].attrs,
|
||||
BP_MEM_WRITE, retaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: not efficient, but simple.
|
||||
* This loop must go in the forward direction to avoid issues
|
||||
* with self-modifying code in Windows 64-bit.
|
||||
*/
|
||||
for (i = 0; i < size; ++i) {
|
||||
uint8_t val8;
|
||||
if (memop_big_endian(op)) {
|
||||
/* Big-endian extract. */
|
||||
val8 = val >> (((size - 1) * 8) - (i * 8));
|
||||
} else {
|
||||
/* Little-endian extract. */
|
||||
val8 = val >> (i * 8);
|
||||
}
|
||||
helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
|
||||
}
|
||||
store_helper_unaligned(env, addr, val, retaddr, size,
|
||||
mmu_idx, memop_big_endian(op));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2196,8 +2521,9 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
|
|||
store_memop(haddr, val, op);
|
||||
}
|
||||
|
||||
void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
void __attribute__((noinline))
|
||||
helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
|
||||
TCGMemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
store_helper(env, addr, val, oi, retaddr, MO_UB);
|
||||
}
|
||||
|
@ -2388,7 +2714,7 @@ void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val)
|
|||
#define ATOMIC_MMU_CLEANUP
|
||||
#define ATOMIC_MMU_IDX get_mmuidx(oi)
|
||||
|
||||
#include "atomic_common.inc.c"
|
||||
#include "atomic_common.c.inc"
|
||||
|
||||
#define DATA_SIZE 1
|
||||
#include "atomic_template.h"
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Internal execution defines for qemu
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#ifndef ACCEL_TCG_INTERNAL_H
|
||||
#define ACCEL_TCG_INTERNAL_H
|
||||
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc,
|
||||
target_ulong cs_base, uint32_t flags,
|
||||
int cflags);
|
||||
|
||||
void QEMU_NORETURN cpu_io_recompile(CPUState *cpu, uintptr_t retaddr);
|
||||
|
||||
#endif /* ACCEL_TCG_INTERNAL_H */
|
|
@ -0,0 +1,22 @@
|
|||
tcg_ss = ss.source_set()
|
||||
tcg_ss.add(files(
|
||||
'tcg-all.c',
|
||||
'cpu-exec-common.c',
|
||||
'cpu-exec.c',
|
||||
'tcg-runtime-gvec.c',
|
||||
'tcg-runtime.c',
|
||||
'translate-all.c',
|
||||
'translator.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_PLUGIN', if_true: [files('plugin-gen.c'), libdl])
|
||||
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
|
||||
|
||||
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
|
||||
'cputlb.c',
|
||||
'tcg-accel-ops.c',
|
||||
'tcg-accel-ops-mttcg.c',
|
||||
'tcg-accel-ops-icount.c',
|
||||
'tcg-accel-ops-rr.c'
|
||||
))
|
|
@ -284,8 +284,8 @@ static TCGOp *copy_extu_i32_i64(TCGOp **begin_op, TCGOp *op)
|
|||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
/* mov_i32 */
|
||||
op = copy_op(begin_op, op, INDEX_op_mov_i32);
|
||||
/* movi_i32 */
|
||||
op = copy_op(begin_op, op, INDEX_op_movi_i32);
|
||||
/* mov_i32 w/ $0 */
|
||||
op = copy_op(begin_op, op, INDEX_op_mov_i32);
|
||||
} else {
|
||||
/* extu_i32_i64 */
|
||||
op = copy_op(begin_op, op, INDEX_op_extu_i32_i64);
|
||||
|
@ -306,41 +306,20 @@ static TCGOp *copy_mov_i64(TCGOp **begin_op, TCGOp *op)
|
|||
return op;
|
||||
}
|
||||
|
||||
static TCGOp *copy_movi_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
|
||||
{
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
/* 2x movi_i32 */
|
||||
op = copy_op(begin_op, op, INDEX_op_movi_i32);
|
||||
op->args[1] = v;
|
||||
|
||||
op = copy_op(begin_op, op, INDEX_op_movi_i32);
|
||||
op->args[1] = v >> 32;
|
||||
} else {
|
||||
/* movi_i64 */
|
||||
op = copy_op(begin_op, op, INDEX_op_movi_i64);
|
||||
op->args[1] = v;
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
static TCGOp *copy_const_ptr(TCGOp **begin_op, TCGOp *op, void *ptr)
|
||||
{
|
||||
if (UINTPTR_MAX == UINT32_MAX) {
|
||||
/* movi_i32 */
|
||||
op = copy_op(begin_op, op, INDEX_op_movi_i32);
|
||||
op->args[1] = (uintptr_t)ptr;
|
||||
/* mov_i32 */
|
||||
op = copy_op(begin_op, op, INDEX_op_mov_i32);
|
||||
op->args[1] = tcgv_i32_arg(tcg_constant_i32((uintptr_t)ptr));
|
||||
} else {
|
||||
/* movi_i64 */
|
||||
op = copy_movi_i64(begin_op, op, (uint64_t)(uintptr_t)ptr);
|
||||
/* mov_i64 */
|
||||
op = copy_op(begin_op, op, INDEX_op_mov_i64);
|
||||
op->args[1] = tcgv_i64_arg(tcg_constant_i64((uintptr_t)ptr));
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
static TCGOp *copy_const_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
|
||||
{
|
||||
return copy_movi_i64(begin_op, op, v);
|
||||
}
|
||||
|
||||
static TCGOp *copy_extu_tl_i64(TCGOp **begin_op, TCGOp *op)
|
||||
{
|
||||
if (TARGET_LONG_BITS == 32) {
|
||||
|
@ -379,14 +358,17 @@ static TCGOp *copy_st_i64(TCGOp **begin_op, TCGOp *op)
|
|||
return op;
|
||||
}
|
||||
|
||||
static TCGOp *copy_add_i64(TCGOp **begin_op, TCGOp *op)
|
||||
static TCGOp *copy_add_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
|
||||
{
|
||||
if (TCG_TARGET_REG_BITS == 32) {
|
||||
/* all 32-bit backends must implement add2_i32 */
|
||||
g_assert(TCG_TARGET_HAS_add2_i32);
|
||||
op = copy_op(begin_op, op, INDEX_op_add2_i32);
|
||||
op->args[4] = tcgv_i32_arg(tcg_constant_i32(v));
|
||||
op->args[5] = tcgv_i32_arg(tcg_constant_i32(v >> 32));
|
||||
} else {
|
||||
op = copy_op(begin_op, op, INDEX_op_add_i64);
|
||||
op->args[2] = tcgv_i64_arg(tcg_constant_i64(v));
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
@ -436,6 +418,12 @@ static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func,
|
|||
return op;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we append/replace ops here we are sensitive to changing patterns of
|
||||
* TCGOps generated by the tcg_gen_FOO calls when we generated the
|
||||
* empty callbacks. This will assert very quickly in a debug build as
|
||||
* we assert the ops we are replacing are the correct ones.
|
||||
*/
|
||||
static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
|
||||
TCGOp *begin_op, TCGOp *op, int *cb_idx)
|
||||
{
|
||||
|
@ -467,11 +455,8 @@ static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
|
|||
/* ld_i64 */
|
||||
op = copy_ld_i64(&begin_op, op);
|
||||
|
||||
/* const_i64 */
|
||||
op = copy_const_i64(&begin_op, op, cb->inline_insn.imm);
|
||||
|
||||
/* add_i64 */
|
||||
op = copy_add_i64(&begin_op, op);
|
||||
op = copy_add_i64(&begin_op, op, cb->inline_insn.imm);
|
||||
|
||||
/* st_i64 */
|
||||
op = copy_st_i64(&begin_op, op);
|
||||
|
@ -486,8 +471,8 @@ static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
|
|||
|
||||
tcg_debug_assert(type == PLUGIN_GEN_CB_MEM);
|
||||
|
||||
/* const_i32 == movi_i32 ("info", so it remains as is) */
|
||||
op = copy_op(&begin_op, op, INDEX_op_movi_i32);
|
||||
/* const_i32 == mov_i32 ("info", so it remains as is) */
|
||||
op = copy_op(&begin_op, op, INDEX_op_mov_i32);
|
||||
|
||||
/* const_ptr */
|
||||
op = copy_const_ptr(&begin_op, op, cb->userp);
|
||||
|
@ -857,7 +842,7 @@ static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
|
|||
pr_ops();
|
||||
}
|
||||
|
||||
bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb)
|
||||
bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_only)
|
||||
{
|
||||
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
|
||||
bool ret = false;
|
||||
|
@ -870,6 +855,7 @@ bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb)
|
|||
ptb->vaddr2 = -1;
|
||||
get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1);
|
||||
ptb->haddr2 = NULL;
|
||||
ptb->mem_only = mem_only;
|
||||
|
||||
plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* QEMU TCG Single Threaded vCPUs implementation using instruction counting
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2014 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-common.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
#include "tcg-accel-ops.h"
|
||||
#include "tcg-accel-ops-icount.h"
|
||||
#include "tcg-accel-ops-rr.h"
|
||||
|
||||
static int64_t icount_get_limit(void)
|
||||
{
|
||||
int64_t deadline;
|
||||
|
||||
if (replay_mode != REPLAY_MODE_PLAY) {
|
||||
/*
|
||||
* Include all the timers, because they may need an attention.
|
||||
* Too long CPU execution may create unnecessary delay in UI.
|
||||
*/
|
||||
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL,
|
||||
QEMU_TIMER_ATTR_ALL);
|
||||
/* Check realtime timers, because they help with input processing */
|
||||
deadline = qemu_soonest_timeout(deadline,
|
||||
qemu_clock_deadline_ns_all(QEMU_CLOCK_REALTIME,
|
||||
QEMU_TIMER_ATTR_ALL));
|
||||
|
||||
/*
|
||||
* Maintain prior (possibly buggy) behaviour where if no deadline
|
||||
* was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than
|
||||
* INT32_MAX nanoseconds ahead, we still use INT32_MAX
|
||||
* nanoseconds.
|
||||
*/
|
||||
if ((deadline < 0) || (deadline > INT32_MAX)) {
|
||||
deadline = INT32_MAX;
|
||||
}
|
||||
|
||||
return icount_round(deadline);
|
||||
} else {
|
||||
return replay_get_instructions();
|
||||
}
|
||||
}
|
||||
|
||||
static void icount_notify_aio_contexts(void)
|
||||
{
|
||||
/* Wake up other AioContexts. */
|
||||
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
|
||||
qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
|
||||
}
|
||||
|
||||
void icount_handle_deadline(void)
|
||||
{
|
||||
assert(qemu_in_vcpu_thread());
|
||||
int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL,
|
||||
QEMU_TIMER_ATTR_ALL);
|
||||
|
||||
/*
|
||||
* Instructions, interrupts, and exceptions are processed in cpu-exec.
|
||||
* Don't interrupt cpu thread, when these events are waiting
|
||||
* (i.e., there is no checkpoint)
|
||||
*/
|
||||
if (deadline == 0
|
||||
&& (replay_mode != REPLAY_MODE_PLAY || replay_has_checkpoint())) {
|
||||
icount_notify_aio_contexts();
|
||||
}
|
||||
}
|
||||
|
||||
void icount_prepare_for_run(CPUState *cpu)
|
||||
{
|
||||
int insns_left;
|
||||
|
||||
/*
|
||||
* These should always be cleared by icount_process_data after
|
||||
* each vCPU execution. However u16.high can be raised
|
||||
* asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt
|
||||
*/
|
||||
g_assert(cpu_neg(cpu)->icount_decr.u16.low == 0);
|
||||
g_assert(cpu->icount_extra == 0);
|
||||
|
||||
cpu->icount_budget = icount_get_limit();
|
||||
insns_left = MIN(0xffff, cpu->icount_budget);
|
||||
cpu_neg(cpu)->icount_decr.u16.low = insns_left;
|
||||
cpu->icount_extra = cpu->icount_budget - insns_left;
|
||||
|
||||
replay_mutex_lock();
|
||||
|
||||
if (cpu->icount_budget == 0 && replay_has_checkpoint()) {
|
||||
icount_notify_aio_contexts();
|
||||
}
|
||||
}
|
||||
|
||||
void icount_process_data(CPUState *cpu)
|
||||
{
|
||||
/* Account for executed instructions */
|
||||
icount_update(cpu);
|
||||
|
||||
/* Reset the counters */
|
||||
cpu_neg(cpu)->icount_decr.u16.low = 0;
|
||||
cpu->icount_extra = 0;
|
||||
cpu->icount_budget = 0;
|
||||
|
||||
replay_account_executed_instructions();
|
||||
|
||||
replay_mutex_unlock();
|
||||
}
|
||||
|
||||
void icount_handle_interrupt(CPUState *cpu, int mask)
|
||||
{
|
||||
int old_mask = cpu->interrupt_request;
|
||||
|
||||
tcg_handle_interrupt(cpu, mask);
|
||||
if (qemu_cpu_is_self(cpu) &&
|
||||
!cpu->can_do_io
|
||||
&& (mask & ~old_mask) != 0) {
|
||||
cpu_abort(cpu, "Raised interrupt while not in I/O function");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* QEMU TCG Single Threaded vCPUs implementation using instruction counting
|
||||
*
|
||||
* Copyright 2020 SUSE LLC
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef TCG_CPUS_ICOUNT_H
|
||||
#define TCG_CPUS_ICOUNT_H
|
||||
|
||||
void icount_handle_deadline(void);
|
||||
void icount_prepare_for_run(CPUState *cpu);
|
||||
void icount_process_data(CPUState *cpu);
|
||||
|
||||
void icount_handle_interrupt(CPUState *cpu, int mask);
|
||||
|
||||
#endif /* TCG_CPUS_ICOUNT_H */
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* QEMU TCG Multi Threaded vCPUs implementation
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2014 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-common.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
#include "tcg-accel-ops.h"
|
||||
#include "tcg-accel-ops-mttcg.h"
|
||||
|
||||
/*
|
||||
* In the multi-threaded case each vCPU has its own thread. The TLS
|
||||
* variable current_cpu can be used deep in the code to find the
|
||||
* current CPUState for a given thread.
|
||||
*/
|
||||
|
||||
static void *mttcg_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
|
||||
assert(tcg_enabled());
|
||||
g_assert(!icount_enabled());
|
||||
|
||||
rcu_register_thread();
|
||||
tcg_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->can_do_io = 1;
|
||||
current_cpu = cpu;
|
||||
cpu_thread_signal_created(cpu);
|
||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||
|
||||
/* process any pending work */
|
||||
cpu->exit_request = 1;
|
||||
|
||||
do {
|
||||
if (cpu_can_run(cpu)) {
|
||||
int r;
|
||||
qemu_mutex_unlock_iothread();
|
||||
r = tcg_cpus_exec(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
switch (r) {
|
||||
case EXCP_DEBUG:
|
||||
cpu_handle_guest_debug(cpu);
|
||||
break;
|
||||
case EXCP_HALTED:
|
||||
/*
|
||||
* during start-up the vCPU is reset and the thread is
|
||||
* kicked several times. If we don't ensure we go back
|
||||
* to sleep in the halted state we won't cleanly
|
||||
* start-up when the vCPU is enabled.
|
||||
*
|
||||
* cpu->halted should ensure we sleep in wait_io_event
|
||||
*/
|
||||
g_assert(cpu->halted);
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
qemu_mutex_unlock_iothread();
|
||||
cpu_exec_step_atomic(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
default:
|
||||
/* Ignore everything else? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qatomic_mb_set(&cpu->exit_request, 0);
|
||||
qemu_wait_io_event(cpu);
|
||||
} while (!cpu->unplug || cpu_can_run(cpu));
|
||||
|
||||
tcg_cpus_destroy(cpu);
|
||||
qemu_mutex_unlock_iothread();
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mttcg_kick_vcpu_thread(CPUState *cpu)
|
||||
{
|
||||
cpu_exit(cpu);
|
||||
}
|
||||
|
||||
void mttcg_start_vcpu_thread(CPUState *cpu)
|
||||
{
|
||||
char thread_name[VCPU_THREAD_NAME_SIZE];
|
||||
|
||||
g_assert(tcg_enabled());
|
||||
tcg_cpu_init_cflags(cpu, current_machine->smp.max_cpus > 1);
|
||||
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
|
||||
/* create a thread per vCPU with TCG (MTTCG) */
|
||||
snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG",
|
||||
cpu->cpu_index);
|
||||
|
||||
qemu_thread_create(cpu->thread, thread_name, mttcg_cpu_thread_fn,
|
||||
cpu, QEMU_THREAD_JOINABLE);
|
||||
|
||||
#ifdef _WIN32
|
||||
cpu->hThread = qemu_thread_get_handle(cpu->thread);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* QEMU TCG Multi Threaded vCPUs implementation
|
||||
*
|
||||
* Copyright 2021 SUSE LLC
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef TCG_CPUS_MTTCG_H
|
||||
#define TCG_CPUS_MTTCG_H
|
||||
|
||||
/* kick MTTCG vCPU thread */
|
||||
void mttcg_kick_vcpu_thread(CPUState *cpu);
|
||||
|
||||
/* start an mttcg vCPU thread */
|
||||
void mttcg_start_vcpu_thread(CPUState *cpu);
|
||||
|
||||
#endif /* TCG_CPUS_MTTCG_H */
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* QEMU TCG Single Threaded vCPUs implementation
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2014 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-common.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
#include "tcg-accel-ops.h"
|
||||
#include "tcg-accel-ops-rr.h"
|
||||
#include "tcg-accel-ops-icount.h"
|
||||
|
||||
/* Kick all RR vCPUs */
|
||||
void rr_kick_vcpu_thread(CPUState *unused)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu_exit(cpu);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* TCG vCPU kick timer
|
||||
*
|
||||
* The kick timer is responsible for moving single threaded vCPU
|
||||
* emulation on to the next vCPU. If more than one vCPU is running a
|
||||
* timer event with force a cpu->exit so the next vCPU can get
|
||||
* scheduled.
|
||||
*
|
||||
* The timer is removed if all vCPUs are idle and restarted again once
|
||||
* idleness is complete.
|
||||
*/
|
||||
|
||||
static QEMUTimer *rr_kick_vcpu_timer;
|
||||
static CPUState *rr_current_cpu;
|
||||
|
||||
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
|
||||
|
||||
static inline int64_t rr_next_kick_time(void)
|
||||
{
|
||||
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;
|
||||
}
|
||||
|
||||
/* Kick the currently round-robin scheduled vCPU to next */
|
||||
static void rr_kick_next_cpu(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
do {
|
||||
cpu = qatomic_mb_read(&rr_current_cpu);
|
||||
if (cpu) {
|
||||
cpu_exit(cpu);
|
||||
}
|
||||
} while (cpu != qatomic_mb_read(&rr_current_cpu));
|
||||
}
|
||||
|
||||
static void rr_kick_thread(void *opaque)
|
||||
{
|
||||
timer_mod(rr_kick_vcpu_timer, rr_next_kick_time());
|
||||
rr_kick_next_cpu();
|
||||
}
|
||||
|
||||
static void rr_start_kick_timer(void)
|
||||
{
|
||||
if (!rr_kick_vcpu_timer && CPU_NEXT(first_cpu)) {
|
||||
rr_kick_vcpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
rr_kick_thread, NULL);
|
||||
}
|
||||
if (rr_kick_vcpu_timer && !timer_pending(rr_kick_vcpu_timer)) {
|
||||
timer_mod(rr_kick_vcpu_timer, rr_next_kick_time());
|
||||
}
|
||||
}
|
||||
|
||||
static void rr_stop_kick_timer(void)
|
||||
{
|
||||
if (rr_kick_vcpu_timer && timer_pending(rr_kick_vcpu_timer)) {
|
||||
timer_del(rr_kick_vcpu_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void rr_wait_io_event(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
while (all_cpu_threads_idle()) {
|
||||
rr_stop_kick_timer();
|
||||
qemu_cond_wait_iothread(first_cpu->halt_cond);
|
||||
}
|
||||
|
||||
rr_start_kick_timer();
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
qemu_wait_io_event_common(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy any remaining vCPUs which have been unplugged and have
|
||||
* finished running
|
||||
*/
|
||||
static void rr_deal_with_unplugged_cpus(void)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
if (cpu->unplug && !cpu_can_run(cpu)) {
|
||||
tcg_cpus_destroy(cpu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* In the single-threaded case each vCPU is simulated in turn. If
|
||||
* there is more than a single vCPU we create a simple timer to kick
|
||||
* the vCPU and ensure we don't get stuck in a tight loop in one vCPU.
|
||||
* This is done explicitly rather than relying on side-effects
|
||||
* elsewhere.
|
||||
*/
|
||||
|
||||
static void *rr_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
|
||||
assert(tcg_enabled());
|
||||
rcu_register_thread();
|
||||
tcg_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->can_do_io = 1;
|
||||
cpu_thread_signal_created(cpu);
|
||||
qemu_guest_random_seed_thread_part2(cpu->random_seed);
|
||||
|
||||
/* wait for initial kick-off after machine start */
|
||||
while (first_cpu->stopped) {
|
||||
qemu_cond_wait_iothread(first_cpu->halt_cond);
|
||||
|
||||
/* process any pending work */
|
||||
CPU_FOREACH(cpu) {
|
||||
current_cpu = cpu;
|
||||
qemu_wait_io_event_common(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
rr_start_kick_timer();
|
||||
|
||||
cpu = first_cpu;
|
||||
|
||||
/* process any pending work */
|
||||
cpu->exit_request = 1;
|
||||
|
||||
while (1) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
replay_mutex_lock();
|
||||
qemu_mutex_lock_iothread();
|
||||
|
||||
if (icount_enabled()) {
|
||||
/* Account partial waits to QEMU_CLOCK_VIRTUAL. */
|
||||
icount_account_warp_timer();
|
||||
/*
|
||||
* Run the timers here. This is much more efficient than
|
||||
* waking up the I/O thread and waiting for completion.
|
||||
*/
|
||||
icount_handle_deadline();
|
||||
}
|
||||
|
||||
replay_mutex_unlock();
|
||||
|
||||
if (!cpu) {
|
||||
cpu = first_cpu;
|
||||
}
|
||||
|
||||
while (cpu && cpu_work_list_empty(cpu) && !cpu->exit_request) {
|
||||
|
||||
qatomic_mb_set(&rr_current_cpu, cpu);
|
||||
current_cpu = cpu;
|
||||
|
||||
qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
|
||||
(cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
||||
|
||||
if (cpu_can_run(cpu)) {
|
||||
int r;
|
||||
|
||||
qemu_mutex_unlock_iothread();
|
||||
if (icount_enabled()) {
|
||||
icount_prepare_for_run(cpu);
|
||||
}
|
||||
r = tcg_cpus_exec(cpu);
|
||||
if (icount_enabled()) {
|
||||
icount_process_data(cpu);
|
||||
}
|
||||
qemu_mutex_lock_iothread();
|
||||
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(cpu);
|
||||
break;
|
||||
} else if (r == EXCP_ATOMIC) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
cpu_exec_step_atomic(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
break;
|
||||
}
|
||||
} else if (cpu->stop) {
|
||||
if (cpu->unplug) {
|
||||
cpu = CPU_NEXT(cpu);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cpu = CPU_NEXT(cpu);
|
||||
} /* while (cpu && !cpu->exit_request).. */
|
||||
|
||||
/* Does not need qatomic_mb_set because a spurious wakeup is okay. */
|
||||
qatomic_set(&rr_current_cpu, NULL);
|
||||
|
||||
if (cpu && cpu->exit_request) {
|
||||
qatomic_mb_set(&cpu->exit_request, 0);
|
||||
}
|
||||
|
||||
if (icount_enabled() && all_cpu_threads_idle()) {
|
||||
/*
|
||||
* When all cpus are sleeping (e.g in WFI), to avoid a deadlock
|
||||
* in the main_loop, wake it up in order to start the warp timer.
|
||||
*/
|
||||
qemu_notify_event();
|
||||
}
|
||||
|
||||
rr_wait_io_event();
|
||||
rr_deal_with_unplugged_cpus();
|
||||
}
|
||||
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rr_start_vcpu_thread(CPUState *cpu)
|
||||
{
|
||||
char thread_name[VCPU_THREAD_NAME_SIZE];
|
||||
static QemuCond *single_tcg_halt_cond;
|
||||
static QemuThread *single_tcg_cpu_thread;
|
||||
|
||||
g_assert(tcg_enabled());
|
||||
tcg_cpu_init_cflags(cpu, false);
|
||||
|
||||
if (!single_tcg_cpu_thread) {
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
|
||||
/* share a single thread for all cpus with TCG */
|
||||
snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "ALL CPUs/TCG");
|
||||
qemu_thread_create(cpu->thread, thread_name,
|
||||
rr_cpu_thread_fn,
|
||||
cpu, QEMU_THREAD_JOINABLE);
|
||||
|
||||
single_tcg_halt_cond = cpu->halt_cond;
|
||||
single_tcg_cpu_thread = cpu->thread;
|
||||
#ifdef _WIN32
|
||||
cpu->hThread = qemu_thread_get_handle(cpu->thread);
|
||||
#endif
|
||||
} else {
|
||||
/* we share the thread */
|
||||
cpu->thread = single_tcg_cpu_thread;
|
||||
cpu->halt_cond = single_tcg_halt_cond;
|
||||
cpu->thread_id = first_cpu->thread_id;
|
||||
cpu->can_do_io = 1;
|
||||
cpu->created = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* QEMU TCG Single Threaded vCPUs implementation
|
||||
*
|
||||
* Copyright 2020 SUSE LLC
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef TCG_CPUS_RR_H
|
||||
#define TCG_CPUS_RR_H
|
||||
|
||||
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
|
||||
|
||||
/* Kick all RR vCPUs. */
|
||||
void rr_kick_vcpu_thread(CPUState *unused);
|
||||
|
||||
/* start the round robin vcpu thread */
|
||||
void rr_start_vcpu_thread(CPUState *cpu);
|
||||
|
||||
#endif /* TCG_CPUS_RR_H */
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* QEMU TCG vCPU common functionality
|
||||
*
|
||||
* Functionality common to all TCG vCPU variants: mttcg, rr and icount.
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2014 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-common.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
#include "tcg-accel-ops.h"
|
||||
#include "tcg-accel-ops-mttcg.h"
|
||||
#include "tcg-accel-ops-rr.h"
|
||||
#include "tcg-accel-ops-icount.h"
|
||||
|
||||
/* common functionality among all TCG variants */
|
||||
|
||||
void tcg_cpu_init_cflags(CPUState *cpu, bool parallel)
|
||||
{
|
||||
uint32_t cflags = cpu->cluster_index << CF_CLUSTER_SHIFT;
|
||||
cflags |= parallel ? CF_PARALLEL : 0;
|
||||
cflags |= icount_enabled() ? CF_USE_ICOUNT : 0;
|
||||
cpu->tcg_cflags = cflags;
|
||||
}
|
||||
|
||||
void tcg_cpus_destroy(CPUState *cpu)
|
||||
{
|
||||
cpu_thread_signal_destroyed(cpu);
|
||||
}
|
||||
|
||||
int tcg_cpus_exec(CPUState *cpu)
|
||||
{
|
||||
int ret;
|
||||
#ifdef CONFIG_PROFILER
|
||||
int64_t ti;
|
||||
#endif
|
||||
assert(tcg_enabled());
|
||||
#ifdef CONFIG_PROFILER
|
||||
ti = profile_getclock();
|
||||
#endif
|
||||
cpu_exec_start(cpu);
|
||||
ret = cpu_exec(cpu);
|
||||
cpu_exec_end(cpu);
|
||||
#ifdef CONFIG_PROFILER
|
||||
qatomic_set(&tcg_ctx->prof.cpu_exec_time,
|
||||
tcg_ctx->prof.cpu_exec_time + profile_getclock() - ti);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* mask must never be zero, except for A20 change call */
|
||||
void tcg_handle_interrupt(CPUState *cpu, int mask)
|
||||
{
|
||||
g_assert(qemu_mutex_iothread_locked());
|
||||
|
||||
cpu->interrupt_request |= mask;
|
||||
|
||||
/*
|
||||
* If called from iothread context, wake the target cpu in
|
||||
* case its halted.
|
||||
*/
|
||||
if (!qemu_cpu_is_self(cpu)) {
|
||||
qemu_cpu_kick(cpu);
|
||||
} else {
|
||||
qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_accel_ops_init(AccelOpsClass *ops)
|
||||
{
|
||||
if (qemu_tcg_mttcg_enabled()) {
|
||||
ops->create_vcpu_thread = mttcg_start_vcpu_thread;
|
||||
ops->kick_vcpu_thread = mttcg_kick_vcpu_thread;
|
||||
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 {
|
||||
ops->create_vcpu_thread = rr_start_vcpu_thread;
|
||||
ops->kick_vcpu_thread = rr_kick_vcpu_thread;
|
||||
ops->handle_interrupt = tcg_handle_interrupt;
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||
|
||||
ops->ops_init = tcg_accel_ops_init;
|
||||
}
|
||||
|
||||
static const TypeInfo tcg_accel_ops_type = {
|
||||
.name = ACCEL_OPS_NAME("tcg"),
|
||||
|
||||
.parent = TYPE_ACCEL_OPS,
|
||||
.class_init = tcg_accel_ops_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void tcg_accel_ops_register_types(void)
|
||||
{
|
||||
type_register_static(&tcg_accel_ops_type);
|
||||
}
|
||||
type_init(tcg_accel_ops_register_types);
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* QEMU TCG vCPU common functionality
|
||||
*
|
||||
* Functionality common to all TCG vcpu variants: mttcg, rr and icount.
|
||||
*
|
||||
* Copyright 2020 SUSE LLC
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef TCG_CPUS_H
|
||||
#define TCG_CPUS_H
|
||||
|
||||
#include "sysemu/cpus.h"
|
||||
|
||||
void tcg_cpus_destroy(CPUState *cpu);
|
||||
int tcg_cpus_exec(CPUState *cpu);
|
||||
void tcg_handle_interrupt(CPUState *cpu, int mask);
|
||||
void tcg_cpu_init_cflags(CPUState *cpu, bool parallel);
|
||||
|
||||
#endif /* TCG_CPUS_H */
|
|
@ -24,54 +24,28 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/accel.h"
|
||||
#include "qemu-common.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "qom/object.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/accel.h"
|
||||
#include "qapi/qapi-builtin-visit.h"
|
||||
|
||||
typedef struct TCGState {
|
||||
struct TCGState {
|
||||
AccelState parent_obj;
|
||||
|
||||
bool mttcg_enabled;
|
||||
int splitwx_enabled;
|
||||
unsigned long tb_size;
|
||||
} TCGState;
|
||||
};
|
||||
typedef struct TCGState TCGState;
|
||||
|
||||
#define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
|
||||
|
||||
#define TCG_STATE(obj) \
|
||||
OBJECT_CHECK(TCGState, (obj), TYPE_TCG_ACCEL)
|
||||
|
||||
/* mask must never be zero, except for A20 change call */
|
||||
static void tcg_handle_interrupt(CPUState *cpu, int mask)
|
||||
{
|
||||
int old_mask;
|
||||
g_assert(qemu_mutex_iothread_locked());
|
||||
|
||||
old_mask = cpu->interrupt_request;
|
||||
cpu->interrupt_request |= mask;
|
||||
|
||||
/*
|
||||
* If called from iothread context, wake the target cpu in
|
||||
* case its halted.
|
||||
*/
|
||||
if (!qemu_cpu_is_self(cpu)) {
|
||||
qemu_cpu_kick(cpu);
|
||||
} else {
|
||||
atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1);
|
||||
if (use_icount &&
|
||||
!cpu->can_do_io
|
||||
&& (mask & ~old_mask) != 0) {
|
||||
cpu_abort(cpu, "Raised interrupt while not in I/O function");
|
||||
}
|
||||
}
|
||||
}
|
||||
DECLARE_INSTANCE_CHECKER(TCGState, TCG_STATE,
|
||||
TYPE_TCG_ACCEL)
|
||||
|
||||
/*
|
||||
* We default to false if we know other options have been enabled
|
||||
|
@ -104,7 +78,7 @@ static bool check_tcg_memory_orders_compatible(void)
|
|||
|
||||
static bool default_mttcg_enabled(void)
|
||||
{
|
||||
if (use_icount || TCG_OVERSIZED_GUEST) {
|
||||
if (icount_enabled() || TCG_OVERSIZED_GUEST) {
|
||||
return false;
|
||||
} else {
|
||||
#ifdef TARGET_SUPPORTS_MTTCG
|
||||
|
@ -120,15 +94,34 @@ static void tcg_accel_instance_init(Object *obj)
|
|||
TCGState *s = TCG_STATE(obj);
|
||||
|
||||
s->mttcg_enabled = default_mttcg_enabled();
|
||||
|
||||
/* If debugging enabled, default "auto on", otherwise off. */
|
||||
#if defined(CONFIG_DEBUG_TCG) && !defined(CONFIG_USER_ONLY)
|
||||
s->splitwx_enabled = -1;
|
||||
#else
|
||||
s->splitwx_enabled = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mttcg_enabled;
|
||||
|
||||
static int tcg_init(MachineState *ms)
|
||||
{
|
||||
TCGState *s = TCG_STATE(current_accel());
|
||||
|
||||
tcg_exec_init(s->tb_size * 1024 * 1024);
|
||||
cpu_interrupt_handler = tcg_handle_interrupt;
|
||||
tcg_exec_init(s->tb_size * 1024 * 1024, s->splitwx_enabled);
|
||||
mttcg_enabled = s->mttcg_enabled;
|
||||
|
||||
/*
|
||||
* Initialize TCG regions only for softmmu.
|
||||
*
|
||||
* This needs to be done later for user mode, because the prologue
|
||||
* generation needs to be delayed so that GUEST_BASE is already set.
|
||||
*/
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_region_init();
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -146,7 +139,7 @@ static void tcg_set_thread(Object *obj, const char *value, Error **errp)
|
|||
if (strcmp(value, "multi") == 0) {
|
||||
if (TCG_OVERSIZED_GUEST) {
|
||||
error_setg(errp, "No MTTCG when guest word size > hosts");
|
||||
} else if (use_icount) {
|
||||
} else if (icount_enabled()) {
|
||||
error_setg(errp, "No MTTCG when icount is enabled");
|
||||
} else {
|
||||
#ifndef TARGET_SUPPORTS_MTTCG
|
||||
|
@ -191,6 +184,18 @@ static void tcg_set_tb_size(Object *obj, Visitor *v,
|
|||
s->tb_size = value;
|
||||
}
|
||||
|
||||
static bool tcg_get_splitwx(Object *obj, Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
return s->splitwx_enabled;
|
||||
}
|
||||
|
||||
static void tcg_set_splitwx(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
TCGState *s = TCG_STATE(obj);
|
||||
s->splitwx_enabled = value;
|
||||
}
|
||||
|
||||
static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(oc);
|
||||
|
@ -208,6 +213,10 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data)
|
|||
object_class_property_set_description(oc, "tb-size",
|
||||
"TCG translation block cache size");
|
||||
|
||||
object_class_property_add_bool(oc, "split-wx",
|
||||
tcg_get_splitwx, tcg_set_splitwx);
|
||||
object_class_property_set_description(oc, "split-wx",
|
||||
"Map jit pages into separate RW and RX regions");
|
||||
}
|
||||
|
||||
static const TypeInfo tcg_accel_type = {
|
||||
|
|
|
@ -27,10 +27,10 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/tb-lookup.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/log.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "exec/tb-lookup.h"
|
||||
|
||||
/* 32-bit helpers */
|
||||
|
||||
|
@ -145,16 +145,18 @@ uint64_t HELPER(ctpop_i64)(uint64_t arg)
|
|||
return ctpop64(arg);
|
||||
}
|
||||
|
||||
void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
||||
const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
uint32_t flags;
|
||||
|
||||
tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, curr_cflags());
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
|
||||
tb = tb_lookup(cpu, pc, cs_base, flags, curr_cflags(cpu));
|
||||
if (tb == NULL) {
|
||||
return tcg_ctx->code_gen_epilogue;
|
||||
return tcg_code_gen_epilogue;
|
||||
}
|
||||
qemu_log_mask_and_addr(CPU_LOG_EXEC, pc,
|
||||
"Chain %d: %p ["
|
||||
|
|
|
@ -24,10 +24,21 @@ DEF_HELPER_FLAGS_1(clrsb_i64, TCG_CALL_NO_RWG_SE, i64, i64)
|
|||
DEF_HELPER_FLAGS_1(ctpop_i32, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(ctpop_i64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_1(lookup_tb_ptr, TCG_CALL_NO_WG_SE, ptr, env)
|
||||
DEF_HELPER_FLAGS_1(lookup_tb_ptr, TCG_CALL_NO_WG_SE, cptr, env)
|
||||
|
||||
DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env)
|
||||
|
||||
#ifndef IN_HELPER_PROTO
|
||||
/*
|
||||
* Pass calls to memset directly to libc, without a thunk in qemu.
|
||||
* Do not re-declare memset, especially since we fudge the type here;
|
||||
* we assume sizeof(void *) == sizeof(size_t), which is true for
|
||||
* all supported hosts.
|
||||
*/
|
||||
#define helper_memset memset
|
||||
DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr)
|
||||
#endif /* IN_HELPER_PROTO */
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
|
||||
DEF_HELPER_FLAGS_5(atomic_cmpxchgb, TCG_CALL_NO_WG,
|
||||
|
|
|
@ -7,4 +7,4 @@ exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
|
|||
exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x"
|
||||
|
||||
# translate-all.c
|
||||
translate_block(void *tb, uintptr_t pc, uint8_t *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p"
|
||||
translate_block(void *tb, uintptr_t pc, const void *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include "trace/trace-accel_tcg.h"
|
File diff suppressed because it is too large
Load Diff
|
@ -17,6 +17,7 @@
|
|||
#include "exec/log.h"
|
||||
#include "exec/translator.h"
|
||||
#include "exec/plugin-gen.h"
|
||||
#include "sysemu/replay.h"
|
||||
|
||||
/* Pairs with tcg_clear_temp_count.
|
||||
To be called by #TranslatorOps.{translate_insn,tb_stop} if
|
||||
|
@ -57,7 +58,8 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
|||
ops->tb_start(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, tb);
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, tb,
|
||||
tb_cflags(db->tb) & CF_MEMI_ONLY);
|
||||
|
||||
while (true) {
|
||||
db->num_insns++;
|
||||
|
@ -99,6 +101,8 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
|||
gen_io_start();
|
||||
ops->translate_insn(db, cpu);
|
||||
} else {
|
||||
/* we should only see CF_MEMI_ONLY for io_recompile */
|
||||
tcg_debug_assert(!(tb_cflags(db->tb) & CF_MEMI_ONLY));
|
||||
ops->translate_insn(db, cpu);
|
||||
}
|
||||
|
||||
|
@ -132,8 +136,8 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
|||
}
|
||||
|
||||
/* The disas_log hook may use these values rather than recompute. */
|
||||
db->tb->size = db->pc_next - db->pc_first;
|
||||
db->tb->icount = db->num_insns;
|
||||
tb->size = db->pc_next - db->pc_first;
|
||||
tb->icount = db->num_insns;
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
|
||||
|
|
|
@ -9,6 +9,10 @@ void cpu_resume(CPUState *cpu)
|
|||
{
|
||||
}
|
||||
|
||||
void cpu_remove_sync(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -18,15 +18,16 @@
|
|||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
#include "disas/disas.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "translate-all.h"
|
||||
#include "exec/translate-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "qemu/atomic128.h"
|
||||
#include "trace-root.h"
|
||||
#include "trace/trace-root.h"
|
||||
#include "trace/mem.h"
|
||||
|
||||
#undef EAX
|
||||
|
@ -49,7 +50,8 @@ __thread uintptr_t helper_retaddr;
|
|||
/* exit the current TB from a signal handler. The host registers are
|
||||
restored in a state compatible with the CPU emulator
|
||||
*/
|
||||
static void cpu_exit_tb_from_sighandler(CPUState *cpu, sigset_t *old_set)
|
||||
static void QEMU_NORETURN cpu_exit_tb_from_sighandler(CPUState *cpu,
|
||||
sigset_t *old_set)
|
||||
{
|
||||
/* XXX: use siglongjmp ? */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
|
@ -88,7 +90,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
|||
* use that value directly. Within cpu_restore_state_from_tb, we
|
||||
* assume PC comes from GETPC(), as used by the helper functions,
|
||||
* so we adjust the address by -GETPC_ADJ to form an address that
|
||||
* is within the call insn, so that the address does not accidentially
|
||||
* is within the call insn, so that the address does not accidentally
|
||||
* match the beginning of the next guest insn. However, when the
|
||||
* pc comes from the signal frame it points to the actual faulting
|
||||
* host memory insn and not the return from a call insn.
|
||||
|
@ -186,7 +188,8 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
|||
clear_helper_retaddr();
|
||||
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
cc->tlb_fill(cpu, address, 0, access_type, MMU_USER_IDX, false, pc);
|
||||
cc->tcg_ops->tlb_fill(cpu, address, 0, access_type,
|
||||
MMU_USER_IDX, false, pc);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
|
@ -210,14 +213,15 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr,
|
|||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!guest_addr_valid(addr) || page_check_range(addr, 1, flags) < 0) {
|
||||
if (!guest_addr_valid_untagged(addr) ||
|
||||
page_check_range(addr, 1, flags) < 0) {
|
||||
if (nonfault) {
|
||||
return TLB_INVALID_MASK;
|
||||
} else {
|
||||
CPUState *cpu = env_cpu(env);
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
cc->tlb_fill(cpu, addr, fault_size, access_type,
|
||||
MMU_USER_IDX, false, ra);
|
||||
cc->tcg_ops->tlb_fill(cpu, addr, fault_size, access_type,
|
||||
MMU_USER_IDX, false, ra);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +235,7 @@ int probe_access_flags(CPUArchState *env, target_ulong addr,
|
|||
int flags;
|
||||
|
||||
flags = probe_access_internal(env, addr, 0, access_type, nonfault, ra);
|
||||
*phost = flags ? NULL : g2h(addr);
|
||||
*phost = flags ? NULL : g2h(env_cpu(env), addr);
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
@ -244,7 +248,7 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
|||
flags = probe_access_internal(env, addr, size, access_type, false, ra);
|
||||
g_assert(flags == 0);
|
||||
|
||||
return size ? g2h(addr) : NULL;
|
||||
return size ? g2h(env_cpu(env), addr) : NULL;
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
|
@ -702,16 +706,51 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
|||
|
||||
#elif defined(__mips__)
|
||||
|
||||
#if defined(__misp16) || defined(__mips_micromips)
|
||||
#error "Unsupported encoding"
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
ucontext_t *uc = puc;
|
||||
greg_t pc = uc->uc_mcontext.pc;
|
||||
int is_write;
|
||||
uintptr_t pc = uc->uc_mcontext.pc;
|
||||
uint32_t insn = *(uint32_t *)pc;
|
||||
int is_write = 0;
|
||||
|
||||
/* Detect all store instructions at program counter. */
|
||||
switch((insn >> 26) & 077) {
|
||||
case 050: /* SB */
|
||||
case 051: /* SH */
|
||||
case 052: /* SWL */
|
||||
case 053: /* SW */
|
||||
case 054: /* SDL */
|
||||
case 055: /* SDR */
|
||||
case 056: /* SWR */
|
||||
case 070: /* SC */
|
||||
case 071: /* SWC1 */
|
||||
case 074: /* SCD */
|
||||
case 075: /* SDC1 */
|
||||
case 077: /* SD */
|
||||
#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
|
||||
case 072: /* SWC2 */
|
||||
case 076: /* SDC2 */
|
||||
#endif
|
||||
is_write = 1;
|
||||
break;
|
||||
case 023: /* COP1X */
|
||||
/* Required in all versions of MIPS64 since
|
||||
MIPS64r1 and subsequent versions of MIPS32r2. */
|
||||
switch (insn & 077) {
|
||||
case 010: /* SWXC1 */
|
||||
case 011: /* SDXC1 */
|
||||
case 015: /* SUXC1 */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* XXX: compute is_write */
|
||||
is_write = 0;
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
|
@ -804,7 +843,7 @@ uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_UB, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldub_p(g2h(ptr));
|
||||
ret = ldub_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -815,7 +854,7 @@ int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_SB, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldsb_p(g2h(ptr));
|
||||
ret = ldsb_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -826,7 +865,7 @@ uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = lduw_be_p(g2h(ptr));
|
||||
ret = lduw_be_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -837,7 +876,7 @@ int cpu_ldsw_be_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_BESW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldsw_be_p(g2h(ptr));
|
||||
ret = ldsw_be_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -848,7 +887,7 @@ uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldl_be_p(g2h(ptr));
|
||||
ret = ldl_be_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -859,7 +898,7 @@ uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldq_be_p(g2h(ptr));
|
||||
ret = ldq_be_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -870,7 +909,7 @@ uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = lduw_le_p(g2h(ptr));
|
||||
ret = lduw_le_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -881,7 +920,7 @@ int cpu_ldsw_le_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_LESW, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldsw_le_p(g2h(ptr));
|
||||
ret = ldsw_le_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -892,7 +931,7 @@ uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldl_le_p(g2h(ptr));
|
||||
ret = ldl_le_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -903,7 +942,7 @@ uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr ptr)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, false);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
ret = ldq_le_p(g2h(ptr));
|
||||
ret = ldq_le_p(g2h(env_cpu(env), ptr));
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1013,7 +1052,7 @@ void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_UB, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stb_p(g2h(ptr), val);
|
||||
stb_p(g2h(env_cpu(env), ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
|
@ -1022,7 +1061,7 @@ void cpu_stw_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stw_be_p(g2h(ptr), val);
|
||||
stw_be_p(g2h(env_cpu(env), ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
|
@ -1031,7 +1070,7 @@ void cpu_stl_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stl_be_p(g2h(ptr), val);
|
||||
stl_be_p(g2h(env_cpu(env), ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
|
@ -1040,7 +1079,7 @@ void cpu_stq_be_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stq_be_p(g2h(ptr), val);
|
||||
stq_be_p(g2h(env_cpu(env), ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
|
@ -1049,7 +1088,7 @@ void cpu_stw_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stw_le_p(g2h(ptr), val);
|
||||
stw_le_p(g2h(env_cpu(env), ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
|
@ -1058,7 +1097,7 @@ void cpu_stl_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stl_le_p(g2h(ptr), val);
|
||||
stl_le_p(g2h(env_cpu(env), ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
|
@ -1067,7 +1106,7 @@ void cpu_stq_le_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
|
|||
uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, true);
|
||||
|
||||
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
|
||||
stq_le_p(g2h(ptr), val);
|
||||
stq_le_p(g2h(env_cpu(env), ptr), val);
|
||||
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
|
||||
}
|
||||
|
||||
|
@ -1132,7 +1171,7 @@ uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr)
|
|||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldub_p(g2h(ptr));
|
||||
ret = ldub_p(g2h_untagged(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
@ -1142,7 +1181,7 @@ uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr)
|
|||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = lduw_p(g2h(ptr));
|
||||
ret = lduw_p(g2h_untagged(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
@ -1152,7 +1191,7 @@ uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr)
|
|||
uint32_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldl_p(g2h(ptr));
|
||||
ret = ldl_p(g2h_untagged(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
@ -1162,7 +1201,7 @@ uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr)
|
|||
uint64_t ret;
|
||||
|
||||
set_helper_retaddr(1);
|
||||
ret = ldq_p(g2h(ptr));
|
||||
ret = ldq_p(g2h_untagged(ptr));
|
||||
clear_helper_retaddr();
|
||||
return ret;
|
||||
}
|
||||
|
@ -1175,7 +1214,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
|||
if (unlikely(addr & (size - 1))) {
|
||||
cpu_loop_exit_atomic(env_cpu(env), retaddr);
|
||||
}
|
||||
void *ret = g2h(addr);
|
||||
void *ret = g2h(env_cpu(env), addr);
|
||||
set_helper_retaddr(retaddr);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1189,7 +1228,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
|||
#define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END))
|
||||
#define EXTRA_ARGS
|
||||
|
||||
#include "atomic_common.inc.c"
|
||||
#include "atomic_common.c.inc"
|
||||
|
||||
#define DATA_SIZE 1
|
||||
#include "atomic_template.h"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
obj-y += xen-all.o
|
|
@ -0,0 +1 @@
|
|||
specific_ss.add(when: 'CONFIG_XEN', if_true: files('xen-all.c'))
|
|
@ -15,7 +15,8 @@
|
|||
#include "hw/xen/xen-legacy-backend.h"
|
||||
#include "hw/xen/xen_pt.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/accel.h"
|
||||
#include "qemu/accel.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/xen.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "migration/misc.h"
|
||||
|
@ -121,7 +122,7 @@ static void xenstore_record_dm_state(struct xs_handle *xs, const char *state)
|
|||
}
|
||||
|
||||
|
||||
static void xen_change_state_handler(void *opaque, int running,
|
||||
static void xen_change_state_handler(void *opaque, bool running,
|
||||
RunState state)
|
||||
{
|
||||
if (running) {
|
||||
|
@ -214,9 +215,24 @@ static const TypeInfo xen_accel_type = {
|
|||
.class_init = xen_accel_class_init,
|
||||
};
|
||||
|
||||
static void xen_accel_ops_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||
|
||||
ops->create_vcpu_thread = dummy_start_vcpu_thread;
|
||||
}
|
||||
|
||||
static const TypeInfo xen_accel_ops_type = {
|
||||
.name = ACCEL_OPS_NAME("xen"),
|
||||
|
||||
.parent = TYPE_ACCEL_OPS,
|
||||
.class_init = xen_accel_ops_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void xen_type_init(void)
|
||||
{
|
||||
type_register_static(&xen_accel_type);
|
||||
type_register_static(&xen_accel_ops_type);
|
||||
}
|
||||
|
||||
type_init(xen_type_init);
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
common-obj-y = audio.o audio_legacy.o noaudio.o wavaudio.o mixeng.o
|
||||
common-obj-$(CONFIG_SPICE) += spiceaudio.o
|
||||
common-obj-$(CONFIG_AUDIO_COREAUDIO) += coreaudio.o
|
||||
common-obj-$(CONFIG_AUDIO_DSOUND) += dsoundaudio.o
|
||||
common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
|
||||
common-obj-y += wavcapture.o
|
||||
|
||||
coreaudio.o-libs := $(COREAUDIO_LIBS)
|
||||
dsoundaudio.o-libs := $(DSOUND_LIBS)
|
||||
|
||||
# alsa module
|
||||
common-obj-$(CONFIG_AUDIO_ALSA) += alsa.mo
|
||||
alsa.mo-objs = alsaaudio.o
|
||||
alsa.mo-libs := $(ALSA_LIBS)
|
||||
|
||||
# oss module
|
||||
common-obj-$(CONFIG_AUDIO_OSS) += oss.mo
|
||||
oss.mo-objs = ossaudio.o
|
||||
oss.mo-libs := $(OSS_LIBS)
|
||||
|
||||
# pulseaudio module
|
||||
common-obj-$(CONFIG_AUDIO_PA) += pa.mo
|
||||
pa.mo-objs = paaudio.o
|
||||
pa.mo-libs := $(PULSE_LIBS)
|
||||
|
||||
# sdl module
|
||||
common-obj-$(CONFIG_AUDIO_SDL) += sdl.mo
|
||||
sdl.mo-objs = sdlaudio.o
|
||||
sdl.mo-cflags := $(SDL_CFLAGS)
|
||||
sdl.mo-libs := $(SDL_LIBS)
|
||||
|
||||
# jack module
|
||||
common-obj-$(CONFIG_AUDIO_JACK) += jack.mo
|
||||
jack.mo-objs = jackaudio.o
|
||||
jack.mo-libs := $(JACK_LIBS)
|
|
@ -278,32 +278,28 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
|
|||
case AUDIO_FORMAT_S16:
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_S16_BE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return SND_PCM_FORMAT_S16_LE;
|
||||
}
|
||||
|
||||
case AUDIO_FORMAT_U16:
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_U16_BE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return SND_PCM_FORMAT_U16_LE;
|
||||
}
|
||||
|
||||
case AUDIO_FORMAT_S32:
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_S32_BE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return SND_PCM_FORMAT_S32_LE;
|
||||
}
|
||||
|
||||
case AUDIO_FORMAT_U32:
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_U32_BE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return SND_PCM_FORMAT_U32_LE;
|
||||
}
|
||||
|
||||
|
@ -599,7 +595,7 @@ static int alsa_open(bool in, struct alsa_params_req *req,
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
alsa_dump_info(req, obt, obtfmt, pdo);
|
||||
alsa_dump_info(req, obt, obtfmt, apdo);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
|
@ -722,8 +718,7 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
|
|||
alsa_logerr (err, "Could not stop %s\n", typ);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
err = snd_pcm_prepare (handle);
|
||||
if (err < 0) {
|
||||
alsa_logerr (err, "Could not prepare handle for %s\n", typ);
|
||||
|
@ -929,6 +924,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
|
|||
.init_in = alsa_init_in,
|
||||
.fini_in = alsa_fini_in,
|
||||
.read = alsa_read,
|
||||
.run_buffer_in = audio_generic_run_buffer_in,
|
||||
.enable_in = alsa_enable_in,
|
||||
};
|
||||
|
||||
|
|
187
audio/audio.c
187
audio/audio.c
|
@ -34,6 +34,7 @@
|
|||
#include "qemu/module.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define AUDIO_CAP "audio"
|
||||
|
@ -103,9 +104,6 @@ const struct mixeng_volume nominal_volume = {
|
|||
|
||||
static bool legacy_config = true;
|
||||
|
||||
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
|
||||
#error No its not
|
||||
#else
|
||||
int audio_bug (const char *funcname, int cond)
|
||||
{
|
||||
if (cond) {
|
||||
|
@ -118,25 +116,11 @@ int audio_bug (const char *funcname, int cond)
|
|||
AUD_log (NULL, "I am sorry\n");
|
||||
}
|
||||
AUD_log (NULL, "Context:\n");
|
||||
|
||||
#if defined AUDIO_BREAKPOINT_ON_BUG
|
||||
# if defined HOST_I386
|
||||
# if defined __GNUC__
|
||||
__asm__ ("int3");
|
||||
# elif defined _MSC_VER
|
||||
_asm _emit 0xcc;
|
||||
# else
|
||||
abort ();
|
||||
# endif
|
||||
# else
|
||||
abort ();
|
||||
# endif
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
return cond;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int audio_bits_to_index (int bits)
|
||||
{
|
||||
|
@ -360,8 +344,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
|||
|
||||
if (info->is_signed || info->is_float) {
|
||||
memset(buf, 0x00, len * info->bytes_per_frame);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
switch (info->bits) {
|
||||
case 8:
|
||||
memset(buf, 0x80, len * info->bytes_per_frame);
|
||||
|
@ -600,8 +583,7 @@ static size_t audio_pcm_sw_get_rpos_in(SWVoiceIn *sw)
|
|||
rpos = hw->conv_buf->pos - live;
|
||||
if (rpos >= 0) {
|
||||
return rpos;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return hw->conv_buf->size + rpos;
|
||||
}
|
||||
}
|
||||
|
@ -804,10 +786,14 @@ static int audio_is_timer_needed(AudioState *s)
|
|||
HWVoiceOut *hwo = NULL;
|
||||
|
||||
while ((hwo = audio_pcm_hw_find_any_enabled_out(s, hwo))) {
|
||||
if (!hwo->poll_mode) return 1;
|
||||
if (!hwo->poll_mode) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
while ((hwi = audio_pcm_hw_find_any_enabled_in(s, hwi))) {
|
||||
if (!hwi->poll_mode) return 1;
|
||||
if (!hwi->poll_mode) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -924,8 +910,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
|||
audio_reset_timer (s);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (hw->enabled) {
|
||||
int nb_active = 0;
|
||||
|
||||
|
@ -972,8 +957,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
|
|||
}
|
||||
}
|
||||
sw->total_hw_samples_acquired = hw->total_samples_captured;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (hw->enabled) {
|
||||
int nb_active = 0;
|
||||
|
||||
|
@ -1089,14 +1073,18 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
|||
size_t clipped = 0;
|
||||
|
||||
while (live) {
|
||||
size_t size, decr, proc;
|
||||
size_t size = live * hw->info.bytes_per_frame;
|
||||
size_t decr, proc;
|
||||
void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
|
||||
if (!buf || size == 0) {
|
||||
|
||||
if (size == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
decr = MIN(size / hw->info.bytes_per_frame, live);
|
||||
audio_pcm_hw_clip_out(hw, buf, decr);
|
||||
if (buf) {
|
||||
audio_pcm_hw_clip_out(hw, buf, decr);
|
||||
}
|
||||
proc = hw->pcm_ops->put_buffer_out(hw, buf,
|
||||
decr * hw->info.bytes_per_frame) /
|
||||
hw->info.bytes_per_frame;
|
||||
|
@ -1144,7 +1132,7 @@ static void audio_run_out (AudioState *s)
|
|||
|
||||
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
|
||||
size_t played, live, prev_rpos, free;
|
||||
int nb_live, cleanup_required;
|
||||
int nb_live;
|
||||
|
||||
live = audio_pcm_hw_get_live_out (hw, &nb_live);
|
||||
if (!nb_live) {
|
||||
|
@ -1182,6 +1170,9 @@ static void audio_run_out (AudioState *s)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (hw->pcm_ops->run_buffer_out) {
|
||||
hw->pcm_ops->run_buffer_out(hw);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1203,7 +1194,6 @@ static void audio_run_out (AudioState *s)
|
|||
audio_capture_mix_and_clear (hw, prev_rpos, played);
|
||||
}
|
||||
|
||||
cleanup_required = 0;
|
||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||
if (!sw->active && sw->empty) {
|
||||
continue;
|
||||
|
@ -1219,7 +1209,6 @@ static void audio_run_out (AudioState *s)
|
|||
|
||||
if (!sw->total_hw_samples_mixed) {
|
||||
sw->empty = 1;
|
||||
cleanup_required |= !sw->active && !sw->callback.fn;
|
||||
}
|
||||
|
||||
if (sw->active) {
|
||||
|
@ -1229,19 +1218,6 @@ static void audio_run_out (AudioState *s)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanup_required) {
|
||||
SWVoiceOut *sw1;
|
||||
|
||||
sw = hw->sw_head.lh_first;
|
||||
while (sw) {
|
||||
sw1 = sw->entries.le_next;
|
||||
if (!sw->active && !sw->callback.fn) {
|
||||
audio_close_out (sw);
|
||||
}
|
||||
sw = sw1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1250,6 +1226,10 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
|
|||
size_t conv = 0;
|
||||
STSampleBuffer *conv_buf = hw->conv_buf;
|
||||
|
||||
if (hw->pcm_ops->run_buffer_in) {
|
||||
hw->pcm_ops->run_buffer_in(hw);
|
||||
}
|
||||
|
||||
while (samples) {
|
||||
size_t proc;
|
||||
size_t size = samples * hw->info.bytes_per_frame;
|
||||
|
@ -1257,7 +1237,6 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
|
|||
|
||||
assert(size % hw->info.bytes_per_frame == 0);
|
||||
if (size == 0) {
|
||||
hw->pcm_ops->put_buffer_in(hw, buf, size);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1391,14 +1370,11 @@ void audio_run(AudioState *s, const char *msg)
|
|||
#endif
|
||||
}
|
||||
|
||||
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||
void audio_generic_run_buffer_in(HWVoiceIn *hw)
|
||||
{
|
||||
ssize_t start;
|
||||
|
||||
if (unlikely(!hw->buf_emul)) {
|
||||
size_t calc_size = hw->conv_buf->size * hw->info.bytes_per_frame;
|
||||
hw->buf_emul = g_malloc(calc_size);
|
||||
hw->size_emul = calc_size;
|
||||
hw->size_emul = hw->samples * hw->info.bytes_per_frame;
|
||||
hw->buf_emul = g_malloc(hw->size_emul);
|
||||
hw->pos_emul = hw->pending_emul = 0;
|
||||
}
|
||||
|
||||
|
@ -1413,8 +1389,12 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
||||
{
|
||||
ssize_t start = (ssize_t)hw->pos_emul - hw->pending_emul;
|
||||
|
||||
start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
|
||||
if (start < 0) {
|
||||
start += hw->size_emul;
|
||||
}
|
||||
|
@ -1456,10 +1436,8 @@ void audio_generic_run_buffer_out(HWVoiceOut *hw)
|
|||
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||
{
|
||||
if (unlikely(!hw->buf_emul)) {
|
||||
size_t calc_size = hw->mix_buf->size * hw->info.bytes_per_frame;
|
||||
|
||||
hw->buf_emul = g_malloc(calc_size);
|
||||
hw->size_emul = calc_size;
|
||||
hw->size_emul = hw->samples * hw->info.bytes_per_frame;
|
||||
hw->buf_emul = g_malloc(hw->size_emul);
|
||||
hw->pos_emul = hw->pending_emul = 0;
|
||||
}
|
||||
|
||||
|
@ -1481,22 +1459,58 @@ 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 dst_size, copy_size;
|
||||
void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size);
|
||||
copy_size = MIN(size, dst_size);
|
||||
size_t total = 0;
|
||||
|
||||
memcpy(dst, buf, copy_size);
|
||||
return hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
|
||||
while (total < size) {
|
||||
size_t dst_size = size - total;
|
||||
size_t copy_size, proc;
|
||||
void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size);
|
||||
|
||||
if (dst_size == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
copy_size = MIN(size - total, dst_size);
|
||||
if (dst) {
|
||||
memcpy(dst, (char *)buf + total, copy_size);
|
||||
}
|
||||
proc = hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
|
||||
total += proc;
|
||||
|
||||
if (proc == 0 || proc < copy_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hw->pcm_ops->run_buffer_out) {
|
||||
hw->pcm_ops->run_buffer_out(hw);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
|
||||
{
|
||||
void *src = hw->pcm_ops->get_buffer_in(hw, &size);
|
||||
size_t total = 0;
|
||||
|
||||
memcpy(buf, src, size);
|
||||
hw->pcm_ops->put_buffer_in(hw, src, size);
|
||||
if (hw->pcm_ops->run_buffer_in) {
|
||||
hw->pcm_ops->run_buffer_in(hw);
|
||||
}
|
||||
|
||||
return size;
|
||||
while (total < size) {
|
||||
size_t src_size = size - total;
|
||||
void *src = hw->pcm_ops->get_buffer_in(hw, &src_size);
|
||||
|
||||
if (src_size == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy((char *)buf + total, src, src_size);
|
||||
hw->pcm_ops->put_buffer_in(hw, src, src_size);
|
||||
total += src_size;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static int audio_driver_init(AudioState *s, struct audio_driver *drv,
|
||||
|
@ -1518,8 +1532,7 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv,
|
|||
audio_init_nb_voices_in(s, drv);
|
||||
s->drv = drv;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (msg) {
|
||||
dolog("Could not init `%s' audio driver\n", drv->name);
|
||||
}
|
||||
|
@ -1527,7 +1540,7 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv,
|
|||
}
|
||||
}
|
||||
|
||||
static void audio_vm_change_state_handler (void *opaque, int running,
|
||||
static void audio_vm_change_state_handler (void *opaque, bool running,
|
||||
RunState state)
|
||||
{
|
||||
AudioState *s = opaque;
|
||||
|
@ -1549,13 +1562,6 @@ static void audio_vm_change_state_handler (void *opaque, int running,
|
|||
audio_reset_timer (s);
|
||||
}
|
||||
|
||||
static bool is_cleaning_up;
|
||||
|
||||
bool audio_is_cleaning_up(void)
|
||||
{
|
||||
return is_cleaning_up;
|
||||
}
|
||||
|
||||
static void free_audio_state(AudioState *s)
|
||||
{
|
||||
HWVoiceOut *hwo, *hwon;
|
||||
|
@ -1608,7 +1614,6 @@ static void free_audio_state(AudioState *s)
|
|||
|
||||
void audio_cleanup(void)
|
||||
{
|
||||
is_cleaning_up = true;
|
||||
while (!QTAILQ_EMPTY(&audio_states)) {
|
||||
AudioState *s = QTAILQ_FIRST(&audio_states);
|
||||
QTAILQ_REMOVE(&audio_states, s, list);
|
||||
|
@ -1658,6 +1663,23 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
|
|||
/* silence gcc warning about uninitialized variable */
|
||||
AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head);
|
||||
|
||||
if (using_spice) {
|
||||
/*
|
||||
* When using spice allow the spice audio driver being picked
|
||||
* as default.
|
||||
*
|
||||
* Temporary hack. Using audio devices without explicit
|
||||
* audiodev= property is already deprecated. Same goes for
|
||||
* the -soundhw switch. Once this support gets finally
|
||||
* removed we can also drop the concept of a default audio
|
||||
* backend and this can go away.
|
||||
*/
|
||||
driver = audio_driver_lookup("spice");
|
||||
if (driver) {
|
||||
driver->can_be_default = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
/* -audiodev option */
|
||||
legacy_config = false;
|
||||
|
@ -1674,7 +1696,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
|
|||
head = audio_handle_legacy_opts();
|
||||
/*
|
||||
* In case of legacy initialization, all Audiodevs in the list will have
|
||||
* the same configuration (except the driver), so it does't matter which
|
||||
* the same configuration (except the driver), so it doesn't matter which
|
||||
* one we chose. We need an Audiodev to set up AudioState before we can
|
||||
* init a driver. Also note that dev at this point is still in the
|
||||
* list.
|
||||
|
@ -1825,8 +1847,7 @@ CaptureVoiceOut *AUD_add_capture(
|
|||
if (cap) {
|
||||
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||
return cap;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
HWVoiceOut *hw;
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
|
@ -1972,7 +1993,7 @@ void audio_create_pdos(Audiodev *dev)
|
|||
CASE(JACK, jack, Jack);
|
||||
CASE(OSS, oss, Oss);
|
||||
CASE(PA, pa, Pa);
|
||||
CASE(SDL, sdl, );
|
||||
CASE(SDL, sdl, Sdl);
|
||||
CASE(SPICE, spice, );
|
||||
CASE(WAV, wav, );
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "qemu/queue.h"
|
||||
#include "qapi/qapi-types-audio.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
|
||||
typedef void (*audio_callback_fn) (void *opaque, int avail);
|
||||
|
||||
|
@ -160,7 +161,6 @@ static inline void *advance (void *p, int incr)
|
|||
int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
|
||||
int freq, int bits, int nchannels);
|
||||
|
||||
bool audio_is_cleaning_up(void);
|
||||
void audio_cleanup(void);
|
||||
|
||||
void audio_sample_to_uint64(const void *samples, int pos,
|
||||
|
|
|
@ -172,12 +172,14 @@ struct audio_pcm_ops {
|
|||
int (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
|
||||
void (*fini_in) (HWVoiceIn *hw);
|
||||
size_t (*read) (HWVoiceIn *hw, void *buf, size_t size);
|
||||
void (*run_buffer_in)(HWVoiceIn *hw);
|
||||
void *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
|
||||
void (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
|
||||
void (*enable_in)(HWVoiceIn *hw, bool enable);
|
||||
void (*volume_in)(HWVoiceIn *hw, Volume *vol);
|
||||
};
|
||||
|
||||
void audio_generic_run_buffer_in(HWVoiceIn *hw);
|
||||
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_run_buffer_out(HWVoiceOut *hw);
|
||||
|
|
|
@ -286,7 +286,8 @@ static void handle_sdl(Audiodev *dev)
|
|||
{
|
||||
/* SDL is output only */
|
||||
get_samples_to_usecs("QEMU_SDL_SAMPLES", &dev->u.sdl.out->buffer_length,
|
||||
&dev->u.sdl.out->has_buffer_length, dev->u.sdl.out);
|
||||
&dev->u.sdl.out->has_buffer_length,
|
||||
qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.out));
|
||||
}
|
||||
|
||||
/* wav */
|
||||
|
|
|
@ -47,8 +47,7 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
|
|||
#ifdef DAC
|
||||
dolog ("Driver `%s' does not support " NAME "\n", drv->name);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
|
||||
drv->name,
|
||||
glue (s->nb_hw_voices_, TYPE),
|
||||
|
@ -204,13 +203,13 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
|
|||
|
||||
if (!hw->sw_head.lh_first) {
|
||||
#ifdef DAC
|
||||
audio_detach_capture (hw);
|
||||
audio_detach_capture(hw);
|
||||
#endif
|
||||
QLIST_REMOVE (hw, entries);
|
||||
glue (hw->pcm_ops->fini_, TYPE) (hw);
|
||||
glue (s->nb_hw_voices_, TYPE) += 1;
|
||||
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
|
||||
g_free (hw);
|
||||
QLIST_REMOVE(hw, entries);
|
||||
glue(hw->pcm_ops->fini_, TYPE) (hw);
|
||||
glue(s->nb_hw_voices_, TYPE) += 1;
|
||||
glue(audio_pcm_hw_free_resources_ , TYPE) (hw);
|
||||
g_free(hw);
|
||||
*hwp = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -337,7 +336,7 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
|||
case AUDIODEV_DRIVER_PA:
|
||||
return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
|
||||
case AUDIODEV_DRIVER_SDL:
|
||||
return dev->u.sdl.TYPE;
|
||||
return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE);
|
||||
case AUDIODEV_DRIVER_SPICE:
|
||||
return dev->u.spice.TYPE;
|
||||
case AUDIODEV_DRIVER_WAV:
|
||||
|
@ -387,8 +386,7 @@ static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
|
|||
|
||||
if (pdo->fixed_settings) {
|
||||
hw_as = audiodev_to_audsettings(pdo);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
hw_as = *as;
|
||||
}
|
||||
|
||||
|
@ -498,8 +496,7 @@ SW *glue (AUD_open_, TYPE) (
|
|||
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
|
||||
if (!sw) {
|
||||
dolog ("Failed to create voice `%s'\n", name);
|
||||
|
@ -553,8 +550,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
|
|||
|
||||
if (cur_ts >= old_ts) {
|
||||
delta = cur_ts - old_ts;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
delta = UINT64_MAX - old_ts + cur_ts;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#define AUDIO_CAP "win-int"
|
||||
#include <windows.h>
|
||||
#include <mmreg.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "audio.h"
|
||||
|
@ -16,7 +17,6 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
|
|||
{
|
||||
memset (wfx, 0, sizeof (*wfx));
|
||||
|
||||
wfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx->nChannels = as->nchannels;
|
||||
wfx->nSamplesPerSec = as->freq;
|
||||
wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
|
||||
|
@ -26,11 +26,13 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
|
|||
switch (as->fmt) {
|
||||
case AUDIO_FORMAT_S8:
|
||||
case AUDIO_FORMAT_U8:
|
||||
wfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx->wBitsPerSample = 8;
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_S16:
|
||||
case AUDIO_FORMAT_U16:
|
||||
wfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx->wBitsPerSample = 16;
|
||||
wfx->nAvgBytesPerSec <<= 1;
|
||||
wfx->nBlockAlign <<= 1;
|
||||
|
@ -38,13 +40,21 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
|
|||
|
||||
case AUDIO_FORMAT_S32:
|
||||
case AUDIO_FORMAT_U32:
|
||||
wfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx->wBitsPerSample = 32;
|
||||
wfx->nAvgBytesPerSec <<= 2;
|
||||
wfx->nBlockAlign <<= 2;
|
||||
break;
|
||||
|
||||
case AUDIO_FORMAT_F32:
|
||||
wfx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
wfx->wBitsPerSample = 32;
|
||||
wfx->nAvgBytesPerSec <<= 2;
|
||||
wfx->nBlockAlign <<= 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", as->freq);
|
||||
dolog("Internal logic error: Bad audio format %d\n", as->fmt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -54,12 +64,6 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
|
|||
int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
|
||||
struct audsettings *as)
|
||||
{
|
||||
if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
|
||||
dolog ("Invalid wave format, tag is not PCM, but %d\n",
|
||||
wfx->wFormatTag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!wfx->nSamplesPerSec) {
|
||||
dolog ("Invalid wave format, frequency is zero\n");
|
||||
return -1;
|
||||
|
@ -83,23 +87,42 @@ int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
|
|||
return -1;
|
||||
}
|
||||
|
||||
switch (wfx->wBitsPerSample) {
|
||||
case 8:
|
||||
as->fmt = AUDIO_FORMAT_U8;
|
||||
break;
|
||||
if (wfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
switch (wfx->wBitsPerSample) {
|
||||
case 8:
|
||||
as->fmt = AUDIO_FORMAT_U8;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
as->fmt = AUDIO_FORMAT_S16;
|
||||
break;
|
||||
case 16:
|
||||
as->fmt = AUDIO_FORMAT_S16;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
as->fmt = AUDIO_FORMAT_S32;
|
||||
break;
|
||||
case 32:
|
||||
as->fmt = AUDIO_FORMAT_S32;
|
||||
break;
|
||||
|
||||
default:
|
||||
dolog ("Invalid wave format, bits per sample is not "
|
||||
"8, 16 or 32, but %d\n",
|
||||
wfx->wBitsPerSample);
|
||||
default:
|
||||
dolog("Invalid PCM wave format, bits per sample is not "
|
||||
"8, 16 or 32, but %d\n",
|
||||
wfx->wBitsPerSample);
|
||||
return -1;
|
||||
}
|
||||
} else if (wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
|
||||
switch (wfx->wBitsPerSample) {
|
||||
case 32:
|
||||
as->fmt = AUDIO_FORMAT_F32;
|
||||
break;
|
||||
|
||||
default:
|
||||
dolog("Invalid IEEE_FLOAT wave format, bits per sample is not "
|
||||
"32, but %d\n",
|
||||
wfx->wBitsPerSample);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
dolog("Invalid wave format, tag is not PCM and not IEEE_FLOAT, "
|
||||
"but %d\n",
|
||||
wfx->wFormatTag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,33 +32,30 @@
|
|||
#define AUDIO_CAP "coreaudio"
|
||||
#include "audio_int.h"
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_6
|
||||
#define MAC_OS_X_VERSION_10_6 1060
|
||||
#endif
|
||||
|
||||
typedef struct coreaudioVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
pthread_mutex_t mutex;
|
||||
AudioDeviceID outputDeviceID;
|
||||
int frameSizeSetting;
|
||||
uint32_t bufferCount;
|
||||
UInt32 audioDevicePropertyBufferFrameSize;
|
||||
AudioStreamBasicDescription outputStreamBasicDescription;
|
||||
AudioDeviceIOProcID ioprocid;
|
||||
bool enabled;
|
||||
} coreaudioVoiceOut;
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
/* The APIs used here only become available from 10.6 */
|
||||
static const AudioObjectPropertyAddress voice_addr = {
|
||||
kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
static OSStatus coreaudio_get_voice(AudioDeviceID *id)
|
||||
{
|
||||
UInt32 size = sizeof(*id);
|
||||
AudioObjectPropertyAddress addr = {
|
||||
kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
return AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
||||
&addr,
|
||||
&voice_addr,
|
||||
0,
|
||||
NULL,
|
||||
&size,
|
||||
|
@ -169,108 +166,12 @@ static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
|
|||
&size,
|
||||
result);
|
||||
}
|
||||
#else
|
||||
/* Legacy versions of functions using deprecated APIs */
|
||||
|
||||
static OSStatus coreaudio_get_voice(AudioDeviceID *id)
|
||||
{
|
||||
UInt32 size = sizeof(*id);
|
||||
|
||||
return AudioHardwareGetProperty(
|
||||
kAudioHardwarePropertyDefaultOutputDevice,
|
||||
&size,
|
||||
id);
|
||||
}
|
||||
|
||||
static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
|
||||
AudioValueRange *framerange)
|
||||
{
|
||||
UInt32 size = sizeof(*framerange);
|
||||
|
||||
return AudioDeviceGetProperty(
|
||||
id,
|
||||
0,
|
||||
0,
|
||||
kAudioDevicePropertyBufferFrameSizeRange,
|
||||
&size,
|
||||
framerange);
|
||||
}
|
||||
|
||||
static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
|
||||
{
|
||||
UInt32 size = sizeof(*framesize);
|
||||
|
||||
return AudioDeviceGetProperty(
|
||||
id,
|
||||
0,
|
||||
false,
|
||||
kAudioDevicePropertyBufferFrameSize,
|
||||
&size,
|
||||
framesize);
|
||||
}
|
||||
|
||||
static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
|
||||
{
|
||||
UInt32 size = sizeof(*framesize);
|
||||
|
||||
return AudioDeviceSetProperty(
|
||||
id,
|
||||
NULL,
|
||||
0,
|
||||
false,
|
||||
kAudioDevicePropertyBufferFrameSize,
|
||||
size,
|
||||
framesize);
|
||||
}
|
||||
|
||||
static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
|
||||
AudioStreamBasicDescription *d)
|
||||
{
|
||||
UInt32 size = sizeof(*d);
|
||||
|
||||
return AudioDeviceGetProperty(
|
||||
id,
|
||||
0,
|
||||
false,
|
||||
kAudioDevicePropertyStreamFormat,
|
||||
&size,
|
||||
d);
|
||||
}
|
||||
|
||||
static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
|
||||
AudioStreamBasicDescription *d)
|
||||
{
|
||||
UInt32 size = sizeof(*d);
|
||||
|
||||
return AudioDeviceSetProperty(
|
||||
id,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
kAudioDevicePropertyStreamFormat,
|
||||
size,
|
||||
d);
|
||||
}
|
||||
|
||||
static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
|
||||
{
|
||||
UInt32 size = sizeof(*result);
|
||||
|
||||
return AudioDeviceGetProperty(
|
||||
id,
|
||||
0,
|
||||
0,
|
||||
kAudioDevicePropertyDeviceIsRunning,
|
||||
&size,
|
||||
result);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void coreaudio_logstatus (OSStatus status)
|
||||
{
|
||||
const char *str = "BUG";
|
||||
|
||||
switch(status) {
|
||||
switch (status) {
|
||||
case kAudioHardwareNoError:
|
||||
str = "kAudioHardwareNoError";
|
||||
break;
|
||||
|
@ -356,17 +257,8 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
|
|||
coreaudio_logstatus (status);
|
||||
}
|
||||
|
||||
static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
|
||||
{
|
||||
OSStatus status;
|
||||
UInt32 result = 0;
|
||||
status = coreaudio_get_isrunning(outputDeviceID, &result);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr(status,
|
||||
"Could not determine whether Device is playing\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#define coreaudio_playback_logerr(status, ...) \
|
||||
coreaudio_logerr2(status, "playback", __VA_ARGS__)
|
||||
|
||||
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
|
||||
{
|
||||
|
@ -421,12 +313,12 @@ COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
|
|||
/* callback to feed audiooutput buffer */
|
||||
static OSStatus audioDeviceIOProc(
|
||||
AudioDeviceID inDevice,
|
||||
const AudioTimeStamp* inNow,
|
||||
const AudioBufferList* inInputData,
|
||||
const AudioTimeStamp* inInputTime,
|
||||
AudioBufferList* outOutputData,
|
||||
const AudioTimeStamp* inOutputTime,
|
||||
void* hwptr)
|
||||
const AudioTimeStamp *inNow,
|
||||
const AudioBufferList *inInputData,
|
||||
const AudioTimeStamp *inInputTime,
|
||||
AudioBufferList *outOutputData,
|
||||
const AudioTimeStamp *inOutputTime,
|
||||
void *hwptr)
|
||||
{
|
||||
UInt32 frameCount, pending_frames;
|
||||
void *out = outOutputData->mBuffers[0].mData;
|
||||
|
@ -439,6 +331,11 @@ static OSStatus audioDeviceIOProc(
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (inDevice != core->outputDeviceID) {
|
||||
coreaudio_unlock (core, "audioDeviceIOProc(old device)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
frameCount = core->audioDevicePropertyBufferFrameSize;
|
||||
pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
|
||||
|
||||
|
@ -471,156 +368,298 @@ static OSStatus audioDeviceIOProc(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
void *drv_opaque)
|
||||
static OSStatus init_out_device(coreaudioVoiceOut *core)
|
||||
{
|
||||
OSStatus status;
|
||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||
int err;
|
||||
const char *typ = "playback";
|
||||
AudioValueRange frameRange;
|
||||
Audiodev *dev = drv_opaque;
|
||||
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
|
||||
int frames;
|
||||
struct audsettings fake_as;
|
||||
|
||||
/* create mutex */
|
||||
err = pthread_mutex_init(&core->mutex, NULL);
|
||||
if (err) {
|
||||
dolog("Could not create mutex\nReason: %s\n", strerror (err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
fake_as = *as;
|
||||
as = &fake_as;
|
||||
as->fmt = AUDIO_FORMAT_F32;
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
|
||||
status = coreaudio_get_voice(&core->outputDeviceID);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr2 (status, typ,
|
||||
"Could not get default output Device\n");
|
||||
return -1;
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not get default output Device\n");
|
||||
return status;
|
||||
}
|
||||
if (core->outputDeviceID == kAudioDeviceUnknown) {
|
||||
dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
|
||||
return -1;
|
||||
dolog ("Could not initialize playback - Unknown Audiodevice\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* get minimum and maximum buffer frame sizes */
|
||||
status = coreaudio_get_framesizerange(core->outputDeviceID,
|
||||
&frameRange);
|
||||
if (status == kAudioHardwareBadObjectError) {
|
||||
return 0;
|
||||
}
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr2 (status, typ,
|
||||
"Could not get device buffer frame range\n");
|
||||
return -1;
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not get device buffer frame range\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
frames = audio_buffer_frames(
|
||||
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
|
||||
if (frameRange.mMinimum > frames) {
|
||||
if (frameRange.mMinimum > core->frameSizeSetting) {
|
||||
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
|
||||
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
|
||||
} else if (frameRange.mMaximum < frames) {
|
||||
} else if (frameRange.mMaximum < core->frameSizeSetting) {
|
||||
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
|
||||
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
|
||||
}
|
||||
else {
|
||||
core->audioDevicePropertyBufferFrameSize = frames;
|
||||
} else {
|
||||
core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting;
|
||||
}
|
||||
|
||||
/* set Buffer Frame Size */
|
||||
status = coreaudio_set_framesize(core->outputDeviceID,
|
||||
&core->audioDevicePropertyBufferFrameSize);
|
||||
if (status == kAudioHardwareBadObjectError) {
|
||||
return 0;
|
||||
}
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr2 (status, typ,
|
||||
"Could not set device buffer frame size %" PRIu32 "\n",
|
||||
(uint32_t)core->audioDevicePropertyBufferFrameSize);
|
||||
return -1;
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not set device buffer frame size %" PRIu32 "\n",
|
||||
(uint32_t)core->audioDevicePropertyBufferFrameSize);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* get Buffer Frame Size */
|
||||
status = coreaudio_get_framesize(core->outputDeviceID,
|
||||
&core->audioDevicePropertyBufferFrameSize);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr2 (status, typ,
|
||||
"Could not get device buffer frame size\n");
|
||||
return -1;
|
||||
if (status == kAudioHardwareBadObjectError) {
|
||||
return 0;
|
||||
}
|
||||
hw->samples = (cpdo->has_buffer_count ? cpdo->buffer_count : 4) *
|
||||
core->audioDevicePropertyBufferFrameSize;
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not get device buffer frame size\n");
|
||||
return status;
|
||||
}
|
||||
core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
|
||||
|
||||
/* get StreamFormat */
|
||||
status = coreaudio_get_streamformat(core->outputDeviceID,
|
||||
&core->outputStreamBasicDescription);
|
||||
if (status == kAudioHardwareBadObjectError) {
|
||||
return 0;
|
||||
}
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr2 (status, typ,
|
||||
"Could not get Device Stream properties\n");
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not get Device Stream properties\n");
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
return -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* set Samplerate */
|
||||
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
||||
|
||||
status = coreaudio_set_streamformat(core->outputDeviceID,
|
||||
&core->outputStreamBasicDescription);
|
||||
if (status == kAudioHardwareBadObjectError) {
|
||||
return 0;
|
||||
}
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
|
||||
as->freq);
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not set samplerate %lf\n",
|
||||
core->outputStreamBasicDescription.mSampleRate);
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
return -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* set Callback */
|
||||
core->ioprocid = NULL;
|
||||
status = AudioDeviceCreateIOProcID(core->outputDeviceID,
|
||||
audioDeviceIOProc,
|
||||
hw,
|
||||
&core->hw,
|
||||
&core->ioprocid);
|
||||
if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
|
||||
coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
return -1;
|
||||
if (status == kAudioHardwareBadDeviceError) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* start Playback */
|
||||
if (!isPlaying(core->outputDeviceID)) {
|
||||
status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr2 (status, typ, "Could not start playback\n");
|
||||
AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid);
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
return -1;
|
||||
}
|
||||
if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
|
||||
coreaudio_playback_logerr (status, "Could not set IOProc\n");
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fini_out_device(coreaudioVoiceOut *core)
|
||||
{
|
||||
OSStatus status;
|
||||
UInt32 isrunning;
|
||||
|
||||
/* stop playback */
|
||||
status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
|
||||
if (status != kAudioHardwareBadObjectError) {
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr(status,
|
||||
"Could not determine whether Device is playing\n");
|
||||
}
|
||||
|
||||
if (isrunning) {
|
||||
status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
|
||||
if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr(status, "Could not stop playback\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* remove callback */
|
||||
status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
|
||||
core->ioprocid);
|
||||
if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr(status, "Could not remove IOProc\n");
|
||||
}
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
}
|
||||
|
||||
static void update_device_playback_state(coreaudioVoiceOut *core)
|
||||
{
|
||||
OSStatus status;
|
||||
UInt32 isrunning;
|
||||
|
||||
status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
if (status != kAudioHardwareBadObjectError) {
|
||||
coreaudio_logerr(status,
|
||||
"Could not determine whether Device is playing\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (core->enabled) {
|
||||
/* start playback */
|
||||
if (!isrunning) {
|
||||
status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
|
||||
if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr (status, "Could not resume playback\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* stop playback */
|
||||
if (isrunning) {
|
||||
status = AudioDeviceStop(core->outputDeviceID,
|
||||
core->ioprocid);
|
||||
if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr(status, "Could not pause playback\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static OSStatus handle_voice_change(
|
||||
AudioObjectID in_object_id,
|
||||
UInt32 in_number_addresses,
|
||||
const AudioObjectPropertyAddress *in_addresses,
|
||||
void *in_client_data)
|
||||
{
|
||||
OSStatus status;
|
||||
coreaudioVoiceOut *core = in_client_data;
|
||||
|
||||
if (coreaudio_lock(core, __func__)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (core->outputDeviceID) {
|
||||
fini_out_device(core);
|
||||
}
|
||||
|
||||
status = init_out_device(core);
|
||||
if (!status) {
|
||||
update_device_playback_state(core);
|
||||
}
|
||||
|
||||
coreaudio_unlock (core, __func__);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
void *drv_opaque)
|
||||
{
|
||||
OSStatus status;
|
||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||
int err;
|
||||
Audiodev *dev = drv_opaque;
|
||||
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
|
||||
struct audsettings obt_as;
|
||||
|
||||
/* create mutex */
|
||||
err = pthread_mutex_init(&core->mutex, NULL);
|
||||
if (err) {
|
||||
dolog("Could not create mutex\nReason: %s\n", strerror (err));
|
||||
goto mutex_error;
|
||||
}
|
||||
|
||||
if (coreaudio_lock(core, __func__)) {
|
||||
goto lock_error;
|
||||
}
|
||||
|
||||
obt_as = *as;
|
||||
as = &obt_as;
|
||||
as->fmt = AUDIO_FORMAT_F32;
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
|
||||
core->frameSizeSetting = audio_buffer_frames(
|
||||
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
|
||||
|
||||
core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
|
||||
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
||||
|
||||
status = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
|
||||
&voice_addr, handle_voice_change,
|
||||
core);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr (status,
|
||||
"Could not listen to voice property change\n");
|
||||
goto listener_error;
|
||||
}
|
||||
|
||||
if (init_out_device(core)) {
|
||||
goto device_error;
|
||||
}
|
||||
|
||||
coreaudio_unlock(core, __func__);
|
||||
return 0;
|
||||
|
||||
device_error:
|
||||
status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
|
||||
&voice_addr,
|
||||
handle_voice_change,
|
||||
core);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_playback_logerr(status,
|
||||
"Could not remove voice property change listener\n");
|
||||
}
|
||||
|
||||
listener_error:
|
||||
coreaudio_unlock(core, __func__);
|
||||
|
||||
lock_error:
|
||||
err = pthread_mutex_destroy(&core->mutex);
|
||||
if (err) {
|
||||
dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
|
||||
}
|
||||
|
||||
mutex_error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void coreaudio_fini_out (HWVoiceOut *hw)
|
||||
{
|
||||
OSStatus status;
|
||||
int err;
|
||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||
|
||||
if (!audio_is_cleaning_up()) {
|
||||
/* stop playback */
|
||||
if (isPlaying(core->outputDeviceID)) {
|
||||
status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr (status, "Could not stop playback\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* remove callback */
|
||||
status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
|
||||
core->ioprocid);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr (status, "Could not remove IOProc\n");
|
||||
}
|
||||
if (coreaudio_lock(core, __func__)) {
|
||||
abort();
|
||||
}
|
||||
core->outputDeviceID = kAudioDeviceUnknown;
|
||||
|
||||
status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
|
||||
&voice_addr,
|
||||
handle_voice_change,
|
||||
core);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr(status, "Could not remove voice property change listener\n");
|
||||
}
|
||||
|
||||
fini_out_device(core);
|
||||
|
||||
coreaudio_unlock(core, __func__);
|
||||
|
||||
/* destroy mutex */
|
||||
err = pthread_mutex_destroy(&core->mutex);
|
||||
|
@ -631,29 +670,16 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
|
|||
|
||||
static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
|
||||
{
|
||||
OSStatus status;
|
||||
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
|
||||
|
||||
if (enable) {
|
||||
/* start playback */
|
||||
if (!isPlaying(core->outputDeviceID)) {
|
||||
status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr (status, "Could not resume playback\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* stop playback */
|
||||
if (!audio_is_cleaning_up()) {
|
||||
if (isPlaying(core->outputDeviceID)) {
|
||||
status = AudioDeviceStop(core->outputDeviceID,
|
||||
core->ioprocid);
|
||||
if (status != kAudioHardwareNoError) {
|
||||
coreaudio_logerr (status, "Could not pause playback\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (coreaudio_lock(core, __func__)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
core->enabled = enable;
|
||||
update_device_playback_state(core);
|
||||
|
||||
coreaudio_unlock(core, __func__);
|
||||
}
|
||||
|
||||
static void *coreaudio_audio_init(Audiodev *dev)
|
||||
|
|
|
@ -205,7 +205,7 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
NULL
|
||||
);
|
||||
#else
|
||||
bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
|
||||
bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
|
||||
hr = IDirectSound_CreateSoundBuffer (
|
||||
s->dsound,
|
||||
&bd,
|
||||
|
|
|
@ -89,7 +89,9 @@ static void dsound_log_hresult (HRESULT hr)
|
|||
#endif
|
||||
#ifdef DSERR_ALLOCATED
|
||||
case DSERR_ALLOCATED:
|
||||
str = "The request failed because resources, such as a priority level, were already in use by another caller";
|
||||
str = "The request failed because resources, "
|
||||
"such as a priority level, were already in use "
|
||||
"by another caller";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_ALREADYINITIALIZED
|
||||
|
@ -104,7 +106,8 @@ static void dsound_log_hresult (HRESULT hr)
|
|||
#endif
|
||||
#ifdef DSERR_BADSENDBUFFERGUID
|
||||
case DSERR_BADSENDBUFFERGUID:
|
||||
str = "The GUID specified in an audiopath file does not match a valid mix-in buffer";
|
||||
str = "The GUID specified in an audiopath file "
|
||||
"does not match a valid mix-in buffer";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_BUFFERLOST
|
||||
|
@ -114,26 +117,35 @@ static void dsound_log_hresult (HRESULT hr)
|
|||
#endif
|
||||
#ifdef DSERR_BUFFERTOOSMALL
|
||||
case DSERR_BUFFERTOOSMALL:
|
||||
str = "The buffer size is not great enough to enable effects processing";
|
||||
str = "The buffer size is not great enough to "
|
||||
"enable effects processing";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_CONTROLUNAVAIL
|
||||
case DSERR_CONTROLUNAVAIL:
|
||||
str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC";
|
||||
str = "The buffer control (volume, pan, and so on) "
|
||||
"requested by the caller is not available. "
|
||||
"Controls must be specified when the buffer is created, "
|
||||
"using the dwFlags member of DSBUFFERDESC";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_DS8_REQUIRED
|
||||
case DSERR_DS8_REQUIRED:
|
||||
str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface";
|
||||
str = "A DirectSound object of class CLSID_DirectSound8 or later "
|
||||
"is required for the requested functionality. "
|
||||
"For more information, see IDirectSound8 Interface";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_FXUNAVAILABLE
|
||||
case DSERR_FXUNAVAILABLE:
|
||||
str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software";
|
||||
str = "The effects requested could not be found on the system, "
|
||||
"or they are in the wrong order or in the wrong location; "
|
||||
"for example, an effect expected in hardware "
|
||||
"was found in software";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_GENERIC
|
||||
case DSERR_GENERIC :
|
||||
case DSERR_GENERIC:
|
||||
str = "An undetermined error occurred inside the DirectSound subsystem";
|
||||
break;
|
||||
#endif
|
||||
|
@ -154,7 +166,8 @@ static void dsound_log_hresult (HRESULT hr)
|
|||
#endif
|
||||
#ifdef DSERR_NODRIVER
|
||||
case DSERR_NODRIVER:
|
||||
str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID";
|
||||
str = "No sound driver is available for use, "
|
||||
"or the given GUID is not a valid DirectSound device ID";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_NOINTERFACE
|
||||
|
@ -169,12 +182,14 @@ static void dsound_log_hresult (HRESULT hr)
|
|||
#endif
|
||||
#ifdef DSERR_OTHERAPPHASPRIO
|
||||
case DSERR_OTHERAPPHASPRIO:
|
||||
str = "Another application has a higher priority level, preventing this call from succeeding";
|
||||
str = "Another application has a higher priority level, "
|
||||
"preventing this call from succeeding";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_OUTOFMEMORY
|
||||
case DSERR_OUTOFMEMORY:
|
||||
str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request";
|
||||
str = "The DirectSound subsystem could not allocate "
|
||||
"sufficient memory to complete the caller's request";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_PRIOLEVELNEEDED
|
||||
|
@ -189,7 +204,9 @@ static void dsound_log_hresult (HRESULT hr)
|
|||
#endif
|
||||
#ifdef DSERR_UNINITIALIZED
|
||||
case DSERR_UNINITIALIZED:
|
||||
str = "The Initialize method has not been called or has not been called successfully before other methods were called";
|
||||
str = "The Initialize method has not been called "
|
||||
"or has not been called successfully "
|
||||
"before other methods were called";
|
||||
break;
|
||||
#endif
|
||||
#ifdef DSERR_UNSUPPORTED
|
||||
|
@ -198,7 +215,7 @@ static void dsound_log_hresult (HRESULT hr)
|
|||
break;
|
||||
#endif
|
||||
default:
|
||||
AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr);
|
||||
AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT 0x%lx)\n", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -342,12 +359,12 @@ static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb,
|
|||
dsound_unlock_out (dsb, p1, p2, blen1, blen2);
|
||||
}
|
||||
|
||||
static int dsound_open (dsound *s)
|
||||
static int dsound_set_cooperative_level(dsound *s)
|
||||
{
|
||||
HRESULT hr;
|
||||
HWND hwnd;
|
||||
|
||||
hwnd = GetForegroundWindow ();
|
||||
hwnd = GetDesktopWindow();
|
||||
hr = IDirectSound_SetCooperativeLevel (
|
||||
s->dsound,
|
||||
hwnd,
|
||||
|
@ -404,8 +421,7 @@ static void dsound_enable_out(HWVoiceOut *hw, bool enable)
|
|||
dsound_logerr (hr, "Could not stop playing buffer\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
dolog ("warning: Voice is not playing\n");
|
||||
}
|
||||
}
|
||||
|
@ -509,8 +525,7 @@ static void dsound_enable_in(HWVoiceIn *hw, bool enable)
|
|||
dsound_logerr (hr, "Could not stop capturing\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
dolog ("warning: Voice is not capturing\n");
|
||||
}
|
||||
}
|
||||
|
@ -659,8 +674,7 @@ static void *dsound_audio_init(Audiodev *dev)
|
|||
);
|
||||
if (FAILED (hr)) {
|
||||
dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
|
||||
if (FAILED (hr)) {
|
||||
dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
|
||||
|
@ -673,7 +687,7 @@ static void *dsound_audio_init(Audiodev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
err = dsound_open (s);
|
||||
err = dsound_set_cooperative_level(s);
|
||||
if (err) {
|
||||
dsound_audio_fini (s);
|
||||
return NULL;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu-common.h"
|
||||
#include "audio.h"
|
||||
|
||||
|
@ -63,6 +64,7 @@ typedef struct QJackClient {
|
|||
QJackState state;
|
||||
jack_client_t *client;
|
||||
jack_nframes_t freq;
|
||||
QEMUBH *shutdown_bh;
|
||||
|
||||
struct QJack *j;
|
||||
int nchannels;
|
||||
|
@ -87,6 +89,7 @@ QJackIn;
|
|||
static int qjack_client_init(QJackClient *c);
|
||||
static void qjack_client_connect_ports(QJackClient *c);
|
||||
static void qjack_client_fini(QJackClient *c);
|
||||
static QemuMutex qjack_shutdown_lock;
|
||||
|
||||
static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames)
|
||||
{
|
||||
|
@ -104,7 +107,7 @@ static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames)
|
|||
static void qjack_buffer_clear(QJackBuffer *buffer)
|
||||
{
|
||||
assert(buffer->data);
|
||||
atomic_store_release(&buffer->used, 0);
|
||||
qatomic_store_release(&buffer->used, 0);
|
||||
buffer->rptr = 0;
|
||||
buffer->wptr = 0;
|
||||
}
|
||||
|
@ -129,7 +132,7 @@ static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size)
|
|||
assert(buffer->data);
|
||||
const int samples = size / sizeof(float);
|
||||
int frames = samples / buffer->channels;
|
||||
const int avail = buffer->frames - atomic_load_acquire(&buffer->used);
|
||||
const int avail = buffer->frames - qatomic_load_acquire(&buffer->used);
|
||||
|
||||
if (frames > avail) {
|
||||
frames = avail;
|
||||
|
@ -153,7 +156,7 @@ static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size)
|
|||
|
||||
buffer->wptr = wptr;
|
||||
|
||||
atomic_add(&buffer->used, frames);
|
||||
qatomic_add(&buffer->used, frames);
|
||||
return frames * buffer->channels * sizeof(float);
|
||||
};
|
||||
|
||||
|
@ -161,7 +164,7 @@ static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size)
|
|||
static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames)
|
||||
{
|
||||
assert(buffer->data);
|
||||
const int avail = buffer->frames - atomic_load_acquire(&buffer->used);
|
||||
const int avail = buffer->frames - qatomic_load_acquire(&buffer->used);
|
||||
int wptr = buffer->wptr;
|
||||
|
||||
if (frames > avail) {
|
||||
|
@ -185,7 +188,7 @@ static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames)
|
|||
}
|
||||
buffer->wptr = wptr;
|
||||
|
||||
atomic_add(&buffer->used, frames);
|
||||
qatomic_add(&buffer->used, frames);
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
@ -195,7 +198,7 @@ static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size)
|
|||
assert(buffer->data);
|
||||
const int samples = size / sizeof(float);
|
||||
int frames = samples / buffer->channels;
|
||||
const int avail = atomic_load_acquire(&buffer->used);
|
||||
const int avail = qatomic_load_acquire(&buffer->used);
|
||||
|
||||
if (frames > avail) {
|
||||
frames = avail;
|
||||
|
@ -219,7 +222,7 @@ static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size)
|
|||
|
||||
buffer->rptr = rptr;
|
||||
|
||||
atomic_sub(&buffer->used, frames);
|
||||
qatomic_sub(&buffer->used, frames);
|
||||
return frames * buffer->channels * sizeof(float);
|
||||
}
|
||||
|
||||
|
@ -228,7 +231,7 @@ static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames)
|
|||
{
|
||||
assert(buffer->data);
|
||||
int copy = frames;
|
||||
const int used = atomic_load_acquire(&buffer->used);
|
||||
const int used = qatomic_load_acquire(&buffer->used);
|
||||
int rptr = buffer->rptr;
|
||||
|
||||
if (copy > used) {
|
||||
|
@ -252,7 +255,7 @@ static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames)
|
|||
}
|
||||
buffer->rptr = rptr;
|
||||
|
||||
atomic_sub(&buffer->used, copy);
|
||||
qatomic_sub(&buffer->used, copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
@ -274,7 +277,7 @@ static int qjack_process(jack_nframes_t nframes, void *arg)
|
|||
if (likely(c->enabled)) {
|
||||
qjack_buffer_read_l(&c->fifo, buffers, nframes);
|
||||
} else {
|
||||
for(int i = 0; i < c->nchannels; ++i) {
|
||||
for (int i = 0; i < c->nchannels; ++i) {
|
||||
memset(buffers[i], 0, nframes * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
@ -306,21 +309,27 @@ static int qjack_xrun(void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void qjack_shutdown_bh(void *opaque)
|
||||
{
|
||||
QJackClient *c = (QJackClient *)opaque;
|
||||
qjack_client_fini(c);
|
||||
}
|
||||
|
||||
static void qjack_shutdown(void *arg)
|
||||
{
|
||||
QJackClient *c = (QJackClient *)arg;
|
||||
c->state = QJACK_STATE_SHUTDOWN;
|
||||
qemu_bh_schedule(c->shutdown_bh);
|
||||
}
|
||||
|
||||
static void qjack_client_recover(QJackClient *c)
|
||||
{
|
||||
if (c->state == QJACK_STATE_SHUTDOWN) {
|
||||
qjack_client_fini(c);
|
||||
if (c->state != QJACK_STATE_DISCONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* packets is used simply to throttle this */
|
||||
if (c->state == QJACK_STATE_DISCONNECTED &&
|
||||
c->packets % 100 == 0) {
|
||||
if (c->packets % 100 == 0) {
|
||||
|
||||
/* if enabled then attempt to recover */
|
||||
if (c->enabled) {
|
||||
|
@ -489,15 +498,16 @@ static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
QJackOut *jo = (QJackOut *)hw;
|
||||
Audiodev *dev = (Audiodev *)drv_opaque;
|
||||
|
||||
qjack_client_fini(&jo->c);
|
||||
|
||||
jo->c.out = true;
|
||||
jo->c.enabled = false;
|
||||
jo->c.nchannels = as->nchannels;
|
||||
jo->c.opt = dev->u.jack.out;
|
||||
|
||||
jo->c.shutdown_bh = qemu_bh_new(qjack_shutdown_bh, &jo->c);
|
||||
|
||||
int ret = qjack_client_init(&jo->c);
|
||||
if (ret != 0) {
|
||||
qemu_bh_delete(jo->c.shutdown_bh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -525,15 +535,16 @@ static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as,
|
|||
QJackIn *ji = (QJackIn *)hw;
|
||||
Audiodev *dev = (Audiodev *)drv_opaque;
|
||||
|
||||
qjack_client_fini(&ji->c);
|
||||
|
||||
ji->c.out = false;
|
||||
ji->c.enabled = false;
|
||||
ji->c.nchannels = as->nchannels;
|
||||
ji->c.opt = dev->u.jack.in;
|
||||
|
||||
ji->c.shutdown_bh = qemu_bh_new(qjack_shutdown_bh, &ji->c);
|
||||
|
||||
int ret = qjack_client_init(&ji->c);
|
||||
if (ret != 0) {
|
||||
qemu_bh_delete(ji->c.shutdown_bh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -555,7 +566,7 @@ static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void qjack_client_fini(QJackClient *c)
|
||||
static void qjack_client_fini_locked(QJackClient *c)
|
||||
{
|
||||
switch (c->state) {
|
||||
case QJACK_STATE_RUNNING:
|
||||
|
@ -564,28 +575,40 @@ static void qjack_client_fini(QJackClient *c)
|
|||
|
||||
case QJACK_STATE_SHUTDOWN:
|
||||
jack_client_close(c->client);
|
||||
c->client = NULL;
|
||||
|
||||
qjack_buffer_free(&c->fifo);
|
||||
g_free(c->port);
|
||||
|
||||
c->state = QJACK_STATE_DISCONNECTED;
|
||||
/* fallthrough */
|
||||
|
||||
case QJACK_STATE_DISCONNECTED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qjack_buffer_free(&c->fifo);
|
||||
g_free(c->port);
|
||||
|
||||
c->state = QJACK_STATE_DISCONNECTED;
|
||||
static void qjack_client_fini(QJackClient *c)
|
||||
{
|
||||
qemu_mutex_lock(&qjack_shutdown_lock);
|
||||
qjack_client_fini_locked(c);
|
||||
qemu_mutex_unlock(&qjack_shutdown_lock);
|
||||
}
|
||||
|
||||
static void qjack_fini_out(HWVoiceOut *hw)
|
||||
{
|
||||
QJackOut *jo = (QJackOut *)hw;
|
||||
qjack_client_fini(&jo->c);
|
||||
|
||||
qemu_bh_delete(jo->c.shutdown_bh);
|
||||
}
|
||||
|
||||
static void qjack_fini_in(HWVoiceIn *hw)
|
||||
{
|
||||
QJackIn *ji = (QJackIn *)hw;
|
||||
qjack_client_fini(&ji->c);
|
||||
|
||||
qemu_bh_delete(ji->c.shutdown_bh);
|
||||
}
|
||||
|
||||
static void qjack_enable_out(HWVoiceOut *hw, bool enable)
|
||||
|
@ -634,6 +657,7 @@ static struct audio_pcm_ops jack_pcm_ops = {
|
|||
.init_in = qjack_init_in,
|
||||
.fini_in = qjack_fini_in,
|
||||
.read = qjack_read,
|
||||
.run_buffer_in = audio_generic_run_buffer_in,
|
||||
.enable_in = qjack_enable_in
|
||||
};
|
||||
|
||||
|
@ -662,6 +686,7 @@ static void qjack_info(const char *msg)
|
|||
|
||||
static void register_audio_jack(void)
|
||||
{
|
||||
qemu_mutex_init(&qjack_shutdown_lock);
|
||||
audio_driver_register(&jack_driver);
|
||||
jack_set_thread_creator(qjack_thread_creator);
|
||||
jack_set_error_function(qjack_error);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
softmmu_ss.add([spice_headers, files('audio.c')])
|
||||
softmmu_ss.add(files(
|
||||
'audio_legacy.c',
|
||||
'mixeng.c',
|
||||
'noaudio.c',
|
||||
'wavaudio.c',
|
||||
'wavcapture.c',
|
||||
))
|
||||
|
||||
softmmu_ss.add(when: [coreaudio, 'CONFIG_AUDIO_COREAUDIO'], if_true: files('coreaudio.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 = {}
|
||||
foreach m : [
|
||||
['CONFIG_AUDIO_ALSA', 'alsa', alsa, 'alsaaudio.c'],
|
||||
['CONFIG_AUDIO_OSS', 'oss', oss, 'ossaudio.c'],
|
||||
['CONFIG_AUDIO_PA', 'pa', pulse, 'paaudio.c'],
|
||||
['CONFIG_AUDIO_SDL', 'sdl', sdl, 'sdlaudio.c'],
|
||||
['CONFIG_AUDIO_JACK', 'jack', jack, 'jackaudio.c'],
|
||||
['CONFIG_SPICE', 'spice', spice, 'spiceaudio.c']
|
||||
]
|
||||
if config_host.has_key(m[0])
|
||||
module_ss = ss.source_set()
|
||||
module_ss.add(when: m[2], if_true: files(m[3]))
|
||||
audio_modules += {m[1] : module_ss}
|
||||
endif
|
||||
endforeach
|
||||
|
||||
modules += {'audio': audio_modules}
|
|
@ -124,6 +124,7 @@ static struct audio_pcm_ops no_pcm_ops = {
|
|||
.init_in = no_init_in,
|
||||
.fini_in = no_fini_in,
|
||||
.read = no_read,
|
||||
.run_buffer_in = audio_generic_run_buffer_in,
|
||||
.enable_in = no_enable_in
|
||||
};
|
||||
|
||||
|
|
|
@ -142,16 +142,14 @@ static int aud_to_ossfmt (AudioFormat fmt, int endianness)
|
|||
case AUDIO_FORMAT_S16:
|
||||
if (endianness) {
|
||||
return AFMT_S16_BE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return AFMT_S16_LE;
|
||||
}
|
||||
|
||||
case AUDIO_FORMAT_U16:
|
||||
if (endianness) {
|
||||
return AFMT_U16_BE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return AFMT_U16_LE;
|
||||
}
|
||||
|
||||
|
@ -542,16 +540,14 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
int trig = 0;
|
||||
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
|
||||
oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
trig = PCM_ENABLE_OUTPUT;
|
||||
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
|
||||
oss_logerr (
|
||||
errno,
|
||||
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
|
||||
);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
oss->mmapped = 1;
|
||||
}
|
||||
}
|
||||
|
@ -762,6 +758,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
|
|||
.init_in = oss_init_in,
|
||||
.fini_in = oss_fini_in,
|
||||
.read = oss_read,
|
||||
.run_buffer_in = audio_generic_run_buffer_in,
|
||||
.enable_in = oss_enable_in
|
||||
};
|
||||
|
||||
|
|
|
@ -207,6 +207,46 @@ static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
|||
PAVoiceOut *p = (PAVoiceOut *) hw;
|
||||
PAConnection *c = p->g->conn;
|
||||
void *ret;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
||||
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
|
||||
"pa_threaded_mainloop_lock failed\n");
|
||||
if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
|
||||
/* wait for stream to become ready */
|
||||
l = 0;
|
||||
ret = NULL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
l = pa_stream_writable_size(p->stream);
|
||||
CHECK_SUCCESS_GOTO(c, l != (size_t) -1, unlock_and_fail,
|
||||
"pa_stream_writable_size failed\n");
|
||||
|
||||
*size = -1;
|
||||
r = pa_stream_begin_write(p->stream, &ret, size);
|
||||
CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail,
|
||||
"pa_stream_begin_write failed\n");
|
||||
|
||||
unlock:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
if (*size > l) {
|
||||
*size = l;
|
||||
}
|
||||
return ret;
|
||||
|
||||
unlock_and_fail:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t qpa_put_buffer_out(HWVoiceOut *hw, void *data, size_t length)
|
||||
{
|
||||
PAVoiceOut *p = (PAVoiceOut *)hw;
|
||||
PAConnection *c = p->g->conn;
|
||||
int r;
|
||||
|
||||
pa_threaded_mainloop_lock(c->mainloop);
|
||||
|
@ -214,18 +254,15 @@ static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
|||
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
|
||||
"pa_threaded_mainloop_lock failed\n");
|
||||
|
||||
*size = -1;
|
||||
r = pa_stream_begin_write(p->stream, &ret, size);
|
||||
CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail,
|
||||
"pa_stream_begin_write failed\n");
|
||||
r = pa_stream_write(p->stream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, "pa_stream_write failed\n");
|
||||
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return ret;
|
||||
return length;
|
||||
|
||||
unlock_and_fail:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
*size = 0;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
|
||||
|
@ -239,6 +276,11 @@ static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
|
|||
|
||||
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
|
||||
"pa_threaded_mainloop_lock failed\n");
|
||||
if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
|
||||
/* wait for stream to become ready */
|
||||
l = 0;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
l = pa_stream_writable_size(p->stream);
|
||||
|
||||
|
@ -252,6 +294,7 @@ static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
|
|||
r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, "pa_stream_write failed\n");
|
||||
|
||||
unlock:
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
return l;
|
||||
|
||||
|
@ -437,7 +480,7 @@ static pa_stream *qpa_simple_new (
|
|||
}
|
||||
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(c->mainloop);
|
||||
|
@ -474,7 +517,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
ss.rate = as->freq;
|
||||
|
||||
ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss);
|
||||
ba.minreq = -1;
|
||||
ba.minreq = pa_usec_to_bytes(MIN(ppdo->latency >> 2,
|
||||
(g->dev->timer_period >> 2) * 3), &ss);
|
||||
ba.maxlength = -1;
|
||||
ba.prebuf = -1;
|
||||
|
||||
|
@ -495,9 +539,12 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
}
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
/*
|
||||
* This is wrong. hw->samples counts in frames. hw->samples will be
|
||||
* number of channels times larger than expected.
|
||||
*/
|
||||
hw->samples = audio_buffer_samples(
|
||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
||||
&obt_as, ppdo->buffer_length);
|
||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -521,8 +568,9 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
|||
ss.channels = as->nchannels;
|
||||
ss.rate = as->freq;
|
||||
|
||||
ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss);
|
||||
ba.maxlength = pa_usec_to_bytes(ppdo->latency * 2, &ss);
|
||||
ba.fragsize = pa_usec_to_bytes((g->dev->timer_period >> 1) * 3, &ss);
|
||||
ba.maxlength = pa_usec_to_bytes(
|
||||
MAX(ppdo->latency, g->dev->timer_period * 3), &ss);
|
||||
ba.minreq = -1;
|
||||
ba.prebuf = -1;
|
||||
|
||||
|
@ -543,9 +591,12 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
|||
}
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
/*
|
||||
* This is wrong. hw->samples counts in frames. hw->samples will be
|
||||
* number of channels times larger than expected.
|
||||
*/
|
||||
hw->samples = audio_buffer_samples(
|
||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
||||
&obt_as, ppdo->buffer_length);
|
||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -695,10 +746,6 @@ static void qpa_volume_in(HWVoiceIn *hw, Volume *vol)
|
|||
static int qpa_validate_per_direction_opts(Audiodev *dev,
|
||||
AudiodevPaPerDirectionOptions *pdo)
|
||||
{
|
||||
if (!pdo->has_buffer_length) {
|
||||
pdo->has_buffer_length = true;
|
||||
pdo->buffer_length = 46440;
|
||||
}
|
||||
if (!pdo->has_latency) {
|
||||
pdo->has_latency = true;
|
||||
pdo->latency = 15000;
|
||||
|
@ -861,7 +908,7 @@ static struct audio_pcm_ops qpa_pcm_ops = {
|
|||
.fini_out = qpa_fini_out,
|
||||
.write = qpa_write,
|
||||
.get_buffer_out = qpa_get_buffer_out,
|
||||
.put_buffer_out = qpa_write, /* pa handles it */
|
||||
.put_buffer_out = qpa_put_buffer_out,
|
||||
.volume_out = qpa_volume_out,
|
||||
|
||||
.init_in = qpa_init_in,
|
||||
|
|
313
audio/sdlaudio.c
313
audio/sdlaudio.c
|
@ -41,15 +41,19 @@
|
|||
|
||||
typedef struct SDLVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
} SDLVoiceOut;
|
||||
|
||||
static struct SDLAudioState {
|
||||
int exit;
|
||||
int initialized;
|
||||
bool driver_created;
|
||||
Audiodev *dev;
|
||||
} glob_sdl;
|
||||
typedef struct SDLAudioState SDLAudioState;
|
||||
SDL_AudioDeviceID devid;
|
||||
} SDLVoiceOut;
|
||||
|
||||
typedef struct SDLVoiceIn {
|
||||
HWVoiceIn hw;
|
||||
int exit;
|
||||
int initialized;
|
||||
Audiodev *dev;
|
||||
SDL_AudioDeviceID devid;
|
||||
} SDLVoiceIn;
|
||||
|
||||
static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
|
||||
{
|
||||
|
@ -155,9 +159,10 @@ static int sdl_to_audfmt(int sdlfmt, AudioFormat *fmt, int *endianness)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
|
||||
static SDL_AudioDeviceID sdl_open(SDL_AudioSpec *req, SDL_AudioSpec *obt,
|
||||
int rec)
|
||||
{
|
||||
int status;
|
||||
SDL_AudioDeviceID devid;
|
||||
#ifndef _WIN32
|
||||
int err;
|
||||
sigset_t new, old;
|
||||
|
@ -166,18 +171,19 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
|
|||
err = sigfillset (&new);
|
||||
if (err) {
|
||||
dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno));
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
err = pthread_sigmask (SIG_BLOCK, &new, &old);
|
||||
if (err) {
|
||||
dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err));
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
status = SDL_OpenAudio (req, obt);
|
||||
if (status) {
|
||||
sdl_logerr ("SDL_OpenAudio failed\n");
|
||||
devid = SDL_OpenAudioDevice(NULL, rec, req, obt, 0);
|
||||
if (!devid) {
|
||||
sdl_logerr("SDL_OpenAudioDevice for %s failed\n",
|
||||
rec ? "recording" : "playback");
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -190,112 +196,175 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
|
|||
exit (EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
return devid;
|
||||
}
|
||||
|
||||
static void sdl_close (SDLAudioState *s)
|
||||
static void sdl_close_out(SDLVoiceOut *sdl)
|
||||
{
|
||||
if (s->initialized) {
|
||||
SDL_LockAudio();
|
||||
s->exit = 1;
|
||||
SDL_UnlockAudio();
|
||||
SDL_PauseAudio (1);
|
||||
SDL_CloseAudio ();
|
||||
s->initialized = 0;
|
||||
if (sdl->initialized) {
|
||||
SDL_LockAudioDevice(sdl->devid);
|
||||
sdl->exit = 1;
|
||||
SDL_UnlockAudioDevice(sdl->devid);
|
||||
SDL_PauseAudioDevice(sdl->devid, 1);
|
||||
sdl->initialized = 0;
|
||||
}
|
||||
if (sdl->devid) {
|
||||
SDL_CloseAudioDevice(sdl->devid);
|
||||
sdl->devid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
static void sdl_callback_out(void *opaque, Uint8 *buf, int len)
|
||||
{
|
||||
SDLVoiceOut *sdl = opaque;
|
||||
SDLAudioState *s = &glob_sdl;
|
||||
HWVoiceOut *hw = &sdl->hw;
|
||||
|
||||
if (s->exit) {
|
||||
return;
|
||||
}
|
||||
if (!sdl->exit) {
|
||||
|
||||
/* dolog ("in callback samples=%zu live=%zu\n", samples, sdl->live); */
|
||||
/* dolog("callback_out: len=%d avail=%zu\n", len, hw->pending_emul); */
|
||||
|
||||
while (hw->pending_emul && len) {
|
||||
size_t write_len;
|
||||
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
|
||||
if (start < 0) {
|
||||
start += hw->size_emul;
|
||||
while (hw->pending_emul && len) {
|
||||
size_t write_len;
|
||||
ssize_t start = (ssize_t)hw->pos_emul - hw->pending_emul;
|
||||
if (start < 0) {
|
||||
start += hw->size_emul;
|
||||
}
|
||||
assert(start >= 0 && start < hw->size_emul);
|
||||
|
||||
write_len = MIN(MIN(hw->pending_emul, len),
|
||||
hw->size_emul - start);
|
||||
|
||||
memcpy(buf, hw->buf_emul + start, write_len);
|
||||
hw->pending_emul -= write_len;
|
||||
len -= write_len;
|
||||
buf += write_len;
|
||||
}
|
||||
assert(start >= 0 && start < hw->size_emul);
|
||||
|
||||
write_len = MIN(MIN(hw->pending_emul, len),
|
||||
hw->size_emul - start);
|
||||
|
||||
memcpy(buf, hw->buf_emul + start, write_len);
|
||||
hw->pending_emul -= write_len;
|
||||
len -= write_len;
|
||||
buf += write_len;
|
||||
}
|
||||
|
||||
/* clear remaining buffer that we couldn't fill with data */
|
||||
if (len) {
|
||||
memset(buf, 0, len);
|
||||
audio_pcm_info_clear_buf(&hw->info, buf,
|
||||
len / hw->info.bytes_per_frame);
|
||||
}
|
||||
}
|
||||
|
||||
#define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args, fail, unlock) \
|
||||
static ret_type glue(sdl_, name)args_decl \
|
||||
{ \
|
||||
ret_type ret; \
|
||||
\
|
||||
SDL_LockAudio(); \
|
||||
\
|
||||
ret = glue(audio_generic_, name)args; \
|
||||
\
|
||||
SDL_UnlockAudio(); \
|
||||
return ret; \
|
||||
static void sdl_close_in(SDLVoiceIn *sdl)
|
||||
{
|
||||
if (sdl->initialized) {
|
||||
SDL_LockAudioDevice(sdl->devid);
|
||||
sdl->exit = 1;
|
||||
SDL_UnlockAudioDevice(sdl->devid);
|
||||
SDL_PauseAudioDevice(sdl->devid, 1);
|
||||
sdl->initialized = 0;
|
||||
}
|
||||
if (sdl->devid) {
|
||||
SDL_CloseAudioDevice(sdl->devid);
|
||||
sdl->devid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl_callback_in(void *opaque, Uint8 *buf, int len)
|
||||
{
|
||||
SDLVoiceIn *sdl = opaque;
|
||||
HWVoiceIn *hw = &sdl->hw;
|
||||
|
||||
if (sdl->exit) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* dolog("callback_in: len=%d pending=%zu\n", len, hw->pending_emul); */
|
||||
|
||||
while (hw->pending_emul < hw->size_emul && len) {
|
||||
size_t read_len = MIN(len, MIN(hw->size_emul - hw->pos_emul,
|
||||
hw->size_emul - hw->pending_emul));
|
||||
|
||||
memcpy(hw->buf_emul + hw->pos_emul, buf, read_len);
|
||||
|
||||
hw->pending_emul += read_len;
|
||||
hw->pos_emul = (hw->pos_emul + read_len) % hw->size_emul;
|
||||
len -= read_len;
|
||||
buf += read_len;
|
||||
}
|
||||
}
|
||||
|
||||
#define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args, dir) \
|
||||
static ret_type glue(sdl_, name)args_decl \
|
||||
{ \
|
||||
ret_type ret; \
|
||||
glue(SDLVoice, dir) *sdl = (glue(SDLVoice, dir) *)hw; \
|
||||
\
|
||||
SDL_LockAudioDevice(sdl->devid); \
|
||||
ret = glue(audio_generic_, name)args; \
|
||||
SDL_UnlockAudioDevice(sdl->devid); \
|
||||
\
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define SDL_WRAPPER_VOID_FUNC(name, args_decl, args, dir) \
|
||||
static void glue(sdl_, name)args_decl \
|
||||
{ \
|
||||
glue(SDLVoice, dir) *sdl = (glue(SDLVoice, dir) *)hw; \
|
||||
\
|
||||
SDL_LockAudioDevice(sdl->devid); \
|
||||
glue(audio_generic_, name)args; \
|
||||
SDL_UnlockAudioDevice(sdl->devid); \
|
||||
}
|
||||
|
||||
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||
(hw, size), *size = 0, sdl_unlock)
|
||||
(hw, size), Out)
|
||||
SDL_WRAPPER_FUNC(put_buffer_out, size_t,
|
||||
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
|
||||
/*nothing*/, sdl_unlock_and_post)
|
||||
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size), Out)
|
||||
SDL_WRAPPER_FUNC(write, size_t,
|
||||
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
|
||||
/*nothing*/, sdl_unlock_and_post)
|
||||
|
||||
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size), Out)
|
||||
SDL_WRAPPER_FUNC(read, size_t, (HWVoiceIn *hw, void *buf, size_t size),
|
||||
(hw, buf, size), In)
|
||||
SDL_WRAPPER_FUNC(get_buffer_in, void *, (HWVoiceIn *hw, size_t *size),
|
||||
(hw, size), In)
|
||||
SDL_WRAPPER_VOID_FUNC(put_buffer_in, (HWVoiceIn *hw, void *buf, size_t size),
|
||||
(hw, buf, size), In)
|
||||
#undef SDL_WRAPPER_FUNC
|
||||
#undef SDL_WRAPPER_VOID_FUNC
|
||||
|
||||
static void sdl_fini_out (HWVoiceOut *hw)
|
||||
static void sdl_fini_out(HWVoiceOut *hw)
|
||||
{
|
||||
(void) hw;
|
||||
SDLVoiceOut *sdl = (SDLVoiceOut *)hw;
|
||||
|
||||
sdl_close (&glob_sdl);
|
||||
sdl_close_out(sdl);
|
||||
}
|
||||
|
||||
static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||
void *drv_opaque)
|
||||
{
|
||||
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
|
||||
SDLAudioState *s = &glob_sdl;
|
||||
SDLVoiceOut *sdl = (SDLVoiceOut *)hw;
|
||||
SDL_AudioSpec req, obt;
|
||||
int endianness;
|
||||
int err;
|
||||
AudioFormat effective_fmt;
|
||||
Audiodev *dev = drv_opaque;
|
||||
AudiodevSdlPerDirectionOptions *spdo = dev->u.sdl.out;
|
||||
struct audsettings obt_as;
|
||||
|
||||
req.freq = as->freq;
|
||||
req.format = aud_to_sdlfmt (as->fmt);
|
||||
req.channels = as->nchannels;
|
||||
req.samples = audio_buffer_samples(s->dev->u.sdl.out, as, 11610);
|
||||
req.callback = sdl_callback;
|
||||
/*
|
||||
* This is wrong. SDL samples are QEMU frames. The buffer size will be
|
||||
* the requested buffer size multiplied by the number of channels.
|
||||
*/
|
||||
req.samples = audio_buffer_samples(
|
||||
qapi_AudiodevSdlPerDirectionOptions_base(spdo), as, 11610);
|
||||
req.callback = sdl_callback_out;
|
||||
req.userdata = sdl;
|
||||
|
||||
if (sdl_open (&req, &obt)) {
|
||||
sdl->dev = dev;
|
||||
sdl->devid = sdl_open(&req, &obt, 0);
|
||||
if (!sdl->devid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
|
||||
if (err) {
|
||||
sdl_close (s);
|
||||
sdl_close_out(sdl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -305,44 +374,97 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = obt.samples;
|
||||
hw->samples = (spdo->has_buffer_count ? spdo->buffer_count : 4) *
|
||||
obt.samples;
|
||||
|
||||
s->initialized = 1;
|
||||
s->exit = 0;
|
||||
SDL_PauseAudio (0);
|
||||
sdl->initialized = 1;
|
||||
sdl->exit = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdl_enable_out(HWVoiceOut *hw, bool enable)
|
||||
{
|
||||
SDL_PauseAudio(!enable);
|
||||
SDLVoiceOut *sdl = (SDLVoiceOut *)hw;
|
||||
|
||||
SDL_PauseAudioDevice(sdl->devid, !enable);
|
||||
}
|
||||
|
||||
static void sdl_fini_in(HWVoiceIn *hw)
|
||||
{
|
||||
SDLVoiceIn *sdl = (SDLVoiceIn *)hw;
|
||||
|
||||
sdl_close_in(sdl);
|
||||
}
|
||||
|
||||
static int sdl_init_in(HWVoiceIn *hw, audsettings *as, void *drv_opaque)
|
||||
{
|
||||
SDLVoiceIn *sdl = (SDLVoiceIn *)hw;
|
||||
SDL_AudioSpec req, obt;
|
||||
int endianness;
|
||||
int err;
|
||||
AudioFormat effective_fmt;
|
||||
Audiodev *dev = drv_opaque;
|
||||
AudiodevSdlPerDirectionOptions *spdo = dev->u.sdl.in;
|
||||
struct audsettings obt_as;
|
||||
|
||||
req.freq = as->freq;
|
||||
req.format = aud_to_sdlfmt(as->fmt);
|
||||
req.channels = as->nchannels;
|
||||
/* SDL samples are QEMU frames */
|
||||
req.samples = audio_buffer_frames(
|
||||
qapi_AudiodevSdlPerDirectionOptions_base(spdo), as, 11610);
|
||||
req.callback = sdl_callback_in;
|
||||
req.userdata = sdl;
|
||||
|
||||
sdl->dev = dev;
|
||||
sdl->devid = sdl_open(&req, &obt, 1);
|
||||
if (!sdl->devid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
|
||||
if (err) {
|
||||
sdl_close_in(sdl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.channels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info(&hw->info, &obt_as);
|
||||
hw->samples = (spdo->has_buffer_count ? spdo->buffer_count : 4) *
|
||||
obt.samples;
|
||||
hw->size_emul = hw->samples * hw->info.bytes_per_frame;
|
||||
hw->buf_emul = g_malloc(hw->size_emul);
|
||||
hw->pos_emul = hw->pending_emul = 0;
|
||||
|
||||
sdl->initialized = 1;
|
||||
sdl->exit = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdl_enable_in(HWVoiceIn *hw, bool enable)
|
||||
{
|
||||
SDLVoiceIn *sdl = (SDLVoiceIn *)hw;
|
||||
|
||||
SDL_PauseAudioDevice(sdl->devid, !enable);
|
||||
}
|
||||
|
||||
static void *sdl_audio_init(Audiodev *dev)
|
||||
{
|
||||
SDLAudioState *s = &glob_sdl;
|
||||
if (s->driver_created) {
|
||||
sdl_logerr("Can't create multiple sdl backends\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
|
||||
sdl_logerr ("SDL failed to initialize audio subsystem\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->driver_created = true;
|
||||
s->dev = dev;
|
||||
return s;
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void sdl_audio_fini (void *opaque)
|
||||
{
|
||||
SDLAudioState *s = opaque;
|
||||
sdl_close (s);
|
||||
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
||||
s->driver_created = false;
|
||||
s->dev = NULL;
|
||||
}
|
||||
|
||||
static struct audio_pcm_ops sdl_pcm_ops = {
|
||||
|
@ -355,6 +477,15 @@ static struct audio_pcm_ops sdl_pcm_ops = {
|
|||
/* wrapper for audio_generic_put_buffer_out */
|
||||
.put_buffer_out = sdl_put_buffer_out,
|
||||
.enable_out = sdl_enable_out,
|
||||
.init_in = sdl_init_in,
|
||||
.fini_in = sdl_fini_in,
|
||||
/* wrapper for audio_generic_read */
|
||||
.read = sdl_read,
|
||||
/* wrapper for audio_generic_get_buffer_in */
|
||||
.get_buffer_in = sdl_get_buffer_in,
|
||||
/* wrapper for audio_generic_put_buffer_in */
|
||||
.put_buffer_in = sdl_put_buffer_in,
|
||||
.enable_in = sdl_enable_in,
|
||||
};
|
||||
|
||||
static struct audio_driver sdl_audio_driver = {
|
||||
|
@ -364,10 +495,10 @@ static struct audio_driver sdl_audio_driver = {
|
|||
.fini = sdl_audio_fini,
|
||||
.pcm_ops = &sdl_pcm_ops,
|
||||
.can_be_default = 1,
|
||||
.max_voices_out = 1,
|
||||
.max_voices_in = 0,
|
||||
.voice_size_out = sizeof (SDLVoiceOut),
|
||||
.voice_size_in = 0
|
||||
.max_voices_out = INT_MAX,
|
||||
.max_voices_in = INT_MAX,
|
||||
.voice_size_out = sizeof(SDLVoiceOut),
|
||||
.voice_size_in = sizeof(SDLVoiceIn),
|
||||
};
|
||||
|
||||
static void register_audio_sdl(void)
|
||||
|
|
|
@ -106,7 +106,7 @@ static int line_out_init(HWVoiceOut *hw, struct audsettings *as,
|
|||
out->active = 0;
|
||||
|
||||
out->sin.base.sif = &playback_sif.base;
|
||||
qemu_spice_add_interface (&out->sin.base);
|
||||
qemu_spice.add_interface(&out->sin.base);
|
||||
#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3
|
||||
spice_server_set_playback_rate(&out->sin, settings.freq);
|
||||
#endif
|
||||
|
@ -130,12 +130,11 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
|
|||
}
|
||||
|
||||
if (out->frame) {
|
||||
*size = audio_rate_get_bytes(
|
||||
&hw->info, &out->rate,
|
||||
(out->fsize - out->fpos) * hw->info.bytes_per_frame);
|
||||
} else {
|
||||
audio_rate_start(&out->rate);
|
||||
*size = MIN((out->fsize - out->fpos) << 2, *size);
|
||||
}
|
||||
|
||||
*size = audio_rate_get_bytes(&hw->info, &out->rate, *size);
|
||||
|
||||
return out->frame + out->fpos;
|
||||
}
|
||||
|
||||
|
@ -143,12 +142,14 @@ static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size)
|
|||
{
|
||||
SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
|
||||
|
||||
assert(buf == out->frame + out->fpos && out->fpos <= out->fsize);
|
||||
out->fpos += size >> 2;
|
||||
if (buf) {
|
||||
assert(buf == out->frame + out->fpos && out->fpos <= out->fsize);
|
||||
out->fpos += size >> 2;
|
||||
|
||||
if (out->fpos == out->fsize) { /* buffer full */
|
||||
spice_server_playback_put_samples(&out->sin, out->frame);
|
||||
out->frame = NULL;
|
||||
if (out->fpos == out->fsize) { /* buffer full */
|
||||
spice_server_playback_put_samples(&out->sin, out->frame);
|
||||
out->frame = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
|
@ -214,7 +215,7 @@ static int line_in_init(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
|||
in->active = 0;
|
||||
|
||||
in->sin.base.sif = &record_sif.base;
|
||||
qemu_spice_add_interface (&in->sin.base);
|
||||
qemu_spice.add_interface(&in->sin.base);
|
||||
#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3
|
||||
spice_server_set_record_rate(&in->sin, settings.freq);
|
||||
#endif
|
||||
|
@ -292,6 +293,7 @@ static struct audio_pcm_ops audio_callbacks = {
|
|||
.init_in = line_in_init,
|
||||
.fini_in = line_in_fini,
|
||||
.read = line_in_read,
|
||||
.run_buffer_in = audio_generic_run_buffer_in,
|
||||
.enable_in = line_in_enable,
|
||||
#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
|
||||
.volume_in = line_in_volume,
|
||||
|
@ -310,11 +312,6 @@ static struct audio_driver spice_audio_driver = {
|
|||
.voice_size_in = sizeof (SpiceVoiceIn),
|
||||
};
|
||||
|
||||
void qemu_spice_audio_init (void)
|
||||
{
|
||||
spice_audio_driver.can_be_default = 1;
|
||||
}
|
||||
|
||||
static void register_audio_spice(void)
|
||||
{
|
||||
audio_driver_register(&spice_audio_driver);
|
||||
|
|
|
@ -9,12 +9,9 @@ alsa_read_zero(long len) "Failed to read %ld frames (read zero)"
|
|||
alsa_xrun_out(void) "Recovering from playback xrun"
|
||||
alsa_xrun_in(void) "Recovering from capture xrun"
|
||||
alsa_resume_out(void) "Resuming suspended output stream"
|
||||
alsa_resume_in(void) "Resuming suspended input stream"
|
||||
alsa_no_frames(int state) "No frames available and ALSA state is %d"
|
||||
|
||||
# ossaudio.c
|
||||
oss_version(int version) "OSS version = 0x%x"
|
||||
oss_invalid_available_size(int size, int bufsize) "Invalid available size, size=%d bufsize=%d"
|
||||
|
||||
# audio.c
|
||||
audio_timer_start(int interval) "interval %d ms"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue